@nrwl/react-native 13.8.1 → 13.8.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.
Files changed (66) hide show
  1. package/executors.json +10 -0
  2. package/generators.json +36 -0
  3. package/migrations.json +41 -0
  4. package/package.json +10 -9
  5. package/src/executors/build-android/build-android.impl.js +8 -6
  6. package/src/executors/build-android/build-android.impl.js.map +1 -1
  7. package/src/executors/build-android/build-android.impl.ts +8 -10
  8. package/src/executors/storybook/compat.d.ts +2 -0
  9. package/src/executors/storybook/compat.js +6 -0
  10. package/src/executors/storybook/compat.js.map +1 -0
  11. package/src/executors/storybook/schema.d.ts +7 -0
  12. package/src/executors/storybook/schema.json +28 -0
  13. package/src/executors/storybook/storybook.impl.d.ts +5 -0
  14. package/src/executors/storybook/storybook.impl.js +63 -0
  15. package/src/executors/storybook/storybook.impl.js.map +1 -0
  16. package/src/executors/storybook/storybook.impl.ts +92 -0
  17. package/src/generators/application/files/app/android/app/build.gradle.template +1 -1
  18. package/src/generators/application/files/app/android/app/src/main/res/drawable/rn_edit_text_material.xml +29 -0
  19. package/src/generators/application/files/app/android/app/src/main/res/values/styles.xml +1 -0
  20. package/src/generators/application/files/app/android/build.gradle.template +7 -3
  21. package/src/generators/application/files/app/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  22. package/src/generators/application/files/app/android/gradle.properties +1 -1
  23. package/src/generators/application/files/app/ios/__className__.xcodeproj/project.pbxproj.template +29 -72
  24. package/src/generators/application/files/app/metro.config.js.template +1 -0
  25. package/src/generators/application/files/app/package.json.template +2 -1
  26. package/src/generators/application/files/app/src/app/App.tsx.template +1 -1
  27. package/src/generators/component-story/component-story.d.ts +8 -0
  28. package/src/generators/component-story/component-story.js +95 -0
  29. package/src/generators/component-story/component-story.js.map +1 -0
  30. package/src/generators/component-story/component-story.spec.ts +445 -0
  31. package/src/generators/component-story/files/__componentFileName__.stories.__fileExt__ +25 -0
  32. package/src/generators/component-story/schema.d.ts +4 -0
  33. package/src/generators/component-story/schema.json +25 -0
  34. package/src/generators/init/init.js +1 -1
  35. package/src/generators/init/init.js.map +1 -1
  36. package/src/generators/stories/schema.d.ts +3 -0
  37. package/src/generators/stories/schema.json +18 -0
  38. package/src/generators/stories/stories-app.spec.ts +66 -0
  39. package/src/generators/stories/stories-lib.spec.ts +86 -0
  40. package/src/generators/stories/stories.d.ts +7 -0
  41. package/src/generators/stories/stories.js +66 -0
  42. package/src/generators/stories/stories.js.map +1 -0
  43. package/src/generators/storybook-configuration/configuration.d.ts +5 -0
  44. package/src/generators/storybook-configuration/configuration.js +52 -0
  45. package/src/generators/storybook-configuration/configuration.js.map +1 -0
  46. package/src/generators/storybook-configuration/configuration.spec.ts +142 -0
  47. package/src/generators/storybook-configuration/files/app/storybook.ts.template +9 -0
  48. package/src/generators/storybook-configuration/files/app/toggle-storybook.tsx.template +114 -0
  49. package/src/generators/storybook-configuration/files/root/story-loader.js.template +13 -0
  50. package/src/generators/storybook-configuration/lib/create-storybook-files.d.ts +6 -0
  51. package/src/generators/storybook-configuration/lib/create-storybook-files.js +46 -0
  52. package/src/generators/storybook-configuration/lib/create-storybook-files.js.map +1 -0
  53. package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.d.ts +7 -0
  54. package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.js +30 -0
  55. package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.js.map +1 -0
  56. package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.spec.ts +65 -0
  57. package/src/generators/storybook-configuration/schema.d.ts +9 -0
  58. package/src/generators/storybook-configuration/schema.json +38 -0
  59. package/src/migrations/update-13-5-0/add-babel-config-root-13-5-0.js +3 -8
  60. package/src/migrations/update-13-5-0/add-babel-config-root-13-5-0.js.map +1 -1
  61. package/src/utils/format-file.d.ts +1 -0
  62. package/src/utils/format-file.js +17 -0
  63. package/src/utils/format-file.js.map +1 -0
  64. package/src/utils/versions.d.ts +9 -8
  65. package/src/utils/versions.js +11 -10
  66. package/src/utils/versions.js.map +1 -1
