@nordcraft/runtime 1.0.75 → 1.0.77

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 (43) hide show
  1. package/README.md +1 -1
  2. package/dist/api/createAPI.d.ts +3 -2
  3. package/dist/api/createAPI.js.map +1 -1
  4. package/dist/components/createComponent.js +5 -5
  5. package/dist/components/createComponent.js.map +1 -1
  6. package/dist/components/createElement.js +2 -2
  7. package/dist/components/createElement.js.map +1 -1
  8. package/dist/components/createNode.js +4 -4
  9. package/dist/components/createNode.js.map +1 -1
  10. package/dist/components/renderComponent.js +2 -2
  11. package/dist/components/renderComponent.js.map +1 -1
  12. package/dist/context/subscribeToContext.js +2 -5
  13. package/dist/context/subscribeToContext.js.map +1 -1
  14. package/dist/custom-element/ToddleComponent.js +4 -4
  15. package/dist/custom-element/ToddleComponent.js.map +1 -1
  16. package/dist/custom-element.main.esm.js +18 -18
  17. package/dist/custom-element.main.esm.js.map +3 -3
  18. package/dist/editor/types.d.ts +3 -1
  19. package/dist/editor/types.js.map +1 -1
  20. package/dist/editor-preview.main.js +49 -49
  21. package/dist/editor-preview.main.js.map +1 -1
  22. package/dist/page.main.esm.js +3 -3
  23. package/dist/page.main.esm.js.map +3 -3
  24. package/dist/page.main.js +2 -2
  25. package/dist/page.main.js.map +1 -1
  26. package/dist/styles/CustomPropertyStyleSheet.d.ts +11 -10
  27. package/dist/styles/CustomPropertyStyleSheet.js.map +1 -1
  28. package/dist/utils/nodes.js +1 -1
  29. package/dist/utils/nodes.js.map +1 -1
  30. package/package.json +4 -4
  31. package/src/api/createAPI.ts +2 -1
  32. package/src/api/createAPIv2.ts +7 -7
  33. package/src/components/createComponent.ts +41 -35
  34. package/src/components/createElement.ts +2 -2
  35. package/src/components/createNode.ts +5 -5
  36. package/src/components/renderComponent.ts +2 -2
  37. package/src/context/subscribeToContext.ts +5 -5
  38. package/src/custom-element/ToddleComponent.ts +24 -21
  39. package/src/editor/types.ts +4 -1
  40. package/src/editor-preview.main.ts +72 -67
  41. package/src/page.main.ts +14 -12
  42. package/src/styles/CustomPropertyStyleSheet.ts +18 -14
  43. package/src/utils/nodes.ts +1 -1
