@nordcraft/runtime 1.0.94 → 1.0.96

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 (75) hide show
  1. package/dist/api/createAPI.js +29 -11
  2. package/dist/api/createAPI.js.map +1 -1
  3. package/dist/api/createAPIv2.js +49 -11
  4. package/dist/api/createAPIv2.js.map +1 -1
  5. package/dist/components/createComponent.js +14 -5
  6. package/dist/components/createComponent.js.map +1 -1
  7. package/dist/components/createElement.js +48 -16
  8. package/dist/components/createElement.js.map +1 -1
  9. package/dist/components/createNode.js +23 -10
  10. package/dist/components/createNode.js.map +1 -1
  11. package/dist/components/createNode.test.js +3 -3
  12. package/dist/components/createNode.test.js.map +1 -1
  13. package/dist/components/createSlot.js +2 -1
  14. package/dist/components/createSlot.js.map +1 -1
  15. package/dist/components/createText.js +7 -2
  16. package/dist/components/createText.js.map +1 -1
  17. package/dist/components/renderComponent.d.ts +4 -1
  18. package/dist/components/renderComponent.js +4 -2
  19. package/dist/components/renderComponent.js.map +1 -1
  20. package/dist/context/subscribeToContext.js +12 -2
  21. package/dist/context/subscribeToContext.js.map +1 -1
  22. package/dist/custom-element/ToddleComponent.js +12 -4
  23. package/dist/custom-element/ToddleComponent.js.map +1 -1
  24. package/dist/custom-element.main.esm.js +29 -29
  25. package/dist/custom-element.main.esm.js.map +4 -4
  26. package/dist/editor/editorUtils.d.ts +1 -0
  27. package/dist/editor/editorUtils.js +14 -0
  28. package/dist/editor/editorUtils.js.map +1 -0
  29. package/dist/editor/types.d.ts +4 -0
  30. package/dist/editor/types.js.map +1 -1
  31. package/dist/editor-preview.main.js +71 -18
  32. package/dist/editor-preview.main.js.map +1 -1
  33. package/dist/events/handleAction.js +62 -31
  34. package/dist/events/handleAction.js.map +1 -1
  35. package/dist/page.main.esm.js +3 -3
  36. package/dist/page.main.esm.js.map +4 -4
  37. package/dist/page.main.js +39 -8
  38. package/dist/page.main.js.map +1 -1
  39. package/dist/utils/createFormulaCache.js +1 -1
  40. package/dist/utils/createFormulaCache.js.map +1 -1
  41. package/dist/utils/nodes.d.ts +1 -0
  42. package/dist/utils/nodes.js +9 -0
  43. package/dist/utils/nodes.js.map +1 -1
  44. package/dist/utils/nodes.test.d.ts +1 -0
  45. package/dist/utils/nodes.test.js +192 -0
  46. package/dist/utils/nodes.test.js.map +1 -0
  47. package/dist/utils/subscribeCustomProperty.d.ts +1 -1
  48. package/dist/utils/subscribeCustomProperty.js +8 -4
  49. package/dist/utils/subscribeCustomProperty.js.map +1 -1
  50. package/dist/utils/subscribeCustomProperty.test.d.ts +1 -0
  51. package/dist/utils/subscribeCustomProperty.test.js +63 -0
  52. package/dist/utils/subscribeCustomProperty.test.js.map +1 -0
  53. package/package.json +3 -3
  54. package/src/api/createAPI.ts +90 -46
  55. package/src/api/createAPIv2.ts +67 -13
  56. package/src/components/createComponent.ts +85 -67
  57. package/src/components/createElement.ts +63 -27
  58. package/src/components/createNode.test.ts +3 -3
  59. package/src/components/createNode.ts +47 -22
  60. package/src/components/createSlot.ts +2 -1
  61. package/src/components/createText.ts +34 -18
  62. package/src/components/renderComponent.ts +8 -1
  63. package/src/context/subscribeToContext.ts +12 -2
  64. package/src/custom-element/ToddleComponent.ts +37 -22
  65. package/src/editor/editorUtils.ts +13 -0
  66. package/src/editor/types.ts +5 -0
  67. package/src/editor-preview.main.ts +125 -46
  68. package/src/events/handleAction.ts +173 -96
  69. package/src/page.main.ts +64 -26
  70. package/src/types.d.ts +3 -0
  71. package/src/utils/createFormulaCache.ts +3 -3
  72. package/src/utils/nodes.test.ts +246 -0
  73. package/src/utils/nodes.ts +11 -0
  74. package/src/utils/subscribeCustomProperty.test.ts +78 -0
  75. package/src/utils/subscribeCustomProperty.ts +21 -22
