@builder.io/sdk-react-native 0.0.1-5 → 0.0.1-50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +15 -0
  3. package/package.json +6 -4
  4. package/src/blocks/button.js +5 -6
  5. package/src/blocks/button.lite.tsx +7 -11
  6. package/src/blocks/columns.js +32 -16
  7. package/src/blocks/columns.lite.tsx +39 -16
  8. package/src/blocks/custom-code.js +1 -2
  9. package/src/blocks/custom-code.lite.tsx +2 -10
  10. package/src/blocks/embed.js +1 -2
  11. package/src/blocks/embed.lite.tsx +2 -6
  12. package/src/blocks/form.js +11 -15
  13. package/src/blocks/form.lite.tsx +18 -22
  14. package/src/blocks/fragment.js +13 -0
  15. package/src/blocks/fragment.lite.tsx +10 -0
  16. package/src/blocks/image.js +27 -7
  17. package/src/blocks/image.lite.tsx +42 -10
  18. package/src/blocks/img.js +3 -3
  19. package/src/blocks/img.lite.tsx +2 -3
  20. package/src/blocks/input.js +3 -3
  21. package/src/blocks/input.lite.tsx +2 -5
  22. package/src/blocks/raw-text.js +1 -3
  23. package/src/blocks/raw-text.lite.tsx +1 -7
  24. package/src/blocks/section.js +3 -3
  25. package/src/blocks/section.lite.tsx +1 -2
  26. package/src/blocks/select.js +7 -6
  27. package/src/blocks/select.lite.tsx +6 -7
  28. package/src/blocks/submit-button.js +3 -3
  29. package/src/blocks/submit-button.lite.tsx +1 -2
  30. package/src/blocks/symbol.js +65 -12
  31. package/src/blocks/symbol.lite.tsx +44 -4
  32. package/src/blocks/text.js +57 -1
  33. package/src/blocks/text.lite.tsx +1 -7
  34. package/src/blocks/textarea.js +1 -1
  35. package/src/blocks/textarea.lite.tsx +0 -1
  36. package/src/blocks/video.js +90 -44
  37. package/src/blocks/video.lite.tsx +0 -1
  38. package/src/components/block-styles.js +7 -0
  39. package/src/components/block-styles.lite.tsx +6 -0
  40. package/src/components/error-boundary.js +25 -0
  41. package/src/components/error-boundary.lite.tsx +6 -0
  42. package/src/components/render-block.js +43 -19
  43. package/src/components/render-block.lite.tsx +69 -34
  44. package/src/components/render-blocks.js +12 -5
  45. package/src/components/render-blocks.lite.tsx +16 -7
  46. package/src/components/render-content.js +224 -24
  47. package/src/components/render-content.lite.tsx +247 -34
  48. package/src/context/builder.context.js +6 -1
  49. package/src/functions/evaluate.js +15 -6
  50. package/src/functions/event-handler-name.js +8 -0
  51. package/src/functions/get-block-actions.js +13 -12
  52. package/src/functions/get-block-component-options.js +17 -1
  53. package/src/functions/get-block-properties.js +7 -4
  54. package/src/functions/get-block-styles.js +31 -1
  55. package/src/functions/get-builder-search-params/fn.test.js +14 -0
  56. package/src/functions/get-builder-search-params/index.js +23 -0
  57. package/src/functions/get-content/fn.test.js +32 -0
  58. package/src/functions/get-content/index.js +138 -0
  59. package/src/functions/get-fetch.js +13 -0
  60. package/src/functions/get-global-this.js +19 -0
  61. package/src/functions/get-processed-block.js +3 -1
  62. package/src/functions/get-processed-block.test.js +12 -7
  63. package/src/functions/get-target.js +1 -1
  64. package/src/functions/is-browser.js +1 -2
  65. package/src/functions/is-previewing.js +15 -0
  66. package/src/functions/is-react-native.js +1 -1
  67. package/src/functions/on-change.test.js +0 -1
  68. package/src/functions/previewing-model-name.js +12 -0
  69. package/src/functions/register-component.js +1 -0
  70. package/src/functions/register.js +30 -0
  71. package/src/functions/set-editor-settings.js +16 -0
  72. package/src/functions/set.test.js +0 -1
  73. package/src/functions/track.js +5 -1
  74. package/src/functions/transform-block.js +38 -0
  75. package/src/index-helpers/blocks-exports.js +19 -0
  76. package/src/index-helpers/top-of-file.js +2 -0
  77. package/src/index.js +8 -18
  78. package/src/scripts/init-editing.js +18 -2
  79. package/src/types/deep-partial.js +1 -0
  80. package/src/types/typescript.js +1 -0
  81. package/index.js +0 -11
  82. package/src/functions/get-content.js +0 -103
  83. package/src/package.json +0 -18
