@teleporthq/teleport-plugin-css 0.40.0 → 0.40.3
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/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +134 -39
- package/dist/cjs/index.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 +135 -40
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/index.ts +179 -49
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,
|
|
@@ -14,6 +20,9 @@ import {
|
|
|
14
20
|
PluginCSS,
|
|
15
21
|
UIDLElement,
|
|
16
22
|
UIDLElementNode,
|
|
23
|
+
UIDLExpressionValue,
|
|
24
|
+
StateDefaultValueTypes,
|
|
25
|
+
PropDefaultValueTypes,
|
|
17
26
|
} from '@teleporthq/teleport-types'
|
|
18
27
|
import { createStyleSheetPlugin } from './style-sheet'
|
|
19
28
|
import { createConditionalStatement } from './utils'
|
|
@@ -45,7 +54,12 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
45
54
|
|
|
46
55
|
const cssPlugin: ComponentPlugin = async (structure) => {
|
|
47
56
|
const { uidl, chunks, dependencies, options } = structure
|
|
48
|
-
const {
|
|
57
|
+
const {
|
|
58
|
+
node,
|
|
59
|
+
styleSetDefinitions: componentStyleSet = {},
|
|
60
|
+
propDefinitions = {},
|
|
61
|
+
stateDefinitions = {},
|
|
62
|
+
} = uidl
|
|
49
63
|
const { projectStyleSet, designLanguage: { tokens = {} } = {}, isRootComponent } = options || {}
|
|
50
64
|
const {
|
|
51
65
|
styleSetDefinitions = {},
|
|
@@ -89,7 +103,7 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
89
103
|
|
|
90
104
|
const generateStylesForElementNode = (element: UIDLElement) => {
|
|
91
105
|
const classNamesToAppend: Set<string> = new Set()
|
|
92
|
-
const dynamicVariantsToAppend: Set<string> = new Set()
|
|
106
|
+
const dynamicVariantsToAppend: Set<string | types.ConditionalExpression> = new Set()
|
|
93
107
|
const {
|
|
94
108
|
style = {},
|
|
95
109
|
key,
|
|
@@ -255,59 +269,170 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
255
269
|
}
|
|
256
270
|
|
|
257
271
|
if (styleRef.content.condition) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
|
273
356
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
|
278
387
|
}
|
|
279
388
|
|
|
280
|
-
|
|
281
|
-
defaultValue = defaultValue ?? usedProp.defaultValue
|
|
282
|
-
|
|
283
|
-
// Since we know the operand and the default value from the prop.
|
|
284
|
-
// We can try building the condition and check if the condition is true or false.
|
|
285
|
-
// @todo: You can only use a 'value' in UIDL or 'conditions' but not both.
|
|
286
|
-
// UIDL validations need to be improved on this aspect.
|
|
287
|
-
const dynamicConditions = createConditionalStatement(
|
|
288
|
-
staticValue !== undefined
|
|
289
|
-
? [{ operand: staticValue, operation: '===' }]
|
|
290
|
-
: conditions,
|
|
291
|
-
defaultValue
|
|
292
|
-
)
|
|
293
|
-
const matchCondition =
|
|
294
|
-
matchingCriteria && matchingCriteria === 'all' ? '&&' : '||'
|
|
295
|
-
const conditionString = dynamicConditions.join(` ${matchCondition} `)
|
|
296
|
-
|
|
297
|
-
// tslint:disable-next-line function-constructor
|
|
298
|
-
const isConditionPassing = new Function(`return ${conditionString}`)()
|
|
299
|
-
if (isConditionPassing) {
|
|
389
|
+
default: {
|
|
300
390
|
classNamesToAppend.add(styleRef.content.referenceId)
|
|
301
391
|
return
|
|
302
392
|
}
|
|
303
|
-
return
|
|
304
393
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
+
}
|
|
310
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
|
|
311
436
|
}
|
|
312
437
|
} else {
|
|
313
438
|
classNamesToAppend.add(content.referenceId)
|
|
@@ -352,7 +477,12 @@ const createCSSPlugin: ComponentPluginFactory<CSSPluginConfig> = (config) => {
|
|
|
352
477
|
? types.identifier(dynamicVariantPrefix)
|
|
353
478
|
: types.identifier(propsPrefix)
|
|
354
479
|
|
|
355
|
-
|
|
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
|
+
}
|
|
356
486
|
})
|
|
357
487
|
)
|
|
358
488
|
}
|