@nordcraft/runtime 1.0.95 → 1.0.97

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 (74) 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 +19 -10
  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 +22 -11
  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 +2 -0
  27. package/dist/editor/editorUtils.js +26 -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 +82 -18
  32. package/dist/editor-preview.main.js.map +1 -1
  33. package/dist/events/handleAction.js +74 -42
  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.map +1 -1
  40. package/dist/utils/nodes.d.ts +1 -0
  41. package/dist/utils/nodes.js +9 -0
  42. package/dist/utils/nodes.js.map +1 -1
  43. package/dist/utils/nodes.test.d.ts +1 -0
  44. package/dist/utils/nodes.test.js +192 -0
  45. package/dist/utils/nodes.test.js.map +1 -0
  46. package/dist/utils/subscribeCustomProperty.d.ts +1 -1
  47. package/dist/utils/subscribeCustomProperty.js +8 -4
  48. package/dist/utils/subscribeCustomProperty.js.map +1 -1
  49. package/dist/utils/subscribeCustomProperty.test.d.ts +1 -0
  50. package/dist/utils/subscribeCustomProperty.test.js +63 -0
  51. package/dist/utils/subscribeCustomProperty.test.js.map +1 -0
  52. package/package.json +3 -3
  53. package/src/api/createAPI.ts +90 -46
  54. package/src/api/createAPIv2.ts +79 -13
  55. package/src/components/createComponent.ts +123 -85
  56. package/src/components/createElement.ts +63 -27
  57. package/src/components/createNode.test.ts +3 -3
  58. package/src/components/createNode.ts +55 -31
  59. package/src/components/createSlot.ts +2 -1
  60. package/src/components/createText.ts +35 -18
  61. package/src/components/renderComponent.ts +8 -1
  62. package/src/context/subscribeToContext.ts +12 -2
  63. package/src/custom-element/ToddleComponent.ts +37 -22
  64. package/src/editor/editorUtils.ts +28 -0
  65. package/src/editor/types.ts +5 -0
  66. package/src/editor-preview.main.ts +137 -46
  67. package/src/events/handleAction.ts +190 -113
  68. package/src/page.main.ts +64 -26
  69. package/src/types.d.ts +3 -0
  70. package/src/utils/createFormulaCache.ts +2 -2
  71. package/src/utils/nodes.test.ts +246 -0
  72. package/src/utils/nodes.ts +11 -0
  73. package/src/utils/subscribeCustomProperty.test.ts +78 -0
  74. 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 { throttleToIdleCallback } 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,37 @@ 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 = (
255
+ path,
256
+ data,
257
+ ctx,
258
+ ) => {
259
+ if (
260
+ data !== undefined &&
261
+ path.length > 0 &&
262
+ // We are currently skipping all children formulas to lower the scope of reporting to what the user can see in the canvas
263
+ ctx.component?.name === component?.name
264
+ ) {
265
+ try {
266
+ componentFormulaData[path.join('/')] = JSON.parse(JSON.stringify(data))
267
+ } catch {
268
+ componentFormulaData[path.join('/')] =
269
+ `[Unserializable value of type ${typeof data}]`
270
+ } finally {
271
+ reportComponentFormulaData()
272
+ }
273
+ }
274
+ }
275
+ const reportComponentFormulaData = throttleToIdleCallback(() => {
276
+ postMessageToEditor({
277
+ type: 'componentFormulaData',
278
+ data: componentFormulaData,
279
+ component: component?.name,
280
+ })
281
+ componentFormulaData = {}
282
+ })
246
283
  let selectedNodeId: string | null = null
247
284
  let highlightedNodeId: string | null = null
