@saltcorn/builder 0.8.0-beta.4 → 0.8.1-beta.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 '@tippyjs/react';
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
- const blockProps = (is_block) =>
31
- is_block ? { style: { display: "block" } } : {};
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
- 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
- );
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 <Tooltip>
84
- <div>Formulae in Saltcorn are JavaScript expressions based on the current database row.</div>
85
- {fields ? <Fragment> Variables in scope: &nbsp;
86
- {fields.map((f, ix) => <Fragment key={ix}><code>{f.name}</code>{" "}</Fragment>)}</Fragment> : null}
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: &nbsp;
93
+ {fields.map((f, ix) => (
94
+ <Fragment key={ix}>
95
+ <code>{f.name}</code>{" "}
96
+ </Fragment>
97
+ ))}
98
+ </Fragment>
99
+ ) : null}
87
100
 
88
- <a className="d-block" href="https://wiki.saltcorn.com/view/ShowPage/formulas">Wiki page on formulas</a>
89
- </Tooltip>
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
- const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
105
- const { mode } = useContext(optionsCtx);
123
+ const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
124
+ const { mode } = useContext(optionsCtx);
106
125
 
107
- /**
108
- * @returns {void}
109
- */
110
- const switchIsFml = () => {
111
- const isFmlAfter = !isFormula[nodekey];
112
- setProp((prop) => {
113
- prop.isFormula[nodekey] = isFmlAfter;
114
- if (isFmlAfter && prop[nodekey] && prop[nodekey][0] !== '"') {
115
- prop[nodekey] = `"${prop[nodekey]}"`;
116
- } else if (
117
- !isFmlAfter &&
118
- typeof prop[nodekey] === "string" &&
119
- prop[nodekey][0] === '"' &&
120
- prop[nodekey][prop[nodekey].length - 1] === '"'
121
- ) {
122
- prop[nodekey] = prop[nodekey].substring(1, prop[nodekey].length - 1);
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
- return mode !== "show" ? (
135
- children
136
- ) : (
137
- <Fragment>
138
- <div className="input-group input-group-sm w-100">
139
- {isFormula[nodekey] ? (
140
- <input
141
- type="text"
142
- className="form-control text-to-display"
143
- value={node[nodekey] || ""}
144
- onChange={(e) => {
145
- if (e.target) {
146
- const target_value = e.target.value;
147
- setProp((prop) => (prop[nodekey] = target_value));
148
- }
149
- }}
150
- />
151
- ) : (
152
- children
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
- <button
156
- className={`btn activate-formula ${isFormula[nodekey] ? "btn-secondary" : "btn-outline-secondary"
157
- }`}
158
- title="Calculated formula"
159
- type="button"
160
- onClick={switchIsFml}
161
- >
162
- <i className="fas fa-calculator"></i>
163
- </button>
164
- </div>
165
- {isFormula[nodekey] && (
166
- <div style={{ marginTop: "-5px" }}>
167
- <small className="text-muted font-monospace">
168
- FORMULA
169
- <FormulaTooltip />
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
- {errorString ? (
172
- <small className="text-danger font-monospace d-block">
173
- {errorString}
174
- </small>
175
- ) : null}
176
- </div>
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
- const MinRoleSetting = ({ minRole, setProp }) => {
192
- const options = useContext(optionsCtx);
193
- return (
194
- <div>
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
- onChange={(e) => (e) => {
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
- </div>
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
- const TextStyleSetting = ({ textStyle, setProp }) => {
302
- return (
303
- <div>
304
- <label>Text Style</label>
305
- <TextStyleSelect textStyle={textStyle} setProp={setProp} />
306
- </div>
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
- const TextStyleRow = ({ textStyle, setProp }) => {
320
- return (
321
- <tr>
322
- <td>
323
- <label>Text Style</label>
324
- </td>
325
- <td>
326
- <TextStyleSelect textStyle={textStyle} setProp={setProp} />
327
- </td>
328
- </tr>
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
- const Accordion = ({ titles, children }) => {
342
- const [currentTab, setCurrentTab] = useState(0);
343
- return (
344
- <Fragment>
345
- {children.map((child, ix) => {
346
- const isCurrent = ix === currentTab;
347
- return (
348
- <Fragment key={ix}>
349
- <div
350
- className={`bg-${isCurrent ? "primary" : "secondary"
351
- } ps-1 text-white w-100 mt-1`}
352
- onClick={() => setCurrentTab(ix)}
353
- >
354
- <span className="w-1em">
355
- {isCurrent ? (
356
- <FontAwesomeIcon icon={faChevronDown} />
357
- ) : (
358
- <FontAwesomeIcon icon={faChevronRight} />
359
- )}
360
- </span>
361
- {child.props.accordiontitle || titles[ix]}
362
- </div>
363
- {isCurrent ? child : null}
364
- </Fragment>
365
- );
366
- })}
367
- </Fragment>
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
- (changes = {}) => {
420
- const { node_id, options, name, fieldview, setPreviews } = {
421
- ...args,
422
- ...changes,
423
- };
424
- const configuration = {
425
- ...(args.configuration || {}),
426
- ...(changes.configuration || {}),
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
- (changes = {}) => {
445
- const { node_id, options, view, setPreviews, configuration } = {
446
- ...args,
447
- ...changes,
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
- const SelectUnits = ({ vert, autoable, ...props }) => (
480
- <select {...props}>
481
- <option>px</option>
482
- <option>%</option>
483
- <option>{vert ? "vh" : "vw"}</option>
484
- <option>em</option>
485
- <option>rem</option>
486
- {autoable && <option>auto</option>}
487
- </select>
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
- const ConfigForm = ({ fields, configuration, setProp, node, onChange }) => (
597
- <div>
598
- {fields.map((f, ix) => {
599
- if (f.showIf && configuration) {
600
- let noshow = false;
601
- Object.entries(f.showIf).forEach(([nm, value]) => {
602
- if (Array.isArray(value))
603
- noshow = noshow || value.includes(configuration[nm]);
604
- else noshow = noshow || value !== configuration[nm];
605
- });
606
- if (noshow) return null;
607
- }
608
- return (
609
- <div key={ix}>
610
- {!isCheckbox(f) ? <label>{f.label || f.name}</label> : null}
611
- <ConfigField
612
- field={f}
613
- configuration={configuration}
614
- setProp={setProp}
615
- onChange={onChange}
616
- />
617
- {f.sublabel ? (
618
- <i dangerouslySetInnerHTML={{ __html: f.sublabel }}></i>
619
- ) : null}
620
- </div>
621
- );
622
- })}
623
- <br />
624
- </div>
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
- const ConfigField = ({
648
- field,
649
- configuration,
650
- setProp,
651
- onChange,
652
- props,
653
- isStyle,
654
- }) => {
655
- /**
656
- * @param {object} v
657
- * @returns {void}
658
- */
659
- const options = useContext(optionsCtx);
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
- const myOnChange = (v) => {
662
- setProp((prop) => {
663
- if (configuration) {
664
- if (!prop.configuration) prop.configuration = {};
665
- prop.configuration[field.name] = v;
666
- } else if (isStyle) {
667
- if (!prop.style) prop.style = {};
668
- prop.style[field.name] = v;
669
- } else prop[field.name] = v;
670
- });
671
- onChange && onChange(field.name, v);
672
- };
673
- const value = or_if_undef(
674
- configuration
675
- ? configuration[field.name]
676
- : isStyle
677
- ? props.style[field.name]
678
- : props[field.name],
679
- field.default
680
- );
681
- if (field.input_type === "fromtype") field.input_type = null;
682
- if (field.type && field.type.name === "String" && field.attributes.options) {
683
- field.input_type = "select";
684
- field.options =
685
- typeof field.attributes.options === "string"
686
- ? field.attributes.options.split(",").map((s) => s.trim())
687
- : field.attributes.options;
688
- if (!field.required && field.options) field.options.unshift("");
689
- }
690
- const dispatch = {
691
- String() {
692
- if (field.attributes?.options) {
693
- const options =
694
- typeof field.attributes.options === "string"
695
- ? field.attributes.options.split(",").map((s) => s.trim())
696
- : field.attributes.options;
697
- return (
698
- <select
699
- className="form-control form-select"
700
- value={value || ""}
701
- onChange={(e) => e.target && myOnChange(e.target.value)}
702
- onBlur={(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
- 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="checkbox"
764
- className="form-check-input"
765
- checked={value}
766
- onChange={(e) => e.target && myOnChange(e.target.checked)}
738
+ type="text"
739
+ className="form-control"
740
+ value={value || ""}
741
+ onChange={(e) => e.target && myOnChange(e.target.value)}
767
742
  />
768
- <label className="form-check-label">{field.label}</label>
769
- </div>
770
- ),
771
- textarea: () => (
772
- <textarea
773
- rows="6"
774
- type="text"
775
- className="form-control"
776
- value={value}
777
- onChange={(e) => e.target && myOnChange(e.target.value)}
778
- />
779
- ),
780
- code: () => (
781
- <textarea
782
- rows="6"
783
- type="text"
784
- className="form-control"
785
- value={value}
786
- onChange={(e) => e.target && myOnChange(e.target.value)}
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
- select: () => (
790
- <select
791
- className="form-control form-select"
792
- value={value || ""}
793
- onChange={(e) => e.target && myOnChange(e.target.value)}
794
- onBlur={(e) => e.target && myOnChange(e.target.value)}
795
- >
796
- {field.options.map((o, ix) => (
797
- <option key={ix}>{o}</option>
798
- ))}
799
- </select>
800
- ),
801
- btn_select: () => (
802
- <div className="btn-group w-100" role="group">
803
- {field.options.map((o, ix) => (
804
- <button
805
- key={ix}
806
- title={o.title || o.value}
807
- type="button"
808
- style={{ width: `${Math.floor(100 / field.options.length)}%` }}
809
- className={`btn btn-sm btn-${value !== o.value ? "outline-" : ""
810
- }secondary ${field.btnClass || ""}`}
811
- onClick={() => myOnChange(o.value)}
812
- >
813
- {o.label}
814
- </button>
815
- ))}
816
- </div>
817
- ),
818
- DimUnits: () => {
819
- let styleVal, styleDim;
820
- if (isStyle && value === "auto") {
821
- styleVal = "";
822
- styleDim = "auto";
823
- } else if (isStyle && value && typeof value === "string") {
824
- const matches = value.match(/^([0-9]+\.?[0-9]*)(.*)/);
825
- if (matches) {
826
- styleVal = matches[1];
827
- styleDim = matches[2];
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
- return (
831
- <Fragment>
832
- {styleDim !== "auto" && (
833
- <input
834
- type="number"
835
- value={(isStyle ? styleVal : value) || ""}
836
- className="w-50 form-control-sm d-inline dimunit"
837
- disabled={field.autoable && styleDim === "auto"}
838
- onChange={(e) =>
839
- e?.target &&
840
- myOnChange(
841
- isStyle
842
- ? `${e.target.value}${styleDim || "px"}`
843
- : e.target.value
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
- </Fragment>
881
- );
882
- },
883
- };
884
- const f = dispatch[field.input_type || field.type.name || field.type];
885
- return f ? f() : null;
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
- const SettingsFromFields = (fields) => () => {
896
- const node = useNode((node) => {
897
- const ps = {};
898
- fields.forEach((f) => {
899
- ps[f.name] = node.data.props[f.name];
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
- const {
906
- actions: { setProp },
907
- } = node;
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
- return (
910
- <table className="w-100">
911
- <tbody>
912
- {fields.map((f, ix) => (
913
- <SettingsRow field={f} key={ix} node={node} setProp={setProp} />
914
- ))}
915
- </tbody>
916
- </table>
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
- const SettingsSectionHeaderRow = ({ title }) => (
929
- <tr>
930
- <th colSpan="2">{title}</th>
931
- </tr>
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
- const SettingsRow = ({ field, node, setProp, onChange, isStyle }) => {
947
- const fullWidth = ["String", "Bool", "textarea"].includes(field.type);
948
- const needLabel = field.type !== "Bool";
949
- const inner = field.canBeFormula ? (
950
- <OrFormula
951
- nodekey={field.name}
952
- isFormula={node.isFormula}
953
- {...{ setProp, node }}
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
- return (
972
- <tr>
973
- {fullWidth ? (
974
- <td colSpan="2">
975
- {needLabel && <label>{field.label}</label>}
976
- {inner}
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
- <Fragment>
980
- <td>
981
- <label>{field.label}</label>
982
- </td>
983
- <td>{inner}</td>
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
- const ButtonOrLinkSettingsRows = ({
1066
- setProp,
1067
- btnClass = null,
1068
- keyPrefix = "",
1069
- values,
1070
- linkFirst = false,
1071
- }) => {
1072
- const setAProp = setAPropGen(setProp);
1073
- const addBtnClass = (s) => (btnClass ? `${btnClass} ${s}` : s);
1074
- return [
1075
- <tr key="btnstyle">
1076
- <td>
1077
- <label>Style</label>
1078
- </td>
1079
- <td>
1080
- <select
1081
- className="form-control form-select"
1082
- value={values[keyPrefix + "style"]}
1083
- onChange={setAProp(keyPrefix + "style")}
1084
- >
1085
- {linkFirst ? (
1086
- <option value={addBtnClass("btn-link")}>Link</option>
1087
- ) : null}
1088
- <option value={addBtnClass("btn-primary")}>Primary button</option>
1089
- <option value={addBtnClass("btn-secondary")}>Secondary button</option>
1090
- <option value={addBtnClass("btn-success")}>Success button</option>
1091
- <option value={addBtnClass("btn-danger")}>Danger button</option>
1092
- <option value={addBtnClass("btn-outline-primary")}>
1093
- Primary outline button
1094
- </option>
1095
- <option value={addBtnClass("btn-outline-secondary")}>
1096
- Secondary outline button
1097
- </option>
1098
- <option value={addBtnClass("btn-custom-color")}>
1099
- Button custom color
1100
- </option>
1101
- {!linkFirst ? (
1102
- <option value={addBtnClass("btn-link")}>Link</option>
1103
- ) : null}
1104
- </select>
1105
- </td>
1106
- </tr>,
1107
- <tr key="btnsz">
1108
- <td>
1109
- <label>Size</label>
1110
- </td>
1111
- <td>
1112
- <select
1113
- className="form-control form-select"
1114
- value={values[keyPrefix + "size"]}
1115
- onChange={setAProp(keyPrefix + "size")}
1116
- >
1117
- <option value="">Standard</option>
1118
- <option value="btn-lg">Large</option>
1119
- <option value="btn-sm">Small</option>
1120
- <option value="btn-block">Block</option>
1121
- <option value="btn-block btn-lg">Large block</option>
1122
- </select>
1123
- </td>
1124
- </tr>,
1125
- <tr key="btnicon">
1126
- <td>
1127
- <label>Icon</label>
1128
- </td>
1129
- <td>
1130
- <FontIconPicker
1131
- value={values[keyPrefix + "icon"]}
1132
- onChange={(value) =>
1133
- setProp((prop) => (prop[keyPrefix + "icon"] = value))
1134
- }
1135
- isMulti={false}
1136
- icons={faIcons}
1137
- />
1138
- </td>
1139
- </tr>,
1140
- ...(values[keyPrefix + "style"] === addBtnClass("btn-custom-color")
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
- (key, opts = {}) =>
1246
- (e) => {
1247
- if (e.target) {
1248
- const target_value = opts?.checked ? e.target.checked : e.target.value;
1249
- setProp((prop) => (prop[key] = target_value));
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 <Tippy content={children} visible={visible} onClickOutside={hide} interactive={true}>
1258
- <span
1259
- onClick={visible ? hide : show} className="ms-1"
1260
- ><FontAwesomeIcon icon={faInfoCircle} /></span>
1261
- </Tippy>
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
+ };