@builder.io/sdk-react-native 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,10 +60,27 @@ function RenderBlock(props) {
60
60
  shouldEvaluateBindings: true,
61
61
  });
62
62
  }
63
+ function proxyState() {
64
+ if (typeof Proxy === "undefined") {
65
+ console.error("no Proxy available in this environment, cannot proxy state.");
66
+ return props.context.state;
67
+ }
68
+ const useState = new Proxy(props.context.state, {
69
+ set: (obj, prop, value) => {
70
+ var _a, _b;
71
+ // set the value on the state object, so that the event handler instantly gets the update.
72
+ obj[prop] = value;
73
+ // set the value in the context, so that the rest of the app gets the update.
74
+ (_b = (_a = props.context).setState) === null || _b === void 0 ? void 0 : _b.call(_a, obj);
75
+ return true;
76
+ },
77
+ });
78
+ return useState;
79
+ }
63
80
  function actions() {
64
81
  return (0, get_block_actions_js_1.getBlockActions)({
65
82
  block: useBlock(),
66
- state: props.context.state,
83
+ state: proxyState(),
67
84
  context: props.context.context,
68
85
  });
69
86
  }
@@ -137,6 +154,7 @@ function RenderBlock(props) {
137
154
  state: props.context.state,
138
155
  content: props.context.content,
139
156
  context: props.context.context,
157
+ setState: props.context.setState,
140
158
  registeredComponents: props.context.registeredComponents,
141
159
  inheritedStyles: getInheritedTextStyles(),
142
160
  };