@@ -21,6 +21,7 @@ import {
21
21
  } from '@nordcraft/core/dist/formula/formula'
22
22
  import {
23
23
  type CodeFormula,
24
+ type FormulaEvaluationReporter,
24
25
  type PluginFormula,
25
26
  type ToddleFormula,
26
27
  } from '@nordcraft/core/dist/formula/formulaTypes'
@@ -63,6 +64,7 @@ import { dragEnded } from './editor/drag-drop/dragEnded'
63
64
  import { dragMove } from './editor/drag-drop/dragMove'
64
65
  import { dragReorder } from './editor/drag-drop/dragReorder'
65
66
  import { dragStarted } from './editor/drag-drop/dragStarted'
67
+ import { debounce } from './editor/editorUtils'
66
68
  import { introspectApiRequest } from './editor/graphql'
67
69
  import { isInputTarget } from './editor/input'
68
70
  import { updateComponentLinks } from './editor/links'
@@ -91,7 +93,11 @@ import type {
91
93
  import { createFormulaCache } from './utils/createFormulaCache'
92
94
  import { getThemeSignal } from './utils/getThemeSignal'
93
95
  import { markSelectedElement } from './utils/markSelectedElement'
94
- import { getNodeAndAncestors, isNodeOrAncestorConditional } from './utils/nodes'
96
+ import {
97
+ getNodeAndAncestors,
98
+ isNodeOrAncestorConditional,
99
+ stripNodeIdRepeatIndices,
100
+ } from './utils/nodes'
95
101
  import { rectHasPoint } from './utils/rectHasPoint'
96
102
  import {
97
103
  getScrollStateRestorer,
@@ -243,6 +249,24 @@ export const createRoot = (
243
249
  ...(packageComponents ?? []),
244
250
  ]
245
251
  let component: Component | null = null
252
+ let componentFormulaData: Record<string, any> = {}
253
+
254
+ const reportFormulaEvaluation: FormulaEvaluationReporter = (path, data) => {
255
+ componentFormulaData[path.join('/')] = data
256
+ reportComponentFormulaData()
257
+ }
258
+ const reportComponentFormulaData = debounce(
259
+ () => {
260
+ postMessageToEditor({
261
+ type: 'componentFormulaData',
262
+ data: componentFormulaData,
263
+ component: component?.name,
264
+ })
265
+ componentFormulaData = {}
266
+ },
267
+ 5, // 5ms debounce to batch multiple rapid updates
268
+ true,
269
+ )
246
270
  let selectedNodeId: string | null = null
247
271
  let highlightedNodeId: string | null = null
248
272
  let styleVariantSelection: {
@@ -311,6 +335,8 @@ export const createRoot = (
311
335
  )
312
336
  // Destroy the dataSignal (including subscribers) for the previous component
313
337
  dataSignal.destroy()
338
+ // Reset all evaluated formula data
339
+ componentFormulaData = {}
314
340
  // Re-subscribe all dataSignal subscribers
315
341
  setupDataSignalSubscribers()
316
342
  // Re-initialize the data signal for the new component
@@ -512,7 +538,13 @@ export const createRoot = (
512
538
  return
513
539
  }
514
540
  case 'highlight': {
515
- highlightedNodeId = message.data.highlightedNodeId ?? null
541
+ const highlightId = message.data.highlightedNodeId
542
+ highlightedNodeId = highlightId
543
+ ? highlightId
544
+ .split('.')
545
+ .map((part) => part.split('(')[0])
546
+ .join('.')
547
+ : null
516
548
  return
517
549
  }
518
550
  case 'mousemove':
@@ -614,7 +646,7 @@ export const createRoot = (
614
646
  } else if (type === 'mousemove' && id !== highlightedNodeId) {
615
647
  postMessageToEditor({
616
648
  type: 'highlight',
617
- highlightedNodeId: id,
649
+ highlightedNodeId: stripNodeIdRepeatIndices(id),
618
650
  })
619
651
  } else if (
620
652
  type === 'dblclick' &&
@@ -704,6 +736,7 @@ export const createRoot = (
704
736
  package: ctx?.package,
705
737
  toddle: window.toddle,
706
738
  env,
739
+ jsonPath: [],
707
740
  }
708
741
  const introspectionResult = await introspectApiRequest({
709
742
  api,
@@ -1181,19 +1214,32 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1181
1214
  .map(([customPropertyName, customProperty]) => [
1182
1215
  customPropertyName,
1183
1216
  appendUnit(
1184
- applyFormula(customProperty.formula, {
1185
- data: {
1186
- Attributes: dataSignal.get().Attributes,
1187
- Variables: dataSignal.get().Variables,
1188
- Contexts: ctxDataSignal?.get().Contexts ?? {},
1189
- },
1190
- component: getCurrentComponent(),
1191
- root: ctx?.root,
1192
- formulaCache: {},
1193
- package: ctx?.package,
1194
- toddle: window.toddle,
1195
- env,
1196
- } as FormulaContext),
1217
+ applyFormula(
1218
+ customProperty.formula,
1219
+ {
1220
+ data: {
1221
+ Attributes: dataSignal.get().Attributes,
1222
+ Variables: dataSignal.get().Variables,
1223
+ Contexts: ctxDataSignal?.get().Contexts ?? {},
1224
+ },
1225
+ component: getCurrentComponent(),
1226
+ root: ctx?.root,
1227
+ formulaCache: {},
1228
+ package: ctx?.package,
1229
+ toddle: window.toddle,
1230
+ env,
1231
+ // TODO: Ensure we have the node id here
1232
+ jsonPath: [
1233
+ 'nodes',
1234
+ '<random id>',
1235
+ 'variants',
1236
+ styleVariantSelection?.styleVariantIndex ?? 0,
1237
+ customPropertyName,
1238
+ ],
1239
+ reportFormulaEvaluation,
1240
+ } as FormulaContext,
1241
+ [],
1242
+ ),
1197
1243
  customProperty.unit,
1198
1244
  ),
1199
1245
  ])
@@ -1306,6 +1352,8 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1306
1352
  package: ctx?.package,
1307
1353
  toddle: window.toddle,
1308
1354
  env,
1355
+ jsonPath: ['route', 'info', 'meta'],
1356
+ reportFormulaEvaluation,
1309
1357
  })
1310
1358
  }
1311
1359
  if (fastDeepEqual(_component.contexts, ctx?.component.contexts) === false) {
@@ -1351,6 +1399,9 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1351
1399
  package: ctx?.package,
1352
1400
  toddle: window.toddle,
1353
1401
  env,
1402
+ jsonPath: [],
1403
+ // We don't evaluate formulas in context providers in preview mode currently
1404
+ reportFormulaEvaluation: undefined,
1354
1405
  }
1355
1406
 
1356
1407
  // Pages can also be context-providers!
@@ -1373,7 +1424,11 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1373
1424
  providerComponent.variables ?? {},
1374
1425
  ([name, variable]) => [
1375
1426
  name,
1376
- applyFormula(variable.initialValue, formulaContext),
1427
+ applyFormula(variable.initialValue, formulaContext, [
1428
+ 'variables',
1429
+ name,
1430
+ 'initialValue',
1431
+ ]),
1377
1432
  ],
1378
1433
  )
1379
1434
 
@@ -1391,7 +1446,10 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1391
1446
 
1392
1447
  return [
1393
1448
  formulaName,
1394
- applyFormula(formula.formula, formulaContext),
1449
+ applyFormula(formula.formula, formulaContext, [
1450
+ 'formulas',
1451
+ formulaName,
1452
+ ]),
1395
1453
  ]
1396
1454
  }),
