@builder.io/sdk-react 0.2.0 → 0.2.2

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 (166) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/dist/react/blocks/symbol/symbol.js +2 -1
  3. package/dist/react/components/render-block/block-styles.js +3 -0
  4. package/dist/react/components/render-block/render-block.helpers.js +16 -1
  5. package/dist/react/components/render-block/render-block.js +36 -55
  6. package/dist/react/components/render-content/render-content.js +8 -7
  7. package/dist/react/components/render-content-variants/helpers.js +98 -0
  8. package/dist/react/components/render-content-variants/render-content-variants.js +45 -0
  9. package/dist/react/components/render-inlined-styles.js +3 -3
  10. package/dist/react/functions/get-block-properties.js +4 -1
  11. package/dist/react/functions/get-content/index.js +22 -15
  12. package/dist/react/functions/track/index.js +2 -1
  13. package/dist/react/helpers/logger.js +7 -0
  14. package/dist/rsc/blocks/symbol/symbol.js +2 -1
  15. package/dist/rsc/components/render-block/block-styles.js +3 -0
  16. package/dist/rsc/components/render-block/render-block.helpers.js +16 -1
  17. package/dist/rsc/components/render-block/render-block.js +32 -51
  18. package/dist/rsc/components/render-content/render-content.js +1 -0
  19. package/dist/rsc/components/render-content-variants/helpers.js +99 -0
  20. package/dist/rsc/components/render-content-variants/render-content-variants.js +45 -0
  21. package/dist/rsc/components/render-inlined-styles.js +3 -3
  22. package/dist/rsc/functions/get-block-properties.js +4 -1
  23. package/dist/rsc/functions/get-content/index.js +22 -15
  24. package/dist/rsc/functions/track/index.js +2 -1
  25. package/dist/rsc/helpers/logger.js +7 -0
  26. package/package.json +1 -1
  27. package/packages/react/src/blocks/symbol/symbol.jsx +2 -1
  28. package/packages/react/src/components/render-block/block-styles.jsx +3 -0
  29. package/packages/react/src/components/render-block/render-block.helpers.js +16 -0
  30. package/packages/react/src/components/render-block/render-block.jsx +42 -61
  31. package/packages/react/src/components/render-content/render-content.jsx +11 -8
  32. package/packages/react/src/components/render-inlined-styles.jsx +4 -4
  33. package/packages/react/src/functions/get-block-properties.js +4 -1
  34. package/packages/react/src/functions/get-content/index.js +21 -15
  35. package/packages/react/src/functions/track/index.js +2 -1
  36. package/packages/react/src/helpers/logger.js +9 -0
  37. package/packages/rsc/src/blocks/symbol/symbol.jsx +2 -4
  38. package/packages/rsc/src/components/render-block/block-styles.jsx +3 -0
  39. package/packages/rsc/src/components/render-block/render-block.helpers.js +16 -0
  40. package/packages/rsc/src/components/render-block/render-block.jsx +32 -53
  41. package/packages/rsc/src/components/render-content/render-content.jsx +1 -0
  42. package/packages/rsc/src/components/render-inlined-styles.jsx +3 -3
  43. package/packages/rsc/src/functions/get-block-properties.js +4 -1
  44. package/packages/rsc/src/functions/get-content/index.js +21 -15
  45. package/packages/rsc/src/functions/track/index.js +2 -1
  46. package/packages/rsc/src/helpers/logger.js +9 -0
  47. package/packages/react/src/functions/get-block-tag.js +0 -6
  48. package/packages/rsc/src/functions/get-block-tag.js +0 -6
  49. package/src/blocks/BaseText.jsx +0 -9
  50. package/src/blocks/button/button.jsx +0 -27
  51. package/src/blocks/button/component-info.js +0 -41
  52. package/src/blocks/columns/columns.jsx +0 -172
  53. package/src/blocks/columns/component-info.js +0 -242
  54. package/src/blocks/custom-code/component-info.js +0 -31
  55. package/src/blocks/custom-code/custom-code.jsx +0 -64
  56. package/src/blocks/embed/component-info.js +0 -44
  57. package/src/blocks/embed/embed.jsx +0 -49
  58. package/src/blocks/embed/helpers.js +0 -9
  59. package/src/blocks/form/component-info.js +0 -262
  60. package/src/blocks/form/form.jsx +0 -253
  61. package/src/blocks/fragment/component-info.js +0 -11
  62. package/src/blocks/fragment/fragment.jsx +0 -5
  63. package/src/blocks/image/component-info.js +0 -151
  64. package/src/blocks/image/image.helpers.js +0 -48
  65. package/src/blocks/image/image.jsx +0 -122
  66. package/src/blocks/img/component-info.js +0 -20
  67. package/src/blocks/img/img.jsx +0 -17
  68. package/src/blocks/input/component-info.js +0 -74
  69. package/src/blocks/input/input.jsx +0 -19
  70. package/src/blocks/raw-text/component-info.js +0 -16
  71. package/src/blocks/raw-text/raw-text.jsx +0 -10
  72. package/src/blocks/section/component-info.js +0 -49
  73. package/src/blocks/section/section.jsx +0 -27
  74. package/src/blocks/select/component-info.js +0 -59
  75. package/src/blocks/select/select.jsx +0 -20
  76. package/src/blocks/submit-button/component-info.js +0 -28
  77. package/src/blocks/submit-button/submit-button.jsx +0 -9
  78. package/src/blocks/symbol/component-info.js +0 -43
  79. package/src/blocks/symbol/symbol.jsx +0 -84
  80. package/src/blocks/text/component-info.js +0 -24
  81. package/src/blocks/text/text.jsx +0 -10
  82. package/src/blocks/textarea/component-info.js +0 -47
  83. package/src/blocks/textarea/textarea.jsx +0 -13
  84. package/src/blocks/util.js +0 -8
  85. package/src/blocks/video/component-info.js +0 -106
  86. package/src/blocks/video/video.jsx +0 -58
  87. package/src/components/render-block/block-styles.jsx +0 -69
  88. package/src/components/render-block/render-block.helpers.js +0 -23
  89. package/src/components/render-block/render-block.jsx +0 -252
  90. package/src/components/render-block/render-component-with-context.jsx +0 -38
  91. package/src/components/render-block/render-component.jsx +0 -33
  92. package/src/components/render-block/render-repeated-block.jsx +0 -33
  93. package/src/components/render-block/types.js +0 -0
  94. package/src/components/render-blocks.jsx +0 -89
  95. package/src/components/render-content/builder-editing.jsx +0 -5
  96. package/src/components/render-content/components/render-styles.jsx +0 -64
  97. package/src/components/render-content/index.js +0 -4
  98. package/src/components/render-content/render-content.jsx +0 -370
  99. package/src/components/render-inlined-styles.jsx +0 -28
  100. package/src/constants/builder-registered-components.js +0 -54
  101. package/src/constants/device-sizes.js +0 -48
  102. package/src/constants/target.js +0 -4
  103. package/src/context/builder.context.js +0 -12
  104. package/src/context/types.js +0 -0
  105. package/src/functions/camel-to-kebab-case.js +0 -4
  106. package/src/functions/evaluate.js +0 -29
  107. package/src/functions/event-handler-name.js +0 -7
  108. package/src/functions/extract-text-styles.js +0 -22
  109. package/src/functions/fast-clone.js +0 -4
  110. package/src/functions/get-block-actions-handler.js +0 -11
  111. package/src/functions/get-block-actions.js +0 -18
  112. package/src/functions/get-block-component-options.js +0 -28
  113. package/src/functions/get-block-properties.js +0 -50
  114. package/src/functions/get-block-tag.js +0 -6
  115. package/src/functions/get-builder-search-params/fn.test.js +0 -13
  116. package/src/functions/get-builder-search-params/index.js +0 -38
  117. package/src/functions/get-content/ab-testing.js +0 -99
  118. package/src/functions/get-content/generate-content-url.js +0 -55
  119. package/src/functions/get-content/generate-content-url.test.js +0 -31
  120. package/src/functions/get-content/index.js +0 -65
  121. package/src/functions/get-content/types.js +0 -0
  122. package/src/functions/get-fetch.js +0 -14
  123. package/src/functions/get-global-this.js +0 -18
  124. package/src/functions/get-processed-block.js +0 -59
  125. package/src/functions/get-processed-block.test.js +0 -32
  126. package/src/functions/get-react-native-block-styles.js +0 -33
  127. package/src/functions/if-target.js +0 -15
  128. package/src/functions/is-browser.js +0 -6
  129. package/src/functions/is-editing.js +0 -7
  130. package/src/functions/is-iframe.js +0 -7
  131. package/src/functions/is-previewing.js +0 -14
  132. package/src/functions/on-change.js +0 -27
  133. package/src/functions/on-change.test.js +0 -19
  134. package/src/functions/register-component.js +0 -68
  135. package/src/functions/register.js +0 -29
  136. package/src/functions/sanitize-react-native-block-styles.js +0 -66
  137. package/src/functions/set-editor-settings.js +0 -15
  138. package/src/functions/set.js +0 -11
  139. package/src/functions/set.test.js +0 -16
  140. package/src/functions/track.js +0 -124
  141. package/src/functions/transform-block-properties.js +0 -6
  142. package/src/functions/transform-block.js +0 -6
  143. package/src/helpers/ab-tests.js +0 -16
  144. package/src/helpers/cookie.js +0 -81
  145. package/src/helpers/css.js +0 -34
  146. package/src/helpers/flatten.js +0 -34
  147. package/src/helpers/localStorage.js +0 -35
  148. package/src/helpers/nullable.js +0 -4
  149. package/src/helpers/sessionId.js +0 -52
  150. package/src/helpers/time.js +0 -5
  151. package/src/helpers/url.js +0 -13
  152. package/src/helpers/url.test.js +0 -21
  153. package/src/helpers/uuid.js +0 -13
  154. package/src/helpers/visitorId.js +0 -34
  155. package/src/index-helpers/blocks-exports.js +0 -22
  156. package/src/index-helpers/top-of-file.js +0 -4
  157. package/src/index.js +0 -14
  158. package/src/scripts/init-editing.js +0 -93
  159. package/src/types/builder-block.js +0 -0
  160. package/src/types/builder-content.js +0 -0
  161. package/src/types/can-track.js +0 -0
  162. package/src/types/components.js +0 -0
  163. package/src/types/deep-partial.js +0 -0
  164. package/src/types/element.js +0 -0
  165. package/src/types/targets.js +0 -0
  166. package/src/types/typescript.js +0 -0
