@saltcorn/builder 0.6.4-beta.1 → 0.6.4-beta.2

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.6.4-beta.1",
3
+ "version": "0.6.4-beta.2",
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",
@@ -382,6 +382,7 @@ const JoinFieldElem = ({ connectors, options }) => (
382
382
  >
383
383
  <JoinField
384
384
  name={options.parent_field_list[0]}
385
+ configuration={{}}
385
386
  textStyle={""}
386
387
  block={false}
387
388
  />
@@ -621,6 +622,9 @@ const ToolboxEdit = () => {
621
622
  <HTMLElem connectors={connectors} />
622
623
  <ViewElem connectors={connectors} views={views} />
623
624
  </div>
625
+ <div className="toolbar-row">
626
+ <JoinFieldElem connectors={connectors} options={options} />
627
+ </div>
624
628
  </Fragment>
625
629
  );
626
630
  };
@@ -12,7 +12,7 @@ Copyright (c) 2017 Taha Paksu
12
12
  */
13
13
 
14
14
  export /**
15
- *
15
+ *
16
16
  * @param {object} props
17
17
  * @param {function} props.setProp
18
18
  * @param {object} props.node
@@ -21,7 +21,7 @@ export /**
21
21
  * @subcategory components
22
22
  * @namespace
23
23
  */
