@builder.io/sdk-svelte 5.2.16 → 5.4.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 (164) hide show
  1. package/README.md +4 -0
  2. package/lib/browser/blocks/symbol/symbol.helpers.d.ts +1 -0
  3. package/lib/browser/blocks/symbol/symbol.helpers.js +6 -0
  4. package/lib/browser/blocks/symbol/symbol.svelte +5 -1
  5. package/lib/browser/components/block/block.helpers.d.ts +1 -3
  6. package/lib/browser/components/block/block.helpers.js +31 -4
  7. package/lib/browser/components/block/block.svelte +14 -1
  8. package/lib/browser/components/builder-scripts.svelte +39 -0
  9. package/lib/browser/components/builder-scripts.svelte.d.ts +22 -0
  10. package/lib/browser/components/content/components/styles.helpers.d.ts +1 -1
  11. package/lib/browser/components/content/components/styles.helpers.js +1 -1
  12. package/lib/browser/components/content/content.helpers.d.ts +5 -1
  13. package/lib/browser/components/content/content.helpers.js +39 -2
  14. package/lib/browser/components/content/content.svelte +4 -17
  15. package/lib/browser/components/content-variants/content-variants.svelte +15 -8
  16. package/lib/browser/components/content-variants/content-variants.svelte.d.ts +5 -0
  17. package/lib/browser/components/content-variants/helpers.d.ts +6 -0
  18. package/lib/browser/components/content-variants/helpers.js +5 -0
  19. package/lib/browser/constants/builder-registered-components.d.ts +1 -0
  20. package/lib/browser/constants/builder-registered-components.js +40 -33
  21. package/lib/browser/constants/device-sizes.js +14 -2
  22. package/lib/browser/constants/sdk-version.d.ts +1 -1
  23. package/lib/browser/constants/sdk-version.js +1 -1
  24. package/lib/browser/context/builder-scripts.context.d.ts +7 -0
  25. package/lib/browser/context/builder-scripts.context.js +5 -0
  26. package/lib/browser/functions/evaluate/browser-runtime/browser.js +13 -1
  27. package/lib/browser/functions/evaluate/evaluate.js +21 -5
  28. package/lib/browser/functions/evaluate/node-runtime/node-runtime.js +114 -23
  29. package/lib/browser/functions/evaluate/safe-state-expression.d.ts +33 -0
  30. package/lib/browser/functions/evaluate/safe-state-expression.js +236 -0
  31. package/lib/browser/functions/evaluate/should-force-browser-runtime-in-node.js +3 -1
  32. package/lib/browser/functions/extract-localized-values.d.ts +4 -0
  33. package/lib/browser/functions/extract-localized-values.js +65 -26
  34. package/lib/browser/functions/get-block-properties.js +2 -1
  35. package/lib/browser/functions/get-processed-block.d.ts +0 -1
  36. package/lib/browser/functions/get-processed-block.js +45 -57
  37. package/lib/browser/functions/is-editing-or-previewing.d.ts +1 -0
  38. package/lib/browser/functions/is-editing-or-previewing.js +3 -0
  39. package/lib/browser/functions/set.d.ts +29 -1
  40. package/lib/browser/functions/set.js +85 -4
  41. package/lib/browser/helpers/bounded-cache.d.ts +4 -0
  42. package/lib/browser/helpers/bounded-cache.js +12 -0
  43. package/lib/browser/helpers/copy-plain-data.d.ts +6 -0
  44. package/lib/browser/helpers/copy-plain-data.js +40 -0
  45. package/lib/browser/index-helpers/blocks-exports.d.ts +1 -0
  46. package/lib/browser/index-helpers/blocks-exports.js +1 -0
  47. package/lib/edge/blocks/symbol/symbol.helpers.d.ts +1 -0
  48. package/lib/edge/blocks/symbol/symbol.helpers.js +6 -0
  49. package/lib/edge/blocks/symbol/symbol.svelte +5 -1
  50. package/lib/edge/components/block/block.helpers.d.ts +1 -3
  51. package/lib/edge/components/block/block.helpers.js +31 -4
  52. package/lib/edge/components/block/block.svelte +14 -1
  53. package/lib/edge/components/builder-scripts.svelte +39 -0
  54. package/lib/edge/components/builder-scripts.svelte.d.ts +22 -0
  55. package/lib/edge/components/content/components/styles.helpers.d.ts +1 -1
  56. package/lib/edge/components/content/components/styles.helpers.js +1 -1
  57. package/lib/edge/components/content/content.helpers.d.ts +5 -1
  58. package/lib/edge/components/content/content.helpers.js +39 -2
  59. package/lib/edge/components/content/content.svelte +4 -17
  60. package/lib/edge/components/content-variants/content-variants.svelte +15 -8
  61. package/lib/edge/components/content-variants/content-variants.svelte.d.ts +5 -0
  62. package/lib/edge/components/content-variants/helpers.d.ts +6 -0
  63. package/lib/edge/components/content-variants/helpers.js +5 -0
  64. package/lib/edge/constants/builder-registered-components.d.ts +1 -0
  65. package/lib/edge/constants/builder-registered-components.js +40 -33
  66. package/lib/edge/constants/device-sizes.js +14 -2
  67. package/lib/edge/constants/sdk-version.d.ts +1 -1
  68. package/lib/edge/constants/sdk-version.js +1 -1
  69. package/lib/edge/context/builder-scripts.context.d.ts +7 -0
  70. package/lib/edge/context/builder-scripts.context.js +5 -0
  71. package/lib/edge/functions/evaluate/browser-runtime/browser.js +13 -1
  72. package/lib/edge/functions/evaluate/evaluate.js +21 -5
  73. package/lib/edge/functions/evaluate/node-runtime/node-runtime.js +114 -23
  74. package/lib/edge/functions/evaluate/safe-state-expression.d.ts +33 -0
  75. package/lib/edge/functions/evaluate/safe-state-expression.js +236 -0
  76. package/lib/edge/functions/evaluate/should-force-browser-runtime-in-node.js +3 -1
  77. package/lib/edge/functions/extract-localized-values.d.ts +4 -0
  78. package/lib/edge/functions/extract-localized-values.js +65 -26
  79. package/lib/edge/functions/get-block-properties.js +2 -1
  80. package/lib/edge/functions/get-processed-block.d.ts +0 -1
  81. package/lib/edge/functions/get-processed-block.js +45 -57
  82. package/lib/edge/functions/is-editing-or-previewing.d.ts +1 -0
  83. package/lib/edge/functions/is-editing-or-previewing.js +3 -0
  84. package/lib/edge/functions/set.d.ts +29 -1
  85. package/lib/edge/functions/set.js +85 -4
  86. package/lib/edge/helpers/bounded-cache.d.ts +4 -0
  87. package/lib/edge/helpers/bounded-cache.js +12 -0
  88. package/lib/edge/helpers/copy-plain-data.d.ts +6 -0
  89. package/lib/edge/helpers/copy-plain-data.js +40 -0
  90. package/lib/edge/index-helpers/blocks-exports.d.ts +1 -0
  91. package/lib/edge/index-helpers/blocks-exports.js +1 -0
  92. package/lib/node/blocks/symbol/symbol.helpers.d.ts +1 -0
  93. package/lib/node/blocks/symbol/symbol.helpers.js +6 -0
  94. package/lib/node/blocks/symbol/symbol.svelte +5 -1
  95. package/lib/node/components/block/block.helpers.d.ts +1 -3
  96. package/lib/node/components/block/block.helpers.js +31 -4
  97. package/lib/node/components/block/block.svelte +14 -1
  98. package/lib/node/components/builder-scripts.svelte +39 -0
  99. package/lib/node/components/builder-scripts.svelte.d.ts +22 -0
  100. package/lib/node/components/content/components/styles.helpers.d.ts +1 -1
  101. package/lib/node/components/content/components/styles.helpers.js +1 -1
  102. package/lib/node/components/content/content.helpers.d.ts +5 -1
  103. package/lib/node/components/content/content.helpers.js +39 -2
  104. package/lib/node/components/content/content.svelte +4 -17
  105. package/lib/node/components/content-variants/content-variants.svelte +15 -8
  106. package/lib/node/components/content-variants/content-variants.svelte.d.ts +5 -0
  107. package/lib/node/components/content-variants/helpers.d.ts +6 -0
  108. package/lib/node/components/content-variants/helpers.js +5 -0
  109. package/lib/node/constants/builder-registered-components.d.ts +1 -0
  110. package/lib/node/constants/builder-registered-components.js +40 -33
  111. package/lib/node/constants/device-sizes.js +14 -2
  112. package/lib/node/constants/sdk-version.d.ts +1 -1
  113. package/lib/node/constants/sdk-version.js +1 -1
  114. package/lib/node/context/builder-scripts.context.d.ts +7 -0
  115. package/lib/node/context/builder-scripts.context.js +5 -0
  116. package/lib/node/functions/evaluate/browser-runtime/browser.js +13 -1
  117. package/lib/node/functions/evaluate/evaluate.js +21 -5
  118. package/lib/node/functions/evaluate/node-runtime/node-runtime.js +114 -23
  119. package/lib/node/functions/evaluate/safe-state-expression.d.ts +33 -0
  120. package/lib/node/functions/evaluate/safe-state-expression.js +236 -0
  121. package/lib/node/functions/evaluate/should-force-browser-runtime-in-node.js +3 -1
  122. package/lib/node/functions/extract-localized-values.d.ts +4 -0
  123. package/lib/node/functions/extract-localized-values.js +65 -26
  124. package/lib/node/functions/get-block-properties.js +2 -1
  125. package/lib/node/functions/get-processed-block.d.ts +0 -1
  126. package/lib/node/functions/get-processed-block.js +45 -57
  127. package/lib/node/functions/is-editing-or-previewing.d.ts +1 -0
  128. package/lib/node/functions/is-editing-or-previewing.js +3 -0
  129. package/lib/node/functions/set.d.ts +29 -1
  130. package/lib/node/functions/set.js +85 -4
  131. package/lib/node/helpers/bounded-cache.d.ts +4 -0
  132. package/lib/node/helpers/bounded-cache.js +12 -0
  133. package/lib/node/helpers/copy-plain-data.d.ts +6 -0
  134. package/lib/node/helpers/copy-plain-data.js +40 -0
  135. package/lib/node/index-helpers/blocks-exports.d.ts +1 -0
  136. package/lib/node/index-helpers/blocks-exports.js +1 -0
  137. package/package.json +1 -1
  138. package/src/blocks/symbol/symbol.helpers.ts +7 -0
  139. package/src/blocks/symbol/symbol.svelte +8 -1
  140. package/src/components/block/block.helpers.ts +38 -5
  141. package/src/components/block/block.svelte +14 -1
  142. package/src/components/builder-scripts.svelte +57 -0
  143. package/src/components/content/components/styles.helpers.ts +1 -1
  144. package/src/components/content/content.helpers.ts +45 -4
  145. package/src/components/content/content.svelte +7 -24
  146. package/src/components/content-variants/content-variants.svelte +21 -8
  147. package/src/components/content-variants/helpers.ts +6 -0
  148. package/src/constants/builder-registered-components.ts +40 -34
  149. package/src/constants/device-sizes.ts +14 -3
  150. package/src/constants/sdk-version.ts +1 -1
  151. package/src/context/builder-scripts.context.ts +6 -0
  152. package/src/functions/evaluate/browser-runtime/browser.ts +14 -1
  153. package/src/functions/evaluate/evaluate.ts +22 -5
  154. package/src/functions/evaluate/node-runtime/node-runtime.ts +116 -25
  155. package/src/functions/evaluate/safe-state-expression.ts +224 -0
  156. package/src/functions/evaluate/should-force-browser-runtime-in-node.ts +3 -1
  157. package/src/functions/extract-localized-values.ts +61 -27
  158. package/src/functions/get-block-properties.ts +5 -1
  159. package/src/functions/get-processed-block.ts +46 -57
  160. package/src/functions/is-editing-or-previewing.ts +3 -0
  161. package/src/functions/set.ts +89 -4
  162. package/src/helpers/bounded-cache.ts +12 -0
  163. package/src/helpers/copy-plain-data.ts +36 -0
  164. package/src/index-helpers/blocks-exports.ts +1 -0
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  This is Builder's Svelte SDK.
4
4
 
