@builder.io/sdk-react-native 0.0.1-44 → 0.0.1-50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/blocks/button.js +23 -73
- package/src/blocks/button.lite.tsx +3 -3
- package/src/blocks/columns.js +56 -288
- package/src/blocks/columns.lite.tsx +22 -22
- package/src/blocks/custom-code.js +46 -76
- package/src/blocks/custom-code.lite.tsx +11 -19
- package/src/blocks/embed.js +46 -69
- package/src/blocks/embed.lite.tsx +11 -15
- package/src/blocks/form.js +194 -491
- package/src/blocks/form.lite.tsx +51 -51
- package/src/blocks/fragment.js +8 -16
- package/src/blocks/fragment.lite.tsx +2 -2
- package/src/blocks/image.js +91 -113
- package/src/blocks/image.lite.tsx +12 -13
- package/src/blocks/img.js +28 -51
- package/src/blocks/img.lite.tsx +6 -6
- package/src/blocks/input.js +28 -100
- package/src/blocks/input.lite.tsx +4 -4
- package/src/blocks/raw-text.js +10 -16
- package/src/blocks/raw-text.lite.tsx +3 -8
- package/src/blocks/section.js +23 -71
- package/src/blocks/section.lite.tsx +3 -3
- package/src/blocks/select.js +28 -78
- package/src/blocks/select.lite.tsx +5 -5
- package/src/blocks/submit-button.js +21 -47
- package/src/blocks/submit-button.lite.tsx +2 -2
- package/src/blocks/symbol.js +71 -20
- package/src/blocks/symbol.lite.tsx +48 -8
- package/src/blocks/text.js +27 -40
- package/src/blocks/text.lite.tsx +3 -8
- package/src/blocks/textarea.js +24 -60
- package/src/blocks/textarea.lite.tsx +2 -2
- package/src/blocks/video.js +66 -71
- package/src/blocks/video.lite.tsx +5 -5
- package/src/components/block-styles.js +4 -2
- package/src/components/block-styles.lite.tsx +2 -2
- package/src/components/error-boundary.js +9 -11
- package/src/components/error-boundary.lite.tsx +2 -2
- package/src/components/render-block.js +44 -100
- package/src/components/render-block.lite.tsx +23 -28
- package/src/components/render-blocks.js +41 -60
- package/src/components/render-blocks.lite.tsx +20 -14
- package/src/components/render-content.js +189 -142
- package/src/components/render-content.lite.tsx +166 -60
- package/src/constants/device-sizes.js +11 -8
- package/src/context/builder.context.js +10 -3
- package/src/functions/evaluate.js +20 -20
- package/src/functions/event-handler-name.js +3 -1
- package/src/functions/get-block-actions.js +17 -16
- package/src/functions/get-block-component-options.js +9 -16
- package/src/functions/get-block-properties.js +14 -18
- package/src/functions/get-block-styles.js +17 -34
- package/src/functions/get-block-tag.js +4 -2
- package/src/functions/get-builder-search-params/fn.test.js +14 -0
- package/src/functions/get-builder-search-params/index.js +23 -0
- package/src/functions/get-content/fn.test.js +32 -0
- package/src/functions/get-content/index.js +138 -0
- package/src/functions/get-fetch.js +7 -5
- package/src/functions/get-global-this.js +7 -5
- package/src/functions/get-processed-block.js +13 -17
- package/src/functions/get-processed-block.test.js +17 -16
- package/src/functions/get-target.js +4 -2
- package/src/functions/if-target.js +3 -1
- package/src/functions/is-browser.js +4 -2
- package/src/functions/is-editing.js +5 -5
- package/src/functions/is-iframe.js +4 -2
- package/src/functions/is-previewing.js +6 -4
- package/src/functions/is-react-native.js +3 -1
- package/src/functions/macro-eval.js +5 -2
- package/src/functions/on-change.js +7 -4
- package/src/functions/on-change.test.js +9 -10
- package/src/functions/previewing-model-name.js +5 -3
- package/src/functions/register-component.js +27 -38
- package/src/functions/register.js +10 -8
- package/src/functions/set-editor-settings.js +7 -5
- package/src/functions/set.js +5 -14
- package/src/functions/set.test.js +13 -14
- package/src/functions/track.js +12 -6
- package/src/functions/transform-block.js +13 -17
- package/src/index-helpers/blocks-exports.js +19 -0
- package/src/index-helpers/top-of-file.js +2 -0
- package/src/index.js +11 -26
- package/src/scripts/init-editing.js +40 -64
- package/src/types/typescript.js +1 -0
- package/src/functions/get-content.js +0 -152
- package/src/functions/get-content.test.js +0 -58
package/src/blocks/form.lite.tsx
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { View, StyleSheet, Image, Text } from
|
|
3
|
-
import { useState, useRef } from
|
|
4
|
-
import RenderBlock from
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, StyleSheet, Image, Text } from "react-native";
|
|
3
|
+
import { useState, useRef } from "react";
|
|
4
|
+
import RenderBlock from "../components/render-block.lite";
|
|
5
5
|
|
|
6
6
|
export default function FormComponent(props) {
|
|
7
|
-
const [state, setState] = useState(() =>
|
|
7
|
+
const [state, setState] = useState(() => "unsubmitted");
|
|
8
8
|
|
|
9
9
|
const [responseData, setResponseData] = useState(() => null);
|
|
10
10
|
|
|
11
|
-
const [formErrorMessage, setFormErrorMessage] = useState(() =>
|
|
11
|
+
const [formErrorMessage, setFormErrorMessage] = useState(() => "");
|
|
12
12
|
|
|
13
13
|
function submissionState() {
|
|
14
14
|
return (Builder.isEditing && props.previewState) || state;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function onSubmit(event) {
|
|
18
|
-
const sendWithJs = props.sendWithJs || props.sendSubmissionsTo ===
|
|
18
|
+
const sendWithJs = props.sendWithJs || props.sendSubmissionsTo === "email";
|
|
19
19
|
|
|
20
|
-
if (props.sendSubmissionsTo ===
|
|
20
|
+
if (props.sendSubmissionsTo === "zapier") {
|
|
21
21
|
event.preventDefault();
|
|
22
22
|
} else if (sendWithJs) {
|
|
23
|
-
if (!(props.action || props.sendSubmissionsTo ===
|
|
23
|
+
if (!(props.action || props.sendSubmissionsTo === "email")) {
|
|
24
24
|
event.preventDefault();
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
@@ -32,7 +32,7 @@ export default function FormComponent(props) {
|
|
|
32
32
|
const formData = new FormData(el); // TODO: maybe support null
|
|
33
33
|
|
|
34
34
|
const formPairs = Array.from(
|
|
35
|
-
event.currentTarget.querySelectorAll(
|
|
35
|
+
event.currentTarget.querySelectorAll("input,select,textarea")
|
|
36
36
|
)
|
|
37
37
|
.filter((el) => !!el.name)
|
|
38
38
|
.map((el) => {
|
|
@@ -40,7 +40,7 @@ export default function FormComponent(props) {
|
|
|
40
40
|
const key = el.name;
|
|
41
41
|
|
|
42
42
|
if (el instanceof HTMLInputElement) {
|
|
43
|
-
if (el.type ===
|
|
43
|
+
if (el.type === "radio") {
|
|
44
44
|
if (el.checked) {
|
|
45
45
|
value = el.name;
|
|
46
46
|
return {
|
|
@@ -48,15 +48,15 @@ export default function FormComponent(props) {
|
|
|
48
48
|
value,
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
} else if (el.type ===
|
|
51
|
+
} else if (el.type === "checkbox") {
|
|
52
52
|
value = el.checked;
|
|
53
|
-
} else if (el.type ===
|
|
53
|
+
} else if (el.type === "number" || el.type === "range") {
|
|
54
54
|
const num = el.valueAsNumber;
|
|
55
55
|
|
|
56
56
|
if (!isNaN(num)) {
|
|
57
57
|
value = num;
|
|
58
58
|
}
|
|
59
|
-
} else if (el.type ===
|
|
59
|
+
} else if (el.type === "file") {
|
|
60
60
|
// TODO: one vs multiple files
|
|
61
61
|
value = el.files;
|
|
62
62
|
} else {
|
|
@@ -73,8 +73,8 @@ export default function FormComponent(props) {
|
|
|
73
73
|
});
|
|
74
74
|
let contentType = props.contentType;
|
|
75
75
|
|
|
76
|
-
if (props.sendSubmissionsTo ===
|
|
77
|
-
contentType =
|
|
76
|
+
if (props.sendSubmissionsTo === "email") {
|
|
77
|
+
contentType = "multipart/form-data";
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
Array.from(formPairs).forEach(({ value }) => {
|
|
@@ -83,13 +83,13 @@ export default function FormComponent(props) {
|
|
|
83
83
|
(Array.isArray(value) && value[0] instanceof File) ||
|
|
84
84
|
value instanceof FileList
|
|
85
85
|
) {
|
|
86
|
-
contentType =
|
|
86
|
+
contentType = "multipart/form-data";
|
|
87
87
|
}
|
|
88
88
|
}); // TODO: send as urlEncoded or multipart by default
|
|
89
89
|
// because of ease of use and reliability in browser API
|
|
90
90
|
// for encoding the form?
|
|
91
91
|
|
|
92
|
-
if (contentType !==
|
|
92
|
+
if (contentType !== "application/json") {
|
|
93
93
|
body = formData;
|
|
94
94
|
} else {
|
|
95
95
|
// Json
|
|
@@ -100,38 +100,38 @@ export default function FormComponent(props) {
|
|
|
100
100
|
body = JSON.stringify(json);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
if (contentType && contentType !==
|
|
103
|
+
if (contentType && contentType !== "multipart/form-data") {
|
|
104
104
|
if (
|
|
105
105
|
/* Zapier doesn't allow content-type header to be sent from browsers */ !(
|
|
106
|
-
sendWithJs && props.action?.includes(
|
|
106
|
+
sendWithJs && props.action?.includes("zapier.com")
|
|
107
107
|
)
|
|
108
108
|
) {
|
|
109
|
-
headers[
|
|
109
|
+
headers["content-type"] = contentType;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
-
const presubmitEvent = new CustomEvent(
|
|
112
|
+
const presubmitEvent = new CustomEvent("presubmit", { detail: { body } });
|
|
113
113
|
if (formRef.current) {
|
|
114
114
|
formRef.current.dispatchEvent(presubmitEvent);
|
|
115
115
|
if (presubmitEvent.defaultPrevented) {
|
|
116
116
|
return;
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
setState(
|
|
119
|
+
setState("sending");
|
|
120
120
|
const formUrl = `${
|
|
121
|
-
builder.env ===
|
|
121
|
+
builder.env === "dev" ? "http://localhost:5000" : "https://builder.io"
|
|
122
122
|
}/api/v1/form-submit?apiKey=${builder.apiKey}&to=${btoa(
|
|
123
|
-
props.sendSubmissionsToEmail ||
|
|
124
|
-
)}&name=${encodeURIComponent(props.name ||
|
|
123
|
+
props.sendSubmissionsToEmail || ""
|
|
124
|
+
)}&name=${encodeURIComponent(props.name || "")}`;
|
|
125
125
|
fetch(
|
|
126
|
-
props.sendSubmissionsTo ===
|
|
126
|
+
props.sendSubmissionsTo === "email"
|
|
127
127
|
? formUrl
|
|
128
128
|
: props.action /* TODO: throw error if no action URL */,
|
|
129
|
-
{ body, headers, method: props.method ||
|
|
129
|
+
{ body, headers, method: props.method || "post" }
|
|
130
130
|
).then(
|
|
131
131
|
async (res) => {
|
|
132
132
|
let body;
|
|
133
|
-
const contentType = res.headers.get(
|
|
134
|
-
if (contentType && contentType.indexOf(
|
|
133
|
+
const contentType = res.headers.get("content-type");
|
|
134
|
+
if (contentType && contentType.indexOf("application/json") !== -1) {
|
|
135
135
|
body = await res.json();
|
|
136
136
|
} else {
|
|
137
137
|
body = await res.text();
|
|
@@ -140,7 +140,7 @@ export default function FormComponent(props) {
|
|
|
140
140
|
/* TODO: allow supplying an error formatter function */ let message =
|
|
141
141
|
get(body, props.errorMessagePath);
|
|
142
142
|
if (message) {
|
|
143
|
-
if (typeof message !==
|
|
143
|
+
if (typeof message !== "string") {
|
|
144
144
|
/* TODO: ideally convert json to yaml so it woul dbe like error: - email has been taken */ message =
|
|
145
145
|
JSON.stringify(message);
|
|
146
146
|
}
|
|
@@ -148,9 +148,9 @@ export default function FormComponent(props) {
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
setResponseData(body);
|
|
151
|
-
setState(res.ok ?
|
|
151
|
+
setState(res.ok ? "success" : "error");
|
|
152
152
|
if (res.ok) {
|
|
153
|
-
const submitSuccessEvent = new CustomEvent(
|
|
153
|
+
const submitSuccessEvent = new CustomEvent("submit:success", {
|
|
154
154
|
detail: { res, body },
|
|
155
155
|
});
|
|
156
156
|
if (formRef.current) {
|
|
@@ -168,7 +168,7 @@ export default function FormComponent(props) {
|
|
|
168
168
|
props.successUrl
|
|
169
169
|
) {
|
|
170
170
|
if (formRef.current) {
|
|
171
|
-
const event = new CustomEvent(
|
|
171
|
+
const event = new CustomEvent("route", {
|
|
172
172
|
detail: { url: props.successUrl },
|
|
173
173
|
});
|
|
174
174
|
formRef.current.dispatchEvent(event);
|
|
@@ -182,7 +182,7 @@ export default function FormComponent(props) {
|
|
|
182
182
|
}
|
|
183
183
|
},
|
|
184
184
|
(err) => {
|
|
185
|
-
const submitErrorEvent = new CustomEvent(
|
|
185
|
+
const submitErrorEvent = new CustomEvent("submit:error", {
|
|
186
186
|
detail: { error: err },
|
|
187
187
|
});
|
|
188
188
|
if (formRef.current) {
|
|
@@ -192,7 +192,7 @@ export default function FormComponent(props) {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
setResponseData(err);
|
|
195
|
-
setState(
|
|
195
|
+
setState("error");
|
|
196
196
|
}
|
|
197
197
|
);
|
|
198
198
|
}
|
|
@@ -208,46 +208,46 @@ export default function FormComponent(props) {
|
|
|
208
208
|
name={props.name}
|
|
209
209
|
onSubmit={(event) => onSubmit(event)}
|
|
210
210
|
>
|
|
211
|
-
{
|
|
211
|
+
{" "}
|
|
212
212
|
{props.builderBlock && props.builderBlock.children ? (
|
|
213
213
|
<>
|
|
214
|
-
{props.builderBlock?.children?.map((block) => (
|
|
214
|
+
{props.builderBlock?.children?.map((block, index) => (
|
|
215
215
|
<RenderBlock block={block} />
|
|
216
216
|
))}
|
|
217
217
|
</>
|
|
218
|
-
) : null}{
|
|
219
|
-
{submissionState() ===
|
|
218
|
+
) : null}{" "}
|
|
219
|
+
{submissionState() === "error" ? (
|
|
220
220
|
<>
|
|
221
221
|
<BuilderBlocks dataPath="errorMessage" blocks={props.errorMessage} />
|
|
222
222
|
</>
|
|
223
|
-
) : null}{
|
|
224
|
-
{submissionState() ===
|
|
223
|
+
) : null}{" "}
|
|
224
|
+
{submissionState() === "sending" ? (
|
|
225
225
|
<>
|
|
226
226
|
<BuilderBlocks
|
|
227
227
|
dataPath="sendingMessage"
|
|
228
228
|
blocks={props.sendingMessage}
|
|
229
229
|
/>
|
|
230
230
|
</>
|
|
231
|
-
) : null}{
|
|
232
|
-
{submissionState() ===
|
|
231
|
+
) : null}{" "}
|
|
232
|
+
{submissionState() === "error" && responseData ? (
|
|
233
233
|
<>
|
|
234
|
-
<View
|
|
235
|
-
{
|
|
236
|
-
<Text>{JSON.stringify(responseData, null, 2)}</Text>{
|
|
234
|
+
<View style={styles.view1}>
|
|
235
|
+
{" "}
|
|
236
|
+
<Text>{JSON.stringify(responseData, null, 2)}</Text>{" "}
|
|
237
237
|
</View>
|
|
238
238
|
</>
|
|
239
|
-
) : null}{
|
|
240
|
-
{submissionState() ===
|
|
239
|
+
) : null}{" "}
|
|
240
|
+
{submissionState() === "success" ? (
|
|
241
241
|
<>
|
|
242
242
|
<BuilderBlocks
|
|
243
243
|
dataPath="successMessage"
|
|
244
244
|
blocks={props.successMessage}
|
|
245
245
|
/>
|
|
246
246
|
</>
|
|
247
|
-
) : null}{
|
|
247
|
+
) : null}{" "}
|
|
248
248
|
</View>
|
|
249
249
|
);
|
|
250
250
|
}
|
|
251
251
|
const styles = StyleSheet.create({
|
|
252
|
-
view1: { padding: 10, color:
|
|
252
|
+
view1: { padding: 10, color: "red", textAlign: "center" },
|
|
253
253
|
});
|
package/src/blocks/fragment.js
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import { registerComponent } from '../functions/register-component';
|
|
2
2
|
|
|
3
|
-
import * as React from
|
|
4
|
-
import { View, Text } from
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { View, Text } from "react-native";
|
|
5
5
|
function FragmentComponent(props) {
|
|
6
|
-
|
|
7
|
-
View,
|
|
8
|
-
null,
|
|
9
|
-
/* @__PURE__ */ React.createElement(Text, null, props.children)
|
|
10
|
-
);
|
|
6
|
+
return /* @__PURE__ */ React.createElement(View, null, /* @__PURE__ */ React.createElement(Text, null, props.children));
|
|
11
7
|
}
|
|
12
|
-
export {
|
|
8
|
+
export {
|
|
9
|
+
FragmentComponent as default
|
|
10
|
+
};
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
static: true,
|
|
17
|
-
hidden: true,
|
|
18
|
-
builtIn: true,
|
|
19
|
-
canHaveChildren: true,
|
|
20
|
-
noWrap: true,
|
|
21
|
-
});
|
|
12
|
+
|
|
13
|
+
registerComponent(FragmentComponent, {name:'Fragment',static:true,hidden:true,builtIn:true,canHaveChildren:true,noWrap:true});
|
package/src/blocks/image.js
CHANGED
|
@@ -3,163 +3,141 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
4
4
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
5
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
6
|
-
var __defNormalProp = (obj, key, value) =>
|
|
7
|
-
key in obj
|
|
8
|
-
? __defProp(obj, key, {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
configurable: true,
|
|
11
|
-
writable: true,
|
|
12
|
-
value,
|
|
13
|
-
})
|
|
14
|
-
: (obj[key] = value);
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
15
7
|
var __spreadValues = (a, b) => {
|
|
16
8
|
for (var prop in b || (b = {}))
|
|
17
|
-
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
if (__hasOwnProp.call(b, prop))
|
|
10
|
+
__defNormalProp(a, prop, b[prop]);
|
|
18
11
|
if (__getOwnPropSymbols)
|
|
19
12
|
for (var prop of __getOwnPropSymbols(b)) {
|
|
20
|
-
if (__propIsEnum.call(b, prop))
|
|
13
|
+
if (__propIsEnum.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
15
|
}
|
|
22
16
|
return a;
|
|
23
17
|
};
|
|
24
|
-
import { Image as ReactImage, View } from
|
|
25
|
-
import { registerComponent } from
|
|
18
|
+
import { Image as ReactImage, View } from "react-native";
|
|
19
|
+
import { registerComponent } from "../functions/register-component";
|
|
26
20
|
function Image(props) {
|
|
27
|
-
return props.aspectRatio
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
: /* @__PURE__ */ React.createElement(ReactImage, {
|
|
46
|
-
resizeMode: props.backgroundSize || 'contain',
|
|
47
|
-
style: __spreadValues(
|
|
48
|
-
__spreadValues(
|
|
49
|
-
{
|
|
50
|
-
position: 'relative',
|
|
51
|
-
},
|
|
52
|
-
props.width ? { width: props.width } : {}
|
|
53
|
-
),
|
|
54
|
-
props.height ? { height: props.height } : {}
|
|
55
|
-
),
|
|
56
|
-
source: { uri: props.image },
|
|
57
|
-
});
|
|
21
|
+
return props.aspectRatio ? /* @__PURE__ */ React.createElement(View, {
|
|
22
|
+
style: { position: "relative" }
|
|
23
|
+
}, /* @__PURE__ */ React.createElement(ReactImage, {
|
|
24
|
+
resizeMode: props.backgroundSize || "contain",
|
|
25
|
+
style: { position: "absolute", top: 0, bottom: 0, left: 0, right: 0 },
|
|
26
|
+
source: { uri: props.image }
|
|
27
|
+
}), /* @__PURE__ */ React.createElement(View, {
|
|
28
|
+
style: {
|
|
29
|
+
width: "100%",
|
|
30
|
+
paddingTop: props.aspectRatio * 100 + "%"
|
|
31
|
+
}
|
|
32
|
+
})) : /* @__PURE__ */ React.createElement(ReactImage, {
|
|
33
|
+
resizeMode: props.backgroundSize || "contain",
|
|
34
|
+
style: __spreadValues(__spreadValues({
|
|
35
|
+
position: "relative"
|
|
36
|
+
}, props.width ? { width: props.width } : {}), props.height ? { height: props.height } : {}),
|
|
37
|
+
source: { uri: props.image }
|
|
38
|
+
});
|
|
58
39
|
}
|
|
59
40
|
registerComponent(Image, {
|
|
60
|
-
name:
|
|
41
|
+
name: "Image",
|
|
61
42
|
static: true,
|
|
62
43
|
builtIn: true,
|
|
63
|
-
image:
|
|
64
|
-
'https://firebasestorage.googleapis.com/v0/b/builder-3b0a2.appspot.com/o/images%2Fbaseline-insert_photo-24px.svg?alt=media&token=4e5d0ef4-f5e8-4e57-b3a9-38d63a9b9dc4',
|
|
44
|
+
image: "https://firebasestorage.googleapis.com/v0/b/builder-3b0a2.appspot.com/o/images%2Fbaseline-insert_photo-24px.svg?alt=media&token=4e5d0ef4-f5e8-4e57-b3a9-38d63a9b9dc4",
|
|
65
45
|
defaultStyles: {
|
|
66
|
-
position:
|
|
67
|
-
minHeight:
|
|
68
|
-
minWidth:
|
|
69
|
-
overflow:
|
|
46
|
+
position: "relative",
|
|
47
|
+
minHeight: "20px",
|
|
48
|
+
minWidth: "20px",
|
|
49
|
+
overflow: "hidden"
|
|
70
50
|
},
|
|
71
51
|
canHaveChildren: true,
|
|
72
52
|
inputs: [
|
|
73
53
|
{
|
|
74
|
-
name:
|
|
75
|
-
type:
|
|
54
|
+
name: "image",
|
|
55
|
+
type: "file",
|
|
76
56
|
bubble: true,
|
|
77
|
-
allowedFileTypes: [
|
|
57
|
+
allowedFileTypes: ["jpeg", "jpg", "png", "svg"],
|
|
78
58
|
required: true,
|
|
79
|
-
defaultValue:
|
|
80
|
-
'
|
|
81
|
-
onChange:
|
|
82
|
-
" 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); } } }); }",
|
|
59
|
+
defaultValue: "https://cdn.builder.io/api/v1/image/assets%2Fpwgjf0RoYWbdnJSbpBAjXNRMe9F2%2Ffb27a7c790324294af8be1c35fe30f4d",
|
|
60
|
+
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); } } }); }"
|
|
83
61
|
},
|
|
84
62
|
{
|
|
85
|
-
name:
|
|
86
|
-
type:
|
|
87
|
-
defaultValue:
|
|
63
|
+
name: "backgroundSize",
|
|
64
|
+
type: "text",
|
|
65
|
+
defaultValue: "cover",
|
|
88
66
|
enum: [
|
|
89
67
|
{
|
|
90
|
-
label:
|
|
91
|
-
value:
|
|
92
|
-
helperText:
|
|
68
|
+
label: "contain",
|
|
69
|
+
value: "contain",
|
|
70
|
+
helperText: "The image should never get cropped"
|
|
93
71
|
},
|
|
94
72
|
{
|
|
95
|
-
label:
|
|
96
|
-
value:
|
|
97
|
-
helperText: `The image should fill it's box, cropping when needed
|
|
98
|
-
}
|
|
99
|
-
]
|
|
73
|
+
label: "cover",
|
|
74
|
+
value: "cover",
|
|
75
|
+
helperText: `The image should fill it's box, cropping when needed`
|
|
76
|
+
}
|
|
77
|
+
]
|
|
100
78
|
},
|
|
101
79
|
{
|
|
102
|
-
name:
|
|
103
|
-
type:
|
|
104
|
-
defaultValue:
|
|
80
|
+
name: "backgroundPosition",
|
|
81
|
+
type: "text",
|
|
82
|
+
defaultValue: "center",
|
|
105
83
|
enum: [
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
]
|
|
84
|
+
"center",
|
|
85
|
+
"top",
|
|
86
|
+
"left",
|
|
87
|
+
"right",
|
|
88
|
+
"bottom",
|
|
89
|
+
"top left",
|
|
90
|
+
"top right",
|
|
91
|
+
"bottom left",
|
|
92
|
+
"bottom right"
|
|
93
|
+
]
|
|
116
94
|
},
|
|
117
95
|
{
|
|
118
|
-
name:
|
|
119
|
-
type:
|
|
120
|
-
helperText:
|
|
96
|
+
name: "altText",
|
|
97
|
+
type: "string",
|
|
98
|
+
helperText: "Text to display when the user has images off"
|
|
121
99
|
},
|
|
122
100
|
{
|
|
123
|
-
name:
|
|
124
|
-
type:
|
|
125
|
-
hideFromUI: true
|
|
101
|
+
name: "height",
|
|
102
|
+
type: "number",
|
|
103
|
+
hideFromUI: true
|
|
126
104
|
},
|
|
127
105
|
{
|
|
128
|
-
name:
|
|
129
|
-
type:
|
|
130
|
-
hideFromUI: true
|
|
106
|
+
name: "width",
|
|
107
|
+
type: "number",
|
|
108
|
+
hideFromUI: true
|
|
131
109
|
},
|
|
132
110
|
{
|
|
133
|
-
name:
|
|
134
|
-
type:
|
|
135
|
-
hideFromUI: true
|
|
111
|
+
name: "sizes",
|
|
112
|
+
type: "string",
|
|
113
|
+
hideFromUI: true
|
|
136
114
|
},
|
|
137
115
|
{
|
|
138
|
-
name:
|
|
139
|
-
type:
|
|
140
|
-
hideFromUI: true
|
|
116
|
+
name: "srcset",
|
|
117
|
+
type: "string",
|
|
118
|
+
hideFromUI: true
|
|
141
119
|
},
|
|
142
120
|
{
|
|
143
|
-
name:
|
|
144
|
-
type:
|
|
121
|
+
name: "lazy",
|
|
122
|
+
type: "boolean",
|
|
145
123
|
defaultValue: true,
|
|
146
|
-
hideFromUI: true
|
|
124
|
+
hideFromUI: true
|
|
147
125
|
},
|
|
148
126
|
{
|
|
149
|
-
name:
|
|
150
|
-
type:
|
|
151
|
-
helperText:
|
|
152
|
-
|
|
153
|
-
defaultValue: true,
|
|
127
|
+
name: "fitContent",
|
|
128
|
+
type: "boolean",
|
|
129
|
+
helperText: "When child blocks are provided, fit to them instead of using the image's aspect ratio",
|
|
130
|
+
defaultValue: true
|
|
154
131
|
},
|
|
155
132
|
{
|
|
156
|
-
name:
|
|
157
|
-
type:
|
|
158
|
-
helperText:
|
|
159
|
-
"This is the ratio of height/width, e.g. set to 1.5 for a 300px wide and 200px tall photo. Set to 0 to not force the image to maintain it's aspect ratio",
|
|
133
|
+
name: "aspectRatio",
|
|
134
|
+
type: "number",
|
|
135
|
+
helperText: "This is the ratio of height/width, e.g. set to 1.5 for a 300px wide and 200px tall photo. Set to 0 to not force the image to maintain it's aspect ratio",
|
|
160
136
|
advanced: true,
|
|
161
|
-
defaultValue: 0.7041
|
|
162
|
-
}
|
|
163
|
-
]
|
|
137
|
+
defaultValue: 0.7041
|
|
138
|
+
}
|
|
139
|
+
]
|
|
164
140
|
});
|
|
165
|
-
export {
|
|
141
|
+
export {
|
|
142
|
+
Image as default
|
|
143
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as React from
|
|
2
|
-
import { View, StyleSheet, Image, Text } from
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, StyleSheet, Image, Text } from "react-native";
|
|
3
3
|
|
|
4
4
|
export default function Image(props) {
|
|
5
5
|
return (
|
|
@@ -8,9 +8,8 @@ export default function Image(props) {
|
|
|
8
8
|
<View
|
|
9
9
|
loading="lazy"
|
|
10
10
|
alt={props.altText}
|
|
11
|
-
aria-role={props.altText ?
|
|
11
|
+
aria-role={props.altText ? "presentation" : undefined}
|
|
12
12
|
style={styles.view2}
|
|
13
|
-
className={'builder-image' + (props.class ? ' ' + props.class : '')}
|
|
14
13
|
src={props.image}
|
|
15
14
|
srcset={props.srcset}
|
|
16
15
|
sizes={props.sizes}
|
|
@@ -21,7 +20,7 @@ export default function Image(props) {
|
|
|
21
20
|
|
|
22
21
|
{props.aspectRatio &&
|
|
23
22
|
!(props.fitContent && props.builderBlock?.children?.length) ? (
|
|
24
|
-
<View
|
|
23
|
+
<View style={styles.view3}>
|
|
25
24
|
<Text> </Text>
|
|
26
25
|
</View>
|
|
27
26
|
) : null}
|
|
@@ -44,22 +43,22 @@ export default function Image(props) {
|
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
const styles = StyleSheet.create({
|
|
47
|
-
view1: { position:
|
|
46
|
+
view1: { position: "relative" },
|
|
48
47
|
view2: {
|
|
49
48
|
opacity: 1,
|
|
50
|
-
transition:
|
|
51
|
-
position:
|
|
49
|
+
transition: "opacity 0.2s ease-in-out",
|
|
50
|
+
position: "absolute",
|
|
52
51
|
height: 100,
|
|
53
52
|
width: 100,
|
|
54
53
|
top: 0,
|
|
55
54
|
left: 0,
|
|
56
55
|
},
|
|
57
|
-
view3: { width: 100, pointerEvents:
|
|
56
|
+
view3: { width: 100, pointerEvents: "none", fontSize: 0 },
|
|
58
57
|
view4: {
|
|
59
|
-
display:
|
|
60
|
-
flexDirection:
|
|
61
|
-
alignItems:
|
|
62
|
-
position:
|
|
58
|
+
display: "flex",
|
|
59
|
+
flexDirection: "column",
|
|
60
|
+
alignItems: "stretch",
|
|
61
|
+
position: "absolute",
|
|
63
62
|
top: 0,
|
|
64
63
|
left: 0,
|
|
65
64
|
width: 100,
|