@nordcraft/ssr 1.0.92 → 1.0.94

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.
@@ -31,6 +31,9 @@ import type { ApiCache, ApiEvaluator } from './api'
31
31
  import { getNodeAttrs, toEncodedText } from './attributes'
32
32
 
33
33
  type CustomPropertyRule = `--${string}: ${string}`
34
+ type SlottedContent =
35
+ | string
36
+ | ((contexts: Record<string, Record<string, any>>) => Promise<string>)
34
37
 
35
38
  const renderComponent = async ({
36
39
  path,
@@ -53,7 +56,7 @@ const renderComponent = async ({
53
56
  }: {
54
57
  path: string
55
58
  apiCache: ApiCache
56
- children?: Record<string, string>
59
+ children?: Record<string, SlottedContent>
57
60
  component: Component
58
61
  data: ComponentData
59
62
  env: ToddleServerEnv
@@ -149,7 +152,9 @@ const renderComponent = async ({
149
152
  case 'slot': {
150
153
  const defaultChild = children?.[node.name ?? 'default']
151
154
  if (defaultChild) {
152
- return defaultChild
155
+ return typeof defaultChild === 'function'
156
+ ? await defaultChild(data.Contexts ?? {})
157
+ : defaultChild
153
158
  } else {
154
159
  const slotChildren = await Promise.all(
155
160
  node.children.map((child) =>
@@ -379,95 +384,111 @@ const renderComponent = async ({
379
384
  })
380
385
 
381
386
  const childNodes = await Promise.all(
382
- node.children.map((child, i) => {
387
+ node.children.map(async (child, i) => {
383
388
  const slotName =
384
389
  typeof child === 'string'
385
390
  ? (component.nodes?.[child]?.slot ?? 'default')
386
391
  : 'default'
387
392
 
388
- return renderNode({
389
- id: child,
390
- path: `${path}.${i}[${slotName}]`,
391
- namespace,
392
- node: component.nodes?.[child],
393
- data: {
394
- ...data,
395
- Contexts: {
396
- ...contexts,
397
- [childComponent.name]: Object.fromEntries(
398
- Object.entries(childComponent.formulas ?? {})
399
- .filter(([, formula]) => formula.exposeInContext)
400
- .map(([key, formula]) => [
401
- key,
402
- applyFormula(formula.formula, {
403
- component: childComponent,
404
- package: _packageName,
405
- data: {
406
- Contexts: {
407
- ...data.Contexts,
408
- ...Object.fromEntries(
409
- Object.entries(childComponent.formulas ?? {})
410
- .filter(
411
- ([, formula]) => formula.exposeInContext,
412
- )
413
- .map(([key, formula]) => [
414
- key,
415
- applyFormula(formula.formula, {
416
- data: {
417
- Attributes: attrs,
418
- Apis: { ...data.Apis, ...apis },
419
- Location: data.Location,
420
- Page: data.Page,
421
- },
422
- component,
423
- package: _packageName,
424
- env,
425
- toddle,
426
- }),
427
- ]),
393
+ return (contexts: Record<string, Record<string, unknown>>) => {
394
+ return renderNode({
395
+ id: child,
396
+ path: `${path}.${i}[${slotName}]`,
397
+ namespace,
398
+ node: component.nodes?.[child],
399
+ data: {
400
+ ...data,
401
+ Contexts: {
402
+ ...data.Contexts,
403
+ ...contexts,
404
+ [childComponent.name]: Object.fromEntries(
405
+ Object.entries(childComponent.formulas ?? {})
406
+ .filter(([, formula]) => formula.exposeInContext)
407
+ .map(([key, formula]) => [
408
+ key,
409
+ applyFormula(formula.formula, {
410
+ component: childComponent,
411
+ package: _packageName,
412
+ data: {
413
+ Contexts: {
414
+ ...data.Contexts,
415
+ ...Object.fromEntries(
416
+ Object.entries(childComponent.formulas ?? {})
417
+ .filter(
418
+ ([, formula]) => formula.exposeInContext,
419
+ )
420
+ .map(([key, formula]) => [
421
+ key,
422
+ applyFormula(formula.formula, {
423
+ data: {
424
+ Attributes: attrs,
425
+ Apis: { ...data.Apis, ...apis },
426
+ Location: data.Location,
427
+ Page: data.Page,
428
+ },
429
+ component,
430
+ package: _packageName,
431
+ env,
432
+ toddle,
433
+ }),
434
+ ]),
435
+ ),
436
+ },
437
+ Apis: apis,
438
+ Attributes: attrs,
439
+ Variables: mapValues(
440
+ childComponent.variables ?? {},
441
+ ({ initialValue }) => {
442
+ return applyFormula(initialValue, {
443
+ data: {
444
+ Attributes: attrs,
445
+ Location: data.Location,
446
+ Page: data.Page,
447
+ },
448
+ component,
449
+ package: _packageName,
450
+ env,
451
+ toddle,
452
+ })
453
+ },
428
454
  ),
429
455
  },
430
- Apis: apis,
431
- Attributes: attrs,
432
- Variables: mapValues(
433
- childComponent.variables ?? {},
434
- ({ initialValue }) => {
435
- return applyFormula(initialValue, {
436
- data: {
437
- Attributes: attrs,
438
- Location: data.Location,
439
- Page: data.Page,
440
- },
441
- component,
442
- package: _packageName,
443
- env,
444
- toddle,
445
- })
446
- },
447
- ),
448
- },
449
- env,
450
- toddle,
451
- }),
452
- ]),
453
- ),
456
+ env,
457
+ toddle,
458
+ }),
459
+ ]),
460
+ ),
461
+ },
454
462
  },
455
- },
456
- // pass package name to child component if it's defined
457
- packageName,
458
- })
463
+ // pass package name to child component if it's defined
464
+ packageName,
465
+ })
466
+ }
459
467
  }),
460
468
  )
461
469
 
462
- const children: Record<string, string> = {}
463
- childNodes.forEach((childNode, i) => {
470
+ const children: Record<string, SlottedContent> = {}
471
+ childNodes.forEach((renderFn, i) => {
464
472
  const childNodeId = node.children[i]
465
473
  // Add children to the correct slot in the right order
466
474
  const slotName =
467
475
  typeof childNodeId === 'string'
468
476
  ? (component.nodes?.[childNodeId]?.slot ?? 'default')
469
477
  : 'default'
470
- children[slotName] = `${children[slotName] ?? ''}${childNode}`
478
+
479
+ const existing = children[slotName]
480
+ if (existing) {
481
+ const previous =
482
+ typeof existing === 'function'
483
+ ? existing
484
+ : async () => existing as string
485
+ // Handle multiple elements in the same slot by appending
486
+ children[slotName] = async (contexts) => {
487
+ return (await previous(contexts)) + (await renderFn(contexts))
488
+ }
489
+ } else {
490
+ children[slotName] = renderFn
491
+ }
471
492
  })
472
493
 
473
494
  // Add extra instance styling for each style-variable
@@ -589,9 +610,9 @@ const createComponent = async ({
589
610
  })
590
611
  >
591
612
  attrs: Record<string, any>
592
- children?: Record<string, string>
613
+ children?: Record<string, SlottedContent>
593
614
  component: Component
594
- contexts?: Record<string, Record<string, any>>
615
+ contexts?: Record<string, Record<string, unknown>>
595
616
  env: ToddleServerEnv
596
617
  evaluateComponentApis: ApiEvaluator
597
618
  files: ProjectFiles
@@ -631,17 +652,20 @@ const createComponent = async ({
631
652
  // Own context formulas has access to all other data in the component (attributes, variables, apis etc.) so is applied last
632
653
  data.Contexts = {
633
654
  ...data.Contexts,
634
- ...Object.fromEntries(
635
- Object.entries(component.formulas ?? {})
636
- .filter(([, formula]) => formula.exposeInContext)
637
- .map(([key, formula]) => [
638
- key,
639
- applyFormula(formula.formula, {
640
- ...formulaContext,
641
- data,
642
- }),
643
- ]),
644
- ),
655
+ [component.name]: {
656
+ ...data.Contexts?.[component.name],
657
+ ...Object.fromEntries(
658
+ Object.entries(component.formulas ?? {})
659
+ .filter(([, formula]) => formula.exposeInContext)
660
+ .map(([key, formula]) => [
661
+ key,
662
+ applyFormula(formula.formula, {
663
+ ...formulaContext,
664
+ data,
665
+ }),
666
+ ]),
667
+ ),
668
+ },
645
669
  }
646
670
 
647
671
  return renderComponent({