@nordcraft/runtime 1.0.87 → 1.0.89

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.
Files changed (46) hide show
  1. package/dist/custom-element.main.esm.js +30 -30
  2. package/dist/custom-element.main.esm.js.map +4 -4
  3. package/dist/page.main.esm.js +3 -3
  4. package/dist/page.main.esm.js.map +4 -4
  5. package/dist/src/components/createComponent.js +60 -69
  6. package/dist/src/components/createComponent.js.map +1 -1
  7. package/dist/src/components/createElement.js +33 -50
  8. package/dist/src/components/createElement.js.map +1 -1
  9. package/dist/src/components/createNode.js +8 -1
  10. package/dist/src/components/createNode.js.map +1 -1
  11. package/dist/src/components/createNode.test.d.ts +1 -0
  12. package/dist/src/components/createNode.test.js +608 -0
  13. package/dist/src/components/createNode.test.js.map +1 -0
  14. package/dist/src/components/renderComponent.js +2 -4
  15. package/dist/src/components/renderComponent.js.map +1 -1
  16. package/dist/src/editor-preview.main.js +4 -4
  17. package/dist/src/editor-preview.main.js.map +1 -1
  18. package/dist/src/page.main.js +31 -41
  19. package/dist/src/page.main.js.map +1 -1
  20. package/dist/src/styles/CustomPropertyStyleSheet.d.ts +0 -1
  21. package/dist/src/styles/CustomPropertyStyleSheet.js +1 -1
  22. package/dist/src/styles/CustomPropertyStyleSheet.js.map +1 -1
  23. package/dist/src/styles/CustomPropertyStyleSheet.test.js +2 -5
  24. package/dist/src/styles/CustomPropertyStyleSheet.test.js.map +1 -1
  25. package/dist/src/utils/BatchQueue.d.ts +1 -0
  26. package/dist/src/utils/BatchQueue.js +2 -1
  27. package/dist/src/utils/BatchQueue.js.map +1 -1
  28. package/dist/src/utils/formulaHasValue.d.ts +2 -0
  29. package/dist/src/utils/formulaHasValue.js +3 -0
  30. package/dist/src/utils/formulaHasValue.js.map +1 -0
  31. package/dist/src/utils/subscribeCustomProperty.d.ts +3 -3
  32. package/dist/src/utils/subscribeCustomProperty.js +2 -3
  33. package/dist/src/utils/subscribeCustomProperty.js.map +1 -1
  34. package/package.json +3 -3
  35. package/src/components/createComponent.ts +78 -86
  36. package/src/components/createElement.ts +25 -46
  37. package/src/components/createNode.test.ts +686 -0
  38. package/src/components/createNode.ts +8 -1
  39. package/src/components/renderComponent.ts +2 -4
  40. package/src/editor-preview.main.ts +4 -4
  41. package/src/page.main.ts +49 -51
  42. package/src/styles/CustomPropertyStyleSheet.test.ts +2 -7
  43. package/src/styles/CustomPropertyStyleSheet.ts +1 -2
  44. package/src/utils/BatchQueue.ts +2 -2
  45. package/src/utils/formulaHasValue.ts +7 -0
  46. package/src/utils/subscribeCustomProperty.ts +1 -5
