@builder.io/sdk-solid 0.0.1
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/README.md +3 -0
- package/package.json +9 -0
- package/src/blocks/button.js +41 -0
- package/src/blocks/button.lite.tsx +18 -0
- package/src/blocks/columns.js +133 -0
- package/src/blocks/columns.lite.tsx +96 -0
- package/src/blocks/custom-code.js +72 -0
- package/src/blocks/custom-code.lite.tsx +65 -0
- package/src/blocks/embed.js +62 -0
- package/src/blocks/embed.lite.tsx +57 -0
- package/src/blocks/form.js +355 -0
- package/src/blocks/form.lite.tsx +291 -0
- package/src/blocks/fragment.js +15 -0
- package/src/blocks/fragment.lite.tsx +3 -0
- package/src/blocks/image.js +136 -0
- package/src/blocks/image.lite.tsx +81 -0
- package/src/blocks/img.js +39 -0
- package/src/blocks/img.lite.tsx +16 -0
- package/src/blocks/input.js +45 -0
- package/src/blocks/input.lite.tsx +18 -0
- package/src/blocks/raw-text.js +25 -0
- package/src/blocks/raw-text.lite.tsx +8 -0
- package/src/blocks/section.js +24 -0
- package/src/blocks/section.lite.tsx +16 -0
- package/src/blocks/select.js +57 -0
- package/src/blocks/select.lite.tsx +23 -0
- package/src/blocks/submit-button.js +18 -0
- package/src/blocks/submit-button.lite.tsx +7 -0
- package/src/blocks/symbol.js +69 -0
- package/src/blocks/symbol.lite.tsx +37 -0
- package/src/blocks/text.js +15 -0
- package/src/blocks/text.lite.tsx +3 -0
- package/src/blocks/textarea.js +34 -0
- package/src/blocks/textarea.lite.tsx +11 -0
- package/src/blocks/video.js +54 -0
- package/src/blocks/video.lite.tsx +24 -0
- package/src/components/block-styles.js +3 -0
- package/src/components/block-styles.lite.tsx +3 -0
- package/src/components/error-boundary.js +3 -0
- package/src/components/error-boundary.lite.tsx +3 -0
- package/src/components/render-block.js +154 -0
- package/src/components/render-block.lite.tsx +108 -0
- package/src/components/render-blocks.js +104 -0
- package/src/components/render-blocks.lite.tsx +72 -0
- package/src/components/render-content.js +314 -0
- package/src/components/render-content.lite.tsx +289 -0
- package/src/constants/device-sizes.js +39 -0
- package/src/context/builder.context.js +10 -0
- package/src/functions/evaluate.js +28 -0
- package/src/functions/event-handler-name.js +7 -0
- package/src/functions/get-block-actions.js +23 -0
- package/src/functions/get-block-component-options.js +23 -0
- package/src/functions/get-block-properties.js +29 -0
- package/src/functions/get-block-styles.js +42 -0
- package/src/functions/get-block-tag.js +6 -0
- package/src/functions/get-builder-search-params/fn.test.js +13 -0
- package/src/functions/get-builder-search-params/index.js +22 -0
- package/src/functions/get-content/fn.test.js +31 -0
- package/src/functions/get-content/index.js +137 -0
- package/src/functions/get-fetch.js +12 -0
- package/src/functions/get-global-this.js +18 -0
- package/src/functions/get-processed-block.js +46 -0
- package/src/functions/get-processed-block.test.js +31 -0
- package/src/functions/get-target.js +6 -0
- package/src/functions/if-target.js +6 -0
- package/src/functions/is-browser.js +6 -0
- package/src/functions/is-editing.js +7 -0
- package/src/functions/is-iframe.js +7 -0
- package/src/functions/is-previewing.js +14 -0
- package/src/functions/is-react-native.js +6 -0
- package/src/functions/macro-eval.js +5 -0
- package/src/functions/on-change.js +27 -0
- package/src/functions/on-change.test.js +19 -0
- package/src/functions/previewing-model-name.js +11 -0
- package/src/functions/register-component.js +53 -0
- package/src/functions/register.js +29 -0
- package/src/functions/set-editor-settings.js +15 -0
- package/src/functions/set.js +11 -0
- package/src/functions/set.test.js +16 -0
- package/src/functions/track.js +22 -0
- package/src/functions/transform-block.js +6 -0
- package/src/index-helpers/blocks-exports.js +20 -0
- package/src/index-helpers/top-of-file.js +4 -0
- package/src/index.js +13 -0
- package/src/scripts/init-editing.js +70 -0
- package/src/types/builder-block.js +0 -0
- package/src/types/builder-content.js +0 -0
- package/src/types/deep-partial.js +0 -0
- package/src/types/typescript.js +0 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { template as _$template } from "solid-js/web";
|
|
2
|
+
import { delegateEvents as _$delegateEvents } from "solid-js/web";
|
|
3
|
+
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
4
|
+
import { effect as _$effect } from "solid-js/web";
|
|
5
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
6
|
+
import { insert as _$insert } from "solid-js/web";
|
|
7
|
+
import { memo as _$memo } from "solid-js/web";
|
|
8
|
+
|
|
9
|
+
const _tmpl$ = /*#__PURE__*/_$template(`<style></style>`, 2),
|
|
10
|
+
_tmpl$2 = /*#__PURE__*/_$template(`<div></div>`, 2);
|
|
11
|
+
|
|
12
|
+
import { Show, onMount } from "solid-js";
|
|
13
|
+
import { Dynamic } from "solid-js/web";
|
|
14
|
+
import { createMutable } from "solid-js/store";
|
|
15
|
+
import { isBrowser } from "../functions/is-browser";
|
|
16
|
+
import BuilderContext from "../context/builder.context";
|
|
17
|
+
import { track } from "../functions/track";
|
|
18
|
+
import { isReactNative } from "../functions/is-react-native";
|
|
19
|
+
import { isEditing } from "../functions/is-editing";
|
|
20
|
+
import { isPreviewing } from "../functions/is-previewing";
|
|
21
|
+
import { previewingModelName } from "../functions/previewing-model-name";
|
|
22
|
+
import { getContent } from "../functions/get-content";
|
|
23
|
+
import { convertSearchParamsToQueryObject, getBuilderSearchParams } from "../functions/get-builder-search-params";
|
|
24
|
+
import RenderBlocks from "./render-blocks";
|
|
25
|
+
import { evaluate } from "../functions/evaluate";
|
|
26
|
+
import { getFetch } from "../functions/get-fetch";
|
|
27
|
+
export default function RenderContent(props) {
|
|
28
|
+
const state = createMutable({
|
|
29
|
+
get useContent() {
|
|
30
|
+
const mergedContent = { ...props.content,
|
|
31
|
+
...state.overrideContent,
|
|
32
|
+
data: { ...props.content?.data,
|
|
33
|
+
...props.data,
|
|
34
|
+
...state.overrideContent?.data
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return mergedContent;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
overrideContent: null,
|
|
41
|
+
update: 0,
|
|
42
|
+
overrideState: {},
|
|
43
|
+
|
|
44
|
+
get state() {
|
|
45
|
+
return { ...props.content?.data?.state,
|
|
46
|
+
...props.data,
|
|
47
|
+
...state.overrideState
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
get context() {
|
|
52
|
+
return {};
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
getCssFromFont(font, data) {
|
|
56
|
+
// TODO: compute what font sizes are used and only load those.......
|
|
57
|
+
const family = font.family + (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
|
|
58
|
+
const name = family.split(",")[0];
|
|
59
|
+
const url = font.fileUrl ?? font?.files?.regular;
|
|
60
|
+
let str = "";
|
|
61
|
+
|
|
62
|
+
if (url && family && name) {
|
|
63
|
+
str += `
|
|
64
|
+
@font-face {
|
|
65
|
+
font-family: "${family}";
|
|
66
|
+
src: local("${name}"), url('${url}') format('woff2');
|
|
67
|
+
font-display: fallback;
|
|
68
|
+
font-weight: 400;
|
|
69
|
+
}
|
|
70
|
+
`.trim();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (font.files) {
|
|
74
|
+
for (const weight in font.files) {
|
|
75
|
+
const isNumber = String(Number(weight)) === weight;
|
|
76
|
+
|
|
77
|
+
if (!isNumber) {
|
|
78
|
+
continue;
|
|
79
|
+
} // TODO: maybe limit number loaded
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
const weightUrl = font.files[weight];
|
|
83
|
+
|
|
84
|
+
if (weightUrl && weightUrl !== url) {
|
|
85
|
+
str += `
|
|
86
|
+
@font-face {
|
|
87
|
+
font-family: "${family}";
|
|
88
|
+
src: url('${weightUrl}') format('woff2');
|
|
89
|
+
font-display: fallback;
|
|
90
|
+
font-weight: ${weight};
|
|
91
|
+
}
|
|
92
|
+
`.trim();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return str;
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
getFontCss(data) {
|
|
101
|
+
// TODO: flag for this
|
|
102
|
+
// if (!this.builder.allowCustomFonts) {
|
|
103
|
+
// return '';
|
|
104
|
+
// }
|
|
105
|
+
// TODO: separate internal data from external
|
|
106
|
+
return data?.customFonts?.map(font => this.getCssFromFont(font, data))?.join(" ") || "";
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
processMessage(event) {
|
|
110
|
+
const {
|
|
111
|
+
data
|
|
112
|
+
} = event;
|
|
113
|
+
|
|
114
|
+
if (data) {
|
|
115
|
+
switch (data.type) {
|
|
116
|
+
case "builder.contentUpdate":
|
|
117
|
+
{
|
|
118
|
+
const messageContent = data.data;
|
|
119
|
+
const key = messageContent.key || messageContent.alias || messageContent.entry || messageContent.modelName;
|
|
120
|
+
const contentData = messageContent.data;
|
|
121
|
+
|
|
122
|
+
if (key === props.model) {
|
|
123
|
+
state.overrideContent = contentData;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
case "builder.patchUpdates":
|
|
130
|
+
{
|
|
131
|
+
// TODO
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
evaluateJsCode() {
|
|
139
|
+
// run any dynamic JS code attached to content
|
|
140
|
+
const jsCode = state.useContent?.data?.jsCode;
|
|
141
|
+
|
|
142
|
+
if (jsCode) {
|
|
143
|
+
evaluate({
|
|
144
|
+
code: jsCode,
|
|
145
|
+
context: state.context,
|
|
146
|
+
state: state.state
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
get httpReqsData() {
|
|
152
|
+
return {};
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
evalExpression(expression) {
|
|
156
|
+
return expression.replace(/{{([^}]+)}}/g, (_match, group) => evaluate({
|
|
157
|
+
code: group,
|
|
158
|
+
context: state.context,
|
|
159
|
+
state: state.state
|
|
160
|
+
}));
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
handleRequest({
|
|
164
|
+
url,
|
|
165
|
+
key
|
|
166
|
+
}) {
|
|
167
|
+
const fetchAndSetState = async () => {
|
|
168
|
+
const response = await getFetch()(url);
|
|
169
|
+
const json = await response.json();
|
|
170
|
+
const newOverrideState = { ...state.overrideState,
|
|
171
|
+
[key]: json
|
|
172
|
+
};
|
|
173
|
+
state.overrideState = newOverrideState;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
fetchAndSetState();
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
runHttpRequests() {
|
|
180
|
+
const requests = state.useContent?.data?.httpRequests ?? {};
|
|
181
|
+
Object.entries(requests).forEach(([key, url]) => {
|
|
182
|
+
if (url && (!state.httpReqsData[key] || isEditing())) {
|
|
183
|
+
const evaluatedUrl = state.evalExpression(url);
|
|
184
|
+
state.handleRequest({
|
|
185
|
+
url: evaluatedUrl,
|
|
186
|
+
key
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
emitStateUpdate() {
|
|
193
|
+
window.dispatchEvent(new CustomEvent("builder:component:stateChange", {
|
|
194
|
+
detail: {
|
|
195
|
+
state: state.state,
|
|
196
|
+
ref: {
|
|
197
|
+
name: props.model
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
});
|
|
204
|
+
onMount(() => {
|
|
205
|
+
if (isBrowser()) {
|
|
206
|
+
if (isEditing()) {
|
|
207
|
+
window.addEventListener("message", state.processMessage);
|
|
208
|
+
window.addEventListener("builder:component:stateChangeListenerActivated", state.emitStateUpdate);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (state.useContent) {
|
|
212
|
+
track("impression", {
|
|
213
|
+
contentId: state.useContent.id
|
|
214
|
+
});
|
|
215
|
+
} // override normal content in preview mode
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
if (isPreviewing()) {
|
|
219
|
+
if (props.model && previewingModelName() === props.model) {
|
|
220
|
+
const currentUrl = new URL(location.href);
|
|
221
|
+
const previewApiKey = currentUrl.searchParams.get("apiKey");
|
|
222
|
+
|
|
223
|
+
if (previewApiKey) {
|
|
224
|
+
getContent({
|
|
225
|
+
model: props.model,
|
|
226
|
+
apiKey: previewApiKey,
|
|
227
|
+
options: getBuilderSearchParams(convertSearchParamsToQueryObject(currentUrl.searchParams))
|
|
228
|
+
}).then(content => {
|
|
229
|
+
if (content) {
|
|
230
|
+
state.overrideContent = content;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
state.evaluateJsCode();
|
|
238
|
+
state.runHttpRequests();
|
|
239
|
+
state.emitStateUpdate();
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
return _$createComponent(Dynamic, {
|
|
243
|
+
value: {
|
|
244
|
+
get content() {
|
|
245
|
+
return state.useContent;
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
get state() {
|
|
249
|
+
return state.state;
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
get context() {
|
|
253
|
+
return state.context;
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
get apiKey() {
|
|
257
|
+
return props.apiKey;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
get component() {
|
|
263
|
+
return BuilderContext.Provider;
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
get children() {
|
|
267
|
+
return _$createComponent(Show, {
|
|
268
|
+
get when() {
|
|
269
|
+
return state.state.useContent;
|
|
270
|
+
},
|
|
271
|
+
|
|
272
|
+
get children() {
|
|
273
|
+
const _el$ = _tmpl$2.cloneNode(true);
|
|
274
|
+
|
|
275
|
+
_el$.$$click = event => track("click", {
|
|
276
|
+
contentId: state.state.useContent.id
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
_$insert(_el$, _$createComponent(Show, {
|
|
280
|
+
get when() {
|
|
281
|
+
return _$memo(() => !!(state.state.useContent?.data?.cssCode || state.state.useContent?.data?.customFonts?.length), true)() && !isReactNative();
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
get children() {
|
|
285
|
+
const _el$2 = _tmpl$.cloneNode(true);
|
|
286
|
+
|
|
287
|
+
_$insert(_el$2, () => state.state.useContent.data.cssCode, null);
|
|
288
|
+
|
|
289
|
+
_$insert(_el$2, () => state.state.getFontCss(state.state.useContent.data), null);
|
|
290
|
+
|
|
291
|
+
return _el$2;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
}), null);
|
|
295
|
+
|
|
296
|
+
_$insert(_el$, _$createComponent(RenderBlocks, {
|
|
297
|
+
get blocks() {
|
|
298
|
+
return state.state.useContent?.data?.blocks;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
}), null);
|
|
302
|
+
|
|
303
|
+
_$effect(() => _$setAttribute(_el$, "data-builder-content-id", state.state.useContent?.id));
|
|
304
|
+
|
|
305
|
+
return _el$;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
_$delegateEvents(["click"]);
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { Show, onMount } from "solid-js";
|
|
2
|
+
import { Dynamic } from "solid-js/web";
|
|
3
|
+
import { createMutable } from "solid-js/store";
|
|
4
|
+
|
|
5
|
+
import { isBrowser } from "../functions/is-browser";
|
|
6
|
+
import BuilderContext from "../context/builder.context.lite";
|
|
7
|
+
import { track } from "../functions/track";
|
|
8
|
+
import { isReactNative } from "../functions/is-react-native";
|
|
9
|
+
import { isEditing } from "../functions/is-editing";
|
|
10
|
+
import { isPreviewing } from "../functions/is-previewing";
|
|
11
|
+
import { previewingModelName } from "../functions/previewing-model-name";
|
|
12
|
+
import { getContent } from "../functions/get-content";
|
|
13
|
+
import {
|
|
14
|
+
convertSearchParamsToQueryObject,
|
|
15
|
+
getBuilderSearchParams,
|
|
16
|
+
} from "../functions/get-builder-search-params";
|
|
17
|
+
import RenderBlocks from "./render-blocks.lite";
|
|
18
|
+
import { evaluate } from "../functions/evaluate";
|
|
19
|
+
import { getFetch } from "../functions/get-fetch";
|
|
20
|
+
import { onChange } from "../functions/on-change";
|
|
21
|
+
import { ifTarget } from "../functions/if-target";
|
|
22
|
+
|
|
23
|
+
export default function RenderContent(props) {
|
|
24
|
+
const state = createMutable({
|
|
25
|
+
get useContent() {
|
|
26
|
+
const mergedContent: BuilderContent = {
|
|
27
|
+
...props.content,
|
|
28
|
+
...state.overrideContent,
|
|
29
|
+
data: {
|
|
30
|
+
...props.content?.data,
|
|
31
|
+
...props.data,
|
|
32
|
+
...state.overrideContent?.data,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
return mergedContent;
|
|
36
|
+
},
|
|
37
|
+
overrideContent: null,
|
|
38
|
+
update: 0,
|
|
39
|
+
overrideState: {},
|
|
40
|
+
get state() {
|
|
41
|
+
return {
|
|
42
|
+
...props.content?.data?.state,
|
|
43
|
+
...props.data,
|
|
44
|
+
...state.overrideState,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
get context() {
|
|
48
|
+
return {} as {
|
|
49
|
+
[index: string]: any;
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
getCssFromFont(font: any, data?: any) {
|
|
53
|
+
// TODO: compute what font sizes are used and only load those.......
|
|
54
|
+
const family =
|
|
55
|
+
font.family +
|
|
56
|
+
(font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
|
|
57
|
+
const name = family.split(",")[0];
|
|
58
|
+
const url = font.fileUrl ?? font?.files?.regular;
|
|
59
|
+
let str = "";
|
|
60
|
+
|
|
61
|
+
if (url && family && name) {
|
|
62
|
+
str += `
|
|
63
|
+
@font-face {
|
|
64
|
+
font-family: "${family}";
|
|
65
|
+
src: local("${name}"), url('${url}') format('woff2');
|
|
66
|
+
font-display: fallback;
|
|
67
|
+
font-weight: 400;
|
|
68
|
+
}
|
|
69
|
+
`.trim();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (font.files) {
|
|
73
|
+
for (const weight in font.files) {
|
|
74
|
+
const isNumber = String(Number(weight)) === weight;
|
|
75
|
+
|
|
76
|
+
if (!isNumber) {
|
|
77
|
+
continue;
|
|
78
|
+
} // TODO: maybe limit number loaded
|
|
79
|
+
|
|
80
|
+
const weightUrl = font.files[weight];
|
|
81
|
+
|
|
82
|
+
if (weightUrl && weightUrl !== url) {
|
|
83
|
+
str += `
|
|
84
|
+
@font-face {
|
|
85
|
+
font-family: "${family}";
|
|
86
|
+
src: url('${weightUrl}') format('woff2');
|
|
87
|
+
font-display: fallback;
|
|
88
|
+
font-weight: ${weight};
|
|
89
|
+
}
|
|
90
|
+
`.trim();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return str;
|
|
96
|
+
},
|
|
97
|
+
getFontCss(data?: any) {
|
|
98
|
+
// TODO: flag for this
|
|
99
|
+
// if (!this.builder.allowCustomFonts) {
|
|
100
|
+
// return '';
|
|
101
|
+
// }
|
|
102
|
+
// TODO: separate internal data from external
|
|
103
|
+
return (
|
|
104
|
+
data?.customFonts
|
|
105
|
+
?.map((font: any) => this.getCssFromFont(font, data))
|
|
106
|
+
?.join(" ") || ""
|
|
107
|
+
);
|
|
108
|
+
},
|
|
109
|
+
processMessage(event: MessageEvent) {
|
|
110
|
+
const { data } = event;
|
|
111
|
+
|
|
112
|
+
if (data) {
|
|
113
|
+
switch (data.type) {
|
|
114
|
+
case "builder.contentUpdate": {
|
|
115
|
+
const messageContent = data.data;
|
|
116
|
+
const key =
|
|
117
|
+
messageContent.key ||
|
|
118
|
+
messageContent.alias ||
|
|
119
|
+
messageContent.entry ||
|
|
120
|
+
messageContent.modelName;
|
|
121
|
+
const contentData = messageContent.data;
|
|
122
|
+
|
|
123
|
+
if (key === props.model) {
|
|
124
|
+
state.overrideContent = contentData;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
case "builder.patchUpdates": {
|
|
131
|
+
// TODO
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
evaluateJsCode() {
|
|
138
|
+
// run any dynamic JS code attached to content
|
|
139
|
+
const jsCode = state.useContent?.data?.jsCode;
|
|
140
|
+
|
|
141
|
+
if (jsCode) {
|
|
142
|
+
evaluate({
|
|
143
|
+
code: jsCode,
|
|
144
|
+
context: state.context,
|
|
145
|
+
state: state.state,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
get httpReqsData() {
|
|
150
|
+
return {};
|
|
151
|
+
},
|
|
152
|
+
evalExpression(expression: string) {
|
|
153
|
+
return expression.replace(/{{([^}]+)}}/g, (_match, group) =>
|
|
154
|
+
evaluate({
|
|
155
|
+
code: group,
|
|
156
|
+
context: state.context,
|
|
157
|
+
state: state.state,
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
handleRequest({ url, key }: { key: string; url: string }) {
|
|
162
|
+
const fetchAndSetState = async () => {
|
|
163
|
+
const response = await getFetch()(url);
|
|
164
|
+
const json = await response.json();
|
|
165
|
+
const newOverrideState = { ...state.overrideState, [key]: json };
|
|
166
|
+
state.overrideState = newOverrideState;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
fetchAndSetState();
|
|
170
|
+
},
|
|
171
|
+
runHttpRequests() {
|
|
172
|
+
const requests = state.useContent?.data?.httpRequests ?? {};
|
|
173
|
+
Object.entries(requests).forEach(([key, url]) => {
|
|
174
|
+
if (url && (!state.httpReqsData[key] || isEditing())) {
|
|
175
|
+
const evaluatedUrl = state.evalExpression(url);
|
|
176
|
+
state.handleRequest({
|
|
177
|
+
url: evaluatedUrl,
|
|
178
|
+
key,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
emitStateUpdate() {
|
|
184
|
+
window.dispatchEvent(
|
|
185
|
+
new CustomEvent<BuilderComponentStateChange>(
|
|
186
|
+
"builder:component:stateChange",
|
|
187
|
+
{
|
|
188
|
+
detail: {
|
|
189
|
+
state: state.state,
|
|
190
|
+
ref: {
|
|
191
|
+
name: props.model,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
);
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
onMount(() => {
|
|
201
|
+
if (isBrowser()) {
|
|
202
|
+
if (isEditing()) {
|
|
203
|
+
window.addEventListener("message", state.processMessage);
|
|
204
|
+
window.addEventListener(
|
|
205
|
+
"builder:component:stateChangeListenerActivated",
|
|
206
|
+
state.emitStateUpdate
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (state.useContent) {
|
|
211
|
+
track("impression", {
|
|
212
|
+
contentId: state.useContent.id,
|
|
213
|
+
});
|
|
214
|
+
} // override normal content in preview mode
|
|
215
|
+
|
|
216
|
+
if (isPreviewing()) {
|
|
217
|
+
if (props.model && previewingModelName() === props.model) {
|
|
218
|
+
const currentUrl = new URL(location.href);
|
|
219
|
+
const previewApiKey = currentUrl.searchParams.get("apiKey");
|
|
220
|
+
|
|
221
|
+
if (previewApiKey) {
|
|
222
|
+
getContent({
|
|
223
|
+
model: props.model,
|
|
224
|
+
apiKey: previewApiKey,
|
|
225
|
+
options: getBuilderSearchParams(
|
|
226
|
+
convertSearchParamsToQueryObject(currentUrl.searchParams)
|
|
227
|
+
),
|
|
228
|
+
}).then((content) => {
|
|
229
|
+
if (content) {
|
|
230
|
+
state.overrideContent = content;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
state.evaluateJsCode();
|
|
238
|
+
state.runHttpRequests();
|
|
239
|
+
state.emitStateUpdate();
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return (
|
|
244
|
+
<Dynamic
|
|
245
|
+
value={{
|
|
246
|
+
get content() {
|
|
247
|
+
return state.useContent;
|
|
248
|
+
},
|
|
249
|
+
get state() {
|
|
250
|
+
return state.state;
|
|
251
|
+
},
|
|
252
|
+
get context() {
|
|
253
|
+
return state.context;
|
|
254
|
+
},
|
|
255
|
+
get apiKey() {
|
|
256
|
+
return props.apiKey;
|
|
257
|
+
},
|
|
258
|
+
}}
|
|
259
|
+
component={BuilderContext.Provider}
|
|
260
|
+
>
|
|
261
|
+
<Show when={state.state.useContent}>
|
|
262
|
+
<div
|
|
263
|
+
onClick={(event) =>
|
|
264
|
+
track("click", {
|
|
265
|
+
contentId: state.state.useContent.id,
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
data-builder-content-id={state.state.useContent?.id}
|
|
269
|
+
>
|
|
270
|
+
<Show
|
|
271
|
+
when={
|
|
272
|
+
(state.state.useContent?.data?.cssCode ||
|
|
273
|
+
state.state.useContent?.data?.customFonts?.length) &&
|
|
274
|
+
!isReactNative()
|
|
275
|
+
}
|
|
276
|
+
>
|
|
277
|
+
<style>
|
|
278
|
+
{state.state.useContent.data.cssCode}
|
|
279
|
+
{state.state.getFontCss(state.state.useContent.data)}
|
|
280
|
+
</style>
|
|
281
|
+
</Show>
|
|
282
|
+
<RenderBlocks
|
|
283
|
+
blocks={state.state.useContent?.data?.blocks}
|
|
284
|
+
></RenderBlocks>
|
|
285
|
+
</div>
|
|
286
|
+
</Show>
|
|
287
|
+
</Dynamic>
|
|
288
|
+
);
|
|
289
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const sizeNames = ["xsmall", "small", "medium", "large"];
|
|
2
|
+
const sizes = {
|
|
3
|
+
xsmall: {
|
|
4
|
+
min: 0,
|
|
5
|
+
default: 0,
|
|
6
|
+
max: 0
|
|
7
|
+
},
|
|
8
|
+
small: {
|
|
9
|
+
min: 320,
|
|
10
|
+
default: 321,
|
|
11
|
+
max: 640
|
|
12
|
+
},
|
|
13
|
+
medium: {
|
|
14
|
+
min: 641,
|
|
15
|
+
default: 642,
|
|
16
|
+
max: 991
|
|
17
|
+
},
|
|
18
|
+
large: {
|
|
19
|
+
min: 990,
|
|
20
|
+
default: 991,
|
|
21
|
+
max: 1200
|
|
22
|
+
},
|
|
23
|
+
getWidthForSize(size) {
|
|
24
|
+
return this[size].default;
|
|
25
|
+
},
|
|
26
|
+
getSizeForWidth(width) {
|
|
27
|
+
for (const size of sizeNames) {
|
|
28
|
+
const value = this[size];
|
|
29
|
+
if (width <= value.max) {
|
|
30
|
+
return size;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return "large";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export {
|
|
37
|
+
sizeNames,
|
|
38
|
+
sizes
|
|
39
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isBrowser } from "./is-browser";
|
|
2
|
+
import { isEditing } from "./is-editing";
|
|
3
|
+
function evaluate({
|
|
4
|
+
code,
|
|
5
|
+
context,
|
|
6
|
+
state,
|
|
7
|
+
event
|
|
8
|
+
}) {
|
|
9
|
+
if (code === "") {
|
|
10
|
+
console.warn("Skipping evaluation of empty code block.");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const builder = {
|
|
14
|
+
isEditing: isEditing(),
|
|
15
|
+
isBrowser: isBrowser(),
|
|
16
|
+
isServer: !isBrowser()
|
|
17
|
+
};
|
|
18
|
+
const useReturn = !(code.includes(";") || code.includes(" return ") || code.trim().startsWith("return "));
|
|
19
|
+
const useCode = useReturn ? `return (${code});` : code;
|
|
20
|
+
try {
|
|
21
|
+
return new Function("builder", "Builder", "state", "context", "event", useCode)(builder, builder, state, context, event);
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.warn("Builder custom code error: ", e);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
evaluate
|
|
28
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { evaluate } from "./evaluate";
|
|
2
|
+
import { getEventHandlerName } from "./event-handler-name";
|
|
3
|
+
function getBlockActions(options) {
|
|
4
|
+
var _a;
|
|
5
|
+
const obj = {};
|
|
6
|
+
const optionActions = (_a = options.block.actions) != null ? _a : {};
|
|
7
|
+
for (const key in optionActions) {
|
|
8
|
+
if (!optionActions.hasOwnProperty(key)) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
const value = optionActions[key];
|
|
12
|
+
obj[getEventHandlerName(key)] = (event) => evaluate({
|
|
13
|
+
code: value,
|
|
14
|
+
context: options.context,
|
|
15
|
+
state: options.state,
|
|
16
|
+
event
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return obj;
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
getBlockActions
|
|
23
|
+
};
|