24
- const BoxModelEditor = ({ setProp, node }) => {
24
+ const BoxModelEditor = ({ setProp, node, sizeWithStyle }) => {
25
25
  const [selectedCategory, setSelectedCategory] = useState(false);
26
26
  const [selectedDirection, setSelectedDirection] = useState(false);
27
27
  const selectedProperty = !selectedCategory
@@ -146,7 +146,9 @@ const BoxModelEditor = ({ setProp, node }) => {
146
146
  name="boxmodel-ex-1_width"
147
147
  size="3"
148
148
  value={
149
- node.width
149
+ sizeWithStyle
150
+ ? style["width"]
151
+ : node.width
150
152
  ? `${node.width}${node.widthUnits || "px"}`
151
153
  : ""
152
154
  }
@@ -159,7 +161,9 @@ const BoxModelEditor = ({ setProp, node }) => {
159
161
  name="boxmodel-ex-1_height"
160
162
  size="3"
161
163
  value={
162
- node.height
164
+ sizeWithStyle
165
+ ? style["height"]
166
+ : node.height
163
167
  ? `${node.height}${node.heightUnits || "px"}`
164
168
  : ""
165
169
  }
@@ -271,20 +275,23 @@ const BoxModelEditor = ({ setProp, node }) => {
271
275
  field={{ name: "width", label: "width", type: "DimUnits" }}
272
276
  node={node}
273
277
  setProp={setProp}
278
+ isStyle={!!sizeWithStyle}
274
279
  />
275
280
  <SettingsRow
276
281
  field={{ name: "height", label: "height", type: "DimUnits" }}
277
282
  node={node}
278
283
  setProp={setProp}
284
+ isStyle={!!sizeWithStyle}
279
285
  />
280
286
  <SettingsRow
281
287
  field={{
282
- name: "minHeight",
288
+ name: sizeWithStyle ? "min-height" : "minHeight",
283
289
  label: "min height",
284
290
  type: "DimUnits",
285
291
  }}
286
292
  node={node}
287
293
  setProp={setProp}
294
+ isStyle={!!sizeWithStyle}
288
295
  />
289
296
  </Fragment>
290
297
  )}
@@ -19,20 +19,13 @@ export /**
19
19
  * @param {string} [props.title]
20
20
  * @param {string} props.shadow
21
21
  * @param {boolean} props.noPadding
22
- * @param {object} props.style
22
+ * @param {object} props.style
23
23
  * @returns {div}
24
24
  * @category saltcorn-builder
25
25
  * @subcategory components
26
26
  * @namespace
27
27
  */
28
- const Card = ({
29
- children,
30
- isFormula,
31
- title,
32
- shadow,
33
- noPadding,
34
- style,
35
- }) => {
28
+ const Card = ({ children, isFormula, title, shadow, noPadding, style }) => {
36
29
  const {
37
30
  selected,
38
31
  connectors: { connect, drag },
@@ -119,7 +112,7 @@ const CardSettings = () => {
119
112
  </tbody>
120
113
  </table>
121
114
  <div accordiontitle="Box" className="w-100">
122
- <BoxModelEditor setProp={setProp} node={node} />
115
+ <BoxModelEditor setProp={setProp} node={node} sizeWithStyle={true} />
123
116
  </div>
124
117
  </Accordion>
125
118
  );
@@ -138,8 +131,8 @@ const fields = [
138
131
  { name: "style", default: {} },
139
132
  ];
140
133
 
141
- /**
142
- * @type {object}
134
+ /**
135
+ * @type {object}
143
136
  */
144
137
  Card.craft = {
145
138
  props: {
@@ -8,11 +8,13 @@ import React, { Fragment } from "react";
8
8
  import { Column } from "./Column";
9
9
 
10
10
  import { Element, useNode } from "@craftjs/core";
11
+ import { Accordion, reactifyStyles } from "./utils";
12
+ import { BoxModelEditor } from "./BoxModelEditor";
11
13
 
12
14
  export /**
13
- *
14
- * @param {number} n
15
- * @param {function} f
15
+ *
16
+ * @param {number} n
17
+ * @param {function} f
16
18
  * @returns {object[]}
17
19
  */
18
20
  const ntimes = (n, f) => {
@@ -24,8 +26,8 @@ const ntimes = (n, f) => {
24
26
  };
25
27
 
26
28
  export /**
27
- *
28
- * @param {number[]} xs
29
+ *
30
+ * @param {number[]} xs
29
31
  * @returns {number}
30
32
  */
31
33
  const sum = (xs) => {
@@ -35,14 +37,14 @@ const sum = (xs) => {
35
37
  };
36
38
 
37
39
  /**
38
- * @param {number} ncols
40
+ * @param {number} ncols
39
41
  * @returns {number}
40
42
  */
41
43
  const resetWidths = (ncols) => ntimes(ncols - 1, () => 12 / ncols);
42
44
 
43
45
  /**
44
- * @param {number[]} widths
45
- * @param {number} colix
46
+ * @param {number[]} widths
47
+ * @param {number} colix
46
48
  * @returns {number}
47
49
  */
48
50
  const getWidth = (widths, colix) =>
@@ -58,7 +60,7 @@ export /**
58
60
  * @category saltcorn-builder
59
61
  * @subcategory components
60
62
  */
61
- const Columns = ({ widths, contents, ncols }) => {
63
+ const Columns = ({ widths, contents, ncols, style }) => {
62
64
  const {
63
65
  selected,
64
66
  connectors: { connect, drag },
@@ -67,6 +69,7 @@ const Columns = ({ widths, contents, ncols }) => {
67
69
  <div
68
70
  className={`row ${selected ? "selected-node" : ""}`}
69
71
  ref={(dom) => connect(drag(dom))}
72
+ style={reactifyStyles(style || {})}
70
73
  >
71
74
  {ntimes(ncols, (ix) => (
72
75
  <div key={ix} className={`split-col col-sm-${getWidth(widths, ix)}`}>
@@ -86,19 +89,22 @@ export /**
86
89
  * @subcategory components
87
90
  */
88
91
  const ColumnsSettings = () => {
92
+ const node = useNode((node) => ({
93
+ widths: node.data.props.widths,
94
+ ncols: node.data.props.ncols,
95
+ breakpoints: node.data.props.breakpoints,
96
+ style: node.data.props.style,
97
+ }));
89
98
  const {
90
99
  actions: { setProp },
91
100
  widths,
92
101
  ncols,
93
102
  breakpoints,
94
- } = useNode((node) => ({
95
- widths: node.data.props.widths,
96
- ncols: node.data.props.ncols,
97
- breakpoints: node.data.props.breakpoints,
98
- }));
103
+ style,
104
+ } = node;
99
105
  return (
100
- <div>
101
- <table>
106
+ <Accordion>
107
+ <table accordiontitle="Column properties">
102
108
  <tbody>
103
109
  <tr>
104
110
  <td colSpan="3">
@@ -171,18 +177,22 @@ const ColumnsSettings = () => {
171
177
  ))}
172
178
  </tbody>
173
179
  </table>
174
- </div>
180
+ <div accordiontitle="Box" className="w-100">
181
+ <BoxModelEditor setProp={setProp} node={node} sizeWithStyle={true} />
182
+ </div>
183
+ </Accordion>
175
184
  );
176
185
  };
177
186
 
178
- /**
179
- * @type {object}
187
+ /**
188
+ * @type {object}
180
189
  */
181
190
  Columns.craft = {
182
191
  displayName: "Columns",
183
192
  defaultProps: {
184
193
  widths: [6],
185
194
  ncols: 2,
195
+ style: {},
186
196
  breakpoints: ["sm", "sm"],
187
197
  },
188
198
  related: {
@@ -8,8 +8,15 @@ import React, { useContext, Fragment } from "react";
8
8
  import { useNode } from "@craftjs/core";
9
9
  import optionsCtx from "../context";
10
10
  import previewCtx from "../preview_context";
11
+ import { BoxModelEditor } from "./BoxModelEditor";
11
12
 
12
- import { blockProps, BlockSetting, TextStyleSetting, OrFormula } from "./utils";
13
+ import {
14
+ blockProps,
15
+ BlockSetting,
16
+ reactifyStyles,
17
+ Accordion,
18
+ OrFormula,
19
+ } from "./utils";
13
20
 
14
21
  export /**
15
22
  * @param {object} props
@@ -23,7 +30,7 @@ export /**
23
30
  * @category saltcorn-builder
24
31
  * @subcategory components
25
32
  */
26
- const Image = ({ fileid, block, srctype, url, alt }) => {
33
+ const Image = ({ fileid, block, srctype, url, alt, style }) => {
27
34
  const {
28
35
  selected,
29
36
  connectors: { connect, drag },
@@ -35,7 +42,10 @@ const Image = ({ fileid, block, srctype, url, alt }) => {
35
42
  "No images Available"
36
43
  ) : (
37
44
  <img
38
- className={`w-100 image-widget ${selected ? "selected-node" : ""}`}
45
+ className={`${style && style.width ? "" : "w-100"} image-widget ${
46
+ selected ? "selected-node" : ""
47
+ }`}
48
+ style={reactifyStyles(style || {})}
39
49
  src={theurl}
40
50
  alt={alt}
41
51
  ></img>
@@ -59,6 +69,7 @@ const ImageSettings = () => {
59
69
  srctype: node.data.props.srctype,
60
70
  alt: node.data.props.alt,
61
71
  block: node.data.props.block,
72
+ style: node.data.props.style,
62
73
  isFormula: node.data.props.isFormula,
63
74
  }));
64
75
  const {
@@ -71,6 +82,7 @@ const ImageSettings = () => {
71
82
  block,
72
83
  isFormula,
73
84
  filepath,
85
+ style,
74
86
  } = node;
75
87
  const options = useContext(optionsCtx);
76
88
  const { uploadedFiles, setUploadedFiles } = useContext(previewCtx);
@@ -113,141 +125,146 @@ const ImageSettings = () => {
113
125
  }
114
126
  };
115
127
  return (
116
- <table>
117
- <tbody>
118
- <tr>
119
- <td colSpan="2">
120
- <i>
121
- <small>Preview shown in canvas is indicative</small>
122
- </i>
123
- </td>
124
- </tr>
125
- <tr>
126
- <td>
127
- <label>Source</label>
128
- </td>
129
- <td>
130
- <select
131
- value={srctype}
132
- className="form-control"
133
- onChange={setAProp("srctype")}
134
- >
135
- <option>File</option>
136
- <option>URL</option>
137
- <option>Upload</option>
138
- {options.mode === "show" && <option>Field</option>}
139
- </select>
140
- </td>
141
- </tr>
142
- {srctype === "File" && (
128
+ <Accordion>
129
+ <table accordiontitle="Select image">
130
+ <tbody>
143
131
  <tr>
144
- <td>
145
- <label>File</label>
146
- </td>
147
- <td>
148
- <select
149
- value={fileid}
150
- className="form-control"
151
- onChange={setAProp("fileid")}
152
- >
153
- {options.images.map((f, ix) => (
154
- <option key={ix} value={f.id}>
155
- {f.filename}
156
- </option>
157
- ))}
158
- {(uploadedFiles || []).map((uf, ix) => (
159
- <option key={ix} value={uf.id}>
160
- {uf.filename}
161
- </option>
162
- ))}
163
- </select>
164
- </td>
165
- </tr>
166
- )}
167
- {srctype === "URL" && (
168
- <tr>
169
- <td>
170
- <label>URL</label>
171
- </td>
172
- <td>
173
- <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
174
- <input
175
- type="text"
176
- className="form-control"
177
- value={url}
178
- onChange={setAProp("url")}
179
- />
180
- </OrFormula>
181
- </td>
182
- </tr>
183
- )}
184
- {srctype === "Upload" && (
185
- <tr>
186
- <td>
187
- <label>File</label>
188
- </td>
189
- <td>
190
- <input
191
- type="file"
192
- className="form-control"
193
- value={filepath}
194
- onChange={handleUpload}
195
- />
132
+ <td colSpan="2">
133
+ <i>
134
+ <small>Preview shown in canvas is indicative</small>
135
+ </i>
196
136
  </td>
197
137
  </tr>
198
- )}
199
- {srctype === "Field" && (
200
138
  <tr>
201
139
  <td>
202
- <label>Field</label>
140
+ <label>Source</label>
203
141
  </td>
204
142
  <td>
205
143
  <select
206
- value={field}
144
+ value={srctype}
207
145
  className="form-control"
208
- onChange={setAProp("field")}
146
+ onChange={setAProp("srctype")}
209
147
  >
210
- {options.fields
211
- .filter(
212
- (f) =>
213
- (f.type && f.type.name === "String") ||
214
- f.reftable_name === "_sc_files"
215
- )
216
- .map((f, ix) => (
217
- <option key={ix} value={f.name}>
218
- {f.label}
219
- </option>
220
- ))}
148
+ <option>File</option>
149
+ <option>URL</option>
150
+ <option>Upload</option>
151
+ {options.mode === "show" && <option>Field</option>}
221
152
  </select>
222
153
  </td>
223
154
  </tr>
224
- )}
225
- {srctype !== "Upload" && (
226
- <tr>
227
- <td>
228
- <label>Alt text</label>
229
- </td>
230
- <td>
231
- <OrFormula nodekey="alt" {...{ setProp, isFormula, node }}>
155
+ {srctype === "File" && (
156
+ <tr>
157
+ <td>
158
+ <label>File</label>
159
+ </td>
160
+ <td>
161
+ <select
162
+ value={fileid}
163
+ className="form-control"
164
+ onChange={setAProp("fileid")}
165
+ >
166
+ {options.images.map((f, ix) => (
167
+ <option key={ix} value={f.id}>
168
+ {f.filename}
169
+ </option>
170
+ ))}
171
+ {(uploadedFiles || []).map((uf, ix) => (
172
+ <option key={ix} value={uf.id}>
173
+ {uf.filename}
174
+ </option>
175
+ ))}
176
+ </select>
177
+ </td>
178
+ </tr>
179
+ )}
180
+ {srctype === "URL" && (
181
+ <tr>
182
+ <td>
183
+ <label>URL</label>
184
+ </td>
185
+ <td>
186
+ <OrFormula nodekey="url" {...{ setProp, isFormula, node }}>
187
+ <input
188
+ type="text"
189
+ className="form-control"
190
+ value={url}
191
+ onChange={setAProp("url")}
192
+ />
193
+ </OrFormula>
194
+ </td>
195
+ </tr>
196
+ )}
197
+ {srctype === "Upload" && (
198
+ <tr>
199
+ <td>
200
+ <label>File</label>
201
+ </td>
202
+ <td>
232
203
  <input
233
- type="text"
204
+ type="file"
234
205
  className="form-control"
235
- value={alt}
236
- onChange={setAProp("alt")}
206
+ value={filepath}
207
+ onChange={handleUpload}
237
208
  />
238
- </OrFormula>
239
- </td>
240
- </tr>
241
- )}
242
- {srctype !== "Upload" && (
243
- <tr>
244
- <td colSpan="2">
245
- <BlockSetting block={block} setProp={setProp} />
246
- </td>
247
- </tr>
248
- )}
249
- </tbody>
250
- </table>
209
+ </td>
210
+ </tr>
211
+ )}
212
+ {srctype === "Field" && (
213
+ <tr>
214
+ <td>
215
+ <label>Field</label>
216
+ </td>
217
+ <td>
218
+ <select
219
+ value={field}
220
+ className="form-control"
221
+ onChange={setAProp("field")}
222
+ >
223
+ {options.fields
224
+ .filter(
225
+ (f) =>
226
+ (f.type && f.type.name === "String") ||
227
+ f.reftable_name === "_sc_files"
228
+ )
229
+ .map((f, ix) => (
230
+ <option key={ix} value={f.name}>
231
+ {f.label}
232
+ </option>
233
+ ))}
234
+ </select>
235
+ </td>
236
+ </tr>
237
+ )}
238
+ {srctype !== "Upload" && (
239
+ <tr>
240
+ <td>
241
+ <label>Alt text</label>
242
+ </td>
243
+ <td>
244
+ <OrFormula nodekey="alt" {...{ setProp, isFormula, node }}>
245
+ <input
246
+ type="text"
247
+ className="form-control"
248
+ value={alt}
249
+ onChange={setAProp("alt")}
250
+ />
251
+ </OrFormula>
252
+ </td>
253
+ </tr>
254
+ )}
255
+ {srctype !== "Upload" && (
256
+ <tr>
257
+ <td colSpan="2">
258
+ <BlockSetting block={block} setProp={setProp} />
259
+ </td>
260
+ </tr>
261
+ )}
262
+ </tbody>
263
+ </table>
264
+ <div accordiontitle="Box" className="w-100">
265
+ <BoxModelEditor setProp={setProp} node={node} sizeWithStyle={true} />
266
+ </div>
267
+ </Accordion>
251
268
  );
252
269
  };
253
270
 
@@ -261,6 +278,7 @@ Image.craft = {
261
278
  block: false,
262
279
  isFormula: {},
263
280
  srctype: "File",
281
+ style: {},
264
282
  },
265
283
  related: {
266
284
  settings: ImageSettings,
@@ -272,6 +290,7 @@ Image.craft = {
272
290
  { name: "fileid", default: 0 },
273
291
  "field",
274
292
  "block",
293
+ { name: "style", default: {} },
275
294
  ],
276
295
  },
277
296
  };
@@ -11,6 +11,7 @@ import {
11
11
  blockProps,
12
12
  BlockSetting,
13
13
  TextStyleRow,
14
+ ConfigForm,
14
15
  fetchFieldPreview,
15
16
  } from "./utils";
16
17
  import previewCtx from "../preview_context";
@@ -76,6 +77,7 @@ const JoinFieldSettings = () => {
76
77
  name,
77
78
  block,
78
79
  textStyle,
80
+ configuration,
79
81
  fieldview,
80
82
  node_id,
81
83
  } = useNode((node) => ({
@@ -83,17 +85,22 @@ const JoinFieldSettings = () => {
83
85
  block: node.data.props.block,
84
86
  textStyle: node.data.props.textStyle,
85
87
  fieldview: node.data.props.fieldview,
88
+ configuration: node.data.props.configuration,
89
+
86
90
  node_id: node.id,
87
91
  }));
88
92
  const options = useContext(optionsCtx);
89
93
  const { setPreviews } = useContext(previewCtx);
90
94
 
91
95
  const fvs = options.field_view_options[name];
96
+ const getCfgFields = (fv) =>
97
+ ((options.fieldViewConfigForms || {})[name] || {})[fv];
98
+ const cfgFields = getCfgFields(fieldview);
92
99
  const refetchPreview = fetchFieldPreview({
93
100
  options,
94
101
  name,
95
102
  fieldview,
96
- configuration: {},
103
+ configuration,
97
104
  setPreviews,
98
105
  node_id,
99
106
  });
@@ -167,6 +174,14 @@ const JoinFieldSettings = () => {
167
174
  <TextStyleRow textStyle={textStyle} setProp={setProp} />
168
175
  </tbody>
169
176
  </table>
177
+ {cfgFields ? (
178
+ <ConfigForm
179
+ fields={cfgFields}
180
+ configuration={configuration || {}}
181
+ setProp={setProp}
182
+ onChange={(k, v) => refetchPreview({ configuration: { [k]: v } })}
183
+ />
184
+ ) : null}
170
185
  </Fragment>
171
186
  );
172
187
  };
@@ -185,6 +200,7 @@ JoinField.craft = {
185
200
  "fieldview",
186
201
  "textStyle",
187
202
  "block",
203
+ { name: "configuration", default: {} },
188
204
  ],
189
205
  },
190
206
  };
@@ -236,6 +236,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
236
236
  breakpoints={segment.breakpoints || default_breakpoints(segment)}
237
237
  ncols={segment.besides.length}
238
238
  widths={getColWidths(segment)}
239
+ style={segment.style || {}}
239
240
  contents={segment.besides.map(toTag)}
240
241
  />
241
242
  );
@@ -262,6 +263,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
262
263
  widths={getColWidths(segment)}
263
264
  breakpoints={segment.breakpoints || default_breakpoints(segment)}
264
265
  ncols={segment.besides.length}
266
+ style={segment.style || {}}
265
267
  contents={segment.besides.map(toTag)}
266
268
  />
267
269
  )
@@ -402,6 +404,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
402
404
  return {
403
405
  besides: widths.map((w, ix) => go(nodes[node.linkedNodes["Col" + ix]])),
404
406
  breakpoints: node.props.breakpoints,
407
+ style: node.props.style,
405
408
  widths,
406
409
  };
407
410
  }