@saltcorn/builder 0.7.1 → 0.7.2-beta.3

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": "0.7.1",
3
+ "version": "0.7.2-beta.3",
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",
@@ -279,7 +279,7 @@ const SearchElem = ({ connectors }) => (
279
279
  title="Search bar"
280
280
  label="Search"
281
281
  >
282
- <SearchBar />
282
+ <Element canvas is={SearchBar}></Element>
283
283
  </WrapElem>
284
284
  );
285
285
  /**
@@ -165,7 +165,7 @@ const ActionSettings = () => {
165
165
  <MinRoleSettingRow minRole={minRole} setProp={setProp} />
166
166
  </tbody>
167
167
  </table>
168
- {options.mode === "show" ? (
168
+ {options.mode === "show" || name === "Delete" || name === "Reset" ? (
169
169
  <div className="form-check">
170
170
  <input
171
171
  className="form-check-input"
@@ -41,7 +41,7 @@ const Card = ({ children, isFormula, title, shadow, noPadding, style }) => {
41
41
  >
42
42
  {title && title.length > 0 && (
43
43
  <div className="card-header">
44
- {isFormula.title ? (
44
+ {isFormula?.title ? (
45
45
  <span className="font-monospace">={title}</span>
46
46
  ) : (
47
47
  title
@@ -229,6 +229,7 @@ const ContainerSettings = () => {
229
229
  rotate: node.data.props.rotate,
230
230
  display: node.data.props.display,
231
231
  style: node.data.props.style,
232
+ imgResponsiveWidths: node.data.props.imgResponsiveWidths,
232
233
  }));
233
234
  const {
234
235
  actions: { setProp },
@@ -257,6 +258,7 @@ const ContainerSettings = () => {
257
258
  fullPageWidth,
258
259
  overflow,
259
260
  htmlElement,
261
+ imgResponsiveWidths,
260
262
  } = node;
261
263
  const options = useContext(optionsCtx);
262
264
  const { uploadedFiles } = useContext(previewCtx);
@@ -520,6 +522,26 @@ const ContainerSettings = () => {
520
522
  </select>
521
523
  </td>
522
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
+ )}
523
545
  </Fragment>
524
546
  )}
525
547
  {bgType === "Color" && (
@@ -71,6 +71,7 @@ const ImageSettings = () => {
71
71
  block: node.data.props.block,
72
72
  style: node.data.props.style,
73
73
  isFormula: node.data.props.isFormula,
74
+ imgResponsiveWidths: node.data.props.imgResponsiveWidths,
74
75
  }));
75
76
  const {
76
77
  actions: { setProp },
@@ -82,6 +83,7 @@ const ImageSettings = () => {
82
83
  block,
83
84
  isFormula,
84
85
  filepath,
86
+ imgResponsiveWidths,
85
87
  style,
86
88
  } = node;
87
89
  const options = useContext(optionsCtx);
@@ -252,6 +254,27 @@ const ImageSettings = () => {
252
254
  </td>
253
255
  </tr>
254
256
  )}
257
+ {srctype !== "Upload" && (
258
+ <tr>
259
+ <td>
260
+ <label>Responsive widths</label>
261
+ </td>
262
+
263
+ <td>
264
+ <input
265
+ type="text"
266
+ value={imgResponsiveWidths}
267
+ className="form-control"
268
+ onChange={setAProp("imgResponsiveWidths")}
269
+ />
270
+ <small>
271
+ <i>
272
+ List of widths to serve resized images, e.g. 300, 400, 600
273
+ </i>
274
+ </small>
275
+ </td>
276
+ </tr>
277
+ )}
255
278
  {srctype !== "Upload" && (
256
279
  <tr>
257
280
  <td colSpan="2">
@@ -290,6 +313,7 @@ Image.craft = {
290
313
  { name: "fileid", default: 0 },
291
314
  "field",
292
315
  "block",
316
+ "imgResponsiveWidths",
293
317
  { name: "style", default: {} },
294
318
  ],
295
319
  },
@@ -53,7 +53,7 @@ const Link = ({
53
53
  <span
54
54
  className={`${textStyle} is-builder-link ${
55
55
  selected ? "selected-node" : ""
56
- } ${isFormula.text ? "font-monospace" : ""} ${link_style} ${link_size}`}
56
+ } ${isFormula?.text ? "font-monospace" : ""} ${link_style} ${link_size}`}
57
57
  {...blockProps(block)}
58
58
  ref={(dom) => connect(drag(dom))}
59
59
  style={
@@ -67,7 +67,7 @@ const Link = ({
67
67
  }
68
68
  >
69
69
  <DynamicFontAwesomeIcon icon={link_icon} className="me-1" />
70
- {isFormula.text ? `=${text}` : text}
70
+ {isFormula?.text ? `=${text}` : text}
71
71
  </span>
72
72
  );
73
73
  };
@@ -88,35 +88,60 @@ const Tabs = ({ contents, titles, tabsStyle, ntabs, independent, field }) => {
88
88
  } builder ${selected ? "selected-node" : ""}`}
89
89
  ref={(dom) => connect(drag(dom))}
90
90
  >
91
- {ntimes(ntabs, (ix) => (
92
- <li key={ix} className="nav-item" role="presentation">
93
- <a
94
- className={`nav-link ${ix === showTab ? `active` : ""}`}
95
- onClick={() => setShowTab(ix)}
96
- >
97
- {titles[ix] &&
98
- (typeof titles[ix].label === "undefined"
99
- ? titles[ix]
100
- : titles[ix].label === ""
101
- ? "(empty)"
102
- : titles[ix].label)}
103
- </a>
104
- </li>
105
- ))}
91
+ {ntimes(ntabs, (ix) => {
92
+ if (!titles[ix]) return null;
93
+ const targetIx =
94
+ typeof titles[ix].value === "undefined" ? ix : titles[ix].value;
95
+ return (
96
+ <li key={ix} className="nav-item" role="presentation">
97
+ <a
98
+ className={`nav-link ${targetIx === showTab ? `active` : ""}`}
99
+ onClick={() => setShowTab(targetIx)}
100
+ >
101
+ {titles[ix] &&
102
+ (typeof titles[ix].label === "undefined"
103
+ ? titles[ix]
104
+ : titles[ix].label === ""
105
+ ? "(empty)"
106
+ : titles[ix].label)}
107
+ </a>
108
+ </li>
109
+ );
110
+ })}
106
111
  </ul>
107
112
  <div className="tab-content" id="myTabContent">
108
- {ntimes(ntabs, (ix) => (
109
- <div
110
- key={ix}
111
- className={`tab-pane fade ${ix === showTab ? `show active` : ""}`}
112
- role="tabpanel"
113
- aria-labelledby="home-tab"
114
- >
115
- <Element canvas id={`Tab${ix}`} is={Column}>
116
- {contents[ix]}
117
- </Element>
118
- </div>
119
- ))}
113
+ {ntimes(ntabs, (ix) => {
114
+ if (!titles[ix]) return null;
115
+
116
+ const useIx =
117
+ typeof titles[ix].value === "undefined" ? ix : titles[ix].value;
118
+
119
+ if (useIx !== showTab)
120
+ return (
121
+ <div className="d-none" key={ix}>
122
+ <Element canvas id={`Tab${useIx}`} is={Column}>
123
+ {contents[useIx]}
124
+ </Element>
125
+ </div>
126
+ );
127
+ //d-none display of useIx is bug workaround? needed
128
+ else
129
+ return (
130
+ <div
131
+ key={ix}
132
+ className={`tab-pane fade ${
133
+ useIx === showTab ? `show active` : ""
134
+ }`}
135
+ role="tabpanel"
136
+ aria-labelledby="home-tab"
137
+ >
138
+ <div className="d-none">{useIx}</div>
139
+ <Element canvas id={`Tab${useIx}`} is={Column}>
140
+ {contents[useIx]}
141
+ </Element>
142
+ </div>
143
+ );
144
+ })}
120
145
  </div>
121
146
  </Fragment>
122
147
  );
@@ -163,6 +188,7 @@ const TabsSettings = () => {
163
188
  .then(function (data) {
164
189
  if (data.success) {
165
190
  const len = data.success.length;
191
+
166
192
  setProp((prop) => (prop.ntabs = len));
167
193
  setProp((prop) => (prop.titles = data.success));
168
194
  }
@@ -206,6 +206,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
206
206
  }
207
207
  bgFileId={segment.bgFileId}
208
208
  imageSize={segment.imageSize || "contain"}
209
+ imgResponsiveWidths={segment.imgResponsiveWidths}
209
210
  bgType={segment.bgType || "None"}
210
211
  style={segment.style || {}}
211
212
  bgColor={segment.bgColor || "#ffffff"}
@@ -223,6 +224,14 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
223
224
  </Element>
224
225
  );
225
226
  } else if (segment.type === "tabs") {
227
+ let contentsArray = segment.contents.map(toTag);
228
+ let contents;
229
+ if (segment.tabsStyle === "Value switch") {
230
+ contents = {};
231
+ segment.titles.forEach(({ label, value }, ix) => {
232
+ contents[value] = contentsArray[ix];
233
+ });
234
+ } else contents = contentsArray;
226
235
  return (
227
236
  <Tabs
228
237
  key={ix}
@@ -232,7 +241,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
232
241
  deeplink={segment.deeplink}
233
242
  field={segment.field}
234
243
  tabsStyle={segment.tabsStyle}
235
- contents={segment.contents.map(toTag)}
244
+ contents={contents}
236
245
  />
237
246
  );
238
247
  } else if (segment.besides) {
@@ -321,6 +330,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
321
330
  * @returns {object}
322
331
  */
