@saltcorn/builder 0.0.1-beta.1

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.
Files changed (38) hide show
  1. package/.babelrc +3 -0
  2. package/CHANGELOG.md +8 -0
  3. package/dist/builder_bundle.js +80 -0
  4. package/package.json +47 -0
  5. package/src/components/Builder.js +477 -0
  6. package/src/components/Library.js +224 -0
  7. package/src/components/RenderNode.js +203 -0
  8. package/src/components/Toolbox.js +688 -0
  9. package/src/components/context.js +9 -0
  10. package/src/components/elements/Action.js +204 -0
  11. package/src/components/elements/Aggregation.js +179 -0
  12. package/src/components/elements/BoxModelEditor.js +398 -0
  13. package/src/components/elements/Card.js +152 -0
  14. package/src/components/elements/Column.js +63 -0
  15. package/src/components/elements/Columns.js +201 -0
  16. package/src/components/elements/Container.js +947 -0
  17. package/src/components/elements/DropDownFilter.js +154 -0
  18. package/src/components/elements/DropMenu.js +156 -0
  19. package/src/components/elements/Empty.js +30 -0
  20. package/src/components/elements/Field.js +239 -0
  21. package/src/components/elements/HTMLCode.js +61 -0
  22. package/src/components/elements/Image.js +320 -0
  23. package/src/components/elements/JoinField.js +206 -0
  24. package/src/components/elements/LineBreak.js +46 -0
  25. package/src/components/elements/Link.js +305 -0
  26. package/src/components/elements/SearchBar.js +141 -0
  27. package/src/components/elements/Tabs.js +347 -0
  28. package/src/components/elements/Text.js +330 -0
  29. package/src/components/elements/ToggleFilter.js +243 -0
  30. package/src/components/elements/View.js +189 -0
  31. package/src/components/elements/ViewLink.js +225 -0
  32. package/src/components/elements/boxmodel.html +253 -0
  33. package/src/components/elements/faicons.js +1643 -0
  34. package/src/components/elements/utils.js +1217 -0
  35. package/src/components/preview_context.js +9 -0
  36. package/src/components/storage.js +506 -0
  37. package/src/index.js +73 -0
  38. package/webpack.config.js +21 -0
