@builder.io/sdk-solid 0.0.20 → 0.0.21
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 +1 -1
- package/src/blocks/BaseText.jsx +0 -2
- package/src/blocks/button/button.jsx +1 -3
- package/src/blocks/columns/columns.jsx +1 -13
- package/src/blocks/columns/component-info.js +2 -2
- package/src/blocks/custom-code/custom-code.jsx +0 -8
- package/src/blocks/embed/component-info.js +2 -2
- package/src/blocks/embed/embed.jsx +0 -8
- package/src/blocks/form/form.jsx +9 -43
- package/src/blocks/fragment/fragment.jsx +0 -1
- package/src/blocks/image/component-info.js +2 -2
- package/src/blocks/image/image.jsx +4 -9
- package/src/blocks/img/img.jsx +2 -4
- package/src/blocks/input/input.jsx +0 -2
- package/src/blocks/raw-text/raw-text.jsx +0 -1
- package/src/blocks/section/section.jsx +0 -1
- package/src/blocks/select/select.jsx +0 -3
- package/src/blocks/submit-button/submit-button.jsx +1 -2
- package/src/blocks/symbol/symbol.jsx +4 -10
- package/src/blocks/text/text.jsx +0 -1
- package/src/blocks/textarea/textarea.jsx +0 -1
- package/src/blocks/util.js +6 -5
- package/src/blocks/video/video.jsx +4 -5
- package/src/components/render-block/block-styles.jsx +5 -7
- package/src/components/render-block/render-block.jsx +17 -39
- package/src/components/render-block/render-component-with-context.jsx +0 -8
- package/src/components/render-block/render-component.jsx +1 -6
- package/src/components/render-block/render-repeated-block.jsx +0 -8
- package/src/components/render-blocks.jsx +0 -7
- package/src/components/render-content/builder-editing.jsx +4 -0
- package/src/components/render-content/components/render-styles.jsx +2 -13
- package/src/components/render-content/render-content.jsx +16 -51
- package/src/components/render-inlined-styles.jsx +3 -7
- package/src/constants/device-sizes.js +29 -2
- package/src/functions/get-content/index.js +6 -2
- package/src/functions/register-component.js +1 -5
- package/src/index.js +1 -1
- package/src/scripts/init-editing.js +7 -1
package/package.json
CHANGED
package/src/blocks/BaseText.jsx
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { useContext } from "solid-js";
|
|
2
2
|
import BuilderContext from "../context/builder.context.js";
|
|
3
|
-
|
|
4
3
|
function BaseText(props) {
|
|
5
4
|
const builderContext = useContext(BuilderContext);
|
|
6
5
|
return <span style={builderContext.inheritedStyles}>{props.text}</span>;
|
|
7
6
|
}
|
|
8
|
-
|
|
9
7
|
export default BaseText;
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { Show } from "solid-js";
|
|
2
2
|
import { css } from "solid-styled-components";
|
|
3
|
-
|
|
4
3
|
function Button(props) {
|
|
5
4
|
return <Show fallback={<button class={css({
|
|
6
5
|
all: "unset"
|
|
7
6
|
})} {...props.attributes}>
|
|
8
7
|
{props.text}
|
|
9
8
|
</button>} when={props.link}>
|
|
10
|
-
<a {...props.attributes}
|
|
9
|
+
<a role="button" {...props.attributes} href={props.link} target={props.openLinkInNewTab ? "_blank" : undefined}>
|
|
11
10
|
{props.text}
|
|
12
11
|
</a>
|
|
13
12
|
</Show>;
|
|
14
13
|
}
|
|
15
|
-
|
|
16
14
|
export default Button;
|
|
@@ -1,35 +1,27 @@
|
|
|
1
1
|
import { For } from "solid-js";
|
|
2
2
|
import { css } from "solid-styled-components";
|
|
3
3
|
import RenderBlocks from "../../components/render-blocks.jsx";
|
|
4
|
-
import { markMutable } from "../../functions/mark-mutable";
|
|
5
|
-
|
|
6
4
|
function Columns(props) {
|
|
7
5
|
function getGutterSize() {
|
|
8
6
|
return typeof props.space === "number" ? props.space || 0 : 20;
|
|
9
7
|
}
|
|
10
|
-
|
|
11
8
|
function getColumns() {
|
|
12
9
|
return props.columns || [];
|
|
13
10
|
}
|
|
14
|
-
|
|
15
11
|
function getWidth(index) {
|
|
16
12
|
const columns = getColumns();
|
|
17
13
|
return columns[index]?.width || 100 / columns.length;
|
|
18
14
|
}
|
|
19
|
-
|
|
20
15
|
function getColumnCssWidth(index) {
|
|
21
16
|
const columns = getColumns();
|
|
22
17
|
const gutterSize = getGutterSize();
|
|
23
18
|
const subtractWidth = gutterSize * (columns.length - 1) / columns.length;
|
|
24
19
|
return `calc(${getWidth(index)}% - ${subtractWidth}px)`;
|
|
25
20
|
}
|
|
26
|
-
|
|
27
21
|
function maybeApplyForTablet(prop) {
|
|
28
22
|
const _stackColumnsAt = props.stackColumnsAt || "tablet";
|
|
29
|
-
|
|
30
23
|
return _stackColumnsAt === "tablet" ? prop : "inherit";
|
|
31
24
|
}
|
|
32
|
-
|
|
33
25
|
function columnsCssVars() {
|
|
34
26
|
const flexDir = props.stackColumnsAt === "never" ? "inherit" : props.reverseColumnsWhenStacked ? "column-reverse" : "column";
|
|
35
27
|
return {
|
|
@@ -37,7 +29,6 @@ function Columns(props) {
|
|
|
37
29
|
"--flex-dir-tablet": maybeApplyForTablet(flexDir)
|
|
38
30
|
};
|
|
39
31
|
}
|
|
40
|
-
|
|
41
32
|
function columnCssVars() {
|
|
42
33
|
const width = "100%";
|
|
43
34
|
const marginLeft = "0";
|
|
@@ -48,7 +39,6 @@ function Columns(props) {
|
|
|
48
39
|
"--column-margin-left-tablet": maybeApplyForTablet(marginLeft)
|
|
49
40
|
};
|
|
50
41
|
}
|
|
51
|
-
|
|
52
42
|
return <div class={"builder-columns " + css({
|
|
53
43
|
display: "flex",
|
|
54
44
|
alignItems: "stretch",
|
|
@@ -63,7 +53,6 @@ function Columns(props) {
|
|
|
63
53
|
<For each={props.columns}>
|
|
64
54
|
{(column, _index) => {
|
|
65
55
|
const index = _index();
|
|
66
|
-
|
|
67
56
|
return <div class={"builder-column " + css({
|
|
68
57
|
display: "flex",
|
|
69
58
|
flexDirection: "column",
|
|
@@ -81,7 +70,7 @@ function Columns(props) {
|
|
|
81
70
|
"margin-left": `${index === 0 ? 0 : getGutterSize()}px`,
|
|
82
71
|
...columnCssVars()
|
|
83
72
|
}} key={index}>
|
|
84
|
-
<RenderBlocks blocks={
|
|
73
|
+
<RenderBlocks blocks={column.blocks} path={`component.options.columns.${index}.blocks`} parent={props.builderBlock.id} styleProp={{
|
|
85
74
|
flexGrow: "1"
|
|
86
75
|
}}></RenderBlocks>
|
|
87
76
|
</div>;
|
|
@@ -89,5 +78,4 @@ function Columns(props) {
|
|
|
89
78
|
</For>
|
|
90
79
|
</div>;
|
|
91
80
|
}
|
|
92
|
-
|
|
93
81
|
export default Columns;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serializeFn } from "../util.js";
|
|
2
2
|
const componentInfo = {
|
|
3
3
|
name: "Columns",
|
|
4
4
|
builtIn: true,
|
|
@@ -187,7 +187,7 @@ const componentInfo = {
|
|
|
187
187
|
]
|
|
188
188
|
}
|
|
189
189
|
],
|
|
190
|
-
onChange:
|
|
190
|
+
onChange: serializeFn((options) => {
|
|
191
191
|
function clearWidths() {
|
|
192
192
|
columns.forEach((col) => {
|
|
193
193
|
col.delete("width");
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
import { onMount, createSignal } from "solid-js";
|
|
2
|
-
|
|
3
2
|
function CustomCode(props) {
|
|
4
3
|
const [scriptsInserted, setScriptsInserted] = createSignal([]);
|
|
5
4
|
const [scriptsRun, setScriptsRun] = createSignal([]);
|
|
6
|
-
|
|
7
5
|
function findAndRunScripts() {
|
|
8
6
|
// TODO: Move this function to standalone one in '@builder.io/utils'
|
|
9
7
|
if (elem && elem.getElementsByTagName && typeof window !== "undefined") {
|
|
10
8
|
const scripts = elem.getElementsByTagName("script");
|
|
11
|
-
|
|
12
9
|
for (let i = 0; i < scripts.length; i++) {
|
|
13
10
|
const script = scripts[i];
|
|
14
|
-
|
|
15
11
|
if (script.src) {
|
|
16
12
|
if (scriptsInserted().includes(script.src)) {
|
|
17
13
|
continue;
|
|
18
14
|
}
|
|
19
|
-
|
|
20
15
|
scriptsInserted().push(script.src);
|
|
21
16
|
const newScript = document.createElement("script");
|
|
22
17
|
newScript.async = true;
|
|
@@ -26,7 +21,6 @@ function CustomCode(props) {
|
|
|
26
21
|
if (scriptsRun().includes(script.innerText)) {
|
|
27
22
|
continue;
|
|
28
23
|
}
|
|
29
|
-
|
|
30
24
|
try {
|
|
31
25
|
scriptsRun().push(script.innerText);
|
|
32
26
|
new Function(script.innerText)();
|
|
@@ -37,12 +31,10 @@ function CustomCode(props) {
|
|
|
37
31
|
}
|
|
38
32
|
}
|
|
39
33
|
}
|
|
40
|
-
|
|
41
34
|
let elem;
|
|
42
35
|
onMount(() => {
|
|
43
36
|
findAndRunScripts();
|
|
44
37
|
});
|
|
45
38
|
return <div class={"builder-custom-code" + (props.replaceNodes ? " replace-nodes" : "")} ref={elem} innerHTML={props.code}></div>;
|
|
46
39
|
}
|
|
47
|
-
|
|
48
40
|
export default CustomCode;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serializeFn } from "../util.js";
|
|
2
2
|
const componentInfo = {
|
|
3
3
|
name: "Embed",
|
|
4
4
|
static: true,
|
|
@@ -10,7 +10,7 @@ const componentInfo = {
|
|
|
10
10
|
required: true,
|
|
11
11
|
defaultValue: "",
|
|
12
12
|
helperText: "e.g. enter a youtube url, google map, etc",
|
|
13
|
-
onChange:
|
|
13
|
+
onChange: serializeFn((options) => {
|
|
14
14
|
const url = options.get("url");
|
|
15
15
|
if (url) {
|
|
16
16
|
options.set("content", "Loading...");
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { on, createEffect, createSignal } from "solid-js";
|
|
2
2
|
import { isJsScript } from "./helpers.js";
|
|
3
|
-
|
|
4
3
|
function Embed(props) {
|
|
5
4
|
const [scriptsInserted, setScriptsInserted] = createSignal([]);
|
|
6
5
|
const [scriptsRun, setScriptsRun] = createSignal([]);
|
|
7
6
|
const [ranInitFn, setRanInitFn] = createSignal(false);
|
|
8
|
-
|
|
9
7
|
function findAndRunScripts() {
|
|
10
8
|
if (!elem || !elem.getElementsByTagName) return;
|
|
11
9
|
const scripts = elem.getElementsByTagName("script");
|
|
12
|
-
|
|
13
10
|
for (let i = 0; i < scripts.length; i++) {
|
|
14
11
|
const script = scripts[i];
|
|
15
|
-
|
|
16
12
|
if (script.src && !scriptsInserted().includes(script.src)) {
|
|
17
13
|
scriptsInserted().push(script.src);
|
|
18
14
|
const newScript = document.createElement("script");
|
|
@@ -29,18 +25,14 @@ function Embed(props) {
|
|
|
29
25
|
}
|
|
30
26
|
}
|
|
31
27
|
}
|
|
32
|
-
|
|
33
28
|
let elem;
|
|
34
|
-
|
|
35
29
|
function onUpdateFn_0() {
|
|
36
30
|
if (elem && !ranInitFn()) {
|
|
37
31
|
setRanInitFn(true);
|
|
38
32
|
findAndRunScripts();
|
|
39
33
|
}
|
|
40
34
|
}
|
|
41
|
-
|
|
42
35
|
createEffect(on(() => [elem, ranInitFn()], onUpdateFn_0));
|
|
43
36
|
return <div class="builder-embed" ref={elem} innerHTML={props.content}></div>;
|
|
44
37
|
}
|
|
45
|
-
|
|
46
38
|
export default Embed;
|
package/src/blocks/form/form.jsx
CHANGED
|
@@ -3,19 +3,15 @@ import { css } from "solid-styled-components";
|
|
|
3
3
|
import RenderBlock from "../../components/render-block/render-block.jsx";
|
|
4
4
|
import BuilderBlocks from "../../components/render-blocks.jsx";
|
|
5
5
|
import { isEditing } from "../../functions/is-editing.js";
|
|
6
|
-
|
|
7
6
|
function FormComponent(props) {
|
|
8
7
|
const [formState, setFormState] = createSignal("unsubmitted");
|
|
9
8
|
const [responseData, setResponseData] = createSignal(null);
|
|
10
9
|
const [formErrorMessage, setFormErrorMessage] = createSignal("");
|
|
11
|
-
|
|
12
10
|
function submissionState() {
|
|
13
11
|
return isEditing() && props.previewState || formState();
|
|
14
12
|
}
|
|
15
|
-
|
|
16
13
|
function onSubmit(event) {
|
|
17
14
|
const sendWithJs = props.sendWithJs || props.sendSubmissionsTo === "email";
|
|
18
|
-
|
|
19
15
|
if (props.sendSubmissionsTo === "zapier") {
|
|
20
16
|
event.preventDefault();
|
|
21
17
|
} else if (sendWithJs) {
|
|
@@ -23,17 +19,16 @@ function FormComponent(props) {
|
|
|
23
19
|
event.preventDefault();
|
|
24
20
|
return;
|
|
25
21
|
}
|
|
26
|
-
|
|
27
22
|
event.preventDefault();
|
|
28
23
|
const el = event.currentTarget;
|
|
29
24
|
const headers = props.customHeaders || {};
|
|
30
25
|
let body;
|
|
31
|
-
const formData = new FormData(el);
|
|
26
|
+
const formData = new FormData(el);
|
|
32
27
|
|
|
28
|
+
// TODO: maybe support null
|
|
33
29
|
const formPairs = Array.from(event.currentTarget.querySelectorAll("input,select,textarea")).filter(el => !!el.name).map(el => {
|
|
34
30
|
let value;
|
|
35
31
|
const key = el.name;
|
|
36
|
-
|
|
37
32
|
if (el instanceof HTMLInputElement) {
|
|
38
33
|
if (el.type === "radio") {
|
|
39
34
|
if (el.checked) {
|
|
@@ -47,7 +42,6 @@ function FormComponent(props) {
|
|
|
47
42
|
value = el.checked;
|
|
48
43
|
} else if (el.type === "number" || el.type === "range") {
|
|
49
44
|
const num = el.valueAsNumber;
|
|
50
|
-
|
|
51
45
|
if (!isNaN(num)) {
|
|
52
46
|
value = num;
|
|
53
47
|
}
|
|
@@ -60,28 +54,26 @@ function FormComponent(props) {
|
|
|
60
54
|
} else {
|
|
61
55
|
value = el.value;
|
|
62
56
|
}
|
|
63
|
-
|
|
64
57
|
return {
|
|
65
58
|
key,
|
|
66
59
|
value
|
|
67
60
|
};
|
|
68
61
|
});
|
|
69
62
|
let contentType = props.contentType;
|
|
70
|
-
|
|
71
63
|
if (props.sendSubmissionsTo === "email") {
|
|
72
64
|
contentType = "multipart/form-data";
|
|
73
65
|
}
|
|
74
|
-
|
|
75
66
|
Array.from(formPairs).forEach(({
|
|
76
67
|
value
|
|
77
68
|
}) => {
|
|
78
69
|
if (value instanceof File || Array.isArray(value) && value[0] instanceof File || value instanceof FileList) {
|
|
79
70
|
contentType = "multipart/form-data";
|
|
80
71
|
}
|
|
81
|
-
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// TODO: send as urlEncoded or multipart by default
|
|
82
75
|
// because of ease of use and reliability in browser API
|
|
83
76
|
// for encoding the form?
|
|
84
|
-
|
|
85
77
|
if (contentType !== "application/json") {
|
|
86
78
|
body = formData;
|
|
87
79
|
} else {
|
|
@@ -95,65 +87,51 @@ function FormComponent(props) {
|
|
|
95
87
|
});
|
|
96
88
|
body = JSON.stringify(json);
|
|
97
89
|
}
|
|
98
|
-
|
|
99
90
|
if (contentType && contentType !== "multipart/form-data") {
|
|
100
|
-
if (
|
|
101
|
-
/* Zapier doesn't allow content-type header to be sent from browsers */
|
|
91
|
+
if ( /* Zapier doesn't allow content-type header to be sent from browsers */
|
|
102
92
|
!(sendWithJs && props.action?.includes("zapier.com"))) {
|
|
103
93
|
headers["content-type"] = contentType;
|
|
104
94
|
}
|
|
105
95
|
}
|
|
106
|
-
|
|
107
96
|
const presubmitEvent = new CustomEvent("presubmit", {
|
|
108
97
|
detail: {
|
|
109
98
|
body
|
|
110
99
|
}
|
|
111
100
|
});
|
|
112
|
-
|
|
113
101
|
if (formRef) {
|
|
114
102
|
formRef.dispatchEvent(presubmitEvent);
|
|
115
|
-
|
|
116
103
|
if (presubmitEvent.defaultPrevented) {
|
|
117
104
|
return;
|
|
118
105
|
}
|
|
119
106
|
}
|
|
120
|
-
|
|
121
107
|
setFormState("sending");
|
|
122
108
|
const formUrl = `${builder.env === "dev" ? "http://localhost:5000" : "https://builder.io"}/api/v1/form-submit?apiKey=${builder.apiKey}&to=${btoa(props.sendSubmissionsToEmail || "")}&name=${encodeURIComponent(props.name || "")}`;
|
|
123
|
-
fetch(props.sendSubmissionsTo === "email" ? formUrl : props.action
|
|
124
|
-
/* TODO: throw error if no action URL */
|
|
125
|
-
, {
|
|
109
|
+
fetch(props.sendSubmissionsTo === "email" ? formUrl : props.action /* TODO: throw error if no action URL */, {
|
|
126
110
|
body,
|
|
127
111
|
headers,
|
|
128
112
|
method: props.method || "post"
|
|
129
113
|
}).then(async res => {
|
|
130
114
|
let body;
|
|
131
115
|
const contentType = res.headers.get("content-type");
|
|
132
|
-
|
|
133
116
|
if (contentType && contentType.indexOf("application/json") !== -1) {
|
|
134
117
|
body = await res.json();
|
|
135
118
|
} else {
|
|
136
119
|
body = await res.text();
|
|
137
120
|
}
|
|
138
|
-
|
|
139
121
|
if (!res.ok && props.errorMessagePath) {
|
|
140
122
|
/* TODO: allow supplying an error formatter function */
|
|
141
123
|
let message = get(body, props.errorMessagePath);
|
|
142
|
-
|
|
143
124
|
if (message) {
|
|
144
125
|
if (typeof message !== "string") {
|
|
145
126
|
/* TODO: ideally convert json to yaml so it woul dbe like
|
|
146
127
|
error: - email has been taken */
|
|
147
128
|
message = JSON.stringify(message);
|
|
148
129
|
}
|
|
149
|
-
|
|
150
130
|
setFormErrorMessage(message);
|
|
151
131
|
}
|
|
152
132
|
}
|
|
153
|
-
|
|
154
133
|
setResponseData(body);
|
|
155
134
|
setFormState(res.ok ? "success" : "error");
|
|
156
|
-
|
|
157
135
|
if (res.ok) {
|
|
158
136
|
const submitSuccessEvent = new CustomEvent("submit:success", {
|
|
159
137
|
detail: {
|
|
@@ -161,23 +139,18 @@ function FormComponent(props) {
|
|
|
161
139
|
body
|
|
162
140
|
}
|
|
163
141
|
});
|
|
164
|
-
|
|
165
142
|
if (formRef) {
|
|
166
143
|
formRef.dispatchEvent(submitSuccessEvent);
|
|
167
|
-
|
|
168
144
|
if (submitSuccessEvent.defaultPrevented) {
|
|
169
145
|
return;
|
|
170
146
|
}
|
|
171
147
|
/* TODO: option to turn this on/off? */
|
|
172
|
-
|
|
173
|
-
|
|
174
148
|
if (props.resetFormOnSubmit !== false) {
|
|
175
149
|
formRef.reset();
|
|
176
150
|
}
|
|
177
151
|
}
|
|
178
|
-
/* TODO: client side route event first that can be preventDefaulted */
|
|
179
|
-
|
|
180
152
|
|
|
153
|
+
/* TODO: client side route event first that can be preventDefaulted */
|
|
181
154
|
if (props.successUrl) {
|
|
182
155
|
if (formRef) {
|
|
183
156
|
const event = new CustomEvent("route", {
|
|
@@ -186,7 +159,6 @@ function FormComponent(props) {
|
|
|
186
159
|
}
|
|
187
160
|
});
|
|
188
161
|
formRef.dispatchEvent(event);
|
|
189
|
-
|
|
190
162
|
if (!event.defaultPrevented) {
|
|
191
163
|
location.href = props.successUrl;
|
|
192
164
|
}
|
|
@@ -201,29 +173,24 @@ function FormComponent(props) {
|
|
|
201
173
|
error: err
|
|
202
174
|
}
|
|
203
175
|
});
|
|
204
|
-
|
|
205
176
|
if (formRef) {
|
|
206
177
|
formRef.dispatchEvent(submitErrorEvent);
|
|
207
|
-
|
|
208
178
|
if (submitErrorEvent.defaultPrevented) {
|
|
209
179
|
return;
|
|
210
180
|
}
|
|
211
181
|
}
|
|
212
|
-
|
|
213
182
|
setResponseData(err);
|
|
214
183
|
setFormState("error");
|
|
215
184
|
});
|
|
216
185
|
}
|
|
217
186
|
}
|
|
218
|
-
|
|
219
187
|
let formRef;
|
|
220
188
|
const builderContext = useContext(BuilderContext);
|
|
221
|
-
return <form
|
|
189
|
+
return <form validate={props.validate} ref={formRef} action={!props.sendWithJs && props.action} method={props.method} name={props.name} onSubmit={event => onSubmit(event)} {...props.attributes}>
|
|
222
190
|
<Show when={props.builderBlock && props.builderBlock.children}>
|
|
223
191
|
<For each={props.builderBlock?.children}>
|
|
224
192
|
{(block, _index) => {
|
|
225
193
|
const index = _index();
|
|
226
|
-
|
|
227
194
|
return <RenderBlock block={block} context={builderContext}></RenderBlock>;
|
|
228
195
|
}}
|
|
229
196
|
</For>
|
|
@@ -248,5 +215,4 @@ function FormComponent(props) {
|
|
|
248
215
|
</Show>
|
|
249
216
|
</form>;
|
|
250
217
|
}
|
|
251
|
-
|
|
252
218
|
export default FormComponent;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { serializeFn } from "../util.js";
|
|
2
2
|
const componentInfo = {
|
|
3
3
|
name: "Image",
|
|
4
4
|
static: true,
|
|
@@ -19,7 +19,7 @@ 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:
|
|
22
|
+
onChange: serializeFn((options) => {
|
|
23
23
|
const DEFAULT_ASPECT_RATIO = 0.7041;
|
|
24
24
|
options.delete("srcset");
|
|
25
25
|
options.delete("noWebp");
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { Show } from "solid-js";
|
|
2
2
|
import { css } from "solid-styled-components";
|
|
3
3
|
import { getSrcSet } from "./image.helpers.js";
|
|
4
|
-
|
|
5
4
|
function Image(props) {
|
|
6
5
|
function srcSetToUse() {
|
|
7
6
|
const imageToUse = props.image || props.src;
|
|
8
7
|
const url = imageToUse;
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
if (!url ||
|
|
9
|
+
// We can auto add srcset for cdn.builder.io and shopify
|
|
11
10
|
// images, otherwise you can supply this prop manually
|
|
12
11
|
!(url.match(/builder\.io/) || url.match(/cdn\.shopify\.com/))) {
|
|
13
12
|
return props.srcset;
|
|
14
13
|
}
|
|
15
|
-
|
|
16
14
|
if (props.srcset && props.image?.includes("builder.io/api/v1/image")) {
|
|
17
15
|
if (!props.srcset.includes(props.image.split("?")[0])) {
|
|
18
16
|
console.debug("Removed given srcset");
|
|
@@ -21,10 +19,8 @@ function Image(props) {
|
|
|
21
19
|
} else if (props.image && !props.srcset) {
|
|
22
20
|
return getSrcSet(url);
|
|
23
21
|
}
|
|
24
|
-
|
|
25
22
|
return getSrcSet(url);
|
|
26
23
|
}
|
|
27
|
-
|
|
28
24
|
function webpSrcSet() {
|
|
29
25
|
if (srcSetToUse()?.match(/builder\.io/) && !props.noWebp) {
|
|
30
26
|
return srcSetToUse().replace(/\?/g, "?format=webp&");
|
|
@@ -32,7 +28,6 @@ function Image(props) {
|
|
|
32
28
|
return "";
|
|
33
29
|
}
|
|
34
30
|
}
|
|
35
|
-
|
|
36
31
|
return <>
|
|
37
32
|
<picture>
|
|
38
33
|
<Show when={webpSrcSet()}>
|
|
@@ -58,7 +53,8 @@ function Image(props) {
|
|
|
58
53
|
pointerEvents: "none",
|
|
59
54
|
fontSize: "0"
|
|
60
55
|
})} style={{
|
|
61
|
-
"padding-top":
|
|
56
|
+
"padding-top":
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
62
58
|
props.aspectRatio * 100 + "%"
|
|
63
59
|
}}></div>
|
|
64
60
|
</Show>
|
|
@@ -81,5 +77,4 @@ function Image(props) {
|
|
|
81
77
|
</Show>
|
|
82
78
|
</>;
|
|
83
79
|
}
|
|
84
|
-
|
|
85
80
|
export default Image;
|
package/src/blocks/img/img.jsx
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { isEditing } from "../../functions/is-editing.js";
|
|
2
|
-
|
|
3
2
|
function ImgComponent(props) {
|
|
4
|
-
return <img
|
|
3
|
+
return <img style={{
|
|
5
4
|
"object-fit": props.backgroundSize || "cover",
|
|
6
5
|
"object-position": props.backgroundPosition || "center"
|
|
7
|
-
}} key={isEditing() && props.imgSrc || "default-key"} alt={props.altText} src={props.imgSrc || props.image} />;
|
|
6
|
+
}} key={isEditing() && props.imgSrc || "default-key"} alt={props.altText} src={props.imgSrc || props.image} {...props.attributes} />;
|
|
8
7
|
}
|
|
9
|
-
|
|
10
8
|
export default ImgComponent;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { isEditing } from "../../functions/is-editing.js";
|
|
2
|
-
|
|
3
2
|
function FormInputComponent(props) {
|
|
4
3
|
return <input {...props.attributes} key={isEditing() && props.defaultValue ? props.defaultValue : "default-key"} placeholder={props.placeholder} type={props.type} name={props.name} value={props.value} defaultValue={props.defaultValue} required={props.required} />;
|
|
5
4
|
}
|
|
6
|
-
|
|
7
5
|
export default FormInputComponent;
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { For } from "solid-js";
|
|
2
2
|
import { isEditing } from "../../functions/is-editing.js";
|
|
3
|
-
|
|
4
3
|
function SelectComponent(props) {
|
|
5
4
|
return <select {...props.attributes} value={props.value} key={isEditing() && props.defaultValue ? props.defaultValue : "default-key"} defaultValue={props.defaultValue} name={props.name}>
|
|
6
5
|
<For each={props.options}>
|
|
7
6
|
{(option, _index) => {
|
|
8
7
|
const index = _index();
|
|
9
|
-
|
|
10
8
|
return <option value={option.value}>{option.name || option.value}</option>;
|
|
11
9
|
}}
|
|
12
10
|
</For>
|
|
13
11
|
</select>;
|
|
14
12
|
}
|
|
15
|
-
|
|
16
13
|
export default SelectComponent;
|
|
@@ -2,20 +2,16 @@ import { useContext, on, createEffect, createSignal } from "solid-js";
|
|
|
2
2
|
import RenderContent from "../../components/render-content/render-content.jsx";
|
|
3
3
|
import BuilderContext from "../../context/builder.context.js";
|
|
4
4
|
import { getContent } from "../../functions/get-content/index.js";
|
|
5
|
-
import { markMutable } from "../../functions/mark-mutable";
|
|
6
|
-
|
|
7
5
|
function Symbol(props) {
|
|
8
6
|
const [className, setClassName] = createSignal("builder-symbol");
|
|
9
7
|
const [fetchedContent, setFetchedContent] = createSignal(null);
|
|
10
|
-
|
|
11
8
|
function contentToUse() {
|
|
12
9
|
return props.symbol?.content || fetchedContent();
|
|
13
10
|
}
|
|
14
|
-
|
|
15
11
|
const builderContext = useContext(BuilderContext);
|
|
16
|
-
|
|
17
12
|
function onUpdateFn_0() {
|
|
18
13
|
const symbolToUse = props.symbol;
|
|
14
|
+
|
|
19
15
|
/**
|
|
20
16
|
* If:
|
|
21
17
|
* - we have a symbol prop
|
|
@@ -25,7 +21,6 @@ function Symbol(props) {
|
|
|
25
21
|
*
|
|
26
22
|
* then we want to re-fetch the symbol content.
|
|
27
23
|
*/
|
|
28
|
-
|
|
29
24
|
if (symbolToUse && !symbolToUse.content && !fetchedContent() && symbolToUse.model) {
|
|
30
25
|
getContent({
|
|
31
26
|
model: symbolToUse.model,
|
|
@@ -38,16 +33,15 @@ function Symbol(props) {
|
|
|
38
33
|
});
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
|
-
|
|
42
36
|
createEffect(on(() => [props.symbol, fetchedContent()], onUpdateFn_0));
|
|
43
37
|
return <div class={className()} {...props.attributes} dataSet={{
|
|
44
38
|
class: className()
|
|
45
39
|
}}>
|
|
46
|
-
<RenderContent apiKey={builderContext.apiKey} context={builderContext.context} customComponents={
|
|
40
|
+
<RenderContent apiKey={builderContext.apiKey} context={builderContext.context} customComponents={Object.values(builderContext.registeredComponents)} data={{
|
|
41
|
+
...props.symbol?.data,
|
|
47
42
|
...builderContext.state,
|
|
48
43
|
...props.symbol?.content?.data?.state
|
|
49
|
-
}
|
|
44
|
+
}} model={props.symbol?.model} content={contentToUse()}></RenderContent>
|
|
50
45
|
</div>;
|
|
51
46
|
}
|
|
52
|
-
|
|
53
47
|
export default Symbol;
|
package/src/blocks/text/text.jsx
CHANGED
package/src/blocks/util.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
const serializeFn = (fnValue) => {
|
|
2
|
+
const fnStr = fnValue.toString().trim();
|
|
3
|
+
const appendFunction = !fnStr.startsWith("function") && !fnStr.startsWith("(");
|
|
4
|
+
return `return (${appendFunction ? "function " : ""}${fnStr}).apply(this, arguments)`;
|
|
5
|
+
};
|
|
5
6
|
export {
|
|
6
|
-
|
|
7
|
+
serializeFn
|
|
7
8
|
};
|