@builder.io/sdk-svelte 0.7.3 → 0.7.5

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 (63) hide show
  1. package/lib/browser/blocks/video/video.svelte +77 -16
  2. package/lib/browser/components/block/block.svelte +4 -1
  3. package/lib/browser/components/content/components/enable-editor.svelte +1 -2
  4. package/lib/browser/components/content/components/enable-editor.svelte.d.ts +0 -1
  5. package/lib/browser/components/content/content.helpers.d.ts +1 -1
  6. package/lib/browser/components/content/content.helpers.js +5 -7
  7. package/lib/browser/components/content/content.svelte +2 -4
  8. package/lib/browser/components/content/content.svelte.d.ts +0 -1
  9. package/lib/browser/components/content/content.types.d.ts +0 -4
  10. package/lib/browser/components/content-variants/content-variants.svelte +6 -7
  11. package/lib/browser/components/content-variants/helpers.d.ts +3 -3
  12. package/lib/browser/components/content-variants/helpers.js +24 -159
  13. package/lib/browser/components/content-variants/inlined-fns.d.ts +14 -0
  14. package/lib/browser/components/content-variants/inlined-fns.js +14 -0
  15. package/lib/browser/components/inlined-script.svelte +1 -1
  16. package/lib/browser/constants/sdk-version.d.ts +1 -1
  17. package/lib/browser/constants/sdk-version.js +1 -1
  18. package/lib/edge/blocks/video/video.svelte +77 -16
  19. package/lib/edge/components/block/block.svelte +4 -1
  20. package/lib/edge/components/content/components/enable-editor.svelte +1 -2
  21. package/lib/edge/components/content/components/enable-editor.svelte.d.ts +0 -1
  22. package/lib/edge/components/content/content.helpers.d.ts +1 -1
  23. package/lib/edge/components/content/content.helpers.js +5 -7
  24. package/lib/edge/components/content/content.svelte +2 -4
  25. package/lib/edge/components/content/content.svelte.d.ts +0 -1
  26. package/lib/edge/components/content/content.types.d.ts +0 -4
  27. package/lib/edge/components/content-variants/content-variants.svelte +6 -7
  28. package/lib/edge/components/content-variants/helpers.d.ts +3 -3
  29. package/lib/edge/components/content-variants/helpers.js +24 -159
  30. package/lib/edge/components/content-variants/inlined-fns.d.ts +14 -0
  31. package/lib/edge/components/content-variants/inlined-fns.js +14 -0
  32. package/lib/edge/components/inlined-script.svelte +1 -1
  33. package/lib/edge/constants/sdk-version.d.ts +1 -1
  34. package/lib/edge/constants/sdk-version.js +1 -1
  35. package/lib/node/blocks/video/video.svelte +77 -16
  36. package/lib/node/components/block/block.svelte +4 -1
  37. package/lib/node/components/content/components/enable-editor.svelte +1 -2
  38. package/lib/node/components/content/components/enable-editor.svelte.d.ts +0 -1
  39. package/lib/node/components/content/content.helpers.d.ts +1 -1
  40. package/lib/node/components/content/content.helpers.js +5 -7
  41. package/lib/node/components/content/content.svelte +2 -4
  42. package/lib/node/components/content/content.svelte.d.ts +0 -1
  43. package/lib/node/components/content/content.types.d.ts +0 -4
  44. package/lib/node/components/content-variants/content-variants.svelte +6 -7
  45. package/lib/node/components/content-variants/helpers.d.ts +3 -3
  46. package/lib/node/components/content-variants/helpers.js +24 -159
  47. package/lib/node/components/content-variants/inlined-fns.d.ts +14 -0
  48. package/lib/node/components/content-variants/inlined-fns.js +14 -0
  49. package/lib/node/components/inlined-script.svelte +1 -1
  50. package/lib/node/constants/sdk-version.d.ts +1 -1
  51. package/lib/node/constants/sdk-version.js +1 -1
  52. package/package.json +9 -1
  53. package/src/blocks/video/video.svelte +82 -16
  54. package/src/components/block/block.svelte +4 -1
  55. package/src/components/content/components/enable-editor.svelte +1 -2
  56. package/src/components/content/content.helpers.ts +5 -7
  57. package/src/components/content/content.svelte +2 -4
  58. package/src/components/content/content.types.ts +0 -4
  59. package/src/components/content-variants/content-variants.svelte +7 -8
  60. package/src/components/content-variants/helpers.ts +26 -162
  61. package/src/components/content-variants/inlined-fns.ts +22 -0
  62. package/src/components/inlined-script.svelte +1 -1
  63. package/src/constants/sdk-version.ts +1 -1
