@storybook/react-native 6.0.1-beta.0 → 6.0.1-beta.10

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.
Files changed (78) hide show
  1. package/dist/document-polyfill/DOM/Document.d.ts +14 -0
  2. package/dist/document-polyfill/DOM/Document.js +37 -0
  3. package/dist/document-polyfill/DOM/Element.d.ts +37 -0
  4. package/dist/document-polyfill/DOM/Element.js +58 -0
  5. package/dist/document-polyfill/DOM/HTMLCanvasElement.d.ts +4 -0
  6. package/dist/document-polyfill/DOM/HTMLCanvasElement.js +4 -0
  7. package/dist/document-polyfill/DOM/HTMLImageElement.d.ts +4 -0
  8. package/dist/document-polyfill/DOM/HTMLImageElement.js +4 -0
  9. package/dist/document-polyfill/DOM/HTMLVideoElement.d.ts +4 -0
  10. package/dist/document-polyfill/DOM/HTMLVideoElement.js +4 -0
  11. package/dist/document-polyfill/DOM/Node.d.ts +26 -0
  12. package/dist/document-polyfill/DOM/Node.js +33 -0
  13. package/dist/{preview/global.js → document-polyfill/index.d.ts} +0 -0
  14. package/dist/document-polyfill/index.js +3 -0
  15. package/dist/document-polyfill/module.d.ts +0 -0
  16. package/dist/document-polyfill/module.js +1 -0
  17. package/dist/{types-6.0.js → document-polyfill/module.native.d.ts} +0 -0
  18. package/dist/document-polyfill/module.native.js +2 -0
  19. package/dist/index.d.ts +16 -13
  20. package/dist/index.js +18 -18
  21. package/dist/preview/View.d.ts +40 -0
  22. package/dist/preview/View.js +90 -0
  23. package/dist/preview/components/OnDeviceUI/OnDeviceUI.d.ts +6 -3
  24. package/dist/preview/components/OnDeviceUI/OnDeviceUI.js +33 -38
  25. package/dist/preview/components/OnDeviceUI/Panel.js +1 -0
  26. package/dist/preview/components/OnDeviceUI/animation.d.ts +16 -6
  27. package/dist/preview/components/OnDeviceUI/animation.js +4 -3
  28. package/dist/preview/components/OnDeviceUI/navigation/Bar.d.ts +3 -1
  29. package/dist/preview/components/OnDeviceUI/navigation/Bar.js +1 -1
  30. package/dist/preview/components/OnDeviceUI/navigation/Navigation.d.ts +4 -3
  31. package/dist/preview/components/OnDeviceUI/navigation/Navigation.js +15 -10
  32. package/dist/preview/components/OnDeviceUI/navigation/VisibilityButton.d.ts +3 -1
  33. package/dist/preview/components/OnDeviceUI/navigation/VisibilityButton.js +34 -5
  34. package/dist/preview/components/Shared/icons.d.ts +5 -0
  35. package/dist/preview/components/Shared/icons.js +21 -0
  36. package/dist/preview/components/Shared/text.d.ts +3 -32
  37. package/dist/preview/components/Shared/text.js +3 -4
  38. package/dist/preview/components/Shared/theme.d.ts +4 -0
  39. package/dist/preview/components/Shared/theme.js +4 -0
  40. package/dist/preview/components/StoryListView/StoryListView.d.ts +7 -4
  41. package/dist/preview/components/StoryListView/StoryListView.js +46 -27
  42. package/dist/preview/components/StoryView/StoryView.d.ts +5 -3
  43. package/dist/preview/components/StoryView/StoryView.js +6 -24
  44. package/dist/preview/executeLoadable.d.ts +24 -0
  45. package/dist/preview/executeLoadable.js +79 -0
  46. package/dist/preview/rn-host-detect.d.ts +1 -0
  47. package/dist/preview/rn-host-detect.js +62 -0
  48. package/dist/preview/start.d.ts +16 -0
  49. package/dist/preview/start.js +83 -0
  50. package/dist/types/types-6.0.d.ts +72 -0
  51. package/dist/types/types-6.0.js +1 -0
  52. package/dist/types/types.d.ts +14 -0
  53. package/dist/types/types.js +1 -0
  54. package/package.json +16 -13
  55. package/scripts/__snapshots__/loader.test.js.snap +82 -7
  56. package/scripts/loader.js +40 -10
  57. package/scripts/loader.test.js +47 -5
  58. package/scripts/mocks/file-extensions/FakeComponent.tsx +1 -0
  59. package/scripts/mocks/file-extensions/FakeStory.stories.tsx +10 -0
  60. package/scripts/mocks/file-extensions/main.ts +13 -0
  61. package/scripts/mocks/file-extensions/preview.tsx +23 -0
  62. package/scripts/mocks/preview-files/js/preview.js +24 -0
  63. package/scripts/mocks/preview-files/jsx/preview.jsx +24 -0
  64. package/scripts/mocks/preview-files/ts/preview.ts +9 -0
  65. package/scripts/mocks/preview-files/tsx/preview.tsx +9 -0
  66. package/scripts/mocks/wrong-extension-preview/FakeComponent.tsx +1 -0
  67. package/scripts/mocks/wrong-extension-preview/FakeStory.stories.tsx +10 -0
  68. package/scripts/mocks/wrong-extension-preview/main.js +9 -0
  69. package/scripts/mocks/wrong-extension-preview/preview.txt +24 -0
  70. package/scripts/watcher.js +7 -4
  71. package/dist/preview/Preview.d.ts +0 -55
  72. package/dist/preview/Preview.js +0 -117
  73. package/dist/preview/global.d.ts +0 -8
  74. package/dist/preview/index.d.ts +0 -1
  75. package/dist/preview/index.js +0 -1
  76. package/dist/preview/loadCsf.d.ts +0 -16
  77. package/dist/preview/loadCsf.js +0 -175
  78. package/dist/types-6.0.d.ts +0 -34
