@teleporthq/teleport-plugin-html-base-component 0.36.5 → 0.37.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/node-handlers.d.ts.map +1 -1
- package/dist/cjs/node-handlers.js +125 -47
- package/dist/cjs/node-handlers.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/node-handlers.d.ts.map +1 -1
- package/dist/esm/node-handlers.js +127 -49
- package/dist/esm/node-handlers.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/node-handlers.ts +158 -13
package/src/node-handlers.ts
CHANGED
|
@@ -22,10 +22,11 @@ import {
|
|
|
22
22
|
UIDLComponentOutputOptions,
|
|
23
23
|
UIDLElement,
|
|
24
24
|
ElementsLookup,
|
|
25
|
+
UIDLConditionalNode,
|
|
25
26
|
} from '@teleporthq/teleport-types'
|
|
26
27
|
import { join, relative } from 'path'
|
|
27
|
-
import { HASTBuilders, HASTUtils } from '@teleporthq/teleport-plugin-common'
|
|
28
|
-
import { StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'
|
|
28
|
+
import { HASTBuilders, HASTUtils, ASTUtils } from '@teleporthq/teleport-plugin-common'
|
|
29
|
+
import { GenericUtils, StringUtils, UIDLUtils } from '@teleporthq/teleport-shared'
|
|
29
30
|
import { staticNode } from '@teleporthq/teleport-uidl-builders'
|
|
30
31
|
import { createCSSPlugin } from '@teleporthq/teleport-plugin-css'
|
|
31
32
|
import { generateUniqueKeys, createNodesLookup } from '@teleporthq/teleport-uidl-resolver'
|
|
@@ -128,7 +129,69 @@ export const generateHtmlSyntax: NodeToHTML<UIDLNode, Promise<HastNode | HastTex
|
|
|
128
129
|
return dynamicNode
|
|
129
130
|
|
|
130
131
|
case 'conditional':
|
|
131
|
-
|
|
132
|
+
const conditionalNodeComment = HASTBuilders.createComment(
|
|
133
|
+
'Conditional nodes are not supported in HTML'
|
|
134
|
+
)
|
|
135
|
+
const {
|
|
136
|
+
value: staticValue,
|
|
137
|
+
reference,
|
|
138
|
+
condition: { conditions, matchingCriteria },
|
|
139
|
+
} = node.content
|
|
140
|
+
|
|
141
|
+
if (reference.type !== 'dynamic') {
|
|
142
|
+
return conditionalNodeComment
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const {
|
|
146
|
+
content: { referenceType, id },
|
|
147
|
+
} = reference
|
|
148
|
+
|
|
149
|
+
switch (referenceType) {
|
|
150
|
+
case 'prop': {
|
|
151
|
+
const usedProp = propDefinitions[id]
|
|
152
|
+
if (usedProp === undefined || usedProp.defaultValue === undefined) {
|
|
153
|
+
return conditionalNodeComment
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Since we know the operand and the default value from the prop.
|
|
157
|
+
// We can try building the condition and check if the condition is true or false.
|
|
158
|
+
// @todo: You can only use a 'value' in UIDL or 'conditions' but not both.
|
|
159
|
+
// UIDL validations need to be improved on this aspect.
|
|
160
|
+
const dynamicConditions = createConditionalStatement(
|
|
161
|
+
staticValue !== undefined ? [{ operand: staticValue, operation: '===' }] : conditions,
|
|
162
|
+
usedProp.defaultValue
|
|
163
|
+
)
|
|
164
|
+
const matchCondition = matchingCriteria && matchingCriteria === 'all' ? '&&' : '||'
|
|
165
|
+
const conditionString = dynamicConditions.join(` ${matchCondition} `)
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
// tslint:disable-next-line function-constructor
|
|
169
|
+
const isConditionPassing = new Function(`return ${conditionString}`)()
|
|
170
|
+
if (isConditionPassing) {
|
|
171
|
+
return generateHtmlSyntax(
|
|
172
|
+
node.content.node,
|
|
173
|
+
compName,
|
|
174
|
+
nodesLookup,
|
|
175
|
+
propDefinitions,
|
|
176
|
+
stateDefinitions,
|
|
177
|
+
subComponentOptions,
|
|
178
|
+
structure
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
return conditionalNodeComment
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return conditionalNodeComment
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
case 'state':
|
|
189
|
+
default:
|
|
190
|
+
return conditionalNodeComment
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
case 'expr':
|
|
194
|
+
return HASTBuilders.createComment('Expressions are not supported in HTML')
|
|
132
195
|
|
|
133
196
|
default:
|
|
134
197
|
throw new HTMLComponentGeneratorError(
|
|
@@ -141,6 +204,40 @@ export const generateHtmlSyntax: NodeToHTML<UIDLNode, Promise<HastNode | HastTex
|
|
|
141
204
|
}
|
|
142
205
|
}
|
|
143
206
|
|
|
207
|
+
const createConditionalStatement = (
|
|
208
|
+
conditions: UIDLConditionalNode['content']['condition']['conditions'],
|
|
209
|
+
leftOperand: UIDLPropDefinition['defaultValue']
|
|
210
|
+
) => {
|
|
211
|
+
return conditions.map((condition) => {
|
|
212
|
+
const { operation, operand } = condition
|
|
213
|
+
|
|
214
|
+
if (operand === undefined) {
|
|
215
|
+
return `${ASTUtils.convertToUnaryOperator(operation)}${getValueType(operand)}`
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return `${getValueType(leftOperand)} ${ASTUtils.convertToBinaryOperator(
|
|
219
|
+
operation
|
|
220
|
+
)} ${getValueType(operand)}`
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const getValueType = (value: UIDLPropDefinition['defaultValue']) => {
|
|
225
|
+
const valueType = typeof value
|
|
226
|
+
switch (valueType) {
|
|
227
|
+
case 'string':
|
|
228
|
+
return `"${value}"`
|
|
229
|
+
case 'number':
|
|
230
|
+
return value
|
|
231
|
+
case 'boolean':
|
|
232
|
+
return value
|
|
233
|
+
default:
|
|
234
|
+
throw new HTMLComponentGeneratorError(
|
|
235
|
+
`Conditional node received an operand of type ${valueType} \n
|
|
236
|
+
Received ${JSON.stringify(value)}`
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
144
241
|
const generateElementNode: NodeToHTML<UIDLElementNode, Promise<HastNode | HastText>> = async (
|
|
145
242
|
node,
|
|
146
243
|
compName,
|
|
@@ -339,10 +436,15 @@ const generateComponentContent = async (
|
|
|
339
436
|
const combinedStates = { ...stateDefinitions, ...(componentClone?.stateDefinitions || {}) }
|
|
340
437
|
const statesForInstance = Object.keys(combinedStates).reduce(
|
|
341
438
|
(acc: Record<string, UIDLStateDefinition>, propKey) => {
|
|
342
|
-
|
|
439
|
+
const attr = attrs[propKey]
|
|
440
|
+
if (attr.type === 'object') {
|
|
441
|
+
throw new Error(`Object attributes are not supported in html exports`)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (attr) {
|
|
343
445
|
acc[propKey] = {
|
|
344
446
|
...combinedStates[propKey],
|
|
345
|
-
defaultValue:
|
|
447
|
+
defaultValue: attr?.content || combinedStates[propKey]?.defaultValue,
|
|
346
448
|
}
|
|
347
449
|
} else {
|
|
348
450
|
acc[propKey] = combinedStates[propKey]
|
|
@@ -358,8 +460,9 @@ const generateComponentContent = async (
|
|
|
358
460
|
// We check if we are passing any props and pick the value from the atrrs, if not we pick the value from the propDefinitions of
|
|
359
461
|
// the component instance that we are using here.
|
|
360
462
|
for (const propKey of Object.keys(combinedProps)) {
|
|
361
|
-
const
|
|
362
|
-
|
|
463
|
+
const attribute = attrs[propKey]
|
|
464
|
+
|
|
465
|
+
if (attribute?.type === 'element') {
|
|
363
466
|
propsForInstance[propKey] = {
|
|
364
467
|
...combinedProps[propKey],
|
|
365
468
|
defaultValue: attrs[propKey],
|
|
@@ -373,13 +476,15 @@ const generateComponentContent = async (
|
|
|
373
476
|
subComponentOptions,
|
|
374
477
|
structure
|
|
375
478
|
)
|
|
376
|
-
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (attribute?.type === 'dynamic') {
|
|
377
482
|
// When we are using a component instance in a component and the attribute
|
|
378
483
|
// that is passed to the component is of dynamic reference.
|
|
379
484
|
// If means, the component is redirecting the prop that is received to the prop of the component that it is consuming.
|
|
380
485
|
// In this case, we need to pass the value of the prop that is received to the prop of the component that it is consuming.
|
|
381
486
|
// And similary we do the same for the states.
|
|
382
|
-
switch (
|
|
487
|
+
switch (attribute.content.referenceType) {
|
|
383
488
|
case 'prop':
|
|
384
489
|
propsForInstance[propKey] = combinedProps[propKey]
|
|
385
490
|
break
|
|
@@ -388,15 +493,30 @@ const generateComponentContent = async (
|
|
|
388
493
|
break
|
|
389
494
|
default:
|
|
390
495
|
throw new Error(
|
|
391
|
-
`ReferenceType ${
|
|
496
|
+
`ReferenceType ${attribute.content.referenceType} is not supported in HTML Export.`
|
|
392
497
|
)
|
|
393
498
|
}
|
|
394
|
-
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (attribute?.type === 'object') {
|
|
395
502
|
propsForInstance[propKey] = {
|
|
396
503
|
...combinedProps[propKey],
|
|
397
|
-
defaultValue:
|
|
504
|
+
defaultValue: (attribute?.content as object) || combinedProps[propKey]?.defaultValue,
|
|
398
505
|
}
|
|
399
|
-
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (
|
|
509
|
+
attribute?.type !== 'dynamic' &&
|
|
510
|
+
attribute?.type !== 'element' &&
|
|
511
|
+
attribute?.type !== 'object'
|
|
512
|
+
) {
|
|
513
|
+
propsForInstance[propKey] = {
|
|
514
|
+
...combinedProps[propKey],
|
|
515
|
+
defaultValue: attribute?.content || combinedProps[propKey]?.defaultValue,
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (attribute === undefined) {
|
|
400
520
|
const propFromCurrentComponent = combinedProps[propKey]
|
|
401
521
|
if (propFromCurrentComponent.type === 'element' && propFromCurrentComponent.defaultValue) {
|
|
402
522
|
await generateHtmlSyntax(
|
|
@@ -501,11 +621,35 @@ const generateDynamicNode: NodeToHTML<UIDLDynamicReference, Promise<HastNode | H
|
|
|
501
621
|
propDefinitions,
|
|
502
622
|
stateDefinitions
|
|
503
623
|
): Promise<HastNode | HastText> => {
|
|
624
|
+
if (node.content.referenceType === 'locale') {
|
|
625
|
+
const localeTag = HASTBuilders.createHTMLNode('span')
|
|
626
|
+
const commentNode = HASTBuilders.createComment(`Content for locale ${node.content.id}`)
|
|
627
|
+
HASTUtils.addChildNode(localeTag, commentNode)
|
|
628
|
+
return localeTag
|
|
629
|
+
}
|
|
630
|
+
|
|
504
631
|
const usedReferenceValue = getValueFromReference(
|
|
505
632
|
node.content.id,
|
|
506
633
|
node.content.referenceType === 'prop' ? propDefinitions : stateDefinitions
|
|
507
634
|
)
|
|
508
635
|
|
|
636
|
+
if (usedReferenceValue.type === 'object' && usedReferenceValue.defaultValue) {
|
|
637
|
+
// Let's say users are biding the prop to a node using something like this "fields.Title"
|
|
638
|
+
// But the fields in the object is the value where the object is defined either in propDefinitions
|
|
639
|
+
// or on the attrs. So, we just need to parsed the rest of the object path and get the value from the object.
|
|
640
|
+
const pathKeys: string[] = node.content.id.split(/\.|\[(['"]?)(.+?)\1\]/).filter(Boolean)
|
|
641
|
+
pathKeys.shift()
|
|
642
|
+
|
|
643
|
+
const value = GenericUtils.getValueFromPath(
|
|
644
|
+
pathKeys.join('.'),
|
|
645
|
+
usedReferenceValue.defaultValue as Record<string, UIDLPropDefinition>
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
if (value) {
|
|
649
|
+
return HASTBuilders.createTextNode(String(value))
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
|
|
509
653
|
if (usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue) {
|
|
510
654
|
const elementNode = usedReferenceValue.defaultValue as UIDLElementNode
|
|
511
655
|
|
|
@@ -651,6 +795,7 @@ const handleAttributes = (
|
|
|
651
795
|
case 'element':
|
|
652
796
|
case 'import':
|
|
653
797
|
case 'expr':
|
|
798
|
+
case 'object':
|
|
654
799
|
break
|
|
655
800
|
|
|
656
801
|
default: {
|