@@ -1,26 +1,128 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __async = (__this, __arguments, generator) => {
21
+ return new Promise((resolve, reject) => {
22
+ var fulfilled = (value) => {
23
+ try {
24
+ step(generator.next(value));
25
+ } catch (e) {
26
+ reject(e);
27
+ }
28
+ };
29
+ var rejected = (value) => {
30
+ try {
31
+ step(generator.throw(value));
32
+ } catch (e) {
33
+ reject(e);
34
+ }
35
+ };
36
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
37
+ step((generator = generator.apply(__this, __arguments)).next());
38
+ });
39
+ };
1
40
  import * as React from "react";
2
- import { View } from "react-native";
41
+ import { View, Text } from "react-native";
3
42
  import { useState, useEffect } from "react";
4
43
  import { isBrowser } from "../functions/is-browser";
5
- import RenderBlock from "./render-block";
6
44
  import BuilderContext from "../context/builder.context";
7
45
  import { track } from "../functions/track";
46
+ import { isReactNative } from "../functions/is-react-native";
47
+ import { isEditing } from "../functions/is-editing";
48
+ import { isPreviewing } from "../functions/is-previewing";
49
+ import { previewingModelName } from "../functions/previewing-model-name";
50
+ import { getContent } from "../functions/get-content";
51
+ import {
52
+ convertSearchParamsToQueryObject,
53
+ getBuilderSearchParams
54
+ } from "../functions/get-builder-search-params";
55
+ import RenderBlocks from "./render-blocks";
56
+ import { evaluate } from "../functions/evaluate";
57
+ import { getFetch } from "../functions/get-fetch";
8
58
  function RenderContent(props) {
9
- var _a, _b, _c, _d, _e;
59
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
10
60
  function useContent() {
11
- return overrideContent || props.content;
61
+ var _a2;
62
+ const mergedContent = __spreadProps(__spreadValues(__spreadValues({}, props.content), overrideContent), {
63
+ data: __spreadValues(__spreadValues({}, (_a2 = props.content) == null ? void 0 : _a2.data), overrideContent == null ? void 0 : overrideContent.data)
64
+ });
65
+ return mergedContent;
12
66
  }
13
- const [update, setUpdate] = useState(() => 0);
14
- const [state, setState] = useState(() => ({}));
15
- const [context, setContext] = useState(() => ({}));
16
67
  const [overrideContent, setOverrideContent] = useState(() => null);
68
+ const [update, setUpdate] = useState(() => 0);
69
+ const [overrideState, setOverrideState] = useState(() => ({}));
70
+ function state() {
71
+ var _a2, _b2;
72
+ return __spreadValues(__spreadValues({}, (_b2 = (_a2 = props.content) == null ? void 0 : _a2.data) == null ? void 0 : _b2.state), overrideState);
73
+ }
74
+ function context() {
75
+ return {};
76
+ }
77
+ function getCssFromFont(font, data) {
78
+ var _a2, _b2;
79
+ const family = font.family + (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
80
+ const name = family.split(",")[0];
81
+ const url = (_b2 = font.fileUrl) != null ? _b2 : (_a2 = font == null ? void 0 : font.files) == null ? void 0 : _a2.regular;
82
+ let str = "";
83
+ if (url && family && name) {
84
+ str += `
85
+ @font-face {
86
+ font-family: "${family}";
87
+ src: local("${name}"), url('${url}') format('woff2');
88
+ font-display: fallback;
89
+ font-weight: 400;
90
+ }
91
+ `.trim();
92
+ }
93
+ if (font.files) {
94
+ for (const weight in font.files) {
95
+ const isNumber = String(Number(weight)) === weight;
96
+ if (!isNumber) {
97
+ continue;
98
+ }
99
+ const weightUrl = font.files[weight];
100
+ if (weightUrl && weightUrl !== url) {
101
+ str += `
102
+ @font-face {
103
+ font-family: "${family}";
104
+ src: url('${weightUrl}') format('woff2');
105
+ font-display: fallback;
106
+ font-weight: ${weight};
107
+ }
108
+ `.trim();
109
+ }
110
+ }
111
+ }
112
+ return str;
113
+ }
114
+ function getFontCss(data) {
115
+ var _a2, _b2;
116
+ return ((_b2 = (_a2 = data == null ? void 0 : data.customFonts) == null ? void 0 : _a2.map((font) => getCssFromFont(font, data))) == null ? void 0 : _b2.join(" ")) || "";
117
+ }
17
118
  function processMessage(event) {
18
119
  const { data } = event;
19
120
  if (data) {
20
121
  switch (data.type) {
21
122
  case "builder.contentUpdate": {
22
- const key = data.data.key || data.data.alias || data.data.entry || data.data.modelName;
23
- const contentData = data.data.data;
123
+ const messageContent = data.data;
124
+ const key = messageContent.key || messageContent.alias || messageContent.entry || messageContent.modelName;
125
+ const contentData = messageContent.data;
24
126
  if (key === props.model) {
25
127
  setOverrideContent(contentData);
26
128
  }
@@ -32,34 +134,132 @@ function RenderContent(props) {
32
134
  }
33
135
  }
34
136
  }
137
+ function evaluateJsCode() {
138
+ var _a2, _b2;
139
+ const jsCode = (_b2 = (_a2 = useContent == null ? void 0 : useContent()) == null ? void 0 : _a2.data) == null ? void 0 : _b2.jsCode;
140
+ if (jsCode) {
141
+ evaluate({
142
+ code: jsCode,
143
+ context: context(),
144
+ state: state()
145
+ });
146
+ }
147
+ }
148
+ function httpReqsData() {
149
+ return {};
150
+ }
151
+ function evalExpression(expression) {
152
+ return expression.replace(/{{([^}]+)}}/g, (_match, group) => evaluate({
153
+ code: group,
154
+ context: context(),
155
+ state: state()
156
+ }));
157
+ }
158
+ function handleRequest({ url, key }) {
159
+ const fetchAndSetState = () => __async(this, null, function* () {
160
+ const response = yield getFetch()(url);
161
+ const json = yield response.json();
162
+ const newOverrideState = __spreadProps(__spreadValues({}, overrideState), { [key]: json });
163
+ setOverrideState(newOverrideState);
164
+ });
165
+ fetchAndSetState();
166
+ }
167
+ function runHttpRequests() {
168
+ var _a2, _b2, _c2;
169
+ const requests = (_c2 = (_b2 = (_a2 = useContent == null ? void 0 : useContent()) == null ? void 0 : _a2.data) == null ? void 0 : _b2.httpRequests) != null ? _c2 : {};
170
+ Object.entries(requests).forEach(([key, url]) => {
171
+ if (url && (!httpReqsData()[key] || isEditing())) {
172
+ const evaluatedUrl = evalExpression(url);
173
+ handleRequest({
174
+ url: evaluatedUrl,
175
+ key
176
+ });
177
+ }
178
+ });
179
+ }
180
+ function emitStateUpdate() {
181
+ window.dispatchEvent(new CustomEvent("builder:component:stateChange", {
182
+ detail: {
183
+ state: state(),
184
+ ref: {
185
+ name: props.model
186
+ }
187
+ }
188
+ }));
189
+ }
35
190
  useEffect(() => {
36
191
  if (isBrowser()) {
37
- window.addEventListener("message", processMessage);
192
+ if (isEditing()) {
193
+ window.addEventListener("message", processMessage);
194
+ window.addEventListener("builder:component:stateChangeListenerActivated", emitStateUpdate);
195
+ }
196
+ if (useContent()) {
197
+ track("impression", {
198
+ contentId: useContent().id
199
+ });
200
+ }
201
+ if (isPreviewing()) {
202
+ if (props.model && previewingModelName() === props.model) {
203
+ const currentUrl = new URL(location.href);
204
+ const previewApiKey = currentUrl.searchParams.get("apiKey");
205
+ if (previewApiKey) {
206
+ getContent({
207
+ model: props.model,
208
+ apiKey: previewApiKey,
209
+ options: getBuilderSearchParams(convertSearchParamsToQueryObject(currentUrl.searchParams))
210
+ }).then((content) => {
211
+ if (content) {
212
+ setOverrideContent(content);
213
+ }
214
+ });
215
+ }
216
+ }
217
+ }
218
+ evaluateJsCode();
219
+ runHttpRequests();
220
+ emitStateUpdate();
38
221
  }
39
222
  }, []);
223
+ useEffect(() => {
224
+ evaluateJsCode();
225
+ }, [(_b = (_a = useContent == null ? void 0 : useContent()) == null ? void 0 : _a.data) == null ? void 0 : _b.jsCode]);
226
+ useEffect(() => {
227
+ runHttpRequests();
228
+ }, [(_d = (_c = useContent == null ? void 0 : useContent()) == null ? void 0 : _c.data) == null ? void 0 : _d.httpRequests]);
229
+ useEffect(() => {
230
+ emitStateUpdate();
231
+ }, [state()]);
232
+ useEffect(() => {
233
+ return () => {
234
+ if (isBrowser()) {
235
+ window.removeEventListener("message", processMessage);
236
+ window.removeEventListener("builder:component:stateChangeListenerActivated", emitStateUpdate);
237
+ }
238
+ };
239
+ }, []);
40
240
  return /* @__PURE__ */ React.createElement(BuilderContext.Provider, {
41
241
  value: {
42
242
  get content() {
43
- return props.content;
243
+ return useContent();
44
244
  },
45
245
  get state() {
46
- return state;
246
+ return state();
47
247
  },
48
248
  get context() {
49
- return context;
249
+ return context();
250
+ },
251
+ get apiKey() {
252
+ return props.apiKey;
50
253
  }
51
254
  }
52
- }, /* @__PURE__ */ React.createElement(View, {
53
- onClick: (event) => {
54
- track("click", {
55
- contentId: props.content.id
56
- });
57
- },
58
- "data-builder-content-id": (_a = props.content) == null ? void 0 : _a.id
59
- }, ((_c = (_b = useContent == null ? void 0 : useContent()) == null ? void 0 : _b.data) == null ? void 0 : _c.cssCode) && /* @__PURE__ */ React.createElement(View, null, useContent().data.cssCode), (_e = (_d = useContent == null ? void 0 : useContent()) == null ? void 0 : _d.data) == null ? void 0 : _e.blocks.map((block) => /* @__PURE__ */ React.createElement(RenderBlock, {
60
- key: block.id,
61
- block
62
- }))));
255
+ }, useContent() ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(View, {
256
+ onClick: (event) => track("click", {
257
+ contentId: useContent().id
258
+ }),
259
+ "data-builder-content-id": (_e = useContent == null ? void 0 : useContent()) == null ? void 0 : _e.id
260
+ }, (((_g = (_f = useContent == null ? void 0 : useContent()) == null ? void 0 : _f.data) == null ? void 0 : _g.cssCode) || ((_j = (_i = (_h = useContent == null ? void 0 : useContent()) == null ? void 0 : _h.data) == null ? void 0 : _i.customFonts) == null ? void 0 : _j.length)) && !isReactNative() ? /* @__PURE__ */ React.createElement(View, null, /* @__PURE__ */ React.createElement(Text, null, useContent().data.cssCode), /* @__PURE__ */ React.createElement(Text, null, state().getFontCss(useContent().data))) : null, /* @__PURE__ */ React.createElement(RenderBlocks, {
261
+ blocks: (_l = (_k = useContent == null ? void 0 : useContent()) == null ? void 0 : _k.data) == null ? void 0 : _l.blocks
262
+ }))) : null);
63
263
  }
