@saltcorn/builder 1.6.0-alpha.1 → 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 +85 -1
- package/dist/builder_bundle.js.LICENSE.txt +18 -51
- package/package.json +31 -27
- package/src/components/Builder.js +445 -155
- package/src/components/Library.js +25 -13
- package/src/components/RenderNode.js +26 -8
- package/src/components/Toolbox.js +333 -269
- package/src/components/elements/Action.js +144 -29
- package/src/components/elements/Aggregation.js +20 -23
- package/src/components/elements/ArrayManager.js +17 -10
- package/src/components/elements/BoxModelEditor.js +19 -17
- package/src/components/elements/Card.js +47 -34
- package/src/components/elements/Clone.js +74 -2
- package/src/components/elements/Column.js +1 -1
- package/src/components/elements/Columns.js +130 -121
- package/src/components/elements/Container.js +185 -92
- package/src/components/elements/DropDownFilter.js +10 -8
- package/src/components/elements/DropMenu.js +18 -9
- package/src/components/elements/Field.js +9 -7
- package/src/components/elements/HTMLCode.js +3 -1
- package/src/components/elements/Image.js +20 -15
- package/src/components/elements/JoinField.js +15 -11
- package/src/components/elements/Link.js +18 -16
- package/src/components/elements/ListColumn.js +7 -3
- package/src/components/elements/ListColumns.js +4 -1
- package/src/components/elements/MonacoEditor.js +4 -2
- package/src/components/elements/Page.js +7 -4
- package/src/components/elements/RelationBadges.js +16 -11
- package/src/components/elements/RelationOnDemandPicker.js +18 -12
- package/src/components/elements/SearchBar.js +37 -10
- package/src/components/elements/Table.js +72 -65
- package/src/components/elements/Tabs.js +18 -15
- package/src/components/elements/Text.js +19 -14
- package/src/components/elements/ToggleFilter.js +28 -25
- package/src/components/elements/View.js +36 -18
- package/src/components/elements/ViewLink.js +15 -11
- package/src/components/elements/utils.js +224 -55
- package/src/components/storage.js +33 -134
- package/src/hooks/useTranslation.js +11 -0
- package/src/index.js +6 -3
|
@@ -4,13 +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
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
10
|
+
import PreviewCtx from "../preview_context";
|
|
9
11
|
|
|
10
12
|
import { Element, useNode } from "@craftjs/core";
|
|
11
13
|
import {
|
|
12
14
|
Accordion,
|
|
13
|
-
ConfigField,
|
|
14
15
|
SettingsRow,
|
|
15
16
|
reactifyStyles,
|
|
16
17
|
SettingsSectionHeaderRow,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
parseStyles,
|
|
19
20
|
} from "./utils";
|
|
20
21
|
import { BoxModelEditor } from "./BoxModelEditor";
|
|
22
|
+
import { ArrayManager } from "./ArrayManager";
|
|
21
23
|
import {
|
|
22
24
|
AlignTop,
|
|
23
25
|
AlignMiddle,
|
|
@@ -65,6 +67,35 @@ const resetWidths = (ncols) => ntimes(ncols - 1, () => Math.floor(12 / ncols));
|
|
|
65
67
|
const getWidth = (widths, colix) =>
|
|
66
68
|
colix < widths.length ? widths[colix] : 12 - sum(widths);
|
|
67
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
|
+
|
|
68
99
|
export /**
|
|
69
100
|
* @param {object} opts
|
|
70
101
|
* @param {number[]} opts.widths
|
|
@@ -87,11 +118,13 @@ const Columns = ({
|
|
|
87
118
|
colClasses,
|
|
88
119
|
colStyles,
|
|
89
120
|
customClass,
|
|
121
|
+
breakpoints,
|
|
90
122
|
}) => {
|
|
91
123
|
const {
|
|
92
124
|
selected,
|
|
93
125
|
connectors: { connect, drag },
|
|
94
126
|
} = useNode((node) => ({ selected: node.events.selected }));
|
|
127
|
+
const { previewDevice } = useContext(PreviewCtx);
|
|
95
128
|
return (
|
|
96
129
|
<div
|
|
97
130
|
className={`row builder-columns ${customClass || ""} ${selected ? "selected-node" : ""} ${
|
|
@@ -103,7 +136,11 @@ const Columns = ({
|
|
|
103
136
|
{ntimes(ncols, (ix) => (
|
|
104
137
|
<div
|
|
105
138
|
key={ix}
|
|
106
|
-
className={`split-col
|
|
139
|
+
className={`split-col ${getColClass(
|
|
140
|
+
getWidth(widths, ix),
|
|
141
|
+
breakpoints?.[ix],
|
|
142
|
+
previewDevice
|
|
143
|
+
)} text-${
|
|
107
144
|
aligns?.[ix]
|
|
108
145
|
} align-items-${vAligns?.[ix]} ${colClasses?.[ix] || ""}`}
|
|
109
146
|
style={parseStyles(colStyles?.[ix] || "")}
|
|
@@ -124,6 +161,7 @@ export /**
|
|
|
124
161
|
* @subcategory components
|
|
125
162
|
*/
|
|
126
163
|
const ColumnsSettings = () => {
|
|
164
|
+
const { t } = useTranslation();
|
|
127
165
|
const node = useNode((node) => ({
|
|
128
166
|
widths: node.data.props.widths,
|
|
129
167
|
ncols: node.data.props.ncols,
|
|
@@ -154,122 +192,93 @@ const ColumnsSettings = () => {
|
|
|
154
192
|
currentSettingsTab,
|
|
155
193
|
} = node;
|
|
156
194
|
const colSetsNode = {
|
|
157
|
-
vAlign: vAligns?.[setting_col_n
|
|
158
|
-
hAlign: aligns?.[setting_col_n
|
|
159
|
-
colClass: colClasses?.[setting_col_n
|
|
160
|
-
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] || "",
|
|
161
199
|
};
|
|
162
200
|
return (
|
|
163
201
|
<Accordion
|
|
164
202
|
value={currentSettingsTab}
|
|
165
203
|
onChange={(ix) => setProp((prop) => (prop.currentSettingsTab = ix))}
|
|
166
204
|
>
|
|
167
|
-
<
|
|
168
|
-
<
|
|
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
|
-
<td align="right">
|
|
205
|
-
{ix < ncols - 1 ? (
|
|
206
|
-
<input
|
|
207
|
-
type="number"
|
|
208
|
-
value={widths[ix]}
|
|
209
|
-
className="form-control"
|
|
210
|
-
step="1"
|
|
211
|
-
min="1"
|
|
212
|
-
max={12 - (sum(widths) - widths[ix]) - 1}
|
|
213
|
-
onChange={(e) => {
|
|
214
|
-
if (!e.target) return;
|
|
215
|
-
const value = e.target.value;
|
|
216
|
-
setProp((prop) => (prop.widths[ix] = +value));
|
|
217
|
-
}}
|
|
218
|
-
/>
|
|
219
|
-
) : (
|
|
220
|
-
`${12 - sum(widths)}`
|
|
221
|
-
)}
|
|
222
|
-
</td>
|
|
223
|
-
<td>/12</td>
|
|
224
|
-
<td>
|
|
225
|
-
<select
|
|
226
|
-
className="form-control form-select"
|
|
227
|
-
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}
|
|
228
242
|
onChange={(e) => {
|
|
229
243
|
if (!e.target) return;
|
|
230
244
|
const value = e.target.value;
|
|
231
|
-
setProp((prop) => (prop.
|
|
245
|
+
setProp((prop) => (prop.widths[setting_col_n] = +value));
|
|
232
246
|
}}
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
props={node}
|
|
260
|
-
></ConfigField>
|
|
261
|
-
<table className="w-100">
|
|
262
|
-
<tbody>
|
|
263
|
-
<SettingsSectionHeaderRow title="Align" />
|
|
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>
|
|
272
|
+
<SettingsSectionHeaderRow title={t("Align")} />
|
|
264
273
|
<SettingsRow
|
|
265
274
|
field={{
|
|
266
275
|
name: "vAlign",
|
|
267
|
-
label: "Vertical",
|
|
276
|
+
label: t("Vertical"),
|
|
268
277
|
type: "btn_select",
|
|
269
278
|
options: [
|
|
270
|
-
{ value: "start", title: "Start", label: <AlignTop /> },
|
|
271
|
-
{ value: "center", title: "Center", label: <AlignMiddle /> },
|
|
272
|
-
{ value: "end", title: "End", label: <AlignBottom /> },
|
|
279
|
+
{ value: "start", title: t("Start"), label: <AlignTop /> },
|
|
280
|
+
{ value: "center", title: t("Center"), label: <AlignMiddle /> },
|
|
281
|
+
{ value: "end", title: t("End"), label: <AlignBottom /> },
|
|
273
282
|
],
|
|
274
283
|
}}
|
|
275
284
|
node={colSetsNode}
|
|
@@ -277,19 +286,19 @@ const ColumnsSettings = () => {
|
|
|
277
286
|
onChange={(k, v) =>
|
|
278
287
|
setProp((prop) => {
|
|
279
288
|
if (!prop.vAligns) prop.vAligns = [];
|
|
280
|
-
|
|
289
|
+
prop.vAligns[setting_col_n] = v;
|
|
281
290
|
})
|
|
282
291
|
}
|
|
283
292
|
/>
|
|
284
293
|
<SettingsRow
|
|
285
294
|
field={{
|
|
286
295
|
name: "hAlign",
|
|
287
|
-
label: "Horizontal",
|
|
296
|
+
label: t("Horizontal"),
|
|
288
297
|
type: "btn_select",
|
|
289
298
|
options: [
|
|
290
|
-
{ value: "start", title: "Left", label: <AlignStart /> },
|
|
291
|
-
{ value: "center", title: "Center", label: <AlignCenter /> },
|
|
292
|
-
{ value: "end", title: "Right", label: <AlignEnd /> },
|
|
299
|
+
{ value: "start", title: t("Left"), label: <AlignStart /> },
|
|
300
|
+
{ value: "center", title: t("Center"), label: <AlignCenter /> },
|
|
301
|
+
{ value: "end", title: t("Right"), label: <AlignEnd /> },
|
|
293
302
|
],
|
|
294
303
|
}}
|
|
295
304
|
node={colSetsNode}
|
|
@@ -297,14 +306,14 @@ const ColumnsSettings = () => {
|
|
|
297
306
|
onChange={(k, v) =>
|
|
298
307
|
setProp((prop) => {
|
|
299
308
|
if (!prop.aligns) prop.aligns = [];
|
|
300
|
-
|
|
309
|
+
prop.aligns[setting_col_n] = v;
|
|
301
310
|
})
|
|
302
311
|
}
|
|
303
312
|
/>
|
|
304
313
|
<SettingsRow
|
|
305
314
|
field={{
|
|
306
315
|
name: "colClass",
|
|
307
|
-
label: "Class",
|
|
316
|
+
label: t("Class"),
|
|
308
317
|
type: "String",
|
|
309
318
|
}}
|
|
310
319
|
node={colSetsNode}
|
|
@@ -312,34 +321,34 @@ const ColumnsSettings = () => {
|
|
|
312
321
|
onChange={(k, v) =>
|
|
313
322
|
setProp((prop) => {
|
|
314
323
|
if (!prop.colClasses) prop.colClasses = [];
|
|
315
|
-
|
|
324
|
+
prop.colClasses[setting_col_n] = v;
|
|
316
325
|
})
|
|
317
326
|
}
|
|
318
327
|
/>
|
|
319
328
|
<SettingsRow
|
|
320
329
|
field={{
|
|
321
330
|
name: "colStyle",
|
|
322
|
-
label: "CSS",
|
|
323
|
-
type: "
|
|
331
|
+
label: t("CSS"),
|
|
332
|
+
type: "String",
|
|
324
333
|
}}
|
|
325
334
|
node={colSetsNode}
|
|
326
335
|
setProp={setProp}
|
|
327
336
|
onChange={(k, v) =>
|
|
328
337
|
setProp((prop) => {
|
|
329
338
|
if (!prop.colStyles) prop.colStyles = [];
|
|
330
|
-
prop.colStyles[setting_col_n
|
|
339
|
+
prop.colStyles[setting_col_n] = v;
|
|
331
340
|
})
|
|
332
341
|
}
|
|
333
342
|
/>
|
|
334
343
|
</tbody>
|
|
335
344
|
</table>
|
|
336
345
|
</div>
|
|
337
|
-
<table className="w-100" accordiontitle="Gutters and class">
|
|
346
|
+
<table className="w-100" accordiontitle={t("Gutters and class")}>
|
|
338
347
|
<tbody>
|
|
339
348
|
<SettingsRow
|
|
340
349
|
field={{
|
|
341
350
|
name: "gx",
|
|
342
|
-
label: "Horizontal 0-5",
|
|
351
|
+
label: t("Horizontal 0-5"),
|
|
343
352
|
type: "Integer",
|
|
344
353
|
}}
|
|
345
354
|
node={node}
|
|
@@ -348,7 +357,7 @@ const ColumnsSettings = () => {
|
|
|
348
357
|
<SettingsRow
|
|
349
358
|
field={{
|
|
350
359
|
name: "gy",
|
|
351
|
-
label: "Vertical 0-5",
|
|
360
|
+
label: t("Vertical 0-5"),
|
|
352
361
|
type: "Integer",
|
|
353
362
|
}}
|
|
354
363
|
node={node}
|
|
@@ -357,7 +366,7 @@ const ColumnsSettings = () => {
|
|
|
357
366
|
<SettingsRow
|
|
358
367
|
field={{
|
|
359
368
|
name: "customClass",
|
|
360
|
-
label: "Custom class",
|
|
369
|
+
label: t("Custom class"),
|
|
361
370
|
type: "String",
|
|
362
371
|
}}
|
|
363
372
|
node={node}
|
|
@@ -365,7 +374,7 @@ const ColumnsSettings = () => {
|
|
|
365
374
|
/>
|
|
366
375
|
</tbody>
|
|
367
376
|
</table>
|
|
368
|
-
<div accordiontitle="Box" className="w-100">
|
|
377
|
+
<div accordiontitle={t("Box")} className="w-100">
|
|
369
378
|
<BoxModelEditor setProp={setProp} node={node} sizeWithStyle={true} />
|
|
370
379
|
</div>
|
|
371
380
|
</Accordion>
|
|
@@ -382,7 +391,7 @@ Columns.craft = {
|
|
|
382
391
|
ncols: 2,
|
|
383
392
|
style: {},
|
|
384
393
|
breakpoints: ["sm", "sm"],
|
|
385
|
-
setting_col_n:
|
|
394
|
+
setting_col_n: 0,
|
|
386
395
|
customClass: "",
|
|
387
396
|
},
|
|
388
397
|
related: {
|