1397
1455
  ),
@@ -1407,14 +1465,20 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1407
1465
  _component.variables ?? {},
1408
1466
  ([name, { initialValue }]) => [
1409
1467
  name,
1410
- applyFormula(initialValue, {
1411
- data: { Attributes, Contexts },
1412
- component: _component!,
1413
- root: document,
1414
- package: ctx?.package,
1415
- toddle: window.toddle,
1416
- env,
1417
- }),
1468
+ applyFormula(
1469
+ initialValue,
1470
+ {
1471
+ data: { Attributes, Contexts },
1472
+ component: _component!,
1473
+ root: document,
1474
+ package: ctx?.package,
1475
+ toddle: window.toddle,
1476
+ env,
1477
+ jsonPath: ctx?.jsonPath,
1478
+ reportFormulaEvaluation,
1479
+ },
1480
+ ['variables', name, 'initialValue'],
1481
+ ),
1418
1482
  ],
1419
1483
  )
1420
1484
  }
@@ -1455,6 +1519,9 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1455
1519
  for (const api in newCtx.component.apis) {
1456
1520
  // check if the api has changed (ignoring onCompleted and onFailed).
1457
1521
  const apiInstance = newCtx.component.apis[api]
1522
+ if (!apiInstance) {
1523
+ continue
1524
+ }
1458
1525
  const previousApiInstance = ctx?.component.apis?.[api]
1459
1526
  if (isLegacyApi(apiInstance)) {
1460
1527
  if (
@@ -1478,14 +1545,17 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1478
1545
  ]),
1479
1546
  }
1480
1547
  })
