From bc326fcd3713287509b20071ec51eebbc20154fe Mon Sep 17 00:00:00 2001 From: Daniel Williams Date: Tue, 22 Oct 2024 20:03:08 +0100 Subject: [PATCH] feat: onDisabledRemoveStorybook option (#622) * feat: experiment with onDisabledRemoveStorybook option * fix: readme * v8.3.10-alpha.0 * feat: types for withstorybook * v8.3.10-alpha.1 * fix: uninitialised force render * v8.3.10-alpha.2 * fix: search results empty string error * v8.3.10 --- README.md | 16 +++++ examples/expo-example/package.json | 14 ++-- lerna.json | 2 +- packages/ondevice-actions/package.json | 2 +- packages/ondevice-backgrounds/package.json | 4 +- packages/ondevice-controls/package.json | 6 +- packages/ondevice-notes/package.json | 4 +- packages/react-native-theming/package.json | 2 +- packages/react-native-ui/package.json | 4 +- .../react-native-ui/src/SearchResults.tsx | 10 +-- .../react-native/metro/withStorybook.d.ts | 72 +++++++++++++++++++ packages/react-native/metro/withStorybook.js | 28 +++++++- packages/react-native/package.json | 6 +- packages/react-native/readme.md | 11 ++- packages/react-native/src/View.tsx | 2 +- yarn.lock | 40 +++++------ 16 files changed, 172 insertions(+), 51 deletions(-) create mode 100644 packages/react-native/metro/withStorybook.d.ts diff --git a/README.md b/README.md index 6e13e8d472..b95719f932 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,15 @@ module.exports = withStorybook(finalConfig, { }); ``` +#### Reanimated setup + +Make sure you have `react-native-reanimated` in your project and the plugin setup in your babel config. + +```js +// babel.config.js +plugins: ['react-native-reanimated/plugin']; +``` + ## Writing stories In storybook we use a syntax called CSF that looks like this: @@ -328,6 +337,13 @@ module.exports = withStorybook(defaultConfig, { }); ``` +#### onDisabledRemoveStorybook + +Type: `boolean`, default: `false` + +If onDisabledRemoveStorybook `true` and `enabled` is `false`, the storybook package will be removed from the build. +This is useful if you want to remove storybook from your production build. + #### useJs Type: `boolean`, default: `false` diff --git a/examples/expo-example/package.json b/examples/expo-example/package.json index 71f815ff1e..35e927a755 100644 --- a/examples/expo-example/package.json +++ b/examples/expo-example/package.json @@ -1,6 +1,6 @@ { "name": "expo-example", - "version": "8.3.9", + "version": "8.3.10", "private": true, "main": "index.js", "scripts": { @@ -28,10 +28,10 @@ "@storybook/addon-essentials": "^8.3.5", "@storybook/addon-interactions": "^8.3.5", "@storybook/addon-links": "^8.3.5", - "@storybook/addon-ondevice-actions": "^8.3.9", - "@storybook/addon-ondevice-backgrounds": "^8.3.9", - "@storybook/addon-ondevice-controls": "^8.3.9", - "@storybook/addon-ondevice-notes": "^8.3.9", + "@storybook/addon-ondevice-actions": "^8.3.10", + "@storybook/addon-ondevice-backgrounds": "^8.3.10", + "@storybook/addon-ondevice-controls": "^8.3.10", + "@storybook/addon-ondevice-notes": "^8.3.10", "@storybook/addon-react-native-server": "0.0.6", "@storybook/addon-react-native-web": "^0.0.22", "@storybook/addon-webpack5-compiler-babel": "^3.0.3", @@ -39,8 +39,8 @@ "@storybook/builder-webpack5": "^8.3.5", "@storybook/global": "^5.0.0", "@storybook/react": "^8.3.5", - "@storybook/react-native": "^8.3.9", - "@storybook/react-native-theming": "^8.3.9", + "@storybook/react-native": "^8.3.10", + "@storybook/react-native-theming": "^8.3.10", "@storybook/react-webpack5": "^8.3.5", "@storybook/test": "^8.3.5", "expo": "^51.0.34", diff --git a/lerna.json b/lerna.json index 98ead382b6..f778e441db 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { "npmClient": "yarn", "registry": "https://registry.npmjs.org", - "version": "8.3.9" + "version": "8.3.10" } \ No newline at end of file diff --git a/packages/ondevice-actions/package.json b/packages/ondevice-actions/package.json index 196a952d1f..a3cde9fe53 100644 --- a/packages/ondevice-actions/package.json +++ b/packages/ondevice-actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-ondevice-actions", - "version": "8.3.9", + "version": "8.3.10", "description": "Action Logger addon for react-native storybook", "keywords": [ "storybook" diff --git a/packages/ondevice-backgrounds/package.json b/packages/ondevice-backgrounds/package.json index d5297c9192..434701a5a9 100644 --- a/packages/ondevice-backgrounds/package.json +++ b/packages/ondevice-backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-ondevice-backgrounds", - "version": "8.3.9", + "version": "8.3.10", "description": "A react-native storybook addon to show different backgrounds for your preview", "keywords": [ "addon", @@ -33,7 +33,7 @@ }, "dependencies": { "@storybook/core": "^8.3.5", - "@storybook/react-native-theming": "^8.3.9" + "@storybook/react-native-theming": "^8.3.10" }, "devDependencies": { "typescript": "^5.3.3" diff --git a/packages/ondevice-controls/package.json b/packages/ondevice-controls/package.json index 8c9cd80f75..3d41cba6dd 100644 --- a/packages/ondevice-controls/package.json +++ b/packages/ondevice-controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-ondevice-controls", - "version": "8.3.9", + "version": "8.3.10", "description": "Display storybook controls on your device.", "keywords": [ "addon", @@ -32,8 +32,8 @@ "dependencies": { "@storybook/addon-controls": "^8.3.5", "@storybook/core": "^8.3.5", - "@storybook/react-native-theming": "^8.3.9", - "@storybook/react-native-ui": "^8.3.9", + "@storybook/react-native-theming": "^8.3.10", + "@storybook/react-native-ui": "^8.3.10", "deep-equal": "^1.0.1", "prop-types": "^15.7.2", "react-native-modal-datetime-picker": "^14.0.0", diff --git a/packages/ondevice-notes/package.json b/packages/ondevice-notes/package.json index cac5b12dd5..c10d30e7bb 100644 --- a/packages/ondevice-notes/package.json +++ b/packages/ondevice-notes/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-ondevice-notes", - "version": "8.3.9", + "version": "8.3.10", "description": "Write notes for your react-native Storybook stories.", "keywords": [ "addon", @@ -30,7 +30,7 @@ }, "dependencies": { "@storybook/core": "^8.3.5", - "@storybook/react-native-theming": "^8.3.9", + "@storybook/react-native-theming": "^8.3.10", "react-native-markdown-display": "^7.0.2" }, "devDependencies": { diff --git a/packages/react-native-theming/package.json b/packages/react-native-theming/package.json index 2e9b43891b..b48cb17a9e 100644 --- a/packages/react-native-theming/package.json +++ b/packages/react-native-theming/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-native-theming", - "version": "8.3.9", + "version": "8.3.10", "description": "A wrapper library around emotion 11 to provide theming support for react-native storybook", "keywords": [ "react", diff --git a/packages/react-native-ui/package.json b/packages/react-native-ui/package.json index 1cdf0255b6..224692d8ec 100644 --- a/packages/react-native-ui/package.json +++ b/packages/react-native-ui/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-native-ui", - "version": "8.3.9", + "version": "8.3.10", "description": "ui components for react native storybook", "keywords": [ "react", @@ -59,7 +59,7 @@ "dependencies": { "@storybook/core": "^8.3.5", "@storybook/react": "^8.3.5", - "@storybook/react-native-theming": "^8.3.9", + "@storybook/react-native-theming": "^8.3.10", "fuse.js": "^7.0.0", "memoizerific": "^1.11.3", "polished": "^4.3.1", diff --git a/packages/react-native-ui/src/SearchResults.tsx b/packages/react-native-ui/src/SearchResults.tsx index c0696c5431..82eea3ca97 100644 --- a/packages/react-native-ui/src/SearchResults.tsx +++ b/packages/react-native-ui/src/SearchResults.tsx @@ -205,20 +205,22 @@ export const SearchResults: FC<{ return ( - {results.length > 0 && !query && ( + {results.length > 0 && !query ? ( Recently opened - )} - {results.length === 0 && query && ( + ) : null} + + {results.length === 0 && query ? ( No components found Find components by name or path. - )} + ) : null} + {results.map((result, index) => { if (isExpandType(result)) { return ( diff --git a/packages/react-native/metro/withStorybook.d.ts b/packages/react-native/metro/withStorybook.d.ts new file mode 100644 index 0000000000..3528a1fd10 --- /dev/null +++ b/packages/react-native/metro/withStorybook.d.ts @@ -0,0 +1,72 @@ +import type { InputConfigT } from 'metro-config'; + +/** + * Options for configuring WebSockets used for syncing storybook instances or sending events to storybook. + */ +interface WebsocketsOptions { + /** + * The port WebSocket server will listen on. Defaults to 7007. + */ + port?: number; + + /** + * The host WebSocket server will bind to. Defaults to 'localhost'. + */ + host?: string; +} + +/** + * Options for configuring Storybook with React Native. + */ +interface WithStorybookOptions { + /** + * The path to the Storybook config folder. Defaults to './.storybook'. + */ + configPath?: string; + + /** + * Whether Storybook is enabled. Defaults to true. + */ + enabled?: boolean; + + /** + * WebSocket configuration for syncing storybook instances or sending events to storybook. + */ + websockets?: WebsocketsOptions; + + /** + * Whether to use JavaScript files for Storybook configuration instead of TypeScript. Defaults to false. + */ + useJs?: boolean; + + /** + * If enabled is false and onDisabledRemoveStorybook is true, we will attempt to remove storybook from the js bundle. + */ + onDisabledRemoveStorybook?: boolean; +} + +/** + * Configures Metro bundler to work with Storybook in React Native. + * This function wraps a Metro configuration to enable Storybook usage. + * + * @param config - The Metro bundler configuration to be modified. + * @param options - Options to customize the Storybook configuration. + * @returns The modified Metro configuration. + * + * @example + * const { getDefaultConfig } = require('expo/metro-config'); + * const withStorybook = require('@storybook/react-native/metro/withStorybook'); + * const path = require('path'); + * + * const projectRoot = __dirname; + * const config = getDefaultConfig(projectRoot); + * + * module.exports = withStorybook(config, { + * enabled: true, + * configPath: path.resolve(projectRoot, './.storybook'), + * websockets: { port: 7007, host: 'localhost' }, + * useJs: false, + * onDisabledRemoveStorybook: true, + * }); + */ +export function withStorybook(config: InputConfigT, options?: WithStorybookOptions): InputConfigT; diff --git a/packages/react-native/metro/withStorybook.js b/packages/react-native/metro/withStorybook.js index 9e24aa7b16..d6896cbeb4 100644 --- a/packages/react-native/metro/withStorybook.js +++ b/packages/react-native/metro/withStorybook.js @@ -5,9 +5,35 @@ const { WebSocketServer } = require('ws'); module.exports = ( config, - { configPath, enabled = true, websockets, useJs = false } = { enabled: true, useJs: false } + { configPath, enabled = true, websockets, useJs = false, onDisabledRemoveStorybook = false } = { + enabled: true, + useJs: false, + onDisabledRemoveStorybook: false, + } ) => { if (!enabled) { + if (onDisabledRemoveStorybook) { + return { + ...config, + resolver: { + ...config.resolver, + resolveRequest: (context, moduleName, platform) => { + const resolveFunction = config?.resolver?.resolveRequest + ? config?.resolver?.resolveRequest + : context.resolveRequest; + + if (moduleName.startsWith('storybook') || moduleName.startsWith('@storybook')) { + return { + type: 'empty', + }; + } + + return resolveFunction(context, moduleName, platform); + }, + }, + }; + } + return config; } diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 221470aeca..5cdf7cc77d 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-native", - "version": "8.3.9", + "version": "8.3.10", "description": "A better way to develop React Native Components for your app", "keywords": [ "react", @@ -43,8 +43,8 @@ "@storybook/csf": "^0.1.1", "@storybook/global": "^5.0.0", "@storybook/react": "^8.3.5", - "@storybook/react-native-theming": "^8.3.9", - "@storybook/react-native-ui": "^8.3.9", + "@storybook/react-native-theming": "^8.3.10", + "@storybook/react-native-ui": "^8.3.10", "chokidar": "^3.5.1", "commander": "^8.2.0", "dedent": "^1.5.1", diff --git a/packages/react-native/readme.md b/packages/react-native/readme.md index 94ab53a4ba..ccf22cba51 100644 --- a/packages/react-native/readme.md +++ b/packages/react-native/readme.md @@ -1,12 +1,10 @@ # Storybook for React Native > [!IMPORTANT] -> This readme is in the process of being updated for v8 which is not yet released to stable, for v7 docs see the [v7.6 docs](https://github.com/storybookjs/react-native/tree/v7.6.20-stable). +> This readme is for v8, for v7 docs see the [v7.6 docs](https://github.com/storybookjs/react-native/tree/v7.6.20-stable). With Storybook for React Native you can design and develop individual React Native components without running your app. -This readme is for the 8.3.1 version, you can find the 7.6 docs [here](https://github.com/storybookjs/react-native/tree/v7.6.20-stable). - If you are migrating from 7.6 to 8.3 you can find the migration guide [here](https://github.com/storybookjs/react-native/blob/next/MIGRATION.md#from-version-76x-to-83x) For more information about storybook visit: [storybook.js.org](https://storybook.js.org) @@ -330,6 +328,13 @@ module.exports = withStorybook(defaultConfig, { }); ``` +#### onDisabledRemoveStorybook + +Type: `boolean`, default: `false` + +If onDisabledRemoveStorybook `true` and `enabled` is `false`, the storybook package will be removed from the build. +This is useful if you want to remove storybook from your production build. + #### useJs Type: `boolean`, default: `false` diff --git a/packages/react-native/src/View.tsx b/packages/react-native/src/View.tsx index 0e7933ece1..c7c0d66e07 100644 --- a/packages/react-native/src/View.tsx +++ b/packages/react-native/src/View.tsx @@ -69,7 +69,7 @@ export type Params = { export class View { _storyIndex: StoryIndex; _setStory: (story: StoryContext) => void = () => {}; - _forceRerender: () => void; + _forceRerender: () => void = () => {}; _ready: boolean = false; _preview: PreviewWithSelection; _asyncStorageStoryId: string; diff --git a/yarn.lock b/yarn.lock index df3bd204ec..83e13e4e46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4549,7 +4549,7 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-ondevice-actions@npm:^8.3.9, @storybook/addon-ondevice-actions@workspace:packages/ondevice-actions": +"@storybook/addon-ondevice-actions@npm:^8.3.10, @storybook/addon-ondevice-actions@workspace:packages/ondevice-actions": version: 0.0.0-use.local resolution: "@storybook/addon-ondevice-actions@workspace:packages/ondevice-actions" dependencies: @@ -4564,12 +4564,12 @@ __metadata: languageName: unknown linkType: soft -"@storybook/addon-ondevice-backgrounds@npm:^8.3.9, @storybook/addon-ondevice-backgrounds@workspace:packages/ondevice-backgrounds": +"@storybook/addon-ondevice-backgrounds@npm:^8.3.10, @storybook/addon-ondevice-backgrounds@workspace:packages/ondevice-backgrounds": version: 0.0.0-use.local resolution: "@storybook/addon-ondevice-backgrounds@workspace:packages/ondevice-backgrounds" dependencies: "@storybook/core": "npm:^8.3.5" - "@storybook/react-native-theming": "npm:^8.3.9" + "@storybook/react-native-theming": "npm:^8.3.10" typescript: "npm:^5.3.3" peerDependencies: react: "*" @@ -4577,14 +4577,14 @@ __metadata: languageName: unknown linkType: soft -"@storybook/addon-ondevice-controls@npm:^8.3.9, @storybook/addon-ondevice-controls@workspace:packages/ondevice-controls": +"@storybook/addon-ondevice-controls@npm:^8.3.10, @storybook/addon-ondevice-controls@workspace:packages/ondevice-controls": version: 0.0.0-use.local resolution: "@storybook/addon-ondevice-controls@workspace:packages/ondevice-controls" dependencies: "@storybook/addon-controls": "npm:^8.3.5" "@storybook/core": "npm:^8.3.5" - "@storybook/react-native-theming": "npm:^8.3.9" - "@storybook/react-native-ui": "npm:^8.3.9" + "@storybook/react-native-theming": "npm:^8.3.10" + "@storybook/react-native-ui": "npm:^8.3.10" cross-env: "npm:^7.0.3" deep-equal: "npm:^1.0.1" prop-types: "npm:^15.7.2" @@ -4601,12 +4601,12 @@ __metadata: languageName: unknown linkType: soft -"@storybook/addon-ondevice-notes@npm:^8.3.9, @storybook/addon-ondevice-notes@workspace:packages/ondevice-notes": +"@storybook/addon-ondevice-notes@npm:^8.3.10, @storybook/addon-ondevice-notes@workspace:packages/ondevice-notes": version: 0.0.0-use.local resolution: "@storybook/addon-ondevice-notes@workspace:packages/ondevice-notes" dependencies: "@storybook/core": "npm:^8.3.5" - "@storybook/react-native-theming": "npm:^8.3.9" + "@storybook/react-native-theming": "npm:^8.3.10" react-native-markdown-display: "npm:^7.0.2" typescript: "npm:^5.3.3" peerDependencies: @@ -4927,7 +4927,7 @@ __metadata: languageName: node linkType: hard -"@storybook/react-native-theming@npm:^8.3.9, @storybook/react-native-theming@workspace:packages/react-native-theming": +"@storybook/react-native-theming@npm:^8.3.10, @storybook/react-native-theming@workspace:packages/react-native-theming": version: 0.0.0-use.local resolution: "@storybook/react-native-theming@workspace:packages/react-native-theming" dependencies: @@ -4941,13 +4941,13 @@ __metadata: languageName: unknown linkType: soft -"@storybook/react-native-ui@npm:^8.3.9, @storybook/react-native-ui@workspace:packages/react-native-ui": +"@storybook/react-native-ui@npm:^8.3.10, @storybook/react-native-ui@workspace:packages/react-native-ui": version: 0.0.0-use.local resolution: "@storybook/react-native-ui@workspace:packages/react-native-ui" dependencies: "@storybook/core": "npm:^8.3.5" "@storybook/react": "npm:^8.3.5" - "@storybook/react-native-theming": "npm:^8.3.9" + "@storybook/react-native-theming": "npm:^8.3.10" "@types/jest": "npm:^29.4.3" "@types/react": "npm:~18.2.79" babel-jest: "npm:^29.4.3" @@ -4970,7 +4970,7 @@ __metadata: languageName: unknown linkType: soft -"@storybook/react-native@npm:^8.3.9, @storybook/react-native@workspace:packages/react-native": +"@storybook/react-native@npm:^8.3.10, @storybook/react-native@workspace:packages/react-native": version: 0.0.0-use.local resolution: "@storybook/react-native@workspace:packages/react-native" dependencies: @@ -4978,8 +4978,8 @@ __metadata: "@storybook/csf": "npm:^0.1.1" "@storybook/global": "npm:^5.0.0" "@storybook/react": "npm:^8.3.5" - "@storybook/react-native-theming": "npm:^8.3.9" - "@storybook/react-native-ui": "npm:^8.3.9" + "@storybook/react-native-theming": "npm:^8.3.10" + "@storybook/react-native-ui": "npm:^8.3.10" "@types/jest": "npm:^29.4.3" "@types/react": "npm:~18.2.79" babel-jest: "npm:^29.4.3" @@ -9693,10 +9693,10 @@ __metadata: "@storybook/addon-essentials": "npm:^8.3.5" "@storybook/addon-interactions": "npm:^8.3.5" "@storybook/addon-links": "npm:^8.3.5" - "@storybook/addon-ondevice-actions": "npm:^8.3.9" - "@storybook/addon-ondevice-backgrounds": "npm:^8.3.9" - "@storybook/addon-ondevice-controls": "npm:^8.3.9" - "@storybook/addon-ondevice-notes": "npm:^8.3.9" + "@storybook/addon-ondevice-actions": "npm:^8.3.10" + "@storybook/addon-ondevice-backgrounds": "npm:^8.3.10" + "@storybook/addon-ondevice-controls": "npm:^8.3.10" + "@storybook/addon-ondevice-notes": "npm:^8.3.10" "@storybook/addon-react-native-server": "npm:0.0.6" "@storybook/addon-react-native-web": "npm:^0.0.22" "@storybook/addon-webpack5-compiler-babel": "npm:^3.0.3" @@ -9704,8 +9704,8 @@ __metadata: "@storybook/builder-webpack5": "npm:^8.3.5" "@storybook/global": "npm:^5.0.0" "@storybook/react": "npm:^8.3.5" - "@storybook/react-native": "npm:^8.3.9" - "@storybook/react-native-theming": "npm:^8.3.9" + "@storybook/react-native": "npm:^8.3.10" + "@storybook/react-native-theming": "npm:^8.3.10" "@storybook/react-webpack5": "npm:^8.3.5" "@storybook/test": "npm:^8.3.5" "@testing-library/react-native": "npm:12.4.3"