323
332
  const go = (node) => {
333
+ if (!node) return;
324
334
  const matchElement = allElements.find(
325
335
  (e) =>
326
336
  e.craft.related &&
@@ -373,6 +383,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
373
383
  bgFileId: node.props.bgFileId,
374
384
  bgType: node.props.bgType,
375
385
  imageSize: node.props.imageSize,
386
+ imgResponsiveWidths: node.props.imgResponsiveWidths,
376
387
  bgColor: node.props.bgColor,
377
388
  setTextColor: node.props.setTextColor,
378
389
  textColor: node.props.textColor,
@@ -416,11 +427,19 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
416
427
  };
417
428
  }
418
429
  if (node.displayName === Tabs.craft.displayName) {
430
+ let contents;
431
+ if (node.props.tabsStyle === "Value switch") {
432
+ contents = node.props.titles.map(({ value }, ix) => {
433
+ const useIx = typeof value === "undefined" ? ix : value;
434
+ return go(nodes[node.linkedNodes["Tab" + useIx]]);
435
+ });
436
+ } else
437
+ contents = ntimes(node.props.ntabs, (ix) =>
438
+ go(nodes[node.linkedNodes["Tab" + ix]])
439
+ );
419
440
  return {
420
441
  type: "tabs",
421
- contents: ntimes(node.props.ntabs, (ix) =>
422
- go(nodes[node.linkedNodes["Tab" + ix]])
423
- ),
442
+ contents,
424
443
  titles: node.props.titles,
425
444
  tabsStyle: node.props.tabsStyle,
426
445
  field: node.props.field,