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