@teleporthq/teleport-component-generator-react 0.44.1-alpha.0 → 0.44.4
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/__tests__/end2end/index.ts +3 -3
- package/__tests__/integration/component-referenced-styles.ts +70 -58
- package/__tests__/integration/component-reserved-word-state.ts +105 -0
- package/__tests__/integration/component-style.ts +33 -35
- package/__tests__/integration/component-with-object-prop.ts +19 -0
- package/__tests__/integration/dynamic-style-inline.ts +72 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +22 -24
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react-mapping.d.ts.map +1 -1
- package/dist/cjs/react-mapping.js +43 -3
- package/dist/cjs/react-mapping.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +22 -24
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react-mapping.d.ts.map +1 -1
- package/dist/esm/react-mapping.js +43 -3
- package/dist/esm/react-mapping.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -15
- package/src/index.ts +24 -27
- package/src/react-mapping.ts +43 -3
|
@@ -26,7 +26,7 @@ describe('React Component Generator', () => {
|
|
|
26
26
|
expect(result.files).toBeDefined()
|
|
27
27
|
expect(Array.isArray(result.files)).toBeTruthy()
|
|
28
28
|
expect(result.files.length).toBeTruthy()
|
|
29
|
-
expect(jsFile
|
|
29
|
+
expect(jsFile?.content).toContain('import React')
|
|
30
30
|
expect(result.dependencies).toBeDefined()
|
|
31
31
|
})
|
|
32
32
|
})
|
|
@@ -42,7 +42,7 @@ describe('React Component Generator', () => {
|
|
|
42
42
|
|
|
43
43
|
expect(jsFile).toBeDefined()
|
|
44
44
|
expect(result.files.length).toBe(1)
|
|
45
|
-
expect(jsFile
|
|
45
|
+
expect(jsFile?.content).toContain('import React')
|
|
46
46
|
expect(result.dependencies).toBeDefined()
|
|
47
47
|
})
|
|
48
48
|
})
|
|
@@ -58,7 +58,7 @@ describe('React Component Generator', () => {
|
|
|
58
58
|
|
|
59
59
|
expect(jsFile).toBeDefined()
|
|
60
60
|
expect(result.files.length).toBe(1)
|
|
61
|
-
expect(jsFile
|
|
61
|
+
expect(jsFile?.content).toContain('import React')
|
|
62
62
|
expect(result.dependencies).toBeDefined()
|
|
63
63
|
})
|
|
64
64
|
})
|
|
@@ -30,7 +30,7 @@ describe('Generates media, pseudo and normal styles', () => {
|
|
|
30
30
|
}
|
|
31
31
|
const uidl = component(
|
|
32
32
|
'MyComponent',
|
|
33
|
-
elementNode('container',
|
|
33
|
+
elementNode('container', {}, [staticNode('Hello !!')], null, style, null, referencedStyles)
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
it('Generates styles using CSS Modules', async () => {
|
|
@@ -40,12 +40,12 @@ describe('Generates media, pseudo and normal styles', () => {
|
|
|
40
40
|
const jsFile = findFileByType(files, FileType.JS)
|
|
41
41
|
|
|
42
42
|
expect(cssFile).toBeDefined()
|
|
43
|
-
expect(cssFile
|
|
44
|
-
expect(cssFile
|
|
43
|
+
expect(cssFile?.content).toContain('@media(max-width: 991px)')
|
|
44
|
+
expect(cssFile?.content).toContain('width: 100px')
|
|
45
45
|
|
|
46
46
|
expect(jsFile).toBeDefined()
|
|
47
|
-
expect(jsFile
|
|
48
|
-
expect(jsFile
|
|
47
|
+
expect(jsFile?.content).toContain(`className={styles['my-component-container']}`)
|
|
48
|
+
expect(jsFile?.content).toContain(`import styles from './my-component.module.css`)
|
|
49
49
|
})
|
|
50
50
|
|
|
51
51
|
it('Generates styles using CSS', async () => {
|
|
@@ -57,12 +57,12 @@ describe('Generates media, pseudo and normal styles', () => {
|
|
|
57
57
|
const jsFile = findFileByType(files, FileType.JS)
|
|
58
58
|
|
|
59
59
|
expect(cssFile).toBeDefined()
|
|
60
|
-
expect(cssFile
|
|
61
|
-
expect(cssFile
|
|
60
|
+
expect(cssFile?.content).toContain('@media(max-width: 991px)')
|
|
61
|
+
expect(cssFile?.content).toContain('width: 100px')
|
|
62
62
|
|
|
63
63
|
expect(jsFile).toBeDefined()
|
|
64
|
-
expect(jsFile
|
|
65
|
-
expect(jsFile
|
|
64
|
+
expect(jsFile?.content).toContain(`className="my-component-container"`)
|
|
65
|
+
expect(jsFile?.content).toContain(`import './my-component.css`)
|
|
66
66
|
})
|
|
67
67
|
|
|
68
68
|
it('Generates styles using Styled-Components', async () => {
|
|
@@ -76,10 +76,10 @@ describe('Generates media, pseudo and normal styles', () => {
|
|
|
76
76
|
|
|
77
77
|
expect(cssFile).not.toBeDefined()
|
|
78
78
|
expect(jsFile).toBeDefined()
|
|
79
|
-
expect(jsFile
|
|
80
|
-
expect(jsFile
|
|
81
|
-
expect(jsFile
|
|
82
|
-
expect(jsFile
|
|
79
|
+
expect(jsFile?.content).toContain(`<MyComponentContainer>Hello !!</MyComponentContainer>`)
|
|
80
|
+
expect(jsFile?.content).toContain(`const MyComponentContainer = styled('div')`)
|
|
81
|
+
expect(jsFile?.content).toContain(`width: '100px'`)
|
|
82
|
+
expect(jsFile?.content).toContain(`display: 'none'`)
|
|
83
83
|
})
|
|
84
84
|
|
|
85
85
|
it('Generates styles using ReactJSS', async () => {
|
|
@@ -93,11 +93,11 @@ describe('Generates media, pseudo and normal styles', () => {
|
|
|
93
93
|
expect(cssFile).not.toBeDefined()
|
|
94
94
|
expect(jsFile).toBeDefined()
|
|
95
95
|
|
|
96
|
-
expect(jsFile
|
|
97
|
-
expect(jsFile
|
|
98
|
-
expect(jsFile
|
|
99
|
-
expect(jsFile
|
|
100
|
-
expect(jsFile
|
|
96
|
+
expect(jsFile?.content).toContain(`const classes = useStyles()`)
|
|
97
|
+
expect(jsFile?.content).toContain(`className={classes['myComponentContainer']}`)
|
|
98
|
+
expect(jsFile?.content).toContain(`myComponentContainer: {`)
|
|
99
|
+
expect(jsFile?.content).toContain(`width: '100px'`)
|
|
100
|
+
expect(jsFile?.content).toContain(`display: 'none'`)
|
|
101
101
|
})
|
|
102
102
|
|
|
103
103
|
it('Generates styles using StyledJSX', async () => {
|
|
@@ -110,10 +110,10 @@ describe('Generates media, pseudo and normal styles', () => {
|
|
|
110
110
|
|
|
111
111
|
expect(cssFile).not.toBeDefined()
|
|
112
112
|
expect(jsFile).toBeDefined()
|
|
113
|
-
expect(jsFile
|
|
114
|
-
expect(jsFile
|
|
115
|
-
expect(jsFile
|
|
116
|
-
expect(jsFile
|
|
113
|
+
expect(jsFile?.content).toContain(`className`)
|
|
114
|
+
expect(jsFile?.content).toContain(`container {`)
|
|
115
|
+
expect(jsFile?.content).toContain(`width: 100px`)
|
|
116
|
+
expect(jsFile?.content).toContain(`display: none`)
|
|
117
117
|
})
|
|
118
118
|
})
|
|
119
119
|
|
|
@@ -143,12 +143,12 @@ describe('Add referenced styles even when direct styles are not present on node'
|
|
|
143
143
|
const jsFile = findFileByType(files, FileType.JS)
|
|
144
144
|
|
|
145
145
|
expect(cssFile).toBeDefined()
|
|
146
|
-
expect(cssFile
|
|
147
|
-
expect(cssFile
|
|
146
|
+
expect(cssFile?.content).toContain('@media(max-width: 991px)')
|
|
147
|
+
expect(cssFile?.content).not.toContain('width: 100px')
|
|
148
148
|
|
|
149
149
|
expect(jsFile).toBeDefined()
|
|
150
|
-
expect(jsFile
|
|
151
|
-
expect(jsFile
|
|
150
|
+
expect(jsFile?.content).toContain(`className={styles['my-component-container']}`)
|
|
151
|
+
expect(jsFile?.content).toContain(`import styles from './my-component.module.css`)
|
|
152
152
|
})
|
|
153
153
|
|
|
154
154
|
it('Generates styles using CSS', async () => {
|
|
@@ -160,12 +160,12 @@ describe('Add referenced styles even when direct styles are not present on node'
|
|
|
160
160
|
const jsFile = findFileByType(files, FileType.JS)
|
|
161
161
|
|
|
162
162
|
expect(cssFile).toBeDefined()
|
|
163
|
-
expect(cssFile
|
|
164
|
-
expect(cssFile
|
|
163
|
+
expect(cssFile?.content).toContain('@media(max-width: 991px)')
|
|
164
|
+
expect(cssFile?.content).not.toContain('width: 100px')
|
|
165
165
|
|
|
166
166
|
expect(jsFile).toBeDefined()
|
|
167
|
-
expect(jsFile
|
|
168
|
-
expect(jsFile
|
|
167
|
+
expect(jsFile?.content).toContain(`className="my-component-container"`)
|
|
168
|
+
expect(jsFile?.content).toContain(`import './my-component.css`)
|
|
169
169
|
})
|
|
170
170
|
|
|
171
171
|
it('Generates styles using Styled-Components', async () => {
|
|
@@ -178,10 +178,10 @@ describe('Add referenced styles even when direct styles are not present on node'
|
|
|
178
178
|
|
|
179
179
|
expect(cssFile).not.toBeDefined()
|
|
180
180
|
expect(jsFile).toBeDefined()
|
|
181
|
-
expect(jsFile
|
|
182
|
-
expect(jsFile
|
|
183
|
-
expect(jsFile
|
|
184
|
-
expect(jsFile
|
|
181
|
+
expect(jsFile?.content).toContain(`<MyComponentContainer>Hello !!</MyComponentContainer>`)
|
|
182
|
+
expect(jsFile?.content).toContain(`const MyComponentContainer = styled('div')`)
|
|
183
|
+
expect(jsFile?.content).not.toContain(`width: '100px'`)
|
|
184
|
+
expect(jsFile?.content).toContain(`display: 'none'`)
|
|
185
185
|
})
|
|
186
186
|
|
|
187
187
|
it('Generates styles using ReactJSS', async () => {
|
|
@@ -195,10 +195,10 @@ describe('Add referenced styles even when direct styles are not present on node'
|
|
|
195
195
|
|
|
196
196
|
expect(cssFile).not.toBeDefined()
|
|
197
197
|
expect(jsFile).toBeDefined()
|
|
198
|
-
expect(jsFile
|
|
199
|
-
expect(jsFile
|
|
200
|
-
expect(jsFile
|
|
201
|
-
expect(jsFile
|
|
198
|
+
expect(jsFile?.content).toContain(`className={classes['myComponentContainer']}`)
|
|
199
|
+
expect(jsFile?.content).toContain(`myComponentContainer: {`)
|
|
200
|
+
expect(jsFile?.content).not.toContain(`width: '100px'`)
|
|
201
|
+
expect(jsFile?.content).toContain(`display: 'none'`)
|
|
202
202
|
})
|
|
203
203
|
|
|
204
204
|
it('Generates styles using StyledJSX', async () => {
|
|
@@ -211,14 +211,18 @@ describe('Add referenced styles even when direct styles are not present on node'
|
|
|
211
211
|
|
|
212
212
|
expect(cssFile).not.toBeDefined()
|
|
213
213
|
expect(jsFile).toBeDefined()
|
|
214
|
-
expect(jsFile
|
|
215
|
-
expect(jsFile
|
|
216
|
-
expect(jsFile
|
|
217
|
-
expect(jsFile
|
|
214
|
+
expect(jsFile?.content).toContain(`className`)
|
|
215
|
+
expect(jsFile?.content).toContain(`container {`)
|
|
216
|
+
expect(jsFile?.content).not.toContain(`width: '100px'`)
|
|
217
|
+
expect(jsFile?.content).toContain(`display: none`)
|
|
218
218
|
})
|
|
219
219
|
})
|
|
220
220
|
|
|
221
|
-
describe('
|
|
221
|
+
describe('Silently drops project-styles whose referenceId is missing from the UIDL', () => {
|
|
222
|
+
// Tolerant fallback for agent-generated UIDLs: when a node references a
|
|
223
|
+
// project style that wasn't defined in `projectStyleSet.styleSetDefinitions`,
|
|
224
|
+
// the plugin pipeline drops the reference and emits the component without
|
|
225
|
+
// that style rather than aborting the whole generation.
|
|
222
226
|
const styles: UIDLReferencedStyles = {
|
|
223
227
|
'123456789': {
|
|
224
228
|
type: 'style-map',
|
|
@@ -235,14 +239,20 @@ describe('Throws Error when a node is using project-styles but not present in UI
|
|
|
235
239
|
|
|
236
240
|
it('CSS Modules', async () => {
|
|
237
241
|
const generator = createReactComponentGenerator()
|
|
238
|
-
await
|
|
242
|
+
const { files } = await generator.generateComponent(uidl)
|
|
243
|
+
const jsFile = findFileByType(files, FileType.JS)
|
|
244
|
+
expect(jsFile).toBeDefined()
|
|
245
|
+
expect(jsFile?.content).not.toContain('987654321')
|
|
239
246
|
})
|
|
240
247
|
|
|
241
248
|
it('CSS', async () => {
|
|
242
249
|
const generator = createReactComponentGenerator({
|
|
243
250
|
variation: ReactStyleVariation.CSS,
|
|
244
251
|
})
|
|
245
|
-
await
|
|
252
|
+
const { files } = await generator.generateComponent(uidl)
|
|
253
|
+
const jsFile = findFileByType(files, FileType.JS)
|
|
254
|
+
expect(jsFile).toBeDefined()
|
|
255
|
+
expect(jsFile?.content).not.toContain('987654321')
|
|
246
256
|
})
|
|
247
257
|
|
|
248
258
|
it('Styled Components', async () => {
|
|
@@ -310,9 +320,9 @@ describe('Referes from project style and adds it to the node, without any styles
|
|
|
310
320
|
|
|
311
321
|
const { files } = await generator.generateComponent(uidl, cssOptions)
|
|
312
322
|
const jsFile = findFileByType(files, FileType.JS)
|
|
313
|
-
expect(jsFile
|
|
314
|
-
expect(jsFile
|
|
315
|
-
expect(jsFile
|
|
323
|
+
expect(jsFile?.content).toContain(`className={projectStyles['primary-button']}`)
|
|
324
|
+
expect(jsFile?.content).toContain(`import projectStyles from '../style.module.css'`)
|
|
325
|
+
expect(jsFile?.content).not.toContain(`import styles from './my-component.module.css'`)
|
|
316
326
|
})
|
|
317
327
|
|
|
318
328
|
it('CSS', async () => {
|
|
@@ -329,9 +339,9 @@ describe('Referes from project style and adds it to the node, without any styles
|
|
|
329
339
|
const { files } = await generator.generateComponent(uidl, cssOptions)
|
|
330
340
|
const jsFile = findFileByType(files, FileType.JS)
|
|
331
341
|
|
|
332
|
-
expect(jsFile
|
|
333
|
-
expect(jsFile
|
|
334
|
-
expect(jsFile
|
|
342
|
+
expect(jsFile?.content).toContain('className="primaryButton"')
|
|
343
|
+
expect(jsFile?.content).not.toContain(`import '../style.css'`)
|
|
344
|
+
expect(jsFile?.content).not.toContain(`import './my-component.css'`)
|
|
335
345
|
})
|
|
336
346
|
|
|
337
347
|
it('StyledComponents', async () => {
|
|
@@ -342,9 +352,11 @@ describe('Referes from project style and adds it to the node, without any styles
|
|
|
342
352
|
const { files } = await generator.generateComponent(uidl, options)
|
|
343
353
|
const jsFile = findFileByType(files, FileType.JS)
|
|
344
354
|
|
|
345
|
-
expect(jsFile
|
|
346
|
-
expect(jsFile
|
|
347
|
-
expect(jsFile
|
|
355
|
+
expect(jsFile?.content).toContain(`<MyComponentContainer projVariant=\"primaryButton\">`)
|
|
356
|
+
expect(jsFile?.content).toContain(`import { projectStyleVariants } from '../style'`)
|
|
357
|
+
expect(jsFile?.content).toContain(
|
|
358
|
+
`const MyComponentContainer = styled('div')(projectStyleVariants)`
|
|
359
|
+
)
|
|
348
360
|
})
|
|
349
361
|
|
|
350
362
|
it('Styled JSX', async () => {
|
|
@@ -355,7 +367,7 @@ describe('Referes from project style and adds it to the node, without any styles
|
|
|
355
367
|
const { files } = await generator.generateComponent(uidl, options)
|
|
356
368
|
const jsFile = findFileByType(files, FileType.JS)
|
|
357
369
|
// Styled JSX is used only with NextJS, for NextJS we don't need to import anything
|
|
358
|
-
expect(jsFile
|
|
370
|
+
expect(jsFile?.content).toContain('<div className="primaryButton">')
|
|
359
371
|
})
|
|
360
372
|
|
|
361
373
|
it('React JSS', async () => {
|
|
@@ -366,8 +378,8 @@ describe('Referes from project style and adds it to the node, without any styles
|
|
|
366
378
|
const { files } = await generator.generateComponent(uidl, options)
|
|
367
379
|
const jsFile = findFileByType(files, FileType.JS)
|
|
368
380
|
|
|
369
|
-
expect(jsFile
|
|
370
|
-
expect(jsFile
|
|
371
|
-
expect(jsFile
|
|
381
|
+
expect(jsFile?.content).toContain(`div className={projectStyles['primaryButton']}>`)
|
|
382
|
+
expect(jsFile?.content).toContain(`const projectStyles = useProjectStyles()`)
|
|
383
|
+
expect(jsFile?.content).toContain(`import { useProjectStyles } from '../style'`)
|
|
372
384
|
})
|
|
373
385
|
})
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A UIDL state name is DATA — it mirrors a database column, and a WoW character
|
|
3
|
+
* sheet has a column called `class`. The generator turned that straight into a
|
|
4
|
+
* JS binding:
|
|
5
|
+
*
|
|
6
|
+
* const [class, setClass] = useState("")
|
|
7
|
+
*
|
|
8
|
+
* which is a SyntaxError, so the prettier post-processor threw and `packProject`
|
|
9
|
+
* aborted — every page of the project failed to generate, not just this one.
|
|
10
|
+
*
|
|
11
|
+
* These tests exercise the reserved name in every position a state can appear
|
|
12
|
+
* (declaration, text binding, attribute binding, conditional, event setter).
|
|
13
|
+
* `createReactComponentGenerator()` runs the prettier post-processor, so a
|
|
14
|
+
* generation that RESOLVES is itself proof that the emitted module parses —
|
|
15
|
+
* a missed emission site would reject here.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { createReactComponentGenerator } from '../../src'
|
|
19
|
+
import { GeneratedFile } from '@teleporthq/teleport-types'
|
|
20
|
+
import {
|
|
21
|
+
component,
|
|
22
|
+
definition,
|
|
23
|
+
staticNode,
|
|
24
|
+
dynamicNode,
|
|
25
|
+
elementNode,
|
|
26
|
+
conditionalNode,
|
|
27
|
+
} from '@teleporthq/teleport-uidl-builders'
|
|
28
|
+
|
|
29
|
+
const generator = createReactComponentGenerator()
|
|
30
|
+
|
|
31
|
+
const JS_FILE = 'js'
|
|
32
|
+
const findFileByType = (files: GeneratedFile[], type: string = JS_FILE) =>
|
|
33
|
+
files.find((file) => file.fileType === type)
|
|
34
|
+
|
|
35
|
+
const reservedStateUidl = component(
|
|
36
|
+
'Character Sheet',
|
|
37
|
+
elementNode('container', {}, [
|
|
38
|
+
// Text binding.
|
|
39
|
+
elementNode('text', {}, [dynamicNode('state', 'class')]),
|
|
40
|
+
// Attribute binding.
|
|
41
|
+
elementNode('input', { value: dynamicNode('state', 'class') }, []),
|
|
42
|
+
// Conditional.
|
|
43
|
+
conditionalNode(
|
|
44
|
+
dynamicNode('state', 'class'),
|
|
45
|
+
elementNode('text', {}, [staticNode('Class chosen')]),
|
|
46
|
+
true
|
|
47
|
+
),
|
|
48
|
+
// Event setter.
|
|
49
|
+
elementNode('button', {}, [staticNode('Reset')], null, null, {
|
|
50
|
+
click: [{ type: 'stateChange', modifies: 'class', newState: '' }],
|
|
51
|
+
}),
|
|
52
|
+
// A neighbouring ordinary state must be untouched by the fix.
|
|
53
|
+
elementNode('text', {}, [dynamicNode('state', 'realm')]),
|
|
54
|
+
]),
|
|
55
|
+
{},
|
|
56
|
+
{
|
|
57
|
+
class: definition('string', ''),
|
|
58
|
+
realm: definition('string', ''),
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
describe('Component with a RESERVED-WORD state name', () => {
|
|
63
|
+
it('generates a module that parses (prettier would reject `const [class, …]`)', async () => {
|
|
64
|
+
const result = await generator.generateComponent(reservedStateUidl)
|
|
65
|
+
expect(findFileByType(result.files, JS_FILE)).toBeDefined()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('declares the state under a bindable identifier', async () => {
|
|
69
|
+
const { content } = findFileByType(
|
|
70
|
+
(await generator.generateComponent(reservedStateUidl)).files,
|
|
71
|
+
JS_FILE
|
|
72
|
+
)
|
|
73
|
+
expect(content).toContain('const [class_, setClass] = useState')
|
|
74
|
+
expect(content).not.toContain('const [class,')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('reads the state through the SAME identifier it declared', async () => {
|
|
78
|
+
const { content } = findFileByType(
|
|
79
|
+
(await generator.generateComponent(reservedStateUidl)).files,
|
|
80
|
+
JS_FILE
|
|
81
|
+
)
|
|
82
|
+
// Text + attribute + conditional all bind the sanitised name.
|
|
83
|
+
// (`value` is emitted as React's `defaultValue` by the attribute mapper.)
|
|
84
|
+
expect(content).toContain('{class_}')
|
|
85
|
+
expect(content).toContain('defaultValue={class_}')
|
|
86
|
+
expect(content).toContain('{class_ && ')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('calls the setter for the state-change event', async () => {
|
|
90
|
+
const { content } = findFileByType(
|
|
91
|
+
(await generator.generateComponent(reservedStateUidl)).files,
|
|
92
|
+
JS_FILE
|
|
93
|
+
)
|
|
94
|
+
expect(content).toContain('setClass(')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('leaves an ordinary neighbouring state byte-identical', async () => {
|
|
98
|
+
const { content } = findFileByType(
|
|
99
|
+
(await generator.generateComponent(reservedStateUidl)).files,
|
|
100
|
+
JS_FILE
|
|
101
|
+
)
|
|
102
|
+
expect(content).toContain('const [realm, setRealm] = useState')
|
|
103
|
+
expect(content).toContain('{realm}')
|
|
104
|
+
})
|
|
105
|
+
})
|
|
@@ -49,8 +49,8 @@ describe('React Styles in Component', () => {
|
|
|
49
49
|
const jsFile = findFileByType(result.files, FileType.JS)
|
|
50
50
|
|
|
51
51
|
expect(jsFile).toBeDefined()
|
|
52
|
-
expect(jsFile
|
|
53
|
-
expect(jsFile
|
|
52
|
+
expect(jsFile?.content).toContain('display: active')
|
|
53
|
+
expect(jsFile?.content).toContain('height: props.config.height')
|
|
54
54
|
})
|
|
55
55
|
|
|
56
56
|
it('CSSModules should refer state in styles when state is mapped', async () => {
|
|
@@ -63,9 +63,9 @@ describe('React Styles in Component', () => {
|
|
|
63
63
|
|
|
64
64
|
expect(jsFile).toBeDefined()
|
|
65
65
|
expect(cssFile).toBeDefined()
|
|
66
|
-
expect(jsFile
|
|
67
|
-
expect(jsFile
|
|
68
|
-
expect(cssFile
|
|
66
|
+
expect(jsFile?.content).toContain('display: active')
|
|
67
|
+
expect(jsFile?.content).toContain('height: props.config.height')
|
|
68
|
+
expect(cssFile?.content).toContain('align-self: center;')
|
|
69
69
|
})
|
|
70
70
|
|
|
71
71
|
it('Basic CSS should refer state in styles when state is mapped', async () => {
|
|
@@ -78,9 +78,9 @@ describe('React Styles in Component', () => {
|
|
|
78
78
|
|
|
79
79
|
expect(jsFile).toBeDefined()
|
|
80
80
|
expect(cssFile).toBeDefined()
|
|
81
|
-
expect(jsFile
|
|
82
|
-
expect(jsFile
|
|
83
|
-
expect(cssFile
|
|
81
|
+
expect(jsFile?.content).toContain('display: active')
|
|
82
|
+
expect(jsFile?.content).toContain('height: props.config.height')
|
|
83
|
+
expect(cssFile?.content).toContain('align-self: center;')
|
|
84
84
|
})
|
|
85
85
|
|
|
86
86
|
it('JSS should through error when state is refered', async () => {
|
|
@@ -106,8 +106,8 @@ describe('React Styles in Component', () => {
|
|
|
106
106
|
const jsFile = findFileByType(result.files, FileType.JS)
|
|
107
107
|
|
|
108
108
|
expect(jsFile).toBeDefined()
|
|
109
|
-
expect(jsFile
|
|
110
|
-
expect(jsFile
|
|
109
|
+
expect(jsFile?.content).toContain('props.direction')
|
|
110
|
+
expect(jsFile?.content).toContain(`alignSelf: 'center'`)
|
|
111
111
|
})
|
|
112
112
|
|
|
113
113
|
it('should support object props in styledjsx', async () => {
|
|
@@ -118,21 +118,19 @@ describe('React Styles in Component', () => {
|
|
|
118
118
|
const jsFile = findFileByType(result.files, FileType.JS)
|
|
119
119
|
|
|
120
120
|
expect(jsFile).toBeDefined()
|
|
121
|
-
expect(jsFile
|
|
121
|
+
expect(jsFile?.content).toContain(`align-self: center`)
|
|
122
122
|
})
|
|
123
123
|
|
|
124
|
-
it('should
|
|
124
|
+
it('should resolve a state reference in StyledJSX to an inline style', async () => {
|
|
125
125
|
const styledJSXGenerator = createReactComponentGenerator({
|
|
126
126
|
variation: ReactStyleVariation.StyledJSX,
|
|
127
127
|
})
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
)
|
|
135
|
-
}
|
|
128
|
+
const result = await styledJSXGenerator.generateComponent(ComponentWithInvalidStateStyles)
|
|
129
|
+
const jsFile = findFileByType(result.files, FileType.JS)
|
|
130
|
+
|
|
131
|
+
expect(jsFile).toBeDefined()
|
|
132
|
+
expect(jsFile?.content).toContain('backgroundColor: active')
|
|
133
|
+
expect(jsFile?.content).toContain(`height: \${props.config.height}`)
|
|
136
134
|
})
|
|
137
135
|
|
|
138
136
|
it('should explicitly send prop if style is using one prop variable', async () => {
|
|
@@ -145,8 +143,8 @@ describe('React Styles in Component', () => {
|
|
|
145
143
|
const jsFile = findFileByType(result.files, FileType.JS)
|
|
146
144
|
|
|
147
145
|
expect(jsFile).toBeDefined()
|
|
148
|
-
expect(jsFile
|
|
149
|
-
expect(jsFile
|
|
146
|
+
expect(jsFile?.content).toContain('<ComponentWithSinglePropContainer')
|
|
147
|
+
expect(jsFile?.content).toContain('height: props.config.height')
|
|
150
148
|
})
|
|
151
149
|
|
|
152
150
|
it('should inject props only once for styled components', async () => {
|
|
@@ -156,21 +154,21 @@ describe('React Styles in Component', () => {
|
|
|
156
154
|
const result = await styledJSXGenerator.generateComponent(ComponentWithValidStyle)
|
|
157
155
|
|
|
158
156
|
const jsFile = findFileByType(result.files, FileType.JS)
|
|
159
|
-
expect(jsFile
|
|
157
|
+
expect(jsFile?.content).toContain('<ComponentWithAttrPropContainer {...props}')
|
|
160
158
|
})
|
|
161
159
|
|
|
162
|
-
it('should
|
|
160
|
+
it('should resolve a state reference in StyledComponents to an inline style', async () => {
|
|
163
161
|
const styledComponentsGenerator = createReactComponentGenerator({
|
|
164
162
|
variation: ReactStyleVariation.StyledComponents,
|
|
165
163
|
})
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
164
|
+
const result = await styledComponentsGenerator.generateComponent(
|
|
165
|
+
ComponentWithInvalidStateStyles
|
|
166
|
+
)
|
|
167
|
+
const jsFile = findFileByType(result.files, FileType.JS)
|
|
168
|
+
|
|
169
|
+
expect(jsFile).toBeDefined()
|
|
170
|
+
expect(jsFile?.content).toContain('backgroundColor: active')
|
|
171
|
+
expect(jsFile?.content).toContain('height: props.config.height')
|
|
174
172
|
})
|
|
175
173
|
})
|
|
176
174
|
|
|
@@ -184,9 +182,9 @@ describe('React Styles in Component', () => {
|
|
|
184
182
|
|
|
185
183
|
expect(jsFile).toBeDefined()
|
|
186
184
|
expect(cssFile).toBeDefined()
|
|
187
|
-
expect(jsFile
|
|
188
|
-
expect(jsFile
|
|
189
|
-
expect(cssFile
|
|
185
|
+
expect(jsFile?.content).toContain('import React')
|
|
186
|
+
expect(jsFile?.content).toContain('flexDirection: props.direction')
|
|
187
|
+
expect(cssFile?.content).toContain(`align-self: center`)
|
|
190
188
|
})
|
|
191
189
|
})
|
|
192
190
|
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createReactComponentGenerator } from '../../src'
|
|
2
|
+
import componentUIDL from '../../../../examples/uidl-samples/component.json'
|
|
3
|
+
import { FileType } from '@teleporthq/teleport-types'
|
|
4
|
+
|
|
5
|
+
describe('declares a propDefinitions with type object and use it', () => {
|
|
6
|
+
test('use the value from the object in prop', async () => {
|
|
7
|
+
const generator = createReactComponentGenerator()
|
|
8
|
+
const result = await generator.generateComponent(componentUIDL)
|
|
9
|
+
const jsFile = result.files.find((file) => file.fileType === FileType.JS)
|
|
10
|
+
|
|
11
|
+
expect(jsFile).toBeDefined()
|
|
12
|
+
expect(jsFile?.content).toContain('config: PropTypes.object')
|
|
13
|
+
expect(jsFile?.content).toContain("height: props.config?.['height']")
|
|
14
|
+
expect(jsFile?.content).toContain(`config: {
|
|
15
|
+
height: 30,
|
|
16
|
+
width: 30,
|
|
17
|
+
}`)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createReactComponentGenerator } from '../../src'
|
|
2
|
+
import {
|
|
3
|
+
ComponentUIDL,
|
|
4
|
+
GeneratedFile,
|
|
5
|
+
FileType,
|
|
6
|
+
ReactStyleVariation,
|
|
7
|
+
} from '@teleporthq/teleport-types'
|
|
8
|
+
import { dynamicNode, staticNode, component, elementNode } from '@teleporthq/teleport-uidl-builders'
|
|
9
|
+
|
|
10
|
+
const findFileByType = (files: GeneratedFile[], type: string = FileType.JS) =>
|
|
11
|
+
files.find((file) => file.fileType === type)
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A dynamic STYLE value bound to an object PROP field (a prop reference with a
|
|
15
|
+
* refPath) must be emitted as an INLINE `style={{ ... }}` expression that keeps
|
|
16
|
+
* the full member access — NOT left to the styled-jsx `${props.x}` interpolation,
|
|
17
|
+
* which only uses `content.id` and would drop the refPath (producing
|
|
18
|
+
* `props.product` instead of `props.product.color`).
|
|
19
|
+
*/
|
|
20
|
+
describe('Dynamic style values → inline style', () => {
|
|
21
|
+
const ComponentWithObjectPropStyle: ComponentUIDL = component(
|
|
22
|
+
'ComponentWithObjectPropStyle',
|
|
23
|
+
elementNode('container', {}, [], undefined, {
|
|
24
|
+
backgroundColor: dynamicNode('prop', 'product', ['color']),
|
|
25
|
+
alignSelf: staticNode('center'),
|
|
26
|
+
}),
|
|
27
|
+
{
|
|
28
|
+
product: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
defaultValue: {},
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
it('inlines an object-prop-field style (prop + refPath) with the full path', async () => {
|
|
36
|
+
const generator = createReactComponentGenerator({ variation: ReactStyleVariation.StyledJSX })
|
|
37
|
+
const result = await generator.generateComponent(ComponentWithObjectPropStyle)
|
|
38
|
+
const jsFile = findFileByType(result.files, FileType.JS)
|
|
39
|
+
|
|
40
|
+
expect(jsFile).toBeDefined()
|
|
41
|
+
// The full object-field access is inlined (optional-chained), keeping refPath.
|
|
42
|
+
expect(jsFile?.content).toContain('style={{')
|
|
43
|
+
expect(jsFile?.content).toContain("props.product?.['color']")
|
|
44
|
+
// …and the styled-jsx CSS block does NOT carry a broken `props.product`
|
|
45
|
+
// background-color declaration (which would drop the `.color` refPath).
|
|
46
|
+
expect(jsFile?.content).not.toContain(`background-color: \${props.product}`)
|
|
47
|
+
// The static sibling still goes through the shared CSS class.
|
|
48
|
+
expect(jsFile?.content).toContain('align-self: center')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('keeps a SIMPLE prop style (no refPath) on the styled-jsx interpolation path', async () => {
|
|
52
|
+
const ComponentWithSimplePropStyle: ComponentUIDL = component(
|
|
53
|
+
'ComponentWithSimplePropStyle',
|
|
54
|
+
elementNode('container', {}, [], undefined, {
|
|
55
|
+
color: dynamicNode('prop', 'textColor'),
|
|
56
|
+
}),
|
|
57
|
+
{
|
|
58
|
+
textColor: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
defaultValue: 'black',
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
const generator = createReactComponentGenerator({ variation: ReactStyleVariation.StyledJSX })
|
|
65
|
+
const result = await generator.generateComponent(ComponentWithSimplePropStyle)
|
|
66
|
+
const jsFile = findFileByType(result.files, FileType.JS)
|
|
67
|
+
|
|
68
|
+
expect(jsFile).toBeDefined()
|
|
69
|
+
// Simple prop stays a styled-jsx interpolation inside the <style jsx> block.
|
|
70
|
+
expect(jsFile?.content).toContain(`\${props.textColor}`)
|
|
71
|
+
})
|
|
72
|
+
})
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,mBAAmB,EACnB,0BAA0B,EAE3B,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,mBAAmB,EACnB,0BAA0B,EAE3B,MAAM,4BAA4B,CAAA;AAEnC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAoB9C,QAAA,MAAM,6BAA6B,EAAE,0BA6BpC,CAAA;AAED,OAAO,EAAE,6BAA6B,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAA"}
|