@nrwl/react-native 13.8.1 → 13.8.4-beta.0
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/executors.json +10 -0
- package/generators.json +36 -0
- package/migrations.json +41 -0
- package/package.json +10 -9
- package/src/executors/build-android/build-android.impl.js +8 -6
- package/src/executors/build-android/build-android.impl.js.map +1 -1
- package/src/executors/build-android/build-android.impl.ts +8 -10
- package/src/executors/storybook/compat.d.ts +2 -0
- package/src/executors/storybook/compat.js +6 -0
- package/src/executors/storybook/compat.js.map +1 -0
- package/src/executors/storybook/schema.d.ts +7 -0
- package/src/executors/storybook/schema.json +28 -0
- package/src/executors/storybook/storybook.impl.d.ts +5 -0
- package/src/executors/storybook/storybook.impl.js +63 -0
- package/src/executors/storybook/storybook.impl.js.map +1 -0
- package/src/executors/storybook/storybook.impl.ts +92 -0
- package/src/generators/application/files/app/android/app/build.gradle.template +1 -1
- package/src/generators/application/files/app/android/app/src/main/res/drawable/rn_edit_text_material.xml +29 -0
- package/src/generators/application/files/app/android/app/src/main/res/values/styles.xml +1 -0
- package/src/generators/application/files/app/android/build.gradle.template +7 -3
- package/src/generators/application/files/app/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/src/generators/application/files/app/android/gradle.properties +1 -1
- package/src/generators/application/files/app/ios/__className__.xcodeproj/project.pbxproj.template +29 -72
- package/src/generators/application/files/app/metro.config.js.template +1 -0
- package/src/generators/application/files/app/package.json.template +2 -1
- package/src/generators/application/files/app/src/app/App.tsx.template +1 -1
- package/src/generators/component-story/component-story.d.ts +8 -0
- package/src/generators/component-story/component-story.js +95 -0
- package/src/generators/component-story/component-story.js.map +1 -0
- package/src/generators/component-story/component-story.spec.ts +445 -0
- package/src/generators/component-story/files/__componentFileName__.stories.__fileExt__ +25 -0
- package/src/generators/component-story/schema.d.ts +4 -0
- package/src/generators/component-story/schema.json +25 -0
- package/src/generators/init/init.js +1 -1
- package/src/generators/init/init.js.map +1 -1
- package/src/generators/stories/schema.d.ts +3 -0
- package/src/generators/stories/schema.json +18 -0
- package/src/generators/stories/stories-app.spec.ts +66 -0
- package/src/generators/stories/stories-lib.spec.ts +86 -0
- package/src/generators/stories/stories.d.ts +7 -0
- package/src/generators/stories/stories.js +66 -0
- package/src/generators/stories/stories.js.map +1 -0
- package/src/generators/storybook-configuration/configuration.d.ts +5 -0
- package/src/generators/storybook-configuration/configuration.js +52 -0
- package/src/generators/storybook-configuration/configuration.js.map +1 -0
- package/src/generators/storybook-configuration/configuration.spec.ts +142 -0
- package/src/generators/storybook-configuration/files/app/storybook.ts.template +9 -0
- package/src/generators/storybook-configuration/files/app/toggle-storybook.tsx.template +114 -0
- package/src/generators/storybook-configuration/files/root/story-loader.js.template +13 -0
- package/src/generators/storybook-configuration/lib/create-storybook-files.d.ts +6 -0
- package/src/generators/storybook-configuration/lib/create-storybook-files.js +46 -0
- package/src/generators/storybook-configuration/lib/create-storybook-files.js.map +1 -0
- package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.d.ts +7 -0
- package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.js +30 -0
- package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.js.map +1 -0
- package/src/generators/storybook-configuration/lib/replace-app-import-with-storybook-toggle.spec.ts +65 -0
- package/src/generators/storybook-configuration/schema.d.ts +9 -0
- package/src/generators/storybook-configuration/schema.json +38 -0
- package/src/migrations/update-13-5-0/add-babel-config-root-13-5-0.js +3 -8
- package/src/migrations/update-13-5-0/add-babel-config-root-13-5-0.js.map +1 -1
- package/src/utils/format-file.d.ts +1 -0
- package/src/utils/format-file.js +17 -0
- package/src/utils/format-file.js.map +1 -0
- package/src/utils/versions.d.ts +9 -8
- package/src/utils/versions.js +11 -10
- package/src/utils/versions.js.map +1 -1
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import { getProjects, Tree, updateProjectConfiguration } from '@nrwl/devkit';
|
|
2
|
+
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
|
3
|
+
import componentStoryGenerator from './component-story';
|
|
4
|
+
import { Linter } from '@nrwl/linter';
|
|
5
|
+
|
|
6
|
+
import { formatFile } from '../../utils/format-file';
|
|
7
|
+
import libraryGenerator from '../library/library';
|
|
8
|
+
import componentGenerator from '../component/component';
|
|
9
|
+
|
|
10
|
+
describe('react-native:component-story', () => {
|
|
11
|
+
let appTree: Tree;
|
|
12
|
+
let cmpPath = 'libs/test-ui-lib/src/lib/test-ui-lib/test-ui-lib.tsx';
|
|
13
|
+
let storyFilePath =
|
|
14
|
+
'libs/test-ui-lib/src/lib/test-ui-lib/test-ui-lib.stories.tsx';
|
|
15
|
+
|
|
16
|
+
describe('default setup', () => {
|
|
17
|
+
beforeEach(async () => {
|
|
18
|
+
appTree = await createTestUILib('test-ui-lib', true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('when file does not contain a component', () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
appTree.write(
|
|
24
|
+
cmpPath,
|
|
25
|
+
`export const add = (a: number, b: number) => a + b;`
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should fail with a descriptive error message', async () => {
|
|
30
|
+
try {
|
|
31
|
+
await componentStoryGenerator(appTree, {
|
|
32
|
+
componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
|
|
33
|
+
project: 'test-ui-lib',
|
|
34
|
+
});
|
|
35
|
+
} catch (e) {
|
|
36
|
+
expect(e.message).toContain(
|
|
37
|
+
'Could not find any React Native component in file libs/test-ui-lib/src/lib/test-ui-lib/test-ui-lib.tsx'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('default component setup', () => {
|
|
44
|
+
beforeEach(async () => {
|
|
45
|
+
await componentStoryGenerator(appTree, {
|
|
46
|
+
componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
|
|
47
|
+
project: 'test-ui-lib',
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should create the story file', () => {
|
|
52
|
+
expect(appTree.exists(storyFilePath)).toBeTruthy();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should properly set up the story', () => {
|
|
56
|
+
expect(
|
|
57
|
+
formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
|
|
58
|
+
).toContain(formatFile`
|
|
59
|
+
import { storiesOf } from '@storybook/react-native';
|
|
60
|
+
import React from 'react';
|
|
61
|
+
import { TestUiLib, TestUiLibProps } from './test-ui-lib';
|
|
62
|
+
const props: TestUiLibProps = {};
|
|
63
|
+
storiesOf('TestUiLib', module)
|
|
64
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
65
|
+
.add('Primary', () => <TestUiLib {...props} />);
|
|
66
|
+
`);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('when using plain JS components', () => {
|
|
71
|
+
let storyFilePathPlain =
|
|
72
|
+
'libs/test-ui-lib/src/lib/test-ui-libplain.stories.jsx';
|
|
73
|
+
|
|
74
|
+
beforeEach(async () => {
|
|
75
|
+
appTree.write(
|
|
76
|
+
'libs/test-ui-lib/src/lib/test-ui-libplain.jsx',
|
|
77
|
+
`import React from 'react';
|
|
78
|
+
|
|
79
|
+
import './test.scss';
|
|
80
|
+
|
|
81
|
+
export const Test = () => {
|
|
82
|
+
return (
|
|
83
|
+
<div>
|
|
84
|
+
<h1>Welcome to test component</h1>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default Test;
|
|
90
|
+
`
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
await componentStoryGenerator(appTree, {
|
|
94
|
+
componentPath: 'lib/test-ui-libplain.jsx',
|
|
95
|
+
project: 'test-ui-lib',
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should create the story file', () => {
|
|
100
|
+
expect(appTree.exists(storyFilePathPlain)).toBeTruthy();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should properly set up the story', () => {
|
|
104
|
+
expect(formatFile`${appTree.read(storyFilePathPlain, 'utf-8')}`)
|
|
105
|
+
.toContain(formatFile`
|
|
106
|
+
import { storiesOf } from '@storybook/react-native';
|
|
107
|
+
import React from 'react';
|
|
108
|
+
import { Test } from './test-ui-libplain';
|
|
109
|
+
|
|
110
|
+
const props = {};
|
|
111
|
+
|
|
112
|
+
storiesOf('Test', module)
|
|
113
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
114
|
+
.add('Primary', () => <Test {...props} />);
|
|
115
|
+
`);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('component without any props defined', () => {
|
|
120
|
+
beforeEach(async () => {
|
|
121
|
+
appTree.write(
|
|
122
|
+
cmpPath,
|
|
123
|
+
`import React from 'react';
|
|
124
|
+
|
|
125
|
+
import { View, Text } from 'react-native';
|
|
126
|
+
|
|
127
|
+
export function Test() {
|
|
128
|
+
return (
|
|
129
|
+
<View>
|
|
130
|
+
<Text>Welcome to test!</Text>
|
|
131
|
+
</View>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default Test;
|
|
136
|
+
`
|
|
137
|
+
);
|
|
138
|
+
await componentStoryGenerator(appTree, {
|
|
139
|
+
componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
|
|
140
|
+
project: 'test-ui-lib',
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should create a story without controls', () => {
|
|
145
|
+
expect(formatFile`${appTree.read(storyFilePath, 'utf-8')}`)
|
|
146
|
+
.toContain(formatFile`
|
|
147
|
+
import { storiesOf } from '@storybook/react-native';
|
|
148
|
+
import React from 'react';
|
|
149
|
+
import { Test } from './test-ui-lib';
|
|
150
|
+
const props = {};
|
|
151
|
+
storiesOf('Test', module)
|
|
152
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
153
|
+
.add('Primary', () => <Test {...props} />);
|
|
154
|
+
`);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe('component with props', () => {
|
|
159
|
+
beforeEach(async () => {
|
|
160
|
+
await componentStoryGenerator(appTree, {
|
|
161
|
+
componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
|
|
162
|
+
project: 'test-ui-lib',
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should setup controls based on the component props', () => {
|
|
167
|
+
expect(
|
|
168
|
+
formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
|
|
169
|
+
).toContain(formatFile`
|
|
170
|
+
import { storiesOf } from '@storybook/react-native';
|
|
171
|
+
import React from 'react';
|
|
172
|
+
import { TestUiLib, TestUiLibProps } from './test-ui-lib';
|
|
173
|
+
const props: TestUiLibProps = {};
|
|
174
|
+
storiesOf('TestUiLib', module)
|
|
175
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
176
|
+
.add('Primary', () => <TestUiLib {...props} />);
|
|
177
|
+
`);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('component with props and actions', () => {
|
|
182
|
+
beforeEach(async () => {
|
|
183
|
+
appTree.write(
|
|
184
|
+
cmpPath,
|
|
185
|
+
`import React from 'react';
|
|
186
|
+
|
|
187
|
+
export type ButtonStyle = 'default' | 'primary' | 'warning';
|
|
188
|
+
|
|
189
|
+
export interface TestProps {
|
|
190
|
+
name: string;
|
|
191
|
+
displayAge: boolean;
|
|
192
|
+
someAction: (e: unknown) => void;
|
|
193
|
+
style: ButtonStyle;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export const Test = (props: TestProps) => {
|
|
197
|
+
return (
|
|
198
|
+
<div>
|
|
199
|
+
<h1>Welcome to test component, {props.name}</h1>
|
|
200
|
+
<button onClick={props.someAction}>Click me!</button>
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export default Test;
|
|
206
|
+
`
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
await componentStoryGenerator(appTree, {
|
|
210
|
+
componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
|
|
211
|
+
project: 'test-ui-lib',
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should setup controls based on the component props', () => {
|
|
216
|
+
expect(
|
|
217
|
+
formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
|
|
218
|
+
).toContain(formatFile`
|
|
219
|
+
import { action } from '@storybook/addon-actions';
|
|
220
|
+
import { storiesOf } from '@storybook/react-native';
|
|
221
|
+
import React from 'react';
|
|
222
|
+
import { Test, TestProps } from './test-ui-lib';
|
|
223
|
+
const actions = { someAction: action('someAction executed!') };
|
|
224
|
+
const props: TestProps = { name: '', displayAge: false };
|
|
225
|
+
storiesOf('Test', module)
|
|
226
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
227
|
+
.add('Primary', () => <Test {...props} {...actions} />);
|
|
228
|
+
`);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
[
|
|
233
|
+
{
|
|
234
|
+
name: 'default export function',
|
|
235
|
+
src: `export default function Test(props: TestProps) {
|
|
236
|
+
return (
|
|
237
|
+
<div>
|
|
238
|
+
<h1>Welcome to test component, {props.name}</h1>
|
|
239
|
+
</div>
|
|
240
|
+
);
|
|
241
|
+
};
|
|
242
|
+
`,
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: 'function and then export',
|
|
246
|
+
src: `
|
|
247
|
+
function Test(props: TestProps) {
|
|
248
|
+
return (
|
|
249
|
+
<div>
|
|
250
|
+
<h1>Welcome to test component, {props.name}</h1>
|
|
251
|
+
</div>
|
|
252
|
+
);
|
|
253
|
+
};
|
|
254
|
+
export default Test;
|
|
255
|
+
`,
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: 'arrow function',
|
|
259
|
+
src: `
|
|
260
|
+
const Test = (props: TestProps) => {
|
|
261
|
+
return (
|
|
262
|
+
<div>
|
|
263
|
+
<h1>Welcome to test component, {props.name}</h1>
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
};
|
|
267
|
+
export default Test;
|
|
268
|
+
`,
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: 'arrow function without {..}',
|
|
272
|
+
src: `
|
|
273
|
+
const Test = (props: TestProps) => <div><h1>Welcome to test component, {props.name}</h1></div>;
|
|
274
|
+
export default Test
|
|
275
|
+
`,
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
name: 'direct export of component class',
|
|
279
|
+
src: `
|
|
280
|
+
export default class Test extends React.Component<TestProps> {
|
|
281
|
+
render() {
|
|
282
|
+
return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
`,
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'component class & then default export',
|
|
289
|
+
src: `
|
|
290
|
+
class Test extends React.Component<TestProps> {
|
|
291
|
+
render() {
|
|
292
|
+
return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
export default Test
|
|
296
|
+
`,
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: 'PureComponent class & then default export',
|
|
300
|
+
src: `
|
|
301
|
+
class Test extends React.PureComponent<TestProps> {
|
|
302
|
+
render() {
|
|
303
|
+
return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
export default Test
|
|
307
|
+
`,
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: 'direct export of component class new JSX transform',
|
|
311
|
+
src: `
|
|
312
|
+
export default class Test extends Component<TestProps> {
|
|
313
|
+
render() {
|
|
314
|
+
return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
`,
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: 'component class & then default export new JSX transform',
|
|
321
|
+
src: `
|
|
322
|
+
class Test extends Component<TestProps> {
|
|
323
|
+
render() {
|
|
324
|
+
return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
export default Test
|
|
328
|
+
`,
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
name: 'PureComponent class & then default export new JSX transform',
|
|
332
|
+
src: `
|
|
333
|
+
class Test extends PureComponent<TestProps> {
|
|
334
|
+
render() {
|
|
335
|
+
return <div><h1>Welcome to test component, {this.props.name}</h1></div>;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
export default Test
|
|
339
|
+
`,
|
|
340
|
+
},
|
|
341
|
+
].forEach((config) => {
|
|
342
|
+
describe(`React Native component defined as:${config.name}`, () => {
|
|
343
|
+
beforeEach(async () => {
|
|
344
|
+
appTree.write(
|
|
345
|
+
cmpPath,
|
|
346
|
+
`import React from 'react';
|
|
347
|
+
|
|
348
|
+
export interface TestProps {
|
|
349
|
+
name: string;
|
|
350
|
+
displayAge: boolean;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
${config.src}
|
|
354
|
+
`
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
await componentStoryGenerator(appTree, {
|
|
358
|
+
componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
|
|
359
|
+
project: 'test-ui-lib',
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it('should properly setup the controls based on the component props', () => {
|
|
364
|
+
expect(
|
|
365
|
+
formatFile`${appTree.read(storyFilePath, 'utf-8').replace('·', '')}`
|
|
366
|
+
).toContain(formatFile`
|
|
367
|
+
import { storiesOf } from '@storybook/react-native';
|
|
368
|
+
import React from 'react';
|
|
369
|
+
import { Test, TestProps } from './test-ui-lib';
|
|
370
|
+
const props: TestProps = {
|
|
371
|
+
name: '',
|
|
372
|
+
displayAge: false,
|
|
373
|
+
};
|
|
374
|
+
storiesOf('Test', module)
|
|
375
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
376
|
+
.add('Primary', () => <Test {...props} />);
|
|
377
|
+
`);
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe('using eslint', () => {
|
|
384
|
+
beforeEach(async () => {
|
|
385
|
+
appTree = await createTestUILib('test-ui-lib', false);
|
|
386
|
+
await componentGenerator(appTree, {
|
|
387
|
+
name: 'test-ui-lib',
|
|
388
|
+
project: 'test-ui-lib',
|
|
389
|
+
export: true,
|
|
390
|
+
});
|
|
391
|
+
await componentStoryGenerator(appTree, {
|
|
392
|
+
componentPath: 'lib/test-ui-lib/test-ui-lib.tsx',
|
|
393
|
+
project: 'test-ui-lib',
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('should properly set up the story', () => {
|
|
398
|
+
expect(formatFile`${appTree.read(storyFilePath, 'utf-8')}`)
|
|
399
|
+
.toContain(formatFile`
|
|
400
|
+
import { storiesOf } from '@storybook/react-native';
|
|
401
|
+
import React from 'react';
|
|
402
|
+
import { TestUiLib, TestUiLibProps } from './test-ui-lib';
|
|
403
|
+
|
|
404
|
+
const props: TestUiLibProps = {};
|
|
405
|
+
|
|
406
|
+
storiesOf('TestUiLib', module)
|
|
407
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
408
|
+
.add('Primary', () => <TestUiLib {...props} />);
|
|
409
|
+
`);
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
export async function createTestUILib(
|
|
415
|
+
libName: string,
|
|
416
|
+
useEsLint = false
|
|
417
|
+
): Promise<Tree> {
|
|
418
|
+
let appTree = createTreeWithEmptyWorkspace();
|
|
419
|
+
appTree.write('.gitignore', '');
|
|
420
|
+
|
|
421
|
+
await libraryGenerator(appTree, {
|
|
422
|
+
name: libName,
|
|
423
|
+
linter: useEsLint ? Linter.EsLint : Linter.TsLint,
|
|
424
|
+
skipFormat: true,
|
|
425
|
+
skipTsConfig: false,
|
|
426
|
+
unitTestRunner: 'jest',
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
await componentGenerator(appTree, {
|
|
430
|
+
name: libName,
|
|
431
|
+
project: libName,
|
|
432
|
+
export: true,
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
if (useEsLint) {
|
|
436
|
+
const currentWorkspaceJson = getProjects(appTree);
|
|
437
|
+
|
|
438
|
+
const projectConfig = currentWorkspaceJson.get(libName);
|
|
439
|
+
projectConfig.targets.lint.options.linter = 'eslint';
|
|
440
|
+
|
|
441
|
+
updateProjectConfiguration(appTree, libName, projectConfig);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return appTree;
|
|
445
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<% if (hasActions) { %>
|
|
2
|
+
import { action } from '@storybook/addon-actions';
|
|
3
|
+
<% } %>
|
|
4
|
+
import { storiesOf } from '@storybook/react-native';
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import {
|
|
7
|
+
<%= componentName %>
|
|
8
|
+
<% if ( propsTypeName ) { %>, <%= propsTypeName %> <% } %>
|
|
9
|
+
} from './<%= componentFileName %>';
|
|
10
|
+
|
|
11
|
+
<% if (hasActions) { %>
|
|
12
|
+
const actions = {<% for (let argType of argTypes) { %>
|
|
13
|
+
<%= argType.name %>: action('<%- argType.actionText %>'),
|
|
14
|
+
<% } %>};
|
|
15
|
+
<% } %>
|
|
16
|
+
|
|
17
|
+
const props <% if ( propsTypeName ) { %>:<%= propsTypeName %><% } %> = {<% for (let prop of props) { %>
|
|
18
|
+
<%= prop.name %>: <%- prop.defaultValue %>,
|
|
19
|
+
<% } %>};
|
|
20
|
+
|
|
21
|
+
storiesOf('<%= componentName %>', module)
|
|
22
|
+
.addDecorator((getStory) => <>{getStory()}</>)
|
|
23
|
+
.add('Primary', () => (
|
|
24
|
+
<<%= componentName %> {...props} <% if (hasActions) { %> {...actions} <% } %>/>
|
|
25
|
+
));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"cli": "nx",
|
|
4
|
+
"$id": "NxReactNativeComponentStory",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"project": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "The project name where to add the components.",
|
|
10
|
+
"examples": ["shared-ui-component"],
|
|
11
|
+
"$default": {
|
|
12
|
+
"$source": "projectName",
|
|
13
|
+
"index": 0
|
|
14
|
+
},
|
|
15
|
+
"x-prompt": "What's the name of the project where the component lives?"
|
|
16
|
+
},
|
|
17
|
+
"componentPath": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Relative path to the component file from the library root",
|
|
20
|
+
"examples": ["lib/components"],
|
|
21
|
+
"x-prompt": "What's path of the component relative to the project's lib root?"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"required": ["project", "componentPath"]
|
|
25
|
+
}
|
|
@@ -37,7 +37,7 @@ function updateDependencies(host) {
|
|
|
37
37
|
return (0, devkit_1.addDependenciesToPackageJson)(host, {
|
|
38
38
|
react: versions_1.reactVersion,
|
|
39
39
|
'react-native': versions_2.reactNativeVersion,
|
|
40
|
-
}, Object.assign({ '@nrwl/react-native': versions_2.nxVersion, '@types/react': versions_1.typesReactVersion, '@types/react-native': versions_2.typesReactNativeVersion, '@react-native-community/cli': versions_2.reactNativeCommunityCli, '@react-native-community/cli-platform-android': versions_2.reactNativeCommunityCliAndroid, '@react-native-community/cli-platform-ios': versions_2.reactNativeCommunityCliIos, 'metro-react-native-babel-preset': versions_2.metroReactNativeBabelPresetVersion, '@testing-library/react-native': versions_2.testingLibraryReactNativeVersion, '@testing-library/jest-native': versions_2.testingLibraryJestNativeVersion, 'jest-react-native': versions_2.jestReactNativeVersion, metro: versions_2.metroVersion, 'metro-resolver': versions_2.metroVersion, 'react-test-renderer': versions_2.reactTestRendererVersion, 'react-native-svg-transformer': versions_2.reactNativeSvgTransformerVersion, 'react-native-svg': versions_2.reactNativeSvgVersion, 'react-native-config': versions_2.reactNativeConfigVersion }, (isPnpm
|
|
40
|
+
}, Object.assign({ '@nrwl/react-native': versions_2.nxVersion, '@types/react': versions_1.typesReactVersion, '@types/react-native': versions_2.typesReactNativeVersion, '@react-native-community/cli': versions_2.reactNativeCommunityCli, '@react-native-community/cli-platform-android': versions_2.reactNativeCommunityCliAndroid, '@react-native-community/cli-platform-ios': versions_2.reactNativeCommunityCliIos, 'metro-react-native-babel-preset': versions_2.metroReactNativeBabelPresetVersion, '@testing-library/react-native': versions_2.testingLibraryReactNativeVersion, '@testing-library/jest-native': versions_2.testingLibraryJestNativeVersion, 'jest-react-native': versions_2.jestReactNativeVersion, metro: versions_2.metroVersion, 'metro-resolver': versions_2.metroVersion, 'react-test-renderer': versions_2.reactTestRendererVersion, 'react-native-svg-transformer': versions_2.reactNativeSvgTransformerVersion, 'react-native-svg': versions_2.reactNativeSvgVersion, 'react-native-config': versions_2.reactNativeConfigVersion, '@react-native-async-storage/async-storage': versions_2.reactNativeAsyncStorageVersion }, (isPnpm
|
|
41
41
|
? {
|
|
42
42
|
'metro-config': versions_2.metroVersion,
|
|
43
43
|
'@babel/runtime': versions_2.babelRuntimeVersion, // @babel/runtime is used by react-native-svg
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../../../packages/react-native/src/generators/init/init.ts"],"names":[],"mappings":";;;;AAAA,iGAA4F;AAC5F,yCAOsB;AAEtB,2FAAqF;AACrF,qCAA+C;AAC/C,uCAAiD;AACjD,6DAGwC;AAExC,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../../../../packages/react-native/src/generators/init/init.ts"],"names":[],"mappings":";;;;AAAA,iGAA4F;AAC5F,yCAOsB;AAEtB,2FAAqF;AACrF,qCAA+C;AAC/C,uCAAiD;AACjD,6DAGwC;AAExC,mDAkB8B;AAE9B,qEAA+D;AAC/D,yEAAmE;AAEnE,SAAsB,wBAAwB,CAAC,IAAU,EAAE,MAAc;;QACvE,IAAA,6CAAoB,EAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;QACjD,IAAA,wCAAiB,EAAC,IAAI,CAAC,CAAC;QACxB,IAAA,4CAAmB,EAAC,IAAI,CAAC,CAAC;QAE1B,MAAM,KAAK,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;QAE/D,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,KAAK,MAAM,EAAE;YAC9D,MAAM,QAAQ,GAAG,IAAA,wBAAiB,EAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;SACtB;QAED,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,KAAK,OAAO,EAAE;YAC7D,MAAM,SAAS,GAAG,MAAM,IAAA,0BAAkB,EAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACrD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;SACvB;QAED,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;YACtB,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;SACzB;QAED,OAAO,IAAA,sCAAgB,EAAC,GAAG,KAAK,CAAC,CAAC;IACpC,CAAC;CAAA;AAtBD,4DAsBC;AAED,SAAgB,kBAAkB,CAAC,IAAU;IAC3C,MAAM,MAAM,GAAG,IAAA,6BAAoB,EAAC,IAAI,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC;IAC1D,OAAO,IAAA,qCAA4B,EACjC,IAAI,EACJ;QACE,KAAK,EAAE,uBAAY;QACnB,cAAc,EAAE,6BAAkB;KACnC,kBAEC,oBAAoB,EAAE,oBAAS,EAC/B,cAAc,EAAE,4BAAiB,EACjC,qBAAqB,EAAE,kCAAuB,EAC9C,6BAA6B,EAAE,kCAAuB,EACtD,8CAA8C,EAC5C,yCAA8B,EAChC,0CAA0C,EAAE,qCAA0B,EACtE,iCAAiC,EAAE,6CAAkC,EACrE,+BAA+B,EAAE,2CAAgC,EACjE,8BAA8B,EAAE,0CAA+B,EAC/D,mBAAmB,EAAE,iCAAsB,EAC3C,KAAK,EAAE,uBAAY,EACnB,gBAAgB,EAAE,uBAAY,EAC9B,qBAAqB,EAAE,mCAAwB,EAC/C,8BAA8B,EAAE,2CAAgC,EAChE,kBAAkB,EAAE,gCAAqB,EACzC,qBAAqB,EAAE,mCAAwB,EAC/C,2CAA2C,EACzC,yCAA8B,IAC7B,CAAC,MAAM;QACR,CAAC,CAAC;YACE,cAAc,EAAE,uBAAY;YAC5B,gBAAgB,EAAE,8BAAmB,EAAE,6CAA6C;SACrF;QACH,CAAC,CAAC,EAAE,CAAC,EAEV,CAAC;AACJ,CAAC;AApCD,gDAoCC;AAED,SAAS,cAAc,CAAC,IAAU;IAChC,OAAO,IAAA,0CAAiC,EAAC,IAAI,EAAE,CAAC,oBAAoB,CAAC,EAAE,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED,kBAAe,wBAAwB,CAAC;AAC3B,QAAA,wBAAwB,GAAG,IAAA,2BAAkB,EACxD,wBAAwB,CACzB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"cli": "nx",
|
|
4
|
+
"$id": "NxReactNativeStorybookStories",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"project": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "Library or application name",
|
|
10
|
+
"$default": {
|
|
11
|
+
"$source": "projectName",
|
|
12
|
+
"index": 0
|
|
13
|
+
},
|
|
14
|
+
"x-prompt": "What's the name of the project for which you want to generate stories?"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"required": ["project"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
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 { reactNativeComponentGenerator } from '../component/component';
|
|
7
|
+
|
|
8
|
+
describe('react:stories for applications', () => {
|
|
9
|
+
let appTree: Tree;
|
|
10
|
+
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
appTree = await createTestUIApp('test-ui-app');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should create the stories', async () => {
|
|
16
|
+
await reactNativeComponentGenerator(appTree, {
|
|
17
|
+
name: 'another-cmp',
|
|
18
|
+
project: 'test-ui-app',
|
|
19
|
+
});
|
|
20
|
+
await storiesGenerator(appTree, {
|
|
21
|
+
project: 'test-ui-app',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(appTree.exists('apps/test-ui-app/src/app/App.tsx')).toBeTruthy();
|
|
25
|
+
expect(
|
|
26
|
+
appTree.exists('apps/test-ui-app/src/app/App.stories.tsx')
|
|
27
|
+
).toBeTruthy();
|
|
28
|
+
expect(
|
|
29
|
+
appTree.exists(
|
|
30
|
+
'apps/test-ui-app/src/app/another-cmp/another-cmp.stories.tsx'
|
|
31
|
+
)
|
|
32
|
+
).toBeTruthy();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should ignore files that do not contain components', async () => {
|
|
36
|
+
// create another component
|
|
37
|
+
appTree.write(
|
|
38
|
+
'apps/test-ui-app/src/app/some-utils.js',
|
|
39
|
+
`export const add = (a: number, b: number) => a + b;`
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
await storiesGenerator(appTree, {
|
|
43
|
+
project: 'test-ui-app',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// should just create the story and not error, even though there's a js file
|
|
47
|
+
// not containing any react component
|
|
48
|
+
expect(
|
|
49
|
+
appTree.exists('apps/test-ui-app/src/app/App.stories.tsx')
|
|
50
|
+
).toBeTruthy();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export async function createTestUIApp(libName: string): Promise<Tree> {
|
|
55
|
+
let appTree = createTreeWithEmptyWorkspace();
|
|
56
|
+
appTree.write('.gitignore', '');
|
|
57
|
+
|
|
58
|
+
await applicationGenerator(appTree, {
|
|
59
|
+
linter: Linter.EsLint,
|
|
60
|
+
skipFormat: false,
|
|
61
|
+
style: 'css',
|
|
62
|
+
unitTestRunner: 'none',
|
|
63
|
+
name: libName,
|
|
64
|
+
});
|
|
65
|
+
return appTree;
|
|
66
|
+
}
|