@storybook/react-native 10.0.0-beta.9 → 10.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/metro/withStorybook.d.ts +49 -11
- package/dist/metro/withStorybook.js +48 -24
- package/dist/stub.js +39 -0
- package/package.json +10 -10
- package/readme.md +121 -34
- package/dist/metro/withStorybookConfig.d.ts +0 -116
- package/dist/metro/withStorybookConfig.js +0 -360
- package/metro/withStorybookConfig.js +0 -1
|
@@ -21,10 +21,6 @@ interface WithStorybookOptions {
|
|
|
21
21
|
* The path to the Storybook config folder. Defaults to './.rnstorybook'.
|
|
22
22
|
*/
|
|
23
23
|
configPath?: string;
|
|
24
|
-
/**
|
|
25
|
-
* Whether Storybook is enabled. Defaults to true.
|
|
26
|
-
*/
|
|
27
|
-
enabled?: boolean;
|
|
28
24
|
/**
|
|
29
25
|
* WebSocket configuration for syncing storybook instances or sending events to storybook.
|
|
30
26
|
*/
|
|
@@ -34,9 +30,9 @@ interface WithStorybookOptions {
|
|
|
34
30
|
*/
|
|
35
31
|
useJs?: boolean;
|
|
36
32
|
/**
|
|
37
|
-
*
|
|
33
|
+
* if false, we will attempt to remove storybook from the js bundle.
|
|
38
34
|
*/
|
|
39
|
-
|
|
35
|
+
enabled?: boolean;
|
|
40
36
|
/**
|
|
41
37
|
* Whether to include doc tools in the storybook.requires file. Defaults to true.
|
|
42
38
|
*/
|
|
@@ -50,12 +46,32 @@ interface WithStorybookOptions {
|
|
|
50
46
|
/**
|
|
51
47
|
* Configures Metro bundler to work with Storybook in React Native.
|
|
52
48
|
* This function wraps a Metro configuration to enable Storybook usage.
|
|
49
|
+
* This is intended to replace the withStorybook function in the future.
|
|
53
50
|
*
|
|
54
|
-
* @param config - The Metro bundler configuration to be modified.
|
|
51
|
+
* @param config - The Metro bundler configuration to be modified. This should be a valid Metro config object
|
|
52
|
+
* that includes resolver, transformer, and other Metro-specific options.
|
|
55
53
|
* @param options - Options to customize the Storybook configuration.
|
|
56
|
-
* @
|
|
54
|
+
* @param options.configPath - The path to the Storybook config folder. Defaults to './.rnstorybook'.
|
|
55
|
+
* This is where your main.js/ts and preview.js/ts files are located.
|
|
56
|
+
* @param options.websockets - WebSocket configuration for syncing storybook instances or sending events.
|
|
57
|
+
* When provided, creates a WebSocket server for real-time communication.
|
|
58
|
+
* @param options.websockets.port - The port WebSocket server will listen on. Defaults to 7007.
|
|
59
|
+
* @param options.websockets.host - The host WebSocket server will bind to. Defaults to 'localhost'.
|
|
60
|
+
* @param options.useJs - Whether to use JavaScript files for Storybook configuration instead of TypeScript.
|
|
61
|
+
* When true, generates storybook.requires.js instead of storybook.requires.ts.
|
|
62
|
+
* Defaults to false.
|
|
63
|
+
* @param options.enabled - If false, attempts to remove storybook modules from the JavaScript
|
|
64
|
+
* bundle to reduce bundle size. Defaults to true.
|
|
65
|
+
* @param options.docTools - Whether to include doc tools in the storybook.requires file.
|
|
66
|
+
* Doc tools provide additional documentation features. Defaults to true.
|
|
67
|
+
* @param options.liteMode - Whether to use lite mode for the storybook. In lite mode, the default
|
|
68
|
+
* storybook UI is mocked out so you don't need to install all its dependencies
|
|
69
|
+
* like reanimated etc. This is useful for reducing bundle size and dependencies.
|
|
70
|
+
* Defaults to false.
|
|
71
|
+
* @returns The modified Metro configuration with Storybook support enabled.
|
|
57
72
|
*
|
|
58
73
|
* @example
|
|
74
|
+
* ```javascript
|
|
59
75
|
* const { getDefaultConfig } = require('expo/metro-config');
|
|
60
76
|
* const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
61
77
|
* const path = require('path');
|
|
@@ -64,14 +80,36 @@ interface WithStorybookOptions {
|
|
|
64
80
|
* const config = getDefaultConfig(projectRoot);
|
|
65
81
|
*
|
|
66
82
|
* module.exports = withStorybook(config, {
|
|
67
|
-
* enabled: true,
|
|
68
83
|
* configPath: path.resolve(projectRoot, './.rnstorybook'),
|
|
69
84
|
* websockets: { port: 7007, host: 'localhost' },
|
|
70
85
|
* useJs: false,
|
|
71
86
|
* docTools: true,
|
|
72
|
-
*
|
|
87
|
+
* liteMode: false,
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```javascript
|
|
93
|
+
* // Minimal configuration
|
|
94
|
+
* const { getDefaultConfig } = require('expo/metro-config');
|
|
95
|
+
* const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
96
|
+
*
|
|
97
|
+
* const config = getDefaultConfig(__dirname);
|
|
98
|
+
* module.exports = withStorybook(config);
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```javascript
|
|
103
|
+
* // Disable Storybook in production
|
|
104
|
+
* const { getDefaultConfig } = require('expo/metro-config');
|
|
105
|
+
* const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
106
|
+
*
|
|
107
|
+
* const config = getDefaultConfig(__dirname);
|
|
108
|
+
* module.exports = withStorybook(config, {
|
|
109
|
+
* enabled: process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === "true",
|
|
73
110
|
* });
|
|
111
|
+
* ```
|
|
74
112
|
*/
|
|
75
113
|
declare function withStorybook(config: MetroConfig, options?: WithStorybookOptions): MetroConfig;
|
|
76
114
|
|
|
77
|
-
export { withStorybook
|
|
115
|
+
export { withStorybook };
|
|
@@ -7,6 +7,10 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
7
7
|
var __commonJS = (cb, mod) => function __require() {
|
|
8
8
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
9
|
};
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
10
14
|
var __copyProps = (to, from, except, desc) => {
|
|
11
15
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
16
|
for (let key of __getOwnPropNames(from))
|
|
@@ -23,6 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
27
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
28
|
mod
|
|
25
29
|
));
|
|
30
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
26
31
|
|
|
27
32
|
// scripts/common.js
|
|
28
33
|
var require_common = __commonJS({
|
|
@@ -240,24 +245,28 @@ export const view${useJs ? "" : ": View"} = global.view;
|
|
|
240
245
|
});
|
|
241
246
|
|
|
242
247
|
// src/metro/withStorybook.ts
|
|
248
|
+
var withStorybook_exports = {};
|
|
249
|
+
__export(withStorybook_exports, {
|
|
250
|
+
withStorybook: () => withStorybook
|
|
251
|
+
});
|
|
252
|
+
module.exports = __toCommonJS(withStorybook_exports);
|
|
243
253
|
var path = __toESM(require("path"));
|
|
244
254
|
var import_generate = __toESM(require_generate());
|
|
245
255
|
var import_ws = require("ws");
|
|
246
256
|
var import_common = require("storybook/internal/common");
|
|
247
257
|
var import_telemetry = require("storybook/internal/telemetry");
|
|
248
258
|
function withStorybook(config, options = {
|
|
249
|
-
enabled: true,
|
|
250
259
|
useJs: false,
|
|
251
|
-
|
|
260
|
+
enabled: true,
|
|
252
261
|
docTools: true,
|
|
253
|
-
liteMode: false
|
|
262
|
+
liteMode: false,
|
|
263
|
+
configPath: path.resolve(process.cwd(), "./.rnstorybook")
|
|
254
264
|
}) {
|
|
255
265
|
const {
|
|
256
|
-
configPath,
|
|
257
|
-
enabled = true,
|
|
266
|
+
configPath = path.resolve(process.cwd(), "./.rnstorybook"),
|
|
258
267
|
websockets,
|
|
259
268
|
useJs = false,
|
|
260
|
-
|
|
269
|
+
enabled = true,
|
|
261
270
|
docTools = true,
|
|
262
271
|
liteMode = false
|
|
263
272
|
} = options;
|
|
@@ -268,24 +277,36 @@ function withStorybook(config, options = {
|
|
|
268
277
|
});
|
|
269
278
|
}
|
|
270
279
|
if (!enabled) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
resolver
|
|
275
|
-
|
|
276
|
-
resolveRequest
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
return
|
|
280
|
+
return {
|
|
281
|
+
...config,
|
|
282
|
+
resolver: {
|
|
283
|
+
...config.resolver,
|
|
284
|
+
resolveRequest: (context, moduleName, platform) => {
|
|
285
|
+
const resolveFunction = config?.resolver?.resolveRequest ? config.resolver.resolveRequest : context.resolveRequest;
|
|
286
|
+
if (moduleName.startsWith("storybook") || moduleName.startsWith("@storybook")) {
|
|
287
|
+
return {
|
|
288
|
+
type: "empty"
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
if (moduleName === "tty" || moduleName === "os") {
|
|
292
|
+
return {
|
|
293
|
+
type: "empty"
|
|
294
|
+
};
|
|
284
295
|
}
|
|
296
|
+
const resolved = resolveFunction(context, moduleName, platform);
|
|
297
|
+
if (resolved.filePath?.includes?.(`${configPath}/index.tsx`)) {
|
|
298
|
+
return {
|
|
299
|
+
filePath: path.resolve(__dirname, "../stub.js"),
|
|
300
|
+
type: "sourceFile"
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
if (resolved.filePath?.includes?.(configPath)) {
|
|
304
|
+
return { type: "empty" };
|
|
305
|
+
}
|
|
306
|
+
return resolved;
|
|
285
307
|
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
return config;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
289
310
|
}
|
|
290
311
|
if (websockets) {
|
|
291
312
|
const port = websockets.port ?? 7007;
|
|
@@ -305,7 +326,7 @@ function withStorybook(config, options = {
|
|
|
305
326
|
});
|
|
306
327
|
}
|
|
307
328
|
(0, import_generate.generate)({
|
|
308
|
-
configPath
|
|
329
|
+
configPath,
|
|
309
330
|
useJs,
|
|
310
331
|
docTools
|
|
311
332
|
});
|
|
@@ -346,4 +367,7 @@ function withStorybook(config, options = {
|
|
|
346
367
|
}
|
|
347
368
|
};
|
|
348
369
|
}
|
|
349
|
-
|
|
370
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
371
|
+
0 && (module.exports = {
|
|
372
|
+
withStorybook
|
|
373
|
+
});
|
package/dist/stub.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/stub.tsx
|
|
20
|
+
var stub_exports = {};
|
|
21
|
+
__export(stub_exports, {
|
|
22
|
+
default: () => stub_default
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(stub_exports);
|
|
25
|
+
var import_react_native = require("react-native");
|
|
26
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
27
|
+
var Stub = () => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
28
|
+
import_react_native.View,
|
|
29
|
+
{
|
|
30
|
+
style: {
|
|
31
|
+
flex: 1,
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
padding: 16
|
|
35
|
+
},
|
|
36
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { style: { fontSize: 20, textAlign: "center" }, children: "Storybook is disabled in the withStorybook metro wrapper." })
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
var stub_default = Stub;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storybook/react-native",
|
|
3
|
-
"version": "10.0.0-
|
|
3
|
+
"version": "10.0.0-rc.2",
|
|
4
4
|
"description": "A better way to develop React Native Components for your app",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -24,10 +24,10 @@
|
|
|
24
24
|
"exports": {
|
|
25
25
|
".": "./dist/index.js",
|
|
26
26
|
"./metro/withStorybook": "./dist/metro/withStorybook.js",
|
|
27
|
-
"./metro/withStorybookConfig": "./dist/metro/withStorybookConfig.js",
|
|
28
27
|
"./preview": "./dist/preview.js",
|
|
29
28
|
"./scripts/generate": "./scripts/generate.js",
|
|
30
|
-
"./preset": "./preset.js"
|
|
29
|
+
"./preset": "./preset.js",
|
|
30
|
+
"./stub": "./dist/stub.js"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"bin/**/*",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@storybook/global": "^5.0.0",
|
|
52
|
-
"@storybook/react": "10.0.0
|
|
53
|
-
"@storybook/react-native-theming": "^10.0.0-
|
|
54
|
-
"@storybook/react-native-ui": "^10.0.0-
|
|
55
|
-
"@storybook/react-native-ui-common": "^10.0.0-
|
|
52
|
+
"@storybook/react": "10.0.0",
|
|
53
|
+
"@storybook/react-native-theming": "^10.0.0-rc.2",
|
|
54
|
+
"@storybook/react-native-ui": "^10.0.0-rc.2",
|
|
55
|
+
"@storybook/react-native-ui-common": "^10.0.0-rc.2",
|
|
56
56
|
"commander": "^8.2.0",
|
|
57
57
|
"dedent": "^1.5.1",
|
|
58
58
|
"deepmerge": "^4.3.0",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"jotai": "^2.6.2",
|
|
75
75
|
"react": "19.1.0",
|
|
76
76
|
"react-native": "0.81.4",
|
|
77
|
-
"storybook": "10.0.0
|
|
77
|
+
"storybook": "10.0.0",
|
|
78
78
|
"tsup": "^8.5.0",
|
|
79
79
|
"typescript": "~5.9.2",
|
|
80
80
|
"universal-test-renderer": "^0.6.0"
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"react-native-gesture-handler": ">=2",
|
|
87
87
|
"react-native-reanimated": ">=2",
|
|
88
88
|
"react-native-safe-area-context": "*",
|
|
89
|
-
"storybook": ">=10 || 10.0.0-
|
|
89
|
+
"storybook": ">=10 || 10.0.0-rc.1 || ^10"
|
|
90
90
|
},
|
|
91
91
|
"peerDependenciesMeta": {
|
|
92
92
|
"@gorhom/bottom-sheet": {
|
|
@@ -108,5 +108,5 @@
|
|
|
108
108
|
"publishConfig": {
|
|
109
109
|
"access": "public"
|
|
110
110
|
},
|
|
111
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "5cf63a3b01979f229638feb68a6b4131b9e67cd3"
|
|
112
112
|
}
|
package/readme.md
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
# Storybook for React Native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A new docs site is being built for Storybook for React Native, you can find it at https://storybookjs.github.io/react-native/docs/intro/.
|
|
4
|
+
|
|
5
|
+
> [!IMPORTANT]
|
|
6
|
+
> This readme is for v10, for v9 docs see the [v9.1 docs](https://github.com/storybookjs/react-native/tree/v9.1.4).
|
|
4
7
|
|
|
5
8
|
With Storybook for React Native you can design and develop individual React Native components without running your app.
|
|
6
9
|
|
|
7
|
-
If you are migrating from
|
|
10
|
+
If you are migrating from 9 to 10 you can find the migration guide [here](https://github.com/storybookjs/react-native/blob/next/MIGRATION.md#from-version-9-to-10)
|
|
8
11
|
|
|
9
12
|
For more information about storybook visit: [storybook.js.org](https://storybook.js.org)
|
|
10
13
|
|
|
14
|
+
> [!NOTE]
|
|
11
15
|
> Make sure you align your storybook dependencies to the same major version or you will see broken behaviour.
|
|
12
16
|
|
|
13
17
|

|
|
@@ -79,23 +83,23 @@ Then wrap your config in the withStorybook function as seen below.
|
|
|
79
83
|
|
|
80
84
|
```js
|
|
81
85
|
// metro.config.js
|
|
82
|
-
const path = require('path');
|
|
83
86
|
const { getDefaultConfig } = require('expo/metro-config');
|
|
84
|
-
const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
87
|
+
const { withStorybook } = require('@storybook/react-native/metro/withStorybook');
|
|
85
88
|
|
|
86
|
-
/** @type {import('expo/metro-config').MetroConfig} */
|
|
87
89
|
const config = getDefaultConfig(__dirname);
|
|
88
90
|
|
|
91
|
+
// For basic usage with all defaults, this is all you need
|
|
92
|
+
module.exports = withStorybook(config);
|
|
93
|
+
|
|
94
|
+
// Or customize the options
|
|
89
95
|
module.exports = withStorybook(config, {
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
enabled: true,
|
|
93
|
-
// Path to your storybook config
|
|
94
|
-
configPath: path.resolve(__dirname, './.rnstorybook'),
|
|
95
|
-
// note that this is the default so you can the config path blank if you use .rnstorybook
|
|
96
|
+
// When false, removes Storybook from bundle (useful for production)
|
|
97
|
+
enabled: process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === 'true',
|
|
96
98
|
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
+
// Path to your storybook config (default: './.rnstorybook')
|
|
100
|
+
configPath: './.rnstorybook',
|
|
101
|
+
|
|
102
|
+
// Optional websockets configuration for syncing between devices
|
|
99
103
|
// websockets: {
|
|
100
104
|
// port: 7007,
|
|
101
105
|
// host: 'localhost',
|
|
@@ -107,8 +111,8 @@ module.exports = withStorybook(config, {
|
|
|
107
111
|
|
|
108
112
|
```js
|
|
109
113
|
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
110
|
-
const
|
|
111
|
-
|
|
114
|
+
const { withStorybook } = require('@storybook/react-native/metro/withStorybook');
|
|
115
|
+
|
|
112
116
|
const defaultConfig = getDefaultConfig(__dirname);
|
|
113
117
|
|
|
114
118
|
/**
|
|
@@ -122,15 +126,19 @@ const config = {};
|
|
|
122
126
|
|
|
123
127
|
const finalConfig = mergeConfig(defaultConfig, config);
|
|
124
128
|
|
|
129
|
+
// For basic usage with all defaults
|
|
130
|
+
module.exports = withStorybook(finalConfig);
|
|
131
|
+
|
|
132
|
+
// Or customize the options
|
|
125
133
|
module.exports = withStorybook(finalConfig, {
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// Path to your storybook config
|
|
134
|
+
// When false, removes Storybook from bundle (useful for production)
|
|
135
|
+
enabled: process.env.STORYBOOK_ENABLED === 'true',
|
|
136
|
+
|
|
137
|
+
// Path to your storybook config (default: './.rnstorybook')
|
|
130
138
|
configPath: path.resolve(__dirname, './.rnstorybook'),
|
|
131
139
|
// note that this is the default so you can the config path blank if you use .rnstorybook
|
|
132
140
|
|
|
133
|
-
// Optional websockets configuration
|
|
141
|
+
// Optional websockets configuration for syncing between devices
|
|
134
142
|
// Starts a websocket server on the specified port and host on metro start
|
|
135
143
|
// websockets: {
|
|
136
144
|
// port: 7007,
|
|
@@ -148,6 +156,39 @@ Make sure you have `react-native-reanimated` in your project and the plugin setu
|
|
|
148
156
|
plugins: ['react-native-reanimated/plugin'],
|
|
149
157
|
```
|
|
150
158
|
|
|
159
|
+
## Expo router specific setup
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npm create storybook@latest
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
choose recommended and then native
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npx expo@latest customize metro.config.js
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
copy the metro config
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
175
|
+
module.exports = withStorybook(config);
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
add storybook screen to app
|
|
179
|
+
|
|
180
|
+
create `app/storybook.tsx`
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
export { default } from '../.rnstorybook';
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Then add a way to navigate to your storybook route and I recommend disabling the header for the storybook route.
|
|
187
|
+
|
|
188
|
+
Heres a video showing the same setup:
|
|
189
|
+
|
|
190
|
+
https://www.youtube.com/watch?v=egBqrYg0AIg
|
|
191
|
+
|
|
151
192
|
## Writing stories
|
|
152
193
|
|
|
153
194
|
In storybook we use a syntax called CSF that looks like this:
|
|
@@ -291,13 +332,52 @@ For details of each ondevice addon you can see the readme:
|
|
|
291
332
|
|
|
292
333
|
## Hide/Show storybook
|
|
293
334
|
|
|
294
|
-
|
|
335
|
+
In v10, you have flexible options for integrating Storybook into your app:
|
|
295
336
|
|
|
296
|
-
|
|
297
|
-
Some have opted to toggle the storybook component by using a custom option in the react native developer menu.
|
|
337
|
+
### Option 1: Direct export (simplest)
|
|
298
338
|
|
|
299
|
-
|
|
300
|
-
|
|
339
|
+
Just export Storybook directly. Control inclusion via the metro config `enabled` flag:
|
|
340
|
+
|
|
341
|
+
```tsx
|
|
342
|
+
// App.tsx
|
|
343
|
+
export { default } from './.rnstorybook';
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
```js
|
|
347
|
+
// metro.config.js
|
|
348
|
+
module.exports = withStorybook(config, {
|
|
349
|
+
enabled: process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === 'true',
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
When `enabled: false`, Metro automatically removes Storybook from your bundle.
|
|
354
|
+
|
|
355
|
+
### Option 2: Conditional rendering
|
|
356
|
+
|
|
357
|
+
If you want to switch between your app and Storybook at runtime:
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
// App.tsx
|
|
361
|
+
import StorybookUI from './.rnstorybook';
|
|
362
|
+
import { MyApp } from './MyApp';
|
|
363
|
+
|
|
364
|
+
const isStorybook = process.env.EXPO_PUBLIC_STORYBOOK_ENABLED === 'true';
|
|
365
|
+
|
|
366
|
+
export default function App() {
|
|
367
|
+
return isStorybook ? <StorybookUI /> : <MyApp />;
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Option 3: Expo Router (recommended for Expo)
|
|
372
|
+
|
|
373
|
+
Create a dedicated route for Storybook:
|
|
374
|
+
|
|
375
|
+
```tsx
|
|
376
|
+
// app/storybook.tsx
|
|
377
|
+
export { default } from '../.rnstorybook';
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Then navigate to `/storybook` in your app to view stories.
|
|
301
381
|
|
|
302
382
|
## withStorybook wrapper
|
|
303
383
|
|
|
@@ -322,7 +402,9 @@ module.exports = withStorybook(defaultConfig, {
|
|
|
322
402
|
|
|
323
403
|
Type: `boolean`, default: `true`
|
|
324
404
|
|
|
325
|
-
|
|
405
|
+
Controls whether Storybook is included in your app bundle. When `true`, enables Storybook metro configuration and generates the `storybook.requires` file. When `false`, removes all Storybook code from the bundle by replacing imports with empty modules.
|
|
406
|
+
|
|
407
|
+
This is useful for conditionally including Storybook in development but excluding it from production builds:
|
|
326
408
|
|
|
327
409
|
```js
|
|
328
410
|
// metro.config.js
|
|
@@ -332,18 +414,11 @@ const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
|
332
414
|
const defaultConfig = getDefaultConfig(__dirname);
|
|
333
415
|
|
|
334
416
|
module.exports = withStorybook(defaultConfig, {
|
|
335
|
-
enabled: process.env.
|
|
417
|
+
enabled: process.env.STORYBOOK_ENABLED === 'true',
|
|
336
418
|
// ... other options
|
|
337
419
|
});
|
|
338
420
|
```
|
|
339
421
|
|
|
340
|
-
#### onDisabledRemoveStorybook
|
|
341
|
-
|
|
342
|
-
Type: `boolean`, default: `false`
|
|
343
|
-
|
|
344
|
-
If onDisabledRemoveStorybook `true` and `enabled` is `false`, the storybook package will be removed from the build.
|
|
345
|
-
This is useful if you want to remove storybook from your production build.
|
|
346
|
-
|
|
347
422
|
#### useJs
|
|
348
423
|
|
|
349
424
|
Type: `boolean`, default: `false`
|
|
@@ -356,6 +431,18 @@ Type: `string`, default: `path.resolve(process.cwd(), './.rnstorybook')`
|
|
|
356
431
|
|
|
357
432
|
The location of your Storybook configuration directory, which includes `main.ts` and other project-related files.
|
|
358
433
|
|
|
434
|
+
#### docTools
|
|
435
|
+
|
|
436
|
+
Type: `boolean`, default: `true`
|
|
437
|
+
|
|
438
|
+
Whether to include doc tools in the storybook.requires file. Doc tools provide additional documentation features and work with `babel-plugin-react-docgen-typescript`.
|
|
439
|
+
|
|
440
|
+
#### liteMode
|
|
441
|
+
|
|
442
|
+
Type: `boolean`, default: `false`
|
|
443
|
+
|
|
444
|
+
Whether to use lite mode for Storybook. In lite mode, the default Storybook UI is mocked out so you don't need to install all its dependencies like react-native-reanimated. This is useful for reducing bundle size and dependencies. Use this when using @storybook/react-native-ui-lite instead of @storybook/react-native-ui.
|
|
445
|
+
|
|
359
446
|
### websockets
|
|
360
447
|
|
|
361
448
|
Type: `{ host: string?, port: number? }`, default: `undefined`
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { MetroConfig } from 'metro-config';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Options for configuring WebSockets used for syncing storybook instances or sending events to storybook.
|
|
5
|
-
*/
|
|
6
|
-
interface WebsocketsOptions {
|
|
7
|
-
/**
|
|
8
|
-
* The port WebSocket server will listen on. Defaults to 7007.
|
|
9
|
-
*/
|
|
10
|
-
port?: number;
|
|
11
|
-
/**
|
|
12
|
-
* The host WebSocket server will bind to. Defaults to 'localhost'.
|
|
13
|
-
*/
|
|
14
|
-
host?: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Options for configuring Storybook with React Native.
|
|
18
|
-
*/
|
|
19
|
-
interface WithStorybookOptions {
|
|
20
|
-
/**
|
|
21
|
-
* The path to the Storybook config folder. Defaults to './.rnstorybook'.
|
|
22
|
-
*/
|
|
23
|
-
configPath?: string;
|
|
24
|
-
/**
|
|
25
|
-
* WebSocket configuration for syncing storybook instances or sending events to storybook.
|
|
26
|
-
*/
|
|
27
|
-
websockets?: WebsocketsOptions;
|
|
28
|
-
/**
|
|
29
|
-
* Whether to use JavaScript files for Storybook configuration instead of TypeScript. Defaults to false.
|
|
30
|
-
*/
|
|
31
|
-
useJs?: boolean;
|
|
32
|
-
/**
|
|
33
|
-
* if true, we will attempt to remove storybook from the js bundle.
|
|
34
|
-
*/
|
|
35
|
-
removeStorybook?: boolean;
|
|
36
|
-
/**
|
|
37
|
-
* Whether to include doc tools in the storybook.requires file. Defaults to true.
|
|
38
|
-
*/
|
|
39
|
-
docTools?: boolean;
|
|
40
|
-
/**
|
|
41
|
-
* Whether to use lite mode for the storybook. Defaults to false.
|
|
42
|
-
* This will mock out the default storybook ui so you don't need to install all its dependencies like reanimated etc.
|
|
43
|
-
*/
|
|
44
|
-
liteMode?: boolean;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Configures Metro bundler to work with Storybook in React Native.
|
|
48
|
-
* This function wraps a Metro configuration to enable Storybook usage.
|
|
49
|
-
* This is intended to replace the withStorybook function in the future.
|
|
50
|
-
*
|
|
51
|
-
* @param config - The Metro bundler configuration to be modified. This should be a valid Metro config object
|
|
52
|
-
* that includes resolver, transformer, and other Metro-specific options.
|
|
53
|
-
* @param options - Options to customize the Storybook configuration.
|
|
54
|
-
* @param options.configPath - The path to the Storybook config folder. Defaults to './.rnstorybook'.
|
|
55
|
-
* This is where your main.js/ts and preview.js/ts files are located.
|
|
56
|
-
* @param options.websockets - WebSocket configuration for syncing storybook instances or sending events.
|
|
57
|
-
* When provided, creates a WebSocket server for real-time communication.
|
|
58
|
-
* @param options.websockets.port - The port WebSocket server will listen on. Defaults to 7007.
|
|
59
|
-
* @param options.websockets.host - The host WebSocket server will bind to. Defaults to 'localhost'.
|
|
60
|
-
* @param options.useJs - Whether to use JavaScript files for Storybook configuration instead of TypeScript.
|
|
61
|
-
* When true, generates storybook.requires.js instead of storybook.requires.ts.
|
|
62
|
-
* Defaults to false.
|
|
63
|
-
* @param options.removeStorybook - If enabled is false and this is true, attempts to remove
|
|
64
|
-
* storybook modules from the JavaScript bundle to reduce bundle size.
|
|
65
|
-
* Defaults to false.
|
|
66
|
-
* @param options.docTools - Whether to include doc tools in the storybook.requires file.
|
|
67
|
-
* Doc tools provide additional documentation features. Defaults to true.
|
|
68
|
-
* @param options.liteMode - Whether to use lite mode for the storybook. In lite mode, the default
|
|
69
|
-
* storybook UI is mocked out so you don't need to install all its dependencies
|
|
70
|
-
* like reanimated etc. This is useful for reducing bundle size and dependencies.
|
|
71
|
-
* Defaults to false.
|
|
72
|
-
* @returns The modified Metro configuration with Storybook support enabled.
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* ```javascript
|
|
76
|
-
* const { getDefaultConfig } = require('expo/metro-config');
|
|
77
|
-
* const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
78
|
-
* const path = require('path');
|
|
79
|
-
*
|
|
80
|
-
* const projectRoot = __dirname;
|
|
81
|
-
* const config = getDefaultConfig(projectRoot);
|
|
82
|
-
*
|
|
83
|
-
* module.exports = withStorybook(config, {
|
|
84
|
-
* configPath: path.resolve(projectRoot, './.rnstorybook'),
|
|
85
|
-
* websockets: { port: 7007, host: 'localhost' },
|
|
86
|
-
* useJs: false,
|
|
87
|
-
* docTools: true,
|
|
88
|
-
* liteMode: false,
|
|
89
|
-
* });
|
|
90
|
-
* ```
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* ```javascript
|
|
94
|
-
* // Minimal configuration
|
|
95
|
-
* const { getDefaultConfig } = require('expo/metro-config');
|
|
96
|
-
* const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
97
|
-
*
|
|
98
|
-
* const config = getDefaultConfig(__dirname);
|
|
99
|
-
* module.exports = withStorybook(config);
|
|
100
|
-
* ```
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```javascript
|
|
104
|
-
* // Disable Storybook in production
|
|
105
|
-
* const { getDefaultConfig } = require('expo/metro-config');
|
|
106
|
-
* const withStorybook = require('@storybook/react-native/metro/withStorybook');
|
|
107
|
-
*
|
|
108
|
-
* const config = getDefaultConfig(__dirname);
|
|
109
|
-
* module.exports = withStorybook(config, {
|
|
110
|
-
* removeStorybook: process.env.EXPO_PUBLIC_STORYBOOK_ENABLED !== "true",
|
|
111
|
-
* });
|
|
112
|
-
* ```
|
|
113
|
-
*/
|
|
114
|
-
declare function withStorybookConfig(config: MetroConfig, options?: WithStorybookOptions): MetroConfig;
|
|
115
|
-
|
|
116
|
-
export { withStorybookConfig as default, withStorybookConfig };
|
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
-
};
|
|
10
|
-
var __export = (target, all) => {
|
|
11
|
-
for (var name in all)
|
|
12
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
-
};
|
|
14
|
-
var __copyProps = (to, from, except, desc) => {
|
|
15
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
-
for (let key of __getOwnPropNames(from))
|
|
17
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
-
}
|
|
20
|
-
return to;
|
|
21
|
-
};
|
|
22
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
-
mod
|
|
29
|
-
));
|
|
30
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
31
|
-
|
|
32
|
-
// scripts/common.js
|
|
33
|
-
var require_common = __commonJS({
|
|
34
|
-
"scripts/common.js"(exports2, module2) {
|
|
35
|
-
var { globToRegexp } = require("storybook/internal/common");
|
|
36
|
-
var path2 = require("path");
|
|
37
|
-
var fs = require("fs");
|
|
38
|
-
var cwd = process.cwd();
|
|
39
|
-
var toRequireContext = (specifier) => {
|
|
40
|
-
const { directory, files } = specifier;
|
|
41
|
-
const match = globToRegexp(`./${files}`);
|
|
42
|
-
return {
|
|
43
|
-
path: directory,
|
|
44
|
-
recursive: files.includes("**") || files.split("/").length > 1,
|
|
45
|
-
match
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
var supportedExtensions = ["js", "jsx", "ts", "tsx", "cjs", "mjs"];
|
|
49
|
-
function getFilePathExtension({ configPath }, fileName) {
|
|
50
|
-
for (const ext of supportedExtensions) {
|
|
51
|
-
const filePath = path2.resolve(cwd, configPath, `${fileName}.${ext}`);
|
|
52
|
-
if (fs.existsSync(filePath)) {
|
|
53
|
-
return ext;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
function ensureRelativePathHasDot(relativePath) {
|
|
59
|
-
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
60
|
-
}
|
|
61
|
-
function getPreviewExists({ configPath }) {
|
|
62
|
-
return !!getFilePathExtension({ configPath }, "preview");
|
|
63
|
-
}
|
|
64
|
-
function resolveAddonFile(addon, file, extensions = ["js", "mjs", "ts"], configPath) {
|
|
65
|
-
if (!addon || typeof addon !== "string") return null;
|
|
66
|
-
try {
|
|
67
|
-
const basePath = `${addon}/${file}`;
|
|
68
|
-
require.resolve(basePath);
|
|
69
|
-
return basePath;
|
|
70
|
-
} catch (_error) {
|
|
71
|
-
}
|
|
72
|
-
for (const ext of extensions) {
|
|
73
|
-
try {
|
|
74
|
-
const filePath = `${addon}/${file}.${ext}`;
|
|
75
|
-
require.resolve(filePath);
|
|
76
|
-
return filePath;
|
|
77
|
-
} catch (_error) {
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (addon.startsWith("./") || addon.startsWith("../")) {
|
|
81
|
-
try {
|
|
82
|
-
const extension = getFilePathExtension({ configPath }, `${addon}/${file}`);
|
|
83
|
-
if (extension) {
|
|
84
|
-
return `${addon}/${file}`;
|
|
85
|
-
}
|
|
86
|
-
} catch (_error) {
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
function getAddonName(addon) {
|
|
92
|
-
if (typeof addon === "string") return addon;
|
|
93
|
-
if (typeof addon === "object" && addon.name && typeof addon.name === "string") return addon.name;
|
|
94
|
-
console.error("Invalid addon configuration", addon);
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
module2.exports = {
|
|
98
|
-
toRequireContext,
|
|
99
|
-
getFilePathExtension,
|
|
100
|
-
ensureRelativePathHasDot,
|
|
101
|
-
getPreviewExists,
|
|
102
|
-
resolveAddonFile,
|
|
103
|
-
getAddonName
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// scripts/generate.js
|
|
109
|
-
var require_generate = __commonJS({
|
|
110
|
-
"scripts/generate.js"(exports2, module2) {
|
|
111
|
-
var {
|
|
112
|
-
toRequireContext,
|
|
113
|
-
ensureRelativePathHasDot,
|
|
114
|
-
getPreviewExists,
|
|
115
|
-
resolveAddonFile,
|
|
116
|
-
getAddonName
|
|
117
|
-
} = require_common();
|
|
118
|
-
var { normalizeStories, globToRegexp, loadMainConfig } = require("storybook/internal/common");
|
|
119
|
-
var fs = require("fs");
|
|
120
|
-
var path2 = require("path");
|
|
121
|
-
var cwd = process.cwd();
|
|
122
|
-
async function generate2({
|
|
123
|
-
configPath,
|
|
124
|
-
/* absolute = false, */
|
|
125
|
-
useJs = false,
|
|
126
|
-
docTools = true
|
|
127
|
-
}) {
|
|
128
|
-
const storybookRequiresLocation = path2.resolve(
|
|
129
|
-
cwd,
|
|
130
|
-
configPath,
|
|
131
|
-
`storybook.requires.${useJs ? "js" : "ts"}`
|
|
132
|
-
);
|
|
133
|
-
const main = await loadMainConfig({ configDir: configPath, cwd });
|
|
134
|
-
const storiesSpecifiers = normalizeStories(main.stories, {
|
|
135
|
-
configDir: configPath,
|
|
136
|
-
workingDir: cwd
|
|
137
|
-
});
|
|
138
|
-
const normalizedStories = storiesSpecifiers.map((specifier) => {
|
|
139
|
-
const reg = globToRegexp(`./${specifier.files}`);
|
|
140
|
-
const { path: p, recursive: r, match: m } = toRequireContext(specifier);
|
|
141
|
-
const pathToStory = ensureRelativePathHasDot(path2.posix.relative(configPath, p));
|
|
142
|
-
return `{
|
|
143
|
-
titlePrefix: "${specifier.titlePrefix}",
|
|
144
|
-
directory: "${specifier.directory}",
|
|
145
|
-
files: "${specifier.files}",
|
|
146
|
-
importPathMatcher: /${reg.source}/,
|
|
147
|
-
${useJs ? "" : "// @ts-ignore"}
|
|
148
|
-
req: require.context(
|
|
149
|
-
'${pathToStory}',
|
|
150
|
-
${r},
|
|
151
|
-
${m}
|
|
152
|
-
),
|
|
153
|
-
}`;
|
|
154
|
-
});
|
|
155
|
-
const registeredAddons = [];
|
|
156
|
-
for (const addon of main.addons) {
|
|
157
|
-
const registerPath = resolveAddonFile(
|
|
158
|
-
getAddonName(addon),
|
|
159
|
-
"register",
|
|
160
|
-
["js", "mjs", "jsx", "ts", "tsx"],
|
|
161
|
-
configPath
|
|
162
|
-
);
|
|
163
|
-
if (registerPath) {
|
|
164
|
-
registeredAddons.push(`import "${registerPath}";`);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
const docToolsAnnotation = 'require("@storybook/react-native/preview")';
|
|
168
|
-
const enhancers = [];
|
|
169
|
-
if (docTools) {
|
|
170
|
-
enhancers.push(docToolsAnnotation);
|
|
171
|
-
}
|
|
172
|
-
for (const addon of main.addons) {
|
|
173
|
-
const previewPath = resolveAddonFile(
|
|
174
|
-
getAddonName(addon),
|
|
175
|
-
"preview",
|
|
176
|
-
["js", "mjs", "jsx", "ts", "tsx"],
|
|
177
|
-
configPath
|
|
178
|
-
);
|
|
179
|
-
if (previewPath) {
|
|
180
|
-
enhancers.push(`require('${previewPath}')`);
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
let options = "";
|
|
185
|
-
let optionsVar = "";
|
|
186
|
-
const reactNativeOptions = main.reactNative;
|
|
187
|
-
if (reactNativeOptions && typeof reactNativeOptions === "object") {
|
|
188
|
-
optionsVar = `const options = ${JSON.stringify(reactNativeOptions, null, 2)}`;
|
|
189
|
-
options = "options";
|
|
190
|
-
}
|
|
191
|
-
const previewExists = getPreviewExists({ configPath });
|
|
192
|
-
if (previewExists) {
|
|
193
|
-
enhancers.unshift("require('./preview')");
|
|
194
|
-
}
|
|
195
|
-
const annotations = `[
|
|
196
|
-
${enhancers.join(",\n ")}
|
|
197
|
-
]`;
|
|
198
|
-
const globalTypes = `
|
|
199
|
-
declare global {
|
|
200
|
-
var view: View;
|
|
201
|
-
var STORIES: typeof normalizedStories;
|
|
202
|
-
}
|
|
203
|
-
`;
|
|
204
|
-
const fileContent = `/* do not change this file, it is auto generated by storybook. */
|
|
205
|
-
import { start, updateView${useJs ? "" : ", View"} } from '@storybook/react-native';
|
|
206
|
-
|
|
207
|
-
${registeredAddons.join("\n")}
|
|
208
|
-
|
|
209
|
-
const normalizedStories = [
|
|
210
|
-
${normalizedStories.join(",\n ")}
|
|
211
|
-
];
|
|
212
|
-
|
|
213
|
-
${useJs ? "" : globalTypes}
|
|
214
|
-
|
|
215
|
-
const annotations = ${annotations};
|
|
216
|
-
|
|
217
|
-
global.STORIES = normalizedStories;
|
|
218
|
-
|
|
219
|
-
${useJs ? "" : "// @ts-ignore"}
|
|
220
|
-
module?.hot?.accept?.();
|
|
221
|
-
|
|
222
|
-
${optionsVar}
|
|
223
|
-
|
|
224
|
-
if (!global.view) {
|
|
225
|
-
global.view = start({
|
|
226
|
-
annotations,
|
|
227
|
-
storyEntries: normalizedStories,
|
|
228
|
-
${options ? ` ${options},` : ""}
|
|
229
|
-
});
|
|
230
|
-
} else {
|
|
231
|
-
updateView(global.view, annotations, normalizedStories${options ? `, ${options}` : ""});
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export const view${useJs ? "" : ": View"} = global.view;
|
|
235
|
-
`;
|
|
236
|
-
fs.writeFileSync(storybookRequiresLocation, fileContent, {
|
|
237
|
-
encoding: "utf8",
|
|
238
|
-
flag: "w"
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
module2.exports = {
|
|
242
|
-
generate: generate2
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
// src/metro/withStorybookConfig.ts
|
|
248
|
-
var withStorybookConfig_exports = {};
|
|
249
|
-
__export(withStorybookConfig_exports, {
|
|
250
|
-
default: () => withStorybookConfig_default,
|
|
251
|
-
withStorybookConfig: () => withStorybookConfig
|
|
252
|
-
});
|
|
253
|
-
module.exports = __toCommonJS(withStorybookConfig_exports);
|
|
254
|
-
var path = __toESM(require("path"));
|
|
255
|
-
var import_generate = __toESM(require_generate());
|
|
256
|
-
var import_ws = require("ws");
|
|
257
|
-
var import_common = require("storybook/internal/common");
|
|
258
|
-
var import_telemetry = require("storybook/internal/telemetry");
|
|
259
|
-
function withStorybookConfig(config, options = {
|
|
260
|
-
useJs: false,
|
|
261
|
-
removeStorybook: false,
|
|
262
|
-
docTools: true,
|
|
263
|
-
liteMode: false,
|
|
264
|
-
configPath: path.resolve(process.cwd(), "./.rnstorybook")
|
|
265
|
-
}) {
|
|
266
|
-
const {
|
|
267
|
-
configPath = path.resolve(process.cwd(), "./.rnstorybook"),
|
|
268
|
-
websockets,
|
|
269
|
-
useJs = false,
|
|
270
|
-
removeStorybook = false,
|
|
271
|
-
docTools = true,
|
|
272
|
-
liteMode = false
|
|
273
|
-
} = options;
|
|
274
|
-
const disableTelemetry = (0, import_common.optionalEnvToBoolean)(process.env.STORYBOOK_DISABLE_TELEMETRY);
|
|
275
|
-
if (!disableTelemetry && !removeStorybook) {
|
|
276
|
-
const event = process.env.NODE_ENV === "production" ? "build" : "dev";
|
|
277
|
-
(0, import_telemetry.telemetry)(event, {}).catch((e) => {
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
if (removeStorybook) {
|
|
281
|
-
return {
|
|
282
|
-
...config,
|
|
283
|
-
resolver: {
|
|
284
|
-
...config.resolver,
|
|
285
|
-
resolveRequest: (context, moduleName, platform) => {
|
|
286
|
-
const resolveFunction = config?.resolver?.resolveRequest ? config.resolver.resolveRequest : context.resolveRequest;
|
|
287
|
-
if (moduleName.startsWith("storybook") || moduleName.startsWith("@storybook")) {
|
|
288
|
-
return {
|
|
289
|
-
type: "empty"
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
return resolveFunction(context, moduleName, platform);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
if (websockets) {
|
|
298
|
-
const port = websockets.port ?? 7007;
|
|
299
|
-
const host = websockets.host ?? "localhost";
|
|
300
|
-
const wss = new import_ws.WebSocketServer({ port, host });
|
|
301
|
-
wss.on("connection", function connection(ws) {
|
|
302
|
-
console.log("WebSocket connection established");
|
|
303
|
-
ws.on("error", console.error);
|
|
304
|
-
ws.on("message", function message(data) {
|
|
305
|
-
try {
|
|
306
|
-
const json = JSON.parse(data.toString());
|
|
307
|
-
wss.clients.forEach((wsClient) => wsClient.send(JSON.stringify(json)));
|
|
308
|
-
} catch (error) {
|
|
309
|
-
console.error(error);
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
(0, import_generate.generate)({
|
|
315
|
-
configPath,
|
|
316
|
-
useJs,
|
|
317
|
-
docTools
|
|
318
|
-
});
|
|
319
|
-
return {
|
|
320
|
-
...config,
|
|
321
|
-
transformer: {
|
|
322
|
-
...config.transformer,
|
|
323
|
-
unstable_allowRequireContext: true
|
|
324
|
-
},
|
|
325
|
-
resolver: {
|
|
326
|
-
...config.resolver,
|
|
327
|
-
resolveRequest: (context, moduleName, platform) => {
|
|
328
|
-
const resolveFunction = config?.resolver?.resolveRequest ? config.resolver.resolveRequest : context.resolveRequest;
|
|
329
|
-
const shouldUseCustomResolveConfig = moduleName.startsWith("storybook") || moduleName.startsWith("@storybook") || moduleName.startsWith("uuid");
|
|
330
|
-
const theContext = shouldUseCustomResolveConfig ? {
|
|
331
|
-
...context,
|
|
332
|
-
unstable_enablePackageExports: true,
|
|
333
|
-
unstable_conditionNames: ["import"]
|
|
334
|
-
} : context;
|
|
335
|
-
const resolveResult = resolveFunction(theContext, moduleName, platform);
|
|
336
|
-
if (resolveResult?.filePath?.includes?.("@storybook/react/template/cli")) {
|
|
337
|
-
return {
|
|
338
|
-
type: "empty"
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
if (moduleName === "tty" || moduleName === "os") {
|
|
342
|
-
return {
|
|
343
|
-
type: "empty"
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
if (liteMode && resolveResult?.filePath?.includes?.("@storybook/react-native-ui") && !resolveResult?.filePath?.includes?.("@storybook/react-native-ui-lite") && !resolveResult?.filePath?.includes?.("@storybook/react-native-ui-common")) {
|
|
347
|
-
return {
|
|
348
|
-
type: "empty"
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
return resolveResult;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
var withStorybookConfig_default = withStorybookConfig;
|
|
357
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
358
|
-
0 && (module.exports = {
|
|
359
|
-
withStorybookConfig
|
|
360
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = require('../dist/metro/withStorybookConfig.js');
|