@@ -0,0 +1 @@
1
+ export default function getHost(hostname: any): any;
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+ /*
3
+ * It only for Debug Remotely mode for Android
4
+ * When __DEV__ === false, we can't use window.require('NativeModules')
5
+ */
6
+ function getByRemoteConfig(hostname) {
7
+ var remoteModuleConfig = typeof window !== 'undefined' &&
8
+ window.__fbBatchedBridgeConfig &&
9
+ window.__fbBatchedBridgeConfig.remoteModuleConfig;
10
+ if (!Array.isArray(remoteModuleConfig) ||
11
+ (hostname !== 'localhost' && hostname !== '127.0.0.1')) {
12
+ return { hostname: hostname, passed: false };
13
+ }
14
+ var constants = (remoteModuleConfig.find(getConstants) || [])[1];
15
+ if (constants) {
16
+ var serverHost = constants.ServerHost || hostname;
17
+ return { hostname: serverHost.split(':')[0], passed: true };
18
+ }
19
+ return { hostname: hostname, passed: false };
20
+ }
21
+ function getConstants(config) {
22
+ return config && (config[0] === 'AndroidConstants' || config[0] === 'PlatformConstants');
23
+ }
24
+ function getByRNRequirePolyfill(hostname) {
25
+ var NativeModules;
26
+ var PlatformConstants;
27
+ var AndroidConstants;
28
+ if (typeof window === 'undefined' ||
29
+ !window.__DEV__ ||
30
+ typeof window.require !== 'function' ||
31
+ // RN >= 0.56
32
+ // TODO: Get NativeModules for RN >= 0.56
33
+ window.require.name === 'metroRequire') {
34
+ return hostname;
35
+ }
36
+ NativeModules = window.require('NativeModules');
37
+ if (!NativeModules || (!NativeModules.PlatformConstants && !NativeModules.AndroidConstants)) {
38
+ return hostname;
39
+ }
40
+ PlatformConstants = NativeModules.PlatformConstants;
41
+ AndroidConstants = NativeModules.AndroidConstants;
42
+ var serverHost = (PlatformConstants ? PlatformConstants.ServerHost : AndroidConstants.ServerHost) || hostname;
43
+ return serverHost.split(':')[0];
44
+ }
45
+ /*
46
+ * Get React Native server IP if hostname is `localhost`
47
+ * On Android emulator, the IP of host is `10.0.2.2` (Genymotion: 10.0.3.2)
48
+ */
49
+ export default function getHost(hostname) {
50
+ // Check if it in React Native environment
51
+ if (typeof __fbBatchedBridge !== 'object' ||
52
+ (hostname !== 'localhost' && hostname !== '127.0.0.1')) {
53
+ return hostname;
54
+ }
55
+ var result = getByRemoteConfig(hostname);
56
+ // Leave if get hostname by remote config successful
57
+ if (result.passed) {
58
+ return result.hostname;
59
+ }
60
+ // Otherwise, use RN's require polyfill
61
+ return getByRNRequirePolyfill(hostname);
62
+ }
@@ -0,0 +1,16 @@
1
+ /// <reference types="webpack-env" />
2
+ /// <reference types="node" />
3
+ import { Loadable } from '@storybook/core-client';
4
+ import { PreviewWeb } from '@storybook/preview-web';
5
+ import { ClientApi } from '@storybook/client-api';
6
+ import type { ReactNativeFramework } from '../types/types-6.0';
7
+ import { View } from './View';
8
+ import type { ArgsStoryFn } from '@storybook/csf';
9
+ export declare const render: ArgsStoryFn<ReactNativeFramework>;
10
+ export declare function start(): {
11
+ view: View;
12
+ forceReRender: () => void;
13
+ clientApi: ClientApi<ReactNativeFramework>;
14
+ preview: PreviewWeb<ReactNativeFramework>;
15
+ configure(loadable: Loadable, m: NodeModule): void;
16
+ };
@@ -0,0 +1,83 @@
1
+ import React from 'react';
2
+ import Channel from '@storybook/channels';
3
+ import { addons } from '@storybook/addons';
4
+ import Events from '@storybook/core-events';
5
+ import { PreviewWeb } from '@storybook/preview-web';
6
+ import { ClientApi, setGlobalRender } from '@storybook/client-api';
7
+ import { View } from './View';
8
+ import { executeLoadableForChanges } from './executeLoadable';
9
+ export const render = (args, context) => {
10
+ const { id, component: Component } = context;
11
+ if (!Component) {
12
+ throw new Error(`Unable to render story ${id} as the component annotation is missing from the default export`);
13
+ }
14
+ return React.createElement(Component, Object.assign({}, args));
15
+ };
16
+ export function start() {
17
+ var _a, _b, _c, _d, _e, _f, _g, _h;
18
+ const channel = new Channel({ async: true });
19
+ addons.setChannel(channel);
20
+ const clientApi = new ClientApi();
21
+ const preview = new PreviewWeb();
22
+ clientApi.storyStore = preview.storyStore;
23
+ setGlobalRender(render);
24
+ preview.urlStore = {
25
+ selection: { storyId: '', viewMode: 'story' },
26
+ selectionSpecifier: null,
27
+ setQueryParams: () => { },
28
+ setSelection: (selection) => {
29
+ preview.urlStore.selection = selection;
30
+ },
31
+ };
32
+ preview.view = Object.assign(Object.assign({}, preview.view), { prepareForStory: () => null, showNoPreview: () => { }, showPreparingStory: () => { }, applyLayout: () => { }, showErrorDisplay: (e) => {
33
+ console.log(e);
34
+ }, showStoryDuringRender: () => { }, showMain: () => { },
35
+ // these are just to make typescript happy
36
+ showDocs: (_a = preview.view) === null || _a === void 0 ? void 0 : _a.showDocs, storyRoot: (_b = preview.view) === null || _b === void 0 ? void 0 : _b.storyRoot, prepareForDocs: (_c = preview.view) === null || _c === void 0 ? void 0 : _c.prepareForDocs, docsRoot: (_d = preview.view) === null || _d === void 0 ? void 0 : _d.docsRoot, checkIfLayoutExists: (_e = preview.view) === null || _e === void 0 ? void 0 : _e.checkIfLayoutExists, showMode: (_f = preview.view) === null || _f === void 0 ? void 0 : _f.showMode, showPreparingDocs: (_g = preview.view) === null || _g === void 0 ? void 0 : _g.showPreparingDocs, showStory: (_h = preview.view) === null || _h === void 0 ? void 0 : _h.showStory });
37
+ let initialized = false;
38
+ function onStoriesChanged() {
39
+ const storyIndex = clientApi.getStoryIndex();
40
+ preview.onStoriesChanged({ storyIndex });
41
+ view._storyIndex = storyIndex;
42
+ }
43
+ const view = new View(preview);
44
+ return {
45
+ view,
46
+ forceReRender: () => channel.emit(Events.FORCE_RE_RENDER),
47
+ clientApi,
48
+ preview,
49
+ // This gets called each time the user calls configure (i.e. once per HMR)
50
+ // The first time, it constructs the preview, subsequently it updates it
51
+ configure(loadable, m) {
52
+ clientApi.addParameters({ framework: 'react-native' });
53
+ // We need to run the `executeLoadableForChanges` function *inside* the `getProjectAnnotations
54
+ // function in case it throws. So we also need to process its output there also
55
+ const getProjectAnnotations = () => {
56
+ const { added, removed } = executeLoadableForChanges(loadable, m);
57
+ Array.from(added.entries()).forEach(([fileName, fileExports]) => clientApi.facade.addStoriesFromExports(fileName, fileExports));
58
+ Array.from(removed.entries()).forEach(([fileName]) => clientApi.facade.clearFilenameExports(fileName));
59
+ return Object.assign(Object.assign({}, clientApi.facade.projectAnnotations), { renderToDOM: (context) => {
60
+ view._setStory(context.storyContext);
61
+ } });
62
+ };
63
+ const importFn = (path) => clientApi.importFn(path);
64
+ if (!initialized) {
65
+ preview.initialize({
66
+ getStoryIndex: () => {
67
+ const index = clientApi.getStoryIndex();
68
+ view._storyIndex = index;
69
+ return index;
70
+ },
71
+ importFn,
72
+ getProjectAnnotations,
73
+ });
74
+ initialized = true;
75
+ }
76
+ else {
77
+ // TODO -- why don't we care about the new annotations?
78
+ getProjectAnnotations();
79
+ onStoriesChanged();
80
+ }
81
+ },
82
+ };
83
+ }
@@ -0,0 +1,72 @@
1
+ import { ComponentProps, ComponentType, JSXElementConstructor, ReactElement } from 'react';
2
+ import type { Args, ComponentAnnotations, StoryAnnotations, AnnotatedStoryFn } from '@storybook/csf';
3
+ export declare type StoryFnReactReturnType = ReactElement<unknown>;
4
+ export type { Args, ArgTypes, Parameters, StoryContext } from '@storybook/addons';
5
+ export declare type ReactNativeFramework = {
6
+ component: ComponentType<any>;
7
+ storyResult: StoryFnReactReturnType;
8
+ };
9
+ /**
10
+ * For the common case where a component's stories are simple components that receives args as props:
11
+ *
12
+ * ```tsx
13
+ * export default { ... } as ComponentMeta<typeof Button>;
14
+ * ```
15
+ */
16
+ export declare type ComponentMeta<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = Meta<ComponentProps<T>>;
17
+ /**
18
+ * For the common case where a (CSFv2) story is a simple component that receives args as props:
19
+ *
20
+ * ```tsx
21
+ * const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />
22
+ * ```
23
+ */
24
+ export declare type ComponentStoryFn<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = StoryFn<ComponentProps<T>>;
25
+ /**
26
+ * For the common case where a (CSFv3) story is a simple component that receives args as props:
27
+ *
28
+ * ```tsx
29
+ * const MyStory: ComponentStory<typeof Button> = {
30
+ * args: { buttonArg1: 'val' },
31
+ * }
32
+ * ```
33
+ */
34
+ export declare type ComponentStoryObj<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = StoryObj<ComponentProps<T>>;
35
+ /**
36
+ * For the common case where a (CSFv2) story is a simple component that receives args as props:
37
+ *
38
+ * ```tsx
39
+ * const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />
40
+ * ```
41
+ *
42
+ * NOTE: this is an alias for `ComponentStoryFn`.
43
+ * In Storybook v7, `ComponentStory` will alias `ComponentStoryObj`
44
+ */
45
+ export declare type ComponentStory<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> = Story<ComponentProps<T>>;
46
+ /**
47
+ * Metadata to configure the stories for a component.
48
+ *
49
+ * @see [Default export](https://storybook.js.org/docs/formats/component-story-format/#default-export)
50
+ */
51
+ export declare type Meta<TArgs = Args> = ComponentAnnotations<ReactNativeFramework, TArgs>;
52
+ /**
53
+ * Story function that represents a CSFv2 component example.
54
+ *
55
+ * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
56
+ */
57
+ export declare type StoryFn<TArgs = Args> = AnnotatedStoryFn<ReactNativeFramework, TArgs>;
58
+ /**
59
+ * Story function that represents a CSFv3 component example.
60
+ *
61
+ * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
62
+ */
63
+ export declare type StoryObj<TArgs = Args> = StoryAnnotations<ReactNativeFramework, TArgs>;
64
+ /**
65
+ * Story function that represents a CSFv2 component example.
66
+ *
67
+ * @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
68
+ *
69
+ * NOTE that in Storybook 7.0, this type will be renamed to `StoryFn` and replaced by the current `StoryObj` type.
70
+ *
71
+ */
72
+ export declare type Story<TArgs = Args> = StoryFn<TArgs>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { RenderContext, RenderContextWithoutStoryContext } from '@storybook/client-api';
2
+ export interface PreviewError {
3
+ message?: string;
4
+ stack?: string;
5
+ }
6
+ export interface RequireContext {
7
+ keys: () => string[];
8
+ (id: string): any;
9
+ resolve(id: string): string;
10
+ }
11
+ export declare type LoaderFunction = () => void | any[];
12
+ export declare type Loadable = RequireContext | RequireContext[] | LoaderFunction;
13
+ export type { RenderContext, RenderContextWithoutStoryContext };
14
+ export declare type RenderStoryFunction = (context: RenderContext) => void;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/react-native",
3
- "version": "6.0.1-beta.0",
3
+ "version": "6.0.1-beta.10",
4
4
  "description": "A better way to develop React Native Components for your app",