@@ -24,21 +24,30 @@
24
24
  | "bottom right";
25
25
  posterImage?: string;
26
26
  lazyLoad?: boolean;
27
+ children?: any;
28
+ fitContent?: boolean;
29
+ builderBlock?: BuilderBlock;
27
30
  }
28
31
  </script>
29
32
 
30
33
  <script lang="ts">
34
+ import type { BuilderBlock } from "../../types/builder-block.js";
35
+
31
36
  export let autoPlay: VideoProps["autoPlay"] = undefined;
32
37
  export let muted: VideoProps["muted"] = undefined;
33
38
  export let controls: VideoProps["controls"] = undefined;
34
39
  export let loop: VideoProps["loop"] = undefined;
35
40
  export let playsInline: VideoProps["playsInline"] = undefined;
36
- export let attributes: VideoProps["attributes"] = undefined;
37
41
  export let preload: VideoProps["preload"] = undefined;
42
+ export let attributes: VideoProps["attributes"] = undefined;
38
43
  export let fit: VideoProps["fit"] = undefined;
39
44
  export let position: VideoProps["position"] = undefined;
45
+ export let aspectRatio: VideoProps["aspectRatio"] = undefined;
40
46
  export let video: VideoProps["video"] = undefined;
41
47
  export let posterImage: VideoProps["posterImage"] = undefined;
48
+ export let lazyLoad: VideoProps["lazyLoad"] = undefined;
49
+ export let fitContent: VideoProps["fitContent"] = undefined;
50
+ export let builderBlock: VideoProps["builderBlock"] = undefined;
42
51
 
