@builder.io/sdk-react-native 0.0.1-57 → 0.0.1-58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ### 0.0.1-56
2
+
3
+ 🐛 Fix: image block `srcSet` was incorrectly set as `srcset`
4
+
1
5
  ### 0.0.1-55
2
6
 
3
7
  🐛 Fix: custom components were not rendering correctly
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-57",
4
+ "version": "0.0.1-58",
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"
@@ -1,32 +0,0 @@
1
- import * as React from "react";
2
- import { View, StyleSheet, Image, Text } from "react-native";
3
-
4
- export interface ButtonProps {
5
- attributes?: any;
6
- text?: string;
7
- link?: string;
8
- openLinkInNewTab?: boolean;
9
- }
10
-
11
- export default function Button(props: ButtonProps) {
12
- return (
13
- <>
14
- {props.link ? (
15
- <>
16
- <View
17
- {...props.attributes}
18
- role="button"
19
- href={props.link}
20
- target={props.openLinkInNewTab ? "_blank" : undefined}
21
- >
22
- <Text>{props.text}</Text>
23
- </View>
24
- </>
25
- ) : (
26
- <View {...props.attributes}>
27
- <Text>{props.text}</Text>
28
- </View>
29
- )}
30
- </>
31
- );
32
- }
@@ -1,87 +0,0 @@
1
- import * as React from "react";
2
- import { View, StyleSheet, Image, Text } from "react-native";
3
-
4
- type Column = {
5
- blocks: any; // TODO: Implement this when support for dynamic CSS lands
6
-
7
- width?: number;
8
- };
9
- type StackColumnsAt = "tablet" | "mobile" | "never";
10
- export interface ColumnProps {
11
- columns?: Column[]; // TODO: Implement this when support for dynamic CSS lands
12
-
13
- space?: number; // TODO: Implement this when support for dynamic CSS lands
14
-
15
- stackColumnsAt?: StackColumnsAt; // TODO: Implement this when support for dynamic CSS lands
16
-
17
- reverseColumnsWhenStacked?: boolean;
18
- }
19
-
20
- import RenderBlocks from "../../components/render-blocks.lite";
21
-
22
- export default function Columns(props: ColumnProps) {
23
- function getGutterSize() {
24
- return typeof props.space === "number" ? props.space || 0 : 20;
25
- }
26
-
27
- function getColumns() {
28
- return props.columns || [];
29
- }
30
-
31
- function getWidth(index) {
32
- const columns = getColumns();
33
- return columns[index]?.width || 100 / columns.length;
34
- }
35
-
36
- function getColumnCssWidth(index) {
37
- const columns = getColumns();
38
- const gutterSize = getGutterSize();
39
- const subtractWidth = (gutterSize * (columns.length - 1)) / columns.length;
40
- return `calc(${getWidth(index)}% - ${subtractWidth}px)`;
41
- }
42
-
43
- function maybeApplyForTablet(prop) {
44
- const _stackColumnsAt = props.stackColumnsAt || "tablet";
45
-
46
- return _stackColumnsAt === "tablet" ? prop : "inherit";
47
- }
48
-
49
- function columnsCssVars() {
50
- const flexDir =
51
- props.stackColumnsAt === "never"
52
- ? "inherit"
53
- : props.reverseColumnsWhenStacked
54
- ? "column-reverse"
55
- : "column";
56
- return {
57
- "--flex-dir": flexDir,
58
- "--flex-dir-tablet": maybeApplyForTablet(flexDir),
59
- };
60
- }
61
-
62
- function columnCssVars() {
63
- const width = "100%";
64
- const marginLeft = "0";
65
- return {
66
- "--column-width": width,
67
- "--column-margin-left": marginLeft,
68
- "--column-width-tablet": maybeApplyForTablet(width),
69
- "--column-margin-left-tablet": maybeApplyForTablet(marginLeft),
70
- };
71
- }
72
-
73
- return (
74
- <View style={styles.view1}>
75
- {props.columns?.map((column, index) => (
76
- <View style={styles.view2} key={index}>
77
- <RenderBlocks blocks={column.blocks} />
78
- </View>
79
- ))}
80
- </View>
81
- );
82
- }
83
-
84
- const styles = StyleSheet.create({
85
- view1: { display: "flex", alignItems: "stretch" },
86
- view2: { flexGrow: 1 },
87
- });
@@ -1,62 +0,0 @@
1
- import * as React from "react";
2
- import { View, StyleSheet, Image, Text } from "react-native";
3
- import { useState, useRef, useEffect } from "react";
4
-
5
- export interface CustomCodeProps {
6
- code: string;
7
- replaceNodes?: boolean;
8
- }
9
-
10
- export default function CustomCode(props: CustomCodeProps) {
11
- const elem = useRef<HTMLDivElement>(null);
12
- const [scriptsInserted, setScriptsInserted] = useState(() => []);
13
-
14
- const [scriptsRun, setScriptsRun] = useState(() => []);
15
-
16
- function findAndRunScripts() {
17
- // TODO: Move this function to standalone one in '@builder.io/utils'
18
- if (elem.current && typeof window !== "undefined") {
19
- const scripts = elem.current.getElementsByTagName("script");
20
-
21
- for (let i = 0; i < scripts.length; i++) {
22
- const script = scripts[i];
23
-
24
- if (script.src) {
25
- if (scriptsInserted.includes(script.src)) {
26
- continue;
27
- }
28
-
29
- scriptsInserted.push(script.src);
30
- const newScript = document.createElement("script");
31
- newScript.async = true;
32
- newScript.src = script.src;
33
- document.head.appendChild(newScript);
34
- } else if (
35
- !script.type ||
36
- [
37
- "text/javascript",
38
- "application/javascript",
39
- "application/ecmascript",
40
- ].includes(script.type)
41
- ) {
42
- if (scriptsRun.includes(script.innerText)) {
43
- continue;
44
- }
45
-
46
- try {
47
- scriptsRun.push(script.innerText);
48
- new Function(script.innerText)();
49
- } catch (error) {
50
- console.warn("`CustomCode`: Error running script:", error);
51
- }
52
- }
53
- }
54
- }
55
- }
56
-
57
- useEffect(() => {
58
- findAndRunScripts();
59
- }, []);
60
-
61
- return <View ref={elem} dangerouslySetInnerHTML={{ __html: props.code }} />;
62
- }
@@ -1,63 +0,0 @@
1
- import * as React from "react";
2
- import { View, StyleSheet, Image, Text } from "react-native";
3
- import { useState, useRef, useEffect } from "react";
4
-
5
- export interface EmbedProps {
6
- content: string;
7
- }
8
-
9
- export default function Embed(props: EmbedProps) {
10
- const elem = useRef<HTMLDivElement>(null);
11
- const [scriptsInserted, setScriptsInserted] = useState(() => []);
12
-
13
- const [scriptsRun, setScriptsRun] = useState(() => []);
14
-
15
- function findAndRunScripts() {
16
- // TODO: Move this function to standalone one in '@builder.io/utils'
17
- if (elem.current && typeof window !== "undefined") {
18
- const scripts = elem.current.getElementsByTagName("script");
19
-
20
- for (let i = 0; i < scripts.length; i++) {
21
- const script = scripts[i];
22
-
23
- if (script.src) {
24
- if (scriptsInserted.includes(script.src)) {
25
- continue;
26
- }
27
-
28
- scriptsInserted.push(script.src);
29
- const newScript = document.createElement("script");
30
- newScript.async = true;
31
- newScript.src = script.src;
32
- document.head.appendChild(newScript);
33
- } else if (
34
- !script.type ||
35
- [
36
- "text/javascript",
37
- "application/javascript",
38
- "application/ecmascript",
39
- ].includes(script.type)
40
- ) {
41
- if (scriptsRun.includes(script.innerText)) {
42
- continue;
43
- }
44
-
45
- try {
46
- scriptsRun.push(script.innerText);
47
- new Function(script.innerText)();
48
- } catch (error) {
49
- console.warn("`Embed`: Error running script:", error);
50
- }
51
- }
52
- }
53
- }
54
- }
55
-
56
- useEffect(() => {
57
- findAndRunScripts();
58
- }, []);
59
-
60
- return (
61
- <View ref={elem} dangerouslySetInnerHTML={{ __html: props.content }} />
62
- );
63
- }
@@ -1,307 +0,0 @@
1
- import * as React from "react";
2
- import { View, StyleSheet, Image, Text } from "react-native";
3
- import { useState, useRef } from "react";
4
-
5
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
6
- // @ts-nocheck
7
-
8
- /* eslint-disable */
9
-
10
- /**
11
- * This component was copied over from the old SDKs and has a lot of code pointing to invalid functions/env vars. It needs
12
- * to be cleaned up before the component can actually be usable.
13
- */
14
- export type FormState = "unsubmitted" | "sending" | "success" | "error";
15
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
16
- // @ts-nocheck
17
-
18
- /* eslint-disable */
19
-
20
- /**
21
- * This component was copied over from the old SDKs and has a lot of code pointing to invalid functions/env vars. It needs
22
- * to be cleaned up before the component can actually be usable.
23
- */
24
- interface BuilderElement {}
25
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
26
- // @ts-nocheck
27
-
28
- /* eslint-disable */
29
-
30
- /**
31
- * This component was copied over from the old SDKs and has a lot of code pointing to invalid functions/env vars. It needs
32
- * to be cleaned up before the component can actually be usable.
33
- */
34
- export interface FormProps {
35
- attributes?: any;
36
- name?: string;
37
- action?: string;
38
- validate?: boolean;
39
- method?: string;
40
- builderBlock?: BuilderElement;
41
- sendSubmissionsTo?: string;
42
- sendSubmissionsToEmail?: string;
43
- sendWithJs?: boolean;
44
- contentType?: string;
45
- customHeaders?: {
46
- [key: string]: string;
47
- };
48
- successUrl?: string;
49
- previewState?: FormState;
50
- successMessage?: BuilderElement[];
51
- errorMessage?: BuilderElement[];
52
- sendingMessage?: BuilderElement[];
53
- resetFormOnSubmit?: boolean;
54
- errorMessagePath?: string;
55
- }
56
-
57
- import RenderBlock from "../../components/render-block/render-block.lite";
58
- import { isEditing } from "../../functions/is-editing.js";
59
-
60
- export default function FormComponent(props: FormProps) {
61
- const formRef = useRef(null);
62
- const [formState, setFormState] = useState(() => "unsubmitted");
63
-
64
- const [responseData, setResponseData] = useState(() => null);
65
-
66
- const [formErrorMessage, setFormErrorMessage] = useState(() => "");
67
-
68
- function submissionState() {
69
- return (isEditing() && props.previewState) || formState;
70
- }
71
-
72
- function onSubmit(event) {
73
- const sendWithJs = props.sendWithJs || props.sendSubmissionsTo === "email";
74
-
75
- if (props.sendSubmissionsTo === "zapier") {
76
- event.preventDefault();
77
- } else if (sendWithJs) {
78
- if (!(props.action || props.sendSubmissionsTo === "email")) {
79
- event.preventDefault();
80
- return;
81
- }
82
-
83
- event.preventDefault();
84
- const el = event.currentTarget;
85
- const headers = props.customHeaders || {};
86
- let body;
87
- const formData = new FormData(el); // TODO: maybe support null
88
-
89
- const formPairs = Array.from(
90
- event.currentTarget.querySelectorAll("input,select,textarea")
91
- )
92
- .filter((el) => !!el.name)
93
- .map((el) => {
94
- let value;
95
- const key = el.name;
96
-
97
- if (el instanceof HTMLInputElement) {
98
- if (el.type === "radio") {
99
- if (el.checked) {
100
- value = el.name;
101
- return {
102
- key,
103
- value,
104
- };
105
- }
106
- } else if (el.type === "checkbox") {
107
- value = el.checked;
108
- } else if (el.type === "number" || el.type === "range") {
109
- const num = el.valueAsNumber;
110
-
111
- if (!isNaN(num)) {
112
- value = num;
113
- }
114
- } else if (el.type === "file") {
115
- // TODO: one vs multiple files
116
- value = el.files;
117
- } else {
118
- value = el.value;
119
- }
120
- } else {
121
- value = el.value;
122
- }
123
-
124
- return {
125
- key,
126
- value,
127
- };
128
- });
129
- let contentType = props.contentType;
130
-
131
- if (props.sendSubmissionsTo === "email") {
132
- contentType = "multipart/form-data";
133
- }
134
-
135
- Array.from(formPairs).forEach(({ value }) => {
136
- if (
137
- value instanceof File ||
138
- (Array.isArray(value) && value[0] instanceof File) ||
139
- value instanceof FileList
140
- ) {
141
- contentType = "multipart/form-data";
142
- }
143
- }); // TODO: send as urlEncoded or multipart by default
144
- // because of ease of use and reliability in browser API
145
- // for encoding the form?
146
-
147
- if (contentType !== "application/json") {
148
- body = formData;
149
- } else {
150
- // Json
151
- const json = {};
152
- Array.from(formPairs).forEach(({ value, key }) => {
153
- set(json, key, value);
154
- });
155
- body = JSON.stringify(json);
156
- }
157
-
158
- if (contentType && contentType !== "multipart/form-data") {
159
- if (
160
- /* Zapier doesn't allow content-type header to be sent from browsers */ !(
161
- sendWithJs && props.action?.includes("zapier.com")
162
- )
163
- ) {
164
- headers["content-type"] = contentType;
165
- }
166
- }
167
- const presubmitEvent = new CustomEvent("presubmit", { detail: { body } });
168
- if (formRef.current) {
169
- formRef.current.dispatchEvent(presubmitEvent);
170
- if (presubmitEvent.defaultPrevented) {
171
- return;
172
- }
173
- }
174
- setFormState("sending");
175
- const formUrl = `${
176
- builder.env === "dev" ? "http://localhost:5000" : "https://builder.io"
177
- }/api/v1/form-submit?apiKey=${builder.apiKey}&to=${btoa(
178
- props.sendSubmissionsToEmail || ""
179
- )}&name=${encodeURIComponent(props.name || "")}`;
180
- fetch(
181
- props.sendSubmissionsTo === "email"
182
- ? formUrl
183
- : props.action /* TODO: throw error if no action URL */,
184
- { body, headers, method: props.method || "post" }
185
- ).then(
186
- async (res) => {
187
- let body;
188
- const contentType = res.headers.get("content-type");
189
- if (contentType && contentType.indexOf("application/json") !== -1) {
190
- body = await res.json();
191
- } else {
192
- body = await res.text();
193
- }
194
- if (!res.ok && props.errorMessagePath) {
195
- /* TODO: allow supplying an error formatter function */ let message =
196
- get(body, props.errorMessagePath);
197
- if (message) {
198
- if (typeof message !== "string") {
199
- /* TODO: ideally convert json to yaml so it woul dbe like error: - email has been taken */ message =
200
- JSON.stringify(message);
201
- }
202
- setFormErrorMessage(message);
203
- }
204
- }
205
- setResponseData(body);
206
- setFormState(res.ok ? "success" : "error");
207
- if (res.ok) {
208
- const submitSuccessEvent = new CustomEvent("submit:success", {
209
- detail: { res, body },
210
- });
211
- if (formRef.current) {
212
- formRef.current.dispatchEvent(submitSuccessEvent);
213
- if (submitSuccessEvent.defaultPrevented) {
214
- return;
215
- }
216
- /* TODO: option to turn this on/off? */ if (
217
- props.resetFormOnSubmit !== false
218
- ) {
219
- formRef.current.reset();
220
- }
221
- }
222
- /* TODO: client side route event first that can be preventDefaulted */ if (
223
- props.successUrl
224
- ) {
225
- if (formRef.current) {
226
- const event = new CustomEvent("route", {
227
- detail: { url: props.successUrl },
228
- });
229
- formRef.current.dispatchEvent(event);
230
- if (!event.defaultPrevented) {
231
- location.href = props.successUrl;
232
- }
233
- } else {
234
- location.href = props.successUrl;
235
- }
236
- }
237
- }
238
- },
239
- (err) => {
240
- const submitErrorEvent = new CustomEvent("submit:error", {
241
- detail: { error: err },
242
- });
243
- if (formRef.current) {
244
- formRef.current.dispatchEvent(submitErrorEvent);
245
- if (submitErrorEvent.defaultPrevented) {
246
- return;
247
- }
248
- }
249
- setResponseData(err);
250
- setFormState("error");
251
- }
252
- );
253
- }
254
- }
255
- return (
256
- <View
257
- {...props.attributes}
258
- validate={props.validate}
259
- ref={formRef}
260
- action={!props.sendWithJs && props.action}
261
- method={props.method}
262
- name={props.name}
263
- onSubmit={(event) => onSubmit(event)}
264
- >
265
- {" "}
266
- {props.builderBlock && props.builderBlock.children ? (
267
- <>
268
- {props.builderBlock?.children?.map((block) => (
269
- <RenderBlock block={block} />
270
- ))}
271
- </>
272
- ) : null}{" "}
273
- {submissionState() === "error" ? (
274
- <>
275
- <BuilderBlocks dataPath="errorMessage" blocks={props.errorMessage} />
276
- </>
277
- ) : null}{" "}
278
- {submissionState() === "sending" ? (
279
- <>
280
- <BuilderBlocks
281
- dataPath="sendingMessage"
282
- blocks={props.sendingMessage}
283
- />
284
- </>
285
- ) : null}{" "}
286
- {submissionState() === "error" && responseData ? (
287
- <>
288
- <View style={styles.view1}>
289
- {" "}
290
- <Text>{JSON.stringify(responseData, null, 2)}</Text>{" "}
291
- </View>
292
- </>
293
- ) : null}{" "}
294
- {submissionState() === "success" ? (
295
- <>
296
- <BuilderBlocks
297
- dataPath="successMessage"
298
- blocks={props.successMessage}
299
- />
300
- </>
301
- ) : null}{" "}
302
- </View>
303
- );
304
- }
305
- const styles = StyleSheet.create({
306
- view1: { padding: 10, color: "red", textAlign: "center" },
307
- });
@@ -1,16 +0,0 @@
1
- import * as React from "react";
2
- import { View, StyleSheet, Image, Text } from "react-native";
3
-
4
- export interface FragmentProps {
5
- maxWidth?: number;
6
- attributes?: any;
7
- children?: any;
8
- }
9
-
10
- export default function FragmentComponent(props: FragmentProps) {
11
- return (
12
- <View>
13
- <Text>{props.children}</Text>
14
- </View>
15
- );
16
- }
@@ -1,84 +0,0 @@
1
- import * as React from "react";
2
- import { View, StyleSheet, Image, Text } from "react-native";
3
-
4
- export interface ImageProps {
5
- className?: string;
6
- image: string;
7
- sizes?: string;
8
- lazy?: boolean;
9
- height?: number;
10
- width?: number;
11
- altText?: string;
12
- backgroundSize?: string;
13
- backgroundPosition?: string;
14
- srcset?: string;
15
- aspectRatio?: number;
16
- children?: any;
17
- fitContent?: boolean;
18
- builderBlock?: any;
19
- }
20
-
21
- export default function Image(props: ImageProps) {
22
- return (
23
- <View style={styles.view1}>
24
- <View>
25
- <View
26
- loading="lazy"
27
- alt={props.altText}
28
- role={props.altText ? "presentation" : undefined}
29
- style={styles.view2}
30
- src={props.image}
31
- srcset={props.srcset}
32
- sizes={props.sizes}
33
- />
34
-
35
- <View srcset={props.srcset} />
36
- </View>
37
-
38
- {props.aspectRatio &&
39
- !(props.fitContent && props.builderBlock?.children?.length) ? (
40
- <View style={styles.view3}>
41
- <Text> </Text>
42
- </View>
43
- ) : null}
44
-
45
- {props.builderBlock?.children?.length && props.fitContent ? (
46
- <>
47
- <Text>{props.children}</Text>
48
- </>
49
- ) : null}
50
-
51
- {!props.fitContent ? (
52
- <>
53
- <View style={styles.view4}>
54
- <Text>{props.children}</Text>
55
- </View>
56
- </>
57
- ) : null}
58
- </View>
59
- );
60
- }
61
-
62
- const styles = StyleSheet.create({
63
- view1: { position: "relative" },
64
- view2: {
65
- opacity: 1,
66
- transition: "opacity 0.2s ease-in-out",
67
- position: "absolute",
68
- height: 100,
69
- width: 100,
70
- top: 0,
71
- left: 0,
72
- },
73
- view3: { width: 100, pointerEvents: "none", fontSize: 0 },
74
- view4: {
75
- display: "flex",
76
- flexDirection: "column",
77
- alignItems: "stretch",
78
- position: "absolute",
79
- top: 0,
80
- left: 0,
81
- width: 100,
82
- height: 100,
83
- },
84
- });