5
5
  "keywords": [
6
6
  "react",
@@ -49,14 +49,15 @@
49
49
  "dependencies": {
50
50
  "@emotion/core": "^10.0.20",
51
51
  "@emotion/native": "^10.0.14",
52
- "@storybook/addons": "~6.3",
53
- "@storybook/channel-websocket": "~6.3",
54
- "@storybook/channels": "~6.3",
55
- "@storybook/client-api": "~6.3",
56
- "@storybook/client-logger": "~6.3",
57
- "@storybook/core-client": "~6.3",
58
- "@storybook/core-events": "~6.3",
59
- "@storybook/csf": "0.0.1",
52
+ "@storybook/addons": "^6.5",
53
+ "@storybook/channel-websocket": "^6.5",
54
+ "@storybook/channels": "^6.5",
55
+ "@storybook/client-api": "^6.5",
56
+ "@storybook/client-logger": "^6.5",
57
+ "@storybook/core-client": "^6.5",
58
+ "@storybook/core-events": "^6.5",
59
+ "@storybook/csf": "0.0.2--canary.7c6c115.0",
60
+ "@storybook/preview-web": "^6.5",
60
61
  "chokidar": "^3.5.1",
61
62
  "commander": "^8.2.0",
62
63
  "emotion-theming": "^10.0.19",
@@ -66,15 +67,17 @@
66
67
  "util": "^0.12.4"
67
68
  },
68
69
  "devDependencies": {
69
- "@types/react-native": "^0.66.15",
70
+ "@types/react": "^18.0.21",
71
+ "@types/react-native": "^0.70.4",
70
72
  "babel-jest": "^26.6.3",
71
73
  "jest": "^26.6.3",
72
- "react-test-renderer": "17.0.2"
74
+ "react-test-renderer": "18.2.0"
73
75
  },
74
76
  "peerDependencies": {
75
77
  "@react-native-async-storage/async-storage": ">=1",
76
78
  "react": "*",
77
- "react-native": ">=0.57.0"
79
+ "react-native": ">=0.57.0",
80
+ "react-native-safe-area-context": "*"
78
81
  },
79
82
  "engines": {
80
83
  "node": ">=8.0.0"
@@ -82,5 +85,5 @@
82
85
  "publishConfig": {
83
86
  "access": "public"
84
87
  },
85
- "gitHead": "3490aec85c84210997f38b92afa515b6dc41b8b5"
88
+ "gitHead": "0288f6d0728b0f29698435b5cd2d46dc7dde57fc"
86
89
  }
@@ -1,10 +1,57 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`loader writeRequires when there are different file extensions writes the story imports 1`] = `
4
+ "
5
+ /* do not change this file, it is auto generated by storybook. */
6
+
7
+ import { configure, addDecorator, addParameters, addArgsEnhancer, clearDecorators } from '@storybook/react-native';
8
+
9
+ import \\"@storybook/addon-ondevice-notes/register\\";
10
+ import \\"@storybook/addon-ondevice-controls/register\\";
11
+ import \\"@storybook/addon-ondevice-backgrounds/register\\";
12
+ import \\"@storybook/addon-ondevice-actions/register\\";
13
+
14
+ import { argsEnhancers } from \\"@storybook/addon-actions/dist/modern/preset/addArgs\\"
15
+
16
+
17
+ import { decorators, parameters } from './preview';
18
+
19
+ if (decorators) {
20
+ if(__DEV__){
21
+ // stops the warning from showing on every HMR
22
+ require('react-native').LogBox.ignoreLogs([
23
+ '\`clearDecorators\` is deprecated and will be removed in Storybook 7.0',
24
+ ]);
25
+ }
26
+ // workaround for global decorators getting infinitely applied on HMR, see https://github.com/storybookjs/react-native/issues/185
27
+ clearDecorators();
28
+ decorators.forEach((decorator) => addDecorator(decorator));
29
+ }
30
+
31
+ if (parameters) {
32
+ addParameters(parameters);
33
+ }
34
+
35
+
36
+
37
+ try {
38
+ argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer));
39
+ } catch{}
40
+
41
+
42
+ const getStories=() => {
43
+ return [require(\\"./FakeStory.stories.tsx\\")];
44
+ }
45
+
46
+ configure(getStories, module, false)
47
+ "
48
+ `;
49
+
3
50
  exports[`loader writeRequires when there is a story glob and exclude paths globs writes the story imports 1`] = `
4
51
  "
5
52
  /* do not change this file, it is auto generated by storybook. */
6
53
 
7
- import { configure, addDecorator, addParameters, addArgsEnhancer } from '@storybook/react-native';
54
+ import { configure, addDecorator, addParameters, addArgsEnhancer, clearDecorators } from '@storybook/react-native';
8
55
 
9
56
  import \\"@storybook/addon-ondevice-notes/register\\";
10
57
  import \\"@storybook/addon-ondevice-controls/register\\";
@@ -17,6 +64,14 @@ import \\"@storybook/addon-ondevice-actions/register\\";
17
64
  import { decorators, parameters } from './preview';
18
65
 
19
66
  if (decorators) {
67
+ if(__DEV__){
68
+ // stops the warning from showing on every HMR
69
+ require('react-native').LogBox.ignoreLogs([
70
+ '\`clearDecorators\` is deprecated and will be removed in Storybook 7.0',
71
+ ]);
72
+ }
73
+ // workaround for global decorators getting infinitely applied on HMR, see https://github.com/storybookjs/react-native/issues/185
74
+ clearDecorators();
20
75
  decorators.forEach((decorator) => addDecorator(decorator));
21
76
  }
22
77
 
@@ -25,7 +80,11 @@ import \\"@storybook/addon-ondevice-actions/register\\";
25
80
  }
26
81
 
27
82
 
28
- argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer))
83
+
84
+ try {
85
+ argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer));
86
+ } catch{}
87
+
29
88
 
30
89
  const getStories=() => {
31
90
  return [require(\\"include-components/FakeStory.stories.tsx\\")];
@@ -39,7 +98,7 @@ exports[`loader writeRequires when there is a story glob writes the story import
39
98
  "
