@builder.io/sdk-svelte 0.1.1 → 0.1.3-0

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 (90) hide show
  1. package/package/--package.json +3 -3
  2. package/package/CHANGELOG.md +9 -0
  3. package/package/blocks/BaseText.svelte +1 -1
  4. package/package/blocks/button/button.svelte +1 -1
  5. package/package/blocks/columns/columns.svelte +3 -3
  6. package/package/blocks/custom-code/custom-code.svelte +1 -1
  7. package/package/blocks/embed/embed.svelte +2 -3
  8. package/package/blocks/form/form.svelte +1 -1
  9. package/package/blocks/fragment/fragment.svelte +1 -1
  10. package/package/blocks/image/image.svelte +1 -2
  11. package/package/blocks/img/img.svelte +1 -1
  12. package/package/blocks/input/input.svelte +1 -1
  13. package/package/blocks/raw-text/raw-text.svelte +1 -1
  14. package/package/blocks/section/section.svelte +1 -1
  15. package/package/blocks/select/select.svelte +1 -1
  16. package/package/blocks/submit-button/submit-button.svelte +1 -1
  17. package/package/blocks/symbol/symbol.svelte +4 -2
  18. package/package/blocks/text/text.svelte +1 -1
  19. package/package/blocks/textarea/textarea.svelte +1 -1
  20. package/package/blocks/video/video.svelte +1 -1
  21. package/package/components/render-block/block-styles.svelte +1 -1
  22. package/package/components/render-block/render-block.helpers.d.ts +11 -0
  23. package/package/components/render-block/render-block.helpers.js +58 -0
  24. package/package/components/render-block/render-block.svelte +33 -109
  25. package/package/components/render-block/render-component.svelte +1 -1
  26. package/package/components/render-block/render-repeated-block.svelte +7 -19
  27. package/package/components/render-blocks.svelte +1 -1
  28. package/package/components/render-content/builder-editing.svelte +1 -1
  29. package/package/components/render-content/components/render-styles.svelte +3 -3
  30. package/package/components/render-content/render-content.svelte +53 -53
  31. package/package/components/render-inlined-styles.svelte +1 -1
  32. package/package/functions/track/helpers.d.ts +5 -0
  33. package/package/functions/track/helpers.js +56 -0
  34. package/package/functions/{track.d.ts → track/index.d.ts} +5 -10
  35. package/package/functions/{track.js → track/index.js} +11 -6
  36. package/package/helpers/ab-tests.d.ts +1 -1
  37. package/package/helpers/cookie.d.ts +1 -1
  38. package/package/helpers/cookie.js +7 -2
  39. package/package/helpers/localStorage.d.ts +2 -1
  40. package/package/helpers/localStorage.js +1 -0
  41. package/package/helpers/sessionId.d.ts +2 -2
  42. package/package/helpers/sessionId.js +2 -1
  43. package/package/helpers/url.js +3 -0
  44. package/package/helpers/url.test.js +6 -0
  45. package/package/helpers/visitorId.js +1 -0
  46. package/package/index.d.ts +1 -1
  47. package/package/index.js +1 -1
  48. package/package.json +1 -1
  49. package/src/blocks/BaseText.svelte +2 -2
  50. package/src/blocks/button/button.svelte +1 -6
  51. package/src/blocks/columns/columns.svelte +3 -3
  52. package/src/blocks/custom-code/custom-code.svelte +1 -1
  53. package/src/blocks/embed/component-info.ts +29 -27
  54. package/src/blocks/embed/embed.svelte +1 -3
  55. package/src/blocks/form/form.svelte +2 -7
  56. package/src/blocks/fragment/fragment.svelte +1 -1
  57. package/src/blocks/image/component-info.ts +57 -55
  58. package/src/blocks/image/image.svelte +1 -2
  59. package/src/blocks/img/img.svelte +1 -6
  60. package/src/blocks/input/input.svelte +1 -6
  61. package/src/blocks/raw-text/raw-text.svelte +1 -1
  62. package/src/blocks/section/section.svelte +1 -6
  63. package/src/blocks/select/select.svelte +1 -6
  64. package/src/blocks/submit-button/submit-button.svelte +1 -6
  65. package/src/blocks/symbol/symbol.svelte +5 -8
  66. package/src/blocks/text/text.svelte +1 -1
  67. package/src/blocks/textarea/textarea.svelte +1 -6
  68. package/src/blocks/video/video.svelte +1 -6
  69. package/src/components/render-block/block-styles.svelte +1 -1
  70. package/src/components/render-block/render-block.helpers.ts +85 -0
  71. package/src/components/render-block/render-block.svelte +41 -118
  72. package/src/components/render-block/render-component.svelte +1 -1
  73. package/src/components/render-block/render-repeated-block.svelte +8 -20
  74. package/src/components/render-blocks.svelte +2 -2
  75. package/src/components/render-content/builder-editing.svelte +1 -1
  76. package/src/components/render-content/components/render-styles.svelte +5 -3
  77. package/src/components/render-content/render-content.svelte +59 -64
  78. package/src/components/render-inlined-styles.svelte +1 -1
  79. package/src/functions/track/helpers.ts +67 -0
  80. package/src/functions/{track.ts → track/index.ts} +16 -17
  81. package/src/helpers/cookie.ts +9 -4
  82. package/src/helpers/localStorage.ts +3 -1
  83. package/src/helpers/sessionId.ts +5 -1
  84. package/src/helpers/url.test.ts +7 -0
  85. package/src/helpers/url.ts +4 -0
  86. package/src/helpers/visitorId.ts +3 -1
  87. package/src/index.ts +1 -1
  88. package/package/components/render-block/render-component-with-context.svelte +0 -32
  89. package/package/components/render-block/render-component-with-context.svelte.d.ts +0 -19
  90. package/src/components/render-block/render-component-with-context.svelte +0 -38
