@saltcorn/builder 1.6.0-alpha.10 → 1.6.0-alpha.11
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/dist/builder_bundle.js +86 -4126
- package/package.json +2 -2
- package/src/components/Builder.js +126 -48
- package/src/components/RenderNode.js +8 -1
- package/src/components/elements/ArrayManager.js +10 -5
- package/src/components/elements/Columns.js +112 -105
- package/src/components/elements/Container.js +16 -3
- package/src/components/storage.js +6 -5
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
* @subcategory components / elements
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React, { Fragment } from "react";
|
|
7
|
+
import React, { Fragment, useContext } from "react";
|
|
8
8
|
import { Column } from "./Column";
|
|
9
9
|
import useTranslation from "../../hooks/useTranslation";
|
|
10
|
+
import PreviewCtx from "../preview_context";
|
|
10
11
|
|
|
11
12
|
import { Element, useNode } from "@craftjs/core";
|
|
12
13
|
import {
|
|
13
14
|
Accordion,
|
|
14
|
-
ConfigField,
|
|
15
15
|
SettingsRow,
|
|
16
16
|
reactifyStyles,
|
|
17
17
|
SettingsSectionHeaderRow,
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
parseStyles,
|
|
20
20
|
} from "./utils";
|
|
21
21
|
import { BoxModelEditor } from "./BoxModelEditor";
|
|
22
|
+
import { ArrayManager } from "./ArrayManager";
|
|
22
23
|
import {
|
|
23
24
|
AlignTop,
|
|
24
25
|
AlignMiddle,
|
|
@@ -66,6 +67,35 @@ const resetWidths = (ncols) => ntimes(ncols - 1, () => Math.floor(12 / ncols));
|
|
|
66
67
|
const getWidth = (widths, colix) =>
|
|
67
68
|
colix < widths.length ? widths[colix] : 12 - sum(widths);
|
|
68
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Bootstrap breakpoint minimum widths (px)
|
|
72
|
+
*/
|
|
73
|
+
const BREAKPOINT_MIN_WIDTH = {
|
|
74
|
+
"": 0,
|
|
75
|
+
sm: 576,
|
|
76
|
+
md: 768,
|
|
77
|
+
lg: 992,
|
|
78
|
+
xl: 1200,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const PREVIEW_DEVICE_WIDTH = {
|
|
82
|
+
desktop: Infinity,
|
|
83
|
+
tablet: 768,
|
|
84
|
+
mobile: 375,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const getColClass = (width, breakpoint, previewDevice) => {
|
|
88
|
+
if (!previewDevice || previewDevice === "desktop") {
|
|
89
|
+
const bp = breakpoint || "sm";
|
|
90
|
+
return bp ? `col-${bp}-${width}` : `col-${width}`;
|
|
91
|
+
}
|
|
92
|
+
const deviceWidth = PREVIEW_DEVICE_WIDTH[previewDevice] || Infinity;
|
|
93
|
+
const bpMin = BREAKPOINT_MIN_WIDTH[breakpoint || "sm"] || 0;
|
|
94
|
+
if (deviceWidth < bpMin) return "col-12";
|
|
95
|
+
const bp = breakpoint || "sm";
|
|
96
|
+
return bp ? `col-${bp}-${width}` : `col-${width}`;
|
|
97
|
+
};
|
|
98
|
+
|
|
69
99
|
export /**
|
|
70
100
|
* @param {object} opts
|
|
71
101
|
* @param {number[]} opts.widths
|
|
@@ -88,11 +118,13 @@ const Columns = ({
|
|
|
88
118
|
colClasses,
|
|
89
119
|
colStyles,
|
|
90
120
|
customClass,
|
|
121
|
+
breakpoints,
|
|
91
122
|
}) => {
|
|
92
123
|
const {
|
|
93
124
|
selected,
|
|
94
125
|
connectors: { connect, drag },
|
|
95
126
|
} = useNode((node) => ({ selected: node.events.selected }));
|
|
127
|
+
const { previewDevice } = useContext(PreviewCtx);
|
|
96
128
|
return (
|
|
97
129
|
<div
|
|
98
130
|
className={`row builder-columns ${customClass || ""} ${selected ? "selected-node" : ""} ${
|
|
@@ -104,7 +136,11 @@ const Columns = ({
|
|
|
104
136
|
{ntimes(ncols, (ix) => (
|
|
105
137
|
<div
|
|
106
138
|
key={ix}
|
|
107
|
-
className={`split-col
|
|
139
|
+
className={`split-col ${getColClass(
|
|
140
|
+
getWidth(widths, ix),
|
|
141
|
+
breakpoints?.[ix],
|
|
142
|
+
previewDevice
|
|
143
|
+
)} text-${
|
|
108
144
|
aligns?.[ix]
|
|
109
145
|
} align-items-${vAligns?.[ix]} ${colClasses?.[ix] || ""}`}
|
|
110
146
|
style={parseStyles(colStyles?.[ix] || "")}
|
|
@@ -156,112 +192,83 @@ const ColumnsSettings = () => {
|
|
|
156
192
|
currentSettingsTab,
|
|
157
193
|
} = node;
|
|
158
194
|
const colSetsNode = {
|
|
159
|
-
vAlign: vAligns?.[setting_col_n
|
|
160
|
-
hAlign: aligns?.[setting_col_n
|
|
161
|
-
colClass: colClasses?.[setting_col_n
|
|
162
|
-
colStyle: colStyles?.[setting_col_n
|
|
195
|
+
vAlign: vAligns?.[setting_col_n],
|
|
196
|
+
hAlign: aligns?.[setting_col_n],
|
|
197
|
+
colClass: colClasses?.[setting_col_n] || "",
|
|
198
|
+
colStyle: colStyles?.[setting_col_n] || "",
|
|
163
199
|
};
|
|
164
200
|
return (
|
|
165
201
|
<Accordion
|
|
166
202
|
value={currentSettingsTab}
|
|
167
203
|
onChange={(ix) => setProp((prop) => (prop.currentSettingsTab = ix))}
|
|
168
204
|
>
|
|
169
|
-
<
|
|
170
|
-
<
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
</
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
<td align="right">
|
|
207
|
-
{ix < ncols - 1 ? (
|
|
208
|
-
<input
|
|
209
|
-
type="number"
|
|
210
|
-
value={widths[ix]}
|
|
211
|
-
className="form-control"
|
|
212
|
-
step="1"
|
|
213
|
-
min="1"
|
|
214
|
-
max={12 - (sum(widths) - widths[ix]) - 1}
|
|
215
|
-
onChange={(e) => {
|
|
216
|
-
if (!e.target) return;
|
|
217
|
-
const value = e.target.value;
|
|
218
|
-
setProp((prop) => (prop.widths[ix] = +value));
|
|
219
|
-
}}
|
|
220
|
-
/>
|
|
221
|
-
) : (
|
|
222
|
-
`${12 - sum(widths)}`
|
|
223
|
-
)}
|
|
224
|
-
</td>
|
|
225
|
-
<td>/12</td>
|
|
226
|
-
<td>
|
|
227
|
-
<select
|
|
228
|
-
className="form-control form-select"
|
|
229
|
-
value={breakpoints[ix]}
|
|
205
|
+
<div accordiontitle={t("Column properties")}>
|
|
206
|
+
<ArrayManager
|
|
207
|
+
node={node}
|
|
208
|
+
setProp={setProp}
|
|
209
|
+
countProp={"ncols"}
|
|
210
|
+
currentProp={"setting_col_n"}
|
|
211
|
+
managedArrays={["widths", "breakpoints", "aligns", "vAligns", "colClasses", "colStyles"]}
|
|
212
|
+
manageContents={true}
|
|
213
|
+
contentsKey={"besides"}
|
|
214
|
+
initialAddProps={{
|
|
215
|
+
breakpoints: "sm",
|
|
216
|
+
}}
|
|
217
|
+
onLayoutChange={(layout, action) => {
|
|
218
|
+
if (action === "add" || action === "delete") {
|
|
219
|
+
const n = layout.besides.length;
|
|
220
|
+
layout.widths = ntimes(n, () => Math.floor(12 / n));
|
|
221
|
+
}
|
|
222
|
+
}}
|
|
223
|
+
/>
|
|
224
|
+
<table className="w-100 mt-2">
|
|
225
|
+
<tbody>
|
|
226
|
+
<tr>
|
|
227
|
+
<th colSpan="4">{t("Width & Breakpoint")}</th>
|
|
228
|
+
</tr>
|
|
229
|
+
<tr>
|
|
230
|
+
<td>
|
|
231
|
+
<label>{t("Width")}</label>
|
|
232
|
+
</td>
|
|
233
|
+
<td colSpan="3" align="right">
|
|
234
|
+
{setting_col_n < ncols - 1 ? (
|
|
235
|
+
<input
|
|
236
|
+
type="number"
|
|
237
|
+
value={widths[setting_col_n]}
|
|
238
|
+
className="form-control"
|
|
239
|
+
step="1"
|
|
240
|
+
min="1"
|
|
241
|
+
max={12 - (sum(widths) - widths[setting_col_n]) - 1}
|
|
230
242
|
onChange={(e) => {
|
|
231
243
|
if (!e.target) return;
|
|
232
244
|
const value = e.target.value;
|
|
233
|
-
setProp((prop) => (prop.
|
|
245
|
+
setProp((prop) => (prop.widths[setting_col_n] = +value));
|
|
234
246
|
}}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
setProp={setProp}
|
|
261
|
-
props={node}
|
|
262
|
-
></ConfigField>
|
|
263
|
-
<table className="w-100">
|
|
264
|
-
<tbody>
|
|
247
|
+
/>
|
|
248
|
+
) : (
|
|
249
|
+
`${12 - sum(widths)}`
|
|
250
|
+
)}
|
|
251
|
+
</td>
|
|
252
|
+
</tr>
|
|
253
|
+
<tr>
|
|
254
|
+
<td>
|
|
255
|
+
<label>{t("Breakpoint")}</label>
|
|
256
|
+
</td>
|
|
257
|
+
<td colSpan="3">
|
|
258
|
+
<select
|
|
259
|
+
className="form-control form-select"
|
|
260
|
+
value={breakpoints[setting_col_n]}
|
|
261
|
+
onChange={(e) => {
|
|
262
|
+
if (!e.target) return;
|
|
263
|
+
const value = e.target.value;
|
|
264
|
+
setProp((prop) => (prop.breakpoints[setting_col_n] = value));
|
|
265
|
+
}}
|
|
266
|
+
>
|
|
267
|
+
<option value="">{t("none")}</option>
|
|
268
|
+
{buildBootstrapOptions(["sm", "md", "lg"])}
|
|
269
|
+
</select>
|
|
270
|
+
</td>
|
|
271
|
+
</tr>
|
|
265
272
|
<SettingsSectionHeaderRow title={t("Align")} />
|
|
266
273
|
<SettingsRow
|
|
267
274
|
field={{
|
|
@@ -279,7 +286,7 @@ const ColumnsSettings = () => {
|
|
|
279
286
|
onChange={(k, v) =>
|
|
280
287
|
setProp((prop) => {
|
|
281
288
|
if (!prop.vAligns) prop.vAligns = [];
|
|
282
|
-
|
|
289
|
+
prop.vAligns[setting_col_n] = v;
|
|
283
290
|
})
|
|
284
291
|
}
|
|
285
292
|
/>
|
|
@@ -299,7 +306,7 @@ const ColumnsSettings = () => {
|
|
|
299
306
|
onChange={(k, v) =>
|
|
300
307
|
setProp((prop) => {
|
|
301
308
|
if (!prop.aligns) prop.aligns = [];
|
|
302
|
-
|
|
309
|
+
prop.aligns[setting_col_n] = v;
|
|
303
310
|
})
|
|
304
311
|
}
|
|
305
312
|
/>
|
|
@@ -314,7 +321,7 @@ const ColumnsSettings = () => {
|
|
|
314
321
|
onChange={(k, v) =>
|
|
315
322
|
setProp((prop) => {
|
|
316
323
|
if (!prop.colClasses) prop.colClasses = [];
|
|
317
|
-
|
|
324
|
+
prop.colClasses[setting_col_n] = v;
|
|
318
325
|
})
|
|
319
326
|
}
|
|
320
327
|
/>
|
|
@@ -322,14 +329,14 @@ const ColumnsSettings = () => {
|
|
|
322
329
|
field={{
|
|
323
330
|
name: "colStyle",
|
|
324
331
|
label: t("CSS"),
|
|
325
|
-
type: "
|
|
332
|
+
type: "String",
|
|
326
333
|
}}
|
|
327
334
|
node={colSetsNode}
|
|
328
335
|
setProp={setProp}
|
|
329
336
|
onChange={(k, v) =>
|
|
330
337
|
setProp((prop) => {
|
|
331
338
|
if (!prop.colStyles) prop.colStyles = [];
|
|
332
|
-
prop.colStyles[setting_col_n
|
|
339
|
+
prop.colStyles[setting_col_n] = v;
|
|
333
340
|
})
|
|
334
341
|
}
|
|
335
342
|
/>
|
|
@@ -384,7 +391,7 @@ Columns.craft = {
|
|
|
384
391
|
ncols: 2,
|
|
385
392
|
style: {},
|
|
386
393
|
breakpoints: ["sm", "sm"],
|
|
387
|
-
setting_col_n:
|
|
394
|
+
setting_col_n: 0,
|
|
388
395
|
customClass: "",
|
|
389
396
|
},
|
|
390
397
|
related: {
|
|
@@ -136,6 +136,19 @@ const Container = ({
|
|
|
136
136
|
selected,
|
|
137
137
|
connectors: { connect, drag },
|
|
138
138
|
} = useNode((node) => ({ selected: node.events.selected }));
|
|
139
|
+
const { previewDevice } = useContext(previewCtx);
|
|
140
|
+
|
|
141
|
+
const BP_MIN = { "": 0, sm: 576, md: 768, lg: 992, xl: 1200 };
|
|
142
|
+
const DEVICE_W = { desktop: Infinity, tablet: 768, mobile: 375 };
|
|
143
|
+
{
|
|
144
|
+
const dw = DEVICE_W[previewDevice] || Infinity;
|
|
145
|
+
if (minScreenWidth && dw < (BP_MIN[minScreenWidth] || 0)) {
|
|
146
|
+
return <div ref={(dom) => connect(drag(dom))} style={{ display: "none" }} />;
|
|
147
|
+
}
|
|
148
|
+
if (maxScreenWidth && dw >= (BP_MIN[maxScreenWidth] || Infinity)) {
|
|
149
|
+
return <div ref={(dom) => connect(drag(dom))} style={{ display: "none" }} />;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
139
152
|
|
|
140
153
|
const actualChildren = contents || children;
|
|
141
154
|
|
|
@@ -163,8 +176,6 @@ const Container = ({
|
|
|
163
176
|
...parseStyles(customCSS || ""),
|
|
164
177
|
...reactifyStyles(style, transform, rotate),
|
|
165
178
|
display,
|
|
166
|
-
//padding: padding.map((p) => p + "px").join(" "),
|
|
167
|
-
//margin: margin.map((p) => p + "px").join(" "),
|
|
168
179
|
minHeight: minHeight ? `${minHeight}${minHeightUnit || "px"}` : null,
|
|
169
180
|
...(bgType === "Image" && bgFileId
|
|
170
181
|
? {
|
|
@@ -208,7 +219,9 @@ const Container = ({
|
|
|
208
219
|
: {}),
|
|
209
220
|
},
|
|
210
221
|
},
|
|
211
|
-
|
|
222
|
+
<Element canvas id="container-canvas" is={Column}>
|
|
223
|
+
{renderChildren()}
|
|
224
|
+
</Element>
|
|
212
225
|
);
|
|
213
226
|
};
|
|
214
227
|
|
|
@@ -106,7 +106,7 @@ const layoutToNodes = (
|
|
|
106
106
|
* @returns {Element|Text|View|Action|Tabs|Columns}
|
|
107
107
|
*/
|
|
108
108
|
function toTag(segment, ix) {
|
|
109
|
-
if (!segment) return
|
|
109
|
+
if (!segment) return null;
|
|
110
110
|
|
|
111
111
|
if (
|
|
112
112
|
(segment.type === "card" || segment.type === "container") &&
|
|
@@ -318,7 +318,7 @@ const layoutToNodes = (
|
|
|
318
318
|
colClasses={segment.colClasses}
|
|
319
319
|
colStyles={segment.colStyles}
|
|
320
320
|
aligns={segment.aligns}
|
|
321
|
-
setting_col_n={
|
|
321
|
+
setting_col_n={segment.setting_col_n !== undefined ? segment.setting_col_n : 0}
|
|
322
322
|
contents={segment.besides.map(toTag)}
|
|
323
323
|
/>
|
|
324
324
|
);
|
|
@@ -354,7 +354,7 @@ const layoutToNodes = (
|
|
|
354
354
|
colClasses={segment.colClasses}
|
|
355
355
|
colStyles={segment.colStyles}
|
|
356
356
|
aligns={segment.aligns}
|
|
357
|
-
setting_col_n={
|
|
357
|
+
setting_col_n={segment.setting_col_n !== undefined ? segment.setting_col_n : 0}
|
|
358
358
|
contents={segment.besides.map(toTag)}
|
|
359
359
|
/>
|
|
360
360
|
)
|
|
@@ -522,14 +522,15 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
522
522
|
besides: widths.map((w, ix) => go(nodes[node.linkedNodes["Col" + ix]])),
|
|
523
523
|
breakpoints: node.props.breakpoints,
|
|
524
524
|
customClass: node.props.customClass,
|
|
525
|
-
gx: +node.props.gx,
|
|
526
|
-
gy: +node.props.gy,
|
|
525
|
+
gx: node.props.gx != null ? +node.props.gx : undefined,
|
|
526
|
+
gy: node.props.gy != null ? +node.props.gy : undefined,
|
|
527
527
|
aligns: node.props.aligns,
|
|
528
528
|
vAligns: node.props.vAligns,
|
|
529
529
|
colClasses: node.props.colClasses,
|
|
530
530
|
colStyles: node.props.colStyles,
|
|
531
531
|
style: node.props.style,
|
|
532
532
|
widths,
|
|
533
|
+
setting_col_n: node.props.setting_col_n,
|
|
533
534
|
...customProps,
|
|
534
535
|
};
|
|
535
536
|
}
|