@teleporthq/teleport-plugin-css 0.41.0 → 0.42.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/__tests__/component-scoped.ts +4 -2
- package/__tests__/style-sheet.ts +3 -3
- package/dist/cjs/index.d.ts +0 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +182 -37
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/style-sheet.d.ts +1 -0
- package/dist/cjs/style-sheet.d.ts.map +1 -1
- package/dist/cjs/style-sheet.js +41 -10
- package/dist/cjs/style-sheet.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts +3 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +29 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +183 -38
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/style-sheet.d.ts +1 -0
- package/dist/esm/style-sheet.d.ts.map +1 -1
- package/dist/esm/style-sheet.js +41 -10
- package/dist/esm/style-sheet.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts +3 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +25 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +5 -5
- package/src/index.ts +236 -44
- package/src/style-sheet.ts +58 -12
- package/src/utils.ts +36 -0
package/src/index.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
StyleUtils,
|
|
4
|
+
StyleBuilders,
|
|
5
|
+
HASTUtils,
|
|
6
|
+
ASTUtils,
|
|
7
|
+
createBinaryExpression,
|
|
8
|
+
} from '@teleporthq/teleport-plugin-common'
|
|
3
9
|
import * as types from '@babel/types'
|
|
4
10
|
import {
|
|
5
11
|
ComponentPluginFactory,
|
|
@@ -12,8 +18,14 @@ import {
|
|
|
12
18
|
UIDLElementNodeReferenceStyles,
|
|
13
19
|
UIDLStyleMediaQueryScreenSizeCondition,
|
|
14
20
|
PluginCSS,
|
|
21
|
+
UIDLElement,
|
|
22
|
+
UIDLElementNode,
|
|
23
|
+
UIDLExpressionValue,
|
|
24
|
+
StateDefaultValueTypes,
|
|
25
|
+
PropDefaultValueTypes,
|
|
15
26
|
} from '@teleporthq/teleport-types'
|
|
16
27
|
import { createStyleSheetPlugin } from './style-sheet'
|
|
28
|
+
import { createConditionalStatement } from './utils'
|
|
17
29
|
|
|
18
30
|
interface CSSPluginConfig {
|
|
19
31
|
chunkName: string
|
|
@@ -21,7 +33,6 @@ interface CSSPluginConfig {
|
|
|
21
33
|
componentDecoratorChunkName: string
|
|
22
34
|
inlineStyleAttributeKey: string // style vs :style vs ...
|
|
23
35
|
classAttributeName: string // class vs className
|
|
24
|
-
forceScoping: boolean // class names get the component name prefix
|
|
25
36
|
templateStyle: 'html' | 'jsx'
|
|
26
37
|
declareDependency: 'import' | 'decorator' | 'none'
|
|
27
38
|
dynamicVariantPrefix?: string
|
|
@@ -37,14 +48,18 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
37
48
|
classAttributeName = 'class',
|
|
38
49
|
templateStyle = 'html',
|
|
39
50
|
declareDependency = 'none',
|
|
40
|
-
forceScoping = false,
|
|
41
51
|
dynamicVariantPrefix,
|
|
42
52
|
staticPropReferences = false,
|
|
43
53
|
} = config || {}
|
|
44
54
|
|
|
45
55
|
const cssPlugin: ComponentPlugin = async (structure) => {
|
|
46
56
|
const { uidl, chunks, dependencies, options } = structure
|
|
47
|
-
const {
|
|
57
|
+
const {
|
|
58
|
+
node,
|
|
59
|
+
styleSetDefinitions: componentStyleSet = {},
|
|
60
|
+
propDefinitions = {},
|
|
61
|
+
stateDefinitions = {},
|
|
62
|
+
} = uidl
|
|
48
63
|
const { projectStyleSet, designLanguage: { tokens = {} } = {}, isRootComponent } = options || {}
|
|
49
64
|
const {
|
|
50
65
|
styleSetDefinitions = {},
|
|
@@ -71,7 +86,7 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
71
86
|
(chunk) => chunk.name === componentDecoratorChunkName
|
|
72
87
|
)
|
|
73
88
|
|
|
74
|
-
const
|
|
89
|
+
const jsxNodesLookup = templateChunk.meta.nodesLookup as Record<
|
|
75
90
|
string,
|
|
76
91
|
HastNode | types.JSXElement
|
|
77
92
|
>
|
|
@@ -86,27 +101,33 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
86
101
|
Array<{ [x: string]: Record<string, string | number> }>
|
|
87
102
|
> = {}
|
|
88
103
|
|
|
89
|
-
|
|
104
|
+
const generateStylesForElementNode = (element: UIDLElement) => {
|
|
90
105
|
const classNamesToAppend: Set<string> = new Set()
|
|
91
|
-
const dynamicVariantsToAppend: Set<string> = new Set()
|
|
106
|
+
const dynamicVariantsToAppend: Set<string | types.ConditionalExpression> = new Set()
|
|
92
107
|
const {
|
|
93
108
|
style = {},
|
|
94
109
|
key,
|
|
95
110
|
referencedStyles = {},
|
|
96
|
-
dependency,
|
|
97
111
|
attrs = {},
|
|
98
112
|
elementType,
|
|
113
|
+
dependency,
|
|
99
114
|
} = element
|
|
100
|
-
const elementClassName = StringUtils.camelCaseToDashCase(key)
|
|
101
115
|
|
|
102
|
-
|
|
116
|
+
const root = jsxNodesLookup[key]
|
|
117
|
+
if (!root) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Refer to line 323 all component scoped styles are appended with component name by default
|
|
122
|
+
if (dependency?.type === 'local') {
|
|
103
123
|
StyleBuilders.setPropValueForCompStyle({
|
|
104
124
|
attrs,
|
|
105
|
-
|
|
106
|
-
jsxNodesLookup: templateLookup,
|
|
125
|
+
root,
|
|
107
126
|
templateStyle,
|
|
127
|
+
// elementType is used here in-order to target the component name that the class is actually defined.
|
|
128
|
+
// Here we are appendigng to the node where the component is being called.
|
|
108
129
|
getClassName: (styleName: string) =>
|
|
109
|
-
|
|
130
|
+
StringUtils.camelCaseToDashCase(elementType + styleName),
|
|
110
131
|
})
|
|
111
132
|
}
|
|
112
133
|
|
|
@@ -118,12 +139,7 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
118
139
|
return
|
|
119
140
|
}
|
|
120
141
|
|
|
121
|
-
const
|
|
122
|
-
if (!root) {
|
|
123
|
-
throw new PluginCSS(`Node - ${key} is missing from the template chunk`)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const className = getClassName(forceScoping, uidl.name, elementClassName)
|
|
142
|
+
const className = StringUtils.camelCaseToDashCase(key)
|
|
127
143
|
|
|
128
144
|
const { staticStyles, dynamicStyles, tokenStyles } =
|
|
129
145
|
UIDLUtils.splitDynamicAndStaticStyles(style)
|
|
@@ -206,24 +222,21 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
206
222
|
propDefinitions[styleRef.content.content.content.id]?.defaultValue
|
|
207
223
|
|
|
208
224
|
if (defaultPropValue) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
propDefinitions[styleRef.content.content.content.id].defaultValue = getClassName(
|
|
212
|
-
forceScoping,
|
|
213
|
-
uidl.name,
|
|
214
|
-
String(defaultPropValue)
|
|
215
|
-
)
|
|
225
|
+
propDefinitions[styleRef.content.content.content.id].defaultValue =
|
|
226
|
+
StringUtils.camelCaseToDashCase(String(defaultPropValue))
|
|
216
227
|
}
|
|
217
228
|
|
|
229
|
+
// staticPropReferences flag is only used for just html-code generation.
|
|
230
|
+
// This is used to append the class name to the node where the component is being called.
|
|
231
|
+
// Instead of how frameworks handle them using props at runtime. This makes the props
|
|
232
|
+
// to behave statically during the generation time instead by appending them directly.
|
|
218
233
|
if (staticPropReferences) {
|
|
219
|
-
if (
|
|
234
|
+
if (defaultPropValue === undefined || typeof defaultPropValue !== 'string') {
|
|
220
235
|
return
|
|
221
236
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
)
|
|
226
|
-
}
|
|
237
|
+
classNamesToAppend.add(
|
|
238
|
+
StringUtils.camelCaseToDashCase(uidl.name + defaultPropValue)
|
|
239
|
+
)
|
|
227
240
|
} else {
|
|
228
241
|
dynamicVariantsToAppend.add(styleRef.content.content.content.id)
|
|
229
242
|
}
|
|
@@ -239,7 +252,7 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
239
252
|
)
|
|
240
253
|
}
|
|
241
254
|
classNamesToAppend.add(
|
|
242
|
-
|
|
255
|
+
StringUtils.camelCaseToDashCase(uidl.name + styleRef.content.content.content.id)
|
|
243
256
|
)
|
|
244
257
|
}
|
|
245
258
|
|
|
@@ -255,7 +268,175 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
255
268
|
)
|
|
256
269
|
}
|
|
257
270
|
|
|
258
|
-
|
|
271
|
+
if (styleRef.content.condition) {
|
|
272
|
+
if (templateStyle === 'html') {
|
|
273
|
+
const {
|
|
274
|
+
value: staticValue,
|
|
275
|
+
reference,
|
|
276
|
+
expression: { conditions, matchingCriteria },
|
|
277
|
+
} = styleRef.content.condition
|
|
278
|
+
|
|
279
|
+
const {
|
|
280
|
+
content: { referenceType, id, refPath = [] },
|
|
281
|
+
} = reference
|
|
282
|
+
|
|
283
|
+
switch (referenceType) {
|
|
284
|
+
case 'prop': {
|
|
285
|
+
const usedProp = propDefinitions[id]
|
|
286
|
+
if (usedProp === undefined || usedProp.defaultValue === undefined) {
|
|
287
|
+
throw new PluginCSS(`Prop with ${id} is missing in the propDefinitions.`)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
let defaultValue = usedProp.defaultValue
|
|
291
|
+
let operandDefaultValue: StateDefaultValueTypes | PropDefaultValueTypes | string
|
|
292
|
+
for (const path of refPath) {
|
|
293
|
+
defaultValue = (defaultValue as Record<string, unknown[]>)?.[path]
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// If defaultValue is undefined or null after path traversal, use original default
|
|
297
|
+
defaultValue = defaultValue ?? usedProp.defaultValue
|
|
298
|
+
|
|
299
|
+
// our conditions can be of type 'expr' or they can be a dynamic reference
|
|
300
|
+
const rightSideCondition = conditions[0].operand
|
|
301
|
+
const rightSideConditionType = typeof rightSideCondition
|
|
302
|
+
if (rightSideConditionType === 'object') {
|
|
303
|
+
const type = (
|
|
304
|
+
rightSideCondition as UIDLDynamicReference | UIDLExpressionValue
|
|
305
|
+
).type
|
|
306
|
+
if (type === 'dynamic') {
|
|
307
|
+
const dynamicRef = rightSideCondition as UIDLDynamicReference
|
|
308
|
+
if (dynamicRef.content.referenceType === 'prop') {
|
|
309
|
+
const prop = propDefinitions[dynamicRef.content.id]
|
|
310
|
+
if (prop && prop.defaultValue) {
|
|
311
|
+
operandDefaultValue = prop.defaultValue
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (dynamicRef.content.referenceType === 'state') {
|
|
315
|
+
const state = stateDefinitions[dynamicRef.content.id]
|
|
316
|
+
if (state && state.defaultValue) {
|
|
317
|
+
defaultValue = state.defaultValue
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (type === 'expr') {
|
|
322
|
+
operandDefaultValue = (rightSideCondition as UIDLExpressionValue).content
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
operandDefaultValue = rightSideCondition
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Since we know the operand and the default value from the prop.
|
|
329
|
+
// We can try building the condition and check if the condition is true or false.
|
|
330
|
+
// @todo: You can only use a 'value' in UIDL or 'conditions' but not both.
|
|
331
|
+
// UIDL validations need to be improved on this aspect.
|
|
332
|
+
const resolvedConditions = [
|
|
333
|
+
{
|
|
334
|
+
operation: conditions[0].operation,
|
|
335
|
+
operand: operandDefaultValue as string,
|
|
336
|
+
},
|
|
337
|
+
]
|
|
338
|
+
|
|
339
|
+
const dynamicConditions = createConditionalStatement(
|
|
340
|
+
staticValue !== undefined
|
|
341
|
+
? [{ operand: staticValue, operation: '===' }]
|
|
342
|
+
: resolvedConditions,
|
|
343
|
+
defaultValue
|
|
344
|
+
)
|
|
345
|
+
const matchCondition =
|
|
346
|
+
matchingCriteria && matchingCriteria === 'all' ? '&&' : '||'
|
|
347
|
+
const conditionString = dynamicConditions.join(` ${matchCondition} `)
|
|
348
|
+
|
|
349
|
+
// tslint:disable-next-line function-constructor
|
|
350
|
+
const isConditionPassing = new Function(`return ${conditionString}`)()
|
|
351
|
+
if (isConditionPassing) {
|
|
352
|
+
classNamesToAppend.add(styleRef.content.referenceId)
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
case 'state': {
|
|
358
|
+
const usedState = stateDefinitions[id]
|
|
359
|
+
if (usedState === undefined || usedState.defaultValue === undefined) {
|
|
360
|
+
throw new PluginCSS(`State with ${id} is missing in the stateDefinitions.`)
|
|
361
|
+
}
|
|
362
|
+
let defaultValue = usedState.defaultValue
|
|
363
|
+
for (const path of refPath) {
|
|
364
|
+
defaultValue = (defaultValue as Record<string, unknown[]>)?.[path]
|
|
365
|
+
}
|
|
366
|
+
// If defaultValue is undefined or null after path traversal, use original default
|
|
367
|
+
defaultValue = defaultValue ?? usedState.defaultValue
|
|
368
|
+
// Since we know the operand and the default value from the state.
|
|
369
|
+
// We can try building the condition and check if the condition is true or false.
|
|
370
|
+
|
|
371
|
+
const dynamicConditions = createConditionalStatement(
|
|
372
|
+
staticValue !== undefined
|
|
373
|
+
? [{ operand: staticValue, operation: '===' }]
|
|
374
|
+
: conditions,
|
|
375
|
+
defaultValue
|
|
376
|
+
)
|
|
377
|
+
const matchCondition =
|
|
378
|
+
matchingCriteria && matchingCriteria === 'all' ? '&&' : '||'
|
|
379
|
+
const conditionString = dynamicConditions.join(` ${matchCondition} `)
|
|
380
|
+
// tslint:disable-next-line function-constructor
|
|
381
|
+
const isConditionPassing = new Function(`return ${conditionString}`)()
|
|
382
|
+
if (isConditionPassing) {
|
|
383
|
+
classNamesToAppend.add(styleRef.content.referenceId)
|
|
384
|
+
return
|
|
385
|
+
}
|
|
386
|
+
return
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
default: {
|
|
390
|
+
classNamesToAppend.add(styleRef.content.referenceId)
|
|
391
|
+
return
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
const nameToAppend = styleRef.content.condition.reference.content.id
|
|
396
|
+
|
|
397
|
+
const { conditions } = styleRef.content.condition.expression
|
|
398
|
+
|
|
399
|
+
const operator = conditions[0].operation as '===' | '!==' | '<' | '<=' | '>' | '>='
|
|
400
|
+
const right = conditions[0].operand as string | number | boolean
|
|
401
|
+
const referenceType = styleRef.content.condition.reference.content.referenceType
|
|
402
|
+
|
|
403
|
+
let binaryExpressionType = ''
|
|
404
|
+
switch (referenceType) {
|
|
405
|
+
case 'prop': {
|
|
406
|
+
binaryExpressionType = propDefinitions[nameToAppend].type
|
|
407
|
+
break
|
|
408
|
+
}
|
|
409
|
+
case 'state': {
|
|
410
|
+
binaryExpressionType = stateDefinitions[nameToAppend].type
|
|
411
|
+
break
|
|
412
|
+
}
|
|
413
|
+
default: {
|
|
414
|
+
throw new PluginCSS(
|
|
415
|
+
`Un-supported reference type ${referenceType} for ${nameToAppend}`
|
|
416
|
+
)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const binaryExpression = createBinaryExpression(
|
|
421
|
+
{ operation: operator, operand: right },
|
|
422
|
+
{
|
|
423
|
+
key: (referenceType === 'prop' ? 'props?.' : '') + nameToAppend,
|
|
424
|
+
type: binaryExpressionType,
|
|
425
|
+
}
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
const conditionalExpression = types.conditionalExpression(
|
|
429
|
+
binaryExpression,
|
|
430
|
+
types.stringLiteral(content.referenceId),
|
|
431
|
+
types.stringLiteral('')
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
dynamicVariantsToAppend.add(conditionalExpression)
|
|
435
|
+
return
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
classNamesToAppend.add(content.referenceId)
|
|
439
|
+
}
|
|
259
440
|
return
|
|
260
441
|
}
|
|
261
442
|
|
|
@@ -296,18 +477,35 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
296
477
|
? types.identifier(dynamicVariantPrefix)
|
|
297
478
|
: types.identifier(propsPrefix)
|
|
298
479
|
|
|
299
|
-
|
|
480
|
+
if (typeof variant === 'string') {
|
|
481
|
+
return types.memberExpression(dynamicAttrValueIdentifier, types.identifier(variant))
|
|
482
|
+
} else {
|
|
483
|
+
// variant is a ConditionalExpression, so return it directly
|
|
484
|
+
return variant
|
|
485
|
+
}
|
|
300
486
|
})
|
|
301
487
|
)
|
|
302
488
|
}
|
|
303
|
-
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
UIDLUtils.traverseElements(node, generateStylesForElementNode)
|
|
492
|
+
for (const prop of Object.values(propDefinitions)) {
|
|
493
|
+
if (prop.type === 'element' && prop.defaultValue) {
|
|
494
|
+
UIDLUtils.traverseElements(
|
|
495
|
+
prop.defaultValue as UIDLElementNode,
|
|
496
|
+
generateStylesForElementNode
|
|
497
|
+
)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
304
500
|
|
|
305
501
|
if (Object.keys(componentStyleSet).length > 0) {
|
|
306
502
|
StyleBuilders.generateStylesFromStyleSetDefinitions(
|
|
307
503
|
componentStyleSet,
|
|
308
504
|
cssMap,
|
|
309
505
|
mediaStylesMap,
|
|
310
|
-
(styleName: string) =>
|
|
506
|
+
(styleName: string) => {
|
|
507
|
+
return StringUtils.camelCaseToDashCase(uidl.name + styleName)
|
|
508
|
+
}
|
|
311
509
|
)
|
|
312
510
|
}
|
|
313
511
|
|
|
@@ -348,7 +546,7 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
348
546
|
type: ChunkType.STRING,
|
|
349
547
|
name: chunkName,
|
|
350
548
|
fileType: FileType.CSS,
|
|
351
|
-
content: cssMap.join('\n'),
|
|
549
|
+
content: cssMap.join('\n \n'),
|
|
352
550
|
linkAfter: [],
|
|
353
551
|
})
|
|
354
552
|
}
|
|
@@ -370,9 +568,3 @@ const createDynamicInlineStyle = (styles: UIDLStyleDefinitions) => {
|
|
|
370
568
|
})
|
|
371
569
|
.join(', ')
|
|
372
570
|
}
|
|
373
|
-
|
|
374
|
-
const getClassName = (scoping: boolean, uidlName: string, nodeStyleName: string) => {
|
|
375
|
-
return scoping
|
|
376
|
-
? StringUtils.camelCaseToDashCase(`${uidlName}-${nodeStyleName}`)
|
|
377
|
-
: StringUtils.camelCaseToDashCase(nodeStyleName)
|
|
378
|
-
}
|
package/src/style-sheet.ts
CHANGED
|
@@ -5,22 +5,42 @@ import {
|
|
|
5
5
|
ChunkType,
|
|
6
6
|
FileType,
|
|
7
7
|
} from '@teleporthq/teleport-types'
|
|
8
|
+
import { join, relative } from 'path'
|
|
8
9
|
|
|
9
10
|
interface StyleSheetPlugin {
|
|
10
11
|
fileName?: string
|
|
12
|
+
/*
|
|
13
|
+
Frameworks with dev servers don't need relative path mapping.
|
|
14
|
+
*/
|
|
15
|
+
relativeFontPath?: boolean
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> = (config) => {
|
|
14
|
-
const { fileName } = config || {
|
|
19
|
+
const { fileName = 'style', relativeFontPath = false } = config || {
|
|
20
|
+
fileName: 'style',
|
|
21
|
+
relativeFontPath: false,
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
const styleSheetPlugin: ComponentPlugin = async (structure) => {
|
|
16
|
-
const {
|
|
25
|
+
const {
|
|
26
|
+
uidl,
|
|
27
|
+
chunks,
|
|
28
|
+
options: { assets },
|
|
29
|
+
} = structure
|
|
17
30
|
const { styleSetDefinitions = {}, designLanguage: { tokens = {} } = {} } = uidl
|
|
31
|
+
const {
|
|
32
|
+
localFonts = [],
|
|
33
|
+
fontsFolder,
|
|
34
|
+
identifier: assetIdentifier,
|
|
35
|
+
} = assets || { localFonts: [] }
|
|
18
36
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
const canSkipThePlugin =
|
|
38
|
+
localFonts?.length === 0 &&
|
|
39
|
+
Object.keys(styleSetDefinitions).length === 0 &&
|
|
40
|
+
Object.keys(tokens).length === 0
|
|
41
|
+
|
|
42
|
+
if (canSkipThePlugin) {
|
|
43
|
+
return structure
|
|
24
44
|
}
|
|
25
45
|
|
|
26
46
|
const cssMap: string[] = []
|
|
@@ -29,6 +49,35 @@ export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> =
|
|
|
29
49
|
Array<{ [x: string]: Record<string, string | number> }>
|
|
30
50
|
> = {}
|
|
31
51
|
|
|
52
|
+
uidl.outputOptions = uidl.outputOptions || {}
|
|
53
|
+
uidl.outputOptions.styleFileName = fileName
|
|
54
|
+
|
|
55
|
+
if (localFonts.length > 0) {
|
|
56
|
+
localFonts.forEach((font) => {
|
|
57
|
+
const properties = StyleUtils.getContentOfStyleObject(font.properties) as Record<
|
|
58
|
+
string,
|
|
59
|
+
string | number
|
|
60
|
+
>
|
|
61
|
+
const format = properties?.format ? `format('${properties.format}')` : ''
|
|
62
|
+
/* tslint:disable:no-string-literal */
|
|
63
|
+
delete properties['format']
|
|
64
|
+
|
|
65
|
+
const fontPath = relativeFontPath
|
|
66
|
+
? join(
|
|
67
|
+
relative(join(...(uidl.outputOptions?.folderPath || [])), './'),
|
|
68
|
+
join(fontsFolder || '', font.path)
|
|
69
|
+
)
|
|
70
|
+
: join('/', assetIdentifier || '', 'fonts', font.path)
|
|
71
|
+
|
|
72
|
+
cssMap.push(
|
|
73
|
+
StyleBuilders.createFontDecleration({
|
|
74
|
+
...properties,
|
|
75
|
+
src: `url("${fontPath}") ${format}`,
|
|
76
|
+
})
|
|
77
|
+
)
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
32
81
|
if (Object.keys(tokens).length > 0) {
|
|
33
82
|
cssMap.push(
|
|
34
83
|
StyleBuilders.createCSSClassWithSelector(
|
|
@@ -44,7 +93,7 @@ export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> =
|
|
|
44
93
|
styleSetDefinitions,
|
|
45
94
|
cssMap,
|
|
46
95
|
mediaStylesMap,
|
|
47
|
-
(styleName
|
|
96
|
+
(styleName) => styleName
|
|
48
97
|
)
|
|
49
98
|
}
|
|
50
99
|
|
|
@@ -54,14 +103,11 @@ export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> =
|
|
|
54
103
|
return structure
|
|
55
104
|
}
|
|
56
105
|
|
|
57
|
-
uidl.outputOptions = uidl.outputOptions || {}
|
|
58
|
-
uidl.outputOptions.styleFileName = fileName
|
|
59
|
-
|
|
60
106
|
chunks.push({
|
|
61
107
|
name: fileName,
|
|
62
108
|
type: ChunkType.STRING,
|
|
63
109
|
fileType: FileType.CSS,
|
|
64
|
-
content: cssMap.join('\n'),
|
|
110
|
+
content: cssMap.join('\n \n'),
|
|
65
111
|
linkAfter: [],
|
|
66
112
|
})
|
|
67
113
|
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ASTUtils } from '@teleporthq/teleport-plugin-common'
|
|
2
|
+
import { PluginCSS, UIDLConditionalNode, UIDLPropDefinition } from '@teleporthq/teleport-types'
|
|
3
|
+
|
|
4
|
+
export const createConditionalStatement = (
|
|
5
|
+
conditions: UIDLConditionalNode['content']['condition']['conditions'],
|
|
6
|
+
leftOperand: UIDLPropDefinition['defaultValue']
|
|
7
|
+
) => {
|
|
8
|
+
return conditions.map((condition) => {
|
|
9
|
+
const { operation, operand } = condition
|
|
10
|
+
|
|
11
|
+
if (operand === undefined) {
|
|
12
|
+
return `${ASTUtils.convertToUnaryOperator(operation)}${getValueType(operand)}`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return `${getValueType(leftOperand)} ${ASTUtils.convertToBinaryOperator(
|
|
16
|
+
operation
|
|
17
|
+
)} ${getValueType(operand)}`
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const getValueType = (value: UIDLPropDefinition['defaultValue']) => {
|
|
22
|
+
const valueType = typeof value
|
|
23
|
+
switch (valueType) {
|
|
24
|
+
case 'string':
|
|
25
|
+
return `"${value}"`
|
|
26
|
+
case 'number':
|
|
27
|
+
return value
|
|
28
|
+
case 'boolean':
|
|
29
|
+
return value
|
|
30
|
+
default:
|
|
31
|
+
throw new PluginCSS(
|
|
32
|
+
`Conditional node received an operand of type ${valueType} \n
|
|
33
|
+
Received ${JSON.stringify(value)}`
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|