@teleporthq/teleport-plugin-html-base-component 0.32.10 → 0.33.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.
@@ -76,7 +76,7 @@ export const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastTex
76
76
  return HASTBuilders.createHTMLNode(node.type)
77
77
 
78
78
  case 'element':
79
- return generatElementNode(
79
+ const elementNode = await generateElementNode(
80
80
  node,
81
81
  templatesLookUp,
82
82
  propDefinitions,
@@ -84,9 +84,10 @@ export const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastTex
84
84
  subComponentOptions,
85
85
  structure
86
86
  )
87
+ return elementNode
87
88
 
88
89
  case 'dynamic':
89
- return generateDynamicNode(
90
+ const dynamicNode = await generateDynamicNode(
90
91
  node,
91
92
  templatesLookUp,
92
93
  propDefinitions,
@@ -95,6 +96,8 @@ export const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastTex
95
96
  structure
96
97
  )
97
98
 
99
+ return dynamicNode
100
+
98
101
  default:
99
102
  throw new HTMLComponentGeneratorError(
100
103
  `generateHtmlSyntax encountered a node of unsupported type: ${JSON.stringify(
@@ -106,7 +109,7 @@ export const generateHtmlSynatx: NodeToHTML<UIDLNode, Promise<HastNode | HastTex
106
109
  }
107
110
  }
108
111
 
109
- const generatElementNode: NodeToHTML<UIDLElementNode, Promise<HastNode | HastText>> = async (
112
+ const generateElementNode: NodeToHTML<UIDLElementNode, Promise<HastNode | HastText>> = async (
110
113
  node,
111
114
  templatesLookUp,
112
115
  propDefinitions,
@@ -137,6 +140,7 @@ const generatElementNode: NodeToHTML<UIDLElementNode, Promise<HastNode | HastTex
137
140
  node,
138
141
  propDefinitions,
139
142
  stateDefinitions,
143
+ templatesLookUp,
140
144
  subComponentOptions,
141
145
  structure
142
146
  )
@@ -180,17 +184,15 @@ const generatElementNode: NodeToHTML<UIDLElementNode, Promise<HastNode | HastTex
180
184
  handleStyles(node, style, propDefinitions, stateDefinitions)
181
185
  }
182
186
 
183
- if (Object.keys(attrs).length > 0) {
184
- handleAttributes(
185
- elementType,
186
- elementNode,
187
- attrs,
188
- propDefinitions,
189
- stateDefinitions,
190
- structure.options.projectRouteDefinition,
191
- structure.outputOptions
192
- )
193
- }
187
+ handleAttributes(
188
+ elementType,
189
+ elementNode,
190
+ attrs,
191
+ propDefinitions,
192
+ stateDefinitions,
193
+ structure.options.projectRouteDefinition,
194
+ structure.outputOptions
195
+ )
194
196
 
195
197
  return elementNode
196
198
  }
@@ -199,6 +201,7 @@ const generateComponentContent = async (
199
201
  node: UIDLElementNode,
200
202
  propDefinitions: Record<string, UIDLPropDefinition>,
201
203
  stateDefinitions: Record<string, UIDLStateDefinition>,
204
+ templateLookup: Record<string, unknown>,
202
205
  subComponentOptions: {
203
206
  externals: Record<string, ComponentUIDL>
204
207
  plugins: ComponentPlugin[]
@@ -216,7 +219,6 @@ const generateComponentContent = async (
216
219
  // "Component" will not exist when generating a component because the resolver checks for illegal class names
217
220
  const compName = elementType === 'Component' ? 'AppComponent' : elementType
218
221
  const comp = UIDLUtils.cloneObject(externals[compName] || {}) as ComponentUIDL
219
- const lookUpTemplates: Record<string, unknown> = {}
220
222
  let compHasSlots: boolean = false
221
223
 
222
224
  if (!comp || !comp?.node) {
@@ -256,22 +258,26 @@ const generateComponentContent = async (
256
258
  }
257
259
 
258
260
  const combinedProps = { ...propDefinitions, ...(comp?.propDefinitions || {}) }
259
-
260
- const propsForInstance = Object.keys(combinedProps).reduce(
261
- (acc: Record<string, UIDLPropDefinition>, propKey) => {
262
- if (attrs[propKey]) {
263
- acc[propKey] = {
264
- ...combinedProps[propKey],
265
- defaultValue: attrs[propKey]?.content || combinedProps[propKey]?.defaultValue,
266
- }
267
- } else {
268
- acc[propKey] = combinedProps[propKey]
261
+ const propsForInstance: Record<string, UIDLPropDefinition> = {}
262
+ for (const propKey of Object.keys(combinedProps)) {
263
+ // If the attribute is a named-slot, then we can directly pass the value instead of just the content
264
+ if (attrs[propKey]?.type === 'element') {
265
+ propsForInstance[propKey] = {
266
+ ...combinedProps[propKey],
267
+ defaultValue: attrs[propKey],
269
268
  }
269
+ continue
270
+ }
270
271
 
271
- return acc
272
- },
273
- {}
274
- )
272
+ if (attrs[propKey]) {
273
+ propsForInstance[propKey] = {
274
+ ...combinedProps[propKey],
275
+ defaultValue: attrs[propKey]?.content || combinedProps[propKey]?.defaultValue,
276
+ }
277
+ } else {
278
+ propsForInstance[propKey] = combinedProps[propKey]
279
+ }
280
+ }
275
281
 
276
282
  const combinedStates = { ...stateDefinitions, ...(comp?.stateDefinitions || {}) }
277
283
  const statesForInstance = Object.keys(combinedStates).reduce(
@@ -291,7 +297,7 @@ const generateComponentContent = async (
291
297
  )
292
298
 
293
299
  const elementNode = HASTBuilders.createHTMLNode(StringUtils.camelCaseToDashCase(elementType))
294
- lookUpTemplates[key] = elementNode
300
+ templateLookup[key] = elementNode
295
301
 
296
302
  const compTag = (await generateHtmlSynatx(
297
303
  {
@@ -307,7 +313,7 @@ const generateComponentContent = async (
307
313
  },
308
314
  },
309
315
  },
310
- lookUpTemplates,
316
+ templateLookup,
311
317
  propsForInstance,
312
318
  statesForInstance,
313
319
  subComponentOptions,
@@ -337,7 +343,7 @@ const generateComponentContent = async (
337
343
  linkAfter: [],
338
344
  content: compTag,
339
345
  meta: {
340
- nodesLookup: lookUpTemplates,
346
+ nodesLookup: templateLookup,
341
347
  },
342
348
  },
343
349
  ],
@@ -375,19 +381,41 @@ const generateComponentContent = async (
375
381
  return compTag
376
382
  }
377
383
 
378
- const generateDynamicNode: NodeToHTML<UIDLDynamicReference, HastNode> = (
384
+ const generateDynamicNode: NodeToHTML<UIDLDynamicReference, Promise<HastNode>> = async (
379
385
  node,
380
- _,
386
+ templateLookup,
381
387
  propDefinitions,
382
- stateDefinitions
383
- ) => {
384
- const spanTag = HASTBuilders.createHTMLNode('span')
385
- const usedReferenceValue =
386
- node.content.referenceType === 'prop'
387
- ? getValueFromReference(node.content.id, propDefinitions)
388
- : getValueFromReference(node.content.id, stateDefinitions)
388
+ stateDefinitions,
389
+ subComponentOptions,
390
+ structure
391
+ ): Promise<HastNode> => {
392
+ const usedReferenceValue = getValueFromReference(
393
+ node.content.id,
394
+ node.content.referenceType === 'prop' ? propDefinitions : stateDefinitions
395
+ )
396
+
397
+ if (usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue) {
398
+ const slotNode = await generateElementNode(
399
+ usedReferenceValue.defaultValue as UIDLElementNode,
400
+ templateLookup,
401
+ propDefinitions,
402
+ stateDefinitions,
403
+ subComponentOptions,
404
+ structure
405
+ )
406
+
407
+ return slotNode as HastNode
408
+ }
389
409
 
390
- HASTUtils.addTextNode(spanTag, String(usedReferenceValue))
410
+ if (usedReferenceValue.type === 'element' && usedReferenceValue.defaultValue === undefined) {
411
+ const spanTagWrapper = HASTBuilders.createHTMLNode('span')
412
+ const commentNode = HASTBuilders.createComment(`Content for slot ${node.content.id}`)
413
+ HASTUtils.addChildNode(spanTagWrapper, commentNode)
414
+ return spanTagWrapper
415
+ }
416
+
417
+ const spanTag = HASTBuilders.createHTMLNode('span')
418
+ HASTUtils.addTextNode(spanTag, String(usedReferenceValue.defaultValue))
391
419
  return spanTag
392
420
  }
393
421
 
@@ -400,10 +428,12 @@ const handleStyles = (
400
428
  Object.keys(styles).forEach((styleKey) => {
401
429
  let style: string | UIDLStyleValue = styles[styleKey]
402
430
  if (style.type === 'dynamic' && style.content?.referenceType !== 'token') {
403
- if (style.content.referenceType === 'prop') {
404
- style = getValueFromReference(style.content.id, propDefinitions)
405
- } else if (style.content.referenceType === 'state') {
406
- style = getValueFromReference(style.content.id, stateDefinitions)
431
+ const referencedValue = getValueFromReference(
432
+ style.content.id,
433
+ style.content.referenceType === 'prop' ? propDefinitions : stateDefinitions
434
+ )
435
+ if (referencedValue.type === 'string' || referencedValue.type === 'number') {
436
+ style = String(referencedValue.defaultValue)
407
437
  }
408
438
  node.content.style[styleKey] = typeof style === 'string' ? staticNode(style) : style
409
439
  }
@@ -419,99 +449,110 @@ const handleAttributes = (
419
449
  routeDefinitions: UIDLRouteDefinitions,
420
450
  outputOptions: UIDLComponentOutputOptions
421
451
  ) => {
422
- Object.keys(attrs).forEach((attrKey) => {
452
+ for (const attrKey of Object.keys(attrs)) {
423
453
  const attrValue = attrs[attrKey]
454
+ const { type, content } = attrValue
424
455
 
425
- if (
426
- attrKey === 'href' &&
427
- attrValue.type === 'static' &&
428
- typeof attrValue.content === 'string' &&
429
- attrValue.content.startsWith('/')
430
- ) {
431
- let targetLink
456
+ switch (type) {
457
+ case 'static': {
458
+ if (attrKey === 'href' && typeof content === 'string' && content.startsWith('/')) {
459
+ let targetLink
432
460
 
433
- const targetRoute = (routeDefinitions?.values || []).find(
434
- (route) => route.pageOptions.navLink === attrValue.content
435
- )
461
+ const targetRoute = (routeDefinitions?.values || []).find(
462
+ (route) => route.pageOptions.navLink === content
463
+ )
436
464
 
437
- if (targetRoute) {
438
- targetLink = targetRoute.pageOptions.navLink
439
- }
465
+ if (targetRoute) {
466
+ targetLink = targetRoute.pageOptions.navLink
467
+ }
440
468
 
441
- if (!targetRoute && attrValue.content === '/home') {
442
- targetLink = '/'
443
- }
469
+ if (!targetRoute && content === '/home') {
470
+ targetLink = '/'
471
+ }
444
472
 
445
- if (!targetLink && !targetRoute) {
446
- targetLink = attrValue.content
447
- }
473
+ if (!targetLink && !targetRoute) {
474
+ targetLink = content
475
+ }
448
476
 
449
- const currentPageRoute = join(...(outputOptions?.folderPath || []), './')
450
- const localPrefix = relative(
451
- `/${currentPageRoute}`,
452
- `/${targetLink === '/' ? 'index' : targetLink}`
453
- )
477
+ const currentPageRoute = join(...(outputOptions?.folderPath || []), './')
478
+ const localPrefix = relative(
479
+ `/${currentPageRoute}`,
480
+ `/${targetLink === '/' ? 'index' : targetLink}`
481
+ )
454
482
 
455
- HASTUtils.addAttributeToNode(htmlNode, attrKey, `${localPrefix}.html`)
456
- return
457
- }
483
+ HASTUtils.addAttributeToNode(htmlNode, attrKey, `${localPrefix}.html`)
484
+ break
485
+ }
458
486
 
459
- if (attrValue.type === 'dynamic') {
460
- const value =
461
- attrValue.content.referenceType === 'prop'
462
- ? getValueFromReference(attrValue.content.id, propDefinitions)
463
- : getValueFromReference(attrValue.content.id, stateDefinitions)
464
- HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value))
465
- return
466
- }
487
+ if (typeof content === 'boolean') {
488
+ htmlNode.properties[attrKey] = content === true ? 'true' : 'false'
489
+ } else if (typeof content === 'string' || typeof attrValue.content === 'number') {
490
+ let value = StringUtils.encode(String(attrValue.content))
491
+
492
+ /*
493
+ elementType of image is always mapped to img.
494
+ For reference, check `html-mapping` file.
495
+ */
496
+ if (elementType === 'img' && attrKey === 'src' && !isValidURL(value)) {
497
+ /*
498
+ By default we just prefix all the asset paths with just the
499
+ assetPrefix that is configured in the project. But for `html` generators
500
+ we need to prefix that with the current file location.
501
+
502
+ Because, all the other frameworks have a build setup. which serves all the
503
+ assets from the `public` folder. But in the case of `html` here is how it works
504
+
505
+ We load a file from `index.html` the request for the image goes from
506
+ '...url.../public/...image...'
507
+ If it's a nested url, then the request goes from
508
+ '...url/nested/public/...image..'
509
+
510
+ But the nested folder is available only on the root. With this
511
+ The url changes prefixes to
512
+
513
+ ../public/playground_assets/..image.. etc depending on the dept the file is in.
514
+ */
515
+ value = join(relative(join(...outputOptions.folderPath), './'), value)
516
+ }
517
+
518
+ HASTUtils.addAttributeToNode(htmlNode, attrKey, value)
519
+ }
467
520
 
468
- if (attrValue.type === 'raw') {
469
- HASTUtils.addAttributeToNode(htmlNode, attrKey, attrValue.content)
470
- return
471
- }
521
+ break
522
+ }
472
523
 
473
- if (typeof attrValue.content === 'boolean') {
474
- HASTUtils.addBooleanAttributeToNode(htmlNode, attrKey)
475
- return
476
- } else if (typeof attrValue.content === 'string' || typeof attrValue.content === 'number') {
477
- let value = StringUtils.encode(String(attrValue.content))
478
-
479
- /*
480
- elementType of image is always mapped to img.
481
- For reference, check `html-mapping` file.
482
- */
483
- if (elementType === 'img' && attrKey === 'src' && !isValidURL(value)) {
484
- /*
485
- By default we just prefix all the asset paths with just the
486
- assetPrefix that is configured in the project. But for `html` generators
487
- we need to prefix that with the current file location.
488
-
489
- Because, all the other frameworks have a build setup. which serves all the
490
- assets from the `public` folder. But in the case of `html` here is how it works
491
-
492
- We load a file from `index.html` the request for the image goes from
493
- '...url.../public/...image...'
494
- If it's a nested url, then the request goes from
495
- '...url/nested/public/...image..'
496
-
497
- But the nested folder is available only on the root. With this
498
- The url changes prefixes to
499
-
500
- ../public/playground_assets/..image.. etc depending on the dept the file is in.
501
- */
502
- value = join(relative(join(...outputOptions.folderPath), './'), value)
524
+ case 'dynamic': {
525
+ const value = getValueFromReference(
526
+ content.id,
527
+ content.referenceType === 'prop' ? propDefinitions : stateDefinitions
528
+ )
529
+
530
+ HASTUtils.addAttributeToNode(htmlNode, attrKey, String(value.defaultValue))
531
+ break
532
+ }
533
+
534
+ case 'raw': {
535
+ HASTUtils.addAttributeToNode(htmlNode, attrKey, content)
536
+ break
503
537
  }
504
538
 
505
- HASTUtils.addAttributeToNode(htmlNode, attrKey, value)
506
- return
539
+ case 'element':
540
+ case 'import':
541
+ break
542
+
543
+ default: {
544
+ throw new HTMLComponentGeneratorError(
545
+ `Received ${JSON.stringify(attrValue, null, 2)} \n in handleAttributes for html`
546
+ )
547
+ }
507
548
  }
508
- })
549
+ }
509
550
  }
510
551
 
511
552
  const getValueFromReference = (
512
553
  key: string,
513
554
  definitions: Record<string, UIDLPropDefinition>
514
- ): string => {
555
+ ): UIDLPropDefinition | undefined => {
515
556
  const usedReferenceValue = definitions[key.includes('.') ? key.split('.')[0] : key]
516
557
 
517
558
  if (!usedReferenceValue) {
@@ -520,9 +561,9 @@ const getValueFromReference = (
520
561
  )
521
562
  }
522
563
 
523
- if (!usedReferenceValue.hasOwnProperty('defaultValue')) {
564
+ if (['string', 'number', 'object', 'element'].includes(usedReferenceValue?.type) === false) {
524
565
  throw new HTMLComponentGeneratorError(
525
- `Default value is missing from dynamic reference - ${JSON.stringify(
566
+ `Attribute is using dynamic value, but received of type ${JSON.stringify(
526
567
  usedReferenceValue,
527
568
  null,
528
569
  2
@@ -530,9 +571,12 @@ const getValueFromReference = (
530
571
  )
531
572
  }
532
573
 
533
- if (!['string', 'number', 'object'].includes(usedReferenceValue?.type)) {
574
+ if (
575
+ usedReferenceValue.type !== 'element' &&
576
+ usedReferenceValue.hasOwnProperty('defaultValue') === false
577
+ ) {
534
578
  throw new HTMLComponentGeneratorError(
535
- `Attribute is using dynamic value, but received of type ${JSON.stringify(
579
+ `Default value is missing from dynamic reference - ${JSON.stringify(
536
580
  usedReferenceValue,
537
581
  null,
538
582
  2
@@ -540,5 +584,5 @@ const getValueFromReference = (
540
584
  )
541
585
  }
542
586
 
543
- return String(usedReferenceValue.defaultValue)
587
+ return usedReferenceValue
544
588
  }