@builder.io/sdk-solid 0.0.8-15 → 0.0.8-16

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builder.io/sdk-solid",
3
- "version": "0.0.8-15",
3
+ "version": "0.0.8-16",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./src/solid-index.jsx",
@@ -186,7 +186,31 @@ const componentInfo = {
186
186
  ]
187
187
  }
188
188
  ],
189
- onChange: " function clearWidths() { columns.forEach(col => { col.delete('width'); }); } const columns = options.get('columns') as Array<Map<String, any>>; if (Array.isArray(columns)) { const containsColumnWithWidth = !!columns.find(col => col.get('width')); if (containsColumnWithWidth) { const containsColumnWithoutWidth = !!columns.find(col => !col.get('width')); if (containsColumnWithoutWidth) { clearWidths(); } else { const sumWidths = columns.reduce((memo, col) => { return memo + col.get('width'); }, 0); const widthsDontAddUp = sumWidths !== 100; if (widthsDontAddUp) { clearWidths(); } } } } "
189
+ onChange(options) {
190
+ function clearWidths() {
191
+ columns.forEach((col) => {
192
+ col.delete("width");
193
+ });
194
+ }
195
+ const columns = options.get("columns");
196
+ if (Array.isArray(columns)) {
197
+ const containsColumnWithWidth = !!columns.find((col) => col.get("width"));
198
+ if (containsColumnWithWidth) {
199
+ const containsColumnWithoutWidth = !!columns.find((col) => !col.get("width"));
200
+ if (containsColumnWithoutWidth) {
201
+ clearWidths();
202
+ } else {
203
+ const sumWidths = columns.reduce((memo, col) => {
204
+ return memo + col.get("width");
205
+ }, 0);
206
+ const widthsDontAddUp = sumWidths !== 100;
207
+ if (widthsDontAddUp) {
208
+ clearWidths();
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
190
214
  },
191
215
  {
192
216
  name: "space",
@@ -1,4 +1,4 @@
1
- import { onMount, useRef } from "solid-js";
1
+ import { onMount } from "solid-js";
2
2
  import { createMutable } from "solid-js/store";
3
3
 
4
4
  function CustomCode(props) {
@@ -41,7 +41,7 @@ function CustomCode(props) {
41
41
  }
42
42
 
43
43
  });
44
- const elem = useRef();
44
+ let elem;
45
45
  onMount(() => {
46
46
  state.findAndRunScripts();
47
47
  });
@@ -9,7 +9,26 @@ const componentInfo = {
9
9
  required: true,
10
10
  defaultValue: "",
11
11
  helperText: "e.g. enter a youtube url, google map, etc",
12
- onChange: " const url = options.get('url'); if (url) { options.set('content', 'Loading...'); // TODO: get this out of here! const apiKey = 'ae0e60e78201a3f2b0de4b'; return fetch(`https://iframe.ly/api/iframely?url=${url}&api_key=${apiKey}`) .then(res => res.json()) .then(data => { if (options.get('url') === url) { if (data.html) { options.set('content', data.html); } else { options.set('content', 'Invalid url, please try another'); } } }) .catch(err => { options.set( 'content', 'There was an error embedding this URL, please try again or another URL' ); }); } else { options.delete('content'); } "
12
+ onChange(options) {
13
+ const url = options.get("url");
14
+ if (url) {
15
+ options.set("content", "Loading...");
16
+ const apiKey = "ae0e60e78201a3f2b0de4b";
17
+ return fetch(`https://iframe.ly/api/iframely?url=${url}&api_key=${apiKey}`).then((res) => res.json()).then((data) => {
18
+ if (options.get("url") === url) {
19
+ if (data.html) {
20
+ options.set("content", data.html);
21
+ } else {
22
+ options.set("content", "Invalid url, please try another");
23
+ }
24
+ }
25
+ }).catch((_err) => {
26
+ options.set("content", "There was an error embedding this URL, please try again or another URL");
27
+ });
28
+ } else {
29
+ options.delete("content");
30
+ }
31
+ }
13
32
  },
14
33
  {
15
34
  name: "content",
@@ -1,50 +1,47 @@
1
- import { onMount, useRef } from "solid-js";
1
+ import { on, createEffect } from "solid-js";
2
2
  import { createMutable } from "solid-js/store";
3
+ import { isJsScript } from "./helpers";
3
4
 
4
5
  function Embed(props) {
5
6
  const state = createMutable({
6
7
  scriptsInserted: [],
7
8
  scriptsRun: [],
9
+ ranInitFn: false,
8
10
 
9
11
  findAndRunScripts() {
10
- // TODO: Move this function to standalone one in '@builder.io/utils'
11
- if (elem && typeof window !== "undefined") {
12
- const scripts = elem.getElementsByTagName("script");
13
-
14
- for (let i = 0; i < scripts.length; i++) {
15
- const script = scripts[i];
16
-
17
- if (script.src) {
18
- if (state.scriptsInserted.includes(script.src)) {
19
- continue;
20
- }
21
-
22
- state.scriptsInserted.push(script.src);
23
- const newScript = document.createElement("script");
24
- newScript.async = true;
25
- newScript.src = script.src;
26
- document.head.appendChild(newScript);
27
- } else if (!script.type || ["text/javascript", "application/javascript", "application/ecmascript"].includes(script.type)) {
28
- if (state.scriptsRun.includes(script.innerText)) {
29
- continue;
30
- }
31
-
32
- try {
33
- state.scriptsRun.push(script.innerText);
34
- new Function(script.innerText)();
35
- } catch (error) {
36
- console.warn("`Embed`: Error running script:", error);
37
- }
12
+ const scripts = elem.getElementsByTagName("script");
13
+
14
+ for (let i = 0; i < scripts.length; i++) {
15
+ const script = scripts[i];
16
+
17
+ if (script.src && !state.scriptsInserted.includes(script.src)) {
18
+ state.scriptsInserted.push(script.src);
19
+ const newScript = document.createElement("script");
20
+ newScript.async = true;
21
+ newScript.src = script.src;
22
+ document.head.appendChild(newScript);
23
+ } else if (isJsScript(script) && !state.scriptsRun.includes(script.innerText)) {
24
+ try {
25
+ state.scriptsRun.push(script.innerText);
26
+ new Function(script.innerText)();
27
+ } catch (error) {
28
+ console.warn("`Embed`: Error running script:", error);
38
29
  }
39
30
  }
40
31
  }
41
32
  }
42
33
 
43
34
  });
44
- const elem = useRef();
45
- onMount(() => {
46
- state.findAndRunScripts();
47
- });
35
+ let elem;
36
+
37
+ function onUpdateFn_0() {
38
+ if (elem && !state.ranInitFn) {
39
+ state.ranInitFn = true;
40
+ state.findAndRunScripts();
41
+ }
42
+ }
43
+
44
+ createEffect(on(() => [elem, state.ranInitFn], onUpdateFn_0));
48
45
  return <div class="builder-embed" ref={elem} innerHTML={props.content}></div>;
49
46
  }
50
47
 
@@ -0,0 +1,9 @@
1
+ const SCRIPT_MIME_TYPES = [
2
+ "text/javascript",
3
+ "application/javascript",
4
+ "application/ecmascript"
5
+ ];
6
+ const isJsScript = (script) => SCRIPT_MIME_TYPES.includes(script.type);
7
+ export {
8
+ isJsScript
9
+ };
@@ -1,4 +1,4 @@
1
- import { Show, For, useRef } from "solid-js";
1
+ import { Show, For } from "solid-js";
2
2
  import { createMutable } from "solid-js/store";
3
3
  import { css } from "solid-styled-components";
4
4
  import RenderBlock from "../../components/render-block/render-block.jsx";
@@ -218,7 +218,7 @@ function FormComponent(props) {
218
218
  }
219
219
 
220
220
  });
221
- const formRef = useRef();
221
+ let formRef;
222
222
  return <form {...props.attributes} validate={props.validate} ref={formRef} action={!props.sendWithJs && props.action} method={props.method} name={props.name} onSubmit={event => state.onSubmit(event)}>
223
223
  <Show when={props.builderBlock && props.builderBlock.children}>
224
224
  <For each={props.builderBlock?.children}>
@@ -18,7 +18,53 @@ const componentInfo = {
18
18
  allowedFileTypes: ["jpeg", "jpg", "png", "svg"],
19
19
  required: true,
20
20
  defaultValue: "https://cdn.builder.io/api/v1/image/assets%2Fpwgjf0RoYWbdnJSbpBAjXNRMe9F2%2Ffb27a7c790324294af8be1c35fe30f4d",
21
- onChange: " const DEFAULT_ASPECT_RATIO = 0.7041; options.delete('srcset'); options.delete('noWebp'); function loadImage(url, timeout) { return new Promise((resolve, reject) => { const img = document.createElement('img'); let loaded = false; img.onload = () => { loaded = true; resolve(img); }; img.addEventListener('error', event => { console.warn('Image load failed', event.error); reject(event.error); }); img.src = url; setTimeout(() => { if (!loaded) { reject(new Error('Image load timed out')); } }, timeout); }); } function round(num) { return Math.round(num * 1000) / 1000; } const value = options.get('image'); const aspectRatio = options.get('aspectRatio'); // For SVG images - don't render as webp, keep them as SVG fetch(value) .then(res => res.blob()) .then(blob => { if (blob.type.includes('svg')) { options.set('noWebp', true); } }); if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) { return loadImage(value).then(img => { const possiblyUpdatedAspectRatio = options.get('aspectRatio'); if ( options.get('image') === value && (!possiblyUpdatedAspectRatio || possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO) ) { if (img.width && img.height) { options.set('aspectRatio', round(img.height / img.width)); options.set('height', img.height); options.set('width', img.width); } } }); }"
21
+ onChange(options) {
22
+ const DEFAULT_ASPECT_RATIO = 0.7041;
23
+ options.delete("srcset");
24
+ options.delete("noWebp");
25
+ function loadImage(url, timeout = 6e4) {
26
+ return new Promise((resolve, reject) => {
27
+ const img = document.createElement("img");
28
+ let loaded = false;
29
+ img.onload = () => {
30
+ loaded = true;
31
+ resolve(img);
32
+ };
33
+ img.addEventListener("error", (event) => {
34
+ console.warn("Image load failed", event.error);
35
+ reject(event.error);
36
+ });
37
+ img.src = url;
38
+ setTimeout(() => {
39
+ if (!loaded) {
40
+ reject(new Error("Image load timed out"));
41
+ }
42
+ }, timeout);
43
+ });
44
+ }
45
+ function round(num) {
46
+ return Math.round(num * 1e3) / 1e3;
47
+ }
48
+ const value = options.get("image");
49
+ const aspectRatio = options.get("aspectRatio");
50
+ fetch(value).then((res) => res.blob()).then((blob) => {
51
+ if (blob.type.includes("svg")) {
52
+ options.set("noWebp", true);
53
+ }
54
+ });
55
+ if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) {
56
+ return loadImage(value).then((img) => {
57
+ const possiblyUpdatedAspectRatio = options.get("aspectRatio");
58
+ if (options.get("image") === value && (!possiblyUpdatedAspectRatio || possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO)) {
59
+ if (img.width && img.height) {
60
+ options.set("aspectRatio", round(img.height / img.width));
61
+ options.set("height", img.height);
62
+ options.set("width", img.width);
63
+ }
64
+ }
65
+ });
66
+ }
67
+ }
22
68
  },
23
69
  {
24
70
  name: "backgroundSize",
@@ -0,0 +1,48 @@
1
+ function removeProtocol(path) {
2
+ return path.replace(/http(s)?:/, "");
3
+ }
4
+ function updateQueryParam(uri = "", key, value) {
5
+ const re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
6
+ const separator = uri.indexOf("?") !== -1 ? "&" : "?";
7
+ if (uri.match(re)) {
8
+ return uri.replace(re, "$1" + key + "=" + encodeURIComponent(value) + "$2");
9
+ }
10
+ return uri + separator + key + "=" + encodeURIComponent(value);
11
+ }
12
+ function getShopifyImageUrl(src, size) {
13
+ if (!src || !(src == null ? void 0 : src.match(/cdn\.shopify\.com/)) || !size) {
14
+ return src;
15
+ }
16
+ if (size === "master") {
17
+ return removeProtocol(src);
18
+ }
19
+ const match = src.match(/(_\d+x(\d+)?)?(\.(jpg|jpeg|gif|png|bmp|bitmap|tiff|tif)(\?v=\d+)?)/i);
20
+ if (match) {
21
+ const prefix = src.split(match[0]);
22
+ const suffix = match[3];
23
+ const useSize = size.match("x") ? size : `${size}x`;
24
+ return removeProtocol(`${prefix[0]}_${useSize}${suffix}`);
25
+ }
26
+ return null;
27
+ }
28
+ function getSrcSet(url) {
29
+ if (!url) {
30
+ return url;
31
+ }
32
+ const sizes = [100, 200, 400, 800, 1200, 1600, 2e3];
33
+ if (url.match(/builder\.io/)) {
34
+ let srcUrl = url;
35
+ const widthInSrc = Number(url.split("?width=")[1]);
36
+ if (!isNaN(widthInSrc)) {
37
+ srcUrl = `${srcUrl} ${widthInSrc}w`;
38
+ }
39
+ return sizes.filter((size) => size !== widthInSrc).map((size) => `${updateQueryParam(url, "width", size)} ${size}w`).concat([srcUrl]).join(", ");
40
+ }
41
+ if (url.match(/cdn\.shopify\.com/)) {
42
+ return sizes.map((size) => [getShopifyImageUrl(url, `${size}x${size}`), size]).filter(([sizeUrl]) => !!sizeUrl).map(([sizeUrl, size]) => `${sizeUrl} ${size}w`).concat([url]).join(", ");
43
+ }
44
+ return url;
45
+ }
46
+ export {
47
+ getSrcSet
48
+ };
@@ -1,11 +1,40 @@
1
1
  import { Show } from "solid-js";
2
+ import { createMutable } from "solid-js/store";
2
3
  import { css } from "solid-styled-components";
4
+ import { getSrcSet } from "./image.helpers";
3
5
 
4
6
  function Image(props) {
7
+ const state = createMutable({
8
+ get srcSetToUse() {
9
+ const imageToUse = props.image || props.src;
10
+ const url = imageToUse;
11
+
12
+ if (!url || // We can auto add srcset for cdn.builder.io and shopify
13
+ // images, otherwise you can supply this prop manually
14
+ !(url.match(/builder\.io/) || url.match(/cdn\.shopify\.com/))) {
15
+ return props.srcset;
16
+ }
17
+
18
+ if (props.srcset && props.image?.includes("builder.io/api/v1/image")) {
19
+ if (!props.srcset.includes(props.image.split("?")[0])) {
20
+ console.debug("Removed given srcset");
21
+ return getSrcSet(url);
22
+ }
23
+ } else if (props.image && !props.srcset) {
24
+ return getSrcSet(url);
25
+ }
26
+
27
+ return getSrcSet(url);
28
+ }
29
+
30
+ });
5
31
  return <div class={css({
6
32
  position: "relative"
7
33
  })}>
8
34
  <picture>
35
+ <Show when={state.srcSetToUse?.match(/builder\.io/) && !props.noWebp}>
36
+ <source type="image/webp" srcset={state.srcSetToUse?.replace(/\?/g, "?format=webp&")} />
37
+ </Show>
9
38
  <img class={"builder-image" + (props.className ? " " + props.className : "") + " " + css({
10
39
  opacity: "1",
11
40
  transition: "opacity 0.2s ease-in-out",
@@ -17,8 +46,8 @@ function Image(props) {
17
46
  })} loading="lazy" alt={props.altText} role={props.altText ? "presentation" : undefined} style={{
18
47
  "object-position": props.backgroundSize || "center",
19
48
  "object-fit": props.backgroundSize || "cover"
20
- }} src={props.image} srcset={props.srcset} sizes={props.sizes} />
21
- <source srcset={props.srcset} />
49
+ }} src={props.image} srcset={state.srcSetToUse} sizes={props.sizes} />
50
+ <source srcset={state.srcSetToUse} />
22
51
  </picture>
23
52
  <Show when={props.aspectRatio && !(props.fitContent && props.builderBlock?.children?.length)}>
24
53
  <div class={"builder-image-sizer " + css({
@@ -26,6 +55,7 @@ function Image(props) {
26
55
  pointerEvents: "none",
27
56
  fontSize: "0"
28
57
  })} style={{
58
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
29
59
  "padding-top": props.aspectRatio * 100 + "%"
30
60
  }}></div>
31
61
  </Show>
@@ -1,7 +1,8 @@
1
- import { useContext, onMount } from "solid-js";
1
+ import { useContext, onMount, on, createEffect } from "solid-js";
2
2
  import { createMutable } from "solid-js/store";
3
3
  import RenderContent from "../../components/render-content/render-content.jsx";
4
4
  import BuilderContext from "../../context/builder.context";
5
+ import { getContent } from "../../functions/get-content/index.js";
5
6
 
6
7
  function Symbol(props) {
7
8
  const state = createMutable({
@@ -12,6 +13,33 @@ function Symbol(props) {
12
13
  onMount(() => {
13
14
  state.content = props.symbol?.content;
14
15
  });
16
+
17
+ function onUpdateFn_0() {
18
+ const symbolToUse = props.symbol;
19
+ /**
20
+ * If:
21
+ * - we have a symbol prop
22
+ * - yet it does not have any content
23
+ * - and we have not already stored content from before
24
+ * - and it has a model name
25
+ *
26
+ * then we want to re-fetch the symbol content.
27
+ */
28
+
29
+ if (symbolToUse && !symbolToUse.content && !state.content && symbolToUse.model) {
30
+ getContent({
31
+ model: symbolToUse.model,
32
+ apiKey: builderContext.apiKey,
33
+ query: {
34
+ id: symbolToUse.entry
35
+ }
36
+ }).then(response => {
37
+ state.content = response;
38
+ });
39
+ }
40
+ }
41
+
42
+ createEffect(on(() => [props.symbol?.content, props.symbol?.model, props.symbol?.entry, state.content], onUpdateFn_0));
15
43
  return <div class={state.className} {...props.attributes} dataSet={{
16
44
  class: state.className
17
45
  }}>
@@ -8,7 +8,7 @@ function Video(props) {
8
8
  // Hack to get object fit to work as expected and
9
9
  // not have the video overflow
10
10
  "border-radius": 1
11
- }} key={props.video || "no-src"} poster={props.posterImage} autoPlay={props.autoPlay} muted={props.muted} controls={props.controls} loop={props.loop}></video>;
11
+ }} src={props.video || "no-src"} poster={props.posterImage} autoPlay={props.autoPlay} muted={props.muted} controls={props.controls} loop={props.loop}></video>;
12
12
  }
13
13
 
14
14
  export default Video;
@@ -139,34 +139,30 @@ function RenderBlock(props) {
139
139
  return undefined;
140
140
  }
141
141
 
142
- const {
143
- collection,
144
- itemName
145
- } = repeat;
146
142
  const itemsArray = evaluate({
147
- code: collection,
143
+ code: repeat.collection,
148
144
  state: builderContext.state,
149
145
  context: builderContext.context
150
146
  });
151
147
 
152
- if (Array.isArray(itemsArray)) {
153
- const collectionName = collection.split(".").pop();
154
- const itemNameToUse = itemName || (collectionName ? collectionName + "Item" : "item");
155
- const repeatArray = itemsArray.map((item, index) => ({
156
- context: { ...builderContext,
157
- state: { ...builderContext.state,
158
- $index: index,
159
- $item: item,
160
- [itemNameToUse]: item,
161
- [`$${itemNameToUse}Index`]: index
162
- }
163
- },
164
- block: blockWithoutRepeat
165
- }));
166
- return repeatArray;
167
- } else {
148
+ if (!Array.isArray(itemsArray)) {
168
149
  return undefined;
169
150
  }
151
+
152
+ const collectionName = repeat.collection.split(".").pop();
153
+ const itemNameToUse = repeat.itemName || (collectionName ? collectionName + "Item" : "item");
154
+ const repeatArray = itemsArray.map((item, index) => ({
155
+ context: { ...builderContext,
156
+ state: { ...builderContext.state,
157
+ $index: index,
158
+ $item: item,
159
+ [itemNameToUse]: item,
160
+ [`$${itemNameToUse}Index`]: index
161
+ }
162
+ },
163
+ block: blockWithoutRepeat
164
+ }));
165
+ return repeatArray;
170
166
  }
171
167
 
172
168
  });
@@ -1,4 +1,4 @@
1
- import { Show, onMount } from "solid-js";
1
+ import { Show, onMount, on, createEffect } from "solid-js";
2
2
  import { Dynamic } from "solid-js/web";
3
3
  import { createMutable } from "solid-js/store";
4
4
  import { getDefaultRegisteredComponents } from "../../constants/builder-registered-components.js";
@@ -176,14 +176,14 @@ function RenderContent(props) {
176
176
 
177
177
  if (isPreviewing()) {
178
178
  if (props.model && previewingModelName() === props.model) {
179
- const currentUrl = new URL(location.href);
180
- const previewApiKey = currentUrl.searchParams.get("apiKey");
179
+ const searchParams = new URL(location.href).searchParams;
180
+ const previewApiKey = searchParams.get("apiKey") || searchParams.get("builder.space");
181
181
 
182
182
  if (previewApiKey) {
183
183
  getContent({
184
184
  model: props.model,
185
185
  apiKey: previewApiKey,
186
- options: getBuilderSearchParams(convertSearchParamsToQueryObject(currentUrl.searchParams))
186
+ options: getBuilderSearchParams(convertSearchParamsToQueryObject(searchParams))
187
187
  }).then(content => {
188
188
  if (content) {
189
189
  state.overrideContent = content;
@@ -198,6 +198,24 @@ function RenderContent(props) {
198
198
  state.emitStateUpdate();
199
199
  }
200
200
  });
201
+
202
+ function onUpdateFn_0() {
203
+ state.evaluateJsCode();
204
+ }
205
+
206
+ createEffect(on(() => [state.useContent?.data?.jsCode], onUpdateFn_0));
207
+
208
+ function onUpdateFn_1() {
209
+ state.runHttpRequests();
210
+ }
211
+
212
+ createEffect(on(() => [state.useContent?.data?.httpRequests], onUpdateFn_1));
213
+
214
+ function onUpdateFn_2() {
215
+ state.emitStateUpdate();
216
+ }
217
+
218
+ createEffect(on(() => [state.contentState], onUpdateFn_2));
201
219
  return <Dynamic value={{
202
220
  get content() {
203
221
  return state.useContent;
@@ -30,6 +30,8 @@ import { componentInfo as textComponentInfo } from "../blocks/text/component-inf
30
30
  import { default as Text } from "../blocks/text/text.jsx";
31
31
  import { componentInfo as videoComponentInfo } from "../blocks/video/component-info";
32
32
  import { default as Video } from "../blocks/video/video.jsx";
33
+ import { componentInfo as embedComponentInfo } from "../blocks/embed/component-info";
34
+ import { default as embed } from "../blocks/embed/embed.jsx";
33
35
  const getDefaultRegisteredComponents = () => [
34
36
  __spreadValues({ component: Columns }, columnsComponentInfo),
35
37
  __spreadValues({ component: Image }, imageComponentInfo),
@@ -38,7 +40,8 @@ const getDefaultRegisteredComponents = () => [
38
40
  __spreadValues({ component: Symbol }, symbolComponentInfo),
39
41
  __spreadValues({ component: Button }, buttonComponentInfo),
40
42
  __spreadValues({ component: Section }, sectionComponentInfo),
41
- __spreadValues({ component: Fragment }, fragmentComponentInfo)
43
+ __spreadValues({ component: Fragment }, fragmentComponentInfo),
44
+ __spreadValues({ component: embed }, embedComponentInfo)
42
45
  ];
43
46
  export {
44
47
  getDefaultRegisteredComponents
@@ -0,0 +1,38 @@
1
+ const handleABTesting = (item, testGroups) => {
2
+ if (item.variations && Object.keys(item.variations).length) {
3
+ const testGroup = item.id ? testGroups[item.id] : void 0;
4
+ const variationValue = testGroup ? item.variations[testGroup] : void 0;
5
+ if (testGroup && variationValue) {
6
+ item.data = variationValue.data;
7
+ item.testVariationId = variationValue.id;
8
+ item.testVariationName = variationValue.name;
9
+ } else {
10
+ let n = 0;
11
+ const random = Math.random();
12
+ let set = false;
13
+ for (const id in item.variations) {
14
+ const variation = item.variations[id];
15
+ const testRatio = variation.testRatio;
16
+ n += testRatio;
17
+ if (random < n) {
18
+ const variationName = variation.name || (variation.id === item.id ? "Default variation" : "");
19
+ set = true;
20
+ Object.assign(item, {
21
+ data: variation.data,
22
+ testVariationId: variation.id,
23
+ testVariationName: variationName
24
+ });
25
+ }
26
+ }
27
+ if (!set) {
28
+ Object.assign(item, {
29
+ testVariationId: item.id,
30
+ testVariationName: "Default"
31
+ });
32
+ }
33
+ }
34
+ }
35
+ };
36
+ export {
37
+ handleABTesting
38
+ };
@@ -37,20 +37,10 @@ var __async = (__this, __arguments, generator) => {
37
37
  step((generator = generator.apply(__this, __arguments)).next());
38
38
  });
39
39
  };
40
+ import { flatten } from "../../helpers/flatten.js";
40
41
  import { getFetch } from "../get-fetch.js";
42
+ import { handleABTesting } from "./ab-testing.js";
41
43
  const fetch$ = getFetch();
42
- function flatten(object, path = null, separator = ".") {
43
- return Object.keys(object).reduce((acc, key) => {
44
- const value = object[key];
45
- const newPath = [path, key].filter(Boolean).join(separator);
46
- const isObject = [
47
- typeof value === "object",
48
- value !== null,
49
- !(Array.isArray(value) && value.length === 0)
50
- ].every(Boolean);
51
- return isObject ? __spreadValues(__spreadValues({}, acc), flatten(value, newPath, separator)) : __spreadProps(__spreadValues({}, acc), { [newPath]: value });
52
- }, {});
53
- }
54
44
  function getContent(options) {
55
45
  return __async(this, null, function* () {
56
46
  return (yield getAllContent(__spreadProps(__spreadValues({}, options), { limit: 1 }))).results[0] || null;
@@ -83,50 +73,15 @@ const generateContentUrl = (options) => {
83
73
  }
84
74
  return url;
85
75
  };
86
- const handleABTesting = (content, testGroups) => {
87
- for (const item of content.results) {
88
- if (item.variations && Object.keys(item.variations).length) {
89
- const testGroup = testGroups[item.id];
90
- const variationValue = item.variations[testGroup];
91
- if (testGroup && variationValue) {
92
- item.data = variationValue.data;
93
- item.testVariationId = variationValue.id;
94
- item.testVariationName = variationValue.name;
95
- } else {
96
- let n = 0;
97
- const random = Math.random();
98
- let set = false;
99
- for (const id in item.variations) {
100
- const variation = item.variations[id];
101
- const testRatio = variation.testRatio;
102
- n += testRatio;
103
- if (random < n) {
104
- const variationName = variation.name || (variation.id === item.id ? "Default variation" : "");
105
- set = true;
106
- Object.assign(item, {
107
- data: variation.data,
108
- testVariationId: variation.id,
109
- testVariationName: variationName
110
- });
111
- }
112
- }
113
- if (!set) {
114
- Object.assign(item, {
115
- testVariationId: item.id,
116
- testVariationName: "Default"
117
- });
118
- }
119
- }
120
- }
121
- }
122
- };
123
76
  function getAllContent(options) {
124
77
  return __async(this, null, function* () {
125
78
  const url = generateContentUrl(options);
126
79
  const fetch = yield fetch$;
127
80
  const content = yield fetch(url.href).then((res) => res.json());
128
81
  if (options.testGroups) {
129
- handleABTesting(content, options.testGroups);
82
+ for (const item of content.results) {
83
+ handleABTesting(item, options.testGroups);
84
+ }
130
85
  }
131
86
  return content;
132
87
  });
File without changes
@@ -29,7 +29,6 @@ var __objRest = (source, exclude) => {
29
29
  }
30
30
  return target;
31
31
  };
32
- import { fastClone } from "./fast-clone.js";
33
32
  const components = [];
34
33
  function registerComponent(component, info) {
35
34
  components.push(__spreadValues({ component }, info));
@@ -38,31 +37,34 @@ function registerComponent(component, info) {
38
37
  }
39
38
  const createRegisterComponentMessage = (_a) => {
40
39
  var _b = _a, {
41
- component
40
+ component: _
42
41
  } = _b, info = __objRest(_b, [
43
42
  "component"
44
43
  ]);
45
44
  return {
46
45
  type: "builder.registerComponent",
47
- data: prepareComponentInfoToSend(fastClone(info))
46
+ data: prepareComponentInfoToSend(info)
48
47
  };
49
48
  };
50
- function prepareComponentInfoToSend(info) {
51
- return __spreadValues(__spreadValues({}, info), info.inputs && {
52
- inputs: info.inputs.map((input) => {
53
- const keysToConvertFnToString = ["onChange", "showIf"];
54
- for (const key of keysToConvertFnToString) {
55
- const fn = input[key];
56
- if (fn && typeof fn === "function") {
57
- input = __spreadProps(__spreadValues({}, input), {
58
- [key]: `return (${fn.toString()}).apply(this, arguments)`
59
- });
60
- }
61
- }
62
- return input;
63
- })
49
+ const fastClone = (obj) => JSON.parse(JSON.stringify(obj));
50
+ const serializeValue = (value) => typeof value === "function" ? serializeFn(value) : fastClone(value);
51
+ const serializeFn = (fnValue) => {
52
+ const fnStr = fnValue.toString().trim();
53
+ const appendFunction = !fnStr.startsWith("function") && !fnStr.startsWith("(");
54
+ return `return (${appendFunction ? "function " : ""}${fnStr}).apply(this, arguments)`;
55
+ };
56
+ const prepareComponentInfoToSend = (_c) => {
57
+ var _d = _c, {
58
+ inputs
59
+ } = _d, info = __objRest(_d, [
60
+ "inputs"
61
+ ]);
62
+ return __spreadProps(__spreadValues({}, fastClone(info)), {
63
+ inputs: inputs == null ? void 0 : inputs.map((input) => Object.entries(input).reduce((acc, [key, value]) => __spreadProps(__spreadValues({}, acc), {
64
+ [key]: serializeValue(value)
65
+ }), {}))
64
66
  });
65
- }
67
+ };
66
68
  export {
67
69
  components,
68
70
  createRegisterComponentMessage,
@@ -0,0 +1,34 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ function flatten(object, path = null, separator = ".") {
21
+ return Object.keys(object).reduce((acc, key) => {
22
+ const value = object[key];
23
+ const newPath = [path, key].filter(Boolean).join(separator);
24
+ const isObject = [
25
+ typeof value === "object",
26
+ value !== null,
27
+ !(Array.isArray(value) && value.length === 0)
28
+ ].every(Boolean);
29
+ return isObject ? __spreadValues(__spreadValues({}, acc), flatten(value, newPath, separator)) : __spreadProps(__spreadValues({}, acc), { [newPath]: value });
30
+ }, {});
31
+ }
32
+ export {
33
+ flatten
34
+ };
@@ -1,4 +0,0 @@
1
- const fastClone = (obj) => JSON.parse(JSON.stringify(obj));
2
- export {
3
- fastClone
4
- };