64
264
  export {
65
265
  RenderContent as default
@@ -2,24 +2,104 @@ import * as React from "react";
2
2
  import { View, StyleSheet, Image, Text } from "react-native";
3
3
  import { useState, useContext, useEffect } from "react";
4
4
  import { isBrowser } from "../functions/is-browser";
5
- import RenderBlock from "./render-block.lite";
6
5
  import BuilderContext from "../context/builder.context.lite";
7
6
  import { track } from "../functions/track";
8
- import { ifTarget } from "../functions/if-target";
7
+ import { isReactNative } from "../functions/is-react-native";
8
+ import { isEditing } from "../functions/is-editing";
9
+ import { isPreviewing } from "../functions/is-previewing";
10
+ import { previewingModelName } from "../functions/previewing-model-name";
11
+ import { getContent } from "../functions/get-content";
12
+ import {
13
+ convertSearchParamsToQueryObject,
14
+ getBuilderSearchParams,
15
+ } from "../functions/get-builder-search-params";
16
+ import RenderBlocks from "./render-blocks.lite";
17
+ import { evaluate } from "../functions/evaluate";
18
+ import { getFetch } from "../functions/get-fetch";
9
19
  import { onChange } from "../functions/on-change";
20
+ import { ifTarget } from "../functions/if-target";
10
21
 
11
22
  export default function RenderContent(props) {
12
23
  function useContent() {
13
- return overrideContent || props.content;
24
+ const mergedContent = {
25
+ ...props.content,
26
+ ...overrideContent,
27
+ data: { ...props.content?.data, ...overrideContent?.data },
28
+ };
29
+ return mergedContent;
14
30
  }
15
31
 
32
+ const [overrideContent, setOverrideContent] = useState(() => null);
33
+
16
34
  const [update, setUpdate] = useState(() => 0);
17
35
 
18
- const [state, setState] = useState(() => ({}));
36
+ const [overrideState, setOverrideState] = useState(() => ({}));
19
37
 
20
- const [context, setContext] = useState(() => ({}));
38
+ function state() {
39
+ return { ...props.content?.data?.state, ...overrideState };
40
+ }
21
41
 
22
- const [overrideContent, setOverrideContent] = useState(() => null);
42
+ function context() {
43
+ return {};
44
+ }
45
+
46
+ function getCssFromFont(font, data) {
47
+ // TODO: compute what font sizes are used and only load those.......
48
+ const family =
49
+ font.family +
50
+ (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
51
+ const name = family.split(",")[0];
52
+ const url = font.fileUrl ?? font?.files?.regular;
53
+ let str = "";
54
+
55
+ if (url && family && name) {
56
+ str += `
57
+ @font-face {
58
+ font-family: "${family}";
59
+ src: local("${name}"), url('${url}') format('woff2');
60
+ font-display: fallback;
61
+ font-weight: 400;
62
+ }
63
+ `.trim();
64
+ }
65
+
66
+ if (font.files) {
67
+ for (const weight in font.files) {
68
+ const isNumber = String(Number(weight)) === weight;
69
+
70
+ if (!isNumber) {
71
+ continue;
72
+ } // TODO: maybe limit number loaded
73
+
74
+ const weightUrl = font.files[weight];
75
+
76
+ if (weightUrl && weightUrl !== url) {
77
+ str += `
78
+ @font-face {
79
+ font-family: "${family}";
80
+ src: url('${weightUrl}') format('woff2');
81
+ font-display: fallback;
82
+ font-weight: ${weight};
83
+ }
84
+ `.trim();
85
+ }
86
+ }
87
+ }
88
+
89
+ return str;
90
+ }
91
+
92
+ function getFontCss(data) {
93
+ // TODO: flag for this
94
+ // if (!builder.allowCustomFonts) {
95
+ // return '';
96
+ // }
97
+ // TODO: separate internal data from external
98
+ return (
99
+ data?.customFonts?.map((font) => getCssFromFont(font, data))?.join(" ") ||
100
+ ""
101
+ );
102
+ }
23
103
 
24
104
  function processMessage(event) {
25
105
  const { data } = event;
@@ -27,12 +107,13 @@ export default function RenderContent(props) {
27
107
  if (data) {
28
108
  switch (data.type) {
29
109
  case "builder.contentUpdate": {
110
+ const messageContent = data.data;
30
111
  const key =
31
- data.data.key ||
32
- data.data.alias ||
33
- data.data.entry ||
34
- data.data.modelName;
35
- const contentData = data.data.data; // oof
112
+ messageContent.key ||
113
+ messageContent.alias ||
114
+ messageContent.entry ||
115
+ messageContent.modelName;
116
+ const contentData = messageContent.data;
36
117
 
37
118
  if (key === props.model) {
38
119
  setOverrideContent(contentData);
@@ -49,47 +130,179 @@ export default function RenderContent(props) {
49
130
  }
50
131
  }
51
132
 
133
+ function evaluateJsCode() {
134
+ // run any dynamic JS code attached to content
135
+ const jsCode = useContent?.()?.data?.jsCode;
136
+
137
+ if (jsCode) {
138
+ evaluate({
139
+ code: jsCode,
140
+ context: context(),
141
+ state: state(),
142
+ });
143
+ }
144
+ }
145
+
146
+ function httpReqsData() {
147
+ return {};
148
+ }
149
+
150
+ function evalExpression(expression) {
151
+ return expression.replace(/{{([^}]+)}}/g, (_match, group) =>
152
+ evaluate({
153
+ code: group,
154
+ context: context(),
155
+ state: state(),
156
+ })
157
+ );
158
+ }
159
+
160
+ function handleRequest({ url, key }) {
161
+ const fetchAndSetState = async () => {
162
+ const response = await getFetch()(url);
163
+ const json = await response.json();
164
+ const newOverrideState = { ...overrideState, [key]: json };
165
+ setOverrideState(newOverrideState);
166
+ };
167
+
168
+ fetchAndSetState();
169
+ }
170
+
171
+ function runHttpRequests() {
172
+ const requests = useContent?.()?.data?.httpRequests ?? {};
173
+ Object.entries(requests).forEach(([key, url]) => {
174
+ if (url && (!httpReqsData()[key] || isEditing())) {
175
+ const evaluatedUrl = evalExpression(url);
176
+ handleRequest({
177
+ url: evaluatedUrl,
178
+ key,
179
+ });
180
+ }
181
+ });
182
+ }
183
+
184
+ function emitStateUpdate() {
185
+ window.dispatchEvent(
186
+ new CustomEvent("builder:component:stateChange", {
187
+ detail: {
188
+ state: state(),
189
+ ref: {
190
+ name: props.model,
191
+ },
192
+ },
193
+ })
194
+ );
195
+ }
196
+
52
197
  useEffect(() => {
53
198
  if (isBrowser()) {
54
- window.addEventListener("message", processMessage); // TODO: run this when content is defined
55
- // track('impression', {
56
- // contentId: props.content!.id,
57
- // });
199
+ if (isEditing()) {
200
+ window.addEventListener("message", processMessage);
201
+ window.addEventListener(
202
+ "builder:component:stateChangeListenerActivated",
203
+ emitStateUpdate
204
+ );
205
+ }
206
+
207
+ if (useContent()) {
208
+ track("impression", {
209
+ contentId: useContent().id,
210
+ });
211
+ } // override normal content in preview mode
212
+
213
+ if (isPreviewing()) {
214
+ if (props.model && previewingModelName() === props.model) {
215
+ const currentUrl = new URL(location.href);
216
+ const previewApiKey = currentUrl.searchParams.get("apiKey");
217
+
218
+ if (previewApiKey) {
219
+ getContent({
220
+ model: props.model,
221
+ apiKey: previewApiKey,
222
+ options: getBuilderSearchParams(
223
+ convertSearchParamsToQueryObject(currentUrl.searchParams)
224
+ ),
225
+ }).then((content) => {
226
+ if (content) {
227
+ setOverrideContent(content);
228
+ }
229
+ });
230
+ }
231
+ }
232
+ }
233
+
234
+ evaluateJsCode();
235
+ runHttpRequests();
236
+ emitStateUpdate();
58
237
  }
59
238
  }, []);
60
239
 
240
+ useEffect(() => {
241
+ evaluateJsCode();
242
+ }, [useContent?.()?.data?.jsCode]);
243
+ useEffect(() => {
244
+ runHttpRequests();
245
+ }, [useContent?.()?.data?.httpRequests]);
246
+ useEffect(() => {
247
+ emitStateUpdate();
248
+ }, [state()]);
249
+
250
+ useEffect(() => {
251
+ return () => {
252
+ if (isBrowser()) {
253
+ window.removeEventListener("message", processMessage);
254
+ window.removeEventListener(
255
+ "builder:component:stateChangeListenerActivated",
256
+ emitStateUpdate
257
+ );
258
+ }
259
+ };
260
+ }, []);
261
+
61
262
  return (
62
263
  <BuilderContext.Provider
63
264
  value={{
64
265
  get content() {
65
- return props.content;
266
+ return useContent();
66
267
  },
67
268
 
68
269
  get state() {
69
- return state;
270
+ return state();
70
271
  },
71
272
 
72
273
  get context() {
73
- return context;
274
+ return context();
275
+ },
276
+
277
+ get apiKey() {
278
+ return props.apiKey;
74
279
  },
75
280
  }}
76
281
  >
77
- <View
78
- onClick={(event) => {
79
- track("click", {
80
- contentId: props.content.id,
81
- });
82
- }}
83
- data-builder-content-id={props.content?.id}
84
- >
85
- {useContent?.()?.data?.cssCode && (
86
- <View>{useContent().data.cssCode}</View>
87
- )}
88
-
89
- {useContent?.()?.data?.blocks.map((block) => (
90
- <RenderBlock key={block.id} block={block} />
91
- ))}
92
- </View>
282
+ {useContent() ? (
283
+ <>
284
+ <View
285
+ onClick={(event) =>
286
+ track("click", {
287
+ contentId: useContent().id,
288
+ })
289
+ }
290
+ data-builder-content-id={useContent?.()?.id}
291
+ >
292
+ {(useContent?.()?.data?.cssCode ||
293
+ useContent?.()?.data?.customFonts?.length) &&
294
+ !isReactNative() ? (
295
+ <View>
296
+ <Text>{useContent().data.cssCode}</Text>
297
+
298
+ <Text>{state().getFontCss(useContent().data)}</Text>
299
+ </View>
300
+ ) : null}
301
+
302
+ <RenderBlocks blocks={useContent?.()?.data?.blocks} />
303
+ </View>
304
+ </>
305
+ ) : null}
93
306
  </BuilderContext.Provider>
94
307
  );
95
308
  }
@@ -1,5 +1,10 @@
1
1
  import { createContext } from "react";
2
- var stdin_default = createContext({ content: null, context: {}, state: {} });
2
+ var stdin_default = createContext({
3
+ content: null,
4
+ context: {},
5
+ state: {},
6
+ apiKey: null
7
+ });
3
8
  export {
4
9
  stdin_default as default
5
10
  };
@@ -1,18 +1,27 @@
1
1
  import * as React from 'react';
2
2
  import { isBrowser } from "./is-browser";
3
3
  import { isEditing } from "./is-editing";
4
- function evaluate(options) {
5
- const { code } = options;
4
+ function evaluate({
5
+ code,
6
+ context,
7
+ state,
8
+ event
9
+ }) {
10
+ if (code === "") {
11
+ console.warn("Skipping evaluation of empty code block.");
12
+ return;
13
+ }
6
14
  const builder = {
7
15
  isEditing: isEditing(),
8
- isBrowser: isBrowser()
16
+ isBrowser: isBrowser(),
17
+ isServer: !isBrowser()
9
18
  };
10
19
  const useReturn = !(code.includes(";") || code.includes(" return ") || code.trim().startsWith("return "));
11
- const useCode = `${useReturn ? `return (${code});` : code}`;
20
+ const useCode = useReturn ? `return (${code});` : code;
12
21
  try {
13
- return new Function("builder", "Builder", "state", "context", "event", useCode)(builder, builder, options.state, options.context, options.event);
22
+ return new Function("builder", "Builder", "state", "context", "event", useCode)(builder, builder, state, context, event);
14
23
  } catch (e) {
15
- console.warn("Builder custom code error", e);
24
+ console.warn("Builder custom code error: ", e);
16
25
  }
17
26
  }
18
27
  export {
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ function capitalizeFirstLetter(string) {
3
+ return string.charAt(0).toUpperCase() + string.slice(1);
4
+ }
5
+ const getEventHandlerName = (key) => `on${capitalizeFirstLetter(key)}`;
6
+ export {
7
+ getEventHandlerName
8
+ };