@saltcorn/builder 0.7.3-beta.7 → 0.7.4-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.
- package/dist/builder_bundle.js +20 -12
- package/package.json +4 -2
- package/src/components/Builder.js +11 -2
- package/src/components/Library.js +48 -5
- package/src/components/elements/Action.js +9 -12
- package/src/components/elements/Aggregation.js +13 -13
- package/src/components/elements/Columns.js +17 -11
- package/src/components/elements/Container.js +17 -24
- package/src/components/elements/DropDownFilter.js +14 -11
- package/src/components/elements/Field.js +12 -11
- package/src/components/elements/Image.js +3 -7
- package/src/components/elements/JoinField.js +10 -6
- package/src/components/elements/Link.js +12 -22
- package/src/components/elements/SearchBar.js +4 -6
- package/src/components/elements/Tabs.js +13 -26
- package/src/components/elements/Text.js +10 -10
- package/src/components/elements/ToggleFilter.js +11 -14
- package/src/components/elements/View.js +11 -14
- package/src/components/elements/ViewLink.js +9 -11
- package/src/components/elements/utils.js +674 -644
|
@@ -10,11 +10,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
10
10
|
import {
|
|
11
11
|
faChevronDown,
|
|
12
12
|
faChevronRight,
|
|
13
|
+
faInfoCircle
|
|
13
14
|
} from "@fortawesome/free-solid-svg-icons";
|
|
14
15
|
import { useNode, Element } from "@craftjs/core";
|
|
15
16
|
import FontIconPicker from "@fonticonpicker/react-fonticonpicker";
|
|
16
17
|
import faIcons from "./faicons";
|
|
17
18
|
import { Columns, ntimes } from "./Columns";
|
|
19
|
+
import Tippy from '@tippyjs/react';
|
|
18
20
|
|
|
19
21
|
export const DynamicFontAwesomeIcon = ({ icon, className }) => {
|
|
20
22
|
if (!icon) return null;
|
|
@@ -25,8 +27,8 @@ export /**
|
|
|
25
27
|
* @param {boolean} is_block
|
|
26
28
|
* @returns {object}
|
|
27
29
|
*/
|
|
28
|
-
const blockProps = (is_block) =>
|
|
29
|
-
|
|
30
|
+
const blockProps = (is_block) =>
|
|
31
|
+
is_block ? { style: { display: "block" } } : {};
|
|
30
32
|
|
|
31
33
|
export /**
|
|
32
34
|
* @param {object} props
|
|
@@ -37,23 +39,23 @@ export /**
|
|
|
37
39
|
* @subcategory components / elements / utils
|
|
38
40
|
* @namespace
|
|
39
41
|
*/
|
|
40
|
-
const BlockSetting = ({ block, setProp }) => (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
);
|
|
42
|
+
const BlockSetting = ({ block, setProp }) => (
|
|
43
|
+
<div className="form-check">
|
|
44
|
+
<input
|
|
45
|
+
className="form-check-input"
|
|
46
|
+
name="block"
|
|
47
|
+
type="checkbox"
|
|
48
|
+
checked={block}
|
|
49
|
+
onChange={(e) => {
|
|
50
|
+
if (e.target) {
|
|
51
|
+
const target_value = e.target.checked;
|
|
52
|
+
setProp((prop) => (prop.block = target_value));
|
|
53
|
+
}
|
|
54
|
+
}}
|
|
55
|
+
/>
|
|
56
|
+
<label className="form-check-label">Block display</label>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
57
59
|
|
|
58
60
|
export const BlockOrInlineSetting = ({ block, inline, textStyle, setProp }) =>
|
|
59
61
|
!textStyle || !textStyle.startsWith("h") ? (
|
|
@@ -76,6 +78,18 @@ export const BlockOrInlineSetting = ({ block, inline, textStyle, setProp }) =>
|
|
|
76
78
|
</div>
|
|
77
79
|
);
|
|
78
80
|
|
|
81
|
+
export const FormulaTooltip = () => {
|
|
82
|
+
const { fields } = useContext(optionsCtx);
|
|
83
|
+
console.log(fields);
|
|
84
|
+
return <Tooltip>
|
|
85
|
+
<div>Formulae in Saltcorn are JavaScript expressions based on the current database row.</div>
|
|
86
|
+
{fields ? <Fragment> Variables in scope:
|
|
87
|
+
{fields.map((f, ix) => <Fragment><code key={ix}>{f.name}</code>{" "}</Fragment>)}</Fragment> : null}
|
|
88
|
+
|
|
89
|
+
<a className="d-block" href="https://wiki.saltcorn.com/view/ShowPage/formulas">Wiki page on formulas</a>
|
|
90
|
+
</Tooltip>
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
export /**
|
|
80
94
|
* @param {object} props
|
|
81
95
|
* @param {function} props.setProp
|
|
@@ -88,81 +102,83 @@ export /**
|
|
|
88
102
|
* @category saltcorn-builder
|
|
89
103
|
* @subcategory components / elements / utils
|
|
90
104
|
*/
|
|
91
|
-
const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
|
|
92
|
-
|
|
105
|
+
const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
|
|
106
|
+
const { mode } = useContext(optionsCtx);
|
|
93
107
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
/**
|
|
109
|
+
* @returns {void}
|
|
110
|
+
*/
|
|
111
|
+
const switchIsFml = () => {
|
|
112
|
+
const isFmlAfter = !isFormula[nodekey];
|
|
113
|
+
setProp((prop) => {
|
|
114
|
+
prop.isFormula[nodekey] = isFmlAfter;
|
|
115
|
+
if (isFmlAfter && prop[nodekey] && prop[nodekey][0] !== '"') {
|
|
116
|
+
prop[nodekey] = `"${prop[nodekey]}"`;
|
|
117
|
+
} else if (
|
|
118
|
+
!isFmlAfter &&
|
|
119
|
+
typeof prop[nodekey] === "string" &&
|
|
120
|
+
prop[nodekey][0] === '"' &&
|
|
121
|
+
prop[nodekey][prop[nodekey].length - 1] === '"'
|
|
122
|
+
) {
|
|
123
|
+
prop[nodekey] = prop[nodekey].substring(1, prop[nodekey].length - 1);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
let errorString = false;
|
|
128
|
+
if (mode === "show" && isFormula[nodekey]) {
|
|
129
|
+
try {
|
|
130
|
+
Function("return " + node[nodekey]);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
errorString = error.message;
|
|
110
133
|
}
|
|
111
|
-
});
|
|
112
|
-
};
|
|
113
|
-
let errorString = false;
|
|
114
|
-
if (isFormula[nodekey]) {
|
|
115
|
-
try {
|
|
116
|
-
Function("return " + node[nodekey]);
|
|
117
|
-
} catch (error) {
|
|
118
|
-
errorString = error.message;
|
|
119
134
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
)}
|
|
135
|
+
return mode !== "show" ? (
|
|
136
|
+
children
|
|
137
|
+
) : (
|
|
138
|
+
<Fragment>
|
|
139
|
+
<div className="input-group input-group-sm w-100">
|
|
140
|
+
{isFormula[nodekey] ? (
|
|
141
|
+
<input
|
|
142
|
+
type="text"
|
|
143
|
+
className="form-control text-to-display"
|
|
144
|
+
value={node[nodekey] || ""}
|
|
145
|
+
onChange={(e) => {
|
|
146
|
+
if (e.target) {
|
|
147
|
+
const target_value = e.target.value;
|
|
148
|
+
setProp((prop) => (prop[nodekey] = target_value));
|
|
149
|
+
}
|
|
150
|
+
}}
|
|
151
|
+
/>
|
|
152
|
+
) : (
|
|
153
|
+
children
|
|
154
|
+
)}
|
|
141
155
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
</button>
|
|
152
|
-
</div>
|
|
153
|
-
{isFormula[nodekey] && (
|
|
154
|
-
<div style={{ marginTop: "-5px" }}>
|
|
155
|
-
<small className="text-muted font-monospace">FORMULA</small>
|
|
156
|
-
{errorString ? (
|
|
157
|
-
<small className="text-danger font-monospace d-block">
|
|
158
|
-
{errorString}
|
|
159
|
-
</small>
|
|
160
|
-
) : null}
|
|
156
|
+
<button
|
|
157
|
+
className={`btn activate-formula ${isFormula[nodekey] ? "btn-secondary" : "btn-outline-secondary"
|
|
158
|
+
}`}
|
|
159
|
+
title="Calculated formula"
|
|
160
|
+
type="button"
|
|
161
|
+
onClick={switchIsFml}
|
|
162
|
+
>
|
|
163
|
+
<i className="fas fa-calculator"></i>
|
|
164
|
+
</button>
|
|
161
165
|
</div>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
+
{isFormula[nodekey] && (
|
|
167
|
+
<div style={{ marginTop: "-5px" }}>
|
|
168
|
+
<small className="text-muted font-monospace">
|
|
169
|
+
FORMULA
|
|
170
|
+
<FormulaTooltip />
|
|
171
|
+
</small>
|
|
172
|
+
{errorString ? (
|
|
173
|
+
<small className="text-danger font-monospace d-block">
|
|
174
|
+
{errorString}
|
|
175
|
+
</small>
|
|
176
|
+
) : null}
|
|
177
|
+
</div>
|
|
178
|
+
)}
|
|
179
|
+
</Fragment>
|
|
180
|
+
);
|
|
181
|
+
};
|
|
166
182
|
|
|
167
183
|
export /**
|
|
168
184
|
* @param {object} props
|
|
@@ -173,52 +189,15 @@ export /**
|
|
|
173
189
|
* @category saltcorn-builder
|
|
174
190
|
* @subcategory components / elements / utils
|
|
175
191
|
*/
|
|
176
|
-
const MinRoleSetting = ({ minRole, setProp }) => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
<label>Minimum Role</label>
|
|
181
|
-
<select
|
|
182
|
-
className="form-control form-select"
|
|
183
|
-
value={minRole}
|
|
184
|
-
onChange={(e) => (e) => {
|
|
185
|
-
if (e.target) {
|
|
186
|
-
const target_value = e.target.value;
|
|
187
|
-
setProp((prop) => (prop.minRole = target_value));
|
|
188
|
-
}
|
|
189
|
-
}}
|
|
190
|
-
>
|
|
191
|
-
{options.roles.map((r) => (
|
|
192
|
-
<option key={r.id} value={r.id}>
|
|
193
|
-
{r.role}
|
|
194
|
-
</option>
|
|
195
|
-
))}
|
|
196
|
-
</select>
|
|
197
|
-
</div>
|
|
198
|
-
);
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
export /**
|
|
202
|
-
* @param {object} props
|
|
203
|
-
* @param {string} props.minRole
|
|
204
|
-
* @param {function} props.setProp
|
|
205
|
-
* @returns {tr}
|
|
206
|
-
* @namespace
|
|
207
|
-
* @category saltcorn-builder
|
|
208
|
-
* @subcategory components / elements / utils
|
|
209
|
-
*/
|
|
210
|
-
const MinRoleSettingRow = ({ minRole, setProp }) => {
|
|
211
|
-
const options = useContext(optionsCtx);
|
|
212
|
-
return (
|
|
213
|
-
<tr>
|
|
214
|
-
<td>
|
|
192
|
+
const MinRoleSetting = ({ minRole, setProp }) => {
|
|
193
|
+
const options = useContext(optionsCtx);
|
|
194
|
+
return (
|
|
195
|
+
<div>
|
|
215
196
|
<label>Minimum Role</label>
|
|
216
|
-
</td>
|
|
217
|
-
<td>
|
|
218
197
|
<select
|
|
219
|
-
value={minRole}
|
|
220
198
|
className="form-control form-select"
|
|
221
|
-
|
|
199
|
+
value={minRole}
|
|
200
|
+
onChange={(e) => (e) => {
|
|
222
201
|
if (e.target) {
|
|
223
202
|
const target_value = e.target.value;
|
|
224
203
|
setProp((prop) => (prop.minRole = target_value));
|
|
@@ -231,10 +210,47 @@ const MinRoleSettingRow = ({ minRole, setProp }) => {
|
|
|
231
210
|
</option>
|
|
232
211
|
))}
|
|
233
212
|
</select>
|
|
234
|
-
</
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
213
|
+
</div>
|
|
214
|
+
);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export /**
|
|
218
|
+
* @param {object} props
|
|
219
|
+
* @param {string} props.minRole
|
|
220
|
+
* @param {function} props.setProp
|
|
221
|
+
* @returns {tr}
|
|
222
|
+
* @namespace
|
|
223
|
+
* @category saltcorn-builder
|
|
224
|
+
* @subcategory components / elements / utils
|
|
225
|
+
*/
|
|
226
|
+
const MinRoleSettingRow = ({ minRole, setProp }) => {
|
|
227
|
+
const options = useContext(optionsCtx);
|
|
228
|
+
return (
|
|
229
|
+
<tr>
|
|
230
|
+
<td>
|
|
231
|
+
<label>Minimum Role</label>
|
|
232
|
+
</td>
|
|
233
|
+
<td>
|
|
234
|
+
<select
|
|
235
|
+
value={minRole}
|
|
236
|
+
className="form-control form-select"
|
|
237
|
+
onChange={(e) => {
|
|
238
|
+
if (e.target) {
|
|
239
|
+
const target_value = e.target.value;
|
|
240
|
+
setProp((prop) => (prop.minRole = target_value));
|
|
241
|
+
}
|
|
242
|
+
}}
|
|
243
|
+
>
|
|
244
|
+
{options.roles.map((r) => (
|
|
245
|
+
<option key={r.id} value={r.id}>
|
|
246
|
+
{r.role}
|
|
247
|
+
</option>
|
|
248
|
+
))}
|
|
249
|
+
</select>
|
|
250
|
+
</td>
|
|
251
|
+
</tr>
|
|
252
|
+
);
|
|
253
|
+
};
|
|
238
254
|
|
|
239
255
|
/**
|
|
240
256
|
* @param {object} props
|
|
@@ -283,14 +299,14 @@ export /**
|
|
|
283
299
|
* @category saltcorn-builder
|
|
284
300
|
* @subcategory components / elements / utils
|
|
285
301
|
*/
|
|
286
|
-
const TextStyleSetting = ({ textStyle, setProp }) => {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
};
|
|
302
|
+
const TextStyleSetting = ({ textStyle, setProp }) => {
|
|
303
|
+
return (
|
|
304
|
+
<div>
|
|
305
|
+
<label>Text Style</label>
|
|
306
|
+
<TextStyleSelect textStyle={textStyle} setProp={setProp} />
|
|
307
|
+
</div>
|
|
308
|
+
);
|
|
309
|
+
};
|
|
294
310
|
|
|
295
311
|
export /**
|
|
296
312
|
* @param {object} props
|
|
@@ -301,18 +317,18 @@ export /**
|
|
|
301
317
|
* @category saltcorn-builder
|
|
302
318
|
* @subcategory components / elements / utils
|
|
303
319
|
*/
|
|
304
|
-
const TextStyleRow = ({ textStyle, setProp }) => {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
};
|
|
320
|
+
const TextStyleRow = ({ textStyle, setProp }) => {
|
|
321
|
+
return (
|
|
322
|
+
<tr>
|
|
323
|
+
<td>
|
|
324
|
+
<label>Text Style</label>
|
|
325
|
+
</td>
|
|
326
|
+
<td>
|
|
327
|
+
<TextStyleSelect textStyle={textStyle} setProp={setProp} />
|
|
328
|
+
</td>
|
|
329
|
+
</tr>
|
|
330
|
+
);
|
|
331
|
+
};
|
|
316
332
|
|
|
317
333
|
export /**
|
|
318
334
|
* @param {object} props
|
|
@@ -323,36 +339,35 @@ export /**
|
|
|
323
339
|
* @subcategory components / elements / utils
|
|
324
340
|
* @namespace
|
|
325
341
|
*/
|
|
326
|
-
const Accordion = ({ titles, children }) => {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
)
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
};
|
|
342
|
+
const Accordion = ({ titles, children }) => {
|
|
343
|
+
const [currentTab, setCurrentTab] = useState(0);
|
|
344
|
+
return (
|
|
345
|
+
<Fragment>
|
|
346
|
+
{children.map((child, ix) => {
|
|
347
|
+
const isCurrent = ix === currentTab;
|
|
348
|
+
return (
|
|
349
|
+
<Fragment key={ix}>
|
|
350
|
+
<div
|
|
351
|
+
className={`bg-${isCurrent ? "primary" : "secondary"
|
|
352
|
+
} ps-1 text-white w-100 mt-1`}
|
|
353
|
+
onClick={() => setCurrentTab(ix)}
|
|
354
|
+
>
|
|
355
|
+
<span className="w-1em">
|
|
356
|
+
{isCurrent ? (
|
|
357
|
+
<FontAwesomeIcon icon={faChevronDown} />
|
|
358
|
+
) : (
|
|
359
|
+
<FontAwesomeIcon icon={faChevronRight} />
|
|
360
|
+
)}
|
|
361
|
+
</span>
|
|
362
|
+
{child.props.accordiontitle || titles[ix]}
|
|
363
|
+
</div>
|
|
364
|
+
{isCurrent ? child : null}
|
|
365
|
+
</Fragment>
|
|
366
|
+
);
|
|
367
|
+
})}
|
|
368
|
+
</Fragment>
|
|
369
|
+
);
|
|
370
|
+
};
|
|
356
371
|
|
|
357
372
|
/**
|
|
358
373
|
* @param {object} opts
|
|
@@ -402,23 +417,23 @@ const fetchPreview = ({ url, body, options, setPreviews, node_id, isView }) => {
|
|
|
402
417
|
*/
|
|
403
418
|
export const fetchFieldPreview =
|
|
404
419
|
(args = {}) =>
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
420
|
+
(changes = {}) => {
|
|
421
|
+
const { node_id, options, name, fieldview, setPreviews } = {
|
|
422
|
+
...args,
|
|
423
|
+
...changes,
|
|
424
|
+
};
|
|
425
|
+
const configuration = {
|
|
426
|
+
...(args.configuration || {}),
|
|
427
|
+
...(changes.configuration || {}),
|
|
428
|
+
};
|
|
429
|
+
fetchPreview({
|
|
430
|
+
options,
|
|
431
|
+
node_id,
|
|
432
|
+
setPreviews,
|
|
433
|
+
url: `/field/preview/${options.tableName}/${name}/${fieldview}`,
|
|
434
|
+
body: { configuration },
|
|
435
|
+
});
|
|
413
436
|
};
|
|
414
|
-
fetchPreview({
|
|
415
|
-
options,
|
|
416
|
-
node_id,
|
|
417
|
-
setPreviews,
|
|
418
|
-
url: `/field/preview/${options.tableName}/${name}/${fieldview}`,
|
|
419
|
-
body: { configuration },
|
|
420
|
-
});
|
|
421
|
-
};
|
|
422
437
|
|
|
423
438
|
/**
|
|
424
439
|
* @function
|
|
@@ -427,30 +442,30 @@ export const fetchFieldPreview =
|
|
|
427
442
|
*/
|
|
428
443
|
export const fetchViewPreview =
|
|
429
444
|
(args = {}) =>
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
445
|
+
(changes = {}) => {
|
|
446
|
+
const { node_id, options, view, setPreviews, configuration } = {
|
|
447
|
+
...args,
|
|
448
|
+
...changes,
|
|
449
|
+
};
|
|
450
|
+
let viewname,
|
|
451
|
+
body = configuration ? { ...configuration } : {};
|
|
452
|
+
if (view.includes(":")) {
|
|
453
|
+
const [reltype, rest] = view.split(":");
|
|
454
|
+
const [vnm] = rest.split(".");
|
|
455
|
+
viewname = vnm;
|
|
456
|
+
body.reltype = reltype;
|
|
457
|
+
body.path = rest;
|
|
458
|
+
} else viewname = view;
|
|
444
459
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
460
|
+
fetchPreview({
|
|
461
|
+
options,
|
|
462
|
+
node_id,
|
|
463
|
+
setPreviews,
|
|
464
|
+
url: `/view/${viewname}/preview`,
|
|
465
|
+
body,
|
|
466
|
+
isView: true,
|
|
467
|
+
});
|
|
468
|
+
};
|
|
454
469
|
|
|
455
470
|
export /**
|
|
456
471
|
* @param {object} props
|
|
@@ -462,16 +477,16 @@ export /**
|
|
|
462
477
|
* @subcategory components / elements / utils
|
|
463
478
|
* @namespace
|
|
464
479
|
*/
|
|
465
|
-
const SelectUnits = ({ vert, autoable, ...props }) => (
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
);
|
|
480
|
+
const SelectUnits = ({ vert, autoable, ...props }) => (
|
|
481
|
+
<select {...props}>
|
|
482
|
+
<option>px</option>
|
|
483
|
+
<option>%</option>
|
|
484
|
+
<option>{vert ? "vh" : "vw"}</option>
|
|
485
|
+
<option>em</option>
|
|
486
|
+
<option>rem</option>
|
|
487
|
+
{autoable && <option>auto</option>}
|
|
488
|
+
</select>
|
|
489
|
+
);
|
|
475
490
|
|
|
476
491
|
/**
|
|
477
492
|
* @function
|
|
@@ -579,36 +594,36 @@ export /**
|
|
|
579
594
|
* @subcategory components / elements / utils
|
|
580
595
|
* @namespace
|
|
581
596
|
*/
|
|
582
|
-
const ConfigForm = ({ fields, configuration, setProp, node, onChange }) => (
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
);
|
|
597
|
+
const ConfigForm = ({ fields, configuration, setProp, node, onChange }) => (
|
|
598
|
+
<div>
|
|
599
|
+
{fields.map((f, ix) => {
|
|
600
|
+
if (f.showIf && configuration) {
|
|
601
|
+
let noshow = false;
|
|
602
|
+
Object.entries(f.showIf).forEach(([nm, value]) => {
|
|
603
|
+
if (Array.isArray(value))
|
|
604
|
+
noshow = noshow || value.includes(configuration[nm]);
|
|
605
|
+
else noshow = noshow || value !== configuration[nm];
|
|
606
|
+
});
|
|
607
|
+
if (noshow) return null;
|
|
608
|
+
}
|
|
609
|
+
return (
|
|
610
|
+
<div key={ix}>
|
|
611
|
+
{!isCheckbox(f) ? <label>{f.label || f.name}</label> : null}
|
|
612
|
+
<ConfigField
|
|
613
|
+
field={f}
|
|
614
|
+
configuration={configuration}
|
|
615
|
+
setProp={setProp}
|
|
616
|
+
onChange={onChange}
|
|
617
|
+
/>
|
|
618
|
+
{f.sublabel ? (
|
|
619
|
+
<i dangerouslySetInnerHTML={{ __html: f.sublabel }}></i>
|
|
620
|
+
) : null}
|
|
621
|
+
</div>
|
|
622
|
+
);
|
|
623
|
+
})}
|
|
624
|
+
<br />
|
|
625
|
+
</div>
|
|
626
|
+
);
|
|
612
627
|
|
|
613
628
|
/**
|
|
614
629
|
* @param {object|undefined} x
|
|
@@ -630,244 +645,243 @@ export /**
|
|
|
630
645
|
* @subcategory components / elements / utils
|
|
631
646
|
* @namespace
|
|
632
647
|
*/
|
|
633
|
-
const ConfigField = ({
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
}) => {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
648
|
+
const ConfigField = ({
|
|
649
|
+
field,
|
|
650
|
+
configuration,
|
|
651
|
+
setProp,
|
|
652
|
+
onChange,
|
|
653
|
+
props,
|
|
654
|
+
isStyle,
|
|
655
|
+
}) => {
|
|
656
|
+
/**
|
|
657
|
+
* @param {object} v
|
|
658
|
+
* @returns {void}
|
|
659
|
+
*/
|
|
660
|
+
const options = useContext(optionsCtx);
|
|
646
661
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
662
|
+
const myOnChange = (v) => {
|
|
663
|
+
setProp((prop) => {
|
|
664
|
+
if (configuration) {
|
|
665
|
+
if (!prop.configuration) prop.configuration = {};
|
|
666
|
+
prop.configuration[field.name] = v;
|
|
667
|
+
} else if (isStyle) {
|
|
668
|
+
if (!prop.style) prop.style = {};
|
|
669
|
+
prop.style[field.name] = v;
|
|
670
|
+
} else prop[field.name] = v;
|
|
671
|
+
});
|
|
672
|
+
onChange && onChange(field.name, v);
|
|
673
|
+
};
|
|
674
|
+
const value = or_if_undef(
|
|
675
|
+
configuration
|
|
676
|
+
? configuration[field.name]
|
|
677
|
+
: isStyle
|
|
678
|
+
? props.style[field.name]
|
|
679
|
+
: props[field.name],
|
|
680
|
+
field.default
|
|
681
|
+
);
|
|
682
|
+
if (field.input_type === "fromtype") field.input_type = null;
|
|
683
|
+
if (field.type && field.type.name === "String" && field.attributes.options) {
|
|
684
|
+
field.input_type = "select";
|
|
685
|
+
field.options =
|
|
686
|
+
typeof field.attributes.options === "string"
|
|
687
|
+
? field.attributes.options.split(",").map((s) => s.trim())
|
|
688
|
+
: field.attributes.options;
|
|
689
|
+
if (!field.required && field.options) field.options.unshift("");
|
|
690
|
+
}
|
|
691
|
+
const dispatch = {
|
|
692
|
+
String() {
|
|
693
|
+
if (field.attributes?.options) {
|
|
694
|
+
const options =
|
|
695
|
+
typeof field.attributes.options === "string"
|
|
696
|
+
? field.attributes.options.split(",").map((s) => s.trim())
|
|
697
|
+
: field.attributes.options;
|
|
698
|
+
return (
|
|
699
|
+
<select
|
|
700
|
+
className="form-control form-select"
|
|
701
|
+
value={value || ""}
|
|
702
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
703
|
+
>
|
|
704
|
+
{options.map((o, ix) => (
|
|
705
|
+
<option
|
|
706
|
+
key={ix}
|
|
707
|
+
value={typeof o === "string" ? o : o.value || o.name}
|
|
708
|
+
>
|
|
709
|
+
{typeof o === "string" ? o : o.label}
|
|
710
|
+
</option>
|
|
711
|
+
))}
|
|
712
|
+
</select>
|
|
713
|
+
);
|
|
714
|
+
} else
|
|
715
|
+
return (
|
|
716
|
+
<input
|
|
717
|
+
type="text"
|
|
718
|
+
className="form-control"
|
|
719
|
+
value={value || ""}
|
|
720
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
721
|
+
/>
|
|
722
|
+
);
|
|
723
|
+
},
|
|
724
|
+
Font: () => (
|
|
725
|
+
<select
|
|
726
|
+
className="form-control form-select"
|
|
727
|
+
value={value || ""}
|
|
728
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
729
|
+
>
|
|
730
|
+
<option value={""}></option>
|
|
731
|
+
{Object.entries(options.fonts || {}).map(([nm, ff], ix) => (
|
|
732
|
+
<option key={ix} value={ff}>
|
|
733
|
+
{nm}
|
|
734
|
+
</option>
|
|
735
|
+
))}
|
|
736
|
+
</select>
|
|
737
|
+
),
|
|
738
|
+
Integer: () => (
|
|
739
|
+
<input
|
|
740
|
+
type="number"
|
|
741
|
+
className="form-control"
|
|
742
|
+
step={field.step || 1}
|
|
743
|
+
min={field.min}
|
|
744
|
+
max={field.max}
|
|
745
|
+
value={value || ""}
|
|
746
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
747
|
+
/>
|
|
748
|
+
),
|
|
749
|
+
Float: () => (
|
|
750
|
+
<input
|
|
751
|
+
type="number"
|
|
752
|
+
className="form-control"
|
|
753
|
+
value={value || ""}
|
|
754
|
+
step={0.01}
|
|
755
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
756
|
+
/>
|
|
757
|
+
),
|
|
758
|
+
Color: () => <ColorInput value={value} onChange={(c) => myOnChange(c)} />,
|
|
759
|
+
Bool: () => (
|
|
760
|
+
<div className="form-check">
|
|
701
761
|
<input
|
|
702
|
-
type="
|
|
703
|
-
className="form-
|
|
704
|
-
|
|
705
|
-
onChange={(e) => e.target && myOnChange(e.target.
|
|
762
|
+
type="checkbox"
|
|
763
|
+
className="form-check-input"
|
|
764
|
+
checked={value}
|
|
765
|
+
onChange={(e) => e.target && myOnChange(e.target.checked)}
|
|
706
766
|
/>
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
<option key={ix} value={ff}>
|
|
718
|
-
{nm}
|
|
719
|
-
</option>
|
|
720
|
-
))}
|
|
721
|
-
</select>
|
|
722
|
-
),
|
|
723
|
-
Integer: () => (
|
|
724
|
-
<input
|
|
725
|
-
type="number"
|
|
726
|
-
className="form-control"
|
|
727
|
-
step={field.step || 1}
|
|
728
|
-
min={field.min}
|
|
729
|
-
max={field.max}
|
|
730
|
-
value={value || ""}
|
|
731
|
-
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
732
|
-
/>
|
|
733
|
-
),
|
|
734
|
-
Float: () => (
|
|
735
|
-
<input
|
|
736
|
-
type="number"
|
|
737
|
-
className="form-control"
|
|
738
|
-
value={value || ""}
|
|
739
|
-
step={0.01}
|
|
740
|
-
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
741
|
-
/>
|
|
742
|
-
),
|
|
743
|
-
Color: () => <ColorInput value={value} onChange={(c) => myOnChange(c)} />,
|
|
744
|
-
Bool: () => (
|
|
745
|
-
<div className="form-check">
|
|
746
|
-
<input
|
|
747
|
-
type="checkbox"
|
|
748
|
-
className="form-check-input"
|
|
749
|
-
checked={value}
|
|
750
|
-
onChange={(e) => e.target && myOnChange(e.target.checked)}
|
|
767
|
+
<label className="form-check-label">{field.label}</label>
|
|
768
|
+
</div>
|
|
769
|
+
),
|
|
770
|
+
textarea: () => (
|
|
771
|
+
<textarea
|
|
772
|
+
rows="6"
|
|
773
|
+
type="text"
|
|
774
|
+
className="form-control"
|
|
775
|
+
value={value}
|
|
776
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
751
777
|
/>
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
),
|
|
802
|
-
DimUnits: () => {
|
|
803
|
-
let styleVal, styleDim;
|
|
804
|
-
if (isStyle && value === "auto") {
|
|
805
|
-
styleVal = "";
|
|
806
|
-
styleDim = "auto";
|
|
807
|
-
} else if (isStyle && value && typeof value === "string") {
|
|
808
|
-
const matches = value.match(/^([0-9]+\.?[0-9]*)(.*)/);
|
|
809
|
-
if (matches) {
|
|
810
|
-
styleVal = matches[1];
|
|
811
|
-
styleDim = matches[2];
|
|
778
|
+
),
|
|
779
|
+
code: () => (
|
|
780
|
+
<textarea
|
|
781
|
+
rows="6"
|
|
782
|
+
type="text"
|
|
783
|
+
className="form-control"
|
|
784
|
+
value={value}
|
|
785
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
786
|
+
/>
|
|
787
|
+
),
|
|
788
|
+
select: () => (
|
|
789
|
+
<select
|
|
790
|
+
className="form-control form-select"
|
|
791
|
+
value={value || ""}
|
|
792
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
793
|
+
>
|
|
794
|
+
{field.options.map((o, ix) => (
|
|
795
|
+
<option key={ix}>{o}</option>
|
|
796
|
+
))}
|
|
797
|
+
</select>
|
|
798
|
+
),
|
|
799
|
+
btn_select: () => (
|
|
800
|
+
<div className="btn-group w-100" role="group">
|
|
801
|
+
{field.options.map((o, ix) => (
|
|
802
|
+
<button
|
|
803
|
+
key={ix}
|
|
804
|
+
title={o.title || o.value}
|
|
805
|
+
type="button"
|
|
806
|
+
style={{ width: `${Math.floor(100 / field.options.length)}%` }}
|
|
807
|
+
className={`btn btn-sm btn-${value !== o.value ? "outline-" : ""
|
|
808
|
+
}secondary ${field.btnClass || ""}`}
|
|
809
|
+
onClick={() => myOnChange(o.value)}
|
|
810
|
+
>
|
|
811
|
+
{o.label}
|
|
812
|
+
</button>
|
|
813
|
+
))}
|
|
814
|
+
</div>
|
|
815
|
+
),
|
|
816
|
+
DimUnits: () => {
|
|
817
|
+
let styleVal, styleDim;
|
|
818
|
+
if (isStyle && value === "auto") {
|
|
819
|
+
styleVal = "";
|
|
820
|
+
styleDim = "auto";
|
|
821
|
+
} else if (isStyle && value && typeof value === "string") {
|
|
822
|
+
const matches = value.match(/^([0-9]+\.?[0-9]*)(.*)/);
|
|
823
|
+
if (matches) {
|
|
824
|
+
styleVal = matches[1];
|
|
825
|
+
styleDim = matches[2];
|
|
826
|
+
}
|
|
812
827
|
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
)}
|
|
831
|
-
<SelectUnits
|
|
832
|
-
value={or_if_undef(
|
|
833
|
-
configuration
|
|
834
|
-
? configuration[field.name + "Unit"]
|
|
835
|
-
: isStyle
|
|
836
|
-
? styleDim
|
|
837
|
-
: props[field.name + "Unit"],
|
|
838
|
-
"px"
|
|
828
|
+
return (
|
|
829
|
+
<Fragment>
|
|
830
|
+
{styleDim !== "auto" && (
|
|
831
|
+
<input
|
|
832
|
+
type="number"
|
|
833
|
+
value={(isStyle ? styleVal : value) || ""}
|
|
834
|
+
className="w-50 form-control-sm d-inline dimunit"
|
|
835
|
+
disabled={field.autoable && styleDim === "auto"}
|
|
836
|
+
onChange={(e) =>
|
|
837
|
+
e?.target &&
|
|
838
|
+
myOnChange(
|
|
839
|
+
isStyle
|
|
840
|
+
? `${e.target.value}${styleDim || "px"}`
|
|
841
|
+
: e.target.value
|
|
842
|
+
)
|
|
843
|
+
}
|
|
844
|
+
/>
|
|
839
845
|
)}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
846
|
+
<SelectUnits
|
|
847
|
+
value={or_if_undef(
|
|
848
|
+
configuration
|
|
849
|
+
? configuration[field.name + "Unit"]
|
|
850
|
+
: isStyle
|
|
851
|
+
? styleDim
|
|
852
|
+
: props[field.name + "Unit"],
|
|
853
|
+
"px"
|
|
854
|
+
)}
|
|
855
|
+
autoable={field.autoable}
|
|
856
|
+
className={`w-${styleDim === "auto" ? 100 : 50
|
|
857
|
+
} form-control-sm d-inline dimunit`}
|
|
858
|
+
vert={true}
|
|
859
|
+
onChange={(e) => {
|
|
860
|
+
if (!e.target) return;
|
|
861
|
+
const target_value = e.target.value;
|
|
862
|
+
setProp((prop) => {
|
|
863
|
+
const myStyleVal =
|
|
864
|
+
target_value === "auto" && field.autoable && isStyle
|
|
865
|
+
? ""
|
|
866
|
+
: styleVal;
|
|
867
|
+
if (configuration)
|
|
868
|
+
prop.configuration[field.name + "Unit"] = target_value;
|
|
869
|
+
else if (isStyle) {
|
|
870
|
+
prop.style[field.name] = `${or_if_undef(
|
|
871
|
+
myStyleVal,
|
|
872
|
+
0
|
|
873
|
+
)}${target_value}`;
|
|
874
|
+
} else prop[field.name + "Unit"] = target_value;
|
|
875
|
+
});
|
|
876
|
+
}}
|
|
877
|
+
/>
|
|
878
|
+
</Fragment>
|
|
879
|
+
);
|
|
880
|
+
},
|
|
881
|
+
};
|
|
882
|
+
const f = dispatch[field.input_type || field.type.name || field.type];
|
|
883
|
+
return f ? f() : null;
|
|
867
884
|
};
|
|
868
|
-
const f = dispatch[field.input_type || field.type.name || field.type];
|
|
869
|
-
return f ? f() : null;
|
|
870
|
-
};
|
|
871
885
|
|
|
872
886
|
export /**
|
|
873
887
|
* @param {object[]} fields
|
|
@@ -876,30 +890,30 @@ export /**
|
|
|
876
890
|
* @namespace
|
|
877
891
|
* @returns {table}
|
|
878
892
|
*/
|
|
879
|
-
const SettingsFromFields = (fields) => () => {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
893
|
+
const SettingsFromFields = (fields) => () => {
|
|
894
|
+
const node = useNode((node) => {
|
|
895
|
+
const ps = {};
|
|
896
|
+
fields.forEach((f) => {
|
|
897
|
+
ps[f.name] = node.data.props[f.name];
|
|
898
|
+
});
|
|
899
|
+
if (fields.some((f) => f.canBeFormula))
|
|
900
|
+
ps.isFormula = node.data.props.isFormula;
|
|
901
|
+
return ps;
|
|
884
902
|
});
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
});
|
|
889
|
-
const {
|
|
890
|
-
actions: { setProp },
|
|
891
|
-
} = node;
|
|
903
|
+
const {
|
|
904
|
+
actions: { setProp },
|
|
905
|
+
} = node;
|
|
892
906
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
};
|
|
907
|
+
return (
|
|
908
|
+
<table className="w-100">
|
|
909
|
+
<tbody>
|
|
910
|
+
{fields.map((f, ix) => (
|
|
911
|
+
<SettingsRow field={f} key={ix} node={node} setProp={setProp} />
|
|
912
|
+
))}
|
|
913
|
+
</tbody>
|
|
914
|
+
</table>
|
|
915
|
+
);
|
|
916
|
+
};
|
|
903
917
|
|
|
904
918
|
export /**
|
|
905
919
|
* @param {object} props
|
|
@@ -909,11 +923,11 @@ export /**
|
|
|
909
923
|
* @subcategory components / elements / utils
|
|
910
924
|
* @namespace
|
|
911
925
|
*/
|
|
912
|
-
const SettingsSectionHeaderRow = ({ title }) => (
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
);
|
|
926
|
+
const SettingsSectionHeaderRow = ({ title }) => (
|
|
927
|
+
<tr>
|
|
928
|
+
<th colSpan="2">{title}</th>
|
|
929
|
+
</tr>
|
|
930
|
+
);
|
|
917
931
|
|
|
918
932
|
export /**
|
|
919
933
|
* @param {object} props
|
|
@@ -927,49 +941,49 @@ export /**
|
|
|
927
941
|
* @subcategory components / elements / utils
|
|
928
942
|
* @namespace
|
|
929
943
|
*/
|
|
930
|
-
const SettingsRow = ({ field, node, setProp, onChange, isStyle }) => {
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
944
|
+
const SettingsRow = ({ field, node, setProp, onChange, isStyle }) => {
|
|
945
|
+
const fullWidth = ["String", "Bool", "textarea"].includes(field.type);
|
|
946
|
+
const needLabel = field.type !== "Bool";
|
|
947
|
+
const inner = field.canBeFormula ? (
|
|
948
|
+
<OrFormula
|
|
949
|
+
nodekey={field.name}
|
|
950
|
+
isFormula={node.isFormula}
|
|
951
|
+
{...{ setProp, node }}
|
|
952
|
+
>
|
|
953
|
+
<ConfigField
|
|
954
|
+
field={field}
|
|
955
|
+
props={node}
|
|
956
|
+
setProp={setProp}
|
|
957
|
+
onChange={onChange}
|
|
958
|
+
/>
|
|
959
|
+
</OrFormula>
|
|
960
|
+
) : (
|
|
939
961
|
<ConfigField
|
|
940
962
|
field={field}
|
|
941
963
|
props={node}
|
|
942
964
|
setProp={setProp}
|
|
943
965
|
onChange={onChange}
|
|
966
|
+
isStyle={isStyle}
|
|
944
967
|
/>
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
isStyle={isStyle}
|
|
953
|
-
/>
|
|
954
|
-
);
|
|
955
|
-
return (
|
|
956
|
-
<tr>
|
|
957
|
-
{fullWidth ? (
|
|
958
|
-
<td colSpan="2">
|
|
959
|
-
{needLabel && <label>{field.label}</label>}
|
|
960
|
-
{inner}
|
|
961
|
-
</td>
|
|
962
|
-
) : (
|
|
963
|
-
<Fragment>
|
|
964
|
-
<td>
|
|
965
|
-
<label>{field.label}</label>
|
|
968
|
+
);
|
|
969
|
+
return (
|
|
970
|
+
<tr>
|
|
971
|
+
{fullWidth ? (
|
|
972
|
+
<td colSpan="2">
|
|
973
|
+
{needLabel && <label>{field.label}</label>}
|
|
974
|
+
{inner}
|
|
966
975
|
</td>
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
}
|
|
976
|
+
) : (
|
|
977
|
+
<Fragment>
|
|
978
|
+
<td>
|
|
979
|
+
<label>{field.label}</label>
|
|
980
|
+
</td>
|
|
981
|
+
<td>{inner}</td>
|
|
982
|
+
</Fragment>
|
|
983
|
+
)}
|
|
984
|
+
</tr>
|
|
985
|
+
);
|
|
986
|
+
};
|
|
973
987
|
|
|
974
988
|
/**
|
|
975
989
|
* @category saltcorn-builder
|
|
@@ -1046,88 +1060,83 @@ export /**
|
|
|
1046
1060
|
* @subcategory components / elements / utils
|
|
1047
1061
|
* @namespace
|
|
1048
1062
|
*/
|
|
1049
|
-
const ButtonOrLinkSettingsRows = ({
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
}) => {
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
<option value={addBtnClass("btn-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
/>
|
|
1127
|
-
</td>
|
|
1128
|
-
</tr>,
|
|
1129
|
-
...(values[keyPrefix + "style"] === addBtnClass("btn-custom-color")
|
|
1130
|
-
? [
|
|
1063
|
+
const ButtonOrLinkSettingsRows = ({
|
|
1064
|
+
setProp,
|
|
1065
|
+
btnClass = null,
|
|
1066
|
+
keyPrefix = "",
|
|
1067
|
+
values,
|
|
1068
|
+
linkFirst = false,
|
|
1069
|
+
}) => {
|
|
1070
|
+
const setAProp = setAPropGen(setProp);
|
|
1071
|
+
const addBtnClass = (s) => (btnClass ? `${btnClass} ${s}` : s);
|
|
1072
|
+
return [
|
|
1073
|
+
<tr key="btnstyle">
|
|
1074
|
+
<td>
|
|
1075
|
+
<label>Style</label>
|
|
1076
|
+
</td>
|
|
1077
|
+
<td>
|
|
1078
|
+
<select
|
|
1079
|
+
className="form-control form-select"
|
|
1080
|
+
value={values[keyPrefix + "style"]}
|
|
1081
|
+
onChange={setAProp(keyPrefix + "style")}
|
|
1082
|
+
>
|
|
1083
|
+
{linkFirst ? (
|
|
1084
|
+
<option value={addBtnClass("btn-link")}>Link</option>
|
|
1085
|
+
) : null}
|
|
1086
|
+
<option value={addBtnClass("btn-primary")}>Primary button</option>
|
|
1087
|
+
<option value={addBtnClass("btn-secondary")}>Secondary button</option>
|
|
1088
|
+
<option value={addBtnClass("btn-success")}>Success button</option>
|
|
1089
|
+
<option value={addBtnClass("btn-danger")}>Danger button</option>
|
|
1090
|
+
<option value={addBtnClass("btn-outline-primary")}>
|
|
1091
|
+
Primary outline button
|
|
1092
|
+
</option>
|
|
1093
|
+
<option value={addBtnClass("btn-outline-secondary")}>
|
|
1094
|
+
Secondary outline button
|
|
1095
|
+
</option>
|
|
1096
|
+
<option value={addBtnClass("btn-custom-color")}>
|
|
1097
|
+
Button custom color
|
|
1098
|
+
</option>
|
|
1099
|
+
{!linkFirst ? (
|
|
1100
|
+
<option value={addBtnClass("btn-link")}>Link</option>
|
|
1101
|
+
) : null}
|
|
1102
|
+
</select>
|
|
1103
|
+
</td>
|
|
1104
|
+
</tr>,
|
|
1105
|
+
<tr key="btnsz">
|
|
1106
|
+
<td>
|
|
1107
|
+
<label>Size</label>
|
|
1108
|
+
</td>
|
|
1109
|
+
<td>
|
|
1110
|
+
<select
|
|
1111
|
+
className="form-control form-select"
|
|
1112
|
+
value={values[keyPrefix + "size"]}
|
|
1113
|
+
onChange={setAProp(keyPrefix + "size")}
|
|
1114
|
+
>
|
|
1115
|
+
<option value="">Standard</option>
|
|
1116
|
+
<option value="btn-lg">Large</option>
|
|
1117
|
+
<option value="btn-sm">Small</option>
|
|
1118
|
+
<option value="btn-block">Block</option>
|
|
1119
|
+
<option value="btn-block btn-lg">Large block</option>
|
|
1120
|
+
</select>
|
|
1121
|
+
</td>
|
|
1122
|
+
</tr>,
|
|
1123
|
+
<tr key="btnicon">
|
|
1124
|
+
<td>
|
|
1125
|
+
<label>Icon</label>
|
|
1126
|
+
</td>
|
|
1127
|
+
<td>
|
|
1128
|
+
<FontIconPicker
|
|
1129
|
+
value={values[keyPrefix + "icon"]}
|
|
1130
|
+
onChange={(value) =>
|
|
1131
|
+
setProp((prop) => (prop[keyPrefix + "icon"] = value))
|
|
1132
|
+
}
|
|
1133
|
+
isMulti={false}
|
|
1134
|
+
icons={faIcons}
|
|
1135
|
+
/>
|
|
1136
|
+
</td>
|
|
1137
|
+
</tr>,
|
|
1138
|
+
...(values[keyPrefix + "style"] === addBtnClass("btn-custom-color")
|
|
1139
|
+
? [
|
|
1131
1140
|
<tr key="btnbgcol">
|
|
1132
1141
|
<td>
|
|
1133
1142
|
<label>Background</label>
|
|
@@ -1168,9 +1177,9 @@ const ButtonOrLinkSettingsRows = ({
|
|
|
1168
1177
|
</td>
|
|
1169
1178
|
</tr>,
|
|
1170
1179
|
]
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
};
|
|
1180
|
+
: []),
|
|
1181
|
+
];
|
|
1182
|
+
};
|
|
1174
1183
|
|
|
1175
1184
|
/**
|
|
1176
1185
|
* @function
|
|
@@ -1228,3 +1237,24 @@ export const recursivelyCloneToElems = (query) => (nodeId, ix) => {
|
|
|
1228
1237
|
|
|
1229
1238
|
export const isBlock = (block, inline, textStyle) =>
|
|
1230
1239
|
!textStyle || !textStyle.startsWith("h") ? block : !inline;
|
|
1240
|
+
|
|
1241
|
+
export const setAPropGen =
|
|
1242
|
+
(setProp) =>
|
|
1243
|
+
(key, opts = {}) =>
|
|
1244
|
+
(e) => {
|
|
1245
|
+
if (e.target) {
|
|
1246
|
+
const target_value = opts?.checked ? e.target.checked : e.target.value;
|
|
1247
|
+
setProp((prop) => (prop[key] = target_value));
|
|
1248
|
+
}
|
|
1249
|
+
};
|
|
1250
|
+
|
|
1251
|
+
const Tooltip = ({ children }) => {
|
|
1252
|
+
const [visible, setVisible] = useState(false);
|
|
1253
|
+
const show = () => setVisible(true);
|
|
1254
|
+
const hide = () => setVisible(false);
|
|
1255
|
+
return <Tippy content={children} visible={visible} onClickOutside={hide} interactive={true}>
|
|
1256
|
+
<span
|
|
1257
|
+
onClick={visible ? hide : show} className="ms-1"
|
|
1258
|
+
><FontAwesomeIcon icon={faInfoCircle} /></span>
|
|
1259
|
+
</Tippy>
|
|
1260
|
+
}
|