@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
@@ -1,17 +1,10 @@
1
1
  <script context="module" lang="ts">
2
- import type {
3
- BuilderContextInterface,
4
- RegisteredComponent,
5
- } from "../../context/types.js";
2
+ import type { BuilderContextInterface } from "../../context/types.js";
6
3
 
7
4
  import type { BuilderBlock } from "../../types/builder-block.js";
8
5
 
9
- import type { Nullable } from "../../types/typescript.js";
10
-
11
6
  import type { RenderComponentProps } from "./render-component";
12
7
 
13
- import type { RepeatData } from "./types.js";
14
-
15
8
  export type RenderBlockProps = {
16
9
  block: BuilderBlock;
17
10
  context: BuilderContextInterface;
@@ -24,25 +17,24 @@
24
17
  import { getBlockProperties } from "../../functions/get-block-properties.js";
25
18
  import { getBlockTag } from "../../functions/get-block-tag.js";
26
19
  import { getProcessedBlock } from "../../functions/get-processed-block.js";
27
- import { evaluate } from "../../functions/evaluate.js";
28
20
  import BlockStyles from "./block-styles.svelte";
29
- import { isEmptyHtmlElement } from "./render-block.helpers.js";
21
+ import {
22
+ getComponent,
23
+ getRepeatItemData,
24
+ isEmptyHtmlElement,
25
+ } from "./render-block.helpers.js";
30
26
  import RenderRepeatedBlock from "./render-repeated-block.svelte";
31
27
  import { TARGET } from "../../constants/target.js";
32
28
  import { extractTextStyles } from "../../functions/extract-text-styles.js";
33
- import RenderComponentWithContext from "./render-component-with-context.svelte";
34
29
  import RenderComponent from "./render-component.svelte";
35
30
  import { getReactNativeBlockStyles } from "../../functions/get-react-native-block-styles.js";
36
31
 
37
32
  const setAttrs = (node, attrs) => {
38
33
  const attrKeys = Object.keys(attrs);
39
-
40
34
  const setup = (attr) => node.addEventListener(attr.substr(3), attrs[attr]);
41
35
  const teardown = (attr) =>
42
36
  node.removeEventListener(attr.substr(3), attrs[attr]);
43
-
44
37
  attrKeys.map(setup);
45
-
46
38
  return {
47
39
  update(attrs) {
48
40
  const attrKeys = Object.keys(attrs);
@@ -58,32 +50,11 @@
58
50
  export let block: RenderBlockProps["block"];
59
51
  export let context: RenderBlockProps["context"];
60
52
 
61
- $: component = () => {
62
- const componentName = getProcessedBlock({
63
- block: block,
64
- state: context.state,
65
- context: context.context,
66
- shouldEvaluateBindings: false,
67
- }).component?.name;
68
- if (!componentName) {
69
- return null;
70
- }
71
- const ref = context.registeredComponents[componentName];
72
- if (!ref) {
73
- // TODO: Public doc page with more info about this message
74
- console.warn(`
75
- Could not find a registered component named "${componentName}".
76
- If you registered it, is the file that registered it imported by the file that needs to render it?`);
77
- return undefined;
78
- } else {
79
- return ref;
80
- }
81
- };
82
53
  $: tag = () => {
83
54
  return getBlockTag(useBlock());
84
55
  };
85
56
  $: useBlock = () => {
86
- return repeatItemData()
57
+ return repeatItemData
87
58
  ? block
88
59
  : getProcessedBlock({
89
60
  block: block,
@@ -114,20 +85,17 @@
114
85
  : {}),
115
86
  };
116
87
  };
117
- $: shouldWrap = () => {
118
- return !component?.()?.noWrap;
119
- };
120
88
  $: renderComponentProps = () => {
121
89
  return {
122
- blockChildren: useChildren(),
123
- componentRef: component?.()?.component,
90
+ blockChildren: useBlock().children ?? [],
91
+ componentRef: component?.component,
124
92
  componentOptions: {
125
93
  ...getBlockComponentOptions(useBlock()),
126
94
  /**
127
95
  * These attributes are passed to the wrapper element when there is one. If `noWrap` is set to true, then
128
96
  * they are provided to the component itself directly.
129
97
  */
130
- ...(shouldWrap()
98
+ ...(!component?.noWrap
131
99
  ? {}
132
100
  : {
133
101
  attributes: {
@@ -140,13 +108,6 @@
140
108
  context: childrenContext(),
141
109
  };
142
110
  };
143
- $: useChildren = () => {
144
- // TO-DO: When should `canHaveChildren` dictate rendering?
145
- // This is currently commented out because some Builder components (e.g. Box) do not have `canHaveChildren: true`,
146
- // but still receive and need to render children.
147
- // return componentInfo?.canHaveChildren ? useBlock().children : [];
148
- return useBlock().children ?? [];
149
- };
150
111
  $: childrenWithoutParentComponent = () => {
151
112
  /**
152
113
  * When there is no `componentRef`, there might still be children that need to be rendered. In this case,
@@ -155,94 +116,56 @@
155
116
  * blocks, and the children will be repeated within those blocks.
156
117
  */
157
118
  const shouldRenderChildrenOutsideRef =
158
- !component?.()?.component && !repeatItemData();
159
- return shouldRenderChildrenOutsideRef ? useChildren() : [];
160
- };
161
- $: repeatItemData = () => {
162
- /**
163
- * we don't use `useBlock()` here because the processing done within its logic includes evaluating the block's bindings,
164
- * which will not work if there is a repeat.
165
- */
166
- const { repeat, ...blockWithoutRepeat } = block;
167
- if (!repeat?.collection) {
168
- return undefined;
169
- }
170
- const itemsArray = evaluate({
171
- code: repeat.collection,
172
- state: context.state,
173
- context: context.context,
174
- });
175
- if (!Array.isArray(itemsArray)) {
176
- return undefined;
177
- }
178
- const collectionName = repeat.collection.split(".").pop();
179
- const itemNameToUse =
180
- repeat.itemName || (collectionName ? collectionName + "Item" : "item");
181
- const repeatArray = itemsArray.map((item, index) => ({
182
- context: {
183
- ...context,
184
- state: {
185
- ...context.state,
186
- $index: index,
187
- $item: item,
188
- [itemNameToUse]: item,
189
- [`$${itemNameToUse}Index`]: index,
190
- },
191
- },
192
- block: blockWithoutRepeat,
193
- }));
194
- return repeatArray;
195
- };
196
- $: inheritedTextStyles = () => {
197
- if (TARGET !== "reactNative") {
198
- return {};
199
- }
200
- const styles = getReactNativeBlockStyles({
201
- block: useBlock(),
202
- context: context,
203
- blockStyles: attributes().style,
204
- });
205
- return extractTextStyles(styles);
119
+ !component?.component && !repeatItemData;
120
+ return shouldRenderChildrenOutsideRef ? useBlock().children ?? [] : [];
206
121
  };
207
122
  $: childrenContext = () => {
123
+ const getInheritedTextStyles = () => {
124
+ if (TARGET !== "reactNative") {
125
+ return {};
126
+ }
127
+ return extractTextStyles(
128
+ getReactNativeBlockStyles({
129
+ block: useBlock(),
130
+ context: context,
131
+ blockStyles: attributes().style,
132
+ })
133
+ );
134
+ };
208
135
  return {
209
136
  apiKey: context.apiKey,
210
137
  state: context.state,
211
138
  content: context.content,
212
139
  context: context.context,
213
140
  registeredComponents: context.registeredComponents,
214
- inheritedStyles: inheritedTextStyles(),
141
+ inheritedStyles: getInheritedTextStyles(),
215
142
  };
216
143
  };
217
- $: renderComponentTag = () => {
218
- if (TARGET === "reactNative") {
219
- return RenderComponentWithContext;
220
- } else if (TARGET === "vue3") {
221
- // vue3 expects a string for the component tag
222
- return "RenderComponent";
223
- } else {
224
- return RenderComponent;
225
- }
226
- };
144
+
145
+ let component = getComponent({
146
+ block: block,
147
+ context: context,
148
+ });
149
+ let repeatItemData = getRepeatItemData({
150
+ block: block,
151
+ context: context,
152
+ });
227
153
  </script>
228
154
 
229
- {#if shouldWrap()}
155
+ {#if !component?.noWrap}
230
156
  {#if isEmptyHtmlElement(tag())}
231
157
  <svelte:element this={tag()} {...attributes()} use:setAttrs={actions()} />
232
158
  {/if}
233
159
 
234
- {#if !isEmptyHtmlElement(tag()) && repeatItemData()}
235
- {#each repeatItemData() as data, index (index)}
160
+ {#if !isEmptyHtmlElement(tag()) && repeatItemData}
161
+ {#each repeatItemData as data, index (index)}
236
162
  <RenderRepeatedBlock repeatContext={data.context} block={data.block} />
237
163
  {/each}
238
164
  {/if}
239
165
 
240
- {#if !isEmptyHtmlElement(tag()) && !repeatItemData()}
166
+ {#if !isEmptyHtmlElement(tag()) && !repeatItemData}
241
167
  <svelte:element this={tag()} {...attributes()} use:setAttrs={actions()}>
242
- <svelte:component
243
- this={renderComponentTag()}
244
- {...renderComponentProps()}
245
- />
168
+ <RenderComponent {...renderComponentProps()} />
246
169
 
247
170
  {#each childrenWithoutParentComponent() as child ("render-block-" + child.id)}
248
171
  <svelte:self block={child} context={childrenContext()} />
@@ -254,5 +177,5 @@
254
177
  </svelte:element>
255
178
  {/if}
256
179
  {:else}
257
- <svelte:component this={renderComponentTag()} {...renderComponentProps()} />
258
- {/if}
180
+ <RenderComponent {...renderComponentProps()} />
181
+ {/if}
@@ -34,4 +34,4 @@
34
34
  <BlockStyles block={child} {context} />
35
35
  {/each}
36
36
  </svelte:component>
37
- {/if}
37
+ {/if}
@@ -20,7 +20,7 @@
20
20
  </script>
21
21
 
22
22
  <script lang="ts">
23
- import { getContext, setContext } from "svelte";
23
+ import { setContext } from "svelte";
24
24
 
25
25
  import BuilderContext from "../../context/builder.context.js";
26
26
  import RenderBlock from "./render-block.svelte";
@@ -29,25 +29,13 @@
29
29
  export let repeatContext: Props["repeatContext"];
30
30
 
31
31
  setContext(BuilderContext.key, {
32
- get content() {
33
- return repeatContext.content;
34
- },
35
- get state() {
36
- return repeatContext.state;
37
- },
38
- get context() {
39
- return repeatContext.context;
40
- },
41
- get apiKey() {
42
- return repeatContext.apiKey;
43
- },
44
- get registeredComponents() {
45
- return repeatContext.registeredComponents;
46
- },
47
- get inheritedStyles() {
48
- return repeatContext.inheritedStyles;
49
- },
32
+ content: repeatContext.content,
33
+ state: repeatContext.state,
34
+ context: repeatContext.context,
35
+ apiKey: repeatContext.apiKey,
36
+ registeredComponents: repeatContext.registeredComponents,
37
+ inheritedStyles: repeatContext.inheritedStyles,
50
38
  });
51
39
  </script>
52
40
 
53
- <RenderBlock {block} context={repeatContext} />
41
+ <RenderBlock {block} context={repeatContext} />
@@ -10,7 +10,7 @@
10
10
  </script>
11
11
 
12
12
  <script lang="ts">
13
- import { getContext, setContext } from "svelte";
13
+ import { getContext } from "svelte";
14
14
 
15
15
  import BuilderContext from "../context/builder.context.js";
16
16
  import { isEditing } from "../functions/is-editing.js";
@@ -101,4 +101,4 @@
101
101
  flex-direction: column;
102
102
  align-items: stretch;
103
103
  }
104
- </style>
104
+ </style>
@@ -1,4 +1,4 @@
1
1
  <script lang="ts">
2
2
  </script>
3
3
 
4
- <div />
4
+ <div />
@@ -62,11 +62,13 @@
62
62
  }
63
63
  function getFontCss({ customFonts }) {
64
64
  // TODO: flag for this
65
- // if (!builder.allowCustomFonts) {
65
+ // if (!this.builder.allowCustomFonts) {
66
66
  // return '';
67
67
  // }
68
68
  // TODO: separate internal data from external
69
- return customFonts?.map((font) => getCssFromFont(font))?.join(" ") || "";
69
+ return (
70
+ customFonts?.map((font) => this.getCssFromFont(font))?.join(" ") || ""
71
+ );
70
72
  }
71
73
  $: injectedStyles = () => {
72
74
  return `
@@ -77,4 +79,4 @@ ${getFontCss({
77
79
  };
78
80
  </script>
79
81
 
80
- <RenderInlinedStyles styles={injectedStyles()} />
82
+ <RenderInlinedStyles styles={injectedStyles()} />
@@ -11,7 +11,7 @@
11
11
  BuilderContent,
12
12
  } from "../../types/builder-content.js";
13
13
 
14
- import type { Dictionary, Nullable } from "../../types/typescript.js";
14
+ import type { Nullable } from "../../types/typescript.js";
15
15
 
16
16
  export type RenderContentProps = {
17
17
  content?: Nullable<BuilderContent>;
@@ -41,13 +41,7 @@
41
41
  </script>
42
42
 
43
43
  <script lang="ts">
44
- import {
45
- afterUpdate,
46
- getContext,
47
- onDestroy,
48
- onMount,
49
- setContext,
50
- } from "svelte";
44
+ import { onDestroy, onMount, setContext } from "svelte";
51
45
 
52
46
  import { getDefaultRegisteredComponents } from "../../constants/builder-registered-components.js";
53
47
  import { TARGET } from "../../constants/target.js";
@@ -61,14 +55,15 @@
61
55
  components,
62
56
  createRegisterComponentMessage,
63
57
  } from "../../functions/register-component.js";
64
- import { _track } from "../../functions/track.js";
58
+ import { _track } from "../../functions/track/index.js";
65
59
  import RenderBlocks from "../render-blocks.svelte";
66
60
  import RenderContentStyles from "./components/render-styles.svelte";
67
- import BuilderContext from "../../context/builder.context.js";
61
+ import builderContext from "../../context/builder.context.js";
68
62
  import {
69
63
  registerInsertMenu,
70
64
  setupBrowserForEditing,
71
65
  } from "../../scripts/init-editing.js";
66
+ import { checkIsDefined } from "../../helpers/nullable.js";
72
67
 
73
68
  export let content: RenderContentProps["content"];
74
69
  export let data: RenderContentProps["data"];
@@ -80,7 +75,7 @@
80
75
  export let apiKey: RenderContentProps["apiKey"];
81
76
  export let includeRefs: RenderContentProps["includeRefs"];
82
77
 
83
- setContext(BuilderContext.key, {
78
+ setContext(builderContext.key, {
84
79
  get content() {
85
80
  return useContent();
86
81
  },
@@ -88,13 +83,13 @@
88
83
  return contentState();
89
84
  },
90
85
  get context() {
91
- return contextContext();
86
+ return contextContext;
92
87
  },
93
88
  get apiKey() {
94
89
  return apiKey;
95
90
  },
96
91
  get registeredComponents() {
97
- return allRegisteredComponents();
92
+ return allRegisteredComponents;
98
93
  },
99
94
  });
100
95
 
@@ -140,7 +135,7 @@
140
135
  if (jsCode) {
141
136
  evaluate({
142
137
  code: jsCode,
143
- context: contextContext(),
138
+ context: contextContext,
144
139
  state: contentState(),
145
140
  });
146
141
  }
@@ -151,7 +146,7 @@
151
146
  const contentId = useContent?.()?.id;
152
147
  _track({
153
148
  type: "click",
154
- canTrack: canTrackToUse(),
149
+ canTrack: canTrackToUse,
155
150
  contentId,
156
151
  apiKey: apiKey,
157
152
  variationId: variationId !== contentId ? variationId : undefined,
@@ -162,7 +157,7 @@
162
157
  return expression.replace(/{{([^}]+)}}/g, (_match, group) =>
163
158
  evaluate({
164
159
  code: group,
165
- context: contextContext(),
160
+ context: contextContext,
166
161
  state: contentState(),
167
162
  })
168
163
  );
@@ -184,7 +179,7 @@
184
179
  function runHttpRequests() {
185
180
  const requests = useContent?.()?.data?.httpRequests ?? {};
186
181
  Object.entries(requests).forEach(([key, url]) => {
187
- if (url && (!httpReqsData()[key] || isEditing())) {
182
+ if (url && (!httpReqsData[key] || isEditing())) {
188
183
  const evaluatedUrl = evalExpression(url);
189
184
  handleRequest({
190
185
  url: evaluatedUrl,
@@ -211,7 +206,7 @@
211
206
  if (!content && !overrideContent) {
212
207
  return undefined;
213
208
  }
214
- const mergedContent = {
209
+ return {
215
210
  ...content,
216
211
  ...overrideContent,
217
212
  data: {
@@ -228,10 +223,6 @@
228
223
  content?.meta?.breakpoints,
229
224
  },
230
225
  };
231
- return mergedContent;
232
- };
233
- $: canTrackToUse = () => {
234
- return canTrack || true;
235
226
  };
236
227
  $: contentState = () => {
237
228
  return {
@@ -245,32 +236,6 @@
245
236
  ...overrideState,
246
237
  };
247
238
  };
248
- $: contextContext = () => {
249
- return context || {};
250
- };
251
- $: allRegisteredComponents = () => {
252
- const allComponentsArray = [
253
- ...getDefaultRegisteredComponents(),
254
- // While this `components` object is deprecated, we must maintain support for it.
255
- // Since users are able to override our default components, we need to make sure that we do not break such
256
- // existing usage.
257
- // This is why we spread `components` after the default Builder.io components, but before the `customComponents`,
258
- // which is the new standard way of providing custom components, and must therefore take precedence.
259
- ...components,
260
- ...(customComponents || []),
261
- ];
262
- const allComponents = allComponentsArray.reduce(
263
- (acc, curr) => ({
264
- ...acc,
265
- [curr.name]: curr,
266
- }),
267
- {}
268
- );
269
- return allComponents;
270
- };
271
- $: httpReqsData = () => {
272
- return {};
273
- };
274
239
  $: shouldRenderContentStyles = () => {
275
240
  return Boolean(
276
241
  (useContent?.()?.data?.cssCode ||
@@ -285,7 +250,26 @@
285
250
  let overrideContent = null;
286
251
  let update = 0;
287
252
  let useBreakpoints = null;
253
+ let canTrackToUse = checkIsDefined(canTrack) ? canTrack : true;
288
254
  let overrideState = {};
255
+ let contextContext = context || {};
256
+ let allRegisteredComponents = [
257
+ ...getDefaultRegisteredComponents(),
258
+ // While this `components` object is deprecated, we must maintain support for it.
259
+ // Since users are able to override our default components, we need to make sure that we do not break such
260
+ // existing usage.
261
+ // This is why we spread `components` after the default Builder.io components, but before the `props.customComponents`,
262
+ // which is the new standard way of providing custom components, and must therefore take precedence.
263
+ ...components,
264
+ ...(customComponents || []),
265
+ ].reduce(
266
+ (acc, curr) => ({
267
+ ...acc,
268
+ [curr.name]: curr,
269
+ }),
270
+ {}
271
+ );
272
+ let httpReqsData = {};
289
273
 
290
274
  onMount(() => {
291
275
  if (!apiKey) {
@@ -309,7 +293,7 @@
309
293
  }
310
294
  : {}),
311
295
  });
312
- Object.values(allRegisteredComponents()).forEach(
296
+ Object.values(allRegisteredComponents).forEach(
313
297
  (registeredComponent) => {
314
298
  const message = createRegisterComponentMessage(registeredComponent);
315
299
  window.parent?.postMessage(message, "*");
@@ -326,7 +310,7 @@
326
310
  const contentId = useContent?.()?.id;
327
311
  _track({
328
312
  type: "impression",
329
- canTrack: canTrackToUse(),
313
+ canTrack: canTrackToUse,
330
314
  contentId,
331
315
  apiKey: apiKey,
332
316
  variationId: variationId !== contentId ? variationId : undefined,
@@ -336,19 +320,30 @@
336
320
  // override normal content in preview mode
337
321
  if (isPreviewing()) {
338
322
  const searchParams = new URL(location.href).searchParams;
339
- if (model && searchParams.get("builder.preview") === model) {
340
- const previewApiKey =
341
- searchParams.get("apiKey") || searchParams.get("builder.space");
342
- if (previewApiKey) {
343
- getContent({
344
- model: model,
345
- apiKey: previewApiKey,
346
- }).then((content) => {
347
- if (content) {
348
- overrideContent = content;
349
- }
350
- });
351
- }
323
+ const searchParamPreview = searchParams.get("builder.preview");
324
+ const previewApiKey =
325
+ searchParams.get("apiKey") || searchParams.get("builder.space");
326
+
327
+ /**
328
+ * Make sure that:
329
+ * - the preview model name is the same as the one we're rendering, since there can be multiple models rendered
330
+ * at the same time, e.g. header/page/footer.
331
+ * - the API key is the same, since we don't want to preview content from other organizations.
332
+ *
333
+ * TO-DO: should we check that the preview item ID is the same as the initial one being rendered? Or would
334
+ * this break scenarios where the item is not published yet?
335
+ *
336
+ * TO-DO: should we only update the state when there is a change?
337
+ **/
338
+ if (searchParamPreview === model && previewApiKey === apiKey) {
339
+ getContent({
340
+ model: model,
341
+ apiKey: apiKey,
342
+ }).then((content) => {
343
+ if (content) {
344
+ overrideContent = content;
345
+ }
346
+ });
352
347
  }
353
348
  }
354
349
  evaluateJsCode();
@@ -401,4 +396,4 @@
401
396
  key={forceReRenderCount}
402
397
  />
403
398
  </div>
404
- {/if}
399
+ {/if}
@@ -23,4 +23,4 @@
23
23
  {@html injectedStyleScript()}
24
24
  {:else}
25
25
  <svelte:element this={tag()}>{styles}</svelte:element>
26
- {/if}
26
+ {/if}
@@ -0,0 +1,67 @@
1
+ import { TARGET } from '../../constants/target';
2
+ import type { Nullable } from '../../helpers/nullable';
3
+ import { isBrowser } from '../is-browser';
4
+
5
+ const getLocation = (): Nullable<URL> => {
6
+ if (TARGET === 'reactNative') {
7
+ return null;
8
+ } else if (isBrowser()) {
9
+ const parsedLocation = new URL(location.href);
10
+
11
+ // IE11 bug with parsed path being empty string
12
+ // causes issues with our user targeting
13
+ if (parsedLocation.pathname === '') {
14
+ parsedLocation.pathname = '/';
15
+ }
16
+
17
+ return parsedLocation;
18
+ } else {
19
+ console.warn('Cannot get location for tracking in non-browser environment');
20
+ return null;
21
+ }
22
+ };
23
+
24
+ const getUserAgent = () =>
25
+ (typeof navigator === 'object' && navigator.userAgent) || '';
26
+
27
+ export const getUserAttributes = () => {
28
+ const userAgent = getUserAgent();
29
+
30
+ const isMobile = {
31
+ Android() {
32
+ return userAgent.match(/Android/i);
33
+ },
34
+ BlackBerry() {
35
+ return userAgent.match(/BlackBerry/i);
36
+ },
37
+ iOS() {
38
+ return userAgent.match(/iPhone|iPod/i);
39
+ },
40
+ Opera() {
41
+ return userAgent.match(/Opera Mini/i);
42
+ },
43
+ Windows() {
44
+ return userAgent.match(/IEMobile/i) || userAgent.match(/WPDesktop/i);
45
+ },
46
+ any() {
47
+ return (
48
+ isMobile.Android() ||
49
+ isMobile.BlackBerry() ||
50
+ isMobile.iOS() ||
51
+ isMobile.Opera() ||
52
+ isMobile.Windows() ||
53
+ TARGET === 'reactNative'
54
+ );
55
+ },
56
+ };
57
+
58
+ const isTablet = userAgent.match(/Tablet|iPad/i);
59
+
60
+ const url = getLocation();
61
+
62
+ return {
63
+ urlPath: url?.pathname,
64
+ host: url?.host || url?.hostname,
65
+ device: isTablet ? 'tablet' : isMobile.any() ? 'mobile' : 'desktop',
66
+ };
67
+ };