248
285
  let styleVariantSelection: {
@@ -311,6 +348,8 @@ export const createRoot = (
311
348
  )
312
349
  // Destroy the dataSignal (including subscribers) for the previous component
313
350
  dataSignal.destroy()
351
+ // Reset all evaluated formula data
352
+ componentFormulaData = {}
314
353
  // Re-subscribe all dataSignal subscribers
315
354
  setupDataSignalSubscribers()
316
355
  // Re-initialize the data signal for the new component
@@ -512,7 +551,13 @@ export const createRoot = (
512
551
  return
513
552
  }
514
553
  case 'highlight': {
515
- highlightedNodeId = message.data.highlightedNodeId ?? null
554
+ const highlightId = message.data.highlightedNodeId
555
+ highlightedNodeId = highlightId
556
+ ? highlightId
557
+ .split('.')
558
+ .map((part) => part.split('(')[0])
559
+ .join('.')
560
+ : null
516
561
  return
517
562
  }
518
563
  case 'mousemove':
@@ -614,7 +659,7 @@ export const createRoot = (
614
659
  } else if (type === 'mousemove' && id !== highlightedNodeId) {
615
660
  postMessageToEditor({
616
661
  type: 'highlight',
617
- highlightedNodeId: id,
662
+ highlightedNodeId: stripNodeIdRepeatIndices(id),
618
663
  })
619
664
  } else if (
620
665
  type === 'dblclick' &&
@@ -704,6 +749,7 @@ export const createRoot = (
704
749
  package: ctx?.package,
705
750
  toddle: window.toddle,
706
751
  env,
752
+ jsonPath: [],
707
753
  }
708
754
  const introspectionResult = await introspectApiRequest({
709
755
  api,
@@ -1181,19 +1227,32 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1181
1227
  .map(([customPropertyName, customProperty]) => [
1182
1228
  customPropertyName,
1183
1229
  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),
1230
+ applyFormula(
1231
+ customProperty.formula,
1232
+ {
1233
+ data: {
1234
+ Attributes: dataSignal.get().Attributes,
1235
+ Variables: dataSignal.get().Variables,
1236
+ Contexts: ctxDataSignal?.get().Contexts ?? {},
1237
+ },
1238
+ component: getCurrentComponent(),
1239
+ root: ctx?.root,
1240
+ formulaCache: {},
1241
+ package: ctx?.package,
1242
+ toddle: window.toddle,
1243
+ env,
1244
+ // TODO: Ensure we have the node id here
1245
+ jsonPath: [
1246
+ 'nodes',
1247
+ '<random id>',
1248
+ 'variants',
1249
+ styleVariantSelection?.styleVariantIndex ?? 0,
1250
+ customPropertyName,
1251
+ ],
1252
+ reportFormulaEvaluation,
1253
+ } as FormulaContext,
1254
+ [],
1255
+ ),
1197
1256
  customProperty.unit,
1198
1257
  ),
1199
1258
  ])
@@ -1306,6 +1365,8 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1306
1365
  package: ctx?.package,
1307
1366
  toddle: window.toddle,
1308
1367
  env,
1368
+ jsonPath: ['route', 'info', 'meta'],
1369
+ reportFormulaEvaluation,
1309
1370
  })
1310
1371
  }
1311
1372
  if (fastDeepEqual(_component.contexts, ctx?.component.contexts) === false) {
@@ -1351,6 +1412,9 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1351
1412
  package: ctx?.package,
1352
1413
  toddle: window.toddle,
1353
1414
  env,
1415
+ jsonPath: [],
1416
+ // We don't evaluate formulas in context providers in preview mode currently
1417
+ reportFormulaEvaluation: undefined,
1354
1418
  }
1355
1419
 
1356
1420
  // Pages can also be context-providers!
@@ -1373,7 +1437,10 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1373
1437
  providerComponent.variables ?? {},
1374
1438
  ([name, variable]) => [
1375
1439
  name,
1376
- applyFormula(variable.initialValue, formulaContext),
1440
+ applyFormula(variable.initialValue, formulaContext, [
1441
+ 'variables',
1442
+ name,
1443
+ ]),
1377
1444
  ],
1378
1445
  )
1379
1446
 
@@ -1391,7 +1458,10 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1391
1458
 
1392
1459
  return [
1393
1460
  formulaName,
1394
- applyFormula(formula.formula, formulaContext),
1461
+ applyFormula(formula.formula, formulaContext, [
1462
+ 'formulas',
1463
+ formulaName,
1464
+ ]),
1395
1465
  ]
1396
1466
  }),
1397
1467
  ),
@@ -1407,14 +1477,20 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1407
1477
  _component.variables ?? {},
1408
1478
  ([name, { initialValue }]) => [
1409
1479
  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
- }),
1480
+ applyFormula(
1481
+ initialValue,
1482
+ {
1483
+ data: { Attributes, Contexts },
1484
+ component: _component!,
1485
+ root: document,
1486
+ package: ctx?.package,
1487
+ toddle: window.toddle,
1488
+ env,
1489
+ jsonPath: ctx?.jsonPath,
1490
+ reportFormulaEvaluation,
1491
+ },
1492
+ ['variables', name],
1493
+ ),
1418
1494
  ],
1419
1495
  )
1420
1496
  }
@@ -1455,6 +1531,9 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1455
1531
  for (const api in newCtx.component.apis) {
1456
1532
  // check if the api has changed (ignoring onCompleted and onFailed).
1457
1533
  const apiInstance = newCtx.component.apis[api]
1534
+ if (!apiInstance) {
1535
+ continue
1536
+ }
1458
1537
  const previousApiInstance = ctx?.component.apis?.[api]
1459
1538
  if (isLegacyApi(apiInstance)) {
1460
1539
  if (
@@ -1478,14 +1557,17 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1478
1557
  ]),
1479
1558
  }