@@ -0,0 +1,86 @@
1
+ import { Tree } from '@nrwl/devkit';
2
+ import storiesGenerator from './stories';
3
+ import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
4
+ import applicationGenerator from '../application/application';
5
+ import { Linter } from '@nrwl/linter';
6
+ import libraryGenerator from '../library/library';
7
+ import reactNativeComponentGenerator from '../component/component';
8
+
9
+ describe('react-native:stories for libraries', () => {
10
+ let appTree: Tree;
11
+
12
+ beforeEach(async () => {
13
+ appTree = await createTestUILib('test-ui-lib');
14
+ });
15
+
16
+ it('should create the stories', async () => {
17
+ await reactNativeComponentGenerator(appTree, {
18
+ name: 'test-ui-lib',
19
+ project: 'test-ui-lib',
20
+ });
21
+ await reactNativeComponentGenerator(appTree, {
22
+ name: 'another-cmp',
23
+ project: 'test-ui-lib',
24
+ });
25
+ await storiesGenerator(appTree, {
26
+ project: 'test-ui-lib',
27
+ });
28
+
29
+ expect(
30
+ appTree.exists(
31
+ 'libs/test-ui-lib/src/lib/test-ui-lib/test-ui-lib.stories.tsx'
32
+ )
33
+ ).toBeTruthy();
34
+ expect(
35
+ appTree.exists(
36
+ 'libs/test-ui-lib/src/lib/another-cmp/another-cmp.stories.tsx'
37
+ )
38
+ ).toBeTruthy();
39
+ });
40
+
41
+ it('should ignore files that do not contain components', async () => {
42
+ await reactNativeComponentGenerator(appTree, {
43
+ name: 'test-ui-lib',
44
+ project: 'test-ui-lib',
45
+ });
46
+ // create another component
47
+ appTree.write(
48
+ 'libs/test-ui-lib/src/lib/some-utils.ts',
49
+ `export const add = (a: number, b: number) => a + b;`
50
+ );
51
+
52
+ await storiesGenerator(appTree, {
53
+ project: 'test-ui-lib',
54
+ });
55
+
56
+ // should just create the story and not error, even though there's a js file
57
+ // not containing any react component
58
+ expect(
59
+ appTree.exists(
60
+ 'libs/test-ui-lib/src/lib/test-ui-lib/test-ui-lib.stories.tsx'
61
+ )
62
+ ).toBeTruthy();
63
+ });
64
+ });
65
+
66
+ export async function createTestUILib(libName: string): Promise<Tree> {
67
+ let appTree = createTreeWithEmptyWorkspace();
68
+ appTree.write('.gitignore', '');
69
+
70
+ await libraryGenerator(appTree, {
71
+ linter: Linter.EsLint,
72
+ skipFormat: true,
73
+ skipTsConfig: false,
74
+ unitTestRunner: 'none',
75
+ name: libName,
76
+ });
77
+
78
+ await applicationGenerator(appTree, {
79
+ e2eTestRunner: 'none',
80
+ linter: Linter.EsLint,
81
+ skipFormat: false,
82
+ unitTestRunner: 'none',
83
+ name: `${libName}-e2e`,
84
+ });
85
+ return appTree;
86
+ }
@@ -0,0 +1,7 @@
1
+ import { ProjectType, Tree } from '@nrwl/devkit';
2
+ import { StorybookStoriesSchema } from './schema';
3
+ export declare function projectRootPath(tree: Tree, sourceRoot: string, projectType: ProjectType): string;
4
+ export declare function createAllStories(tree: Tree, projectName: string): Promise<void>;
5
+ export declare function storiesGenerator(host: Tree, schema: StorybookStoriesSchema): Promise<void>;
6
+ export default storiesGenerator;
7
+ export declare const storiesSchematic: (options: StorybookStoriesSchema) => (tree: any, context: any) => Promise<any>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.storiesSchematic = exports.storiesGenerator = exports.createAllStories = exports.projectRootPath = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const ast_utils_1 = require("@nrwl/react/src/utils/ast-utils");
6
+ const ts = require("typescript");
7
+ const devkit_1 = require("@nrwl/devkit");
8
+ const path_1 = require("path");
9
+ const component_story_1 = require("../component-story/component-story");
10
+ function projectRootPath(tree, sourceRoot, projectType) {
11
+ let projectDir = '';
12
+ if (projectType === 'application') {
13
+ // apps/test-app/src/app
14
+ projectDir = 'app';
15
+ }
16
+ else if (projectType == 'library') {
17
+ // libs/test-lib/src/lib
18
+ projectDir = 'lib';
19
+ }
20
+ return (0, devkit_1.joinPathFragments)(sourceRoot, projectDir);
21
+ }
22
+ exports.projectRootPath = projectRootPath;
23
+ function containsComponentDeclaration(tree, componentPath) {
24
+ const contents = tree.read(componentPath, 'utf-8');
25
+ if (contents === null) {
26
+ throw new Error(`Failed to read ${componentPath}`);
27
+ }
28
+ const sourceFile = ts.createSourceFile(componentPath, contents, ts.ScriptTarget.Latest, true);
29
+ return !!(0, ast_utils_1.getComponentName)(sourceFile);
30
+ }
31
+ function createAllStories(tree, projectName) {
32
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
33
+ const projects = (0, devkit_1.getProjects)(tree);
34
+ const project = projects.get(projectName);
35
+ const { sourceRoot, projectType } = project;
36
+ const projectPath = projectRootPath(tree, sourceRoot, projectType);
37
+ let componentPaths = [];
38
+ (0, devkit_1.visitNotIgnoredFiles)(tree, projectPath, (path) => {
39
+ if ((path.endsWith('.tsx') && !path.endsWith('.spec.tsx')) ||
40
+ (path.endsWith('.js') && !path.endsWith('.spec.js')) ||
41
+ (path.endsWith('.jsx') && !path.endsWith('.spec.jsx'))) {
42
+ componentPaths.push(path);
43
+ }
44
+ });
45
+ yield Promise.all(componentPaths.map((componentPath) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
46
+ const relativeCmpDir = componentPath.replace((0, path_1.join)(sourceRoot, '/'), '');
47
+ if (!containsComponentDeclaration(tree, componentPath)) {
48
+ return;
49
+ }
50
+ yield (0, component_story_1.default)(tree, {
51
+ componentPath: relativeCmpDir,
52
+ project: projectName,
53
+ });
54
+ })));
55
+ });
56
+ }
57
+ exports.createAllStories = createAllStories;
58
+ function storiesGenerator(host, schema) {
59
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
60
+ yield createAllStories(host, schema.project);
61
+ });
62
+ }
63
+ exports.storiesGenerator = storiesGenerator;
64
+ exports.default = storiesGenerator;
65
+ exports.storiesSchematic = (0, devkit_1.convertNxGenerator)(storiesGenerator);
66
+ //# sourceMappingURL=stories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stories.js","sourceRoot":"","sources":["../../../../../../packages/react-native/src/generators/stories/stories.ts"],"names":[],"mappings":";;;;AAAA,+DAAmE;AACnE,iCAAiC;AACjC,yCAOsB;AACtB,+BAA4B;AAE5B,wEAAyE;AAGzE,SAAgB,eAAe,CAC7B,IAAU,EACV,UAAkB,EAClB,WAAwB;IAExB,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,WAAW,KAAK,aAAa,EAAE;QACjC,wBAAwB;QACxB,UAAU,GAAG,KAAK,CAAC;KACpB;SAAM,IAAI,WAAW,IAAI,SAAS,EAAE;QACnC,wBAAwB;QACxB,UAAU,GAAG,KAAK,CAAC;KACpB;IAED,OAAO,IAAA,0BAAiB,EAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACnD,CAAC;AAfD,0CAeC;AAED,SAAS,4BAA4B,CACnC,IAAU,EACV,aAAqB;IAErB,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACnD,IAAI,QAAQ,KAAK,IAAI,EAAE;QACrB,MAAM,IAAI,KAAK,CAAC,kBAAkB,aAAa,EAAE,CAAC,CAAC;KACpD;IAED,MAAM,UAAU,GAAG,EAAE,CAAC,gBAAgB,CACpC,aAAa,EACb,QAAQ,EACR,EAAE,CAAC,YAAY,CAAC,MAAM,EACtB,IAAI,CACL,CAAC;IAEF,OAAO,CAAC,CAAC,IAAA,4BAAgB,EAAC,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,SAAsB,gBAAgB,CAAC,IAAU,EAAE,WAAmB;;QACpE,MAAM,QAAQ,GAAG,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAE1C,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;QAC5C,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;QAEnE,IAAI,cAAc,GAAa,EAAE,CAAC;QAClC,IAAA,6BAAoB,EAAC,IAAI,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE;YAC/C,IACE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;gBACtD,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;gBACpD,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EACtD;gBACA,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aAC3B;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,CAAC,GAAG,CACf,cAAc,CAAC,GAAG,CAAC,CAAO,aAAa,EAAE,EAAE;YACzC,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,IAAA,WAAI,EAAC,UAAU,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YAExE,IAAI,CAAC,4BAA4B,CAAC,IAAI,EAAE,aAAa,CAAC,EAAE;gBACtD,OAAO;aACR;YAED,MAAM,IAAA,yBAAuB,EAAC,IAAI,EAAE;gBAClC,aAAa,EAAE,cAAc;gBAC7B,OAAO,EAAE,WAAW;aACrB,CAAC,CAAC;QACL,CAAC,CAAA,CAAC,CACH,CAAC;IACJ,CAAC;CAAA;AAhCD,4CAgCC;AAED,SAAsB,gBAAgB,CACpC,IAAU,EACV,MAA8B;;QAE9B,MAAM,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/C,CAAC;CAAA;AALD,4CAKC;AAED,kBAAe,gBAAgB,CAAC;AACnB,QAAA,gBAAgB,GAAG,IAAA,2BAAkB,EAAC,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { GeneratorCallback, Tree } from '@nrwl/devkit';
2
+ import { StorybookConfigureSchema } from './schema';
3
+ export declare function storybookConfigurationGenerator(host: Tree, schema: StorybookConfigureSchema): Promise<GeneratorCallback>;
4
+ export default storybookConfigurationGenerator;
5
+ export declare const storybookConfigurationSchematic: (options: StorybookConfigureSchema) => (tree: any, context: any) => Promise<any>;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.storybookConfigurationSchematic = exports.storybookConfigurationGenerator = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nrwl/devkit");
6
+ const storybook_1 = require("@nrwl/storybook");
7
+ const stories_1 = require("../stories/stories");
8
+ const create_storybook_files_1 = require("./lib/create-storybook-files");
9
+ const replace_app_import_with_storybook_toggle_1 = require("./lib/replace-app-import-with-storybook-toggle");
10
+ function generateStories(host, schema) {
11
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
12
+ yield (0, stories_1.default)(host, {
13
+ project: schema.name,
14
+ });
15
+ });
16
+ }
17
+ function storybookConfigurationGenerator(host, schema) {
18
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
19
+ const installTask = yield (0, storybook_1.configurationGenerator)(host, {
20
+ name: schema.name,
21
+ uiFramework: '@storybook/react-native',
22
+ configureCypress: false,
23
+ js: false,
24
+ linter: schema.linter,
25
+ standaloneConfig: schema.standaloneConfig,
26
+ });
27
+ addStorybookTask(host, schema.name);
28
+ (0, create_storybook_files_1.createStorybookFiles)(host, schema);
29
+ (0, replace_app_import_with_storybook_toggle_1.replaceAppImportWithStorybookToggle)(host, schema);
30
+ if (schema.generateStories) {
31
+ yield generateStories(host, schema);
32
+ }
33
+ return installTask;
34
+ });
35
+ }
36
+ exports.storybookConfigurationGenerator = storybookConfigurationGenerator;
37
+ function addStorybookTask(host, projectName) {
38
+ const projectConfig = (0, devkit_1.readProjectConfiguration)(host, projectName);
39
+ projectConfig.targets['storybook'] = {
40
+ executor: '@nrwl/react-native:storybook',
41
+ options: {
42
+ searchDir: projectConfig.root,
43
+ outputFile: './.storybook/story-loader.js',
44
+ pattern: '**/*.stories.@(js|jsx|ts|tsx|md)',
45
+ silent: false,
46
+ },
47
+ };
48
+ (0, devkit_1.updateProjectConfiguration)(host, projectName, projectConfig);
49
+ }
50
+ exports.default = storybookConfigurationGenerator;
51
+ exports.storybookConfigurationSchematic = (0, devkit_1.convertNxGenerator)(storybookConfigurationGenerator);
52
+ //# sourceMappingURL=configuration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration.js","sourceRoot":"","sources":["../../../../../../packages/react-native/src/generators/storybook-configuration/configuration.ts"],"names":[],"mappings":";;;;AAAA,yCAMsB;AACtB,+CAAyD;AAEzD,gDAAkD;AAClD,yEAAoE;AACpE,6GAAqG;AAIrG,SAAe,eAAe,CAAC,IAAU,EAAE,MAAgC;;QACzE,MAAM,IAAA,iBAAgB,EAAC,IAAI,EAAE;YAC3B,OAAO,EAAE,MAAM,CAAC,IAAI;SACrB,CAAC,CAAC;IACL,CAAC;CAAA;AAED,SAAsB,+BAA+B,CACnD,IAAU,EACV,MAAgC;;QAEhC,MAAM,WAAW,GAAG,MAAM,IAAA,kCAAsB,EAAC,IAAI,EAAE;YACrD,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,WAAW,EAAE,yBAAyB;YACtC,gBAAgB,EAAE,KAAK;YACvB,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;SAC1C,CAAC,CAAC;QAEH,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACpC,IAAA,6CAAoB,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACnC,IAAA,8EAAmC,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAElD,IAAI,MAAM,CAAC,eAAe,EAAE;YAC1B,MAAM,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;SACrC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;CAAA;AAtBD,0EAsBC;AAED,SAAS,gBAAgB,CAAC,IAAU,EAAE,WAAmB;IACvD,MAAM,aAAa,GAAG,IAAA,iCAAwB,EAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAClE,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG;QACnC,QAAQ,EAAE,8BAA8B;QACxC,OAAO,EAAE;YACP,SAAS,EAAE,aAAa,CAAC,IAAI;YAC7B,UAAU,EAAE,8BAA8B;YAC1C,OAAO,EAAE,kCAAkC;YAC3C,MAAM,EAAE,KAAK;SACd;KACF,CAAC;IAEF,IAAA,mCAA0B,EAAC,IAAI,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AAC/D,CAAC;AAED,kBAAe,+BAA+B,CAAC;AAClC,QAAA,+BAA+B,GAAG,IAAA,2BAAkB,EAC/D,+BAA+B,CAChC,CAAC"}
@@ -0,0 +1,142 @@
1
+ import * as fileUtils from '@nrwl/workspace/src/core/file-utils';
2
+ import { Tree } from '@nrwl/devkit';
3
+ import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
4
+ import { Linter } from '@nrwl/linter';
5
+ import { logger } from '@nrwl/devkit';
6
+
7
+ import libraryGenerator from '../library/library';
8
+ import applicationGenerator from '../application/application';
9
+ import componentGenerator from '../component/component';
10
+ import storybookConfigurationGenerator from './configuration';
11
+
12
+ describe('react-native:storybook-configuration', () => {
13
+ let appTree;
14
+
15
+ beforeEach(async () => {
16
+ jest.spyOn(fileUtils, 'readPackageJson').mockReturnValue({
17
+ devDependencies: {
18
+ '@storybook/addon-essentials': '*',
19
+ '@storybook/react-native': '*',
20
+ '@storybook/addon-ondevice-actions': '*',
21
+ '@storybook/addon-ondevice-knobs': '*',
22
+ },
23
+ });
24
+
25
+ jest.spyOn(logger, 'warn').mockImplementation(() => {});
26
+ jest.spyOn(logger, 'debug').mockImplementation(() => {});
27
+ });
28
+
29
+ afterEach(() => {
30
+ jest.restoreAllMocks();
31
+ });
32
+
33
+ describe('should generate files for an app', () => {
34
+ it('should configure everything at once', async () => {
35
+ appTree = await createTestUILib('test-ui-lib');
36
+ appTree.write('.gitignore', '');
37
+ await storybookConfigurationGenerator(appTree, {
38
+ name: 'test-ui-lib',
39
+ standaloneConfig: false,
40
+ });
41
+
42
+ expect(
43
+ appTree.exists('libs/test-ui-lib/.storybook/main.js')
44
+ ).toBeTruthy();
45
+ expect(
46
+ appTree.exists('libs/test-ui-lib/.storybook/tsconfig.json')
47
+ ).toBeTruthy();
48
+ });
49
+
50
+ it('should generate stories for components', async () => {
51
+ appTree = await createTestUILib('test-ui-lib');
52
+ await componentGenerator(appTree, {
53
+ name: 'test-ui-lib',
54
+ project: 'test-ui-lib',
55
+ });
56
+ await storybookConfigurationGenerator(appTree, {
57
+ name: 'test-ui-lib',
58
+ generateStories: true,
59
+ standaloneConfig: false,
60
+ });
61
+
62
+ expect(
63
+ appTree.exists(
64
+ 'libs/test-ui-lib/src/lib/test-ui-lib/test-ui-lib.stories.tsx'
65
+ )
66
+ ).toBeTruthy();
67
+ });
68
+ });
69
+
70
+ describe('should generate files for lib', () => {
71
+ it('should configure everything at once', async () => {
72
+ appTree = await createTestAppLib('test-ui-app');
73
+ await storybookConfigurationGenerator(appTree, {
74
+ name: 'test-ui-app',
75
+ standaloneConfig: false,
76
+ });
77
+
78
+ expect(
79
+ appTree.exists('apps/test-ui-app/.storybook/main.js')
80
+ ).toBeTruthy();
81
+ expect(
82
+ appTree.exists('apps/test-ui-app/.storybook/tsconfig.json')
83
+ ).toBeTruthy();
84
+ });
85
+
86
+ it('should generate stories for components', async () => {
87
+ appTree = await createTestAppLib('test-ui-app');
88
+ await storybookConfigurationGenerator(appTree, {
89
+ name: 'test-ui-app',
90
+ generateStories: true,
91
+ standaloneConfig: false,
92
+ });
93
+
94
+ // Currently the auto-generate stories feature only picks up components under the 'lib' directory.
95
+ // In our 'createTestAppLib' function, we call @nrwl/react-native:component to generate a component
96
+ // under the specified 'lib' directory
97
+ expect(
98
+ appTree.exists(
99
+ 'apps/test-ui-app/src/app/my-component/my-component.stories.tsx'
100
+ )
101
+ ).toBeTruthy();
102
+ });
103
+ });
104
+ });
105
+
106
+ export async function createTestUILib(libName: string): Promise<Tree> {
107
+ let appTree = createTreeWithEmptyWorkspace();
108
+
109
+ await libraryGenerator(appTree, {
110
+ linter: Linter.EsLint,
111
+ skipFormat: true,
112
+ skipTsConfig: false,
113
+ unitTestRunner: 'none',
114
+ name: libName,
115
+ });
116
+ return appTree;
117
+ }
118
+
119
+ export async function createTestAppLib(
120
+ libName: string,
121
+ plainJS = false
122
+ ): Promise<Tree> {
123
+ let appTree = createTreeWithEmptyWorkspace();
124
+
125
+ await applicationGenerator(appTree, {
126
+ e2eTestRunner: 'none',
127
+ linter: Linter.EsLint,
128
+ skipFormat: false,
129
+ style: 'css',
130
+ unitTestRunner: 'none',
131
+ name: libName,
132
+ js: plainJS,
133
+ });
134
+
135
+ await componentGenerator(appTree, {
136
+ name: 'my-component',
137
+ project: libName,
138
+ directory: 'app',
139
+ });
140
+
141
+ return appTree;
142
+ }
@@ -0,0 +1,9 @@
1
+ import { configure, getStorybookUI } from '@storybook/react-native';
2
+
3
+ import { loadStories } from '../../../.storybook/story-loader';
4
+
5
+ configure(loadStories(), module, false);
6
+
7
+ const StorybookUIRoot = getStorybookUI({});
8
+
9
+ export default StorybookUIRoot;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Toggle inspired from https://github.com/infinitered/ignite/blob/master/boilerplate/storybook/toggle-storybook.tsx
3
+ */
4
+ import React, { useState, useEffect, useRef } from 'react';
5
+ import { DevSettings } from 'react-native';
6
+ import AsyncStorage from '@react-native-async-storage/async-storage';
7
+
8
+ import AppRoot from '../src/app/App';
9
+
10
+ export const DEFAULT_REACTOTRON_WS_URI = 'ws://localhost:9090';
11
+
12
+ /**
13
+ * Loads a string from storage.
14
+ *
15
+ * @param key The key to fetch.
16
+ */
17
+ async function loadString(key: string): Promise<string | null> {
18
+ try {
19
+ return await AsyncStorage.getItem(key);
20
+ } catch {
21
+ // not sure why this would fail... even reading the RN docs I'm unclear
22
+ return null;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Saves a string to storage.
28
+ *
29
+ * @param key The key to fetch.
30
+ * @param value The value to store.
31
+ */
32
+ async function saveString(key: string, value: string): Promise<boolean> {
33
+ try {
34
+ await AsyncStorage.setItem(key, value);
35
+ return true;
36
+ } catch {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Toggle Storybook mode, in __DEV__ mode only.
43
+ *
44
+ * In non-__DEV__ mode, or when Storybook isn't toggled on,
45
+ * renders its children.
46
+ *
47
+ * The mode flag is persisted in async storage, which means it
48
+ * persists across reloads/restarts - this is handy when developing
49
+ * new components in Storybook.
50
+ */
51
+ function ToggleStorybook(props) {
52
+ const [showStorybook, setShowStorybook] = useState(false);
53
+ const [StorybookUIRoot, setStorybookUIRoot] = useState(null);
54
+ const ws = useRef(new WebSocket(DEFAULT_REACTOTRON_WS_URI));
55
+
56
+ useEffect(() => {
57
+ if (!__DEV__) {
58
+ return undefined;
59
+ }
60
+
61
+ // Load the setting from storage if it's there
62
+ loadString('devStorybook').then((storedSetting) => {
63
+ // Set the initial value
64
+ setShowStorybook(storedSetting === 'on');
65
+
66
+ if (DevSettings) {
67
+ // Add our toggle command to the menu
68
+ DevSettings.addMenuItem('Toggle Storybook', () => {
69
+ setShowStorybook((show) => {
70
+ // On toggle, flip the current value
71
+ show = !show;
72
+
73
+ // Write it back to storage
74
+ saveString('devStorybook', show ? 'on' : 'off');
75
+
76
+ // Return it to change the local state
77
+ return show;
78
+ });
79
+ });
80
+ }
81
+
82
+ // Load the storybook UI once
83
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
84
+ setStorybookUIRoot(() => require('./storybook.ts').default);
85
+
86
+ // Behave as Reactotron.storybookSwitcher(), not a HOC way.
87
+ ws.current.onmessage = (e) => {
88
+ const data = JSON.parse(e.data);
89
+
90
+ if (data.type === 'storybook') {
91
+ saveString('devStorybook', data.payload ? 'on' : 'off');
92
+ setShowStorybook(data.payload);
93
+ }
94
+ };
95
+ ws.current.onerror = (e) => {
96
+ setShowStorybook(storedSetting === 'on');
97
+ };
98
+ });
99
+ }, []);
100
+
101
+ if (showStorybook) {
102
+ return StorybookUIRoot ? <StorybookUIRoot /> : null;
103
+ } else {
104
+ return props.children;
105
+ }
106
+ }
107
+
108
+ export default () => {
109
+ return (
110
+ <ToggleStorybook>
111
+ <AppRoot />
112
+ </ToggleStorybook>
113
+ );
114
+ };
@@ -0,0 +1,13 @@
1
+ // Auto-generated file created by react-native-storybook-loader
2
+ // Do not edit.
3
+ //
4
+ // https://github.com/elderfo/react-native-storybook-loader.git
5
+
6
+ function loadStories() {}
7
+
8
+ const stories = [];
9
+
10
+ module.exports = {
11
+ loadStories,
12
+ stories,
13
+ };
@@ -0,0 +1,6 @@
1
+ import { Tree } from '@nrwl/devkit';
2
+ import { StorybookConfigureSchema } from '../schema';
3
+ /**
4
+ * This function generate ./storybook under project root.
5
+ */
6
+ export declare function createStorybookFiles(host: Tree, schema: StorybookConfigureSchema): Promise<void>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createStorybookFiles = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nrwl/devkit");
6
+ const path_1 = require("path");
7
+ const chalk = require("chalk");
8
+ /**
9
+ * This function generate ./storybook under project root.
10
+ */
11
+ function createStorybookFiles(host, schema) {
12
+ var _a;
13
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
14
+ const { root, projectType, targets, sourceRoot } = (0, devkit_1.readProjectConfiguration)(host, schema.name);
15
+ // do not proceed if not a react native project
16
+ if (((_a = targets === null || targets === void 0 ? void 0 : targets.start) === null || _a === void 0 ? void 0 : _a.executor) !== '@nrwl/react-native:start') {
17
+ return;
18
+ }
19
+ const storybookUIFileName = schema.js ? 'storybook.js' : 'storybook.ts';
20
+ const storybookUIFilePath = (0, path_1.join)(root, `./${storybookUIFileName}`);
21
+ if (host.exists(storybookUIFilePath)) {
22
+ devkit_1.logger.warn(`${storybookUIFileName} file already exists for React Native ${projectType} ${schema.name}! Skipping generating this file.`);
23
+ return;
24
+ }
25
+ if (projectType !== 'application') {
26
+ devkit_1.logger.info(`${chalk.bold.cyan('info')} To see your Storybook stories on the device, you should start your mobile app for the <platform> of your choice (typically ios or android).`);
27
+ }
28
+ const projectDirectory = projectType === 'application' ? 'app' : 'lib';
29
+ devkit_1.logger.debug(`Adding storybook file to React Native app ${projectDirectory}`);
30
+ // copy files to app's .storybook folder
31
+ (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/app'), (0, path_1.join)(root, '.storybook'), {
32
+ tmpl: '',
33
+ offsetFromRoot: (0, devkit_1.offsetFromRoot)(sourceRoot),
34
+ projectType: projectDirectory,
35
+ });
36
+ // copy files to workspace root's .storybook folder
37
+ (0, devkit_1.generateFiles)(host, (0, path_1.join)(__dirname, '../files/root'), (0, path_1.join)(root, (0, devkit_1.offsetFromRoot)(root), '.storybook'), {
38
+ tmpl: '',
39
+ });
40
+ if (schema.js) {
41
+ (0, devkit_1.toJS)(host);
42
+ }
43
+ });
44
+ }
45
+ exports.createStorybookFiles = createStorybookFiles;
46
+ //# sourceMappingURL=create-storybook-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-storybook-files.js","sourceRoot":"","sources":["../../../../../../../packages/react-native/src/generators/storybook-configuration/lib/create-storybook-files.ts"],"names":[],"mappings":";;;;AAAA,yCAOsB;AACtB,+BAA4B;AAC5B,+BAA+B;AAI/B;;GAEG;AACH,SAAsB,oBAAoB,CACxC,IAAU,EACV,MAAgC;;;QAEhC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,IAAA,iCAAwB,EACzE,IAAI,EACJ,MAAM,CAAC,IAAI,CACZ,CAAC;QAEF,+CAA+C;QAC/C,IAAI,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,0CAAE,QAAQ,MAAK,0BAA0B,EAAE;YAC3D,OAAO;SACR;QAED,MAAM,mBAAmB,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC;QACxE,MAAM,mBAAmB,GAAG,IAAA,WAAI,EAAC,IAAI,EAAE,KAAK,mBAAmB,EAAE,CAAC,CAAC;QAEnE,IAAI,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE;YACpC,eAAM,CAAC,IAAI,CACT,GAAG,mBAAmB,yCAAyC,WAAW,IAAI,MAAM,CAAC,IAAI,kCAAkC,CAC5H,CAAC;YACF,OAAO;SACR;QACD,IAAI,WAAW,KAAK,aAAa,EAAE;YACjC,eAAM,CAAC,IAAI,CACT,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAChB,MAAM,CACP,8IAA8I,CAChJ,CAAC;SACH;QAED,MAAM,gBAAgB,GAAG,WAAW,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAEvE,eAAM,CAAC,KAAK,CAAC,6CAA6C,gBAAgB,EAAE,CAAC,CAAC;QAE9E,wCAAwC;QACxC,IAAA,sBAAa,EACX,IAAI,EACJ,IAAA,WAAI,EAAC,SAAS,EAAE,cAAc,CAAC,EAC/B,IAAA,WAAI,EAAC,IAAI,EAAE,YAAY,CAAC,EACxB;YACE,IAAI,EAAE,EAAE;YACR,cAAc,EAAE,IAAA,uBAAc,EAAC,UAAU,CAAC;YAC1C,WAAW,EAAE,gBAAgB;SAC9B,CACF,CAAC;QAEF,mDAAmD;QACnD,IAAA,sBAAa,EACX,IAAI,EACJ,IAAA,WAAI,EAAC,SAAS,EAAE,eAAe,CAAC,EAChC,IAAA,WAAI,EAAC,IAAI,EAAE,IAAA,uBAAc,EAAC,IAAI,CAAC,EAAE,YAAY,CAAC,EAC9C;YACE,IAAI,EAAE,EAAE;SACT,CACF,CAAC;QAEF,IAAI,MAAM,CAAC,EAAE,EAAE;YACb,IAAA,aAAI,EAAC,IAAI,CAAC,CAAC;SACZ;;CACF;AA5DD,oDA4DC"}
@@ -0,0 +1,7 @@
1
+ import { Tree } from '@nrwl/devkit';
2
+ import { StorybookConfigureSchema } from '../schema';
3
+ /**
4
+ * To replace the import statement for storybook.
5
+ * Need to import app with storybook toggle from .storybook/toggle-storybook
6
+ */
7
+ export declare function replaceAppImportWithStorybookToggle(host: Tree, schema: StorybookConfigureSchema): void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.replaceAppImportWithStorybookToggle = void 0;
4
+ const devkit_1 = require("@nrwl/devkit");
5
+ const path_1 = require("path");
6
+ /**
7
+ * To replace the import statement for storybook.
8
+ * Need to import app with storybook toggle from .storybook/toggle-storybook
9
+ */
10
+ function replaceAppImportWithStorybookToggle(host, schema) {
11
+ const { root, sourceRoot } = (0, devkit_1.readProjectConfiguration)(host, schema.name);
12
+ const mainFilePath = (0, path_1.join)(sourceRoot, schema.js ? 'main.js' : 'main.tsx');
13
+ const appImportImport = `import App from './app/App';`;
14
+ const storybookeToggleImport = `import App from '../.storybook/toggle-storybook';`;
15
+ try {
16
+ devkit_1.logger.debug(`Updating import for ${mainFilePath}`);
17
+ const contents = host.read(mainFilePath, 'utf-8');
18
+ if (!contents.includes(appImportImport) ||
19
+ contents.includes(storybookeToggleImport)) {
20
+ devkit_1.logger.warn((0, devkit_1.stripIndents) `${mainFilePath} is already udpated.`);
21
+ return;
22
+ }
23
+ host.write(mainFilePath, contents.replace(appImportImport, storybookeToggleImport));
24
+ }
25
+ catch (_a) {
26
+ devkit_1.logger.warn((0, devkit_1.stripIndents) `Unable to update import in ${mainFilePath} for project ${root}.`);
27
+ }
28
+ }
29
+ exports.replaceAppImportWithStorybookToggle = replaceAppImportWithStorybookToggle;
30
+ //# sourceMappingURL=replace-app-import-with-storybook-toggle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replace-app-import-with-storybook-toggle.js","sourceRoot":"","sources":["../../../../../../../packages/react-native/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.ts"],"names":[],"mappings":";;;AAAA,yCAKsB;AACtB,+BAA4B;AAI5B;;;GAGG;AACH,SAAgB,mCAAmC,CACjD,IAAU,EACV,MAAgC;IAEhC,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,IAAA,iCAAwB,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAEzE,MAAM,YAAY,GAAG,IAAA,WAAI,EAAC,UAAU,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC1E,MAAM,eAAe,GAAG,8BAA8B,CAAC;IACvD,MAAM,sBAAsB,GAAG,mDAAmD,CAAC;IAEnF,IAAI;QACF,eAAM,CAAC,KAAK,CAAC,uBAAuB,YAAY,EAAE,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAClD,IACE,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC;YACnC,QAAQ,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EACzC;YACA,eAAM,CAAC,IAAI,CAAC,IAAA,qBAAY,EAAA,GAAG,YAAY,sBAAsB,CAAC,CAAC;YAC/D,OAAO;SACR;QACD,IAAI,CAAC,KAAK,CACR,YAAY,EACZ,QAAQ,CAAC,OAAO,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAC1D,CAAC;KACH;IAAC,WAAM;QACN,eAAM,CAAC,IAAI,CACT,IAAA,qBAAY,EAAA,8BAA8B,YAAY,gBAAgB,IAAI,GAAG,CAC9E,CAAC;KACH;AACH,CAAC;AA7BD,kFA6BC"}