43
52
  function mitosis_styling(node, vars) {
44
53
  Object.entries(vars || {}).forEach(([p, v]) => {
@@ -81,25 +90,82 @@
81
90
  };
82
91
  $: spreadProps = () => {
83
92
  return {
84
- ...attributes,
85
93
  ...videoProps(),
86
94
  };
87
95
  };
88
96
  </script>
89
97
 
90
- <video
98
+ <div
91
99
  use:mitosis_styling={{
92
- width: "100%",
93
- height: "100%",
94
- ...attributes?.style,
95
- objectFit: fit,
96
- objectPosition: position,
97
- // Hack to get object fit to work as expected and
98
- // not have the video overflow
99
- borderRadius: 1,
100
+ position: "relative",
100
101
  }}
101
- {...spreadProps()}
102
- preload={preload || "metadata"}
103
- src={video || "no-src"}
104
- poster={posterImage}
105
- />
102
+ >
103
+ <video
104
+ use:mitosis_styling={{
105
+ width: "100%",
106
+ height: "100%",
107
+ ...attributes?.style,
108
+ objectFit: fit,
109
+ objectPosition: position,
110
+ // Hack to get object fit to work as expected and
111
+ // not have the video overflow
112
+ zIndex: 2,
113
+ borderRadius: "1px",
114
+ ...(aspectRatio
115
+ ? {
116
+ position: "absolute",
117
+ }
118
+ : null),
119
+ }}
120
+ class="builder-video"
121
+ {...spreadProps()}
122
+ preload={preload || "metadata"}
123
+ src={video || "no-src"}
124
+ poster={posterImage}
125
+ >
126
+ {#if !lazyLoad}
127
+ <source type="video/mp4" src={video} />
128
+ {/if}
129
+ </video>
130
+
131
+ {#if aspectRatio && !(fitContent && builderBlock?.children?.length)}
132
+ <div
133
+ use:mitosis_styling={{
134
+ width: "100%",
135
+ paddingTop: aspectRatio * 100 + "%",
136
+ pointerEvents: "none",
137
+ fontSize: "0px",
138
+ }}
139
+ />
140
+ {/if}
141
+
142
+ {#if builderBlock?.children?.length && fitContent}
143
+ <div
144
+ use:mitosis_styling={{
145
+ display: "flex",
146
+ flexDirection: "column",
147
+ alignItems: "stretch",
148
+ }}
149
+ >
150
+ <slot />
151
+ </div>
152
+ {/if}
153
+
154
+ {#if builderBlock?.children?.length && !fitContent}
155
+ <div
156
+ use:mitosis_styling={{
157
+ pointerEvents: "none",
158
+ display: "flex",
159
+ flexDirection: "column",
160
+ alignItems: "stretch",
161
+ position: "absolute",
162
+ top: "0",
163
+ left: "0",
164
+ width: "100%",
165
+ height: "100%",
166
+ }}
167
+ >
168
+ <slot />
169
+ </div>
170
+ {/if}
171
+ </div>
@@ -48,7 +48,7 @@
48
48
  });
49
49
  };
50
50
  $: processedBlock = () => {
51
- return repeatItem()
51
+ return block.repeat?.collection
52
52
  ? block
53
53
  : getProcessedBlock({
54
54
  block: block,
@@ -69,6 +69,9 @@
69
69
  if ("show" in processedBlock()) {
70
70
  return processedBlock().show;
71
71
  }
72
+ if (block.repeat?.collection && !repeatItem?.()?.length) {
73
+ return false;
74
+ }
72
75
  return true;
73
76
  };
74
77
  $: childrenWithoutParentComponent = () => {
@@ -49,7 +49,6 @@
49
49
  export let enrich: BuilderEditorProps["enrich"] = undefined;
50
50
  export let content: BuilderEditorProps["content"] = undefined;
51
51
  export let showContent: BuilderEditorProps["showContent"];
52
- export let classNameProp: BuilderEditorProps["classNameProp"];
53
52
 
54
53
  function mergeNewContent(newContent: BuilderContent) {
55
54
  const newContentValue = {
@@ -362,7 +361,7 @@
362
361
  hidden: true,
363
362
  "aria-hidden": true,
364
363
  }}
365
- class={classNameProp}
364
+ class={`variant-${content?.testVariationId || content?.id}`}
366
365
  on:initeditingbldr={(event) => {
367
366
  elementRef_onIniteditingbldr(event);
368
367
  }}
@@ -8,24 +8,22 @@ export const getContextStateInitialValue = ({
8
8
  locale
9
9
  }: Pick<ContentProps, 'content' | 'data' | 'locale'>) => {
10
10
  const defaultValues: BuilderRenderState = {};
11
+ const initialState = content?.data?.state || {};
11
12
 
12
13
  // set default values for content state inputs
13
14
  content?.data?.inputs?.forEach(input => {
14
- if (input.name && input.defaultValue !== undefined && content?.data?.state && content.data.state[input.name] === undefined) {
15
+ if (input.name && input.defaultValue !== undefined) {
15
16
  defaultValues[input.name] = input.defaultValue;
16
17
  }
17
18
  });
18
- const stateToUse: BuilderRenderState = {
19
- ...content?.data?.state,
19
+ return {
20
+ ...defaultValues,
21
+ ...initialState,
20
22
  ...data,
21
23
  ...(locale ? {
22
24
  locale
23
25
  } : {})
24
26
  };
25
- return {
26
- ...defaultValues,
27
- ...stateToUse
28
- };
29
27
  };
30
28
  export const getContentInitialValue = ({
31
29
  content,
@@ -17,7 +17,7 @@
17
17
  import type { ComponentInfo } from "../../types/components.js";
18
18
  import type { Dictionary } from "../../types/typescript.js";
19
19
  import Blocks from "../blocks/blocks.svelte";
20
- import { getRenderContentScriptString } from "../content-variants/helpers.js";
20
+ import { getUpdateVariantVisibilityScript } from "../content-variants/helpers.js";
21
21
  import InlinedScript from "../inlined-script.svelte";
22
22
  import EnableEditor from "./components/enable-editor.svelte";
23
23
  import ContentStyles from "./components/styles.svelte";
@@ -39,7 +39,6 @@
39
39
  export let canTrack: ContentProps["canTrack"] = undefined;
40
40
  export let includeRefs: ContentProps["includeRefs"] = undefined;
41
41
  export let enrich: ContentProps["enrich"] = undefined;
42
- export let classNameProp: ContentProps["classNameProp"];
43
42
  export let showContent: ContentProps["showContent"];
44
43
  export let isSsrAbTest: ContentProps["isSsrAbTest"];
45
44
 
@@ -47,7 +46,7 @@
47
46
  $builderContextSignal.rootState = newRootState;
48
47
  }
49
48
 
50
- let scriptStr = getRenderContentScriptString({
49
+ let scriptStr = getUpdateVariantVisibilityScript({
51
50
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
52
51
  variationId: content?.testVariationId!,
53
52
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
@@ -120,7 +119,6 @@
120
119
  {locale}
121
120
  {includeRefs}
122
121
  {enrich}
123
- {classNameProp}
124
122
  {showContent}
125
123
  {builderContextSignal}
126
124
  {...{}}
@@ -2,10 +2,6 @@ import type { BuilderRenderState } from '../../context/types.js';
2
2
  import type { EnforcePartials } from '../../types/enforced-partials.js';
3
3
  import type { ContentVariantsPrps } from '../content-variants/content-variants.types.js';
4
4
  interface InternalRenderProps {
5
- /**
6
- * TO-DO: improve qwik generator to not remap this name for non-HTML tags, then name it `className`
7
- */
8
- classNameProp: string | undefined;
9
5
  showContent: boolean;
10
6
  isSsrAbTest: boolean;
11
7
  }
@@ -18,10 +18,10 @@
18
18
  import InlinedStyles from "../inlined-styles.svelte";
19
19
  import type { ContentVariantsPrps } from "./content-variants.types.js";
20
20
  import {
21
- checkShouldRunVariants,
21
+ checkShouldRenderVariants,
22
22
  getScriptString,
23
+ getUpdateCookieAndStylesScript,
23
24
  getVariants,
24
- getVariantsScriptString,
25
25
  } from "./helpers.js";
26
26
 
27
27
  export let canTrack: VariantsProviderProps["canTrack"] = undefined;
@@ -39,8 +39,8 @@
39
39
  export let includeRefs: VariantsProviderProps["includeRefs"] = undefined;
40
40
  export let enrich: VariantsProviderProps["enrich"] = undefined;
41
41
 
42
- $: variantScriptStr = () => {
43
- return getVariantsScriptString(
42
+ $: updateCookieAndStylesScriptStr = () => {
43
+ return getUpdateCookieAndStylesScript(
44
44
  getVariants(content).map((value) => ({
45
45
  id: value.testVariationId!,
46
46
  testRatio: value.testRatio,
@@ -65,7 +65,7 @@
65
65
  });
66
66
  };
67
67
 
68
- let shouldRenderVariants = checkShouldRunVariants({
68
+ let shouldRenderVariants = checkShouldRenderVariants({
69
69
  canTrack: getDefaultCanTrack(canTrack),
70
70
  content: content,
71
71
  });
@@ -74,6 +74,7 @@
74
74
  /**
75
75
  * We unmount the non-winning variants post-hydration in Vue.
76
76
  */
77
+ shouldRenderVariants = false;
77
78
  });
78
79
  </script>
79
80
 
@@ -87,13 +88,12 @@
87
88
  styles={hideVariantsStyleString()}
88
89
  />
89
90
 
90
- <InlinedScript scriptStr={variantScriptStr()} />
91
+ <InlinedScript scriptStr={updateCookieAndStylesScriptStr()} />
91
92
 
92
93
  {#each getVariants(content) as variant (variant.testVariationId)}
93
94
  <ContentComponent
94
95
  content={variant}
95
96
  showContent={false}
96
- classNameProp={undefined}
97
97
  {model}
98
98
  {data}
99
99
  {context}
@@ -112,7 +112,6 @@
112
112
  <ContentComponent
113
113
  {...{}}
114
114
  content={defaultContent()}
115
- classNameProp={`variant-${content?.id}`}
116
115
  showContent={true}
117
116
  {model}
118
117
  {data}
@@ -3,12 +3,22 @@ import { isBrowser } from '../../functions/is-browser.js';
3
3
  import type { Nullable } from '../../helpers/nullable.js';
4
4
  import type { BuilderContent } from '../../types/builder-content.js';
5
5
  import type { Target } from '../../types/targets.js';
6
+ import { UPDATE_COOKIES_AND_STYLES_SCRIPT, UPDATE_VARIANT_VISIBILITY_SCRIPT } from './inlined-fns.js';
7
+
8
+ /**
9
+ * We hardcode explicit function names here, because the `.toString()` of a function can change depending on the bundler.
10
+ * Some bundlers will minify the fn name, etc.
11
+ *
12
+ * So we hardcode the function names here, and then use those names in the script string to make sure the function names are consistent.
13
+ */
14
+ const UPDATE_COOKIES_AND_STYLES_SCRIPT_NAME = 'builderIoAbTest';
15
+ const UPDATE_VARIANT_VISIBILITY_SCRIPT_FN_NAME = 'builderIoRenderContent';
6
16
  export const getVariants = (content: Nullable<BuilderContent>) => Object.values(content?.variations || {}).map(variant => ({
7
17
  ...variant,
8
18
  testVariationId: variant.id,
9
19
  id: content?.id
10
20
  }));
11
- export const checkShouldRunVariants = ({
21
+ export const checkShouldRenderVariants = ({
12
22
  canTrack,
13
23
  content
14
24
  }: {
@@ -25,13 +35,14 @@ export const checkShouldRunVariants = ({
25
35
  if (!canTrack) return false;
26
36
 
27
37
  /**
28
- * For Vue 2 and Vue 3, we need to (initially) render the variants. This is to avoid hydration mismatch errors.
38
+ * For Vue and Svelte, we need to (initially) render the variants. This is to avoid hydration mismatch errors.
29
39
  * Unlike React, Vue's hydration checks are shallow and do not check the attributes/contents of each element, so we
30
40
  * are able to modify the `hidden` HTML attributes and `display` CSS properties without causing a hydration mismatch error.
31
41
  *
32
- * NOTE: after the app is hydrated, we strip the variants from the DOM (on mount) to reduce the amount of HTML in the DOM.
42
+ * NOTE: For Vue: after the app is hydrated, we strip the variants from the DOM (on mount) to reduce the amount of HTML in the DOM.
43
+ * This isn't necessary, just a nice to have.
33
44
  */
34
- if (TARGET === 'vue2' || TARGET === 'vue3') return true;
45
+ if (TARGET === 'vue2' || TARGET === 'vue3' || TARGET === 'svelte') return true;
35
46
  if (isBrowser()) return false;
36
47
  return true;
37
48
  };
@@ -39,169 +50,22 @@ type VariantData = {
39
50
  id: string;
40
51
  testRatio?: number;
41
52
  };
42
-
43
- /**
44
- * NOTE: when this function is stringified, single-line comments can cause weird issues when compiled by Sveltekit.
45
- * Make sure to write multi-line comments only.
46
- */
47
- function bldrAbTest(contentId: string, variants: VariantData[], isHydrationTarget: boolean) {
48
- function getAndSetVariantId(): string {
49
- function setCookie(name: string, value: string, days?: number) {
50
- let expires = '';
51
- if (days) {
52
- const date = new Date();
53
- date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
54
- expires = '; expires=' + date.toUTCString();
55
- }
56
- document.cookie = name + '=' + (value || '') + expires + '; path=/' + '; Secure; SameSite=None';
57
- }
58
- function getCookie(name: string) {
59
- const nameEQ = name + '=';
60
- const ca = document.cookie.split(';');
61
- for (let i = 0; i < ca.length; i++) {
62
- let c = ca[i];
63
- while (c.charAt(0) === ' ') c = c.substring(1, c.length);
64
- if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
65
- }
66
- return null;
67
- }
68
- const cookieName = `builder.tests.${contentId}`;
69
- const variantInCookie = getCookie(cookieName);
70
- const availableIDs = variants.map(vr => vr.id).concat(contentId);
71
- /**
72
- * cookie already exists
73
- */
74
- if (variantInCookie && availableIDs.includes(variantInCookie)) {
75
- return variantInCookie;
76
- }
77
-
78
- /**
79
- * no cookie exists, find variant
80
- */
81
- let n = 0;
82
- const random = Math.random();
83
- for (let i = 0; i < variants.length; i++) {
84
- const variant = variants[i];
85
- const testRatio = variant.testRatio;
86
- n += testRatio!;
87
- if (random < n) {
88
- setCookie(cookieName, variant.id);
89
- return variant.id;
90
- }
91
- }
92
-
93
- /**
94
- * no variant found, assign default content
95
- */
96
- setCookie(cookieName, contentId);
97
- return contentId;
98
- }
99
- const winningVariantId = getAndSetVariantId();
100
- const styleEl = (document.currentScript?.previousElementSibling as HTMLStyleElement);
101
-
102
- /**
103
- * For React to work, we need hydration to match SSR, so we completely remove this node and the styles tag.
104
- */
105
- if (isHydrationTarget) {
106
- styleEl.remove();
107
- const thisScriptEl = document.currentScript;
108
- thisScriptEl?.remove();
109
- } else {
110
- /* update styles to hide all variants except the winning variant */
111
- const newStyleStr = variants.concat({
112
- id: contentId
113
- }).filter(variant => variant.id !== winningVariantId).map(value => {
114
- return `.variant-${value.id} { display: none; }
115
- `;
116
- }).join('');
117
- styleEl.innerHTML = newStyleStr;
118
- }
119
- }
120
-
121
- /**
122
- * NOTE: when this function is stringified, single-line comments can cause weird issues when compiled by Sveltekit.
123
- * Make sure to write multi-line comments only.
124
- */
125
- function bldrCntntScrpt(variantContentId: string, defaultContentId: string, isHydrationTarget: boolean) {
126
- if (!navigator.cookieEnabled) {
127
- return;
128
- }
129
- function getCookie(name: string) {
130
- const nameEQ = name + '=';
131
- const ca = document.cookie.split(';');
132
- for (let i = 0; i < ca.length; i++) {
133
- let c = ca[i];
134
- while (c.charAt(0) === ' ') c = c.substring(1, c.length);
135
- if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
136
- }
137
- return null;
138
- }
139
- const cookieName = `builder.tests.${defaultContentId}`;
140
- const variantId = getCookie(cookieName);
141
- const parentDiv = document.currentScript?.parentElement;
142
- const variantIsDefaultContent = variantContentId === defaultContentId;
143
- if (variantId === variantContentId) {
144
- if (variantIsDefaultContent) {
145
- /** the default content is already visible, no need to do anything */
146
- return;
147
- }
148
-
149
- /** this is the winning variant and not already visible: remove `hidden` and `aria-hidden` attr */
150
-
151
- parentDiv?.removeAttribute('hidden');
152
- parentDiv?.removeAttribute('aria-hidden');
153
- } else {
154
- if (variantIsDefaultContent) {
155
- if (isHydrationTarget) {
156
- /**
157
- * For React to work, we need to support hydration, in which case the first CSR will have none of the hidden variants.
158
- * So we completely remove that node.
159
- */
160
- parentDiv?.remove();
161
- } else {
162
- /** this is not the winning variant, add `hidden` attr */
163
- parentDiv?.setAttribute('hidden', 'true');
164
- parentDiv?.setAttribute('aria-hidden', 'true');
165
- }
166
- }
167
-
168
- /** This is not the winning variant, and it's not the default content.
169
- * There's no need to hide it, because it's already hidden.
170
- */
171
- return;
172
- }
173
- return;
174
- }
175
53
  const getIsHydrationTarget = (target: Target) => target === 'react' || target === 'reactNative';
176
54
  const isHydrationTarget = getIsHydrationTarget(TARGET);
177
-
178
- /**
179
- * We hardcode explicit function names here, because the `.toString()` of a function can change depending on the bundler.
180
- * Some bundlers will minify the fn name, etc.
181
- *
182
- * So we hardcode the function names here, and then use those names in the script string to make sure the function names are consistent.
183
- */
184
- const AB_TEST_FN_NAME = 'builderIoAbTest';
185
- const CONTENT_FN_NAME = 'builderIoRenderContent';
186
- export const getScriptString = () => {
187
- const fnStr = bldrAbTest.toString().replace(/\s+/g, ' ');
188
- const fnStr2 = bldrCntntScrpt.toString().replace(/\s+/g, ' ');
189
- return `
190
- window.${AB_TEST_FN_NAME} = ${fnStr}
191
- window.${CONTENT_FN_NAME} = ${fnStr2}
55
+ export const getScriptString = () => `
56
+ window.${UPDATE_COOKIES_AND_STYLES_SCRIPT_NAME} = ${UPDATE_COOKIES_AND_STYLES_SCRIPT}
57
+ window.${UPDATE_VARIANT_VISIBILITY_SCRIPT_FN_NAME} = ${UPDATE_VARIANT_VISIBILITY_SCRIPT}
192
58
  `;
193
- };
194
- export const getVariantsScriptString = (variants: VariantData[], contentId: string) => {
195
- return `
196
- window.${AB_TEST_FN_NAME}("${contentId}",${JSON.stringify(variants)}, ${isHydrationTarget})`;
197
- };
198
- export const getRenderContentScriptString = ({
59
+ export const getUpdateCookieAndStylesScript = (variants: VariantData[], contentId: string) => `
60
+ window.${UPDATE_COOKIES_AND_STYLES_SCRIPT_NAME}(
61
+ "${contentId}",${JSON.stringify(variants)}, ${isHydrationTarget}
62
+ )`;
63
+ export const getUpdateVariantVisibilityScript = ({
199
64
  contentId,
200
65
  variationId
201
66
  }: {
202
67
  variationId: string;
203
68
  contentId: string;
204
- }) => {
205
- return `
206
- window.${CONTENT_FN_NAME}("${variationId}", "${contentId}", ${isHydrationTarget})`;
207
- }
69
+ }) => `window.${UPDATE_VARIANT_VISIBILITY_SCRIPT_FN_NAME}(
70
+ "${variationId}", "${contentId}", ${isHydrationTarget}
71
+ )`
@@ -0,0 +1,22 @@
1
+ /**
2
+ * WARNING: This file contains functions that get stringified and inlined into the HTML at build-time.
3
+ * They cannot import anything.
4
+ */
5
+
6
+ type VariantData = {
7
+ id: string;
8
+ testRatio?: number;
9
+ };
10
+
11
+ /**
12
+ * For more information on how this works,
13
+ * see our [SSR A/B Test Docs](https://github.com/BuilderIO/builder/tree/main/packages/sdks/src/SSR_AB_TEST.md)
14
+ */
15
+
16
+ /**
17
+ * For more information on how this works,
18
+ * see our [SSR A/B Test Docs](https://github.com/BuilderIO/builder/tree/main/packages/sdks/src/SSR_AB_TEST.md)
19
+ */
20
+
21
+ export const UPDATE_COOKIES_AND_STYLES_SCRIPT = "function updateCookiesAndStyles(contentId, variants, isHydrationTarget) {\n function getAndSetVariantId() {\n function setCookie(name, value, days) {\n let expires = '';\n if (days) {\n const date = new Date();\n date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);\n expires = '; expires=' + date.toUTCString();\n }\n document.cookie = name + '=' + (value || '') + expires + '; path=/' + '; Secure; SameSite=None';\n }\n function getCookie(name) {\n const nameEQ = name + '=';\n const ca = document.cookie.split(';');\n for (let i = 0; i < ca.length; i++) {\n let c = ca[i];\n while (c.charAt(0) === ' ') c = c.substring(1, c.length);\n if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);\n }\n return null;\n }\n const cookieName = `builder.tests.${contentId}`;\n const variantInCookie = getCookie(cookieName);\n const availableIDs = variants.map(vr => vr.id).concat(contentId);\n if (variantInCookie && availableIDs.includes(variantInCookie)) {\n return variantInCookie;\n }\n let n = 0;\n const random = Math.random();\n for (let i = 0; i < variants.length; i++) {\n const variant = variants[i];\n const testRatio = variant.testRatio;\n n += testRatio;\n if (random < n) {\n setCookie(cookieName, variant.id);\n return variant.id;\n }\n }\n setCookie(cookieName, contentId);\n return contentId;\n }\n const winningVariantId = getAndSetVariantId();\n const styleEl = document.currentScript?.previousElementSibling;\n if (isHydrationTarget) {\n styleEl.remove();\n const thisScriptEl = document.currentScript;\n thisScriptEl?.remove();\n } else {\n const newStyleStr = variants.concat({\n id: contentId\n }).filter(variant => variant.id !== winningVariantId).map(value => {\n return `.variant-${value.id} { display: none; }\n `;\n }).join('');\n styleEl.innerHTML = newStyleStr;\n }\n}";
22
+ export const UPDATE_VARIANT_VISIBILITY_SCRIPT = "function updateVariantVisibility(variantContentId, defaultContentId, isHydrationTarget) {\n if (!navigator.cookieEnabled) {\n return;\n }\n function getCookie(name) {\n const nameEQ = name + '=';\n const ca = document.cookie.split(';');\n for (let i = 0; i < ca.length; i++) {\n let c = ca[i];\n while (c.charAt(0) === ' ') c = c.substring(1, c.length);\n if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);\n }\n return null;\n }\n const cookieName = `builder.tests.${defaultContentId}`;\n const winningVariant = getCookie(cookieName);\n const parentDiv = document.currentScript?.parentElement;\n const isDefaultContent = variantContentId === defaultContentId;\n const isWinningVariant = winningVariant === variantContentId;\n if (isWinningVariant && !isDefaultContent) {\n parentDiv?.removeAttribute('hidden');\n parentDiv?.removeAttribute('aria-hidden');\n } else if (!isWinningVariant && isDefaultContent) {\n parentDiv?.setAttribute('hidden', 'true');\n parentDiv?.setAttribute('aria-hidden', 'true');\n }\n if (isHydrationTarget) {\n if (!isWinningVariant) {\n parentDiv?.remove();\n }\n const thisScriptEl = document.currentScript;\n thisScriptEl?.remove();\n }\n return;\n}";
@@ -10,4 +10,4 @@
10
10
  export let id: Props["id"] = undefined;
11
11
  </script>
12
12
 
13
- <svelte:element this={"script"} {id}>{@html scriptStr}</svelte:element>
13
+ {@html `<script id=${id || ""}>${scriptStr}</script>`}
@@ -1 +1 @@
1
- export const SDK_VERSION = "0.7.3"
1
+ export const SDK_VERSION = "0.7.5"