1480
1559
  })
1481
- newCtx.apis[api] = createLegacyAPI(apiInstance, newCtx)
1560
+ newCtx.apis[api] = createLegacyAPI(apiInstance, {
1561
+ ...newCtx,
1562
+ jsonPath: ['apis', api],
1563
+ })
1482
1564
  }
1483
1565
  } else {
1484
1566
  const existingApi = newCtx.apis[api] as ContextApiV2 | undefined
1485
1567
  if (!existingApi) {
1486
1568
  newCtx.apis[api] = createAPI({
1487
1569
  apiRequest: apiInstance,
1488
- ctx: newCtx,
1570
+ ctx: { ...newCtx, jsonPath: ['apis', api] },
1489
1571
  componentData: dataSignal.get(),
1490
1572
  })
1491
1573
  } else {
@@ -1520,7 +1602,7 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1520
1602
  id: 'root',
1521
1603
  path: '0',
1522
1604
  dataSignal: ctxDataSignal,
1523
- ctx: newCtx,
1605
+ ctx: { ...newCtx, jsonPath: ['nodes', 'root'] },
1524
1606
  parentElement: domNode,
1525
1607
  instance: { [newCtx.component.name]: 'root' },
1526
1608
  })
@@ -1625,6 +1707,8 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1625
1707
  package: undefined,
1626
1708
  toddle: window.toddle,
1627
1709
  env,
1710
+ jsonPath: [], // TODO: decide if the component path is needed here
1711
+ reportFormulaEvaluation,
1628
1712
  }
1629
1713
 
1630
1714
  setupThemeSubscription(ctx.component, ctx.dataSignal, env).subscribe(
@@ -1641,15 +1725,21 @@ body[data-mode="design"] [data-id="${animationState.animatedElementId}"], body[d
1641
1725
  .map(([name, formula]) => [
1642
1726
  name,
1643
1727
  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
- }),
1728
+ applyFormula(
1729
+ formula.formula,
1730
+ {
1731
+ data,
1732
+ component,
1733
+ formulaCache: ctx.formulaCache,
1734
+ root: ctx.root,
1735
+ package: ctx.package,
1736
+ toddle: window.toddle,
1737
+ env,
1738
+ jsonPath: ctx.jsonPath,
1739
+ reportFormulaEvaluation,
1740
+ },
1741
+ ['formulas', name],
1742
+ ),
1653
1743
  ),
1654
1744
  ]),
1655
1745
  )
@@ -1756,7 +1846,10 @@ const insertHeadTags = (
1756
1846
  <link
1757
1847
  data-meta-id="${id}"
1758
1848
  ${Object.entries(entry.attrs ?? {})
1759
- .map(([key, value]) => `${key}="${applyFormula(value, context)}"`)
1849
+ .map(
1850
+ ([key, value]) =>
1851
+ `${key}="${applyFormula(value, context, [id, 'attrs', key])}"`,
1852
+ )
1760
1853
  .join(' ')}
1761
1854
  />
1762
1855
  `),
@@ -1768,7 +1861,10 @@ const insertHeadTags = (
1768
1861
  <script
1769
1862
  data-meta-id="${id}"
1770
1863
  ${Object.entries(entry.attrs ?? {})
1771
- .map(([key, value]) => `${key}="${applyFormula(value, context)}"`)
1864
+ .map(
1865
+ ([key, value]) =>
1866
+ `${key}="${applyFormula(value, context, [id, 'attrs', key])}"`,
1867
+ )
1772
1868
  .join(' ')}
1773
1869
  >${applyFormula(entry.content ?? '', context)}</script>
1774
1870
  `),
@@ -1801,7 +1897,7 @@ export function getDOMNodeFromNodeId(
1801
1897
  }
1802
1898
 
1803
1899
  return document.querySelector(
1804
- `[data-id="${selectedNodeId}"]:not([data-component])`,
1900
+ `[data-id="${stripNodeIdRepeatIndices(selectedNodeId)}"]:not([data-component])`,
1805
1901
  )
1806
1902
  }
1807
1903
 
@@ -1818,11 +1914,6 @@ function getNodeId(component: Component, path: string[]) {
1818
1914
  return null
1819
1915
  }
1820
1916
 
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
1917
  return getId(path, currentNode.children[parseInt(nextChild)])
1827
1918
  }
1828
1919
  return getId(path, 'root')