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