40
99
  /* do not change this file, it is auto generated by storybook. */
41
100
 
42
- import { configure, addDecorator, addParameters, addArgsEnhancer } from '@storybook/react-native';
101
+ import { configure, addDecorator, addParameters, addArgsEnhancer, clearDecorators } from '@storybook/react-native';
43
102
 
44
103
  import \\"@storybook/addon-ondevice-notes/register\\";
45
104
  import \\"@storybook/addon-ondevice-controls/register\\";
@@ -52,6 +111,14 @@ import \\"@storybook/addon-ondevice-actions/register\\";
52
111
  import { decorators, parameters } from './preview';
53
112
 
54
113
  if (decorators) {
114
+ if(__DEV__){
115
+ // stops the warning from showing on every HMR
116
+ require('react-native').LogBox.ignoreLogs([
117
+ '\`clearDecorators\` is deprecated and will be removed in Storybook 7.0',
118
+ ]);
119
+ }
120
+ // workaround for global decorators getting infinitely applied on HMR, see https://github.com/storybookjs/react-native/issues/185
121
+ clearDecorators();
55
122
  decorators.forEach((decorator) => addDecorator(decorator));
56
123
  }
57
124
 
@@ -60,7 +127,11 @@ import \\"@storybook/addon-ondevice-actions/register\\";
60
127
  }
