@builder.io/sdk-svelte 0.7.2 → 0.7.4
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/lib/browser/blocks/video/video.svelte +77 -16
- package/lib/browser/components/content/components/enable-editor.svelte +1 -2
- package/lib/browser/components/content/components/enable-editor.svelte.d.ts +0 -1
- package/lib/browser/components/content/content.svelte +2 -4
- package/lib/browser/components/content/content.svelte.d.ts +0 -1
- package/lib/browser/components/content/content.types.d.ts +0 -4
- package/lib/browser/components/content-variants/content-variants.svelte +6 -7
- package/lib/browser/components/content-variants/helpers.d.ts +3 -3
- package/lib/browser/components/content-variants/helpers.js +24 -159
- package/lib/browser/components/content-variants/inlined-fns.d.ts +14 -0
- package/lib/browser/components/content-variants/inlined-fns.js +14 -0
- package/lib/browser/components/inlined-script.svelte +1 -1
- package/lib/browser/constants/sdk-version.d.ts +1 -1
- package/lib/browser/constants/sdk-version.js +1 -1
- package/lib/edge/blocks/video/video.svelte +77 -16
- package/lib/edge/components/content/components/enable-editor.svelte +1 -2
- package/lib/edge/components/content/components/enable-editor.svelte.d.ts +0 -1
- package/lib/edge/components/content/content.svelte +2 -4
- package/lib/edge/components/content/content.svelte.d.ts +0 -1
- package/lib/edge/components/content/content.types.d.ts +0 -4
- package/lib/edge/components/content-variants/content-variants.svelte +6 -7
- package/lib/edge/components/content-variants/helpers.d.ts +3 -3
- package/lib/edge/components/content-variants/helpers.js +24 -159
- package/lib/edge/components/content-variants/inlined-fns.d.ts +14 -0
- package/lib/edge/components/content-variants/inlined-fns.js +14 -0
- package/lib/edge/components/inlined-script.svelte +1 -1
- package/lib/edge/constants/sdk-version.d.ts +1 -1
- package/lib/edge/constants/sdk-version.js +1 -1
- package/lib/node/blocks/video/video.svelte +77 -16
- package/lib/node/components/content/components/enable-editor.svelte +1 -2
- package/lib/node/components/content/components/enable-editor.svelte.d.ts +0 -1
- package/lib/node/components/content/content.svelte +2 -4
- package/lib/node/components/content/content.svelte.d.ts +0 -1
- package/lib/node/components/content/content.types.d.ts +0 -4
- package/lib/node/components/content-variants/content-variants.svelte +6 -7
- package/lib/node/components/content-variants/helpers.d.ts +3 -3
- package/lib/node/components/content-variants/helpers.js +24 -159
- package/lib/node/components/content-variants/inlined-fns.d.ts +14 -0
- package/lib/node/components/content-variants/inlined-fns.js +14 -0
- package/lib/node/components/inlined-script.svelte +1 -1
- package/lib/node/constants/sdk-version.d.ts +1 -1
- package/lib/node/constants/sdk-version.js +1 -1
- package/package.json +9 -1
- package/src/blocks/video/video.svelte +82 -16
- package/src/components/content/components/enable-editor.svelte +1 -2
- package/src/components/content/content.svelte +2 -4
- package/src/components/content/content.types.ts +0 -4
- package/src/components/content-variants/content-variants.svelte +7 -8
- package/src/components/content-variants/helpers.ts +26 -162
- package/src/components/content-variants/inlined-fns.ts +22 -0
- package/src/components/inlined-script.svelte +1 -1
- package/src/constants/sdk-version.ts +1 -1
|
@@ -7,7 +7,7 @@ import { getDefaultCanTrack } from "../../helpers/canTrack.js";
|
|
|
7
7
|
import ContentComponent from "../content/content.svelte";
|
|
8
8
|
import InlinedScript from "../inlined-script.svelte";
|
|
9
9
|
import InlinedStyles from "../inlined-styles.svelte";
|
|
10
|
-
import {
|
|
10
|
+
import { checkShouldRenderVariants, getScriptString, getUpdateCookieAndStylesScript, getVariants, } from "./helpers.js";
|
|
11
11
|
export let canTrack = undefined;
|
|
12
12
|
export let content = undefined;
|
|
13
13
|
export let __isNestedRender = undefined;
|
|
@@ -20,8 +20,8 @@ export let customComponents = undefined;
|
|
|
20
20
|
export let locale = undefined;
|
|
21
21
|
export let includeRefs = undefined;
|
|
22
22
|
export let enrich = undefined;
|
|
23
|
-
$:
|
|
24
|
-
return
|
|
23
|
+
$: updateCookieAndStylesScriptStr = () => {
|
|
24
|
+
return getUpdateCookieAndStylesScript(getVariants(content).map((value) => ({
|
|
25
25
|
id: value.testVariationId,
|
|
26
26
|
testRatio: value.testRatio,
|
|
27
27
|
})), content?.id || "");
|
|
@@ -42,7 +42,7 @@ $: defaultContent = () => {
|
|
|
42
42
|
canTrack: getDefaultCanTrack(canTrack),
|
|
43
43
|
});
|
|
44
44
|
};
|
|
45
|
-
let shouldRenderVariants =
|
|
45
|
+
let shouldRenderVariants = checkShouldRenderVariants({
|
|
46
46
|
canTrack: getDefaultCanTrack(canTrack),
|
|
47
47
|
content: content,
|
|
48
48
|
});
|
|
@@ -50,6 +50,7 @@ onMount(() => {
|
|
|
50
50
|
/**
|
|
51
51
|
* We unmount the non-winning variants post-hydration in Vue.
|
|
52
52
|
*/
|
|
53
|
+
shouldRenderVariants = false;
|
|
53
54
|
});
|
|
54
55
|
</script>
|
|
55
56
|
|
|
@@ -63,13 +64,12 @@ onMount(() => {
|
|
|
63
64
|
styles={hideVariantsStyleString()}
|
|
64
65
|
/>
|
|
65
66
|
|
|
66
|
-
<InlinedScript scriptStr={
|
|
67
|
+
<InlinedScript scriptStr={updateCookieAndStylesScriptStr()} />
|
|
67
68
|
|
|
68
69
|
{#each getVariants(content) as variant (variant.testVariationId)}
|
|
69
70
|
<ContentComponent
|
|
70
71
|
content={variant}
|
|
71
72
|
showContent={false}
|
|
72
|
-
classNameProp={undefined}
|
|
73
73
|
{model}
|
|
74
74
|
{data}
|
|
75
75
|
{context}
|
|
@@ -88,7 +88,6 @@ onMount(() => {
|
|
|
88
88
|
<ContentComponent
|
|
89
89
|
{...{}}
|
|
90
90
|
content={defaultContent()}
|
|
91
|
-
classNameProp={`variant-${content?.id}`}
|
|
92
91
|
showContent={true}
|
|
93
92
|
{model}
|
|
94
93
|
{data}
|
|
@@ -24,7 +24,7 @@ export declare const getVariants: (content: Nullable<BuilderContent>) => {
|
|
|
24
24
|
breakpoints?: import("../../types/typescript.js").Nullable<import("../../types/builder-content.js").Breakpoints>;
|
|
25
25
|
} | undefined;
|
|
26
26
|
}[];
|
|
27
|
-
export declare const
|
|
27
|
+
export declare const checkShouldRenderVariants: ({ canTrack, content }: {
|
|
28
28
|
canTrack: Nullable<boolean>;
|
|
29
29
|
content: Nullable<BuilderContent>;
|
|
30
30
|
}) => boolean;
|
|
@@ -33,8 +33,8 @@ type VariantData = {
|
|
|
33
33
|
testRatio?: number;
|
|
34
34
|
};
|
|
35
35
|
export declare const getScriptString: () => string;
|
|
36
|
-
export declare const
|
|
37
|
-
export declare const
|
|
36
|
+
export declare const getUpdateCookieAndStylesScript: (variants: VariantData[], contentId: string) => string;
|
|
37
|
+
export declare const getUpdateVariantVisibilityScript: ({ contentId, variationId }: {
|
|
38
38
|
variationId: string;
|
|
39
39
|
contentId: string;
|
|
40
40
|
}) => string;
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { TARGET } from '../../constants/target.js';
|
|
2
2
|
import { isBrowser } from '../../functions/is-browser.js';
|
|
3
|
+
import { UPDATE_COOKIES_AND_STYLES_SCRIPT, UPDATE_VARIANT_VISIBILITY_SCRIPT } from './inlined-fns.js';
|
|
4
|
+
/**
|
|
5
|
+
* We hardcode explicit function names here, because the `.toString()` of a function can change depending on the bundler.
|
|
6
|
+
* Some bundlers will minify the fn name, etc.
|
|
7
|
+
*
|
|
8
|
+
* So we hardcode the function names here, and then use those names in the script string to make sure the function names are consistent.
|
|
9
|
+
*/
|
|
10
|
+
const UPDATE_COOKIES_AND_STYLES_SCRIPT_NAME = 'builderIoAbTest';
|
|
11
|
+
const UPDATE_VARIANT_VISIBILITY_SCRIPT_FN_NAME = 'builderIoRenderContent';
|
|
3
12
|
export const getVariants = (content) => Object.values(content?.variations || {}).map(variant => ({
|
|
4
13
|
...variant,
|
|
5
14
|
testVariationId: variant.id,
|
|
6
15
|
id: content?.id
|
|
7
16
|
}));
|
|
8
|
-
export const
|
|
17
|
+
export const checkShouldRenderVariants = ({ canTrack, content }) => {
|
|
9
18
|
const hasVariants = getVariants(content).length > 0;
|
|
10
19
|
/**
|
|
11
20
|
* We cannot SSR in React-Native.
|
|
@@ -17,173 +26,29 @@ export const checkShouldRunVariants = ({ canTrack, content }) => {
|
|
|
17
26
|
if (!canTrack)
|
|
18
27
|
return false;
|
|
19
28
|
/**
|
|
20
|
-
* For Vue
|
|
29
|
+
* For Vue and Svelte, we need to (initially) render the variants. This is to avoid hydration mismatch errors.
|
|
21
30
|
* Unlike React, Vue's hydration checks are shallow and do not check the attributes/contents of each element, so we
|
|
22
31
|
* are able to modify the `hidden` HTML attributes and `display` CSS properties without causing a hydration mismatch error.
|
|
23
32
|
*
|
|
24
|
-
* NOTE: after the app is hydrated, we strip the variants from the DOM (on mount) to reduce the amount of HTML in the DOM.
|
|
33
|
+
* 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.
|
|
34
|
+
* This isn't necessary, just a nice to have.
|
|
25
35
|
*/
|
|
26
|
-
if (TARGET === 'vue2' || TARGET === 'vue3')
|
|
36
|
+
if (TARGET === 'vue2' || TARGET === 'vue3' || TARGET === 'svelte')
|
|
27
37
|
return true;
|
|
28
38
|
if (isBrowser())
|
|
29
39
|
return false;
|
|
30
40
|
return true;
|
|
31
41
|
};
|
|
32
|
-
/**
|
|
33
|
-
* NOTE: when this function is stringified, single-line comments can cause weird issues when compiled by Sveltekit.
|
|
34
|
-
* Make sure to write multi-line comments only.
|
|
35
|
-
*/
|
|
36
|
-
function bldrAbTest(contentId, variants, isHydrationTarget) {
|
|
37
|
-
function getAndSetVariantId() {
|
|
38
|
-
function setCookie(name, value, days) {
|
|
39
|
-
let expires = '';
|
|
40
|
-
if (days) {
|
|
41
|
-
const date = new Date();
|
|
42
|
-
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
43
|
-
expires = '; expires=' + date.toUTCString();
|
|
44
|
-
}
|
|
45
|
-
document.cookie = name + '=' + (value || '') + expires + '; path=/' + '; Secure; SameSite=None';
|
|
46
|
-
}
|
|
47
|
-
function getCookie(name) {
|
|
48
|
-
const nameEQ = name + '=';
|
|
49
|
-
const ca = document.cookie.split(';');
|
|
50
|
-
for (let i = 0; i < ca.length; i++) {
|
|
51
|
-
let c = ca[i];
|
|
52
|
-
while (c.charAt(0) === ' ')
|
|
53
|
-
c = c.substring(1, c.length);
|
|
54
|
-
if (c.indexOf(nameEQ) === 0)
|
|
55
|
-
return c.substring(nameEQ.length, c.length);
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
const cookieName = `builder.tests.${contentId}`;
|
|
60
|
-
const variantInCookie = getCookie(cookieName);
|
|
61
|
-
const availableIDs = variants.map(vr => vr.id).concat(contentId);
|
|
62
|
-
/**
|
|
63
|
-
* cookie already exists
|
|
64
|
-
*/
|
|
65
|
-
if (variantInCookie && availableIDs.includes(variantInCookie)) {
|
|
66
|
-
return variantInCookie;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* no cookie exists, find variant
|
|
70
|
-
*/
|
|
71
|
-
let n = 0;
|
|
72
|
-
const random = Math.random();
|
|
73
|
-
for (let i = 0; i < variants.length; i++) {
|
|
74
|
-
const variant = variants[i];
|
|
75
|
-
const testRatio = variant.testRatio;
|
|
76
|
-
n += testRatio;
|
|
77
|
-
if (random < n) {
|
|
78
|
-
setCookie(cookieName, variant.id);
|
|
79
|
-
return variant.id;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* no variant found, assign default content
|
|
84
|
-
*/
|
|
85
|
-
setCookie(cookieName, contentId);
|
|
86
|
-
return contentId;
|
|
87
|
-
}
|
|
88
|
-
const winningVariantId = getAndSetVariantId();
|
|
89
|
-
const styleEl = document.currentScript?.previousElementSibling;
|
|
90
|
-
/**
|
|
91
|
-
* For React to work, we need hydration to match SSR, so we completely remove this node and the styles tag.
|
|
92
|
-
*/
|
|
93
|
-
if (isHydrationTarget) {
|
|
94
|
-
styleEl.remove();
|
|
95
|
-
const thisScriptEl = document.currentScript;
|
|
96
|
-
thisScriptEl?.remove();
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
/* update styles to hide all variants except the winning variant */
|
|
100
|
-
const newStyleStr = variants.concat({
|
|
101
|
-
id: contentId
|
|
102
|
-
}).filter(variant => variant.id !== winningVariantId).map(value => {
|
|
103
|
-
return `.variant-${value.id} { display: none; }
|
|
104
|
-
`;
|
|
105
|
-
}).join('');
|
|
106
|
-
styleEl.innerHTML = newStyleStr;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* NOTE: when this function is stringified, single-line comments can cause weird issues when compiled by Sveltekit.
|
|
111
|
-
* Make sure to write multi-line comments only.
|
|
112
|
-
*/
|
|
113
|
-
function bldrCntntScrpt(variantContentId, defaultContentId, isHydrationTarget) {
|
|
114
|
-
if (!navigator.cookieEnabled) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
function getCookie(name) {
|
|
118
|
-
const nameEQ = name + '=';
|
|
119
|
-
const ca = document.cookie.split(';');
|
|
120
|
-
for (let i = 0; i < ca.length; i++) {
|
|
121
|
-
let c = ca[i];
|
|
122
|
-
while (c.charAt(0) === ' ')
|
|
123
|
-
c = c.substring(1, c.length);
|
|
124
|
-
if (c.indexOf(nameEQ) === 0)
|
|
125
|
-
return c.substring(nameEQ.length, c.length);
|
|
126
|
-
}
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
const cookieName = `builder.tests.${defaultContentId}`;
|
|
130
|
-
const variantId = getCookie(cookieName);
|
|
131
|
-
const parentDiv = document.currentScript?.parentElement;
|
|
132
|
-
const variantIsDefaultContent = variantContentId === defaultContentId;
|
|
133
|
-
if (variantId === variantContentId) {
|
|
134
|
-
if (variantIsDefaultContent) {
|
|
135
|
-
/** the default content is already visible, no need to do anything */
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
/** this is the winning variant and not already visible: remove `hidden` and `aria-hidden` attr */
|
|
139
|
-
parentDiv?.removeAttribute('hidden');
|
|
140
|
-
parentDiv?.removeAttribute('aria-hidden');
|
|
141
|
-
}
|
|
142
|
-
else {
|
|
143
|
-
if (variantIsDefaultContent) {
|
|
144
|
-
if (isHydrationTarget) {
|
|
145
|
-
/**
|
|
146
|
-
* For React to work, we need to support hydration, in which case the first CSR will have none of the hidden variants.
|
|
147
|
-
* So we completely remove that node.
|
|
148
|
-
*/
|
|
149
|
-
parentDiv?.remove();
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
/** this is not the winning variant, add `hidden` attr */
|
|
153
|
-
parentDiv?.setAttribute('hidden', 'true');
|
|
154
|
-
parentDiv?.setAttribute('aria-hidden', 'true');
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
/** This is not the winning variant, and it's not the default content.
|
|
158
|
-
* There's no need to hide it, because it's already hidden.
|
|
159
|
-
*/
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
42
|
const getIsHydrationTarget = (target) => target === 'react' || target === 'reactNative';
|
|
165
43
|
const isHydrationTarget = getIsHydrationTarget(TARGET);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
*
|
|
170
|
-
* So we hardcode the function names here, and then use those names in the script string to make sure the function names are consistent.
|
|
171
|
-
*/
|
|
172
|
-
const AB_TEST_FN_NAME = 'builderIoAbTest';
|
|
173
|
-
const CONTENT_FN_NAME = 'builderIoRenderContent';
|
|
174
|
-
export const getScriptString = () => {
|
|
175
|
-
const fnStr = bldrAbTest.toString().replace(/\s+/g, ' ');
|
|
176
|
-
const fnStr2 = bldrCntntScrpt.toString().replace(/\s+/g, ' ');
|
|
177
|
-
return `
|
|
178
|
-
window.${AB_TEST_FN_NAME} = ${fnStr}
|
|
179
|
-
window.${CONTENT_FN_NAME} = ${fnStr2}
|
|
44
|
+
export const getScriptString = () => `
|
|
45
|
+
window.${UPDATE_COOKIES_AND_STYLES_SCRIPT_NAME} = ${UPDATE_COOKIES_AND_STYLES_SCRIPT}
|
|
46
|
+
window.${UPDATE_VARIANT_VISIBILITY_SCRIPT_FN_NAME} = ${UPDATE_VARIANT_VISIBILITY_SCRIPT}
|
|
180
47
|
`;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
window.${CONTENT_FN_NAME}("${variationId}", "${contentId}", ${isHydrationTarget})`;
|
|
189
|
-
};
|
|
48
|
+
export const getUpdateCookieAndStylesScript = (variants, contentId) => `
|
|
49
|
+
window.${UPDATE_COOKIES_AND_STYLES_SCRIPT_NAME}(
|
|
50
|
+
"${contentId}",${JSON.stringify(variants)}, ${isHydrationTarget}
|
|
51
|
+
)`;
|
|
52
|
+
export const getUpdateVariantVisibilityScript = ({ contentId, variationId }) => `window.${UPDATE_VARIANT_VISIBILITY_SCRIPT_FN_NAME}(
|
|
53
|
+
"${variationId}", "${contentId}", ${isHydrationTarget}
|
|
54
|
+
)`;
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
* For more information on how this works,
|
|
7
|
+
* see our [SSR A/B Test Docs](https://github.com/BuilderIO/builder/tree/main/packages/sdks/src/SSR_AB_TEST.md)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* For more information on how this works,
|
|
11
|
+
* see our [SSR A/B Test Docs](https://github.com/BuilderIO/builder/tree/main/packages/sdks/src/SSR_AB_TEST.md)
|
|
12
|
+
*/
|
|
13
|
+
export declare 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}";
|
|
14
|
+
export declare 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}";
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
* For more information on how this works,
|
|
7
|
+
* see our [SSR A/B Test Docs](https://github.com/BuilderIO/builder/tree/main/packages/sdks/src/SSR_AB_TEST.md)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* For more information on how this works,
|
|
11
|
+
* see our [SSR A/B Test Docs](https://github.com/BuilderIO/builder/tree/main/packages/sdks/src/SSR_AB_TEST.md)
|
|
12
|
+
*/
|
|
13
|
+
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}";
|
|
14
|
+
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}";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.7.
|
|
1
|
+
export declare const SDK_VERSION = "0.7.4";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.7.
|
|
1
|
+
export const SDK_VERSION = "0.7.4";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@builder.io/sdk-svelte",
|
|
3
3
|
"description": "Builder.io SDK for Svelte",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"lib",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"types": "./lib/browser/index.d.ts",
|
|
39
39
|
"scripts": {
|
|
40
40
|
"release": "npm publish",
|
|
41
|
+
"build-inline-fns": "yarn g:build-inline-fns",
|
|
41
42
|
"prepare": "SDK_ENV=browser svelte-kit sync",
|
|
42
43
|
"build": "nx run-many -p @builder.io/sdk-svelte -t build:node build:edge build:browser --parallel=false",
|
|
43
44
|
"build:node": "SDK_ENV=node svelte-package -i src/ -o lib/node",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"targets": {
|
|
67
68
|
"prepare": {
|
|
68
69
|
"dependsOn": [
|
|
70
|
+
"build-inline-fns",
|
|
69
71
|
"^build:svelte",
|
|
70
72
|
"^build"
|
|
71
73
|
],
|
|
@@ -73,8 +75,14 @@
|
|
|
73
75
|
"{projectRoot}/.svelte-kit"
|
|
74
76
|
]
|
|
75
77
|
},
|
|
78
|
+
"build-inline-fns": {
|
|
79
|
+
"dependsOn": [
|
|
80
|
+
"^build:svelte"
|
|
81
|
+
]
|
|
82
|
+
},
|
|
76
83
|
"build": {
|
|
77
84
|
"dependsOn": [
|
|
85
|
+
"build-inline-fns",
|
|
78
86
|
"^build:svelte",
|
|
79
87
|
"^build",
|
|
80
88
|
"prepare"
|
|
@@ -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
|
-
<
|
|
98
|
+
<div
|
|
91
99
|
use:mitosis_styling={{
|
|
92
|
-
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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>
|
|
@@ -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={
|
|
364
|
+
class={`variant-${content?.testVariationId || content?.id}`}
|
|
366
365
|
on:initeditingbldr={(event) => {
|
|
367
366
|
elementRef_onIniteditingbldr(event);
|
|
368
367
|
}}
|
|
@@ -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 {
|
|
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 =
|
|
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
|
-
|
|
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
|
-
$:
|
|
43
|
-
return
|
|
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 =
|
|
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={
|
|
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}
|