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