@@ -35,6 +35,7 @@ function RenderRepeatedBlock(props) {
35
35
  return (React.createElement(builder_context_js_1.default.Provider, { value: {
36
36
  content: props.repeatContext.content,
37
37
  state: props.repeatContext.state,
38
+ setState: props.repeatContext.setState,
38
39
  context: props.repeatContext.context,
39
40
  apiKey: props.repeatContext.apiKey,
40
41
  registeredComponents: props.repeatContext.registeredComponents,
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFontCss = exports.getCss = void 0;
4
+ const getCssFromFont = (font) => {
5
+ var _a, _b;
6
+ const family = font.family + (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
7
+ const name = family.split(",")[0];
8
+ const url = (_b = font.fileUrl) != null ? _b : (_a = font == null ? void 0 : font.files) == null ? void 0 : _a.regular;
9
+ let str = "";
10
+ if (url && family && name) {
11
+ str += `
12
+ @font-face {
13
+ font-family: "${family}";
14
+ src: local("${name}"), url('${url}') format('woff2');
15
+ font-display: fallback;
16
+ font-weight: 400;
17
+ }
18
+ `.trim();
19
+ }
20
+ if (font.files) {
21
+ for (const weight in font.files) {
22
+ const isNumber = String(Number(weight)) === weight;
23
+ if (!isNumber) {
24
+ continue;
25
+ }
26
+ const weightUrl = font.files[weight];
27
+ if (weightUrl && weightUrl !== url) {
28
+ str += `
29
+ @font-face {
30
+ font-family: "${family}";
31
+ src: url('${weightUrl}') format('woff2');
32
+ font-display: fallback;
33
+ font-weight: ${weight};
34
+ }
35
+ `.trim();
36
+ }
37
+ }
38
+ }
39
+ return str;
40
+ };
41
+ const getFontCss = ({ customFonts }) => {
42
+ var _a;
43
+ return ((_a = customFonts == null ? void 0 : customFonts.map((font) => getCssFromFont(font))) == null ? void 0 : _a.join(" ")) || "";
44
+ };
45
+ exports.getFontCss = getFontCss;
46
+ const getCss = ({ cssCode, contentId }) => {
47
+ if (!cssCode) {
48
+ return "";
49
+ }
50
+ if (!contentId) {
51
+ return cssCode;
52
+ }
53
+ return (cssCode == null ? void 0 : cssCode.replace(/&/g, `div[builder-content-id="${contentId}"]`)) || "";
54
+ };
55
+ exports.getCss = getCss;
@@ -28,64 +28,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const React = __importStar(require("react"));
30
30
  const react_native_1 = require("react-native");
31
+ const react_1 = require("react");
31
32
  const render_inlined_styles_1 = __importDefault(require("../../render-inlined-styles"));
33
+ const render_styles_helpers_1 = require("./render-styles.helpers");
34
+ const render_styles_helpers_2 = require("./render-styles.helpers");
32
35
  function RenderContentStyles(props) {
33
- function getCssFromFont(font) {
34
- var _a, _b;
35
- // TODO: compute what font sizes are used and only load those.......
36
- const family = font.family +
37
- (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
38
- const name = family.split(",")[0];
39
- const url = (_a = font.fileUrl) !== null && _a !== void 0 ? _a : (_b = font === null || font === void 0 ? void 0 : font.files) === null || _b === void 0 ? void 0 : _b.regular;
40
- let str = "";
41
- if (url && family && name) {
42
- str += `
43
- @font-face {
44
- font-family: "${family}";
45
- src: local("${name}"), url('${url}') format('woff2');
46
- font-display: fallback;
47
- font-weight: 400;
48
- }
49
- `.trim();
50
- }
51
- if (font.files) {
52
- for (const weight in font.files) {
53
- const isNumber = String(Number(weight)) === weight;
54
- if (!isNumber) {
55
- continue;
56
- }
57
- // TODO: maybe limit number loaded
58
- const weightUrl = font.files[weight];
59
- if (weightUrl && weightUrl !== url) {
60
- str += `
61
- @font-face {
62
- font-family: "${family}";
63
- src: url('${weightUrl}') format('woff2');
64
- font-display: fallback;
65
- font-weight: ${weight};
66
- }
67
- `.trim();
68
- }
69
- }
70
- }
71
- return str;
72
- }
73
- function getFontCss({ customFonts }) {
74
- var _a;
75
- // TODO: flag for this
76
- // if (!builder.allowCustomFonts) {
77
- // return '';
78
- // }
79
- // TODO: separate internal data from external
80
- return ((_a = customFonts === null || customFonts === void 0 ? void 0 : customFonts.map((font) => getCssFromFont(font))) === null || _a === void 0 ? void 0 : _a.join(" ")) || "";
81
- }
82
- function injectedStyles() {
83
- return `
84
- ${props.cssCode || ""}
85
- ${getFontCss({
86
- customFonts: props.customFonts,
87
- })}`;
88
- }
89
- return React.createElement(render_inlined_styles_1.default, { styles: injectedStyles() });
36
+ const [injectedStyles, setInjectedStyles] = (0, react_1.useState)(() => `
37
+ ${(0, render_styles_helpers_1.getCss)({
38
+ cssCode: props.cssCode,
39
+ contentId: props.contentId,
40
+ })}
41
+ ${(0, render_styles_helpers_2.getFontCss)({
42
+ customFonts: props.customFonts,
43
+ })}
44
+ `);
45
+ return React.createElement(render_inlined_styles_1.default, { styles: injectedStyles });
90
46
  }
91
47
  exports.default = RenderContentStyles;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getContextStateInitialValue = exports.getContentInitialValue = void 0;
4
+ var __defProp = Object.defineProperty;
5
+ var __defProps = Object.defineProperties;
6
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
7
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
19
+ }
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
+ const getContextStateInitialValue = ({ content, data, locale }) => {
24
+ var _a, _b, _c;
25
+ const defaultValues = {};
26
+ (_b = (_a = content == null ? void 0 : content.data) == null ? void 0 : _a.inputs) == null ? void 0 : _b.forEach((input) => {
27
+ var _a2;
28
+ if (input.name && input.defaultValue !== void 0 && ((_a2 = content == null ? void 0 : content.data) == null ? void 0 : _a2.state) && content.data.state[input.name] === void 0) {
29
+ defaultValues[input.name] = input.defaultValue;
30
+ }
31
+ });
32
+ const stateToUse = __spreadValues(__spreadValues(__spreadValues({}, (_c = content == null ? void 0 : content.data) == null ? void 0 : _c.state), data), locale ? { locale } : {});
33
+ return __spreadValues(__spreadValues({}, defaultValues), stateToUse);
34
+ };
35
+ exports.getContextStateInitialValue = getContextStateInitialValue;
36
+ const getContentInitialValue = ({ content, data }) => {
37
+ return !content ? void 0 : __spreadProps(__spreadValues({}, content), {
38
+ data: __spreadValues(__spreadValues({}, content == null ? void 0 : content.data), data),
39
+ meta: content == null ? void 0 : content.meta
40
+ });
41
+ };
42
+ exports.getContentInitialValue = getContentInitialValue;
@@ -45,51 +45,51 @@ const builder_context_js_1 = __importDefault(require("../../context/builder.cont
45
45
  const init_editing_js_1 = require("../../scripts/init-editing.js");
46
46
  const nullable_js_1 = require("../../helpers/nullable.js");
47
47
  const interaction_js_1 = require("../../functions/track/interaction.js");
48
+ const render_content_helpers_js_1 = require("./render-content.helpers.js");
48
49
  function RenderContent(props) {
49
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
50
+ var _a, _b, _c, _d, _e;
50
51
  const elementRef = (0, react_1.useRef)(null);
51
52
  const [forceReRenderCount, setForceReRenderCount] = (0, react_1.useState)(() => 0);
52
53
  const [overrideContent, setOverrideContent] = (0, react_1.useState)(() => null);
53
- function useContent() {
54
- var _a, _b, _c, _d, _e;
55
- if (!props.content && !overrideContent) {
56
- return undefined;
57
- }
58
- return {
59
- ...props.content,
60
- ...overrideContent,
54
+ const [useContent, setUseContent] = (0, react_1.useState)(() => (0, render_content_helpers_js_1.getContentInitialValue)({
55
+ content: props.content,
56
+ data: props.data,
57
+ }));
58
+ function mergeNewContent(newContent) {
59
+ var _a, _b;
60
+ setUseContent({
61
+ ...useContent,
62
+ ...newContent,
61
63
  data: {
62
- ...(_a = props.content) === null || _a === void 0 ? void 0 : _a.data,
63
- ...props.data,
64
- ...overrideContent === null || overrideContent === void 0 ? void 0 : overrideContent.data,
64
+ ...useContent === null || useContent === void 0 ? void 0 : useContent.data,
65
+ ...newContent === null || newContent === void 0 ? void 0 : newContent.data,
65
66
  },
66
67
  meta: {
67
- ...(_b = props.content) === null || _b === void 0 ? void 0 : _b.meta,
68
- ...overrideContent === null || overrideContent === void 0 ? void 0 : overrideContent.meta,
69
- breakpoints: useBreakpoints ||
70
- ((_c = overrideContent === null || overrideContent === void 0 ? void 0 : overrideContent.meta) === null || _c === void 0 ? void 0 : _c.breakpoints) ||
71
- ((_e = (_d = props.content) === null || _d === void 0 ? void 0 : _d.meta) === null || _e === void 0 ? void 0 : _e.breakpoints),
68
+ ...useContent === null || useContent === void 0 ? void 0 : useContent.meta,
69
+ ...newContent === null || newContent === void 0 ? void 0 : newContent.meta,
70
+ breakpoints: ((_a = newContent === null || newContent === void 0 ? void 0 : newContent.meta) === null || _a === void 0 ? void 0 : _a.breakpoints) || ((_b = useContent === null || useContent === void 0 ? void 0 : useContent.meta) === null || _b === void 0 ? void 0 : _b.breakpoints),
72
71
  },
73
- };
72
+ });
73
+ }
74
+ function setBreakpoints(breakpoints) {
75
+ setUseContent({
76
+ ...useContent,
77
+ meta: {
78
+ ...useContent === null || useContent === void 0 ? void 0 : useContent.meta,
79
+ breakpoints,
80
+ },
81
+ });
74
82
  }
75
83
  const [update, setUpdate] = (0, react_1.useState)(() => 0);
76
- const [useBreakpoints, setUseBreakpoints] = (0, react_1.useState)(() => null);
77
84
  const [canTrackToUse, setCanTrackToUse] = (0, react_1.useState)(() => (0, nullable_js_1.checkIsDefined)(props.canTrack) ? props.canTrack : true);
78
- const [overrideState, setOverrideState] = (0, react_1.useState)(() => ({}));
79
- function contentState() {
80
- var _a, _b;
81
- return {
82
- ...(_b = (_a = props.content) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.state,
83
- ...props.data,
84
- ...(props.locale
85
- ? {
86
- locale: props.locale,
87
- }
88
- : {}),
89
- ...overrideState,
90
- };
85
+ const [contentState, setContentState] = (0, react_1.useState)(() => (0, render_content_helpers_js_1.getContextStateInitialValue)({
86
+ content: props.content,
87
+ data: props.data,
88
+ locale: props.locale,
89
+ }));
90
+ function setContextState(newState) {
91
+ setContentState(newState);
91
92
  }
92
- const [contextContext, setContextContext] = (0, react_1.useState)(() => props.context || {});
93
93
  const [allRegisteredComponents, setAllRegisteredComponents] = (0, react_1.useState)(() => [
94
94
  ...(0, builder_registered_components_js_1.getDefaultRegisteredComponents)(),
95
95
  // While this `components` object is deprecated, we must maintain support for it.
@@ -104,17 +104,18 @@ function RenderContent(props) {
104
104
  [curr.name]: curr,
105
105
  }), {}));
106
106
  function processMessage(event) {
107
- var _a;
108
107
  const { data } = event;
109
108
  if (data) {
110
109
  switch (data.type) {
111
110
  case "builder.configureSdk": {
112
111
  const messageContent = data.data;
113
112
  const { breakpoints, contentId } = messageContent;
114
- if (!contentId || contentId !== ((_a = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _a === void 0 ? void 0 : _a.id)) {
113
+ if (!contentId || contentId !== (useContent === null || useContent === void 0 ? void 0 : useContent.id)) {
115
114
  return;
116
115
  }
117
- setUseBreakpoints(breakpoints);
116
+ if (breakpoints) {
117
+ setBreakpoints(breakpoints);
118
+ }
118
119
  setForceReRenderCount(forceReRenderCount + 1); // This is a hack to force Qwik to re-render.
119
120
  break;
120
121
  }
@@ -126,7 +127,7 @@ function RenderContent(props) {
126
127
  messageContent.modelName;
127
128
  const contentData = messageContent.data;
128
129
  if (key === props.model) {
129
- setOverrideContent(contentData);
130
+ mergeNewContent(contentData);
130
131
  setForceReRenderCount(forceReRenderCount + 1); // This is a hack to force Qwik to re-render.
131
132
  }
132
133
  break;
@@ -139,24 +140,23 @@ function RenderContent(props) {
139
140
  }
140
141
  }
141
142
  function evaluateJsCode() {
142
- var _a, _b;
143
+ var _a;
143
144
  // run any dynamic JS code attached to content
144
- const jsCode = (_b = (_a = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.jsCode;
145
+ const jsCode = (_a = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _a === void 0 ? void 0 : _a.jsCode;
145
146
  if (jsCode) {
146
147
  (0, evaluate_js_1.evaluate)({
147
148
  code: jsCode,
148
- context: contextContext,
149
- state: contentState(),
149
+ context: props.context || {},
150
+ state: contentState,
150
151
  });
151
152
  }
152
153
  }
153
154
  const [httpReqsData, setHttpReqsData] = (0, react_1.useState)(() => ({}));
154
155
  const [clicked, setClicked] = (0, react_1.useState)(() => false);
155
156
  function onClick(event) {
156
- var _a, _b;
157
- if (useContent()) {
158
- const variationId = (_a = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _a === void 0 ? void 0 : _a.testVariationId;
159
- const contentId = (_b = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _b === void 0 ? void 0 : _b.id;
157
+ if (useContent) {
158
+ const variationId = useContent === null || useContent === void 0 ? void 0 : useContent.testVariationId;
159
+ const contentId = useContent === null || useContent === void 0 ? void 0 : useContent.id;
160
160
  (0, index_js_2._track)({
161
161
  type: "click",
162
162
  canTrack: canTrackToUse,
@@ -174,27 +174,27 @@ function RenderContent(props) {
174
174
  function evalExpression(expression) {
175
175
  return expression.replace(/{{([^}]+)}}/g, (_match, group) => (0, evaluate_js_1.evaluate)({
176
176
  code: group,
177
- context: contextContext,
178
- state: contentState(),
177
+ context: props.context || {},
178
+ state: contentState,
179
179
  }));
180
180
  }
181
181
  function handleRequest({ url, key }) {
182
182
  (0, get_fetch_js_1.fetch)(url)
183
183
  .then((response) => response.json())
184
184
  .then((json) => {
185
- const newOverrideState = {
186
- ...overrideState,
185
+ const newState = {
186
+ ...contentState,
187
187
  [key]: json,
188
188
  };
189
- setOverrideState(newOverrideState);
189
+ setContextState(newState);
190
190
  })
191
191
  .catch((err) => {
192
192
  console.log("error fetching dynamic data", url, err);
193
193
  });
194
194
  }
195
195
  function runHttpRequests() {
196
- var _a, _b, _c;
197
- const requests = (_c = (_b = (_a = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.httpRequests) !== null && _c !== void 0 ? _c : {};
196
+ var _a, _b;
197
+ const requests = (_b = (_a = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _a === void 0 ? void 0 : _a.httpRequests) !== null && _b !== void 0 ? _b : {};
198
198
  Object.entries(requests).forEach(([key, url]) => {
199
199
  if (url && (!httpReqsData[key] || (0, is_editing_js_1.isEditing)())) {
200
200
  const evaluatedUrl = evalExpression(url);
@@ -209,7 +209,7 @@ function RenderContent(props) {
209
209
  if ((0, is_editing_js_1.isEditing)()) {
210
210
  window.dispatchEvent(new CustomEvent("builder:component:stateChange", {
211
211
  detail: {
212
- state: contentState(),
212
+ state: contentState,
213
213
  ref: {
214
214
  name: props.model,
215
215
  },
@@ -218,13 +218,11 @@ function RenderContent(props) {
218
218
  }
219
219
  }
220
220
  function shouldRenderContentStyles() {
221
- var _a, _b, _c, _d, _e;
222
- return Boolean((((_b = (_a = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.cssCode) ||
223
- ((_e = (_d = (_c = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.customFonts) === null || _e === void 0 ? void 0 : _e.length)) &&
221
+ var _a, _b, _c;
222
+ return Boolean((((_a = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _a === void 0 ? void 0 : _a.cssCode) || ((_c = (_b = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _b === void 0 ? void 0 : _b.customFonts) === null || _c === void 0 ? void 0 : _c.length)) &&
224
223
  target_js_1.TARGET !== "reactNative");
225
224
  }
226
225
  (0, react_1.useEffect)(() => {
227
- var _a, _b;
228
226
  if (!props.apiKey) {
229
227
  console.error("[Builder.io]: No API key provided to `RenderContent` component. This can cause issues. Please provide an API key using the `apiKey` prop.");
230
228
  }
@@ -252,9 +250,9 @@ function RenderContent(props) {
252
250
  window.addEventListener("message", processMessage);
253
251
  window.addEventListener("builder:component:stateChangeListenerActivated", emitStateUpdate);
254
252
  }
255
- if (useContent()) {
256
- const variationId = (_a = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _a === void 0 ? void 0 : _a.testVariationId;
257
- const contentId = (_b = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _b === void 0 ? void 0 : _b.id;
253
+ if (useContent) {
254
+ const variationId = useContent === null || useContent === void 0 ? void 0 : useContent.testVariationId;
255
+ const contentId = useContent === null || useContent === void 0 ? void 0 : useContent.id;
258
256
  (0, index_js_2._track)({
259
257
  type: "impression",
260
258
  canTrack: canTrackToUse,
@@ -284,7 +282,7 @@ function RenderContent(props) {
284
282
  apiKey: props.apiKey,
285
283
  }).then((content) => {
286
284
  if (content) {
287
- setOverrideContent(content);
285
+ mergeNewContent(content);
288
286
  }
289
287
  });
290
288
  }
@@ -296,13 +294,13 @@ function RenderContent(props) {
296
294
  }, []);
297
295
  (0, react_1.useEffect)(() => {
298
296
  evaluateJsCode();
299
- }, [(_b = (_a = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.jsCode, contentState()]);
297
+ }, [(_a = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _a === void 0 ? void 0 : _a.jsCode, contentState]);
300
298
  (0, react_1.useEffect)(() => {
301
299
  runHttpRequests();
302
- }, [(_d = (_c = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.httpRequests]);
300
+ }, [(_b = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _b === void 0 ? void 0 : _b.httpRequests]);
303
301
  (0, react_1.useEffect)(() => {
304
302
  emitStateUpdate();
305
- }, [contentState()]);
303
+ }, [contentState]);
306
304
  (0, react_1.useEffect)(() => {
307
305
  return () => {
308
306
  if ((0, is_browser_js_1.isBrowser)()) {
@@ -312,14 +310,15 @@ function RenderContent(props) {
312
310
  };
313
311
  }, []);
314
312
  return (React.createElement(builder_context_js_1.default.Provider, { value: {
315
- content: useContent(),
316
- state: contentState(),
317
- context: contextContext,
313
+ content: useContent,
314
+ state: contentState,
315
+ setState: setContextState,
316
+ context: props.context || {},
318
317
  apiKey: props.apiKey,
319
318
  registeredComponents: allRegisteredComponents,
320
- } }, useContent() ? (React.createElement(React.Fragment, null,
321
- React.createElement(react_native_1.View, { ref: elementRef, onClick: (event) => onClick(event), "builder-content-id": (_e = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _e === void 0 ? void 0 : _e.id, "builder-model": props.model },
322
- shouldRenderContentStyles() ? (React.createElement(render_styles_1.default, { cssCode: (_g = (_f = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.cssCode, customFonts: (_j = (_h = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.customFonts })) : null,
323
- React.createElement(render_blocks_1.default, { blocks: (_l = (_k = useContent === null || useContent === void 0 ? void 0 : useContent()) === null || _k === void 0 ? void 0 : _k.data) === null || _l === void 0 ? void 0 : _l.blocks, key: forceReRenderCount })))) : null));
319
+ } }, useContent ? (React.createElement(React.Fragment, null,
320
+ React.createElement(react_native_1.View, { ref: elementRef, onClick: (event) => onClick(event), "builder-content-id": useContent === null || useContent === void 0 ? void 0 : useContent.id, "builder-model": props.model },
321
+ shouldRenderContentStyles() ? (React.createElement(render_styles_1.default, { contentId: useContent === null || useContent === void 0 ? void 0 : useContent.id, cssCode: (_c = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _c === void 0 ? void 0 : _c.cssCode, customFonts: (_d = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _d === void 0 ? void 0 : _d.customFonts })) : null,
322
+ React.createElement(render_blocks_1.default, { blocks: (_e = useContent === null || useContent === void 0 ? void 0 : useContent.data) === null || _e === void 0 ? void 0 : _e.blocks, key: forceReRenderCount })))) : null));
324
323
  }
325
324
  exports.default = RenderContent;
@@ -0,0 +1 @@
1
+ "use strict";
@@ -6,6 +6,8 @@ var stdin_default = (0, react_1.createContext)({
6
6
  content: null,
7
7
  context: {},
8
8
  state: {},
9
+ setState() {
10
+ },
9
11
  apiKey: null,
10
12
  registeredComponents: {},
11
13
  inheritedStyles: {}
@@ -0,0 +1 @@
1
+ "use strict";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@builder.io/sdk-react-native",
3
3
  "description": "Builder.io SDK for React Native",
4
- "version": "0.1.4",
4
+ "version": "0.1.5",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -41,10 +41,30 @@ export default function RenderBlock(props) {
41
41
  });
42
42
  }
43
43
 
44
+ function proxyState() {
45
+ if (typeof Proxy === "undefined") {
46
+ console.error(
47
+ "no Proxy available in this environment, cannot proxy state."
48
+ );
49
+ return props.context.state;
50
+ }
51
+ const useState = new Proxy(props.context.state, {
52
+ set: (obj, prop, value) => {
53
+ // set the value on the state object, so that the event handler instantly gets the update.
54
+ obj[prop] = value;
55
+
56
+ // set the value in the context, so that the rest of the app gets the update.
57
+ props.context.setState?.(obj);
58
+ return true;
59
+ },
60
+ });
61
+ return useState;
62
+ }
63
+
44
64
  function actions() {
45
65
  return getBlockActions({
46
66
  block: useBlock(),
47
- state: props.context.state,
67
+ state: proxyState(),
48
68
  context: props.context.context,
49
69
  });
50
70
  }
@@ -126,6 +146,7 @@ export default function RenderBlock(props) {
126
146
  state: props.context.state,
127
147
  content: props.context.content,
128
148
  context: props.context.context,
149
+ setState: props.context.setState,
129
150
  registeredComponents: props.context.registeredComponents,
130
151
  inheritedStyles: getInheritedTextStyles(),
131
152
  };
@@ -10,6 +10,7 @@ export default function RenderRepeatedBlock(props) {
10
10
  value={{
11
11
  content: props.repeatContext.content,
12
12
  state: props.repeatContext.state,
13
+ setState: props.repeatContext.setState,
13
14
  context: props.repeatContext.context,
14
15
  apiKey: props.repeatContext.apiKey,
15
16
  registeredComponents: props.repeatContext.registeredComponents,
@@ -0,0 +1,57 @@
1
+ const getCssFromFont = (font) => {
2
+ var _a, _b;
3
+ const family = font.family + (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
4
+ const name = family.split(",")[0];
5
+ const url = (_b = font.fileUrl) != null ? _b : (_a = font == null ? void 0 : font.files) == null ? void 0 : _a.regular;
6
+ let str = "";
7
+ if (url && family && name) {
8
+ str += `
9
+ @font-face {
10
+ font-family: "${family}";
11
+ src: local("${name}"), url('${url}') format('woff2');
12
+ font-display: fallback;
13
+ font-weight: 400;
14
+ }
15
+ `.trim();
16
+ }
17
+ if (font.files) {
18
+ for (const weight in font.files) {
19
+ const isNumber = String(Number(weight)) === weight;
20
+ if (!isNumber) {
21
+ continue;
22
+ }
23
+ const weightUrl = font.files[weight];
24
+ if (weightUrl && weightUrl !== url) {
25
+ str += `
26
+ @font-face {
27
+ font-family: "${family}";
28
+ src: url('${weightUrl}') format('woff2');
29
+ font-display: fallback;
30
+ font-weight: ${weight};
31
+ }
32
+ `.trim();
33
+ }
34
+ }
35
+ }
36
+ return str;
37
+ };
38
+ const getFontCss = ({ customFonts }) => {
39
+ var _a;
40
+ return ((_a = customFonts == null ? void 0 : customFonts.map((font) => getCssFromFont(font))) == null ? void 0 : _a.join(" ")) || "";
41
+ };
42
+ const getCss = ({
43
+ cssCode,
44
+ contentId
45
+ }) => {
46
+ if (!cssCode) {
47
+ return "";
48
+ }
49
+ if (!contentId) {
50
+ return cssCode;
51
+ }
52
+ return (cssCode == null ? void 0 : cssCode.replace(/&/g, `div[builder-content-id="${contentId}"]`)) || "";
53
+ };
54
+ export {
55
+ getCss,
56
+ getFontCss
57
+ };
@@ -1,65 +1,22 @@
1
1
  import * as React from "react";
2
2
  import { View, StyleSheet, Image, Text } from "react-native";
3
+ import { useState } from "react";
3
4
  import RenderInlinedStyles from "../../render-inlined-styles";
5
+ import { getCss } from "./render-styles.helpers";
6
+ import { getFontCss } from "./render-styles.helpers";
4
7
 
5
8
  export default function RenderContentStyles(props) {
6
- function getCssFromFont(font) {
7
- // TODO: compute what font sizes are used and only load those.......
8
- const family =
9
- font.family +
10
- (font.kind && !font.kind.includes("#") ? ", " + font.kind : "");
11
- const name = family.split(",")[0];
12
- const url = font.fileUrl ?? font?.files?.regular;
13
- let str = "";
14
- if (url && family && name) {
15
- str += `
16
- @font-face {
17
- font-family: "${family}";
18
- src: local("${name}"), url('${url}') format('woff2');
19
- font-display: fallback;
20
- font-weight: 400;
21
- }
22
- `.trim();
23
- }
24
- if (font.files) {
25
- for (const weight in font.files) {
26
- const isNumber = String(Number(weight)) === weight;
27
- if (!isNumber) {
28
- continue;
29
- }
30
- // TODO: maybe limit number loaded
31
- const weightUrl = font.files[weight];
32
- if (weightUrl && weightUrl !== url) {
33
- str += `
34
- @font-face {
35
- font-family: "${family}";
36
- src: url('${weightUrl}') format('woff2');
37
- font-display: fallback;
38
- font-weight: ${weight};
39
- }
40
- `.trim();
41
- }
42
- }
43
- }
44
- return str;
45
- }
46
-
47
- function getFontCss({ customFonts }) {
48
- // TODO: flag for this
49
- // if (!builder.allowCustomFonts) {
50
- // return '';
51
- // }
52
- // TODO: separate internal data from external
53
- return customFonts?.map((font) => getCssFromFont(font))?.join(" ") || "";
54
- }
55
-
56
- function injectedStyles() {
57
- return `
58
- ${props.cssCode || ""}
9
+ const [injectedStyles, setInjectedStyles] = useState(
10
+ () => `
11
+ ${getCss({
12
+ cssCode: props.cssCode,
13
+ contentId: props.contentId,
14
+ })}
59
15
  ${getFontCss({
60
16
  customFonts: props.customFonts,
61
- })}`;
62
- }
17
+ })}
18
+ `
19
+ );
63
20
 
64
- return <RenderInlinedStyles styles={injectedStyles()} />;
21
+ return <RenderInlinedStyles styles={injectedStyles} />;
65
22
  }
@@ -0,0 +1,48 @@
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
+ const getContextStateInitialValue = ({
21
+ content,
22
+ data,
23
+ locale
24
+ }) => {
25
+ var _a, _b, _c;
26
+ const defaultValues = {};
27
+ (_b = (_a = content == null ? void 0 : content.data) == null ? void 0 : _a.inputs) == null ? void 0 : _b.forEach((input) => {
28
+ var _a2;
29
+ if (input.name && input.defaultValue !== void 0 && ((_a2 = content == null ? void 0 : content.data) == null ? void 0 : _a2.state) && content.data.state[input.name] === void 0) {
30
+ defaultValues[input.name] = input.defaultValue;
31
+ }
32
+ });
33
+ const stateToUse = __spreadValues(__spreadValues(__spreadValues({}, (_c = content == null ? void 0 : content.data) == null ? void 0 : _c.state), data), locale ? { locale } : {});
34
+ return __spreadValues(__spreadValues({}, defaultValues), stateToUse);
35
+ };
36
+ const getContentInitialValue = ({
37
+ content,
38
+ data
39
+ }) => {
40
+ return !content ? void 0 : __spreadProps(__spreadValues({}, content), {
41
+ data: __spreadValues(__spreadValues({}, content == null ? void 0 : content.data), data),
42
+ meta: content == null ? void 0 : content.meta
43
+ });
44
+ };
45
+ export {
46
+ getContentInitialValue,
47
+ getContextStateInitialValue
48
+ };
@@ -23,6 +23,10 @@ import {
23
23
  } from "../../scripts/init-editing.js";
24
24
  import { checkIsDefined } from "../../helpers/nullable.js";
25
25
  import { getInteractionPropertiesForEvent } from "../../functions/track/interaction.js";
26
+ import {
27
+ getContentInitialValue,
28
+ getContextStateInitialValue,
29
+ } from "./render-content.helpers.js";
26
30
 
27
31
  export default function RenderContent(props) {
28
32
  const elementRef = useRef(null);
@@ -30,56 +34,58 @@ export default function RenderContent(props) {
30
34
 
31
35
  const [overrideContent, setOverrideContent] = useState(() => null);
32
36
 
33
- function useContent() {
34
- if (!props.content && !overrideContent) {
35
- return undefined;
36
- }
37
- return {
38
- ...props.content,
39
- ...overrideContent,
37
+ const [useContent, setUseContent] = useState(() =>
38
+ getContentInitialValue({
39
+ content: props.content,
40
+ data: props.data,
41
+ })
42
+ );
43
+
44
+ function mergeNewContent(newContent) {
45
+ setUseContent({
46
+ ...useContent,
47
+ ...newContent,
40
48
  data: {
41
- ...props.content?.data,
42
- ...props.data,
43
- ...overrideContent?.data,
49
+ ...useContent?.data,
50
+ ...newContent?.data,
44
51
  },
45
52
  meta: {
46
- ...props.content?.meta,
47
- ...overrideContent?.meta,
53
+ ...useContent?.meta,
54
+ ...newContent?.meta,
48
55
  breakpoints:
49
- useBreakpoints ||
50
- overrideContent?.meta?.breakpoints ||
51
- props.content?.meta?.breakpoints,
56
+ newContent?.meta?.breakpoints || useContent?.meta?.breakpoints,
52
57
  },
53
- };
58
+ });
54
59
  }
55
60
 
56
- const [update, setUpdate] = useState(() => 0);
61
+ function setBreakpoints(breakpoints) {
62
+ setUseContent({
63
+ ...useContent,
64
+ meta: {
65
+ ...useContent?.meta,
66
+ breakpoints,
67
+ },
68
+ });
69
+ }
57
70
 
58
- const [useBreakpoints, setUseBreakpoints] = useState(() => null);
71
+ const [update, setUpdate] = useState(() => 0);
59
72
 
60
73
  const [canTrackToUse, setCanTrackToUse] = useState(() =>
61
74
  checkIsDefined(props.canTrack) ? props.canTrack : true
62
75
  );
63
76
 
64
- const [overrideState, setOverrideState] = useState(() => ({}));
77
+ const [contentState, setContentState] = useState(() =>
78
+ getContextStateInitialValue({
79
+ content: props.content,
80
+ data: props.data,
81
+ locale: props.locale,
82
+ })
83
+ );
65
84
 
66
- function contentState() {
67
- return {
68
- ...props.content?.data?.state,
69
- ...props.data,
70
- ...(props.locale
71
- ? {
72
- locale: props.locale,
73
- }
74
- : {}),
75
- ...overrideState,
76
- };
85
+ function setContextState(newState) {
86
+ setContentState(newState);
77
87
  }
78
88
 
79
- const [contextContext, setContextContext] = useState(
80
- () => props.context || {}
81
- );
82
-
83
89
  const [allRegisteredComponents, setAllRegisteredComponents] = useState(() =>
84
90
  [
85
91
  ...getDefaultRegisteredComponents(),
@@ -106,10 +112,12 @@ export default function RenderContent(props) {
106
112
  case "builder.configureSdk": {
107
113
  const messageContent = data.data;
108
114
  const { breakpoints, contentId } = messageContent;
109
- if (!contentId || contentId !== useContent?.()?.id) {
115
+ if (!contentId || contentId !== useContent?.id) {
110
116
  return;
111
117
  }
112
- setUseBreakpoints(breakpoints);
118
+ if (breakpoints) {
119
+ setBreakpoints(breakpoints);
120
+ }
113
121
  setForceReRenderCount(forceReRenderCount + 1); // This is a hack to force Qwik to re-render.
114
122
  break;
115
123
  }
@@ -122,7 +130,7 @@ export default function RenderContent(props) {
122
130
  messageContent.modelName;
123
131
  const contentData = messageContent.data;
124
132
  if (key === props.model) {
125
- setOverrideContent(contentData);
133
+ mergeNewContent(contentData);
126
134
  setForceReRenderCount(forceReRenderCount + 1); // This is a hack to force Qwik to re-render.
127
135
  }
128
136
 
@@ -138,12 +146,12 @@ export default function RenderContent(props) {
138
146
 
139
147
  function evaluateJsCode() {
140
148
  // run any dynamic JS code attached to content
141
- const jsCode = useContent?.()?.data?.jsCode;
149
+ const jsCode = useContent?.data?.jsCode;
142
150
  if (jsCode) {
143
151
  evaluate({
144
152
  code: jsCode,
145
- context: contextContext,
146
- state: contentState(),
153
+ context: props.context || {},
154
+ state: contentState,
147
155
  });
148
156
  }
149
157
  }
@@ -153,9 +161,9 @@ export default function RenderContent(props) {
153
161
  const [clicked, setClicked] = useState(() => false);
154
162
 
155
163
  function onClick(event) {
156
- if (useContent()) {
157
- const variationId = useContent?.()?.testVariationId;
158
- const contentId = useContent?.()?.id;
164
+ if (useContent) {
165
+ const variationId = useContent?.testVariationId;
166
+ const contentId = useContent?.id;
159
167
  _track({
160
168
  type: "click",
161
169
  canTrack: canTrackToUse,
@@ -175,8 +183,8 @@ export default function RenderContent(props) {
175
183
  return expression.replace(/{{([^}]+)}}/g, (_match, group) =>
176
184
  evaluate({
177
185
  code: group,
178
- context: contextContext,
179
- state: contentState(),
186
+ context: props.context || {},
187
+ state: contentState,
180
188
  })
181
189
  );
182
190
  }
@@ -185,11 +193,11 @@ export default function RenderContent(props) {
185
193
  fetch(url)
186
194
  .then((response) => response.json())
187
195
  .then((json) => {
188
- const newOverrideState = {
189
- ...overrideState,
196
+ const newState = {
197
+ ...contentState,
190
198
  [key]: json,
191
199
  };
192
- setOverrideState(newOverrideState);
200
+ setContextState(newState);
193
201
  })
194
202
  .catch((err) => {
195
203
  console.log("error fetching dynamic data", url, err);
@@ -197,7 +205,7 @@ export default function RenderContent(props) {
197
205
  }
198
206
 
199
207
  function runHttpRequests() {
200
- const requests = useContent?.()?.data?.httpRequests ?? {};
208
+ const requests = useContent?.data?.httpRequests ?? {};
201
209
  Object.entries(requests).forEach(([key, url]) => {
202
210
  if (url && (!httpReqsData[key] || isEditing())) {
203
211
  const evaluatedUrl = evalExpression(url);
@@ -214,7 +222,7 @@ export default function RenderContent(props) {
214
222
  window.dispatchEvent(
215
223
  new CustomEvent("builder:component:stateChange", {
216
224
  detail: {
217
- state: contentState(),
225
+ state: contentState,
218
226
  ref: {
219
227
  name: props.model,
220
228
  },
@@ -226,8 +234,7 @@ export default function RenderContent(props) {
226
234
 
227
235
  function shouldRenderContentStyles() {
228
236
  return Boolean(
229
- (useContent?.()?.data?.cssCode ||
230
- useContent?.()?.data?.customFonts?.length) &&
237
+ (useContent?.data?.cssCode || useContent?.data?.customFonts?.length) &&
231
238
  TARGET !== "reactNative"
232
239
  );
233
240
  }
@@ -266,9 +273,9 @@ export default function RenderContent(props) {
266
273
  emitStateUpdate
267
274
  );
268
275
  }
269
- if (useContent()) {
270
- const variationId = useContent?.()?.testVariationId;
271
- const contentId = useContent?.()?.id;
276
+ if (useContent) {
277
+ const variationId = useContent?.testVariationId;
278
+ const contentId = useContent?.id;
272
279
  _track({
273
280
  type: "impression",
274
281
  canTrack: canTrackToUse,
@@ -303,7 +310,7 @@ export default function RenderContent(props) {
303
310
  apiKey: props.apiKey,
304
311
  }).then((content) => {
305
312
  if (content) {
306
- setOverrideContent(content);
313
+ mergeNewContent(content);
307
314
  }
308
315
  });
309
316
  }
@@ -316,13 +323,13 @@ export default function RenderContent(props) {
316
323
 
317
324
  useEffect(() => {
318
325
  evaluateJsCode();
319
- }, [useContent?.()?.data?.jsCode, contentState()]);
326
+ }, [useContent?.data?.jsCode, contentState]);
320
327
  useEffect(() => {
321
328
  runHttpRequests();
322
- }, [useContent?.()?.data?.httpRequests]);
329
+ }, [useContent?.data?.httpRequests]);
323
330
  useEffect(() => {
324
331
  emitStateUpdate();
325
- }, [contentState()]);
332
+ }, [contentState]);
326
333
 
327
334
  useEffect(() => {
328
335
  return () => {
@@ -339,30 +346,32 @@ export default function RenderContent(props) {
339
346
  return (
340
347
  <builderContext.Provider
341
348
  value={{
342
- content: useContent(),
343
- state: contentState(),
344
- context: contextContext,
349
+ content: useContent,
350
+ state: contentState,
351
+ setState: setContextState,
352
+ context: props.context || {},
345
353
  apiKey: props.apiKey,
346
354
  registeredComponents: allRegisteredComponents,
347
355
  }}
348
356
  >
349
- {useContent() ? (
357
+ {useContent ? (
350
358
  <>
351
359
  <View
352
360
  ref={elementRef}
353
361
  onClick={(event) => onClick(event)}
354
- builder-content-id={useContent?.()?.id}
362
+ builder-content-id={useContent?.id}
355
363
  builder-model={props.model}
356
364
  >
357
365
  {shouldRenderContentStyles() ? (
358
366
  <RenderContentStyles
359
- cssCode={useContent?.()?.data?.cssCode}
360
- customFonts={useContent?.()?.data?.customFonts}
367
+ contentId={useContent?.id}
368
+ cssCode={useContent?.data?.cssCode}
369
+ customFonts={useContent?.data?.customFonts}
361
370
  />
362
371
  ) : null}
363
372
 
364
373
  <RenderBlocks
365
- blocks={useContent?.()?.data?.blocks}
374
+ blocks={useContent?.data?.blocks}
366
375
  key={forceReRenderCount}
367
376
  />
368
377
  </View>
@@ -3,6 +3,8 @@ var stdin_default = createContext({
3
3
  content: null,
4
4
  context: {},
5
5
  state: {},
6
+ setState() {
7
+ },
6
8
  apiKey: null,
7
9
  registeredComponents: {},
8
10
  inheritedStyles: {}
File without changes