@@ -453,7 +453,7 @@ export const createRoot = (
453
453
 
454
454
  const node = getDOMNodeFromNodeId(selectedNodeId)
455
455
  const element =
456
- component?.nodes[node?.getAttribute('data-node-id') ?? '']
456
+ component?.nodes?.[node?.getAttribute('data-node-id') ?? '']
457
457
  if (
458
458
  node &&
459
459
  element &&
@@ -544,7 +544,7 @@ export const createRoot = (
544
544
  return false
545
545
  }
546
546
  const nodeId = getNodeId(component, id.split('.').slice(1))
547
- const node = nodeId ? component?.nodes[nodeId] : undefined
547
+ const node = nodeId ? component?.nodes?.[nodeId] : undefined
548
548
  if (!node) {
549
549
  return false
550
550
  }
@@ -562,7 +562,7 @@ export const createRoot = (
562
562
  if (message.data.metaKey) {
563
563
  // Figure out if the clicked element is a text element
564
564
  // or if one of its descendants is a text element
565
- const root = component.nodes.root
565
+ const root = component.nodes?.root
566
566
  if (root && id) {
567
567
  const nodeLookup = getNodeAndAncestors(component, root, id)
568
568
  if (nodeLookup?.node.type === 'text') {
@@ -574,7 +574,7 @@ export const createRoot = (
574
574
  const firstTextChild =
575
575
  nodeLookup?.node.type === 'element'
576
576
  ? nodeLookup.node.children.find(
577
- (c) => component?.nodes[c]?.type === 'text',
577
+ (c) => component?.nodes?.[c]?.type === 'text',
578
578
  )
579
579
  : undefined
580
580
  if (firstTextChild) {
@@ -603,7 +603,7 @@ export const createRoot = (
603
603
  mode === 'design'
604
604
  ) {
605
605
  // Figure out if the clicked element is a component
606
- const root = component.nodes.root
606
+ const root = component.nodes?.root
607
607
  if (root) {
608
608
  const nodeLookup = getNodeAndAncestors(component, root, id)
609
609
  if (
@@ -659,7 +659,7 @@ export const createRoot = (
659
659
  }
660
660
  case 'introspect_qraphql_api': {
661
661
  const { apiKey } = message.data
662
- const api = component?.apis[apiKey]
662
+ const api = component?.apis?.[apiKey]
663
663
  if (api && !isLegacyApi(api) && component) {
664
664
  const formulaContext: FormulaContext = {
665
665
  component,
@@ -737,7 +737,7 @@ export const createRoot = (
737
737
  parent: parentDataId,
738
738
  index: !isNaN(nextSiblingId)
739
739
  ? nextSiblingId
740
- : component?.nodes[parentNodeId]?.children?.length,
740
+ : component?.nodes?.[parentNodeId]?.children?.length,
741
741
  })
742
742
  dragState = null
743
743
  })
@@ -913,38 +913,9 @@ export const createRoot = (
913
913
  })
914
914
  break
915
915
  case 'preview_style':
916
- const { styles: previewStyleStyles, theme, resources } = message.data
916
+ const { styles: previewStyleStyles, theme } = message.data
917
917
  cancelAnimationFrame(previewStyleAnimationFrame)
918
918
  previewStyleAnimationFrame = requestAnimationFrame(() => {
919
- // Allow for temporarily adding preview resources (e.g. fonts).
920
- const resourceElements = Array.from(
921
- document.head.querySelectorAll('[data-id="preview-resource"]'),
922
- )
923
- // Remove any resources that are no longer needed
924
- resourceElements.forEach((el) => {
925
- if (
926
- !resources ||
927
- resources.length === 0 ||
928
- !resources.some((res) => res.href === el.getAttribute('href'))
929
- ) {
930
- el.remove()
931
- }
932
- })
933
- resources
934
- ?.filter(
935
- (resource) =>
936
- !resourceElements.some(
937
- (el) => el.getAttribute('href') === resource.href,
938
- ),
939
- )
940
- .forEach((resource) => {
941
- const resourceElement = document.createElement('link')
942
- resourceElement.setAttribute('data-id', 'preview-resource')
943
- resourceElement.rel = 'stylesheet'
944
- resourceElement.href = resource.href
945
- document.head.appendChild(resourceElement)
946
- })
947
-
948
919
  // Update or create a new style tag and set the given styles with important priority
949
920
  let styleElement = document.head.querySelector(
950
921
  '[data-id="selected-node-styles"]',
@@ -965,20 +936,23 @@ export const createRoot = (
965
936
  // If style variant targets a pseudo-element, apply styles to it instead
966
937
  let pseudoElement = ''
967
938
  if (component && styleVariantSelection) {
968
- const nodeLookup = getNodeAndAncestors(
969
- component,
970
- component.nodes.root,
971
- styleVariantSelection.nodeId,
972
- )
939
+ const rootNode = component.nodes?.root
940
+ if (rootNode) {
941
+ const nodeLookup = getNodeAndAncestors(
942
+ component,
943
+ rootNode,
944
+ styleVariantSelection.nodeId,
945
+ )
973
946
 
974
- if (
975
- (nodeLookup?.node.type === 'element' ||
976
- nodeLookup?.node.type === 'component') &&
977
- nodeLookup.node.variants?.[
978
- styleVariantSelection.styleVariantIndex
979
- ].pseudoElement
980
- ) {
981
- pseudoElement = `::${nodeLookup.node.variants[styleVariantSelection.styleVariantIndex].pseudoElement}`
947
+ if (
948
+ (nodeLookup?.node.type === 'element' ||
949
+ nodeLookup?.node.type === 'component') &&
950
+ nodeLookup.node.variants?.[
951
+ styleVariantSelection.styleVariantIndex
952
+ ].pseudoElement
953
+ ) {
954
+ pseudoElement = `::${nodeLookup.node.variants[styleVariantSelection.styleVariantIndex].pseudoElement}`
955
+ }
982
956
  }
983
957
  }
984
958
 
@@ -1044,6 +1018,37 @@ export const createRoot = (
1044
1018
  }
1045
1019
  })
1046
1020
  break
1021
+ case 'preview_resources': {
1022
+ const { resources } = message.data
1023
+ // Allow for temporarily adding preview resources (e.g. fonts).
1024
+ const resourceElements = Array.from(
1025
+ document.head.querySelectorAll('[data-id="preview-resource"]'),
1026
+ )
1027
+ // Remove any resources that are no longer needed
1028
+ resourceElements.forEach((el) => {
1029
+ if (
1030
+ resources.length === 0 ||
1031
+ !resources.some((res) => res.href === el.getAttribute('href'))
1032
+ ) {
1033
+ el.remove()
1034
+ }
1035
+ })
1036
+ resources
1037
+ .filter(
1038
+ (resource) =>
1039
+ !resourceElements.some(
1040
+ (el) => el.getAttribute('href') === resource.href,
1041
+ ),
1042
+ )
1043
+ .forEach((resource) => {
1044
+ const resourceElement = document.createElement('link')
1045
+ resourceElement.setAttribute('data-id', 'preview-resource')
1046
+ resourceElement.rel = 'stylesheet'
1047
+ resourceElement.href = resource.href
1048
+ document.head.appendChild(resourceElement)
1049
+ })
1050
+ break
1051
+ }
1047
1052
  case 'preview_theme': {
1048
1053
  const { theme } = message.data
1049
1054
  if (theme) {
@@ -1078,7 +1083,7 @@ export const createRoot = (
1078
1083
  }
1079
1084
  if (mode === 'design') {
1080
1085
  if (selectedNodeId !== null) {
1081
- const root = _component?.nodes.root
1086
+ const root = _component?.nodes?.root
1082
1087
  if (root) {
1083
1088
  const nodeLookup = getNodeAndAncestors(
1084
1089
  _component,
@@ -1106,7 +1111,7 @@ export const createRoot = (
1106
1111
  nodeId: selectedNodeId,
1107
1112
  styleVariantIndex: variantIndex,
1108
1113
  }
1109
- const root = component?.nodes.root
1114
+ const root = component?.nodes?.root
1110
1115
  if (root && component) {
1111
1116
  const nodeLookup = getNodeAndAncestors(component, root, selectedNodeId)
1112
1117
  if (nodeLookup) {
@@ -1187,10 +1192,10 @@ export const createRoot = (
1187
1192
  if (
1188
1193
  fastDeepEqual(ctx?.component.attributes, _component.attributes) === false
1189
1194
  ) {
1190
- Attributes = mapObject(_component.attributes, ([name, { testValue }]) => [
1191
- name,
1192
- testValue,
1193
- ])
1195
+ Attributes = mapObject(
1196
+ _component.attributes ?? {},
1197
+ ([name, { testValue }]) => [name, testValue],
1198
+ )
1194
1199
  }
1195
1200
  if (
1196
1201
  _component.route &&
@@ -1234,10 +1239,10 @@ export const createRoot = (
1234
1239
  )
1235
1240
  }
1236
1241
 
1237
- Attributes = mapObject(_component.attributes, ([name, { testValue }]) => [
1238
- name,
1239
- testValue,
1240
- ])
1242
+ Attributes = mapObject(
1243
+ _component.attributes ?? {},
1244
+ ([name, { testValue }]) => [name, testValue],
1245
+ )
1241
1246
  }
1242
1247
  if (
1243
1248
  fastDeepEqual(
@@ -1282,7 +1287,7 @@ export const createRoot = (
1282
1287
  const formulaContext: FormulaContext = {
1283
1288
  data: {
1284
1289
  Attributes: mapObject(
1285
- providerComponent.attributes,
1290
+ providerComponent.attributes ?? {},
1286
1291
  ([name, attr]) => [name, attr.testValue],
1287
1292
  ),
1288
1293
  // Recursively resolve contexts providers before their children to build up the fake context tree in preview mode
@@ -1316,7 +1321,7 @@ export const createRoot = (
1316
1321
  }
1317
1322
  }
1318
1323
  formulaContext.data.Variables = mapObject(
1319
- providerComponent.variables,
1324
+ providerComponent.variables ?? {},
1320
1325
  ([name, variable]) => [
1321
1326
  name,
1322
1327
  applyFormula(variable.initialValue, formulaContext),
@@ -1350,7 +1355,7 @@ export const createRoot = (
1350
1355
  fastDeepEqual(_component.variables, ctx?.component.variables) === false
1351
1356
  ) {
1352
1357
  Variables = mapObject(
1353
- _component.variables,
1358
+ _component.variables ?? {},
1354
1359
  ([name, { initialValue }]) => [
1355
1360
  name,
1356
1361
  applyFormula(initialValue, {
@@ -1388,7 +1393,7 @@ export const createRoot = (
1388
1393
  for (const api in newCtx.component.apis) {
1389
1394
  // check if the api has changed (ignoring onCompleted and onFailed).
1390
1395
  const apiInstance = newCtx.component.apis[api]
1391
- const previousApiInstance = ctx?.component.apis[api]
1396
+ const previousApiInstance = ctx?.component.apis?.[api]
1392
1397
  if (isLegacyApi(apiInstance)) {
1393
1398
  if (
1394
1399
  fastDeepEqual(
@@ -1405,7 +1410,7 @@ export const createRoot = (
1405
1410
  Apis: omitKeys(data.Apis ?? {}, [
1406
1411
  ...Object.keys(data.Apis ?? {}).filter(
1407
1412
  // remove any data from an api that is not part of the component
1408
- (key) => !newCtx.component.apis[key],
1413
+ (key) => !newCtx.component.apis?.[key],
1409
1414
  ),
1410
1415
  api,
1411
1416
  ]),
@@ -1605,7 +1610,7 @@ export const createRoot = (
1605
1610
  const updateConditionalElements = () => {
1606
1611
  const displayedNodes: string[] = []
1607
1612
  if (selectedNodeId && component) {
1608
- const root = component.nodes.root
1613
+ const root = component.nodes?.root
1609
1614
  if (root) {
1610
1615
  const nodeLookup = getNodeAndAncestors(component, root, selectedNodeId)
1611
1616
  if (isNodeOrAncestorConditional(nodeLookup)) {
@@ -1721,7 +1726,7 @@ function getNodeId(component: Component, path: string[]) {
1721
1726
  if (nextChild === undefined || currentId === undefined) {
1722
1727
  return currentId ?? null
1723
1728
  }
1724
- const currentNode = component.nodes[currentId]
1729
+ const currentNode = component.nodes?.[currentId]
1725
1730
  if (!currentNode?.children) {
1726
1731
  return null
1727
1732
  }
package/src/page.main.ts CHANGED
@@ -162,7 +162,7 @@ export const createRoot = (domNode: HTMLElement) => {
162
162
  ...window.toddle.pageState,
163
163
  // Re-initialize variables since some of them might rely on client-side
164
164
  // state (e.g. localStorage, sensors etc.)
165
- Variables: mapObject(component.variables, ([name, variable]) => [
165
+ Variables: mapObject(component.variables ?? {}, ([name, variable]) => [
166
166
  name,
167
167
  applyFormula(variable.initialValue, {
168
168
  data: window.toddle.pageState,
@@ -213,17 +213,19 @@ export const createRoot = (domNode: HTMLElement) => {
213
213
  }
214
214
 
215
215
  // Note: this function must run procedurally to ensure apis (which are in correct order) can reference each other
216
- sortApiObjects(Object.entries(component.apis)).forEach(([name, api]) => {
217
- if (isLegacyApi(api)) {
218
- ctx.apis[name] = createLegacyAPI(api, ctx)
219
- } else {
220
- ctx.apis[name] = createAPI({
221
- apiRequest: api,
222
- ctx,
223
- componentData: dataSignal.get(),
224
- })
225
- }
226
- })
216
+ sortApiObjects(Object.entries(component.apis ?? {})).forEach(
217
+ ([name, api]) => {
218
+ if (isLegacyApi(api)) {
219
+ ctx.apis[name] = createLegacyAPI(api, ctx)
220
+ } else {
221
+ ctx.apis[name] = createAPI({
222
+ apiRequest: api,
223
+ ctx,
224
+ componentData: dataSignal.get(),
225
+ })
226
+ }
227
+ },
228
+ )
227
229
  // Trigger actions for all APIs after all of them are created.
228
230
  Object.values(ctx.apis)
229
231
  .filter(isContextApiV2)
@@ -1,4 +1,5 @@
1
1
  import type { MediaQuery } from '@nordcraft/core/dist/component/component.types'
2
+ import type { Nullable } from '@nordcraft/core/dist/types'
2
3
 
3
4
  /**
4
5
  * CustomPropertyStyleSheet is a utility class that manages CSS custom properties
@@ -15,7 +16,10 @@ export class CustomPropertyStyleSheet {
15
16
  // Selector to rule index mapping
16
17
  private ruleMap: Map<string, CSSStyleRule | CSSNestedDeclarations> | undefined
17
18
 
18
- constructor(root: Document | ShadowRoot, styleSheet?: CSSStyleSheet | null) {
19
+ constructor(
20
+ root: Document | ShadowRoot,
21
+ styleSheet?: Nullable<CSSStyleSheet>,
22
+ ) {
19
23
  if (styleSheet) {
20
24
  this.styleSheet = styleSheet
21
25
  } else {
@@ -30,10 +34,10 @@ export class CustomPropertyStyleSheet {
30
34
  public registerProperty(
31
35
  selector: string,
32
36
  name: string,
33
- options?: {
34
- mediaQuery?: MediaQuery
35
- startingStyle?: boolean
36
- },
37
+ options?: Nullable<{
38
+ mediaQuery?: Nullable<MediaQuery>
39
+ startingStyle?: Nullable<boolean>
40
+ }>,
37
41
  ): (newValue: string) => void {
38
42
  this.ruleMap ??= this.hydrateFromBase()
39
43
  const fullSelector = CustomPropertyStyleSheet.getFullSelector(
@@ -69,11 +73,11 @@ export class CustomPropertyStyleSheet {
69
73
  public unregisterProperty(
70
74
  selector: string,
71
75
  name: string,
72
- options?: {
73
- mediaQuery?: MediaQuery
74
- startingStyle?: boolean
75
- deepClean?: boolean
76
- },
76
+ options?: Nullable<{
77
+ mediaQuery?: Nullable<MediaQuery>
78
+ startingStyle?: Nullable<boolean>
79
+ deepClean?: Nullable<boolean>
80
+ }>,
77
81
  ): void {
78
82
  if (!this.ruleMap) {
79
83
  return
@@ -161,10 +165,10 @@ export class CustomPropertyStyleSheet {
161
165
 
162
166
  private static getFullSelector(
163
167
  selector: string,
164
- options?: {
165
- mediaQuery?: MediaQuery
166
- startingStyle?: boolean
167
- },
168
+ options?: Nullable<{
169
+ mediaQuery?: Nullable<MediaQuery>
170
+ startingStyle?: Nullable<boolean>
171
+ }>,
168
172
  ) {
169
173
  let result =
170
174
  selector + (options?.startingStyle ? ' { @starting-style { }}' : ' { }')
@@ -38,7 +38,7 @@ export const getNodeAndAncestors = (
38
38
  nodeId: path.slice(0, i + 1).join('.'),
39
39
  })
40
40
  }
41
- return component.nodes[node.children[childIndex]]
41
+ return component.nodes?.[node.children[childIndex]]
42
42
  default:
43
43
  return undefined
44
44
  }