@@ -58,7 +58,7 @@
58
58
  </script>
59
59
 
60
60
  <script lang="ts">
61
- import { getContext, setContext } from "svelte";
61
+ import { getContext } from "svelte";
62
62
 
63
63
  import RenderBlock from "../../components/render-block/render-block.svelte";
64
64
  import BuilderBlocks from "../../components/render-blocks.svelte";
@@ -66,7 +66,6 @@
66
66
 
67
67
  const isEvent = (attr) => attr.startsWith("on:");
68
68
  const isNonEvent = (attr) => !attr.startsWith("on:");
69
-
70
69
  const filterAttrs = (attrs, filter) => {
71
70
  const validAttr = {};
72
71
  Object.keys(attrs).forEach((attr) => {
@@ -76,16 +75,12 @@
76
75
  });
77
76
  return validAttr;
78
77
  };
79
-
80
78
  const setAttrs = (node, attrs) => {
81
79
  const attrKeys = Object.keys(attrs);
82
-
83
80
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
84
81
  const teardown = (attr) =>
85
82
  node.removeEventListener(attr.substr(3), attrs[attr]);
86
-
87
83
  attrKeys.map(setup);
88
-
89
84
  return {
90
85
  update(attrs) {
91
86
  const attrKeys = Object.keys(attrs);
@@ -364,4 +359,4 @@
364
359
  color: red;
365
360
  text-align: center;
366
361
  }
367
- </style>
362
+ </style>
@@ -9,4 +9,4 @@
9
9
  <script lang="ts">
10
10
  </script>
11
11
 
12
- <span><slot /></span>
12
+ <span><slot /></span>
@@ -23,69 +23,71 @@ export const componentInfo: ComponentInfo = {
23
23
  required: true,
24
24
  defaultValue:
25
25
  'https://cdn.builder.io/api/v1/image/assets%2Fpwgjf0RoYWbdnJSbpBAjXNRMe9F2%2Ffb27a7c790324294af8be1c35fe30f4d',
26
- onChange: serializeFn((options: Map<string, any>) => {
27
- const DEFAULT_ASPECT_RATIO = 0.7041;
28
- options.delete('srcset');
29
- options.delete('noWebp');
30
- function loadImage(
31
- url: string,
32
- timeout = 60000
33
- ): Promise<HTMLImageElement> {
34
- return new Promise((resolve, reject) => {
35
- const img = document.createElement('img');
36
- let loaded = false;
37
- img.onload = () => {
38
- loaded = true;
39
- resolve(img);
40
- };
26
+ onChange: serializeFn(
27
+ (options: Map<string, any>): void | Promise<void> => {
28
+ const DEFAULT_ASPECT_RATIO = 0.7041;
29
+ options.delete('srcset');
30
+ options.delete('noWebp');
31
+ function loadImage(
32
+ url: string,
33
+ timeout = 60000
34
+ ): Promise<HTMLImageElement> {
35
+ return new Promise((resolve, reject) => {
36
+ const img = document.createElement('img');
37
+ let loaded = false;
38
+ img.onload = () => {
39
+ loaded = true;
40
+ resolve(img);
41
+ };
41
42
 
42
- img.addEventListener('error', (event) => {
43
- console.warn('Image load failed', event.error);
44
- reject(event.error);
45
- });
43
+ img.addEventListener('error', (event) => {
44
+ console.warn('Image load failed', event.error);
45
+ reject(event.error);
46
+ });
46
47
 
47
- img.src = url;
48
- setTimeout(() => {
49
- if (!loaded) {
50
- reject(new Error('Image load timed out'));
51
- }
52
- }, timeout);
53
- });
54
- }
48
+ img.src = url;
49
+ setTimeout(() => {
50
+ if (!loaded) {
51
+ reject(new Error('Image load timed out'));
52
+ }
53
+ }, timeout);
54
+ });
55
+ }
55
56
 
56
- function round(num: number) {
57
- return Math.round(num * 1000) / 1000;
58
- }
57
+ function round(num: number) {
58
+ return Math.round(num * 1000) / 1000;
59
+ }
59
60
 
60
- const value = options.get('image');
61
- const aspectRatio = options.get('aspectRatio');
61
+ const value = options.get('image');
62
+ const aspectRatio = options.get('aspectRatio');
62
63
 
63
- // For SVG images - don't render as webp, keep them as SVG
64
- fetch(value)
65
- .then((res) => res.blob())
66
- .then((blob) => {
67
- if (blob.type.includes('svg')) {
68
- options.set('noWebp', true);
69
- }
70
- });
64
+ // For SVG images - don't render as webp, keep them as SVG
65
+ fetch(value)
66
+ .then((res) => res.blob())
67
+ .then((blob) => {
68
+ if (blob.type.includes('svg')) {
69
+ options.set('noWebp', true);
70
+ }
71
+ });
71
72
 
72
- if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) {
73
- return loadImage(value).then((img) => {
74
- const possiblyUpdatedAspectRatio = options.get('aspectRatio');
75
- if (
76
- options.get('image') === value &&
77
- (!possiblyUpdatedAspectRatio ||
78
- possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO)
79
- ) {
80
- if (img.width && img.height) {
81
- options.set('aspectRatio', round(img.height / img.width));
82
- options.set('height', img.height);
83
- options.set('width', img.width);
73
+ if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) {
74
+ return loadImage(value).then((img) => {
75
+ const possiblyUpdatedAspectRatio = options.get('aspectRatio');
76
+ if (
77
+ options.get('image') === value &&
78
+ (!possiblyUpdatedAspectRatio ||
79
+ possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO)
80
+ ) {
81
+ if (img.width && img.height) {
82
+ options.set('aspectRatio', round(img.height / img.width));
83
+ options.set('height', img.height);
84
+ options.set('width', img.width);
85
+ }
84
86
  }
85
- }
86
- });
87
+ });
88
+ }
87
89
  }
88
- }),
90
+ ),
89
91
  },
90
92
  {
91
93
  name: 'backgroundSize',
@@ -106,7 +106,6 @@
106
106
  srcset={srcSetToUse()}
107
107
  {sizes}
108
108
  />
109
- <source srcset={srcSetToUse()} />
110
109
  </picture>
111
110
 
112
111
  {#if aspectRatio && !(builderBlock?.children?.length && fitContent)}
@@ -150,4 +149,4 @@
150
149
  width: 100%;
151
150
  height: 100%;
152
151
  }
153
- </style>
152
+ </style>
@@ -23,7 +23,6 @@
23
23
 
24
24
  const isEvent = (attr) => attr.startsWith("on:");
25
25
  const isNonEvent = (attr) => !attr.startsWith("on:");
26
-
27
26
  const filterAttrs = (attrs, filter) => {
28
27
  const validAttr = {};
29
28
  Object.keys(attrs).forEach((attr) => {
@@ -33,16 +32,12 @@
33
32
  });
34
33
  return validAttr;
35
34
  };
36
-
37
35
  const setAttrs = (node, attrs) => {
38
36
  const attrKeys = Object.keys(attrs);
39
-
40
37
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
41
38
  const teardown = (attr) =>
42
39
  node.removeEventListener(attr.substr(3), attrs[attr]);
43
-
44
40
  attrKeys.map(setup);
45
-
46
41
  return {
47
42
  update(attrs) {
48
43
  const attrKeys = Object.keys(attrs);
@@ -83,4 +78,4 @@
83
78
  src={imgSrc || image}
84
79
  {...filterAttrs(attributes, isNonEvent)}
85
80
  use:setAttrs={filterAttrs(attributes, isEvent)}
86
- />
81
+ />
@@ -15,7 +15,6 @@
15
15
 
16
16
  const isEvent = (attr) => attr.startsWith("on:");
17
17
  const isNonEvent = (attr) => !attr.startsWith("on:");
18
-
19
18
  const filterAttrs = (attrs, filter) => {
20
19
  const validAttr = {};
21
20
  Object.keys(attrs).forEach((attr) => {
@@ -25,16 +24,12 @@
25
24
  });
26
25
  return validAttr;
27
26
  };
28
-
29
27
  const setAttrs = (node, attrs) => {
30
28
  const attrKeys = Object.keys(attrs);
31
-
32
29
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
33
30
  const teardown = (attr) =>
34
31
  node.removeEventListener(attr.substr(3), attrs[attr]);
35
-
36
32
  attrKeys.map(setup);
37
-
38
33
  return {
39
34
  update(attrs) {
40
35
  const attrKeys = Object.keys(attrs);
@@ -66,4 +61,4 @@
66
61
  {defaultValue}
67
62
  {required}
68
63
  use:setAttrs={filterAttrs(attributes, isEvent)}
69
- />
64
+ />
@@ -13,4 +13,4 @@
13
13
 
14
14
  <span class={attributes?.class || attributes?.className}
15
15
  >{@html text || ""}</span
16
- >
16
+ >
@@ -10,7 +10,6 @@
10
10
  <script lang="ts">
11
11
  const isEvent = (attr) => attr.startsWith("on:");
12
12
  const isNonEvent = (attr) => !attr.startsWith("on:");
13
-
14
13
  const filterAttrs = (attrs, filter) => {
15
14
  const validAttr = {};
16
15
  Object.keys(attrs).forEach((attr) => {
@@ -20,16 +19,12 @@
20
19
  });
21
20
  return validAttr;
22
21
  };
23
-
24
22
  const setAttrs = (node, attrs) => {
25
23
  const attrKeys = Object.keys(attrs);
26
-
27
24
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
28
25
  const teardown = (attr) =>
29
26
  node.removeEventListener(attr.substr(3), attrs[attr]);
30
-
31
27
  attrKeys.map(setup);
32
-
33
28
  return {
34
29
  update(attrs) {
35
30
  const attrKeys = Object.keys(attrs);
@@ -73,4 +68,4 @@
73
68
  use:setAttrs={filterAttrs(attributes, isEvent)}
74
69
  >
75
70
  <slot />
76
- </section>
71
+ </section>
@@ -16,7 +16,6 @@
16
16
 
17
17
  const isEvent = (attr) => attr.startsWith("on:");
18
18
  const isNonEvent = (attr) => !attr.startsWith("on:");
19
-
20
19
  const filterAttrs = (attrs, filter) => {
21
20
  const validAttr = {};
22
21
  Object.keys(attrs).forEach((attr) => {
@@ -26,16 +25,12 @@
26
25
  });
27
26
  return validAttr;
28
27
  };
29
-
30
28
  const setAttrs = (node, attrs) => {
31
29
  const attrKeys = Object.keys(attrs);
32
-
33
30
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
34
31
  const teardown = (attr) =>
35
32
  node.removeEventListener(attr.substr(3), attrs[attr]);
36
-
37
33
  attrKeys.map(setup);
38
-
39
34
  return {
40
35
  update(attrs) {
41
36
  const attrKeys = Object.keys(attrs);
@@ -66,4 +61,4 @@
66
61
  {#each options as option}
67
62
  <option value={option.value}>{option.name || option.value}</option>
68
63
  {/each}
69
- </select>
64
+ </select>
@@ -8,7 +8,6 @@
8
8
  <script lang="ts">
9
9
  const isEvent = (attr) => attr.startsWith("on:");
10
10
  const isNonEvent = (attr) => !attr.startsWith("on:");
11
-
12
11
  const filterAttrs = (attrs, filter) => {
13
12
  const validAttr = {};
14
13
  Object.keys(attrs).forEach((attr) => {
@@ -18,16 +17,12 @@
18
17
  });
19
18
  return validAttr;
20
19
  };
21
-
22
20
  const setAttrs = (node, attrs) => {
23
21
  const attrKeys = Object.keys(attrs);
24
-
25
22
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
26
23
  const teardown = (attr) =>
27
24
  node.removeEventListener(attr.substr(3), attrs[attr]);
28
-
29
25
  attrKeys.map(setup);
30
-
31
26
  return {
32
27
  update(attrs) {
33
28
  const attrKeys = Object.keys(attrs);
@@ -50,4 +45,4 @@
50
45
  use:setAttrs={filterAttrs(attributes, isEvent)}
51
46
  >
52
47
  {text}
53
- </button>
48
+ </button>
@@ -25,7 +25,7 @@
25
25
  </script>
26
26
 
27
27
  <script lang="ts">
28
- import { afterUpdate, getContext, setContext } from "svelte";
28
+ import { getContext } from "svelte";
29
29
 
30
30
  import RenderContent from "../../components/render-content/render-content.svelte";
31
31
  import BuilderContext from "../../context/builder.context.js";
@@ -34,7 +34,6 @@
34
34
 
35
35
  const isEvent = (attr) => attr.startsWith("on:");
36
36
  const isNonEvent = (attr) => !attr.startsWith("on:");
37
-
38
37
  const filterAttrs = (attrs, filter) => {
39
38
  const validAttr = {};
40
39
  Object.keys(attrs).forEach((attr) => {
@@ -44,16 +43,12 @@
44
43
  });
45
44
  return validAttr;
46
45
  };
47
-
48
46
  const setAttrs = (node, attrs) => {
49
47
  const attrKeys = Object.keys(attrs);
50
-
51
48
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
52
49
  const teardown = (attr) =>
53
50
  node.removeEventListener(attr.substr(3), attrs[attr]);
54
-
55
51
  attrKeys.map(setup);
56
-
57
52
  return {
58
53
  update(attrs) {
59
54
  const attrKeys = Object.keys(attrs);
@@ -106,7 +101,9 @@
106
101
  symbolToUse &&
107
102
  !symbolToUse.content &&
108
103
  !fetchedContent &&
109
- symbolToUse.model
104
+ symbolToUse.model &&
105
+ // This is a hack, we should not need to check for this, but it is needed for Svelte.
106
+ builderContext?.apiKey
110
107
  ) {
111
108
  getContent({
112
109
  model: symbolToUse.model,
@@ -142,4 +139,4 @@
142
139
  model={symbol?.model}
143
140
  content={contentToUse()}
144
141
  />
145
- </div>
142
+ </div>
@@ -8,4 +8,4 @@
8
8
  export let text: TextProps["text"];
9
9
  </script>
10
10
 
11
- <span class="builder-text">{@html text}</span>
11
+ <span class="builder-text">{@html text}</span>
@@ -11,7 +11,6 @@
11
11
  <script lang="ts">
12
12
  const isEvent = (attr) => attr.startsWith("on:");
13
13
  const isNonEvent = (attr) => !attr.startsWith("on:");
14
-
15
14
  const filterAttrs = (attrs, filter) => {
16
15
  const validAttr = {};
17
16
  Object.keys(attrs).forEach((attr) => {
@@ -21,16 +20,12 @@
21
20
  });
22
21
  return validAttr;
23
22
  };
24
-
25
23
  const setAttrs = (node, attrs) => {
26
24
  const attrKeys = Object.keys(attrs);
27
-
28
25
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
29
26
  const teardown = (attr) =>
30
27
  node.removeEventListener(attr.substr(3), attrs[attr]);
31
-
32
28
  attrKeys.map(setup);
33
-
34
29
  return {
35
30
  update(attrs) {
36
31
  const attrKeys = Object.keys(attrs);
@@ -57,4 +52,4 @@
57
52
  {value}
58
53
  {defaultValue}
59
54
  use:setAttrs={filterAttrs(attributes, isEvent)}
60
- />
55
+ />
@@ -29,7 +29,6 @@
29
29
  <script lang="ts">
30
30
  const isEvent = (attr) => attr.startsWith("on:");
31
31
  const isNonEvent = (attr) => !attr.startsWith("on:");
32
-
33
32
  const filterAttrs = (attrs, filter) => {
34
33
  const validAttr = {};
35
34
  Object.keys(attrs).forEach((attr) => {
@@ -39,16 +38,12 @@
39
38
  });
40
39
  return validAttr;
41
40
  };
42
-
43
41
  const setAttrs = (node, attrs) => {
44
42
  const attrKeys = Object.keys(attrs);
45
-
46
43
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
47
44
  const teardown = (attr) =>
48
45
  node.removeEventListener(attr.substr(3), attrs[attr]);
49
-
50
46
  attrKeys.map(setup);
51
-
52
47
  return {
53
48
  update(attrs) {
54
49
  const attrKeys = Object.keys(attrs);
@@ -134,4 +129,4 @@
134
129
  src={video || "no-src"}
135
130
  poster={posterImage}
136
131
  use:setAttrs={filterAttrs(spreadProps(), isEvent)}
137
- />
132
+ />
@@ -72,4 +72,4 @@
72
72
 
73
73
  {#if TARGET !== "reactNative" && css()}
74
74
  <RenderInlinedStyles styles={css()} />
75
- {/if}
75
+ {/if}
@@ -1,3 +1,9 @@
1
+ import type { BuilderContextInterface } from '../../context/types';
2
+ import { evaluate } from '../../functions/evaluate';
3
+ import { getProcessedBlock } from '../../functions/get-processed-block';
4
+ import type { BuilderBlock } from '../../types/builder-block';
5
+ import type { RepeatData } from './types';
6
+
1
7
  /**
2
8
  * https://developer.mozilla.org/en-US/docs/Glossary/Empty_element
3
9
  */
@@ -25,3 +31,82 @@ export const isEmptyHtmlElement = (tagName: unknown) => {
25
31
  EMPTY_HTML_ELEMENTS.includes(tagName.toLowerCase())
26
32
  );
27
33
  };
34
+
35
+ export const getComponent = ({
36
+ block,
37
+ context,
38
+ }: {
39
+ block: BuilderBlock;
40
+ context: BuilderContextInterface;
41
+ }) => {
42
+ const componentName = getProcessedBlock({
43
+ block: block,
44
+ state: context.state,
45
+ context: context.context,
46
+ shouldEvaluateBindings: false,
47
+ }).component?.name;
48
+
49
+ if (!componentName) {
50
+ return null;
51
+ }
52
+
53
+ const ref = context.registeredComponents[componentName];
54
+
55
+ if (!ref) {
56
+ // TODO: Public doc page with more info about this message
57
+ console.warn(`
58
+ Could not find a registered component named "${componentName}".
59
+ If you registered it, is the file that registered it imported by the file that needs to render it?`);
60
+ return undefined;
61
+ } else {
62
+ return ref;
63
+ }
64
+ };
65
+
66
+ export const getRepeatItemData = ({
67
+ block,
68
+ context,
69
+ }: {
70
+ block: BuilderBlock;
71
+ context: BuilderContextInterface;
72
+ }): RepeatData[] | undefined => {
73
+ /**
74
+ * we don't use `state.useBlock` here because the processing done within its logic includes evaluating the block's bindings,
75
+ * which will not work if there is a repeat.
76
+ */
77
+ const { repeat, ...blockWithoutRepeat } = block;
78
+
79
+ if (!repeat?.collection) {
80
+ return undefined;
81
+ }
82
+
83
+ const itemsArray = evaluate({
84
+ code: repeat.collection,
85
+ state: context.state,
86
+ context: context.context,
87
+ });
88
+
89
+ if (!Array.isArray(itemsArray)) {
90
+ return undefined;
91
+ }
92
+
93
+ const collectionName = repeat.collection.split('.').pop();
94
+ const itemNameToUse =
95
+ repeat.itemName || (collectionName ? collectionName + 'Item' : 'item');
96
+
97
+ const repeatArray = itemsArray.map<RepeatData>((item, index) => ({
98
+ context: {
99
+ ...context,
100
+ state: {
101
+ ...context.state,
102
+ $index: index,
103
+ $item: item,
104
+ [itemNameToUse]: item,
105
+ [`$${itemNameToUse}Index`]: index,
106
+ },
107
+ },
108
+ block: blockWithoutRepeat,
109
+ }));
110
+
111
+ return repeatArray;
112
+ };