1481
- newCtx.apis[api] = createLegacyAPI(apiInstance, newCtx)
1548
+ newCtx.apis[api] = createLegacyAPI(apiInstance, {
1549
+ ...newCtx,
1550
+ jsonPath: ['apis', api],
1551
+ })
1482
1552
  }
1483
1553
  } else {
1484
1554
  const existingApi = newCtx.apis[api] as ContextApiV2 | undefined
1485
1555
  if (!existingApi) {
1486
1556
  newCtx.apis[api] = createAPI({
1487
1557
  apiRequest: apiInstance,
1488
- ctx: newCtx,
1558
+ ctx: { ...newCtx, jsonPath: ['apis', api] },
1489
1559
  componentData: dataSignal.get(),
1490
1560
  })
1491
1561
  } else {
@@ -1520,7 +1590,7 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1520
1590
  id: 'root',
1521
1591
  path: '0',
1522
1592
  dataSignal: ctxDataSignal,
1523
- ctx: newCtx,
1593
+ ctx: { ...newCtx, jsonPath: ['nodes', 'root'] },
1524
1594
  parentElement: domNode,
1525
1595
  instance: { [newCtx.component.name]: 'root' },
1526
1596
  })
@@ -1625,6 +1695,8 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1625
1695
  package: undefined,
1626
1696
  toddle: window.toddle,
1627
1697
  env,
1698
+ jsonPath: [], // TODO: decide if the component path is needed here
1699
+ reportFormulaEvaluation,
1628
1700
  }
1629
1701
 
1630
1702
  setupThemeSubscription(ctx.component, ctx.dataSignal, env).subscribe(
@@ -1641,15 +1713,21 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1641
1713
  .map(([name, formula]) => [
1642
1714
  name,
1643
1715
  dataSignal.map((data) =>
1644
- applyFormula(formula.formula, {
1645
- data,
1646
- component,
1647
- formulaCache: ctx.formulaCache,
1648
- root: ctx.root,
1649
- package: ctx.package,
1650
- toddle: window.toddle,
1651
- env,
1652
- }),
1716
+ applyFormula(
1717
+ formula.formula,
1718
+ {
1719
+ data,
1720
+ component,
1721
+ formulaCache: ctx.formulaCache,
1722
+ root: ctx.root,
1723
+ package: ctx.package,
1724
+ toddle: window.toddle,
1725
+ env,
1726
+ jsonPath: ctx.jsonPath,
1727
+ reportFormulaEvaluation,
1728
+ },
1729
+ ['formulas', name],
1730
+ ),
1653
1731
  ),
1654
1732
  ]),
1655
1733
  )
@@ -1756,7 +1834,10 @@ const insertHeadTags = (
1756
1834
  <link
1757
1835
  data-meta-id="${id}"
1758
1836
  ${Object.entries(entry.attrs ?? {})
1759
- .map(([key, value]) => `${key}="${applyFormula(value, context)}"`)
1837
+ .map(
1838
+ ([key, value]) =>
1839
+ `${key}="${applyFormula(value, context, [id, 'attrs', key])}"`,
1840
+ )
1760
1841
  .join(' ')}
1761
1842
  />
1762
1843
  `),
@@ -1768,7 +1849,10 @@ const insertHeadTags = (
1768
1849
  <script
1769
1850
  data-meta-id="${id}"
1770
1851
  ${Object.entries(entry.attrs ?? {})
1771
- .map(([key, value]) => `${key}="${applyFormula(value, context)}"`)
1852
+ .map(
1853
+ ([key, value]) =>
1854
+ `${key}="${applyFormula(value, context, [id, 'attrs', key])}"`,
1855
+ )
1772
1856
  .join(' ')}
1773
1857
  >${applyFormula(entry.content ?? '', context)}</script>
1774
1858
  `),
@@ -1801,7 +1885,7 @@ export function getDOMNodeFromNodeId(
1801
1885
  }
1802
1886
 
1803
1887
  return document.querySelector(
1804
- `[data-id="${selectedNodeId}"]:not([data-component])`,
1888
+ `[data-id="${stripNodeIdRepeatIndices(selectedNodeId)}"]:not([data-component])`,
1805
1889
  )
1806
1890
  }
1807
1891
 
@@ -1818,11 +1902,6 @@ function getNodeId(component: Component, path: string[]) {
1818
1902
  return null
1819
1903
  }
1820
1904
 
1821
- // We only allow selecting the first element in a repeat (which does not have a repeat-index "()")
1822
- if (nextChild.endsWith(')')) {
1823
- return null
1824
- }
1825
-
1826
1905
  return getId(path, currentNode.children[parseInt(nextChild)])
1827
1906
  }
1828
1907
  return getId(path, 'root')