@builder.io/sdk-react-native 0.0.1-59 → 0.0.1-61

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/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.0.1-59",
4
+ "version": "0.0.1-61",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
7
7
  "release:dev": "npm version prerelease --no-git-tag-version && npm publish --tag dev --access public"
@@ -187,7 +187,31 @@ const componentInfo = {
187
187
  ]
188
188
  }
189
189
  ],
190
- onChange: " function clearWidths() { columns.forEach(col => { col.delete('width'); }); } const columns = options.get('columns') as Array<Map<String, any>>; if (Array.isArray(columns)) { const containsColumnWithWidth = !!columns.find(col => col.get('width')); if (containsColumnWithWidth) { const containsColumnWithoutWidth = !!columns.find(col => !col.get('width')); if (containsColumnWithoutWidth) { clearWidths(); } else { const sumWidths = columns.reduce((memo, col) => { return memo + col.get('width'); }, 0); const widthsDontAddUp = sumWidths !== 100; if (widthsDontAddUp) { clearWidths(); } } } } "
190
+ onChange(options) {
191
+ function clearWidths() {
192
+ columns.forEach((col) => {
193
+ col.delete("width");
194
+ });
195
+ }
196
+ const columns = options.get("columns");
197
+ if (Array.isArray(columns)) {
198
+ const containsColumnWithWidth = !!columns.find((col) => col.get("width"));
199
+ if (containsColumnWithWidth) {
200
+ const containsColumnWithoutWidth = !!columns.find((col) => !col.get("width"));
201
+ if (containsColumnWithoutWidth) {
202
+ clearWidths();
203
+ } else {
204
+ const sumWidths = columns.reduce((memo, col) => {
205
+ return memo + col.get("width");
206
+ }, 0);
207
+ const widthsDontAddUp = sumWidths !== 100;
208
+ if (widthsDontAddUp) {
209
+ clearWidths();
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
191
215
  },
192
216
  {
193
217
  name: "space",
@@ -10,7 +10,26 @@ const componentInfo = {
10
10
  required: true,
11
11
  defaultValue: "",
12
12
  helperText: "e.g. enter a youtube url, google map, etc",
13
- onChange: " const url = options.get('url'); if (url) { options.set('content', 'Loading...'); // TODO: get this out of here! const apiKey = 'ae0e60e78201a3f2b0de4b'; return fetch(`https://iframe.ly/api/iframely?url=${url}&api_key=${apiKey}`) .then(res => res.json()) .then(data => { if (options.get('url') === url) { if (data.html) { options.set('content', data.html); } else { options.set('content', 'Invalid url, please try another'); } } }) .catch(err => { options.set( 'content', 'There was an error embedding this URL, please try again or another URL' ); }); } else { options.delete('content'); } "
13
+ onChange(options) {
14
+ const url = options.get("url");
15
+ if (url) {
16
+ options.set("content", "Loading...");
17
+ const apiKey = "ae0e60e78201a3f2b0de4b";
18
+ return fetch(`https://iframe.ly/api/iframely?url=${url}&api_key=${apiKey}`).then((res) => res.json()).then((data) => {
19
+ if (options.get("url") === url) {
20
+ if (data.html) {
21
+ options.set("content", data.html);
22
+ } else {
23
+ options.set("content", "Invalid url, please try another");
24
+ }
25
+ }
26
+ }).catch((_err) => {
27
+ options.set("content", "There was an error embedding this URL, please try again or another URL");
28
+ });
29
+ } else {
30
+ options.delete("content");
31
+ }
32
+ }
14
33
  },
15
34
  {
16
35
  name: "content",
@@ -1,45 +1,38 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
3
  import { useState, useRef, useEffect } from "react";
4
+ import { isJsScript } from "./helpers";
4
5
  function Embed(props) {
5
6
  const elem = useRef(null);
6
7
  const [scriptsInserted, setScriptsInserted] = useState(() => []);
7
8
  const [scriptsRun, setScriptsRun] = useState(() => []);
9
+ const [ranInitFn, setRanInitFn] = useState(() => false);
8
10
  function findAndRunScripts() {
9
- if (elem.current && typeof window !== "undefined") {
10
- const scripts = elem.current.getElementsByTagName("script");
11
- for (let i = 0; i < scripts.length; i++) {
12
- const script = scripts[i];
13
- if (script.src) {
14
- if (scriptsInserted.includes(script.src)) {
15
- continue;
16
- }
17
- scriptsInserted.push(script.src);
18
- const newScript = document.createElement("script");
19
- newScript.async = true;
20
- newScript.src = script.src;
21
- document.head.appendChild(newScript);
22
- } else if (!script.type || [
23
- "text/javascript",
24
- "application/javascript",
25
- "application/ecmascript"
26
- ].includes(script.type)) {
27
- if (scriptsRun.includes(script.innerText)) {
28
- continue;
29
- }
30
- try {
31
- scriptsRun.push(script.innerText);
32
- new Function(script.innerText)();
33
- } catch (error) {
34
- console.warn("`Embed`: Error running script:", error);
35
- }
11
+ const scripts = elem.current.getElementsByTagName("script");
12
+ for (let i = 0; i < scripts.length; i++) {
13
+ const script = scripts[i];
14
+ if (script.src && !scriptsInserted.includes(script.src)) {
15
+ scriptsInserted.push(script.src);
16
+ const newScript = document.createElement("script");
17
+ newScript.async = true;
18
+ newScript.src = script.src;
19
+ document.head.appendChild(newScript);
20
+ } else if (isJsScript(script) && !scriptsRun.includes(script.innerText)) {
21
+ try {
22
+ scriptsRun.push(script.innerText);
23
+ new Function(script.innerText)();
24
+ } catch (error) {
25
+ console.warn("`Embed`: Error running script:", error);
36
26
  }
37
27
  }
38
28
  }
39
29
  }
40
30
  useEffect(() => {
41
- findAndRunScripts();
42
- }, []);
31
+ if (elem.current && !ranInitFn) {
32
+ setRanInitFn(true);
33
+ findAndRunScripts();
34
+ }
35
+ }, [elem, ranInitFn]);
43
36
  return /* @__PURE__ */ React.createElement(View, {
44
37
  ref: elem,
45
38
  dangerouslySetInnerHTML: { __html: props.content }
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ const SCRIPT_MIME_TYPES = [
3
+ "text/javascript",
4
+ "application/javascript",
5
+ "application/ecmascript"
6
+ ];
7
+ const isJsScript = (script) => SCRIPT_MIME_TYPES.includes(script.type);
8
+ export {
9
+ isJsScript
10
+ };
@@ -19,7 +19,53 @@ const componentInfo = {
19
19
  allowedFileTypes: ["jpeg", "jpg", "png", "svg"],
20
20
  required: true,
21
21
  defaultValue: "https://cdn.builder.io/api/v1/image/assets%2Fpwgjf0RoYWbdnJSbpBAjXNRMe9F2%2Ffb27a7c790324294af8be1c35fe30f4d",
22
- onChange: " const DEFAULT_ASPECT_RATIO = 0.7041; options.delete('srcset'); options.delete('noWebp'); function loadImage(url, timeout) { return new Promise((resolve, reject) => { const img = document.createElement('img'); let loaded = false; img.onload = () => { loaded = true; resolve(img); }; img.addEventListener('error', event => { console.warn('Image load failed', event.error); reject(event.error); }); img.src = url; setTimeout(() => { if (!loaded) { reject(new Error('Image load timed out')); } }, timeout); }); } function round(num) { return Math.round(num * 1000) / 1000; } const value = options.get('image'); const aspectRatio = options.get('aspectRatio'); // For SVG images - don't render as webp, keep them as SVG fetch(value) .then(res => res.blob()) .then(blob => { if (blob.type.includes('svg')) { options.set('noWebp', true); } }); if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) { return loadImage(value).then(img => { const possiblyUpdatedAspectRatio = options.get('aspectRatio'); if ( options.get('image') === value && (!possiblyUpdatedAspectRatio || possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO) ) { if (img.width && img.height) { options.set('aspectRatio', round(img.height / img.width)); options.set('height', img.height); options.set('width', img.width); } } }); }"
22
+ onChange(options) {
23
+ const DEFAULT_ASPECT_RATIO = 0.7041;
24
+ options.delete("srcset");
25
+ options.delete("noWebp");
26
+ function loadImage(url, timeout = 6e4) {
27
+ return new Promise((resolve, reject) => {
28
+ const img = document.createElement("img");
29
+ let loaded = false;
30
+ img.onload = () => {
31
+ loaded = true;
32
+ resolve(img);
33
+ };
34
+ img.addEventListener("error", (event) => {
35
+ console.warn("Image load failed", event.error);
36
+ reject(event.error);
37
+ });
38
+ img.src = url;
39
+ setTimeout(() => {
40
+ if (!loaded) {
41
+ reject(new Error("Image load timed out"));
42
+ }
43
+ }, timeout);
44
+ });
45
+ }
46
+ function round(num) {
47
+ return Math.round(num * 1e3) / 1e3;
48
+ }
49
+ const value = options.get("image");
50
+ const aspectRatio = options.get("aspectRatio");
51
+ fetch(value).then((res) => res.blob()).then((blob) => {
52
+ if (blob.type.includes("svg")) {
53
+ options.set("noWebp", true);
54
+ }
55
+ });
56
+ if (value && (!aspectRatio || aspectRatio === DEFAULT_ASPECT_RATIO)) {
57
+ return loadImage(value).then((img) => {
58
+ const possiblyUpdatedAspectRatio = options.get("aspectRatio");
59
+ if (options.get("image") === value && (!possiblyUpdatedAspectRatio || possiblyUpdatedAspectRatio === DEFAULT_ASPECT_RATIO)) {
60
+ if (img.width && img.height) {
61
+ options.set("aspectRatio", round(img.height / img.width));
62
+ options.set("height", img.height);
63
+ options.set("width", img.width);
64
+ }
65
+ }
66
+ });
67
+ }
68
+ }
23
69
  },
24
70
  {
25
71
  name: "backgroundSize",
@@ -0,0 +1,49 @@
1
+ import * as React from 'react';
2
+ function removeProtocol(path) {
3
+ return path.replace(/http(s)?:/, "");
4
+ }
5
+ function updateQueryParam(uri = "", key, value) {
6
+ const re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
7
+ const separator = uri.indexOf("?") !== -1 ? "&" : "?";
8
+ if (uri.match(re)) {
9
+ return uri.replace(re, "$1" + key + "=" + encodeURIComponent(value) + "$2");
10
+ }
11
+ return uri + separator + key + "=" + encodeURIComponent(value);
12
+ }
13
+ function getShopifyImageUrl(src, size) {
14
+ if (!src || !(src == null ? void 0 : src.match(/cdn\.shopify\.com/)) || !size) {
15
+ return src;
16
+ }
17
+ if (size === "master") {
18
+ return removeProtocol(src);
19
+ }
20
+ const match = src.match(/(_\d+x(\d+)?)?(\.(jpg|jpeg|gif|png|bmp|bitmap|tiff|tif)(\?v=\d+)?)/i);
21
+ if (match) {
22
+ const prefix = src.split(match[0]);
23
+ const suffix = match[3];
24
+ const useSize = size.match("x") ? size : `${size}x`;
25
+ return removeProtocol(`${prefix[0]}_${useSize}${suffix}`);
26
+ }
27
+ return null;
28
+ }
29
+ function getSrcSet(url) {
30
+ if (!url) {
31
+ return url;
32
+ }
33
+ const sizes = [100, 200, 400, 800, 1200, 1600, 2e3];
34
+ if (url.match(/builder\.io/)) {
35
+ let srcUrl = url;
36
+ const widthInSrc = Number(url.split("?width=")[1]);
37
+ if (!isNaN(widthInSrc)) {
38
+ srcUrl = `${srcUrl} ${widthInSrc}w`;
39
+ }
40
+ return sizes.filter((size) => size !== widthInSrc).map((size) => `${updateQueryParam(url, "width", size)} ${size}w`).concat([srcUrl]).join(", ");
41
+ }
42
+ if (url.match(/cdn\.shopify\.com/)) {
43
+ return sizes.map((size) => [getShopifyImageUrl(url, `${size}x${size}`), size]).filter(([sizeUrl]) => !!sizeUrl).map(([sizeUrl, size]) => `${sizeUrl} ${size}w`).concat([url]).join(", ");
44
+ }
45
+ return url;
46
+ }
47
+ export {
48
+ getSrcSet
49
+ };
@@ -38,8 +38,8 @@ function Symbol(props) {
38
38
  getContent({
39
39
  model: symbolToUse.model,
40
40
  apiKey: builderContext.apiKey,
41
- options: {
42
- entry: symbolToUse.entry
41
+ query: {
42
+ id: symbolToUse.entry
43
43
  }
44
44
  }).then((response) => {
45
45
  setContent(response);
@@ -11,7 +11,8 @@ function BlockStyles(props) {
11
11
  return getProcessedBlock({
12
12
  block: props.block,
13
13
  state: builderContext.state,
14
- context: builderContext.context
14
+ context: builderContext.context,
15
+ evaluateBindings: true
15
16
  });
16
17
  }
17
18
  function css() {
@@ -38,14 +38,21 @@ import { getBlockProperties } from "../../functions/get-block-properties.js";
38
38
  import { getBlockStyles } from "../../functions/get-block-styles.js";
39
39
  import { getBlockTag } from "../../functions/get-block-tag.js";
40
40
  import { getProcessedBlock } from "../../functions/get-processed-block.js";
41
+ import { evaluate } from "../../functions/evaluate.js";
41
42
  import BlockStyles from "./block-styles.js";
42
43
  import { isEmptyHtmlElement } from "./render-block.helpers.js";
43
44
  import RenderComponent from "./render-component.js";
45
+ import RenderRepeatedBlock from "./render-repeated-block.js";
44
46
  function RenderBlock(props) {
45
- var _a, _b;
47
+ var _a, _b, _c;
46
48
  function component() {
47
49
  var _a2;
48
- const componentName = (_a2 = useBlock().component) == null ? void 0 : _a2.name;
50
+ const componentName = (_a2 = getProcessedBlock({
51
+ block: props.block,
52
+ state: builderContext.state,
53
+ context: builderContext.context,
54
+ evaluateBindings: false
55
+ }).component) == null ? void 0 : _a2.name;
49
56
  if (!componentName) {
50
57
  return null;
51
58
  }
@@ -75,10 +82,11 @@ function RenderBlock(props) {
75
82
  return getBlockTag(useBlock());
76
83
  }
77
84
  function useBlock() {
78
- return getProcessedBlock({
85
+ return repeatItemData() ? props.block : getProcessedBlock({
79
86
  block: props.block,
80
87
  state: builderContext.state,
81
- context: builderContext.context
88
+ context: builderContext.context,
89
+ evaluateBindings: true
82
90
  });
83
91
  }
84
92
  function attributes() {
@@ -99,30 +107,62 @@ function RenderBlock(props) {
99
107
  attributes: attributes()
100
108
  });
101
109
  }
110
+ function renderComponentProps() {
111
+ return {
112
+ blockChildren: children(),
113
+ componentRef: componentRef(),
114
+ componentOptions: componentOptions()
115
+ };
116
+ }
102
117
  function children() {
103
118
  var _a2;
104
119
  return (_a2 = useBlock().children) != null ? _a2 : [];
105
120
  }
106
- function noCompRefChildren() {
107
- return componentRef() ? [] : children();
121
+ function childrenWithoutParentComponent() {
122
+ const shouldRenderChildrenOutsideRef = !componentRef() && !repeatItemData();
123
+ return shouldRenderChildrenOutsideRef ? children() : [];
124
+ }
125
+ function repeatItemData() {
126
+ const _a2 = props.block, { repeat } = _a2, blockWithoutRepeat = __objRest(_a2, ["repeat"]);
127
+ if (!(repeat == null ? void 0 : repeat.collection)) {
128
+ return void 0;
129
+ }
130
+ const itemsArray = evaluate({
131
+ code: repeat.collection,
132
+ state: builderContext.state,
133
+ context: builderContext.context
134
+ });
135
+ if (!Array.isArray(itemsArray)) {
136
+ return void 0;
137
+ }
138
+ const collectionName = repeat.collection.split(".").pop();
139
+ const itemNameToUse = repeat.itemName || (collectionName ? collectionName + "Item" : "item");
140
+ const repeatArray = itemsArray.map((item, index) => ({
141
+ context: __spreadProps(__spreadValues({}, builderContext), {
142
+ state: __spreadProps(__spreadValues({}, builderContext.state), {
143
+ $index: index,
144
+ $item: item,
145
+ [itemNameToUse]: item,
146
+ [`$${itemNameToUse}Index`]: index
147
+ })
148
+ }),
149
+ block: blockWithoutRepeat
150
+ }));
151
+ return repeatArray;
108
152
  }
109
153
  const builderContext = useContext(BuilderContext);
110
154
  const TagNameRef = tagName();
111
- return /* @__PURE__ */ React.createElement(React.Fragment, null, shouldWrap() ? /* @__PURE__ */ React.createElement(React.Fragment, null, !isEmptyHtmlElement(tagName()) ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(TagNameRef, __spreadValues({}, attributes()), /* @__PURE__ */ React.createElement(RenderComponent, {
112
- blockChildren: children(),
113
- componentRef: componentRef(),
114
- componentOptions: componentOptions()
115
- }), (_a = noCompRefChildren()) == null ? void 0 : _a.map((child) => /* @__PURE__ */ React.createElement(RenderBlock, {
155
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, shouldWrap() ? /* @__PURE__ */ React.createElement(React.Fragment, null, !isEmptyHtmlElement(tagName()) ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(TagNameRef, __spreadValues({}, attributes()), repeatItemData() ? /* @__PURE__ */ React.createElement(React.Fragment, null, (_a = repeatItemData()) == null ? void 0 : _a.map((data, index) => /* @__PURE__ */ React.createElement(RenderRepeatedBlock, {
156
+ key: index,
157
+ repeatContext: data.context,
158
+ block: data.block
159
+ }))) : /* @__PURE__ */ React.createElement(RenderComponent, __spreadValues({}, renderComponentProps())), (_b = childrenWithoutParentComponent()) == null ? void 0 : _b.map((child) => /* @__PURE__ */ React.createElement(RenderBlock, {
116
160
  key: "render-block-" + child.id,
117
161
  block: child
118
- })), (_b = noCompRefChildren()) == null ? void 0 : _b.map((child) => /* @__PURE__ */ React.createElement(BlockStyles, {
162
+ })), (_c = childrenWithoutParentComponent()) == null ? void 0 : _c.map((child) => /* @__PURE__ */ React.createElement(BlockStyles, {
119
163
  key: "block-style-" + child.id,
120
164
  block: child
121
- })))) : /* @__PURE__ */ React.createElement(TagNameRef, __spreadValues({}, attributes()))) : /* @__PURE__ */ React.createElement(RenderComponent, {
122
- blockChildren: children(),
123
- componentRef: componentRef(),
124
- componentOptions: componentOptions()
125
- }));
165
+ })))) : /* @__PURE__ */ React.createElement(TagNameRef, __spreadValues({}, attributes()))) : /* @__PURE__ */ React.createElement(RenderComponent, __spreadValues({}, renderComponentProps())));
126
166
  }
127
167
  export {
128
168
  RenderBlock as default
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ import BuilderContext from "../../context/builder.context";
3
+ import RenderBlock from "./render-block.js";
4
+ function RenderRepeatedBlock(props) {
5
+ return /* @__PURE__ */ React.createElement(BuilderContext.Provider, {
6
+ value: {
7
+ get content() {
8
+ return props.repeatContext.content;
9
+ },
10
+ get state() {
11
+ return props.repeatContext.state;
12
+ },
13
+ get context() {
14
+ return props.repeatContext.context;
15
+ },
16
+ get apiKey() {
17
+ return props.repeatContext.apiKey;
18
+ },
19
+ get registeredComponents() {
20
+ return props.repeatContext.registeredComponents;
21
+ }
22
+ }
23
+ }, /* @__PURE__ */ React.createElement(RenderBlock, {
24
+ block: props.block
25
+ }));
26
+ }
27
+ export {
28
+ RenderRepeatedBlock as default
29
+ };
@@ -77,8 +77,8 @@ function RenderContent(props) {
77
77
  var _a2, _b2;
78
78
  return __spreadValues(__spreadValues(__spreadValues({}, (_b2 = (_a2 = props.content) == null ? void 0 : _a2.data) == null ? void 0 : _b2.state), props.data), overrideState);
79
79
  }
80
- function context() {
81
- return {};
80
+ function contextContext() {
81
+ return props.context || {};
82
82
  }
83
83
  function allRegisteredComponents() {
84
84
  const allComponentsArray = [
@@ -114,7 +114,7 @@ function RenderContent(props) {
114
114
  if (jsCode) {
115
115
  evaluate({
116
116
  code: jsCode,
117
- context: context(),
117
+ context: contextContext(),
118
118
  state: contentState()
119
119
  });
120
120
  }
@@ -125,7 +125,7 @@ function RenderContent(props) {
125
125
  function evalExpression(expression) {
126
126
  return expression.replace(/{{([^}]+)}}/g, (_match, group) => evaluate({
127
127
  code: group,
128
- context: context(),
128
+ context: contextContext(),
129
129
  state: contentState()
130
130
  }));
131
131
  }
@@ -182,13 +182,13 @@ function RenderContent(props) {
182
182
  }
183
183
  if (isPreviewing()) {
184
184
  if (props.model && previewingModelName() === props.model) {
185
- const currentUrl = new URL(location.href);
186
- const previewApiKey = currentUrl.searchParams.get("apiKey");
185
+ const searchParams = new URL(location.href).searchParams;
186
+ const previewApiKey = searchParams.get("apiKey") || searchParams.get("builder.space");
187
187
  if (previewApiKey) {
188
188
  getContent({
189
189
  model: props.model,
190
190
  apiKey: previewApiKey,
191
- options: getBuilderSearchParams(convertSearchParamsToQueryObject(currentUrl.searchParams))
191
+ options: getBuilderSearchParams(convertSearchParamsToQueryObject(searchParams))
192
192
  }).then((content) => {
193
193
  if (content) {
194
194
  setOverrideContent(content);
@@ -228,7 +228,7 @@ function RenderContent(props) {
228
228
  return contentState();
229
229
  },
230
230
  get context() {
231
- return context();
231
+ return contextContext();
232
232
  },
233
233
  get apiKey() {
234
234
  return props.apiKey;
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ const convertStyleObject = (obj) => {
3
+ return obj;
4
+ };
5
+ export {
6
+ convertStyleObject
7
+ };
@@ -15,45 +15,19 @@ var __spreadValues = (a, b) => {
15
15
  }
16
16
  return a;
17
17
  };
18
- const propertiesThatMustBeNumber = new Set(["lineHeight"]);
19
- const displayValues = new Set(["flex", "none"]);
20
- const SHOW_WARNINGS = false;
21
- function validateReactNativeStyles(styles) {
22
- for (const key in styles) {
23
- const propertyValue = styles[key];
24
- if (key === "display" && !displayValues.has(propertyValue)) {
25
- if (SHOW_WARNINGS) {
26
- console.warn(`Style value for key "display" must be "flex" or "none" but had ${propertyValue}`);
27
- }
28
- delete styles[key];
29
- }
30
- if (typeof propertyValue === "string" && propertyValue.match(/^-?\d/)) {
31
- const newValue = parseFloat(propertyValue);
32
- if (!isNaN(newValue)) {
33
- styles[key] = newValue;
34
- }
35
- if (typeof newValue === "number" && newValue < 0) {
36
- styles[key] = 0;
37
- }
38
- }
39
- if (propertiesThatMustBeNumber.has(key) && typeof styles[key] !== "number") {
40
- if (SHOW_WARNINGS) {
41
- console.warn(`Style key ${key} must be a number, but had value \`${styles[key]}\``);
42
- }
43
- delete styles[key];
44
- }
45
- }
46
- }
18
+ import { getMaxWidthQueryForSize } from "../constants/device-sizes.js";
19
+ import { convertStyleObject } from "./convert-style-object.js";
20
+ import { sanitizeBlockStyles } from "./sanitize-styles.js";
47
21
  function getBlockStyles(block) {
48
- var _a, _b, _c;
49
- const styles = __spreadValues(__spreadValues({}, (_a = block.responsiveStyles) == null ? void 0 : _a.large), block.styles);
22
+ var _a, _b, _c, _d, _e;
23
+ const styles = __spreadValues(__spreadValues({}, convertStyleObject((_a = block.responsiveStyles) == null ? void 0 : _a.large)), block.styles);
50
24
  if ((_b = block.responsiveStyles) == null ? void 0 : _b.medium) {
51
- Object.assign(styles, block.responsiveStyles.medium);
25
+ styles[getMaxWidthQueryForSize("medium")] = convertStyleObject((_c = block.responsiveStyles) == null ? void 0 : _c.medium);
52
26
  }
53
- if ((_c = block.responsiveStyles) == null ? void 0 : _c.small) {
54
- Object.assign(styles, block.responsiveStyles.small);
27
+ if ((_d = block.responsiveStyles) == null ? void 0 : _d.small) {
28
+ styles[getMaxWidthQueryForSize("small")] = convertStyleObject((_e = block.responsiveStyles) == null ? void 0 : _e.small);
55
29
  }
56
- validateReactNativeStyles(styles);
30
+ sanitizeBlockStyles(styles);
57
31
  return styles;
58
32
  }
59
33
  export {
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { View } from "react-native";
3
- function getBlockTag(block) {
3
+ function getBlockTag(_block) {
4
4
  return View;
5
5
  }
6
6
  export {
@@ -0,0 +1,39 @@
1
+ import * as React from 'react';
2
+ const handleABTesting = (item, testGroups) => {
3
+ if (item.variations && Object.keys(item.variations).length) {
4
+ const testGroup = item.id ? testGroups[item.id] : void 0;
5
+ const variationValue = testGroup ? item.variations[testGroup] : void 0;
6
+ if (testGroup && variationValue) {
7
+ item.data = variationValue.data;
8
+ item.testVariationId = variationValue.id;
9
+ item.testVariationName = variationValue.name;
10
+ } else {
11
+ let n = 0;
12
+ const random = Math.random();
13
+ let set = false;
14
+ for (const id in item.variations) {
15
+ const variation = item.variations[id];
16
+ const testRatio = variation.testRatio;
17
+ n += testRatio;
18
+ if (random < n) {
19
+ const variationName = variation.name || (variation.id === item.id ? "Default variation" : "");
20
+ set = true;
21
+ Object.assign(item, {
22
+ data: variation.data,
23
+ testVariationId: variation.id,
24
+ testVariationName: variationName
25
+ });
26
+ }
27
+ }
28
+ if (!set) {
29
+ Object.assign(item, {
30
+ testVariationId: item.id,
31
+ testVariationName: "Default"
32
+ });
33
+ }
34
+ }
35
+ }
36
+ };
37
+ export {
38
+ handleABTesting
39
+ };
@@ -38,20 +38,10 @@ var __async = (__this, __arguments, generator) => {
38
38
  step((generator = generator.apply(__this, __arguments)).next());
39
39
  });
40
40
  };
41
+ import { flatten } from "../../helpers/flatten.js";
41
42
  import { getFetch } from "../get-fetch.js";
43
+ import { handleABTesting } from "./ab-testing.js";
42
44
  const fetch$ = getFetch();
43
- function flatten(object, path = null, separator = ".") {
44
- return Object.keys(object).reduce((acc, key) => {
45
- const value = object[key];
46
- const newPath = [path, key].filter(Boolean).join(separator);
47
- const isObject = [
48
- typeof value === "object",
49
- value !== null,
50
- !(Array.isArray(value) && value.length === 0)
51
- ].every(Boolean);
52
- return isObject ? __spreadValues(__spreadValues({}, acc), flatten(value, newPath, separator)) : __spreadProps(__spreadValues({}, acc), { [newPath]: value });
53
- }, {});
54
- }
55
45
  function getContent(options) {
56
46
  return __async(this, null, function* () {
57
47
  return (yield getAllContent(__spreadProps(__spreadValues({}, options), { limit: 1 }))).results[0] || null;
@@ -84,50 +74,15 @@ const generateContentUrl = (options) => {
84
74
  }
85
75
  return url;
86
76
  };
87
- const handleABTesting = (content, testGroups) => {
88
- for (const item of content.results) {
89
- if (item.variations && Object.keys(item.variations).length) {
90
- const testGroup = testGroups[item.id];
91
- const variationValue = item.variations[testGroup];
92
- if (testGroup && variationValue) {
93
- item.data = variationValue.data;
94
- item.testVariationId = variationValue.id;
95
- item.testVariationName = variationValue.name;
96
- } else {
97
- let n = 0;
98
- const random = Math.random();
99
- let set = false;
100
- for (const id in item.variations) {
101
- const variation = item.variations[id];
102
- const testRatio = variation.testRatio;
103
- n += testRatio;
104
- if (random < n) {
105
- const variationName = variation.name || (variation.id === item.id ? "Default variation" : "");
106
- set = true;
107
- Object.assign(item, {
108
- data: variation.data,
109
- testVariationId: variation.id,
110
- testVariationName: variationName
111
- });
112
- }
113
- }
114
- if (!set) {
115
- Object.assign(item, {
116
- testVariationId: item.id,
117
- testVariationName: "Default"
118
- });
119
- }
120
- }
121
- }
122
- }
123
- };
124
77
  function getAllContent(options) {
125
78
  return __async(this, null, function* () {
126
79
  const url = generateContentUrl(options);
127
80
  const fetch = yield fetch$;
128
81
  const content = yield fetch(url.href).then((res) => res.json());
129
82
  if (options.testGroups) {
130
- handleABTesting(content, options.testGroups);
83
+ for (const item of content.results) {
84
+ handleABTesting(item, options.testGroups);
85
+ }
131
86
  }
132
87
  return content;
133
88
  });
@@ -0,0 +1 @@
1
+ import * as React from 'react';
@@ -21,9 +21,11 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
21
  import { evaluate } from "./evaluate.js";
22
22
  import { set } from "./set.js";
23
23
  import { transformBlock } from "./transform-block.js";
24
- function getProcessedBlock(options) {
25
- const { state, context } = options;
26
- const block = transformBlock(options.block);
24
+ const evaluateBindings = ({
25
+ block,
26
+ context,
27
+ state
28
+ }) => {
27
29
  if (!block.bindings) {
28
30
  return block;
29
31
  }
@@ -33,14 +35,19 @@ function getProcessedBlock(options) {
33
35
  });
34
36
  for (const binding in block.bindings) {
35
37
  const expression = block.bindings[binding];
36
- const value = evaluate({
37
- code: expression,
38
- state,
39
- context
40
- });
38
+ const value = evaluate({ code: expression, state, context });
41
39
  set(copied, binding, value);
42
40
  }
43
41
  return copied;
42
+ };
43
+ function getProcessedBlock(options) {
44
+ const { state, context } = options;
45
+ const block = transformBlock(options.block);
46
+ if (evaluateBindings) {
47
+ return evaluateBindings({ block, state, context });
48
+ } else {
49
+ return block;
50
+ }
44
51
  }
45
52
  export {
46
53
  getProcessedBlock
@@ -21,7 +21,8 @@ test("Can process bindings", () => {
21
21
  const processed = getProcessedBlock({
22
22
  block,
23
23
  context: {},
24
- state: { test: "hello" }
24
+ state: { test: "hello" },
25
+ evaluateBindings: true
25
26
  });
26
27
  expect(processed).not.toEqual(block);
27
28
  expect((_a = processed.properties) == null ? void 0 : _a.foo).toEqual("baz");
@@ -30,7 +30,6 @@ var __objRest = (source, exclude) => {
30
30
  }
31
31
  return target;
32
32
  };
33
- import { fastClone } from "./fast-clone.js";
34
33
  const components = [];
35
34
  function registerComponent(component, info) {
36
35
  components.push(__spreadValues({ component }, info));
@@ -39,31 +38,34 @@ function registerComponent(component, info) {
39
38
  }
40
39
  const createRegisterComponentMessage = (_a) => {
41
40
  var _b = _a, {
42
- component
41
+ component: _
43
42
  } = _b, info = __objRest(_b, [
44
43
  "component"
45
44
  ]);
46
45
  return {
47
46
  type: "builder.registerComponent",
48
- data: prepareComponentInfoToSend(fastClone(info))
47
+ data: prepareComponentInfoToSend(info)
49
48
  };
50
49
  };
51
- function prepareComponentInfoToSend(info) {
52
- return __spreadValues(__spreadValues({}, info), info.inputs && {
53
- inputs: info.inputs.map((input) => {
54
- const keysToConvertFnToString = ["onChange", "showIf"];
55
- for (const key of keysToConvertFnToString) {
56
- const fn = input[key];
57
- if (fn && typeof fn === "function") {
58
- input = __spreadProps(__spreadValues({}, input), {
59
- [key]: `return (${fn.toString()}).apply(this, arguments)`
60
- });
61
- }
62
- }
63
- return input;
64
- })
50
+ const fastClone = (obj) => JSON.parse(JSON.stringify(obj));
51
+ const serializeValue = (value) => typeof value === "function" ? serializeFn(value) : fastClone(value);
52
+ const serializeFn = (fnValue) => {
53
+ const fnStr = fnValue.toString().trim();
54
+ const appendFunction = !fnStr.startsWith("function") && !fnStr.startsWith("(");
55
+ return `return (${appendFunction ? "function " : ""}${fnStr}).apply(this, arguments)`;
56
+ };
57
+ const prepareComponentInfoToSend = (_c) => {
58
+ var _d = _c, {
59
+ inputs
60
+ } = _d, info = __objRest(_d, [
61
+ "inputs"
62
+ ]);
63
+ return __spreadProps(__spreadValues({}, fastClone(info)), {
64
+ inputs: inputs == null ? void 0 : inputs.map((input) => Object.entries(input).reduce((acc, [key, value]) => __spreadProps(__spreadValues({}, acc), {
65
+ [key]: serializeValue(value)
66
+ }), {}))
65
67
  });
66
- }
68
+ };
67
69
  export {
68
70
  components,
69
71
  createRegisterComponentMessage,
@@ -0,0 +1,33 @@
1
+ import * as React from 'react';
2
+ const propertiesThatMustBeNumber = new Set(["lineHeight"]);
3
+ const displayValues = new Set(["flex", "none"]);
4
+ const SHOW_WARNINGS = false;
5
+ const sanitizeBlockStyles = (styles) => {
6
+ for (const key in styles) {
7
+ const propertyValue = styles[key];
8
+ if (key === "display" && !displayValues.has(propertyValue)) {
9
+ if (SHOW_WARNINGS) {
10
+ console.warn(`Style value for key "display" must be "flex" or "none" but had ${propertyValue}`);
11
+ }
12
+ delete styles[key];
13
+ }
14
+ if (typeof propertyValue === "string" && propertyValue.match(/^-?\d/)) {
15
+ const newValue = parseFloat(propertyValue);
16
+ if (!isNaN(newValue)) {
17
+ styles[key] = newValue;
18
+ }
19
+ if (typeof newValue === "number" && newValue < 0) {
20
+ styles[key] = 0;
21
+ }
22
+ }
23
+ if (propertiesThatMustBeNumber.has(key) && typeof styles[key] !== "number") {
24
+ if (SHOW_WARNINGS) {
25
+ console.warn(`Style key ${key} must be a number, but had value \`${styles[key]}\``);
26
+ }
27
+ delete styles[key];
28
+ }
29
+ }
30
+ };
31
+ export {
32
+ sanitizeBlockStyles
33
+ };
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+ var __defProp = Object.defineProperty;
3
+ var __defProps = Object.defineProperties;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ function flatten(object, path = null, separator = ".") {
22
+ return Object.keys(object).reduce((acc, key) => {
23
+ const value = object[key];
24
+ const newPath = [path, key].filter(Boolean).join(separator);
25
+ const isObject = [
26
+ typeof value === "object",
27
+ value !== null,
28
+ !(Array.isArray(value) && value.length === 0)
29
+ ].every(Boolean);
30
+ return isObject ? __spreadValues(__spreadValues({}, acc), flatten(value, newPath, separator)) : __spreadProps(__spreadValues({}, acc), { [newPath]: value });
31
+ }, {});
32
+ }
33
+ export {
34
+ flatten
35
+ };
@@ -1,5 +0,0 @@
1
- import * as React from 'react';
2
- const fastClone = (obj) => JSON.parse(JSON.stringify(obj));
3
- export {
4
- fastClone
5
- };