package/CHANGELOG.md CHANGED
@@ -1,4 +1,15 @@
1
+ ### 0.2.2
2
+
3
+ - Fix: dynamic bindings for Link URLs.
4
+ - Fix: previewing content that includes a symbol whose `model` property is a `page`.
5
+ - Fix: "Show If"/"Hide If" bindings when the initial value is `undefined`.
6
+
7
+ ### 0.2.1
8
+
9
+ - No Changes.
10
+
1
11
  ### 0.2.0
12
+
2
13
  - Sets the default `apiVersion` to `v3`.
3
14
 
4
15
  In case you feel the need to use our older API Version `v2`, reach out to us at support@builder.io first. But you can override the default by setting `apiVersion` explicitly to `v2` as follows:
@@ -8,6 +19,7 @@ In case you feel the need to use our older API Version `v2`, reach out to us at
8
19
  ```
9
20
 
10
21
  ```js
11
- getContent({ apiVersion: "v2" })
22
+ getContent({ apiVersion: 'v2' });
12
23
  ```
24
+
13
25
  More details on the Builder API Versions visit [this link](https://www.builder.io/c/docs/content-api-versions).
@@ -4,6 +4,7 @@ import RenderContent from "../../components/render-content/render-content";
4
4
  import BuilderContext from "../../context/builder.context.js";
5
5
  import { getContent } from "../../functions/get-content/index.js";
6
6
  import { TARGET } from "../../constants/target";
7
+ import { logger } from "../../helpers/logger";
7
8
  function Symbol(props) {
8
9
  const [className, setClassName] = useState(() => [
9
10
  ...(TARGET === "vue2" || TARGET === "vue3"
@@ -46,7 +47,7 @@ function Symbol(props) {
46
47
  }
47
48
  })
48
49
  .catch((err) => {
49
- console.error("[Builder.io]: Could not fetch symbol content: ", err);
50
+ logger.error("Could not fetch symbol content: ", err);
50
51
  });
51
52
  }
52
53
  }
@@ -32,6 +32,9 @@ function BlockStyles(props) {
32
32
  const mediumStyles = styles?.medium;
33
33
  const smallStyles = styles?.small;
34
34
  const className = useBlock().id;
35
+ if (!className) {
36
+ return "";
37
+ }
35
38
  const largeStylesClass = largeStyles
36
39
  ? createCssClass({
37
40
  className,
@@ -101,4 +101,19 @@ const getRepeatItemData = ({ block, context }) => {
101
101
  }));
102
102
  return repeatArray;
103
103
  };
104
- export { getComponent, getRepeatItemData, isEmptyHtmlElement };
104
+ const getProxyState = (context) => {
105
+ if (typeof Proxy === "undefined") {
106
+ console.error("no Proxy available in this environment, cannot proxy state.");
107
+ return context.state;
108
+ }
109
+ const useState = new Proxy(context.state, {
110
+ set: (obj, prop, value) => {
111
+ var _a;
112
+ obj[prop] = value;
113
+ (_a = context.setState) == null ? void 0 : _a.call(context, obj);
114
+ return true;
115
+ }
116
+ });
117
+ return useState;
118
+ };
119
+ export { getComponent, getProxyState, getRepeatItemData, isEmptyHtmlElement };
@@ -3,24 +3,23 @@ import { useState } from "react";
3
3
  import { getBlockActions } from "../../functions/get-block-actions.js";
4
4
  import { getBlockComponentOptions } from "../../functions/get-block-component-options.js";
5
5
  import { getBlockProperties } from "../../functions/get-block-properties.js";
6
- import { getBlockTag } from "../../functions/get-block-tag.js";
7
6
  import { getProcessedBlock } from "../../functions/get-processed-block.js";
8
7
  import BlockStyles from "./block-styles";
9
- import { getComponent, getRepeatItemData, isEmptyHtmlElement, } from "./render-block.helpers.js";
8
+ import { getComponent, getProxyState, getRepeatItemData, isEmptyHtmlElement, } from "./render-block.helpers.js";
10
9
  import RenderRepeatedBlock from "./render-repeated-block";
11
10
  import { TARGET } from "../../constants/target.js";
12
11
  import { extractTextStyles } from "../../functions/extract-text-styles.js";
13
12
  import RenderComponent from "./render-component";
14
13
  import { getReactNativeBlockStyles } from "../../functions/get-react-native-block-styles.js";
15
- import { checkIsDefined } from "../../helpers/nullable.js";
16
14
  function RenderBlock(props) {
17
15
  const [component, setComponent] = useState(() => getComponent({
18
16
  block: props.block,
19
17
  context: props.context,
20
18
  }));
21
- function tag() {
22
- return getBlockTag(useBlock());
23
- }
19
+ const [repeatItemData, setRepeatItemData] = useState(() => getRepeatItemData({
20
+ block: props.block,
21
+ context: props.context,
22
+ }));
24
23
  function useBlock() {
25
24
  return repeatItemData
26
25
  ? props.block
@@ -31,35 +30,21 @@ function RenderBlock(props) {
31
30
  shouldEvaluateBindings: true,
32
31
  });
33
32
  }
33
+ const [tag, setTag] = useState(() => props.block.tagName || "div");
34
34
  function canShowBlock() {
35
- if (checkIsDefined(useBlock().hide)) {
35
+ if ("hide" in useBlock()) {
36
36
  return !useBlock().hide;
37
37
  }
38
- if (checkIsDefined(useBlock().show)) {
38
+ if ("show" in useBlock()) {
39
39
  return useBlock().show;
40
40
  }
41
41
  return true;
42
42
  }
43
- function proxyState() {
44
- if (typeof Proxy === "undefined") {
45
- console.error("no Proxy available in this environment, cannot proxy state.");
46
- return props.context.state;
47
- }
48
- const useState = new Proxy(props.context.state, {
49
- set: (obj, prop, value) => {
50
- // set the value on the state object, so that the event handler instantly gets the update.
51
- obj[prop] = value;
52
- // set the value in the context, so that the rest of the app gets the update.
53
- props.context.setState?.(obj);
54
- return true;
55
- },
56
- });
57
- return useState;
58
- }
43
+ const [proxyState, setProxyState] = useState(() => getProxyState(props.context));
59
44
  function actions() {
60
45
  return getBlockActions({
61
46
  block: useBlock(),
62
- state: proxyState(),
47
+ state: TARGET === "qwik" ? props.context.state : proxyState,
63
48
  context: props.context.context,
64
49
  });
65
50
  }
@@ -78,28 +63,6 @@ function RenderBlock(props) {
78
63
  : {}),
79
64
  };
80
65
  }
81
- function renderComponentProps() {
82
- return {
83
- blockChildren: useBlock().children ?? [],
84
- componentRef: component?.component,
85
- componentOptions: {
86
- ...getBlockComponentOptions(useBlock()),
87
- /**
88
- * These attributes are passed to the wrapper element when there is one. If `noWrap` is set to true, then
89
- * they are provided to the component itself directly.
90
- */
91
- ...(!component?.noWrap
92
- ? {}
93
- : {
94
- attributes: {
95
- ...attributes(),
96
- ...actions(),
97
- },
98
- }),
99
- },
100
- context: childrenContext(),
101
- };
102
- }
103
66
  function childrenWithoutParentComponent() {
104
67
  /**
105
68
  * When there is no `componentRef`, there might still be children that need to be rendered. In this case,
@@ -110,10 +73,6 @@ function RenderBlock(props) {
110
73
  const shouldRenderChildrenOutsideRef = !component?.component && !repeatItemData;
111
74
  return shouldRenderChildrenOutsideRef ? useBlock().children ?? [] : [];
112
75
  }
113
- const [repeatItemData, setRepeatItemData] = useState(() => getRepeatItemData({
114
- block: props.block,
115
- context: props.context,
116
- }));
117
76
  function childrenContext() {
118
77
  const getInheritedTextStyles = () => {
119
78
  if (TARGET !== "reactNative") {
@@ -136,12 +95,34 @@ function RenderBlock(props) {
136
95
  inheritedStyles: getInheritedTextStyles(),
137
96
  };
138
97
  }
139
- const TagRef = tag();
98
+ function renderComponentProps() {
99
+ return {
100
+ blockChildren: useBlock().children ?? [],
101
+ componentRef: component?.component,
102
+ componentOptions: {
103
+ ...getBlockComponentOptions(useBlock()),
104
+ /**
105
+ * These attributes are passed to the wrapper element when there is one. If `noWrap` is set to true, then
106
+ * they are provided to the component itself directly.
107
+ */
108
+ ...(!component?.noWrap
109
+ ? {}
110
+ : {
111
+ attributes: {
112
+ ...attributes(),
113
+ ...actions(),
114
+ },
115
+ }),
116
+ },
117
+ context: childrenContext(),
118
+ };
119
+ }
120
+ const TagRef = tag;
140
121
  return (React.createElement(React.Fragment, null, canShowBlock() ? (React.createElement(React.Fragment, null, !component?.noWrap ? (React.createElement(React.Fragment, null,
141
- isEmptyHtmlElement(tag()) ? (React.createElement(React.Fragment, null,
122
+ isEmptyHtmlElement(tag) ? (React.createElement(React.Fragment, null,
142
123
  React.createElement(TagRef, { ...attributes(), ...actions() }))) : null,
143
- !isEmptyHtmlElement(tag()) && repeatItemData ? (React.createElement(React.Fragment, null, repeatItemData?.map((data, index) => (React.createElement(RenderRepeatedBlock, { key: index, repeatContext: data.context, block: data.block }))))) : null,
144
- !isEmptyHtmlElement(tag()) && !repeatItemData ? (React.createElement(React.Fragment, null,
124
+ !isEmptyHtmlElement(tag) && repeatItemData ? (React.createElement(React.Fragment, null, repeatItemData?.map((data, index) => (React.createElement(RenderRepeatedBlock, { key: index, repeatContext: data.context, block: data.block }))))) : null,
125
+ !isEmptyHtmlElement(tag) && !repeatItemData ? (React.createElement(React.Fragment, null,
145
126
  React.createElement(TagRef, { ...attributes(), ...actions() },
146
127
  React.createElement(RenderComponent, { ...renderComponentProps() }),
147
128
  childrenWithoutParentComponent()?.map((child) => (React.createElement(RenderBlock, { key: "render-block-" + child.id, block: child, context: childrenContext() }))),
@@ -17,6 +17,7 @@ import { checkIsDefined } from "../../helpers/nullable.js";
17
17
  import { getInteractionPropertiesForEvent } from "../../functions/track/interaction.js";
18
18
  import { getContentInitialValue, getContextStateInitialValue, } from "./render-content.helpers.js";
19
19
  import { TARGET } from "../../constants/target.js";
20
+ import { logger } from "../../helpers/logger.js";
20
21
  function RenderContent(props) {
21
22
  const elementRef = useRef(null);
22
23
  const [forceReRenderCount, setForceReRenderCount] = useState(() => 0);
@@ -186,7 +187,7 @@ function RenderContent(props) {
186
187
  }
187
188
  useEffect(() => {
188
189
  if (!props.apiKey) {
189
- console.error("[Builder.io]: No API key provided to `RenderContent` component. This can cause issues. Please provide an API key using the `apiKey` prop.");
190
+ logger.error("No API key provided to `RenderContent` component. This can cause issues. Please provide an API key using the `apiKey` prop.");
190
191
  }
191
192
  if (isBrowser()) {
192
193
  if (isEditing()) {
@@ -225,19 +226,19 @@ function RenderContent(props) {
225
226
  // override normal content in preview mode
226
227
  if (isPreviewing()) {
227
228
  const searchParams = new URL(location.href).searchParams;
228
- const searchParamPreview = searchParams.get("builder.preview");
229
+ const searchParamPreviewModel = searchParams.get("builder.preview");
230
+ const searchParamPreviewId = searchParams.get(`builder.preview.${searchParamPreviewModel}`);
229
231
  const previewApiKey = searchParams.get("apiKey") || searchParams.get("builder.space");
230
232
  /**
231
233
  * Make sure that:
232
234
  * - the preview model name is the same as the one we're rendering, since there can be multiple models rendered * at the same time, e.g. header/page/footer. * - the API key is the same, since we don't want to preview content from other organizations.
233
- *
234
- * TO-DO: should we check that the preview item ID is the same as the initial one being rendered? Or would
235
- * this break scenarios where the item is not published yet?
235
+ * - if there is content, that the preview ID is the same as that of the one we receive.
236
236
  *
237
237
  * TO-DO: should we only update the state when there is a change?
238
238
  **/
239
- if (searchParamPreview === props.model &&
240
- previewApiKey === props.apiKey) {
239
+ if (searchParamPreviewModel === props.model &&
240
+ previewApiKey === props.apiKey &&
241
+ (!props.content || searchParamPreviewId === props.content.id)) {
241
242
  getContent({
242
243
  model: props.model,
243
244
  apiKey: props.apiKey,
@@ -0,0 +1,98 @@
1
+ const variantScriptFn = function main(contentId, variants) {
2
+ console.log("Running variant script", JSON.stringify({ contentId, variants }));
3
+ if (!navigator.cookieEnabled) {
4
+ console.log("Cookies are disabled, skipping variant script");
5
+ return;
6
+ }
7
+ const templateSelectorById = (id) => `template[data-template-variant-id="${id}"]`;
8
+ function removeTemplates() {
9
+ console.log("Removing variants");
10
+ variants.forEach((template) => {
11
+ const el2 = document.querySelector(templateSelectorById(template.id));
12
+ if (el2) {
13
+ console.log("Removing variant", template.id);
14
+ el2.remove();
15
+ }
16
+ });
17
+ const el = document.getElementById(`variants-script-${contentId}`);
18
+ if (el) {
19
+ console.log("Removing variant script");
20
+ el.remove();
21
+ }
22
+ }
23
+ if (typeof document.createElement("template").content === "undefined") {
24
+ console.log("Template polyfill not found, skipping variant script");
25
+ removeTemplates();
26
+ return;
27
+ }
28
+ function setCookie(name, value, days) {
29
+ let expires = "";
30
+ if (days) {
31
+ const date = new Date();
32
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1e3);
33
+ expires = "; expires=" + date.toUTCString();
34
+ }
35
+ document.cookie = name + "=" + (value || "") + expires + "; path=/; Secure; SameSite=None";
36
+ }
37
+ function getCookie(name) {
38
+ const nameEQ = name + "=";
39
+ const ca = document.cookie.split(";");
40
+ for (let i = 0; i < ca.length; i++) {
41
+ let c = ca[i];
42
+ while (c.charAt(0) == " ")
43
+ c = c.substring(1, c.length);
44
+ if (c.indexOf(nameEQ) == 0)
45
+ return c.substring(nameEQ.length, c.length);
46
+ }
47
+ return null;
48
+ }
49
+ function getAndSetVariantId() {
50
+ const cookieName = `builder.tests.${contentId}`;
51
+ const variantInCookie = getCookie(cookieName);
52
+ const availableIDs = variants.map((vr) => vr.id).concat(contentId);
53
+ if (variantInCookie && availableIDs.indexOf(variantInCookie) > -1) {
54
+ return variantInCookie;
55
+ }
56
+ let n = 0;
57
+ const random = Math.random();
58
+ for (let i = 0; i < variants.length; i++) {
59
+ const variant = variants[i];
60
+ const testRatio = variant.testRatio;
61
+ n += testRatio;
62
+ if (random < n) {
63
+ setCookie(cookieName, variant.id);
64
+ return variant.id;
65
+ }
66
+ }
67
+ setCookie(cookieName, contentId);
68
+ return contentId;
69
+ }
70
+ const variantId = getAndSetVariantId();
71
+ if (variantId !== contentId) {
72
+ console.log("Variant found", variantId);
73
+ const winningTemplate = document.querySelector(templateSelectorById(variantId));
74
+ console.log("winningTemplate", winningTemplate);
75
+ if (!winningTemplate) {
76
+ console.log("No template found for variant", variantId);
77
+ console.log("selector: ", templateSelectorById(variantId));
78
+ return;
79
+ }
80
+ const templatesParent = winningTemplate.parentNode;
81
+ if (templatesParent) {
82
+ templatesParent.replaceChild(winningTemplate.content.firstElementChild, winningTemplate);
83
+ }
84
+ }
85
+ else if (variants.length > 0) {
86
+ console.log("No variant found, removing all variants");
87
+ }
88
+ removeTemplates();
89
+ console.log("Variant script complete");
90
+ };
91
+ const getVariantsScriptString = (variants, contentId) => {
92
+ const fnStr = variantScriptFn.toString().replace(/\s+/g, " ");
93
+ return `
94
+ ${fnStr}
95
+ main("${contentId}", ${JSON.stringify(variants)})
96
+ `;
97
+ };
98
+ export { getVariantsScriptString };
@@ -0,0 +1,45 @@
1
+ import * as React from "react";
2
+ import { useState, useEffect } from "react";
3
+ import { isBrowser } from "../../functions/is-browser";
4
+ import { getVariantsScriptString } from "./helpers";
5
+ import RenderContent from "../render-content/render-content";
6
+ import { checkIsDefined } from "../../helpers/nullable";
7
+ import { handleABTestingSync } from "../../helpers/ab-tests";
8
+ import { TARGET } from "../../constants/target";
9
+ function RenderContentVariants(props) {
10
+ const [variantScriptStr, setVariantScriptStr] = useState(() => getVariantsScriptString(Object.values(props.content?.variations || {}).map((value) => ({
11
+ id: value.id,
12
+ testRatio: value.testRatio,
13
+ })), props.content?.id || ""));
14
+ const [variants, setVariants] = useState(() => [
15
+ ...Object.values(props.content?.variations || {}),
16
+ props.content,
17
+ ]);
18
+ const [contentToUse, setContentToUse] = useState(() => ((isBrowser() && props.canTrack) || !isBrowser()) &&
19
+ Object.keys(props.content?.variations || {}).length > 0
20
+ ? undefined
21
+ : handleABTestingSync({
22
+ item: props.content,
23
+ canTrack: checkIsDefined(props.canTrack) ? props.canTrack : true,
24
+ }));
25
+ const [shouldRenderVariants, setShouldRenderVariants] = useState(() => ((isBrowser() && props.canTrack) || !isBrowser()) &&
26
+ Object.keys(props.content?.variations || {}).length > 0);
27
+ useEffect(() => {
28
+ if (TARGET === "svelte" && shouldRenderVariants) {
29
+ // get first template in loop
30
+ const templates = document.querySelectorAll(`template[data-template-variant-id="${variants[0]?.id}"]`);
31
+ const lastTemplate = templates[templates.length - 1];
32
+ // create and append script as sibling of template
33
+ const script = document.createElement("script");
34
+ script.id = `variants-script-${props.content?.id}`;
35
+ script.innerHTML = variantScriptStr;
36
+ lastTemplate?.parentNode?.append(script, lastTemplate);
37
+ }
38
+ }, []);
39
+ return (React.createElement(React.Fragment, null, shouldRenderVariants ? (React.createElement(React.Fragment, null,
40
+ variants?.map((variant) => (React.createElement("template", { key: variant?.id, "data-template-variant-id": variant?.id },
41
+ React.createElement(RenderContent, { content: variant, apiKey: props.apiKey, apiVersion: props.apiVersion, canTrack: props.canTrack, customComponents: props.customComponents })))),
42
+ React.createElement("script", { id: `variants-script-${props.content?.id}`, dangerouslySetInnerHTML: { __html: variantScriptStr } }),
43
+ React.createElement(RenderContent, { content: contentToUse, apiKey: props.apiKey, apiVersion: props.apiVersion, canTrack: props.canTrack, customComponents: props.customComponents }))) : (React.createElement(RenderContent, { content: contentToUse, apiKey: props.apiKey, apiVersion: props.apiVersion, canTrack: props.canTrack, customComponents: props.customComponents }))));
44
+ }
45
+ export default RenderContentVariants;
@@ -1,14 +1,14 @@
1
1
  import * as React from "react";
2
2
  import { TARGET } from "../constants/target.js";
3
3
  function RenderInlinedStyles(props) {
4
- function injectedStyleScript() {
5
- return `<${tag()}>${props.styles}</${tag()}>`;
6
- }
7
4
  function tag() {
8
5
  // NOTE: we have to obfusctate the name of the tag due to a limitation in the svelte-preprocessor plugin.
9
6
  // https://github.com/sveltejs/vite-plugin-svelte/issues/315#issuecomment-1109000027
10
7
  return "sty" + "le";
11
8
  }
9
+ function injectedStyleScript() {
10
+ return `<${tag()}>${props.styles}</${tag()}>`;
11
+ }
12
12
  const TagRef = tag();
13
13
  return (React.createElement(React.Fragment, null, TARGET === "svelte" || TARGET === "qwik" ? (React.createElement(React.Fragment, null,
14
14
  React.createElement(TagRef, { dangerouslySetInnerHTML: { __html: props.styles } }))) : (React.createElement(TagRef, null, props.styles))));
@@ -20,9 +20,12 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
  import { TARGET } from "../constants/target.js";
21
21
  import { convertStyleMapToCSSArray } from "../helpers/css.js";
22
22
  import { transformBlockProperties } from "./transform-block-properties.js";
23
+ const extractRelevantRootBlockProperties = (block) => {
24
+ return { href: block.href };
25
+ };
23
26
  function getBlockProperties(block) {
24
27
  var _a;
25
- const properties = __spreadProps(__spreadValues({}, block.properties), {
28
+ const properties = __spreadProps(__spreadValues(__spreadValues({}, extractRelevantRootBlockProperties(block)), block.properties), {
26
29
  "builder-id": block.id,
27
30
  style: getStyleAttribute(block.style),
28
31
  class: [block.id, "builder-block", block.class, (_a = block.properties) == null ? void 0 : _a.class].filter(Boolean).join(" ")
@@ -39,13 +39,14 @@ var __async = (__this, __arguments, generator) => {
39
39
  step((generator = generator.apply(__this, __arguments)).next());
40
40
  });
41
41
  };
42
+ import { logger } from "../../helpers/logger.js";
42
43
  import { fetch } from "../get-fetch.js";
43
44
  import { handleABTesting } from "./ab-testing.js";
44
45
  import { generateContentUrl } from "./generate-content-url.js";
45
46
  function getContent(options) {
46
47
  return __async(this, null, function* () {
47
48
  const allContent = yield getAllContent(__spreadProps(__spreadValues({}, options), { limit: 1 }));
48
- if ("results" in allContent) {
49
+ if (allContent && "results" in allContent) {
49
50
  return (allContent == null ? void 0 : allContent.results[0]) || null;
50
51
  }
51
52
  return null;
@@ -53,25 +54,31 @@ function getContent(options) {
53
54
  }
54
55
  function getAllContent(options) {
55
56
  return __async(this, null, function* () {
56
- const url = generateContentUrl(options);
57
- const res = yield fetch(url.href);
58
- const content = yield res.json();
59
- if ("status" in content && !("results" in content)) {
60
- console.error("[Builder.io]: Error fetching data. ", content, options);
61
- return content;
62
- }
63
- const canTrack = options.canTrack !== false;
64
57
  try {
65
- if (canTrack && Array.isArray(content.results)) {
66
- for (const item of content.results) {
67
- yield handleABTesting({ item, canTrack });
58
+ const url = generateContentUrl(options);
59
+ const res = yield fetch(url.href);
60
+ const content = yield res.json();
61
+ if ("status" in content && !("results" in content)) {
62
+ logger.error("Error fetching data. ", content, options);
63
+ return content;
64
+ }
65
+ const canTrack = options.canTrack !== false;
66
+ try {
67
+ if (canTrack && Array.isArray(content.results)) {
68
+ for (const item of content.results) {
69
+ yield handleABTesting({ item, canTrack });
70
+ }
68
71
  }
69
72
  }
73
+ catch (e) {
74
+ logger.error("Could not setup A/B testing. ", e);
75
+ }
76
+ return content;
70
77
  }
71
- catch (e) {
72
- console.error("[Builder.io]: Could not setup A/B testing. ", e);
78
+ catch (error) {
79
+ logger.error("Error fetching data. ", error);
80
+ return null;
73
81
  }
74
- return content;
75
82
  });
76
83
  }
77
84
  export { getAllContent, getContent };
@@ -52,6 +52,7 @@ var __async = (__this, __arguments, generator) => {
52
52
  });
53
53
  };
54
54
  import { TARGET } from "../../constants/target.js";
55
+ import { logger } from "../../helpers/logger.js";
55
56
  import { getSessionId } from "../../helpers/sessionId.js";
56
57
  import { getVisitorId } from "../../helpers/visitorId.js";
57
58
  import { isBrowser } from "../is-browser.js";
@@ -90,7 +91,7 @@ const createEvent = (_a) => __async(void 0, null, function* () {
90
91
  function _track(eventProps) {
91
92
  return __async(this, null, function* () {
92
93
  if (!eventProps.apiKey) {
93
- console.error("[Builder.io]: Missing API key for track call. Please provide your API key.");
94
+ logger.error("Missing API key for track call. Please provide your API key.");
94
95
  return;
95
96
  }
96
97
  if (!eventProps.canTrack) {
@@ -0,0 +1,7 @@
1
+ const MSG_PREFIX = "[Builder.io]: ";
2
+ const logger = {
3
+ log: (...message) => console.log(MSG_PREFIX, ...message),
4
+ error: (...message) => console.error(MSG_PREFIX, ...message),
5
+ warn: (...message) => console.warn(MSG_PREFIX, ...message)
6
+ };
7
+ export { logger };
@@ -3,6 +3,7 @@ import RenderContent from "../../components/render-content/render-content";
3
3
  import BuilderContext from "../../context/builder.context.js";
4
4
  import { getContent } from "../../functions/get-content/index.js";
5
5
  import { TARGET } from "../../constants/target";
6
+ import { logger } from "../../helpers/logger";
6
7
  function Symbol(props) {
7
8
  const _context = { ...props["_context"] };
8
9
  const state = {
@@ -47,7 +48,7 @@ function Symbol(props) {
47
48
  }
48
49
  })
49
50
  .catch((err) => {
50
- console.error("[Builder.io]: Could not fetch symbol content: ", err);
51
+ logger.error("Could not fetch symbol content: ", err);
51
52
  });
52
53
  }
53
54
  },
@@ -34,6 +34,9 @@ function BlockStyles(props) {
34
34
  const mediumStyles = styles?.medium;
35
35
  const smallStyles = styles?.small;
36
36
  const className = state.useBlock.id;
37
+ if (!className) {
38
+ return "";
39
+ }
37
40
  const largeStylesClass = largeStyles
38
41
  ? createCssClass({
39
42
  className,
@@ -101,4 +101,19 @@ const getRepeatItemData = ({ block, context }) => {
101
101
  }));
102
102
  return repeatArray;
103
103
  };
104
- export { getComponent, getRepeatItemData, isEmptyHtmlElement };
104
+ const getProxyState = (context) => {
105
+ if (typeof Proxy === "undefined") {
106
+ console.error("no Proxy available in this environment, cannot proxy state.");
107
+ return context.state;
108
+ }
109
+ const useState = new Proxy(context.state, {
110
+ set: (obj, prop, value) => {
111
+ var _a;
112
+ obj[prop] = value;
113
+ (_a = context.setState) == null ? void 0 : _a.call(context, obj);
114
+ return true;
115
+ }
116
+ });
117
+ return useState;
118
+ };
119
+ export { getComponent, getProxyState, getRepeatItemData, isEmptyHtmlElement };