@saltcorn/builder 1.1.2-beta.8 → 1.1.2-beta.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/builder",
3
- "version": "1.1.2-beta.8",
3
+ "version": "1.1.2-beta.9",
4
4
  "description": "Drag and drop view builder for Saltcorn, open-source no-code platform",
5
5
  "main": "index.js",
6
6
  "homepage": "https://saltcorn.com",
@@ -20,7 +20,7 @@
20
20
  "@babel/preset-react": "7.24.7",
21
21
  "@craftjs/core": "0.1.0-beta.20",
22
22
  "@craftjs/utils": "0.1.0-beta.20",
23
- "@saltcorn/common-code": "1.1.2-beta.8",
23
+ "@saltcorn/common-code": "1.1.2-beta.9",
24
24
  "saltcorn-craft-layers-noeye": "0.1.0-beta.22",
25
25
  "@fonticonpicker/react-fonticonpicker": "1.2.0",
26
26
  "@fortawesome/fontawesome-svg-core": "1.2.34",
@@ -110,6 +110,7 @@ const InitNewElement = ({ nodekeys, savingState, setSavingState }) => {
110
110
 
111
111
  fetch(`/${urlroot}/savebuilder/${options.page_id || options.view_id}`, {
112
112
  method: "POST", // or 'PUT'
113
+ keepalive: true,
113
114
  headers: {
114
115
  "Content-Type": "application/json",
115
116
  "CSRF-Token": options.csrfToken,
@@ -85,8 +85,7 @@ const Action = ({
85
85
  };
86
86
 
87
87
  export /**
88
- * @category saltcorn-builder
89
- * @subcategory components
88
+ * @category saltcorn-builder * @subcategory components
90
89
  * @namespace
91
90
  * @returns {div}
92
91
  */
@@ -108,6 +107,7 @@ const ActionSettings = () => {
108
107
  action_bgcol: node.data.props.action_bgcol,
109
108
  action_bordercol: node.data.props.action_bordercol,
110
109
  action_textcol: node.data.props.action_textcol,
110
+ action_class: node.data.props.action_class,
111
111
  nsteps: node.data.props.nsteps,
112
112
  step_only_ifs: node.data.props.step_only_ifs,
113
113
  step_action_names: node.data.props.step_action_names,
@@ -134,6 +134,7 @@ const ActionSettings = () => {
134
134
  step_action_names,
135
135
  spinner,
136
136
  is_submit_action,
137
+
137
138
  } = node;
138
139
  const options = useContext(optionsCtx);
139
140
  const getCfgFields = (fv) => (options.actionConfigForms || {})[fv];
@@ -36,6 +36,7 @@ import {
36
36
  AlignBottom,
37
37
  SlashCircle,
38
38
  Image,
39
+ Images,
39
40
  Rainbow,
40
41
  Palette,
41
42
  EyeFill,
@@ -194,6 +195,7 @@ const ContainerSettings = () => {
194
195
  bgColor: node.data.props.bgColor,
195
196
  isFormula: node.data.props.isFormula,
196
197
  bgFileId: node.data.props.bgFileId,
198
+ bgField: node.data.props.bgField,
197
199
  imageSize: node.data.props.imageSize,
198
200
  htmlElement: node.data.props.htmlElement,
199
201
  vAlign: node.data.props.vAlign,
@@ -260,6 +262,7 @@ const ContainerSettings = () => {
260
262
  click_action,
261
263
  style,
262
264
  transform,
265
+ bgField,
263
266
  } = node;
264
267
  const options = useContext(optionsCtx);
265
268
  const { uploadedFiles } = useContext(previewCtx);
@@ -340,6 +343,17 @@ const ContainerSettings = () => {
340
343
  node={node}
341
344
  setProp={setProp}
342
345
  />
346
+ <SettingsRow
347
+ field={{
348
+ name: "opacity",
349
+ label: "Opacity",
350
+ type: "Float",
351
+ attributes: { min: 0, max: 1 },
352
+ }}
353
+ node={node}
354
+ setProp={setProp}
355
+ isStyle={true}
356
+ />
343
357
  <SettingsRow
344
358
  field={{
345
359
  name: "position",
@@ -462,6 +476,9 @@ const ContainerSettings = () => {
462
476
  options: [
463
477
  { value: "None", label: <SlashCircle /> },
464
478
  { value: "Image", label: <Image /> },
479
+ ...(options.mode === "show"
480
+ ? [{ value: "Image Field", label: <Images /> }]
481
+ : []),
465
482
  { value: "Color", label: <Palette /> },
466
483
  { value: "Gradient", label: <Rainbow /> },
467
484
  ],
@@ -532,30 +549,59 @@ const ContainerSettings = () => {
532
549
  </Fragment>
533
550
  )}
534
551
  {bgType === "Image" && (
535
- <Fragment>
536
- <tr>
537
- <td>
538
- <label>File</label>
539
- </td>
540
- <td>
541
- <select
542
- value={bgFileId}
543
- className="form-control-sm w-100 form-select"
544
- onChange={setAProp("bgFileId")}
545
- >
546
- {options.images.map((f, ix) => (
547
- <option key={ix} value={f.id}>
548
- {f.filename}
552
+ <tr>
553
+ <td>
554
+ <label>File</label>
555
+ </td>
556
+ <td>
557
+ <select
558
+ value={bgFileId}
559
+ className="form-control-sm w-100 form-select"
560
+ onChange={setAProp("bgFileId")}
561
+ >
562
+ {options.images.map((f, ix) => (
563
+ <option key={ix} value={f.id}>
564
+ {f.filename}
565
+ </option>
566
+ ))}
567
+ {(uploadedFiles || []).map((uf, ix) => (
568
+ <option key={ix} value={uf.id}>
569
+ {uf.filename}
570
+ </option>
571
+ ))}{" "}
572
+ </select>
573
+ </td>
574
+ </tr>
575
+ )}
576
+ {bgType === "Image Field" && (
577
+ <tr>
578
+ <td>
579
+ <label>File field</label>
580
+ </td>
581
+ <td>
582
+ <select
583
+ value={bgField}
584
+ className="form-control-sm w-100 form-select"
585
+ onChange={setAProp("bgField")}
586
+ >
587
+ {options.fields
588
+ .filter(
589
+ (f) =>
590
+ f.type === "String" ||
591
+ (f.type && f.type.name === "String") ||
592
+ (f.type && f.type === "File")
593
+ )
594
+ .map((f, ix) => (
595
+ <option key={ix} value={f.name}>
596
+ {f.label}
549
597
  </option>
550
598
  ))}
551
- {(uploadedFiles || []).map((uf, ix) => (
552
- <option key={ix} value={uf.id}>
553
- {uf.filename}
554
- </option>
555
- ))}{" "}
556
- </select>
557
- </td>
558
- </tr>
599
+ </select>
600
+ </td>
601
+ </tr>
602
+ )}
603
+ {(bgType === "Image" || bgType === "Image Field") && (
604
+ <Fragment>
559
605
  <tr>
560
606
  <td>
561
607
  <label>Size</label>
@@ -863,7 +909,7 @@ const ContainerSettings = () => {
863
909
  name: "animateName",
864
910
  label: "Animation",
865
911
  type: "select",
866
- options: ["None", ...options.keyframes || []],
912
+ options: ["None", ...(options.keyframes || [])],
867
913
  }}
868
914
  node={node}
869
915
  setProp={setProp}
@@ -882,8 +928,12 @@ const ContainerSettings = () => {
882
928
  node={node}
883
929
  setProp={setProp}
884
930
  />
885
- <SettingsRow
886
- field={{ name: "animateInitialHide", label: "Initially hidden", type: "Bool" }}
931
+ <SettingsRow
932
+ field={{
933
+ name: "animateInitialHide",
934
+ label: "Initially hidden",
935
+ type: "Bool",
936
+ }}
887
937
  node={node}
888
938
  setProp={setProp}
889
939
  />
@@ -1086,6 +1136,7 @@ Container.craft = {
1086
1136
  vAlign: "top",
1087
1137
  hAlign: "left",
1088
1138
  bgFileId: 0,
1139
+ bgField: "",
1089
1140
  rotate: 0,
1090
1141
  isFormula: {},
1091
1142
  bgType: "None",
@@ -99,6 +99,7 @@ const DropMenuSettings = () => {
99
99
  action_style: node.data.props.action_style,
100
100
  action_size: node.data.props.action_size,
101
101
  action_title: node.data.props.action_title,
102
+ action_class: node.data.props.action_class,
102
103
  action_icon: node.data.props.action_icon,
103
104
  action_bgcol: node.data.props.action_bgcol,
104
105
  action_bordercol: node.data.props.action_bordercol,
@@ -182,6 +183,7 @@ DropMenu.craft = {
182
183
  "action_icon",
183
184
  "action_bgcol",
184
185
  "action_title",
186
+ "action_class",
185
187
  "action_bordercol",
186
188
  "action_textcol",
187
189
  "menu_direction",
@@ -18,6 +18,7 @@ import {
18
18
  OrFormula,
19
19
  setAPropGen,
20
20
  buildOptions,
21
+ SettingsRow,
21
22
  } from "./utils";
22
23
 
23
24
  export /**
@@ -38,21 +39,19 @@ const Image = ({ fileid, block, srctype, url, alt, style }) => {
38
39
  connectors: { connect, drag },
39
40
  } = useNode((node) => ({ selected: node.events.selected }));
40
41
  const theurl = srctype === "File" ? `/files/serve/${fileid}` : url;
41
- return (
42
- <span {...blockProps(block)} ref={(dom) => connect(drag(dom))}>
43
- {fileid === 0 ? (
44
- "No images Available"
45
- ) : (
46
- <img
47
- className={`${style && style.width ? "" : "w-100"} image-widget ${
48
- selected ? "selected-node" : ""
49
- }`}
50
- style={reactifyStyles(style || {})}
51
- src={theurl}
52
- alt={alt}
53
- ></img>
54
- )}
55
- </span>
42
+ return fileid === 0 ? (
43
+ <span>No images Available</span>
44
+ ) : (
45
+ <img
46
+ {...blockProps(block)}
47
+ ref={(dom) => connect(drag(dom))}
48
+ className={`${style && style.width ? "" : "w-100"} image-widget ${
49
+ selected ? "selected-node" : ""
50
+ }`}
51
+ style={reactifyStyles(style || {})}
52
+ src={theurl}
53
+ alt={alt}
54
+ ></img>
56
55
  );
57
56
  };
58
57
 
@@ -274,6 +273,17 @@ const ImageSettings = () => {
274
273
  </td>
275
274
  </tr>
276
275
  )}
276
+ <SettingsRow
277
+ field={{
278
+ name: "object-fit",
279
+ label: "Object fit",
280
+ type: "select",
281
+ options: ["none", "fill", "contain", "cover", "scale-down"],
282
+ }}
283
+ node={node}
284
+ setProp={setProp}
285
+ isStyle={true}
286
+ />
277
287
  {srctype !== "Upload" && (
278
288
  <tr>
279
289
  <td colSpan="2">
@@ -108,6 +108,7 @@ const LinkSettings = () => {
108
108
  link_style: node.data.props.link_style,
109
109
  link_size: node.data.props.link_size,
110
110
  link_title: node.data.props.link_title,
111
+ link_class: node.data.props.link_class,
111
112
  link_icon: node.data.props.link_icon,
112
113
  link_bgcol: node.data.props.link_bgcol,
113
114
  link_bordercol: node.data.props.link_bordercol,
@@ -392,6 +393,7 @@ Link.craft = {
392
393
  "link_icon",
393
394
  "link_style",
394
395
  "link_title",
396
+ "link_class",
395
397
  "link_bgcol",
396
398
  "link_bordercol",
397
399
  "link_textcol",
@@ -114,6 +114,7 @@ const ViewLinkSettings = () => {
114
114
  link_size: node.data.props.link_size,
115
115
  link_icon: node.data.props.link_icon,
116
116
  link_title: node.data.props.link_title,
117
+ link_class: node.data.props.link_class,
117
118
  textStyle: node.data.props.textStyle,
118
119
  link_bgcol: node.data.props.link_bgcol,
119
120
  link_bordercol: node.data.props.link_bordercol,
@@ -403,6 +404,7 @@ ViewLink.craft = {
403
404
  "link_icon",
404
405
  "link_size",
405
406
  "link_title",
407
+ "link_class",
406
408
  "link_target_blank",
407
409
  "link_bgcol",
408
410
  "link_bordercol",
@@ -993,6 +993,8 @@ const ConfigField = ({
993
993
  className={`field-${field?.name} form-control`}
994
994
  value={value || ""}
995
995
  step={0.01}
996
+ max={or_if_undef(field?.attributes?.max, undefined)}
997
+ min={or_if_undef(field?.attributes?.min, undefined)}
996
998
  onChange={(e) => e.target && myOnChange(e.target.value)}
997
999
  />
998
1000
  ),
@@ -1543,18 +1545,32 @@ const ButtonOrLinkSettingsRows = ({
1543
1545
  ]
1544
1546
  : []),
1545
1547
  values[keyPrefix + "style"] !== "on_page_load" ? (
1546
- <tr key="btntitle">
1547
- <td>
1548
- <label>Hover title</label>
1549
- </td>
1550
- <td>
1551
- <input
1552
- className="form-control"
1553
- value={values[keyPrefix + "title"]}
1554
- onChange={setAProp(keyPrefix + "title")}
1555
- />
1556
- </td>
1557
- </tr>
1548
+ <Fragment>
1549
+ <tr key="btntitle">
1550
+ <td>
1551
+ <label>Hover title</label>
1552
+ </td>
1553
+ <td>
1554
+ <input
1555
+ className="form-control linkoractiontitle"
1556
+ value={values[keyPrefix + "title"]}
1557
+ onChange={setAProp(keyPrefix + "title")}
1558
+ />
1559
+ </td>
1560
+ </tr>
1561
+ <tr key="btnclass">
1562
+ <td>
1563
+ <label>Class</label>
1564
+ </td>
1565
+ <td>
1566
+ <input
1567
+ className="form-control linkoractionclass"
1568
+ value={values[keyPrefix + "class"]}
1569
+ onChange={setAProp(keyPrefix + "class")}
1570
+ />
1571
+ </td>
1572
+ </tr>
1573
+ </Fragment>
1558
1574
  ) : null,
1559
1575
  ];
1560
1576
  };
@@ -194,6 +194,7 @@ const layoutToNodes = (
194
194
  action_size={segment.action_size || ""}
195
195
  action_icon={segment.action_icon || ""}
196
196
  action_title={segment.action_title || ""}
197
+ action_class={segment.action_class || ""}
197
198
  action_bgcol={segment.action_bgcol || ""}
198
199
  action_bordercol={segment.action_bordercol || ""}
199
200
  action_textcol={segment.action_textcol || ""}
@@ -255,6 +256,7 @@ const layoutToNodes = (
255
256
  : segment.fullPageWidth
256
257
  }
257
258
  bgFileId={segment.bgFileId}
259
+ bgField={segment.bgField}
258
260
  imageSize={segment.imageSize || "contain"}
259
261
  imgResponsiveWidths={segment.imgResponsiveWidths}
260
262
  bgType={segment.bgType || "None"}
@@ -544,6 +546,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
544
546
  display: node.props.display,
545
547
  fullPageWidth: node.props.fullPageWidth || false,
546
548
  bgFileId: node.props.bgFileId,
549
+ bgField: node.props.bgField,
547
550
  bgType: node.props.bgType,
548
551
  imageSize: node.props.imageSize,
549
552
  imgResponsiveWidths: node.props.imgResponsiveWidths,
@@ -683,6 +686,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
683
686
  action_size: node.props.action_size,
684
687
  action_icon: node.props.action_icon,
685
688
  action_title: node.props.action_title,
689
+ action_class: node.props.action_class,
686
690
  action_bgcol: node.props.action_bgcol,
687
691
  action_bordercol: node.props.action_bordercol,
688
692
  action_textcol: node.props.action_textcol,
@@ -715,7 +719,9 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
715
719
  action_size: node.props.action_size,
716
720
  action_icon: node.props.action_icon,
717
721
  action_title: node.props.action_title,
722
+ action_class: node.props.action_class,
718
723
  action_bgcol: node.props.action_bgcol,
724
+ spinner: node.props.spinner,
719
725
  action_bordercol: node.props.action_bordercol,
720
726
  action_textcol: node.props.action_textcol,
721
727
  nsteps: node.props.nsteps,