@@ -111,8 +111,7 @@ export function renderComponent({
111
111
  .subscribe((props) => {
112
112
  if (prev) {
113
113
  component.onAttributeChange?.actions?.forEach((action) => {
114
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
115
- handleAction(
114
+ void handleAction(
116
115
  action,
117
116
  dataSignal.get(),
118
117
  ctx,
@@ -143,8 +142,7 @@ export function renderComponent({
143
142
  })
144
143
  }
145
144
  component.onLoad?.actions?.forEach((action) => {
146
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
147
- handleAction(action, dataSignal.get(), ctx)
145
+ void handleAction(action, dataSignal.get(), ctx)
148
146
  })
149
147
  })
150
148
  return rootElem
@@ -1710,7 +1710,7 @@ const insertHeadTags = (
1710
1710
  document.createRange().createContextualFragment(`
1711
1711
  <link
1712
1712
  data-meta-id="${id}"
1713
- ${Object.entries(entry.attrs)
1713
+ ${Object.entries(entry.attrs ?? {})
1714
1714
  .map(([key, value]) => `${key}="${applyFormula(value, context)}"`)
1715
1715
  .join(' ')}
1716
1716
  />
@@ -1722,10 +1722,10 @@ const insertHeadTags = (
1722
1722
  document.createRange().createContextualFragment(`
1723
1723
  <script
1724
1724
  data-meta-id="${id}"
1725
- ${Object.entries(entry.attrs)
1725
+ ${Object.entries(entry.attrs ?? {})
1726
1726
  .map(([key, value]) => `${key}="${applyFormula(value, context)}"`)
1727
1727
  .join(' ')}
1728
- ></script>
1728
+ >${applyFormula(entry.content ?? '', context)}</script>
1729
1729
  `),
1730
1730
  )
1731
1731
  case HeadTagTypes.Style:
@@ -1734,7 +1734,7 @@ const insertHeadTags = (
1734
1734
  document.createRange().createContextualFragment(`
1735
1735
  <style
1736
1736
  data-meta-id="${id}"
1737
- ${Object.entries(entry.attrs)
1737
+ ${Object.entries(entry.attrs ?? {})
1738
1738
  .map(([key, value]) => `${key}="${applyFormula(value, context)}"`)
1739
1739
  .join(' ')}
1740
1740
  >
package/src/page.main.ts CHANGED
@@ -16,6 +16,7 @@ import type {
16
16
  Toddle,
17
17
  } from '@nordcraft/core/dist/types'
18
18
  import { mapObject } from '@nordcraft/core/dist/utils/collections'
19
+ import { VOID_HTML_ELEMENTS } from '@nordcraft/core/dist/utils/html'
19
20
  import { isDefined } from '@nordcraft/core/dist/utils/util'
20
21
  import * as libActions from '@nordcraft/std-lib/dist/actions'
21
22
  import * as libFormulas from '@nordcraft/std-lib/dist/formulas'
@@ -359,22 +360,21 @@ const setupMetaUpdates = (
359
360
  component: Component,
360
361
  dataSignal: Signal<ComponentData>,
361
362
  ) => {
363
+ const getFormulaContext = (data: ComponentData) => ({
364
+ data,
365
+ component,
366
+ root: document,
367
+ package: undefined,
368
+ toddle: window.toddle,
369
+ env,
370
+ })
362
371
  // Handle dynamic updates of the document language
363
372
  const langFormula = component.route?.info?.language?.formula
364
373
  const dynamicLang = langFormula && langFormula.type !== 'value'
365
374
  if (dynamicLang) {
366
375
  dataSignal
367
- .map<string | null>(() =>
368
- component
369
- ? applyFormula(langFormula, {
370
- data: dataSignal.get(),
371
- component,
372
- root: document,
373
- package: undefined,
374
- toddle: window.toddle,
375
- env,
376
- })
377
- : null,
376
+ .map((data) =>
377
+ component ? applyFormula(langFormula, getFormulaContext(data)) : null,
378
378
  )
379
379
  .subscribe((newLang) => {
380
380
  if (isDefined(newLang) && document.documentElement.lang !== newLang) {
@@ -388,17 +388,8 @@ const setupMetaUpdates = (
388
388
  const dynamicTitle = titleFormula && titleFormula.type !== 'value'
389
389
  if (dynamicTitle) {
390
390
  dataSignal
391
- .map<string | null>(() =>
392
- component
393
- ? applyFormula(titleFormula, {
394
- data: dataSignal.get(),
395
- component,
396
- root: document,
397
- package: undefined,
398
- toddle: window.toddle,
399
- env,
400
- })
401
- : null,
391
+ .map((data) =>
392
+ component ? applyFormula(titleFormula, getFormulaContext(data)) : null,
402
393
  )
403
394
  .subscribe((newTitle) => {
404
395
  if (isDefined(newTitle) && document.title !== newTitle) {
@@ -411,10 +402,12 @@ const setupMetaUpdates = (
411
402
  const meta = component.route?.info?.meta
412
403
  const dynamicDescription =
413
404
  descriptionFormula && descriptionFormula.type !== 'value'
414
- const dynamicMetaFormulas = Object.values(meta ?? {}).some((r) =>
415
- Object.values(
416
- r.attrs ?? {}, // fallback to make sure we don't crash on legacy values
417
- ).some((a) => a.type !== 'value'),
405
+ const dynamicMetaFormulas = Object.values(meta ?? {}).some(
406
+ (r) =>
407
+ r.content?.type !== 'value' ||
408
+ Object.values(
409
+ r.attrs ?? {}, // fallback to make sure we don't crash on legacy values
410
+ ).some((a) => a.type !== 'value'),
418
411
  )
419
412
  if (dynamicDescription || dynamicMetaFormulas) {
420
413
  const findMetaElement = (name: string) =>
@@ -423,7 +416,11 @@ const setupMetaUpdates = (
423
416
  ) ?? null
424
417
 
425
418
  const updateMetaElement = (
426
- entry: { tag: string; attrs: Record<string, string> },
419
+ entry: {
420
+ tag: string
421
+ attrs: Record<string, string>
422
+ content: string | undefined
423
+ },
427
424
  id?: string,
428
425
  ) => {
429
426
  let existingElement: HTMLElement | null = null
@@ -452,19 +449,18 @@ const setupMetaUpdates = (
452
449
  }
453
450
  existingElement!.setAttribute(key, value)
454
451
  })
452
+ if (
453
+ typeof entry.content === 'string' &&
454
+ !VOID_HTML_ELEMENTS.includes(entry.tag.toLowerCase())
455
+ ) {
456
+ existingElement.textContent = entry.content
457
+ }
455
458
  }
456
459
  if (dynamicDescription) {
457
460
  dataSignal
458
- .map<string | null>((data) =>
461
+ .map((data) =>
459
462
  component
460
- ? applyFormula(descriptionFormula, {
461
- data,
462
- component,
463
- root: document,
464
- package: undefined,
465
- toddle: window.toddle,
466
- env,
467
- })
463
+ ? applyFormula(descriptionFormula, getFormulaContext(data))
468
464
  : null,
469
465
  )
470
466
  .subscribe((newDescription) => {
@@ -501,6 +497,7 @@ const setupMetaUpdates = (
501
497
  property: 'og:description',
502
498
  content: newDescription,
503
499
  },
500
+ content: undefined,
504
501
  })
505
502
  }
506
503
  }
@@ -509,36 +506,37 @@ const setupMetaUpdates = (
509
506
  if (dynamicMetaFormulas) {
510
507
  Object.entries(meta ?? {})
511
508
  // Filter out meta tags that have no dynamic formulas
512
- .filter(([_, entry]) =>
513
- // fallback to make sure we don't crash on legacy values.
514
- Object.values(entry.attrs ?? {}).some((a) => a.type !== 'value'),
509
+ .filter(
510
+ ([_, entry]) =>
511
+ // fallback to make sure we don't crash on legacy values.
512
+ entry.content?.type !== 'value' ||
513
+ Object.values(entry.attrs ?? {}).some((a) => a.type !== 'value'),
515
514
  )
516
515
  .forEach(([id, entry]) => {
517
516
  dataSignal
518
- .map<Record<string, string>>((data) => {
517
+ .map((data) => {
518
+ const context = getFormulaContext(data)
519
519
  // Return the new values for all attributes (we assume they're strings)
520
520
  const values = Object.entries(entry.attrs ?? {}).reduce(
521
521
  (agg, [key, formula]) =>
522
522
  component
523
523
  ? {
524
524
  ...agg,
525
- [key]: applyFormula(formula, {
526
- data,
527
- component,
528
- root: document,
529
- package: undefined,
530
- toddle: window.toddle,
531
- env,
532
- }),
525
+ [key]: applyFormula(formula, context),
533
526
  }
534
527
  : agg,
535
528
  {},
536
529
  )
537
- return values
530
+ return {
531
+ attrs: values,
532
+ content: entry.content
533
+ ? applyFormula(entry.content, context)
534
+ : undefined,
535
+ }
538
536
  })
539
- .subscribe((attrs) =>
537
+ .subscribe(({ attrs, content }) =>
540
538
  // Update the meta tags with the new values
541
- updateMetaElement({ tag: entry.tag, attrs }, id),
539
+ updateMetaElement({ tag: entry.tag, attrs, content }, id),
542
540
  )
543
541
  })
544
542
  }
@@ -121,7 +121,7 @@ describe('CustomPropertyStyleSheet', () => {
121
121
  '.my-class { --my-other-property: 512px; }',
122
122
  )
123
123
  instance.unregisterProperty('.my-class', '--my-other-property')
124
- expect(instance.getStyleSheet().cssRules[0].cssText).toBe('.my-class { }')
124
+ expect(instance.getStyleSheet().cssRules).toBeEmpty()
125
125
  })
126
126
 
127
127
  test('it unregisters a property with media queries', () => {
@@ -149,11 +149,6 @@ describe('CustomPropertyStyleSheet', () => {
149
149
  mediaQuery: { 'max-width': '600px' },
150
150
  },
151
151
  )
152
- expect(instance.getStyleSheet().cssRules[0].cssText).toBe(
153
- `\
154
- @media (max-width: 600px) {
155
- .my-class-with-media { }
156
- }`,
157
- )
152
+ expect(instance.getStyleSheet().cssRules).toBeEmpty()
158
153
  })
159
154
  })
@@ -76,7 +76,6 @@ export class CustomPropertyStyleSheet {
76
76
  options?: Nullable<{
77
77
  mediaQuery?: Nullable<MediaQuery>
78
78
  startingStyle?: Nullable<boolean>
79
- deepClean?: Nullable<boolean>
80
79
  }>,
81
80
  ): void {
82
81
  if (!this.ruleMap) {
@@ -97,7 +96,7 @@ export class CustomPropertyStyleSheet {
97
96
 
98
97
  // Cleaning up empty selectors is probably not necessary in production and may have performance implications.
99
98
  // However, it is required for the editor-preview as it is a dynamic environment and things may get reordered and canvas reused.
100
- if (options?.deepClean && rule.style.length === 0) {
99
+ if (rule.style.length === 0) {
101
100
  this.styleSheet.deleteRule(
102
101
  Array.from(this.ruleMap.keys()).indexOf(fullSelector),
103
102
  )
@@ -3,13 +3,13 @@
3
3
  * This is more efficient than processing each callback in a separate requestAnimationFrame due to the overhead.
4
4
  */
5
5
  export class BatchQueue {
6
+ constructor() {}
6
7
  private batchQueue: Array<() => void> = []
7
8
  private isProcessing = false
8
9
  private processBatch() {
9
10
  if (this.isProcessing) return
10
11
  this.isProcessing = true
11
-
12
- requestAnimationFrame(() => {
12
+ queueMicrotask(() => {
13
13
  while (this.batchQueue.length > 0) {
14
14
  const callback = this.batchQueue.shift()
15
15
  callback?.()
@@ -0,0 +1,7 @@
1
+ import type { Formula } from '@nordcraft/core/dist/formula/formula'
2
+ import { isDefined } from '@nordcraft/core/dist/utils/util'
3
+
4
+ export const formulaHasValue = (
5
+ formula: Formula | undefined,
6
+ ): formula is Formula =>
7
+ isDefined(formula) && !(formula.type === 'value' && !isDefined(formula.value))
@@ -2,10 +2,9 @@ import type { Signal } from '../signal/signal'
2
2
 
3
3
  import { CUSTOM_PROPERTIES_STYLESHEET_ID } from '@nordcraft/core/dist/styling/theme.const'
4
4
  import type { StyleVariant } from '@nordcraft/core/dist/styling/variantSelector'
5
- import type { Runtime } from '@nordcraft/core/dist/types'
6
5
  import { CustomPropertyStyleSheet } from '../styles/CustomPropertyStyleSheet'
7
6
 
8
- let customPropertiesStylesheet: CustomPropertyStyleSheet | undefined
7
+ export let customPropertiesStylesheet: CustomPropertyStyleSheet | undefined
9
8
 
10
9
  export function subscribeCustomProperty({
11
10
  selector,
@@ -13,14 +12,12 @@ export function subscribeCustomProperty({
13
12
  signal,
14
13
  variant,
15
14
  root,
16
- runtime,
17
15
  }: {
18
16
  selector: string
19
17
  customPropertyName: string
20
18
  signal: Signal<string>
21
19
  variant?: StyleVariant
22
20
  root: Document | ShadowRoot
23
- runtime: Runtime
24
21
  }) {
25
22
  customPropertiesStylesheet ??= new CustomPropertyStyleSheet(
26
23
  root,
@@ -43,7 +40,6 @@ export function subscribeCustomProperty({
43
40
  selector,
44
41
  customPropertyName,
45
42
  {
46
- deepClean: runtime === 'preview',
47
43
  mediaQuery: variant?.mediaQuery,
48
44
  startingStyle: variant?.startingStyle,
49
45
  },