61
128
 
62
129
 
63
- argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer))
130
+
131
+ try {
132
+ argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer));
133
+ } catch{}
134
+
64
135
 
65
136
  const getStories=() => {
66
137
  return [require(\\"./FakeStory.stories.tsx\\")];
@@ -74,7 +145,7 @@ exports[`loader writeRequires when there is no preview does not add preview rela
74
145
  "
75
146
  /* do not change this file, it is auto generated by storybook. */
76
147
 
77
- import { configure, addDecorator, addParameters, addArgsEnhancer } from '@storybook/react-native';
148
+ import { configure, addDecorator, addParameters, addArgsEnhancer, clearDecorators } from '@storybook/react-native';
78
149
 
79
150
  import \\"@storybook/addon-ondevice-notes/register\\";
80
151
  import \\"@storybook/addon-ondevice-controls/register\\";
@@ -85,7 +156,11 @@ import \\"@storybook/addon-ondevice-actions/register\\";
85
156
 
86
157
 
87
158
 
88
- argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer))
159
+
160
+ try {
161
+ argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer));
162
+ } catch{}
163
+
89
164
 
90
165
  const getStories=() => {
91
166
  return [require(\\"./FakeStory.stories.tsx\\")];
@@ -99,7 +174,7 @@ exports[`loader writeRequires when there is no story glob or addons writes no st
99
174
  "
100
175
  /* do not change this file, it is auto generated by storybook. */
101
176
 
102
- import { configure, addDecorator, addParameters, addArgsEnhancer } from '@storybook/react-native';
177
+ import { configure, addDecorator, addParameters, addArgsEnhancer, clearDecorators } from '@storybook/react-native';
103
178
 
104
179
 
105
180
 
package/scripts/loader.js CHANGED
@@ -4,11 +4,21 @@ const glob = require('glob');
4
4
  const prettier = require('prettier');
5
5
 
6
6
  const cwd = process.cwd();
7
+ const supportedExtensions = ['js', 'jsx', 'ts', 'tsx', 'cjs', 'mjs'];
7
8
 
9
+ // we clear decorators as a workaround for global decorators getting infinitely applied on HMR
8
10
  const previewImports = `
9
11
  import { decorators, parameters } from './preview';
10
12
 
11
13
  if (decorators) {
14
+ if(__DEV__){
15
+ // stops the warning from showing on every HMR
16
+ require('react-native').LogBox.ignoreLogs([
17
+ '\`clearDecorators\` is deprecated and will be removed in Storybook 7.0',
18
+ ]);
19
+ }
20
+ // workaround for global decorators getting infinitely applied on HMR, see https://github.com/storybookjs/react-native/issues/185
21
+ clearDecorators();
12
22
  decorators.forEach((decorator) => addDecorator(decorator));
13
23
  }
14
24
 
@@ -38,19 +48,34 @@ function requireUncached(module) {
38
48
  }
39
49
 
40
50
  function getMain({ configPath }) {
41
- const mainPath = path.resolve(cwd, configPath, 'main.js');
51
+ const fileExtension = getFilePathExtension({ configPath }, 'main');
52
+ if (fileExtension === null) {
53
+ throw new Error('main config file not found');
54
+ }
55
+ const mainPath = path.resolve(cwd, configPath, `main.${fileExtension}`);
56
+
42
57
  return requireUncached(mainPath);
43
58
  }
44
59
 
60
+ function getFilePathExtension({ configPath }, fileName) {
61
+ for (const ext of supportedExtensions) {
62
+ const filePath = path.resolve(cwd, configPath, `${fileName}.${ext}`);
63
+ if (fs.existsSync(filePath)) {
64
+ return ext;
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+
45
70
  function getPreviewExists({ configPath }) {
46
- const previewPath = path.resolve(cwd, configPath, 'preview.js');
47
- return fs.existsSync(previewPath);
71
+ return !!getFilePathExtension({ configPath }, 'preview');
48
72
  }
49
73
 
50
74
  function writeRequires({ configPath, absolute = false }) {
51
75
  const storybookRequiresLocation = path.resolve(cwd, configPath, 'storybook.requires.js');
52
76
 
53
- const main = getMain({ configPath });
77
+ const mainImport = getMain({ configPath });
78
+ const main = mainImport.default ?? mainImport;
54
79
  const reactNativeOptions = main.reactNativeOptions;
55
80
  const excludePaths = reactNativeOptions && reactNativeOptions.excludePaths;
56
81
  const normalizedExcludePaths = normalizeExcludePaths(excludePaths);
@@ -60,9 +85,7 @@ function writeRequires({ configPath, absolute = false }) {
60
85
  cwd: path.resolve(cwd, configPath),
61
86
  absolute,
62
87
  // default to always ignore (exclude) anything in node_modules
63
- ignore: normalizedExcludePaths !== undefined
64
- ? normalizedExcludePaths
65
- : ['**/node_modules'],
88
+ ignore: normalizedExcludePaths !== undefined ? normalizedExcludePaths : ['**/node_modules'],
66
89
  });
67
90
  return [...acc, ...paths];
68
91
  }, []);
@@ -76,7 +99,7 @@ function writeRequires({ configPath, absolute = false }) {
76
99
  const storyRequires = storyPaths.map((storyPath) => `require("${storyPath}")`).join(',');
77
100
  const path_array_str = `[${storyRequires}]`;
78
101
 
79
- const registerAddons = main.addons.map((addon) => `import "${addon}/register";`).join('\n');
102
+ const registerAddons = main.addons?.map((addon) => `import "${addon}/register";`).join('\n');
80
103
  let enhancersImport = '';
81
104
  let enhancers = '';
82
105
 
@@ -84,13 +107,19 @@ function writeRequires({ configPath, absolute = false }) {
84
107
  if (main.addons.includes('@storybook/addon-ondevice-actions')) {
85
108
  enhancersImport =
86
109
  'import { argsEnhancers } from "@storybook/addon-actions/dist/modern/preset/addArgs"';
87
- enhancers = 'argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer))';
110
+
111
+ // try/catch is a temporary fix for https://github.com/storybookjs/react-native/issues/327 until a fix is found
112
+ enhancers = `
113
+ try {
114
+ argsEnhancers.forEach(enhancer => addArgsEnhancer(enhancer));
115
+ } catch{}
116
+ `;
88
117
  }
89
118
 
90
119
  const fileContent = `
91
120
  /* do not change this file, it is auto generated by storybook. */
92
121
 
93
- import { configure, addDecorator, addParameters, addArgsEnhancer } from '@storybook/react-native';
122
+ import { configure, addDecorator, addParameters, addArgsEnhancer, clearDecorators } from '@storybook/react-native';
94
123
 
95
124
  ${registerAddons}
96
125
 
@@ -119,4 +148,5 @@ module.exports = {
119
148
  writeRequires,
120
149
  getMain,
121
150
  getPreviewExists,
151
+ getFilePathExtension,
122
152
  };
@@ -1,6 +1,5 @@
1
1
  const path = require('path');
2
2
  const { writeRequires, getMain, getPreviewExists } = require('./loader');
3
- const glob = require('glob');
4
3
 
5
4
  let pathMock;
6
5
  let fileContentMock;
@@ -47,24 +46,51 @@ describe('loader', () => {
47
46
  ],
48
47
  });
49
48
  });