@@ -0,0 +1,947 @@
1
+ /**
2
+ * @category saltcorn-builder
3
+ * @module components/elements/Container
4
+ * @subcategory components / elements
5
+ */
6
+
7
+ import React, { useContext, Fragment } from "react";
8
+
9
+ import { Element, useNode } from "@craftjs/core";
10
+ import optionsCtx from "../context";
11
+ import {
12
+ Accordion,
13
+ BlockSetting,
14
+ OrFormula,
15
+ parseStyles,
16
+ SelectUnits,
17
+ SettingsSectionHeaderRow,
18
+ SettingsRow,
19
+ reactifyStyles,
20
+ bstyleopt,
21
+ } from "./utils";
22
+ import {
23
+ BorderOuter,
24
+ BorderTop,
25
+ BorderBottom,
26
+ BorderLeft,
27
+ BorderRight,
28
+ BorderAll,
29
+ AlignTop,
30
+ AlignMiddle,
31
+ AlignStart,
32
+ AlignEnd,
33
+ AlignCenter,
34
+ Justify,
35
+ AlignBottom,
36
+ SlashCircle,
37
+ Image,
38
+ Rainbow,
39
+ Palette,
40
+ EyeFill,
41
+ EyeSlashFill,
42
+ } from "react-bootstrap-icons";
43
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
44
+ import { faScroll, faRobot } from "@fortawesome/free-solid-svg-icons";
45
+ import { BoxModelEditor } from "./BoxModelEditor";
46
+ import previewCtx from "../preview_context";
47
+
48
+ /**
49
+ *
50
+ * @param {string} string
51
+ * @returns {string}
52
+ */
53
+ function capitalizeFirstLetter(string) {
54
+ return string.charAt(0).toUpperCase() + string.slice(1);
55
+ }
56
+
57
+ export /**
58
+ * @param {object} props
59
+ * @param {*} props.children
60
+ * @param {*} props.minHeight
61
+ * @param {*} props.height
62
+ * @param {*} props.width
63
+ * @param {*} props.minHeightUnit
64
+ * @param {*} props.heightUnit
65
+ * @param {*} props.widthUnit
66
+ * @param {*} props.vAlign
67
+ * @param {*} props.hAlign
68
+ * @param {*} props.bgFileId
69
+ * @param {*} props.imageSize
70
+ * @param {*} props.bgType
71
+ * @param {*} props.display
72
+ * @param {*} props.bgColor
73
+ * @param {*} props.setTextColor
74
+ * @param {*} props.textColor
75
+ * @param {*} props.customClass
76
+ * @param {*} props.customCSS
77
+ * @param {*} props.margin
78
+ * @param {*} props.padding
79
+ * @param {*} props.minScreenWidth
80
+ * @param {*} props.gradStartColor
81
+ * @param {*} props.gradEndColor
82
+ * @param {*} props.gradDirection
83
+ * @param {*} props.rotate
84
+ * @param {*} props.style
85
+ * @param {*} props.htmlElement
86
+ * @returns {DetailedReactHTMLElement}
87
+ * @namespace
88
+ * @category saltcorn-builder
89
+ * @subcategory components
90
+ */
91
+ const Container = ({
92
+ children,
93
+ minHeight,
94
+ height,
95
+ width,
96
+ minHeightUnit,
97
+ heightUnit,
98
+ widthUnit,
99
+ vAlign,
100
+ hAlign,
101
+ bgFileId,
102
+ imageSize,
103
+ bgType,
104
+ display,
105
+ bgColor,
106
+ setTextColor,
107
+ textColor,
108
+ customClass,
109
+ customCSS,
110
+ margin,
111
+ padding,
112
+ minScreenWidth,
113
+ gradStartColor,
114
+ gradEndColor,
115
+ gradDirection,
116
+ rotate,
117
+ style,
118
+ htmlElement,
119
+ }) => {
120
+ const {
121
+ selected,
122
+ connectors: { connect, drag },
123
+ } = useNode((node) => ({ selected: node.events.selected }));
124
+ //console.log("container style", style);
125
+ return React.createElement(
126
+ htmlElement,
127
+ {
128
+ ref: (dom) => connect(drag(dom)),
129
+ className: `${customClass || ""} canvas text-${hAlign} ${
130
+ vAlign === "middle" ? "d-flex align-items-center" : ""
131
+ } ${
132
+ vAlign === "middle" && hAlign === "center" && "justify-content-center"
133
+ } ${selected ? "selected-node" : ""}`,
134
+ style: {
135
+ ...parseStyles(customCSS || ""),
136
+ ...reactifyStyles(style),
137
+ display,
138
+ //padding: padding.map((p) => p + "px").join(" "),
139
+ //margin: margin.map((p) => p + "px").join(" "),
140
+ minHeight: minHeight ? `${minHeight}${minHeightUnit || "px"}` : null,
141
+ ...(bgType === "Image" && bgFileId && +bgFileId
142
+ ? {
143
+ backgroundImage: `url('/files/serve/${bgFileId}')`,
144
+ backgroundSize:
145
+ imageSize === "repeat" ? undefined : imageSize || "contain",
146
+ backgroundRepeat:
147
+ imageSize === "repeat" ? imageSize : "no-repeat",
148
+ }
149
+ : {}),
150
+ ...(bgType === "Color"
151
+ ? {
152
+ backgroundColor: bgColor,
153
+ }
154
+ : {}),
155
+ ...(bgType === "Gradient"
156
+ ? {
157
+ backgroundImage: `linear-gradient(${
158
+ gradDirection || 0
159
+ }deg, ${gradStartColor}, ${gradEndColor})`,
160
+ }
161
+ : {}),
162
+ ...(setTextColor
163
+ ? {
164
+ color: textColor,
165
+ }
166
+ : {}),
167
+ ...(typeof height !== "undefined"
168
+ ? {
169
+ height: `${height}${heightUnit || "px"}`,
170
+ }
171
+ : {}),
172
+ ...(typeof width !== "undefined"
173
+ ? {
174
+ width: `${width}${widthUnit || "px"}`,
175
+ }
176
+ : {}),
177
+ ...(rotate
178
+ ? {
179
+ transform: `rotate(${rotate}deg)`,
180
+ }
181
+ : {}),
182
+ },
183
+ },
184
+ children
185
+ );
186
+ };
187
+
188
+ export /**
189
+ * @returns {div}
190
+ * @returns {Accordion}
191
+ * @namespace
192
+ * @category saltcorn-builder
193
+ * @subcategory components
194
+ */
195
+ const ContainerSettings = () => {
196
+ const node = useNode((node) => ({
197
+ minHeight: node.data.props.minHeight,
198
+ height: node.data.props.height,
199
+ width: node.data.props.width,
200
+ minHeightUnit: node.data.props.minHeightUnit,
201
+ heightUnit: node.data.props.heightUnit,
202
+ widthUnit: node.data.props.widthUnit,
203
+ bgType: node.data.props.bgType,
204
+ bgColor: node.data.props.bgColor,
205
+ isFormula: node.data.props.isFormula,
206
+ bgFileId: node.data.props.bgFileId,
207
+ imageSize: node.data.props.imageSize,
208
+ htmlElement: node.data.props.htmlElement,
209
+ vAlign: node.data.props.vAlign,
210
+ hAlign: node.data.props.hAlign,
211
+ fullPageWidth: node.data.props.fullPageWidth,
212
+ showIfFormula: node.data.props.showIfFormula,
213
+ setTextColor: node.data.props.setTextColor,
214
+ showForRole: node.data.props.showForRole,
215
+ textColor: node.data.props.textColor,
216
+ customClass: node.data.props.customClass,
217
+ customCSS: node.data.props.customCSS,
218
+ minScreenWidth: node.data.props.minScreenWidth,
219
+ maxScreenWidth: node.data.props.maxScreenWidth,
220
+ show_for_owner: node.data.props.show_for_owner,
221
+ margin: node.data.props.margin,
222
+ padding: node.data.props.padding,
223
+ url: node.data.props.url,
224
+ hoverColor: node.data.props.hoverColor,
225
+ gradStartColor: node.data.props.gradStartColor,
226
+ gradEndColor: node.data.props.gradEndColor,
227
+ gradDirection: node.data.props.gradDirection,
228
+ overflow: node.data.props.overflow,
229
+ rotate: node.data.props.rotate,
230
+ display: node.data.props.display,
231
+ style: node.data.props.style,
232
+ imgResponsiveWidths: node.data.props.imgResponsiveWidths,
233
+ }));
234
+ const {
235
+ actions: { setProp },
236
+ bgFileId,
237
+ imageSize,
238
+ bgType,
239
+ display,
240
+ bgColor,
241
+ setTextColor,
242
+ textColor,
243
+ showIfFormula,
244
+ isFormula,
245
+ showForRole,
246
+ customClass,
247
+ customCSS,
248
+ minScreenWidth,
249
+ maxScreenWidth,
250
+ show_for_owner,
251
+ margin,
252
+ padding,
253
+ url,
254
+ hoverColor,
255
+ gradStartColor,
256
+ gradEndColor,
257
+ gradDirection,
258
+ fullPageWidth,
259
+ overflow,
260
+ htmlElement,
261
+ imgResponsiveWidths,
262
+ } = node;
263
+ const options = useContext(optionsCtx);
264
+ const { uploadedFiles } = useContext(previewCtx);
265
+
266
+ const ownership = !!options.ownership;
267
+
268
+ /**
269
+ * @param {string} key
270
+ * @returns {function}
271
+ */
272
+ const setAProp = (key) => (e) => {
273
+ if (e.target) {
274
+ const target_value = e.target.value;
275
+ setProp((prop) => (prop[key] = target_value));
276
+ }
277
+ };
278
+ return (
279
+ <Accordion>
280
+ <div accordiontitle="Box" className="w-100">
281
+ <BoxModelEditor setProp={setProp} node={node} />
282
+ </div>
283
+ <table className="w-100" accordiontitle="Display">
284
+ <tbody>
285
+ <SettingsRow
286
+ field={{
287
+ name: "display",
288
+ label: "Display",
289
+ type: "select",
290
+ options: [
291
+ "block",
292
+ "inline",
293
+ "inline-block",
294
+ "none",
295
+ "flex",
296
+ "inline-flex",
297
+ ],
298
+ }}
299
+ node={node}
300
+ setProp={setProp}
301
+ />
302
+ <SettingsRow
303
+ field={{
304
+ name: "htmlElement",
305
+ label: "HTML element",
306
+ type: "select",
307
+ options: [
308
+ "div",
309
+ "span",
310
+ "article",
311
+ "section",
312
+ "header",
313
+ "nav",
314
+ "main",
315
+ "aside",
316
+ "footer",
317
+ ],
318
+ }}
319
+ node={node}
320
+ setProp={setProp}
321
+ />
322
+ <SettingsRow
323
+ field={{
324
+ name: "overflow",
325
+ label: "Overflow",
326
+ type: "btn_select",
327
+ options: [
328
+ { value: "visible", title: "Visible", label: <EyeFill /> },
329
+ { value: "hidden", title: "Hidden", label: <EyeSlashFill /> },
330
+ {
331
+ value: "scroll",
332
+ title: "Scroll",
333
+ label: <FontAwesomeIcon icon={faScroll} />,
334
+ },
335
+ {
336
+ value: "auto",
337
+ title: "Auto",
338
+ label: <FontAwesomeIcon icon={faRobot} />,
339
+ },
340
+ ],
341
+ }}
342
+ node={node}
343
+ setProp={setProp}
344
+ />
345
+ <tr>
346
+ <td colSpan="2">
347
+ <div className="form-check">
348
+ <input
349
+ className="form-check-input"
350
+ name="block"
351
+ type="checkbox"
352
+ checked={fullPageWidth}
353
+ onChange={(e) =>
354
+ setProp((prop) => (prop.fullPageWidth = e.target.checked))
355
+ }
356
+ />
357
+ <label className="form-check-label">
358
+ Expand to full page width
359
+ </label>
360
+ </div>
361
+ </td>
362
+ </tr>
363
+ </tbody>
364
+ </table>
365
+ <table className="w-100" accordiontitle="Contents">
366
+ <tbody>
367
+ <SettingsRow
368
+ field={{
369
+ name: "rotate",
370
+ label: "Rotate °",
371
+ type: "Integer",
372
+ }}
373
+ node={node}
374
+ setProp={setProp}
375
+ />
376
+ <SettingsSectionHeaderRow title="Align" />
377
+ <SettingsRow
378
+ field={{
379
+ name: "vAlign",
380
+ label: "Vertical",
381
+ type: "btn_select",
382
+ options: [
383
+ { value: "top", title: "All", label: <AlignTop /> },
384
+ { value: "middle", title: "All", label: <AlignMiddle /> },
385
+ { value: "bottom", title: "All", label: <AlignBottom /> },
386
+ ],
387
+ }}
388
+ node={node}
389
+ setProp={setProp}
390
+ />
391
+ <SettingsRow
392
+ field={{
393
+ name: "hAlign",
394
+ label: "Horizontal",
395
+ type: "btn_select",
396
+ options: [
397
+ { value: "left", title: "Left", label: <AlignStart /> },
398
+ { value: "center", title: "Center", label: <AlignCenter /> },
399
+ { value: "right", title: "Right", label: <AlignEnd /> },
400
+ ],
401
+ }}
402
+ node={node}
403
+ setProp={setProp}
404
+ />
405
+ <SettingsSectionHeaderRow title="Background" />
406
+ <SettingsRow
407
+ field={{
408
+ name: "bgType",
409
+ label: "Type",
410
+ type: "btn_select",
411
+ options: [
412
+ { value: "None", label: <SlashCircle /> },
413
+ { value: "Image", label: <Image /> },
414
+ { value: "Color", label: <Palette /> },
415
+ { value: "Gradient", label: <Rainbow /> },
416
+ ],
417
+ }}
418
+ node={node}
419
+ setProp={setProp}
420
+ onChange={(v) =>
421
+ setProp((prop) => {
422
+ prop.bgFileId =
423
+ prop.bgFileId ||
424
+ (options.images.length + uploadedFiles.length > 0 &&
425
+ options.images[0].id);
426
+ })
427
+ }
428
+ />
429
+ {bgType === "Gradient" && (
430
+ <Fragment>
431
+ <tr>
432
+ <td>Start</td>
433
+ <td>
434
+ <OrFormula
435
+ nodekey="gradStartColor"
436
+ {...{ setProp, isFormula, node }}
437
+ >
438
+ <input
439
+ type="color"
440
+ value={gradStartColor}
441
+ className="form-control-sm w-50"
442
+ onChange={setAProp("gradStartColor")}
443
+ />
444
+ </OrFormula>
445
+ </td>
446
+ </tr>
447
+ <tr>
448
+ <td>End</td>
449
+ <td>
450
+ <OrFormula
451
+ nodekey="gradEndColor"
452
+ {...{ setProp, isFormula, node }}
453
+ >
454
+ <input
455
+ type="color"
456
+ value={gradEndColor}
457
+ className="form-control-sm w-50"
458
+ onChange={setAProp("gradEndColor")}
459
+ />
460
+ </OrFormula>
461
+ </td>
462
+ </tr>
463
+ <tr>
464
+ <td>Direction (&deg;)</td>
465
+ <td>
466
+ <OrFormula
467
+ nodekey="gradDirection"
468
+ {...{ setProp, isFormula, node }}
469
+ >
470
+ <input
471
+ type="number"
472
+ min="0"
473
+ max="360"
474
+ value={gradDirection}
475
+ className="form-control-sm w-50"
476
+ onChange={setAProp("gradDirection")}
477
+ />
478
+ </OrFormula>
479
+ </td>
480
+ </tr>
481
+ </Fragment>
482
+ )}
483
+ {bgType === "Image" && (
484
+ <Fragment>
485
+ <tr>
486
+ <td>
487
+ <label>File</label>
488
+ </td>
489
+ <td>
490
+ <select
491
+ value={bgFileId}
492
+ className="form-control-sm w-100 form-select"
493
+ onChange={setAProp("bgFileId")}
494
+ >
495
+ {options.images.map((f, ix) => (
496
+ <option key={ix} value={f.id}>
497
+ {f.filename}
498
+ </option>
499
+ ))}
500
+ {(uploadedFiles || []).map((uf, ix) => (
501
+ <option key={ix} value={uf.id}>
502
+ {uf.filename}
503
+ </option>
504
+ ))}{" "}
505
+ </select>
506
+ </td>
507
+ </tr>
508
+ <tr>
509
+ <td>
510
+ <label>Size</label>
511
+ </td>
512
+
513
+ <td>
514
+ <select
515
+ value={imageSize}
516
+ className="form-control-sm form-select"
517
+ onChange={setAProp("imageSize")}
518
+ >
519
+ <option>contain</option>
520
+ <option>cover</option>
521
+ <option>repeat</option>
522
+ </select>
523
+ </td>
524
+ </tr>
525
+ {imageSize !== "repeat" && (
526
+ <tr>
527
+ <td>
528
+ <label>Responsive widths</label>
529
+ </td>
530
+
531
+ <td>
532
+ <input
533
+ type="text"
534
+ value={imgResponsiveWidths}
535
+ className="form-control"
536
+ onChange={setAProp("imgResponsiveWidths")}
537
+ />
538
+ <small>
539
+ <i>List of widths to serve resized images,
540
+ e.g. 300, 400, 600</i>
541
+ </small>
542
+ </td>
543
+ </tr>
544
+ )}
545
+ </Fragment>
546
+ )}
547
+ {bgType === "Color" && (
548
+ <tr>
549
+ <td>Color</td>
550
+ <td>
551
+ <OrFormula nodekey="bgColor" {...{ setProp, isFormula, node }}>
552
+ <input
553
+ type="color"
554
+ value={bgColor}
555
+ className="form-control-sm w-50"
556
+ onChange={setAProp("bgColor")}
557
+ />
558
+ </OrFormula>
559
+ </td>
560
+ </tr>
561
+ )}
562
+ <SettingsSectionHeaderRow title="Typography" />
563
+ <SettingsRow
564
+ field={{
565
+ name: "font-family",
566
+ label: "Font family",
567
+ type: "Font",
568
+ }}
569
+ node={node}
570
+ setProp={setProp}
571
+ isStyle={true}
572
+ />
573
+ <SettingsRow
574
+ field={{
575
+ name: "font-size",
576
+ label: "Font size",
577
+ type: "DimUnits",
578
+ }}
579
+ node={node}
580
+ setProp={setProp}
581
+ isStyle={true}
582
+ />
583
+ <SettingsRow
584
+ field={{
585
+ name: "font-weight",
586
+ label: "Weight",
587
+ type: "Integer",
588
+ min: 100,
589
+ max: 900,
590
+ step: 100,
591
+ }}
592
+ node={node}
593
+ setProp={setProp}
594
+ isStyle={true}
595
+ />
596
+ <SettingsRow
597
+ field={{
598
+ name: "line-height",
599
+ label: "Line height",
600
+ type: "DimUnits",
601
+ }}
602
+ node={node}
603
+ setProp={setProp}
604
+ isStyle={true}
605
+ />
606
+ <tr>
607
+ <td colSpan="2">
608
+ <label>
609
+ Set text color
610
+ <input
611
+ name="setTextColor"
612
+ type="checkbox"
613
+ checked={setTextColor}
614
+ onChange={(e) =>
615
+ setProp((prop) => (prop.setTextColor = e.target.checked))
616
+ }
617
+ />
618
+ </label>
619
+ </td>
620
+ </tr>
621
+ {setTextColor && (
622
+ <tr>
623
+ <td>
624
+ <label>Text</label>
625
+ </td>
626
+ <td>
627
+ <input
628
+ type="color"
629
+ value={textColor}
630
+ className="form-control-sm"
631
+ onChange={setAProp("textColor")}
632
+ />
633
+ </td>
634
+ </tr>
635
+ )}
636
+ </tbody>
637
+ </table>
638
+ <table className="w-100" accordiontitle="Flex properties">
639
+ <tbody>
640
+ <SettingsSectionHeaderRow title="Flex item" />
641
+ <SettingsRow
642
+ field={{ name: "flex-grow", label: "Grow", type: "Float" }}
643
+ node={node}
644
+ setProp={setProp}
645
+ isStyle={true}
646
+ />
647
+ <SettingsRow
648
+ field={{ name: "flex-shrink", label: "Shrink", type: "Float" }}
649
+ node={node}
650
+ setProp={setProp}
651
+ isStyle={true}
652
+ />
653
+ {display && display.includes("flex") && (
654
+ <Fragment>
655
+ <SettingsSectionHeaderRow title="Flex container" />
656
+ <SettingsRow
657
+ field={{
658
+ name: "flex-direction",
659
+ label: "Direction",
660
+ type: "select",
661
+ options: ["row", "row-reverse", "column", "column-reverse"],
662
+ }}
663
+ node={node}
664
+ setProp={setProp}
665
+ isStyle={true}
666
+ />
667
+ <SettingsRow
668
+ field={{
669
+ name: "flex-wrap",
670
+ label: "Wrap",
671
+ type: "select",
672
+ options: ["nowrap", "wrap", "wrap-reverse"],
673
+ }}
674
+ node={node}
675
+ setProp={setProp}
676
+ isStyle={true}
677
+ />
678
+ <SettingsRow
679
+ field={{
680
+ name: "justify-content",
681
+ label: "Justify content",
682
+ type: "select",
683
+ options: [
684
+ "flex-start",
685
+ "flex-end",
686
+ "center",
687
+ "space-between",
688
+ "space-around",
689
+ "space-evenly",
690
+ "start",
691
+ "end",
692
+ "left",
693
+ "right",
694
+ ],
695
+ }}
696
+ node={node}
697
+ setProp={setProp}
698
+ isStyle={true}
699
+ />
700
+ <SettingsRow
701
+ field={{
702
+ name: "align-items",
703
+ label: "Align items",
704
+ type: "select",
705
+ options: [
706
+ "stretch",
707
+ "flex-start",
708
+ "flex-end",
709
+ "center",
710
+ "baseline",
711
+ "first baseline",
712
+ "last baseline",
713
+ "start",
714
+ "end",
715
+ "self-start",
716
+ "self-end",
717
+ ],
718
+ }}
719
+ node={node}
720
+ setProp={setProp}
721
+ isStyle={true}
722
+ />
723
+ <SettingsRow
724
+ field={{
725
+ name: "align-content",
726
+ label: "Align content",
727
+ type: "select",
728
+ options: [
729
+ "flex-start",
730
+ "flex-end",
731
+ "center",
732
+ "space-between",
733
+ "space-around",
734
+ "space-evenly",
735
+ "stretch",
736
+ "start",
737
+ "end",
738
+ "baseline",
739
+ "first baseline",
740
+ "last baseline",
741
+ ],
742
+ }}
743
+ node={node}
744
+ setProp={setProp}
745
+ isStyle={true}
746
+ />
747
+ </Fragment>
748
+ )}
749
+ </tbody>
750
+ </table>
751
+ <table className="w-100" accordiontitle="Show if...">
752
+ <tbody>
753
+ {["show", "edit"].includes(options.mode) && (
754
+ <SettingsSectionHeaderRow title="Formula - show if true" />
755
+ )}
756
+ {["show", "edit"].includes(options.mode) && (
757
+ <tr>
758
+ <td>
759
+ <input
760
+ type="text"
761
+ className="form-control text-to-display"
762
+ value={showIfFormula}
763
+ onChange={setAProp("showIfFormula")}
764
+ />
765
+ <div style={{ marginTop: "-5px" }}>
766
+ <small className="text-muted font-monospace">FORMULA</small>
767
+ </div>
768
+ </td>
769
+ </tr>
770
+ )}
771
+ <SettingsSectionHeaderRow title="Role" />
772
+ {options.roles.map(({ role, id }) => (
773
+ <tr key={id}>
774
+ <td colSpan="2">
775
+ <div className="form-check">
776
+ <input
777
+ className="form-check-input"
778
+ name="block"
779
+ type="checkbox"
780
+ checked={
781
+ typeof showForRole[id] === "undefined"
782
+ ? true
783
+ : showForRole[id]
784
+ }
785
+ onChange={(e) =>
786
+ setProp((prop) => {
787
+ if (!prop.showForRole || prop.showForRole.length === 0)
788
+ options.roles.forEach(
789
+ (r) => (prop.showForRole[r.id] = true)
790
+ );
791
+ prop.showForRole[id] = e.target.checked;
792
+ })
793
+ }
794
+ />
795
+ <label className="form-check-label">{role}</label>
796
+ </div>
797
+ </td>
798
+ </tr>
799
+ ))}
800
+ {ownership ? (
801
+ <tr>
802
+ <td colSpan="2">
803
+ <div className="form-check">
804
+ <input
805
+ className="form-check-input"
806
+ name="block"
807
+ type="checkbox"
808
+ checked={show_for_owner}
809
+ onChange={(e) =>
810
+ setProp(
811
+ (prop) => (prop.show_for_owner = e.target.checked)
812
+ )
813
+ }
814
+ />
815
+ <label className="form-check-label">Owner</label>
816
+ </div>
817
+ </td>
818
+ </tr>
819
+ ) : null}
820
+ <tr>
821
+ <td>
822
+ <label>Min screen width</label>
823
+ </td>
824
+ <td>
825
+ <select
826
+ value={minScreenWidth}
827
+ className="form-control form-select"
828
+ onChange={setAProp("minScreenWidth")}
829
+ >
830
+ <option value="">all</option>
831
+ <option value="sm">small</option>
832
+ <option value="md">medium</option>
833
+ <option value="lg">large</option>
834
+ <option value="xl">x-large</option>
835
+ </select>
836
+ </td>
837
+ </tr>
838
+ <tr>
839
+ <td>
840
+ <label>Max screen width</label>
841
+ </td>
842
+ <td>
843
+ <select
844
+ value={maxScreenWidth}
845
+ className="form-control form-select"
846
+ onChange={setAProp("maxScreenWidth")}
847
+ >
848
+ <option value="">all</option>
849
+ <option value="md">small</option>
850
+ <option value="lg">medium</option>
851
+ <option value="xl">large</option>
852
+ </select>
853
+ </td>
854
+ </tr>
855
+ </tbody>
856
+ </table>
857
+ <div accordiontitle="Container link">
858
+ <label>URL</label>
859
+ <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
860
+ <input
861
+ type="text"
862
+ className="form-control"
863
+ value={url}
864
+ onChange={setAProp("url")}
865
+ />
866
+ </OrFormula>
867
+
868
+ <label>Hover color</label>
869
+ <select
870
+ value={hoverColor}
871
+ className="form-control form-select"
872
+ onChange={setAProp("hoverColor")}
873
+ >
874
+ <option value="">None</option>
875
+ <option value="gray">gray</option>
876
+ <option value="gray-dark">gray-dark</option>
877
+ <option value="light">light</option>
878
+ <option value="dark">dark</option>
879
+ </select>
880
+ </div>
881
+
882
+ <div accordiontitle="Custom class/CSS">
883
+ <div>
884
+ <label>Custom class</label>
885
+ </div>
886
+ <OrFormula nodekey="customClass" {...{ setProp, isFormula, node }}>
887
+ <input
888
+ type="text"
889
+ className="form-control text-to-display"
890
+ value={customClass}
891
+ onChange={setAProp("customClass")}
892
+ />
893
+ </OrFormula>
894
+ <div>
895
+ <label>Custom CSS</label>
896
+ </div>
897
+ <textarea
898
+ rows="4"
899
+ type="text"
900
+ className="text-to-display form-control"
901
+ value={customCSS}
902
+ onChange={setAProp("customCSS")}
903
+ ></textarea>
904
+ </div>
905
+ </Accordion>
906
+ );
907
+ };
908
+
909
+ /**
910
+ * @type {object}
911
+ */
912
+ Container.craft = {
913
+ displayName: "Container",
914
+ props: {
915
+ minHeight: 0,
916
+ vAlign: "top",
917
+ hAlign: "left",
918
+ bgFileId: 0,
919
+ rotate: 0,
920
+ isFormula: {},
921
+ bgType: "None",
922
+ fullPageWidth: false,
923
+ bgColor: "#ffffff",
924
+ borderColor: "#000000",
925
+ setTextColor: false,
926
+ textColor: "#ffffff",
927
+ gradStartColor: "#ff8888",
928
+ gradEndColor: "#88ff88",
929
+ gradDirection: "0",
930
+ imageSize: "contain",
931
+ showIfFormula: "",
932
+ showForRole: [],
933
+ margin: [0, 0, 0, 0],
934
+ padding: [0, 0, 0, 0],
935
+ minScreenWidth: "",
936
+ display: "block",
937
+ show_for_owner: false,
938
+ style: {},
939
+ htmlElement: "div",
940
+ },
941
+ rules: {
942
+ canDrag: () => true,
943
+ },
944
+ related: {
945
+ settings: ContainerSettings,
946
+ },
947
+ };