@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
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React, { useContext, Fragment, useState } from "react";
|
|
8
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
8
9
|
import { SettingsRow, SettingsSectionHeaderRow, bstyleopt } from "./utils";
|
|
9
10
|
/*
|
|
10
11
|
Contains code from https://github.com/tpaksu/boxmodel
|
|
@@ -22,6 +23,7 @@ export /**
|
|
|
22
23
|
* @namespace
|
|
23
24
|
*/
|
|
24
25
|
const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
26
|
+
const { t } = useTranslation();
|
|
25
27
|
const [selectedCategory, setSelectedCategory] = useState(false);
|
|
26
28
|
const [selectedDirection, setSelectedDirection] = useState(false);
|
|
27
29
|
const selectedProperty = !selectedCategory
|
|
@@ -45,7 +47,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
45
47
|
className="boxmodel-text boxmodel-header"
|
|
46
48
|
onClick={() => setCatAndDir("margin", null)}
|
|
47
49
|
>
|
|
48
|
-
Margin
|
|
50
|
+
{t("Margin")}
|
|
49
51
|
</span>
|
|
50
52
|
<span
|
|
51
53
|
className="boxmodel-input-container boxmodel-input-direction-left"
|
|
@@ -74,7 +76,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
74
76
|
className="boxmodel-text boxmodel-header"
|
|
75
77
|
onClick={() => setCatAndDir("border", null)}
|
|
76
78
|
>
|
|
77
|
-
Border
|
|
79
|
+
{t("Border")}
|
|
78
80
|
</span>
|
|
79
81
|
<span
|
|
80
82
|
className="boxmodel-input-container boxmodel-input-direction-left"
|
|
@@ -109,7 +111,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
109
111
|
className="boxmodel-text boxmodel-header"
|
|
110
112
|
onClick={() => setCatAndDir("padding", null)}
|
|
111
113
|
>
|
|
112
|
-
Padding
|
|
114
|
+
{t("Padding")}
|
|
113
115
|
</span>
|
|
114
116
|
<span
|
|
115
117
|
className="boxmodel-input-container boxmodel-input-direction-left"
|
|
@@ -274,7 +276,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
274
276
|
<SettingsRow
|
|
275
277
|
field={{
|
|
276
278
|
name: "width",
|
|
277
|
-
label: "width",
|
|
279
|
+
label: t("width"),
|
|
278
280
|
type: "DimUnits",
|
|
279
281
|
horiz: true,
|
|
280
282
|
}}
|
|
@@ -285,7 +287,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
285
287
|
<SettingsRow
|
|
286
288
|
field={{
|
|
287
289
|
name: "min-width",
|
|
288
|
-
label: "min width",
|
|
290
|
+
label: t("min width"),
|
|
289
291
|
type: "DimUnits",
|
|
290
292
|
horiz: true,
|
|
291
293
|
}}
|
|
@@ -296,7 +298,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
296
298
|
<SettingsRow
|
|
297
299
|
field={{
|
|
298
300
|
name: "max-width",
|
|
299
|
-
label: "max width",
|
|
301
|
+
label: t("max width"),
|
|
300
302
|
type: "DimUnits",
|
|
301
303
|
horiz: true,
|
|
302
304
|
}}
|
|
@@ -305,7 +307,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
305
307
|
isStyle={true}
|
|
306
308
|
/>
|
|
307
309
|
<SettingsRow
|
|
308
|
-
field={{ name: "height", label: "height", type: "DimUnits" }}
|
|
310
|
+
field={{ name: "height", label: t("height"), type: "DimUnits" }}
|
|
309
311
|
node={node}
|
|
310
312
|
setProp={setProp}
|
|
311
313
|
isStyle={!!sizeWithStyle}
|
|
@@ -313,7 +315,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
313
315
|
<SettingsRow
|
|
314
316
|
field={{
|
|
315
317
|
name: sizeWithStyle ? "min-height" : "minHeight",
|
|
316
|
-
label: "min height",
|
|
318
|
+
label: t("min height"),
|
|
317
319
|
type: "DimUnits",
|
|
318
320
|
}}
|
|
319
321
|
node={node}
|
|
@@ -323,7 +325,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
323
325
|
<SettingsRow
|
|
324
326
|
field={{
|
|
325
327
|
name: "max-height",
|
|
326
|
-
label: "max height",
|
|
328
|
+
label: t("max height"),
|
|
327
329
|
type: "DimUnits",
|
|
328
330
|
}}
|
|
329
331
|
node={node}
|
|
@@ -338,7 +340,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
338
340
|
<SettingsRow
|
|
339
341
|
field={{
|
|
340
342
|
name: selectedProperty + "-width",
|
|
341
|
-
label: "width",
|
|
343
|
+
label: t("width"),
|
|
342
344
|
type: "DimUnits",
|
|
343
345
|
}}
|
|
344
346
|
node={node}
|
|
@@ -348,7 +350,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
348
350
|
<SettingsRow
|
|
349
351
|
field={{
|
|
350
352
|
name: selectedProperty + "-style",
|
|
351
|
-
label: "style",
|
|
353
|
+
label: t("style"),
|
|
352
354
|
type: "btn_select",
|
|
353
355
|
btnClass: "btnstylesel",
|
|
354
356
|
options: [
|
|
@@ -369,7 +371,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
369
371
|
<SettingsRow
|
|
370
372
|
field={{
|
|
371
373
|
name: selectedProperty + "-color",
|
|
372
|
-
label: "color",
|
|
374
|
+
label: t("color"),
|
|
373
375
|
type: "Color",
|
|
374
376
|
}}
|
|
375
377
|
node={node}
|
|
@@ -380,7 +382,7 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
380
382
|
<SettingsRow
|
|
381
383
|
field={{
|
|
382
384
|
name: selectedProperty + "-radius",
|
|
383
|
-
label: "radius",
|
|
385
|
+
label: t("radius"),
|
|
384
386
|
type: "DimUnits",
|
|
385
387
|
}}
|
|
386
388
|
node={node}
|
|
@@ -407,17 +409,17 @@ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
|
|
|
407
409
|
{!selectedProperty && (
|
|
408
410
|
<tr>
|
|
409
411
|
<td colSpan={2}>
|
|
410
|
-
<div>Click above to select a property to adjust
|
|
412
|
+
<div>{t("Click above to select a property to adjust.")}</div>
|
|
411
413
|
<div>
|
|
412
414
|
<small>
|
|
413
|
-
Click a label (margin, border, padding) to adjust all edges.
|
|
415
|
+
{t("Click a label (margin, border, padding) to adjust all edges.")}
|
|
414
416
|
</small>
|
|
415
417
|
</div>
|
|
416
418
|
<div>
|
|
417
|
-
<small>Click an edge to adjust that edge
|
|
419
|
+
<small>{t("Click an edge to adjust that edge.")}</small>
|
|
418
420
|
</div>
|
|
419
421
|
<div>
|
|
420
|
-
<small>Click center to adjust height and width</small>
|
|
422
|
+
<small>{t("Click center to adjust height and width")}</small>
|
|
421
423
|
</div>
|
|
422
424
|
</td>
|
|
423
425
|
</tr>
|
|
@@ -16,9 +16,10 @@ import {
|
|
|
16
16
|
buildOptions,
|
|
17
17
|
} from "./utils";
|
|
18
18
|
import { Column } from "./Column";
|
|
19
|
-
|
|
20
19
|
import { Element, useNode } from "@craftjs/core";
|
|
21
20
|
import { BoxModelEditor } from "./BoxModelEditor";
|
|
21
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
22
|
+
|
|
22
23
|
import {
|
|
23
24
|
AlignTop,
|
|
24
25
|
AlignMiddle,
|
|
@@ -40,7 +41,7 @@ import { bstyleopt } from "./utils";
|
|
|
40
41
|
|
|
41
42
|
export /**
|
|
42
43
|
* @param {object} props
|
|
43
|
-
* @param {string} props.
|
|
44
|
+
* @param {string} props.contents - Card body contents
|
|
44
45
|
* @param {object} props.isFormula
|
|
45
46
|
* @param {string} [props.title]
|
|
46
47
|
* @param {string} props.shadow
|
|
@@ -52,7 +53,7 @@ export /**
|
|
|
52
53
|
* @namespace
|
|
53
54
|
*/
|
|
54
55
|
const Card = ({
|
|
55
|
-
|
|
56
|
+
contents,
|
|
56
57
|
isFormula,
|
|
57
58
|
title,
|
|
58
59
|
shadow,
|
|
@@ -69,6 +70,7 @@ const Card = ({
|
|
|
69
70
|
gradStartColor,
|
|
70
71
|
gradEndColor,
|
|
71
72
|
gradDirection,
|
|
73
|
+
titleRight,
|
|
72
74
|
}) => {
|
|
73
75
|
const {
|
|
74
76
|
selected,
|
|
@@ -110,12 +112,17 @@ const Card = ({
|
|
|
110
112
|
<img src={`/files/serve/${bgFileId}`} className="card-img-top" />
|
|
111
113
|
) : null}
|
|
112
114
|
{title && title.length > 0 && (
|
|
113
|
-
<div className="card-header">
|
|
115
|
+
<div className="card-header right-section">
|
|
114
116
|
{isFormula?.title ? (
|
|
115
117
|
<span className="font-monospace">={title}</span>
|
|
116
118
|
) : (
|
|
117
119
|
title
|
|
118
120
|
)}
|
|
121
|
+
<div className='title-right'>
|
|
122
|
+
<Element canvas id="titleRight" is={Column}>
|
|
123
|
+
{titleRight}
|
|
124
|
+
</Element>
|
|
125
|
+
</div>
|
|
119
126
|
</div>
|
|
120
127
|
)}
|
|
121
128
|
<div
|
|
@@ -132,7 +139,9 @@ const Card = ({
|
|
|
132
139
|
: {}
|
|
133
140
|
}
|
|
134
141
|
>
|
|
135
|
-
<
|
|
142
|
+
<Element canvas id="cardbody" is={Column}>
|
|
143
|
+
{contents}
|
|
144
|
+
</Element>
|
|
136
145
|
</div>
|
|
137
146
|
{hasFooter ? (
|
|
138
147
|
<div className={`card-footer ${noPadding ? "p-0" : ""}`}>
|
|
@@ -152,6 +161,7 @@ export /**
|
|
|
152
161
|
* @namespace
|
|
153
162
|
*/
|
|
154
163
|
const CardSettings = () => {
|
|
164
|
+
const { t } = useTranslation();
|
|
155
165
|
const node = useNode((node) => {
|
|
156
166
|
const ps = {
|
|
157
167
|
currentSettingsTab: node.data.props.currentSettingsTab,
|
|
@@ -186,11 +196,11 @@ const CardSettings = () => {
|
|
|
186
196
|
value={currentSettingsTab}
|
|
187
197
|
onChange={(ix) => setProp((prop) => (prop.currentSettingsTab = ix))}
|
|
188
198
|
>
|
|
189
|
-
<table className="w-100" accordiontitle="Card properties">
|
|
199
|
+
<table className="w-100" accordiontitle={t("Card properties")}>
|
|
190
200
|
<tbody>
|
|
191
201
|
<SettingsRow
|
|
192
202
|
field={{
|
|
193
|
-
label: "Card title",
|
|
203
|
+
label: t("Card title"),
|
|
194
204
|
name: "title",
|
|
195
205
|
type: "String",
|
|
196
206
|
canBeFormula: true,
|
|
@@ -200,7 +210,7 @@ const CardSettings = () => {
|
|
|
200
210
|
/>
|
|
201
211
|
<SettingsRow
|
|
202
212
|
field={{
|
|
203
|
-
label: "Click URL",
|
|
213
|
+
label: t("Click URL"),
|
|
204
214
|
name: "url",
|
|
205
215
|
type: "String",
|
|
206
216
|
canBeFormula: true,
|
|
@@ -210,7 +220,7 @@ const CardSettings = () => {
|
|
|
210
220
|
/>
|
|
211
221
|
<SettingsRow
|
|
212
222
|
field={{
|
|
213
|
-
label: "Class",
|
|
223
|
+
label: t("Class"),
|
|
214
224
|
name: "class",
|
|
215
225
|
type: "String",
|
|
216
226
|
canBeFormula: true,
|
|
@@ -219,18 +229,18 @@ const CardSettings = () => {
|
|
|
219
229
|
setProp={setProp}
|
|
220
230
|
/>
|
|
221
231
|
<SettingsRow
|
|
222
|
-
field={{ label: "Card footer", name: "hasFooter", type: "Bool" }}
|
|
232
|
+
field={{ label: t("Card footer"), name: "hasFooter", type: "Bool" }}
|
|
223
233
|
node={node}
|
|
224
234
|
setProp={setProp}
|
|
225
235
|
/>
|
|
226
236
|
<SettingsRow
|
|
227
|
-
field={{ label: "Shadow", name: "shadow", type: "Bool" }}
|
|
237
|
+
field={{ label: t("Shadow"), name: "shadow", type: "Bool" }}
|
|
228
238
|
node={node}
|
|
229
239
|
setProp={setProp}
|
|
230
240
|
/>
|
|
231
241
|
<SettingsRow
|
|
232
242
|
field={{
|
|
233
|
-
label: "Save indicator",
|
|
243
|
+
label: t("Save indicator"),
|
|
234
244
|
name: "titleAjaxIndicator",
|
|
235
245
|
type: "Bool",
|
|
236
246
|
}}
|
|
@@ -238,37 +248,37 @@ const CardSettings = () => {
|
|
|
238
248
|
setProp={setProp}
|
|
239
249
|
/>
|
|
240
250
|
<SettingsRow
|
|
241
|
-
field={{ label: "No padding", name: "noPadding", type: "Bool" }}
|
|
251
|
+
field={{ label: t("No padding"), name: "noPadding", type: "Bool" }}
|
|
242
252
|
node={node}
|
|
243
253
|
setProp={setProp}
|
|
244
254
|
/>
|
|
245
255
|
</tbody>
|
|
246
256
|
</table>
|
|
247
|
-
<div accordiontitle="Box" className="w-100">
|
|
257
|
+
<div accordiontitle={t("Box")} className="w-100">
|
|
248
258
|
<BoxModelEditor setProp={setProp} node={node} sizeWithStyle={true} />
|
|
249
259
|
</div>
|
|
250
|
-
<table className="w-100" accordiontitle="Contents">
|
|
260
|
+
<table className="w-100" accordiontitle={t("Contents")}>
|
|
251
261
|
<tbody>
|
|
252
|
-
<SettingsSectionHeaderRow title="Align" />
|
|
262
|
+
<SettingsSectionHeaderRow title={t("Align")} />
|
|
253
263
|
<SettingsRow
|
|
254
264
|
field={{
|
|
255
265
|
name: "hAlign",
|
|
256
|
-
label: "Horizontal",
|
|
266
|
+
label: t("Horizontal"),
|
|
257
267
|
type: "btn_select",
|
|
258
268
|
options: [
|
|
259
|
-
{ value: "start", title: "Left", label: <AlignStart /> },
|
|
260
|
-
{ value: "center", title: "Center", label: <AlignCenter /> },
|
|
261
|
-
{ value: "end", title: "Right", label: <AlignEnd /> },
|
|
269
|
+
{ value: "start", title: t("Left"), label: <AlignStart /> },
|
|
270
|
+
{ value: "center", title: t("Center"), label: <AlignCenter /> },
|
|
271
|
+
{ value: "end", title: t("Right"), label: <AlignEnd /> },
|
|
262
272
|
],
|
|
263
273
|
}}
|
|
264
274
|
node={node}
|
|
265
275
|
setProp={setProp}
|
|
266
276
|
/>
|
|
267
|
-
<SettingsSectionHeaderRow title="Background" />
|
|
277
|
+
<SettingsSectionHeaderRow title={t("Background")} />
|
|
268
278
|
<SettingsRow
|
|
269
279
|
field={{
|
|
270
280
|
name: "bgType",
|
|
271
|
-
label: "Type",
|
|
281
|
+
label: t("Type"),
|
|
272
282
|
type: "btn_select",
|
|
273
283
|
options: [
|
|
274
284
|
{ value: "None", label: <SlashCircle /> },
|
|
@@ -294,7 +304,7 @@ const CardSettings = () => {
|
|
|
294
304
|
{bgType === "Gradient" && (
|
|
295
305
|
<Fragment>
|
|
296
306
|
<tr>
|
|
297
|
-
<td>Start</td>
|
|
307
|
+
<td>{t("Start")}</td>
|
|
298
308
|
<td>
|
|
299
309
|
<OrFormula
|
|
300
310
|
nodekey="gradStartColor"
|
|
@@ -310,7 +320,7 @@ const CardSettings = () => {
|
|
|
310
320
|
</td>
|
|
311
321
|
</tr>
|
|
312
322
|
<tr>
|
|
313
|
-
<td>End</td>
|
|
323
|
+
<td>{t("End")}</td>
|
|
314
324
|
<td>
|
|
315
325
|
<OrFormula
|
|
316
326
|
nodekey="gradEndColor"
|
|
@@ -326,7 +336,7 @@ const CardSettings = () => {
|
|
|
326
336
|
</td>
|
|
327
337
|
</tr>
|
|
328
338
|
<tr>
|
|
329
|
-
<td>Direction (°)</td>
|
|
339
|
+
<td>{t("Direction (°)")}</td>
|
|
330
340
|
<td>
|
|
331
341
|
<OrFormula
|
|
332
342
|
nodekey="gradDirection"
|
|
@@ -348,7 +358,7 @@ const CardSettings = () => {
|
|
|
348
358
|
{bgType === "Image" && (
|
|
349
359
|
<tr>
|
|
350
360
|
<td>
|
|
351
|
-
<label>File</label>
|
|
361
|
+
<label>{t("File")}</label>
|
|
352
362
|
</td>
|
|
353
363
|
<td>
|
|
354
364
|
<select
|
|
@@ -373,7 +383,7 @@ const CardSettings = () => {
|
|
|
373
383
|
{bgType === "Image Field" && (
|
|
374
384
|
<tr>
|
|
375
385
|
<td>
|
|
376
|
-
<label>File field</label>
|
|
386
|
+
<label>{t("File field")}</label>
|
|
377
387
|
</td>
|
|
378
388
|
<td>
|
|
379
389
|
<select
|
|
@@ -401,7 +411,7 @@ const CardSettings = () => {
|
|
|
401
411
|
<Fragment>
|
|
402
412
|
<tr>
|
|
403
413
|
<td>
|
|
404
|
-
<label>Location</label>
|
|
414
|
+
<label>{t("Location")}</label>
|
|
405
415
|
</td>
|
|
406
416
|
|
|
407
417
|
<td>
|
|
@@ -410,9 +420,9 @@ const CardSettings = () => {
|
|
|
410
420
|
className="form-control-sm form-select"
|
|
411
421
|
onChange={setAProp("imageLocation")}
|
|
412
422
|
>
|
|
413
|
-
<option>Card</option>
|
|
414
|
-
<option>Body</option>
|
|
415
|
-
<option>Top</option>
|
|
423
|
+
<option>{t("Card")}</option>
|
|
424
|
+
<option>{t("Body")}</option>
|
|
425
|
+
<option>{t("Top")}</option>
|
|
416
426
|
</select>
|
|
417
427
|
</td>
|
|
418
428
|
</tr>
|
|
@@ -423,7 +433,7 @@ const CardSettings = () => {
|
|
|
423
433
|
<Fragment>
|
|
424
434
|
<tr>
|
|
425
435
|
<td>
|
|
426
|
-
<label>Size</label>
|
|
436
|
+
<label>{t("Size")}</label>
|
|
427
437
|
</td>
|
|
428
438
|
|
|
429
439
|
<td>
|
|
@@ -440,7 +450,7 @@ const CardSettings = () => {
|
|
|
440
450
|
)}
|
|
441
451
|
{bgType === "Color" && (
|
|
442
452
|
<tr>
|
|
443
|
-
<td>Color</td>
|
|
453
|
+
<td>{t("Color")}</td>
|
|
444
454
|
<td>
|
|
445
455
|
<OrFormula nodekey="bgColor" {...{ setProp, isFormula, node }}>
|
|
446
456
|
<input
|
|
@@ -472,6 +482,8 @@ const fields = [
|
|
|
472
482
|
{ label: "Card footer", name: "hasFooter", type: "Bool" },
|
|
473
483
|
{ label: "Save indicator", name: "titleAjaxIndicator", type: "Bool" },
|
|
474
484
|
{ label: "No padding", name: "noPadding", type: "Bool" },
|
|
485
|
+
{ label: "Contents", name: "contents", type: "Nodes", nodeID: "cardbody" },
|
|
486
|
+
{ label: "Title Right", name: "titleRight", type: "Nodes", nodeID: "titleRight" },
|
|
475
487
|
{ label: "Footer", name: "footer", type: "Nodes", nodeID: "cardfooter" },
|
|
476
488
|
{ name: "style", default: {} },
|
|
477
489
|
{ label: "Class", name: "class", type: "String", canBeFormula: true },
|
|
@@ -498,13 +510,14 @@ Card.craft = {
|
|
|
498
510
|
shadow: true,
|
|
499
511
|
isFormula: {},
|
|
500
512
|
style: {},
|
|
513
|
+
contents: [],
|
|
501
514
|
footer: [],
|
|
515
|
+
titleRight: [],
|
|
502
516
|
},
|
|
503
517
|
displayName: "Card",
|
|
504
518
|
related: {
|
|
505
519
|
settings: CardSettings,
|
|
506
520
|
segment_type: "card",
|
|
507
|
-
hasContents: true,
|
|
508
521
|
fields,
|
|
509
522
|
},
|
|
510
523
|
};
|
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import React, { Fragment, useState, useEffect } from "react";
|
|
2
2
|
import { ListColumn } from "./ListColumn";
|
|
3
3
|
import { Columns, ntimes } from "./Columns";
|
|
4
|
+
import { Card } from "./Card";
|
|
5
|
+
import { Container } from "./Container";
|
|
6
|
+
import { Tabs } from "./Tabs";
|
|
7
|
+
import { Table } from "./Table";
|
|
4
8
|
import { Element } from "@craftjs/core";
|
|
5
9
|
|
|
6
10
|
const rand_ident = () =>
|
|
7
11
|
Math.floor(Math.random() * 16777215).toString(16);
|
|
8
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Clone the children of a linked node (not the linked node wrapper itself).
|
|
15
|
+
* The parent component's render recreates the wrapper via <Element canvas>.
|
|
16
|
+
*/
|
|
17
|
+
const cloneLinkedNodeChildren = (query, linkedNodeId) => {
|
|
18
|
+
if (!linkedNodeId) return undefined;
|
|
19
|
+
const linkedNodeData = query.node(linkedNodeId).get().data;
|
|
20
|
+
const childNodes = linkedNodeData.nodes || [];
|
|
21
|
+
return childNodes.map(recursivelyCloneToElems(query));
|
|
22
|
+
};
|
|
23
|
+
|
|
9
24
|
export const recursivelyCloneToElems = (query) => (nodeId, ix) => {
|
|
10
25
|
const { data } = query.node(nodeId).get();
|
|
11
26
|
const { type, props, nodes } = data;
|
|
@@ -14,8 +29,6 @@ export const recursivelyCloneToElems = (query) => (nodeId, ix) => {
|
|
|
14
29
|
newProps.rndid = rand_ident();
|
|
15
30
|
}
|
|
16
31
|
|
|
17
|
-
// console.log("cloning", data.displayName, data.linkedNodes["listcol"]);
|
|
18
|
-
|
|
19
32
|
const children = (nodes || []).map(recursivelyCloneToElems(query));
|
|
20
33
|
if (data.displayName === "Columns") {
|
|
21
34
|
const cols = ntimes(data.props.ncols, (ix) =>
|
|
@@ -37,6 +50,65 @@ export const recursivelyCloneToElems = (query) => (nodeId, ix) => {
|
|
|
37
50
|
});
|
|
38
51
|
}
|
|
39
52
|
|
|
53
|
+
if (data.displayName === "Card") {
|
|
54
|
+
const clonedContents = cloneLinkedNodeChildren(
|
|
55
|
+
query,
|
|
56
|
+
data.linkedNodes["cardbody"]
|
|
57
|
+
);
|
|
58
|
+
const clonedFooter = cloneLinkedNodeChildren(
|
|
59
|
+
query,
|
|
60
|
+
data.linkedNodes["cardfooter"]
|
|
61
|
+
);
|
|
62
|
+
return React.createElement(Card, {
|
|
63
|
+
...newProps,
|
|
64
|
+
...(typeof ix !== "undefined" ? { key: ix } : {}),
|
|
65
|
+
contents: clonedContents,
|
|
66
|
+
footer: clonedFooter,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (data.displayName === "Container") {
|
|
71
|
+
const clonedContents = cloneLinkedNodeChildren(
|
|
72
|
+
query,
|
|
73
|
+
data.linkedNodes["container-canvas"]
|
|
74
|
+
);
|
|
75
|
+
return React.createElement(Container, {
|
|
76
|
+
...newProps,
|
|
77
|
+
...(typeof ix !== "undefined" ? { key: ix } : {}),
|
|
78
|
+
contents: clonedContents,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (data.displayName === "Tabs") {
|
|
83
|
+
const cols = ntimes(data.props.ntabs, (ix) =>
|
|
84
|
+
data.linkedNodes["Tab" + ix]
|
|
85
|
+
? cloneLinkedNodeChildren(query, data.linkedNodes["Tab" + ix])
|
|
86
|
+
: undefined
|
|
87
|
+
);
|
|
88
|
+
return React.createElement(Tabs, {
|
|
89
|
+
...newProps,
|
|
90
|
+
...(typeof ix !== "undefined" ? { key: ix } : {}),
|
|
91
|
+
contents: cols,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (data.displayName === "Table") {
|
|
96
|
+
const rows = data.props.rows || 0;
|
|
97
|
+
const columns = data.props.columns || 0;
|
|
98
|
+
const clonedContents = ntimes(rows, (ri) =>
|
|
99
|
+
ntimes(columns, (ci) =>
|
|
100
|
+
data.linkedNodes[`cell_${ri}_${ci}`]
|
|
101
|
+
? cloneLinkedNodeChildren(query, data.linkedNodes[`cell_${ri}_${ci}`])
|
|
102
|
+
: undefined
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
return React.createElement(Table, {
|
|
106
|
+
...newProps,
|
|
107
|
+
...(typeof ix !== "undefined" ? { key: ix } : {}),
|
|
108
|
+
contents: clonedContents,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
40
112
|
if (data.isCanvas)
|
|
41
113
|
return React.createElement(
|
|
42
114
|
Element,
|