49
+ it('should work for any supported file extension', () => {
50
+ const main = getMain({ configPath: './scripts/mocks/file-extensions' });
51
+ expect(main).toEqual({
52
+ default: {
53
+ stories: ['./FakeStory.stories.tsx'],
54
+ addons: [
55
+ '@storybook/addon-ondevice-notes',
56
+ '@storybook/addon-ondevice-controls',
57
+ '@storybook/addon-ondevice-backgrounds',
58
+ '@storybook/addon-ondevice-actions',
59
+ ],
60
+ },
61
+ });
62
+ });
50
63
  });
51
64
 
52
65
  describe('getPreviewExists', () => {
66
+ const supportedExtensions = ['js', 'jsx', 'ts', 'tsx'];
53
67
  describe('when using a relative path', () => {
54
68
  it('should return true if the preview exists', () => {
55
- expect(getPreviewExists({ configPath: 'scripts/mocks/all-config-files' })).toBe(true);
69
+ supportedExtensions.forEach((ext) => {
70
+ expect(getPreviewExists({ configPath: `scripts/mocks/preview-files/${ext}` })).toBe(true);
71
+ });
56
72
  });
57
73
 
58
74
  it('should return false if the preview does not exist', () => {
59
75
  expect(getPreviewExists({ configPath: './scripts/mocks/no-preview' })).toBe(false);
60
76
  });
77
+
78
+ it('should return false if the preview does not match any of supportedExtensions values', () => {
79
+ expect(getPreviewExists({ configPath: './scripts/mocks/wrong-extension-preview' })).toBe(
80
+ false
81
+ );
82
+ });
61
83
  });
62
84
 
63
85
  describe('when using an absolute path', () => {
64
86
  it('should return true if the preview exists', () => {
65
- expect(
66
- getPreviewExists({ configPath: path.resolve(__dirname, 'mocks/all-config-files') })
67
- ).toBe(true);
87
+ supportedExtensions.forEach((ext) => {
88
+ expect(
89
+ getPreviewExists({
90
+ configPath: path.resolve(__dirname, `mocks/preview-files/${ext}`),
91
+ })
92
+ ).toBe(true);
93
+ });
68
94
  });
69
95
 
70
96
  it('should return false if the preview does not exist', () => {
@@ -72,6 +98,12 @@ describe('loader', () => {
72
98
  false
73
99
  );
74
100
  });
101
+
102
+ it('should return false if the preview does not match any of supportedExtensions values', () => {
103
+ expect(
104
+ getPreviewExists({ configPath: path.resolve(__dirname, 'mocks/wrong-extension-preview') })
105
+ ).toBe(false);
106
+ });
75
107
  });
76
108
  });
77
109
 
@@ -86,6 +118,16 @@ describe('loader', () => {
86
118
  });
87
119
  });
88
120
 
121
+ describe('when there are different file extensions', () => {
122
+ it('writes the story imports', () => {
123
+ writeRequires({ configPath: 'scripts/mocks/file-extensions' });
124
+ expect(pathMock).toEqual(
125
+ path.resolve(__dirname, 'mocks/file-extensions/storybook.requires.js')
126
+ );
127
+ expect(fileContentMock).toMatchSnapshot();
128
+ });
129
+ });
130
+
89
131
  describe('when there is a story glob and exclude paths globs', () => {
90
132
  it('writes the story imports', () => {
91
133
  writeRequires({ configPath: 'scripts/mocks/exclude-config-files' });