5
+ ## Minimum supported version
6
+
7
+ The [`peerDependencies`](./package.json) permit **Svelte 4.1.2 through 4.x** (`^4.1.2`, not Svelte 5). This installation range does not establish an actively supported minimum; see the [framework version matrix](../../README.md#framework-version-guidance).
8
+
5
9
  ## Mitosis
6
10
 
7
11
  This SDK is generated by [Mitosis](https://github.com/BuilderIO/mitosis). To see the Mitosis source-code, go [here](../../).
@@ -10,6 +10,7 @@ export interface SymbolInfo {
10
10
  ownerId?: string;
11
11
  global?: boolean;
12
12
  }
13
+ export declare const isSymbolContentInlinedInParent: (symbol: SymbolInfo | undefined, bindings: Record<string, string> | undefined) => boolean;
13
14
  export declare const fetchSymbolContent: ({ builderContextValue, symbol }: {
14
15
  symbol: SymbolInfo | undefined;
15
16
  builderContextValue: BuilderContextInterface;
@@ -1,5 +1,11 @@
1
1
  import { fetchOneEntry } from '../../functions/get-content/index';
2
2
  import { logger } from '../../helpers/logger';
3
+ const isSymbolContentBinding = (key) => {
4
+ const path = key.startsWith('component.') ? key.slice(10) : key;
5
+ return path === 'options.symbol' || path === 'options.symbol.content' || path.startsWith('options.symbol.content.');
6
+ };
7
+ // Bound symbol content is evaluated at render time, so it is not in the parent content JSON.
8
+ export const isSymbolContentInlinedInParent = (symbol, bindings) => !!symbol?.content && !Object.keys(bindings || {}).some(isSymbolContentBinding);
3
9
  export const fetchSymbolContent = async ({ builderContextValue, symbol }) => {
4
10
  /**
5
11
  * If:
@@ -4,7 +4,7 @@ import { filterAttrs } from "../helpers";
4
4
  import "../../components/dynamic-div.svelte";
5
5
  import { getClassPropName } from "../../functions/get-class-prop-name";
6
6
  import { setAttrs } from "../helpers";
7
- import { fetchSymbolContent } from "./symbol.helpers";
7
+ import { fetchSymbolContent, isSymbolContentInlinedInParent, } from "./symbol.helpers";
8
8
  export let symbol = undefined;
9
9
  export let builderComponents;
10
10
  export let attributes = undefined;
@@ -64,6 +64,10 @@ $: onUpdateFn_0(...[symbol]);
64
64
  <ContentVariants
65
65
  nonce={$builderContext.nonce}
66
66
  isNestedRender={true}
67
+ isContentInlinedInParent={isSymbolContentInlinedInParent(
68
+ symbol,
69
+ builderBlock?.bindings
70
+ )}
67
71
  apiVersion={$builderContext.apiVersion}
68
72
  apiKey={symbol?.global && symbol?.ownerId
69
73
  ? symbol.ownerId
@@ -22,9 +22,7 @@ export declare const provideLinkComponent: (block: RegisteredComponent | null |
22
22
  builderLinkComponent?: undefined;
23
23
  };
24
24
  export declare const provideRegisteredComponents: (block: RegisteredComponent | null | undefined, registeredComponents: RegisteredComponents, model: string) => {
25
- builderComponents: {
26
- [k: string]: RegisteredComponent;
27
- };
25
+ builderComponents: RegisteredComponents;
28
26
  } | {
29
27
  builderComponents?: undefined;
30
28
  };
@@ -1,6 +1,7 @@
1
1
  import { evaluate } from '../../functions/evaluate/index';
2
2
  import { extractTextStyles } from '../../functions/extract-text-styles';
3
3
  import { getStyle } from '../../functions/get-style';
4
+ import { isEditingOrPreviewing } from '../../functions/is-editing-or-previewing';
4
5
  const checkIsComponentRestricted = (component, model) => {
5
6
  if (!component)
6
7
  return true;
@@ -25,12 +26,27 @@ export const getComponent = ({ block, registeredComponents, model }) => {
25
26
  return ref;
26
27
  }
27
28
  };
29
+ // Reused per block so repeated items keep a stable block identity across renders.
30
+ const BLOCKS_WITHOUT_REPEAT = new WeakMap();
31
+ const getBlockWithoutRepeat = (block) => {
32
+ if (isEditingOrPreviewing()) {
33
+ const { repeat: _repeat, ...rest } = block;
34
+ return rest;
35
+ }
36
+ let blockWithoutRepeat = BLOCKS_WITHOUT_REPEAT.get(block);
37
+ if (!blockWithoutRepeat) {
38
+ const { repeat: _repeat, ...rest } = block;
39
+ blockWithoutRepeat = rest;
40
+ BLOCKS_WITHOUT_REPEAT.set(block, blockWithoutRepeat);
41
+ }
42
+ return blockWithoutRepeat;
43
+ };
28
44
  export const getRepeatItemData = ({ block, context }) => {
29
45
  /**
30
46
  * we don't use `state.processedBlock` here because the processing done within its logic includes evaluating the block's bindings,
31
47
  * which will not work if there is a repeat.
32
48
  */
33
- const { repeat, ...blockWithoutRepeat } = block;
49
+ const { repeat } = block;
34
50
  if (!repeat?.collection) {
35
51
  return undefined;
36
52
  }
@@ -46,6 +62,7 @@ export const getRepeatItemData = ({ block, context }) => {
46
62
  }
47
63
  const collectionName = repeat.collection.split('.').pop();
48
64
  const itemNameToUse = repeat.itemName || (collectionName ? collectionName + 'Item' : 'item');
65
+ const blockWithoutRepeat = getBlockWithoutRepeat(block);
49
66
  const repeatArray = itemsArray.map((item, index) => ({
50
67
  context: {
51
68
  ...context,
@@ -78,11 +95,21 @@ export const provideLinkComponent = (block, linkComponent) => {
78
95
  };
79
96
  return {};
80
97
  };
98
+ const FILTERED_REGISTERED_COMPONENTS = new WeakMap();
81
99
  export const provideRegisteredComponents = (block, registeredComponents, model) => {
82
100
  if (block?.shouldReceiveBuilderProps?.builderComponents) {
83
- const filteredRegisteredComponents = Object.fromEntries(Object.entries(registeredComponents).filter(([_, component]) => {
84
- return !checkIsComponentRestricted(component, model);
85
- }));
101
+ let byModel = FILTERED_REGISTERED_COMPONENTS.get(registeredComponents);
102
+ if (!byModel) {
103
+ byModel = new Map();
104
+ FILTERED_REGISTERED_COMPONENTS.set(registeredComponents, byModel);
105
+ }
106
+ let filteredRegisteredComponents = byModel.get(model);
107
+ if (!filteredRegisteredComponents) {
108
+ filteredRegisteredComponents = Object.fromEntries(Object.entries(registeredComponents).filter(([_, component]) => {
109
+ return !checkIsComponentRestricted(component, model);
110
+ }));
111
+ byModel.set(model, filteredRegisteredComponents);
112
+ }
86
113
  return {
87
114
  builderComponents: filteredRegisteredComponents
88
115
  };
@@ -73,7 +73,15 @@ $: childrenWithoutParentComponent = () => {
73
73
  : [];
74
74
  };
75
75
  $: componentRefProps = () => {
76
- return {
76
+ const deps = [
77
+ processedBlock(),
78
+ $context,
79
+ $context.rootState,
80
+ $context.localState,
81
+ registeredComponents,
82
+ linkComponent,
83
+ ];
84
+ const componentRefProps = {
77
85
  blockChildren: processedBlock().children ?? [],
78
86
  componentRef: blockComponent?.()?.component,
79
87
  componentOptions: {
@@ -90,11 +98,16 @@ $: componentRefProps = () => {
90
98
  includeBlockProps: blockComponent?.()?.noWrap === true,
91
99
  isInteractive: !(blockComponent?.()?.isRSC && TARGET === "rsc"),
92
100
  };
101
+ return componentRefProps;
93
102
  };
94
103
  let _processedBlock = {
95
104
  value: null,
96
105
  update: false,
97
106
  };
107
+ let _componentRefProps = {
108
+ value: null,
109
+ deps: [],
110
+ };
98
111
  onMount(() => {
99
112
  const blockId = processedBlock().id;
100
113
  const animations = processedBlock().animations;
@@ -0,0 +1,39 @@
1
+ <script context="module">/**
2
+ * Emits the Variant Container and A/B test helper scripts once for all `Content` components inside it.
3
+ */
4
+ </script>
5
+
6
+ <script>import { getContext, setContext } from "svelte";
7
+ import { getInitPersonalizationVariantsFnsScriptString, SDKS_SUPPORTING_PERSONALIZATION, } from "../blocks/personalization-container/helpers";
8
+ import { TARGET } from "../constants/target";
9
+ import BuilderScriptsContext from "../context/builder-scripts.context";
10
+ import { isBrowser } from "../functions/is-browser";
11
+ import { getInitVariantsFnsScriptString, SDKS_SUPPORTING_BUILDER_SCRIPTS, } from "./content-variants/helpers";
12
+ import InlinedScript from "./inlined-script.svelte";
13
+ export let nonce = undefined;
14
+ let parentScriptsContext = getContext(BuilderScriptsContext.key);
15
+ let isSupported = SDKS_SUPPORTING_BUILDER_SCRIPTS.includes(TARGET);
16
+ let shouldRenderAbTestFns = TARGET !== "react" || !isBrowser();
17
+ setContext(BuilderScriptsContext.key, {
18
+ scriptsEmitted: isSupported,
19
+ });
20
+ </script>
21
+
22
+ {#if isSupported && !parentScriptsContext?.scriptsEmitted}
23
+ {#if SDKS_SUPPORTING_PERSONALIZATION.includes(TARGET)}
24
+ <InlinedScript
25
+ id="builderio-init-personalization-variants-fns"
26
+ nonce={nonce || ""}
27
+ scriptStr={getInitPersonalizationVariantsFnsScriptString()}
28
+ />
29
+ {/if}
30
+
31
+ {#if shouldRenderAbTestFns}
32
+ <InlinedScript
33
+ id="builderio-init-variants-fns"
34
+ nonce={nonce || ""}
35
+ scriptStr={getInitVariantsFnsScriptString()}
36
+ />
37
+ {/if}
38
+ {/if}
39
+ <slot />
@@ -0,0 +1,22 @@
1
+ import { SvelteComponent } from "svelte";
2
+ type BuilderScriptsProps = {
3
+ nonce?: string;
4
+ children?: any;
5
+ };
6
+ declare const __propDef: {
7
+ props: {
8
+ nonce?: BuilderScriptsProps["nonce"];
9
+ };
10
+ events: {
11
+ [evt: string]: CustomEvent<any>;
12
+ };
13
+ slots: {
14
+ default: {};
15
+ };
16
+ };
17
+ type BuilderScriptsProps_ = typeof __propDef.props;
18
+ export { BuilderScriptsProps_ as BuilderScriptsProps };
19
+ export type BuilderScriptsEvents = typeof __propDef.events;
20
+ export type BuilderScriptsSlots = typeof __propDef.slots;
21
+ export default class BuilderScripts extends SvelteComponent<BuilderScriptsProps, BuilderScriptsEvents, BuilderScriptsSlots> {
22
+ }
@@ -13,5 +13,5 @@ export declare const getCss: ({ cssCode, contentId }: {
13
13
  cssCode?: string | undefined;
14
14
  contentId?: string | undefined;
15
15
  }) => string;
16
- export declare const getDefaultStyles: (isNested: boolean | undefined) => "" | "\n.builder-button {\n all: unset;\n}\n\n.builder-text > p:first-of-type, .builder-text > .builder-paragraph:first-of-type {\n margin: 0;\n}\n.builder-text > p, .builder-text > .builder-paragraph {\n color: inherit;\n line-height: inherit;\n letter-spacing: inherit;\n font-weight: inherit;\n font-size: inherit;\n text-align: inherit;\n font-family: inherit;\n}\n";
16
+ export declare const getDefaultStyles: (isNested: boolean | undefined) => "" | "\n:where(.builder-button) {\n all: unset;\n}\n\n.builder-text > p:first-of-type, .builder-text > .builder-paragraph:first-of-type {\n margin: 0;\n}\n.builder-text > p, .builder-text > .builder-paragraph {\n color: inherit;\n line-height: inherit;\n letter-spacing: inherit;\n font-weight: inherit;\n font-size: inherit;\n text-align: inherit;\n font-family: inherit;\n}\n";
17
17
  export declare const getWrapperClassName: (variationId?: string) => string;
@@ -57,7 +57,7 @@ export const getCss = ({ cssCode, contentId }) => {
57
57
  return cssCode?.replace(/&/g, `div[builder-content-id="${contentId}"]`) || '';
58
58
  };
59
59
  const DEFAULT_STYLES = `
60
- .builder-button {
60
+ :where(.builder-button) {
61
61
  all: unset;
62
62
  }
63
63
 
@@ -1,6 +1,10 @@
1
+ import type { RegisteredComponent, RegisteredComponents } from '../../context/types';
1
2
  import type { BuilderContent } from '../../types/builder-content';
2
- import type { Nullable } from '../../types/typescript';
3
+ import type { ComponentInfo } from '../../types/components';
4
+ import type { Dictionary, Nullable } from '../../types/typescript';
3
5
  import type { ContentProps } from './content.types';
6
+ export declare const getRegisteredComponents: (registrations: RegisteredComponent[], wrapComponent: (component: any) => any) => RegisteredComponents;
7
+ export declare const getComponentInfos: (registrations: RegisteredComponent[]) => Dictionary<ComponentInfo>;
4
8
  export declare const getRootStateInitialValue: ({ content, data, locale }: Pick<ContentProps, 'content' | 'data' | 'locale'>) => {
5
9
  locale?: string | undefined;
6
10
  };
@@ -1,10 +1,47 @@
1
+ import { serializeIncludingFunctions } from '../../functions/register-component';
2
+ import { copyPlainData } from '../../helpers/copy-plain-data';
3
+ // Registrations are usually module constants, so their derived forms are built once per object.
4
+ const SERIALIZED_COMPONENT_INFOS = new WeakMap();
5
+ const REGISTERED_COMPONENT_ENTRIES = new WeakMap();
6
+ const getSerializedComponentInfo = (registration) => {
7
+ const cached = SERIALIZED_COMPONENT_INFOS.get(registration);
8
+ if (cached)
9
+ return cached;
10
+ const { component: _, ...rest } = registration;
11
+ const info = serializeIncludingFunctions(rest);
12
+ SERIALIZED_COMPONENT_INFOS.set(registration, info);
13
+ return info;
14
+ };
15
+ export const getRegisteredComponents = (registrations, wrapComponent) => {
16
+ const registeredComponents = {};
17
+ for (const registration of registrations) {
18
+ let entry = REGISTERED_COMPONENT_ENTRIES.get(registration);
19
+ if (!entry) {
20
+ entry = {
21
+ component: wrapComponent(registration.component),
22
+ ...getSerializedComponentInfo(registration)
23
+ };
24
+ REGISTERED_COMPONENT_ENTRIES.set(registration, entry);
25
+ }
26
+ registeredComponents[registration.name] = entry;
27
+ }
28
+ return registeredComponents;
29
+ };
30
+ export const getComponentInfos = (registrations) => {
31
+ const componentInfos = {};
32
+ for (const registration of registrations) {
33
+ componentInfos[registration.name] = getSerializedComponentInfo(registration);
34
+ }
35
+ return componentInfos;
36
+ };
1
37
  export const getRootStateInitialValue = ({ content, data, locale }) => {
2
38
  const defaultValues = {};
3
- const initialState = content?.data?.state || {};
39
+ const seen = new WeakMap();
40
+ const initialState = copyPlainData(content?.data?.state || {}, seen);
4
41
  // set default values for content state inputs
5
42
  content?.data?.inputs?.forEach(input => {
6
43
  if (input.name && input.defaultValue !== undefined) {
7
- defaultValues[input.name] = input.defaultValue;
44
+ defaultValues[input.name] = copyPlainData(input.defaultValue, seen);
8
45
  }
9
46
  });
10
47
  return {
@@ -4,7 +4,6 @@ import { getDefaultRegisteredComponents } from "../../constants/builder-register
4
4
  import { TARGET } from "../../constants/target";
5
5
  import ComponentsContext from "../../context/components.context";
6
6
  import { evaluate } from "../../functions/evaluate/evaluate";
7
- import { serializeIncludingFunctions } from "../../functions/register-component";
8
7
  import { logger } from "../../helpers/logger";
9
8
  import Blocks from "../blocks/blocks.svelte";
10
9
  import { getUpdateVariantVisibilityScript } from "../content-variants/helpers";
@@ -12,7 +11,7 @@ import "../dynamic-div.svelte";
12
11
  import InlinedScript from "../inlined-script.svelte";
13
12
  import EnableEditor from "./components/enable-editor.svelte";
14
13
  import ContentStyles from "./components/styles.svelte";
15
- import { getContentInitialValue, getRootStateInitialValue, } from "./content.helpers";
14
+ import { getComponentInfos, getContentInitialValue, getRegisteredComponents, getRootStateInitialValue, } from "./content.helpers";
16
15
  import "./wrap-component-ref";
17
16
  export let content;
18
17
  export let data = undefined;
@@ -45,16 +44,7 @@ let scriptStr = getUpdateVariantVisibilityScript({
45
44
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
46
45
  contentId: content?.id,
47
46
  });
48
- let registeredComponents = [
49
- ...getDefaultRegisteredComponents(),
50
- ...(customComponents || []),
51
- ].reduce((acc, { component, ...info }) => ({
52
- ...acc,
53
- [info.name]: {
54
- component: component,
55
- ...serializeIncludingFunctions(info),
56
- },
57
- }), {});
47
+ let registeredComponents = getRegisteredComponents([...getDefaultRegisteredComponents(), ...(customComponents || [])], (component) => component);
58
48
  let builderContextSignal = writable({
59
49
  content: getContentInitialValue({
60
50
  content: content,
@@ -71,13 +61,10 @@ let builderContextSignal = writable({
71
61
  canTrack: canTrack,
72
62
  apiKey: apiKey,
73
63
  apiVersion: apiVersion,
74
- componentInfos: [
64
+ componentInfos: getComponentInfos([
75
65
  ...getDefaultRegisteredComponents(),
76
66
  ...(customComponents || []),
77
- ].reduce((acc, { component: _, ...info }) => ({
78
- ...acc,
79
- [info.name]: serializeIncludingFunctions(info),
80
- }), {}),
67
+ ]),
81
68
  inheritedStyles: {},
82
69
  BlocksWrapper: blocksWrapper || "div",
83
70
  BlocksWrapperProps: blocksWrapperProps || {},
@@ -1,8 +1,9 @@
1
1
  <script context="module"></script>
2
2
 
3
- <script>import { onMount } from "svelte";
3
+ <script>import { getContext, onMount } from "svelte";
4
4
  import { SDKS_SUPPORTING_PERSONALIZATION, getInitPersonalizationVariantsFnsScriptString, hasPersonalizationContainer, } from "../../blocks/personalization-container/helpers";
5
5
  import { TARGET } from "../../constants/target";
6
+ import BuilderScriptsContext from "../../context/builder-scripts.context";
6
7
  import { handleABTestingSync } from "../../helpers/ab-tests";
7
8
  import { getDefaultCanTrack } from "../../helpers/canTrack";
8
9
  import ContentComponent from "../content/content.svelte";
@@ -11,6 +12,7 @@ import InlinedStyles from "../inlined-styles.svelte";
11
12
  import { checkShouldRenderVariants, getInitVariantsFnsScriptString, getUpdateCookieAndStylesScript, getVariants, } from "./helpers";
12
13
  export let canTrack = undefined;
13
14
  export let content;
15
+ export let isContentInlinedInParent = undefined;
14
16
  export let nonce = undefined;
15
17
  export let apiHost = undefined;
16
18
  export let isNestedRender = undefined;
@@ -29,6 +31,7 @@ export let blocksWrapperProps = undefined;
29
31
  export let contentWrapper = undefined;
30
32
  export let contentWrapperProps = undefined;
31
33
  export let trustedHosts = undefined;
34
+ let scriptsContext = getContext(BuilderScriptsContext.key);
32
35
  $: updateCookieAndStylesScriptStr = () => {
33
36
  return getUpdateCookieAndStylesScript(getVariants(content).map((value) => ({
34
37
  id: value.testVariationId,
@@ -55,7 +58,9 @@ let shouldRenderVariants = checkShouldRenderVariants({
55
58
  canTrack: getDefaultCanTrack(canTrack),
56
59
  content: content,
57
60
  });
58
- let shouldEmitPersonalizationFns = TARGET !== "reactNative" && hasPersonalizationContainer(content);
61
+ let shouldEmitPersonalizationFns = TARGET !== "reactNative" &&
62
+ !isContentInlinedInParent &&
63
+ hasPersonalizationContainer(content);
59
64
  onMount(() => {
60
65
  /**
61
66
  * For Solid/Svelte: we unmount the non-winning variants post-hydration.
@@ -64,7 +69,7 @@ onMount(() => {
64
69
  });
65
70
  </script>
66
71
 
67
- {#if shouldEmitPersonalizationFns}
72
+ {#if shouldEmitPersonalizationFns && !!!scriptsContext?.scriptsEmitted}
68
73
  {#if SDKS_SUPPORTING_PERSONALIZATION.includes(TARGET)}
69
74
  <InlinedScript
70
75
  id="builderio-init-personalization-variants-fns"
@@ -75,11 +80,13 @@ onMount(() => {
75
80
  {/if}
76
81
 
77
82
  {#if shouldRenderVariants}
78
- <InlinedScript
79
- id="builderio-init-variants-fns"
80
- scriptStr={getInitVariantsFnsScriptString()}
81
- nonce={nonce || ""}
82
- />
83
+ {#if !!!scriptsContext?.scriptsEmitted}
84
+ <InlinedScript
85
+ id="builderio-init-variants-fns"
86
+ scriptStr={getInitVariantsFnsScriptString()}
87
+ nonce={nonce || ""}
88
+ />
89
+ {/if}
83
90
  <InlinedStyles
84
91
  id="builderio-variants"
85
92
  styles={hideVariantsStyleString()}
@@ -4,12 +4,17 @@ type VariantsProviderProps = ContentVariantsPrps & {
4
4
  * For internal use only. Do not provide this prop.
5
5
  */
6
6
  isNestedRender?: boolean;
7
+ /**
8
+ * For internal use only. Do not provide this prop.
9
+ */
10
+ isContentInlinedInParent?: boolean;
7
11
  };
8
12
  import type { ContentVariantsPrps } from "./content-variants.types";
9
13
  declare const __propDef: {
10
14
  props: {
11
15
  canTrack?: VariantsProviderProps["canTrack"];
12
16
  content: VariantsProviderProps["content"];
17
+ isContentInlinedInParent?: VariantsProviderProps["isContentInlinedInParent"];
13
18
  nonce?: VariantsProviderProps["nonce"];
14
19
  apiHost?: VariantsProviderProps["apiHost"];
15
20
  isNestedRender?: VariantsProviderProps["isNestedRender"];
@@ -1,5 +1,11 @@
1
1
  import type { Nullable } from '../../helpers/nullable';
2
2
  import type { BuilderContent } from '../../types/builder-content';
3
+ import type { Target } from '../../types/targets';
4
+ /**
5
+ * SDKs where `BuilderScripts` can dedupe helper scripts. Elsewhere `Content` cannot read its context
6
+ * (RSC server components, Angular DI) or has no inline scripts (React Native).
7
+ */
8
+ export declare const SDKS_SUPPORTING_BUILDER_SCRIPTS: Target[];
3
9
  export declare const getVariants: (content: Nullable<BuilderContent>) => {
4
10
  testVariationId: string | undefined;
5
11
  id: string | undefined;
@@ -9,6 +9,11 @@ import { UPDATE_COOKIES_AND_STYLES_SCRIPT, UPDATE_VARIANT_VISIBILITY_SCRIPT } fr
9
9
  */
10
10
  const UPDATE_COOKIES_AND_STYLES_SCRIPT_NAME = 'builderIoAbTest';
11
11
  const UPDATE_VARIANT_VISIBILITY_SCRIPT_FN_NAME = 'builderIoRenderContent';
12
+ /**
13
+ * SDKs where `BuilderScripts` can dedupe helper scripts. Elsewhere `Content` cannot read its context
14
+ * (RSC server components, Angular DI) or has no inline scripts (React Native).
15
+ */
16
+ export const SDKS_SUPPORTING_BUILDER_SCRIPTS = ['react', 'vue', 'svelte', 'solid', 'qwik'];
12
17
  export const getVariants = (content) => Object.values(content?.variations || {}).map(variant => ({
13
18
  ...variant,
14
19
  testVariationId: variant.id,
@@ -2,5 +2,6 @@ import type { RegisteredComponent } from '../context/types';
2
2
  /**
3
3
  * Returns a list of all registered components.
4
4
  * NOTE: This needs to be a function to work around ESM circular dependencies.
5
+ * The list is built once, on first use, so its entries keep a stable identity.
5
6
  */
6
7
  export declare const getDefaultRegisteredComponents: () => RegisteredComponent[];
@@ -23,41 +23,48 @@ import { componentInfo as textComponentInfo } from '../blocks/text/component-inf
23
23
  import { default as Text } from '../blocks/text/index';
24
24
  import { getExtraComponents } from './extra-components';
25
25
  import { TARGET } from './target';
26
+ let DEFAULT_REGISTERED_COMPONENTS;
26
27
  /**
27
28
  * Returns a list of all registered components.
28
29
  * NOTE: This needs to be a function to work around ESM circular dependencies.
30
+ * The list is built once, on first use, so its entries keep a stable identity.
29
31
  */
30
- export const getDefaultRegisteredComponents = () => [{
31
- component: Button,
32
- ...buttonComponentInfo
33
- }, {
34
- component: Columns,
35
- ...columnsComponentInfo
36
- }, {
37
- component: Fragment,
38
- ...fragmentComponentInfo
39
- }, {
40
- component: Image,
41
- ...imageComponentInfo
42
- }, {
43
- component: Section,
44
- ...sectionComponentInfo
45
- }, {
46
- component: Slot,
47
- ...slotComponentInfo
48
- }, {
49
- component: Symbol,
50
- ...symbolComponentInfo
51
- }, {
52
- component: Text,
53
- ...textComponentInfo
54
- }, ...(SDKS_SUPPORTING_PERSONALIZATION.includes(TARGET) ? [{
55
- component: PersonalizationContainer,
56
- ...personalizationContainerComponentInfo
57
- }] : []), ...(TARGET === 'rsc' ? [] : [{
58
- component: Tabs,
59
- ...tabsComponentInfo
32
+ export const getDefaultRegisteredComponents = () => {
33
+ if (DEFAULT_REGISTERED_COMPONENTS)
34
+ return DEFAULT_REGISTERED_COMPONENTS;
35
+ DEFAULT_REGISTERED_COMPONENTS = [{
36
+ component: Button,
37
+ ...buttonComponentInfo
60
38
  }, {
61
- component: Accordion,
62
- ...accordionComponentInfo
63
- }]), ...getExtraComponents()];
39
+ component: Columns,
40
+ ...columnsComponentInfo
41
+ }, {
42
+ component: Fragment,
43
+ ...fragmentComponentInfo
44
+ }, {
45
+ component: Image,
46
+ ...imageComponentInfo
47
+ }, {
48
+ component: Section,
49
+ ...sectionComponentInfo
50
+ }, {
51
+ component: Slot,
52
+ ...slotComponentInfo
53
+ }, {
54
+ component: Symbol,
55
+ ...symbolComponentInfo
56
+ }, {
57
+ component: Text,
58
+ ...textComponentInfo
59
+ }, ...(SDKS_SUPPORTING_PERSONALIZATION.includes(TARGET) ? [{
60
+ component: PersonalizationContainer,
61
+ ...personalizationContainerComponentInfo
62
+ }] : []), ...(TARGET === 'rsc' ? [] : [{
63
+ component: Tabs,
64
+ ...tabsComponentInfo
65
+ }, {
66
+ component: Accordion,
67
+ ...accordionComponentInfo
68
+ }]), ...getExtraComponents()];
69
+ return DEFAULT_REGISTERED_COMPONENTS;
70
+ };
@@ -1,4 +1,3 @@
1
- import { fastClone } from '../functions/fast-clone';
2
1
  const SIZES = {
3
2
  xsmall: {
4
3
  min: 0,
@@ -23,7 +22,20 @@ const SIZES = {
23
22
  };
24
23
  export const getMaxWidthQueryForSize = (size, sizeValues = SIZES) => `@media (max-width: ${sizeValues[size].max}px)`;
25
24
  export const getSizesForBreakpoints = (breakpoints) => {
26
- const newSizes = fastClone(SIZES); // Note: this helps to get a deep clone of fields like small, medium etc
25
+ const newSizes = {
26
+ xsmall: {
27
+ ...SIZES.xsmall
28
+ },
29
+ small: {
30
+ ...SIZES.small
31
+ },
32
+ medium: {
33
+ ...SIZES.medium
34
+ },
35
+ large: {
36
+ ...SIZES.large
37
+ }
38
+ };
27
39
  if (!breakpoints) {
28
40
  return newSizes;
29
41
  }
@@ -1 +1 @@
1
- export declare const SDK_VERSION = "5.2.16";
1
+ export declare const SDK_VERSION = "5.4.0";
@@ -1 +1 @@
1
- export const SDK_VERSION = "5.2.16";
1
+ export const SDK_VERSION = "5.4.0";
@@ -0,0 +1,7 @@
1
+ declare const _default: {
2
+ BuilderScripts: {
3
+ scriptsEmitted: boolean;
4
+ };
5
+ key: symbol;
6
+ };
7
+ export default _default;
@@ -0,0 +1,5 @@
1
+ const key = Symbol();
2
+ export default {
3
+ BuilderScripts: { scriptsEmitted: false },
4
+ key,
5
+ };
@@ -1,4 +1,16 @@
1
+ import { createBoundedCache } from '../../../helpers/bounded-cache';
1
2
  import { flattenState, getFunctionArguments } from '../helpers';
3
+ const MAX_CACHED_FUNCTIONS = 5000;
4
+ const FUNCTION_CACHE = createBoundedCache(MAX_CACHED_FUNCTIONS);
5
+ // `getFunctionArguments` always returns the same argument names, so `code` alone is the key.
6
+ const getCompiledFunction = (argNames, code) => {
7
+ let fn = FUNCTION_CACHE.get(code);
8
+ if (!fn) {
9
+ fn = new Function(...argNames, code);
10
+ FUNCTION_CACHE.set(code, fn);
11
+ }
12
+ return fn;
13
+ };
2
14
  export const runInBrowser = ({ code, builder, context, event, localState, rootSetState, rootState }) => {
3
15
  const functionArgs = getFunctionArguments({
4
16
  builder,
@@ -10,5 +22,5 @@ export const runInBrowser = ({ code, builder, context, event, localState, rootSe
10
22
  rootSetState
11
23
  })
12
24
  });
13
- return new Function(...functionArgs.map(([name]) => name), code)(...functionArgs.map(([, value]) => value));
25
+ return getCompiledFunction(functionArgs.map(([name]) => name), code)(...functionArgs.map(([, value]) => value));
14
26
  };