@bpmn-io/form-js-viewer 0.7.2 → 0.8.0-alpha.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.
- package/dist/assets/form-js.css +127 -24
- package/dist/index.cjs +510 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +507 -43
- package/dist/index.es.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/render/components/form-fields/Checklist.d.ts +10 -0
- package/dist/types/render/components/form-fields/Radio.d.ts +1 -6
- package/dist/types/render/components/form-fields/Select.d.ts +1 -6
- package/dist/types/render/components/form-fields/Taglist.d.ts +10 -0
- package/dist/types/render/components/form-fields/parts/DropdownList.d.ts +1 -0
- package/dist/types/render/components/index.d.ts +3 -1
- package/dist/types/render/hooks/useKeyDownAction.d.ts +1 -0
- package/dist/types/render/hooks/useValuesAsync.d.ts +28 -0
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -8,14 +8,17 @@ var snarkdown = require('@bpmn-io/snarkdown');
|
|
|
8
8
|
var jsxRuntime = require('preact/jsx-runtime');
|
|
9
9
|
var hooks = require('preact/hooks');
|
|
10
10
|
var preact = require('preact');
|
|
11
|
+
var React = require('preact/compat');
|
|
12
|
+
var classNames = require('classnames');
|
|
11
13
|
var Markup = require('preact-markup');
|
|
12
|
-
var compat = require('preact/compat');
|
|
13
14
|
var didi = require('didi');
|
|
14
15
|
|
|
15
16
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
16
17
|
|
|
17
18
|
var Ids__default = /*#__PURE__*/_interopDefaultLegacy(Ids);
|
|
18
19
|
var snarkdown__default = /*#__PURE__*/_interopDefaultLegacy(snarkdown);
|
|
20
|
+
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
21
|
+
var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
|
|
19
22
|
var Markup__default = /*#__PURE__*/_interopDefaultLegacy(Markup);
|
|
20
23
|
|
|
21
24
|
var FN_REF = '__fn';
|
|
@@ -817,19 +820,26 @@ class Importer {
|
|
|
817
820
|
const {
|
|
818
821
|
defaultValue,
|
|
819
822
|
_path,
|
|
820
|
-
type
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
823
|
+
type,
|
|
824
|
+
valuesKey
|
|
825
|
+
} = formField; // get values defined via valuesKey
|
|
826
|
+
|
|
827
|
+
if (valuesKey) {
|
|
828
|
+
importedData = { ...importedData,
|
|
829
|
+
[valuesKey]: minDash.get(data, [valuesKey])
|
|
830
|
+
};
|
|
831
|
+
} // try to get value from data
|
|
832
|
+
// if unavailable - try to get default value from form field
|
|
833
|
+
// if unavailable - get empty value from form field
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
if (_path) {
|
|
837
|
+
importedData = { ...importedData,
|
|
838
|
+
[_path[0]]: minDash.get(data, _path, minDash.isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue)
|
|
839
|
+
};
|
|
840
|
+
}
|
|
829
841
|
|
|
830
|
-
return
|
|
831
|
-
[_path[0]]: minDash.get(data, _path, minDash.isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue)
|
|
832
|
-
};
|
|
842
|
+
return importedData;
|
|
833
843
|
}, {});
|
|
834
844
|
}
|
|
835
845
|
|
|
@@ -990,7 +1000,7 @@ function safeMarkdown(markdown) {
|
|
|
990
1000
|
return sanitizeHTML(html);
|
|
991
1001
|
}
|
|
992
1002
|
|
|
993
|
-
const type$
|
|
1003
|
+
const type$8 = 'button';
|
|
994
1004
|
function Button(props) {
|
|
995
1005
|
const {
|
|
996
1006
|
disabled,
|
|
@@ -1000,7 +1010,7 @@ function Button(props) {
|
|
|
1000
1010
|
action = 'submit'
|
|
1001
1011
|
} = field;
|
|
1002
1012
|
return jsxRuntime.jsx("div", {
|
|
1003
|
-
class: formFieldClasses(type$
|
|
1013
|
+
class: formFieldClasses(type$8),
|
|
1004
1014
|
children: jsxRuntime.jsx("button", {
|
|
1005
1015
|
class: "fjs-button",
|
|
1006
1016
|
type: action,
|
|
@@ -1017,7 +1027,7 @@ Button.create = function (options = {}) {
|
|
|
1017
1027
|
};
|
|
1018
1028
|
};
|
|
1019
1029
|
|
|
1020
|
-
Button.type = type$
|
|
1030
|
+
Button.type = type$8;
|
|
1021
1031
|
Button.label = 'Button';
|
|
1022
1032
|
Button.keyed = true;
|
|
1023
1033
|
|
|
@@ -1099,7 +1109,7 @@ function Label(props) {
|
|
|
1099
1109
|
});
|
|
1100
1110
|
}
|
|
1101
1111
|
|
|
1102
|
-
const type$
|
|
1112
|
+
const type$7 = 'checkbox';
|
|
1103
1113
|
function Checkbox(props) {
|
|
1104
1114
|
const {
|
|
1105
1115
|
disabled,
|
|
@@ -1126,7 +1136,7 @@ function Checkbox(props) {
|
|
|
1126
1136
|
formId
|
|
1127
1137
|
} = hooks.useContext(FormContext);
|
|
1128
1138
|
return jsxRuntime.jsxs("div", {
|
|
1129
|
-
class: formFieldClasses(type$
|
|
1139
|
+
class: formFieldClasses(type$7, errors),
|
|
1130
1140
|
children: [jsxRuntime.jsx(Label, {
|
|
1131
1141
|
id: prefixId(id, formId),
|
|
1132
1142
|
label: label,
|
|
@@ -1152,7 +1162,7 @@ Checkbox.create = function (options = {}) {
|
|
|
1152
1162
|
};
|
|
1153
1163
|
};
|
|
1154
1164
|
|
|
1155
|
-
Checkbox.type = type$
|
|
1165
|
+
Checkbox.type = type$7;
|
|
1156
1166
|
Checkbox.label = 'Checkbox';
|
|
1157
1167
|
Checkbox.keyed = true;
|
|
1158
1168
|
Checkbox.emptyValue = false;
|
|
@@ -1164,6 +1174,152 @@ function useService (type, strict) {
|
|
|
1164
1174
|
return getService(type, strict);
|
|
1165
1175
|
}
|
|
1166
1176
|
|
|
1177
|
+
/**
|
|
1178
|
+
* @enum { String }
|
|
1179
|
+
*/
|
|
1180
|
+
|
|
1181
|
+
const LOAD_STATES = {
|
|
1182
|
+
LOADING: 'loading',
|
|
1183
|
+
LOADED: 'loaded',
|
|
1184
|
+
ERROR: 'error'
|
|
1185
|
+
};
|
|
1186
|
+
/**
|
|
1187
|
+
* @typedef {Object} ValuesGetter
|
|
1188
|
+
* @property {Object[]} values - The values data
|
|
1189
|
+
* @property {(LOAD_STATES)} state - The values data's loading state, to use for conditional rendering
|
|
1190
|
+
*/
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* A hook to load values for single and multiselect components.
|
|
1194
|
+
*
|
|
1195
|
+
* @param {Object} field - The form field to handle values for
|
|
1196
|
+
* @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
|
|
1197
|
+
*/
|
|
1198
|
+
|
|
1199
|
+
function useValuesAsync (field) {
|
|
1200
|
+
const {
|
|
1201
|
+
valuesKey,
|
|
1202
|
+
values: staticValues
|
|
1203
|
+
} = field;
|
|
1204
|
+
const [valuesGetter, setValuesGetter] = hooks.useState({
|
|
1205
|
+
values: [],
|
|
1206
|
+
error: undefined,
|
|
1207
|
+
state: LOAD_STATES.LOADING
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
const initialData = useService('form')._getState().initialData;
|
|
1211
|
+
|
|
1212
|
+
hooks.useEffect(() => {
|
|
1213
|
+
let values = [];
|
|
1214
|
+
|
|
1215
|
+
if (valuesKey !== undefined) {
|
|
1216
|
+
const keyedValues = (initialData || {})[valuesKey];
|
|
1217
|
+
|
|
1218
|
+
if (keyedValues && Array.isArray(keyedValues)) {
|
|
1219
|
+
values = keyedValues;
|
|
1220
|
+
}
|
|
1221
|
+
} else if (staticValues !== undefined) {
|
|
1222
|
+
values = Array.isArray(staticValues) ? staticValues : [];
|
|
1223
|
+
} else {
|
|
1224
|
+
setValuesGetter(getErrorState('No values source defined in the form definition'));
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
setValuesGetter(buildLoadedState(values));
|
|
1229
|
+
}, [valuesKey, staticValues, initialData]);
|
|
1230
|
+
return valuesGetter;
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
const getErrorState = error => ({
|
|
1234
|
+
values: [],
|
|
1235
|
+
error,
|
|
1236
|
+
state: LOAD_STATES.ERROR
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
const buildLoadedState = values => ({
|
|
1240
|
+
values,
|
|
1241
|
+
error: undefined,
|
|
1242
|
+
state: LOAD_STATES.LOADED
|
|
1243
|
+
});
|
|
1244
|
+
|
|
1245
|
+
const type$6 = 'checklist';
|
|
1246
|
+
function Checklist(props) {
|
|
1247
|
+
const {
|
|
1248
|
+
disabled,
|
|
1249
|
+
errors = [],
|
|
1250
|
+
field,
|
|
1251
|
+
value = []
|
|
1252
|
+
} = props;
|
|
1253
|
+
const {
|
|
1254
|
+
description,
|
|
1255
|
+
id,
|
|
1256
|
+
label
|
|
1257
|
+
} = field;
|
|
1258
|
+
|
|
1259
|
+
const toggleCheckbox = v => {
|
|
1260
|
+
let newValue = [...value];
|
|
1261
|
+
|
|
1262
|
+
if (!newValue.includes(v)) {
|
|
1263
|
+
newValue.push(v);
|
|
1264
|
+
} else {
|
|
1265
|
+
newValue = newValue.filter(x => x != v);
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
props.onChange({
|
|
1269
|
+
field,
|
|
1270
|
+
value: newValue
|
|
1271
|
+
});
|
|
1272
|
+
};
|
|
1273
|
+
|
|
1274
|
+
const {
|
|
1275
|
+
state: loadState,
|
|
1276
|
+
values: options
|
|
1277
|
+
} = useValuesAsync(field);
|
|
1278
|
+
const {
|
|
1279
|
+
formId
|
|
1280
|
+
} = hooks.useContext(FormContext);
|
|
1281
|
+
return jsxRuntime.jsxs("div", {
|
|
1282
|
+
class: formFieldClasses(type$6, errors),
|
|
1283
|
+
children: [jsxRuntime.jsx(Label, {
|
|
1284
|
+
label: label
|
|
1285
|
+
}), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
|
|
1286
|
+
return jsxRuntime.jsx(Label, {
|
|
1287
|
+
id: prefixId(`${id}-${index}`, formId),
|
|
1288
|
+
label: v.label,
|
|
1289
|
+
required: false,
|
|
1290
|
+
children: jsxRuntime.jsx("input", {
|
|
1291
|
+
checked: value.includes(v.value),
|
|
1292
|
+
class: "fjs-input",
|
|
1293
|
+
disabled: disabled,
|
|
1294
|
+
id: prefixId(`${id}-${index}`, formId),
|
|
1295
|
+
type: "checkbox",
|
|
1296
|
+
onClick: () => toggleCheckbox(v.value)
|
|
1297
|
+
})
|
|
1298
|
+
}, `${id}-${index}`);
|
|
1299
|
+
}), jsxRuntime.jsx(Description, {
|
|
1300
|
+
description: description
|
|
1301
|
+
}), jsxRuntime.jsx(Errors, {
|
|
1302
|
+
errors: errors
|
|
1303
|
+
})]
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
Checklist.create = function (options = {}) {
|
|
1308
|
+
if (options.valuesKey) return options;
|
|
1309
|
+
return {
|
|
1310
|
+
values: [{
|
|
1311
|
+
label: 'Value',
|
|
1312
|
+
value: 'value'
|
|
1313
|
+
}],
|
|
1314
|
+
...options
|
|
1315
|
+
};
|
|
1316
|
+
};
|
|
1317
|
+
|
|
1318
|
+
Checklist.type = type$6;
|
|
1319
|
+
Checklist.label = 'Checklist';
|
|
1320
|
+
Checklist.keyed = true;
|
|
1321
|
+
Checklist.emptyValue = [];
|
|
1322
|
+
|
|
1167
1323
|
const noop$1 = () => false;
|
|
1168
1324
|
|
|
1169
1325
|
function FormField(props) {
|
|
@@ -1327,7 +1483,7 @@ function PoweredBy(props) {
|
|
|
1327
1483
|
}
|
|
1328
1484
|
|
|
1329
1485
|
return jsxRuntime.jsxs(preact.Fragment, {
|
|
1330
|
-
children: [
|
|
1486
|
+
children: [React.createPortal(jsxRuntime.jsx(Lightbox, {
|
|
1331
1487
|
open: open,
|
|
1332
1488
|
onBackdropClick: toggleOpen(false)
|
|
1333
1489
|
}), document.body), jsxRuntime.jsx(Link, {
|
|
@@ -1372,7 +1528,7 @@ function FormComponent(props) {
|
|
|
1372
1528
|
});
|
|
1373
1529
|
}
|
|
1374
1530
|
|
|
1375
|
-
const type$
|
|
1531
|
+
const type$5 = 'number';
|
|
1376
1532
|
function Number(props) {
|
|
1377
1533
|
const {
|
|
1378
1534
|
disabled,
|
|
@@ -1404,7 +1560,7 @@ function Number(props) {
|
|
|
1404
1560
|
formId
|
|
1405
1561
|
} = hooks.useContext(FormContext);
|
|
1406
1562
|
return jsxRuntime.jsxs("div", {
|
|
1407
|
-
class: formFieldClasses(type$
|
|
1563
|
+
class: formFieldClasses(type$5, errors),
|
|
1408
1564
|
children: [jsxRuntime.jsx(Label, {
|
|
1409
1565
|
id: prefixId(id, formId),
|
|
1410
1566
|
label: label,
|
|
@@ -1429,12 +1585,12 @@ Number.create = function (options = {}) {
|
|
|
1429
1585
|
};
|
|
1430
1586
|
};
|
|
1431
1587
|
|
|
1432
|
-
Number.type = type$
|
|
1588
|
+
Number.type = type$5;
|
|
1433
1589
|
Number.keyed = true;
|
|
1434
1590
|
Number.label = 'Number';
|
|
1435
1591
|
Number.emptyValue = null;
|
|
1436
1592
|
|
|
1437
|
-
const type$
|
|
1593
|
+
const type$4 = 'radio';
|
|
1438
1594
|
function Radio(props) {
|
|
1439
1595
|
const {
|
|
1440
1596
|
disabled,
|
|
@@ -1446,8 +1602,7 @@ function Radio(props) {
|
|
|
1446
1602
|
description,
|
|
1447
1603
|
id,
|
|
1448
1604
|
label,
|
|
1449
|
-
validate = {}
|
|
1450
|
-
values
|
|
1605
|
+
validate = {}
|
|
1451
1606
|
} = field;
|
|
1452
1607
|
const {
|
|
1453
1608
|
required
|
|
@@ -1460,26 +1615,30 @@ function Radio(props) {
|
|
|
1460
1615
|
});
|
|
1461
1616
|
};
|
|
1462
1617
|
|
|
1618
|
+
const {
|
|
1619
|
+
state: loadState,
|
|
1620
|
+
values: options
|
|
1621
|
+
} = useValuesAsync(field);
|
|
1463
1622
|
const {
|
|
1464
1623
|
formId
|
|
1465
1624
|
} = hooks.useContext(FormContext);
|
|
1466
1625
|
return jsxRuntime.jsxs("div", {
|
|
1467
|
-
class: formFieldClasses(type$
|
|
1626
|
+
class: formFieldClasses(type$4, errors),
|
|
1468
1627
|
children: [jsxRuntime.jsx(Label, {
|
|
1469
1628
|
label: label,
|
|
1470
1629
|
required: required
|
|
1471
|
-
}),
|
|
1630
|
+
}), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
|
|
1472
1631
|
return jsxRuntime.jsx(Label, {
|
|
1473
1632
|
id: prefixId(`${id}-${index}`, formId),
|
|
1474
|
-
label:
|
|
1633
|
+
label: option.label,
|
|
1475
1634
|
required: false,
|
|
1476
1635
|
children: jsxRuntime.jsx("input", {
|
|
1477
|
-
checked:
|
|
1636
|
+
checked: option.value === value,
|
|
1478
1637
|
class: "fjs-input",
|
|
1479
1638
|
disabled: disabled,
|
|
1480
1639
|
id: prefixId(`${id}-${index}`, formId),
|
|
1481
1640
|
type: "radio",
|
|
1482
|
-
onClick: () => onChange(
|
|
1641
|
+
onClick: () => onChange(option.value)
|
|
1483
1642
|
})
|
|
1484
1643
|
}, `${id}-${index}`);
|
|
1485
1644
|
}), jsxRuntime.jsx(Description, {
|
|
@@ -1491,6 +1650,7 @@ function Radio(props) {
|
|
|
1491
1650
|
}
|
|
1492
1651
|
|
|
1493
1652
|
Radio.create = function (options = {}) {
|
|
1653
|
+
if (options.valuesKey) return options;
|
|
1494
1654
|
return {
|
|
1495
1655
|
values: [{
|
|
1496
1656
|
label: 'Value',
|
|
@@ -1500,12 +1660,12 @@ Radio.create = function (options = {}) {
|
|
|
1500
1660
|
};
|
|
1501
1661
|
};
|
|
1502
1662
|
|
|
1503
|
-
Radio.type = type$
|
|
1663
|
+
Radio.type = type$4;
|
|
1504
1664
|
Radio.label = 'Radio';
|
|
1505
1665
|
Radio.keyed = true;
|
|
1506
1666
|
Radio.emptyValue = null;
|
|
1507
1667
|
|
|
1508
|
-
const type$
|
|
1668
|
+
const type$3 = 'select';
|
|
1509
1669
|
function Select(props) {
|
|
1510
1670
|
const {
|
|
1511
1671
|
disabled,
|
|
@@ -1517,8 +1677,7 @@ function Select(props) {
|
|
|
1517
1677
|
description,
|
|
1518
1678
|
id,
|
|
1519
1679
|
label,
|
|
1520
|
-
validate = {}
|
|
1521
|
-
values
|
|
1680
|
+
validate = {}
|
|
1522
1681
|
} = field;
|
|
1523
1682
|
const {
|
|
1524
1683
|
required
|
|
@@ -1533,11 +1692,15 @@ function Select(props) {
|
|
|
1533
1692
|
});
|
|
1534
1693
|
};
|
|
1535
1694
|
|
|
1695
|
+
const {
|
|
1696
|
+
state: loadState,
|
|
1697
|
+
values: options
|
|
1698
|
+
} = useValuesAsync(field);
|
|
1536
1699
|
const {
|
|
1537
1700
|
formId
|
|
1538
1701
|
} = hooks.useContext(FormContext);
|
|
1539
1702
|
return jsxRuntime.jsxs("div", {
|
|
1540
|
-
class: formFieldClasses(type$
|
|
1703
|
+
class: formFieldClasses(type$3, errors),
|
|
1541
1704
|
children: [jsxRuntime.jsx(Label, {
|
|
1542
1705
|
id: prefixId(id, formId),
|
|
1543
1706
|
label: label,
|
|
@@ -1550,10 +1713,10 @@ function Select(props) {
|
|
|
1550
1713
|
value: value || '',
|
|
1551
1714
|
children: [jsxRuntime.jsx("option", {
|
|
1552
1715
|
value: ""
|
|
1553
|
-
}),
|
|
1716
|
+
}), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
|
|
1554
1717
|
return jsxRuntime.jsx("option", {
|
|
1555
|
-
value:
|
|
1556
|
-
children:
|
|
1718
|
+
value: option.value,
|
|
1719
|
+
children: option.label
|
|
1557
1720
|
}, `${id}-${index}`);
|
|
1558
1721
|
})]
|
|
1559
1722
|
}), jsxRuntime.jsx(Description, {
|
|
@@ -1565,6 +1728,7 @@ function Select(props) {
|
|
|
1565
1728
|
}
|
|
1566
1729
|
|
|
1567
1730
|
Select.create = function (options = {}) {
|
|
1731
|
+
if (options.valuesKey) return options;
|
|
1568
1732
|
return {
|
|
1569
1733
|
values: [{
|
|
1570
1734
|
label: 'Value',
|
|
@@ -1574,11 +1738,313 @@ Select.create = function (options = {}) {
|
|
|
1574
1738
|
};
|
|
1575
1739
|
};
|
|
1576
1740
|
|
|
1577
|
-
Select.type = type$
|
|
1741
|
+
Select.type = type$3;
|
|
1578
1742
|
Select.label = 'Select';
|
|
1579
1743
|
Select.keyed = true;
|
|
1580
1744
|
Select.emptyValue = null;
|
|
1581
1745
|
|
|
1746
|
+
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
1747
|
+
var CloseIcon = (({
|
|
1748
|
+
styles = {},
|
|
1749
|
+
...props
|
|
1750
|
+
}) => /*#__PURE__*/React__default['default'].createElement("svg", _extends({
|
|
1751
|
+
width: "16",
|
|
1752
|
+
height: "16",
|
|
1753
|
+
fill: "none",
|
|
1754
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
1755
|
+
}, props), /*#__PURE__*/React__default['default'].createElement("path", {
|
|
1756
|
+
fillRule: "evenodd",
|
|
1757
|
+
clipRule: "evenodd",
|
|
1758
|
+
d: "M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7z",
|
|
1759
|
+
fill: "#000"
|
|
1760
|
+
})));
|
|
1761
|
+
|
|
1762
|
+
function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
1763
|
+
function downHandler({
|
|
1764
|
+
key
|
|
1765
|
+
}) {
|
|
1766
|
+
if (key === targetKey) {
|
|
1767
|
+
action();
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
hooks.useEffect(() => {
|
|
1772
|
+
listenerElement.addEventListener('keydown', downHandler);
|
|
1773
|
+
return () => {
|
|
1774
|
+
listenerElement.removeEventListener('keydown', downHandler);
|
|
1775
|
+
};
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
const DEFAULT_LABEL_GETTER = value => value;
|
|
1780
|
+
|
|
1781
|
+
const NOOP = () => {};
|
|
1782
|
+
|
|
1783
|
+
function DropdownList(props) {
|
|
1784
|
+
const {
|
|
1785
|
+
keyEventsListener = window,
|
|
1786
|
+
values = [],
|
|
1787
|
+
getLabel = DEFAULT_LABEL_GETTER,
|
|
1788
|
+
onValueSelected = NOOP,
|
|
1789
|
+
height = 235,
|
|
1790
|
+
emptyListMessage = 'No results'
|
|
1791
|
+
} = props;
|
|
1792
|
+
const [mouseControl, setMouseControl] = hooks.useState(true);
|
|
1793
|
+
const [focusedValueIndex, setFocusedValueIndex] = hooks.useState(0);
|
|
1794
|
+
const dropdownContainer = hooks.useRef();
|
|
1795
|
+
const mouseScreenPos = hooks.useRef();
|
|
1796
|
+
const focusedItem = hooks.useMemo(() => values.length ? values[focusedValueIndex] : null, [focusedValueIndex, values]);
|
|
1797
|
+
const changeFocusedValueIndex = hooks.useCallback(delta => {
|
|
1798
|
+
setFocusedValueIndex(x => Math.min(Math.max(0, x + delta), values.length - 1));
|
|
1799
|
+
}, [values.length]);
|
|
1800
|
+
hooks.useEffect(() => {
|
|
1801
|
+
if (focusedValueIndex === 0) return;
|
|
1802
|
+
|
|
1803
|
+
if (!focusedValueIndex || !values.length) {
|
|
1804
|
+
setFocusedValueIndex(0);
|
|
1805
|
+
} else if (focusedValueIndex >= values.length) {
|
|
1806
|
+
setFocusedValueIndex(values.length - 1);
|
|
1807
|
+
}
|
|
1808
|
+
}, [focusedValueIndex, values.length]);
|
|
1809
|
+
useKeyDownAction('ArrowUp', () => {
|
|
1810
|
+
if (values.length) {
|
|
1811
|
+
changeFocusedValueIndex(-1);
|
|
1812
|
+
setMouseControl(false);
|
|
1813
|
+
}
|
|
1814
|
+
}, keyEventsListener);
|
|
1815
|
+
useKeyDownAction('ArrowDown', () => {
|
|
1816
|
+
if (values.length) {
|
|
1817
|
+
changeFocusedValueIndex(1);
|
|
1818
|
+
setMouseControl(false);
|
|
1819
|
+
}
|
|
1820
|
+
}, keyEventsListener);
|
|
1821
|
+
useKeyDownAction('Enter', () => {
|
|
1822
|
+
if (focusedItem) {
|
|
1823
|
+
onValueSelected(focusedItem);
|
|
1824
|
+
}
|
|
1825
|
+
}, keyEventsListener);
|
|
1826
|
+
hooks.useEffect(() => {
|
|
1827
|
+
const individualEntries = dropdownContainer.current.children;
|
|
1828
|
+
|
|
1829
|
+
if (individualEntries.length && !mouseControl) {
|
|
1830
|
+
individualEntries[focusedValueIndex].scrollIntoView({
|
|
1831
|
+
block: 'nearest',
|
|
1832
|
+
inline: 'nearest'
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
}, [focusedValueIndex, mouseControl]);
|
|
1836
|
+
|
|
1837
|
+
const mouseMove = (e, i) => {
|
|
1838
|
+
const userMoved = !mouseScreenPos.current || mouseScreenPos.current.x !== e.screenX && mouseScreenPos.current.y !== e.screenY;
|
|
1839
|
+
|
|
1840
|
+
if (userMoved) {
|
|
1841
|
+
mouseScreenPos.current = {
|
|
1842
|
+
x: e.screenX,
|
|
1843
|
+
y: e.screenY
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
if (!mouseControl) {
|
|
1847
|
+
setMouseControl(true);
|
|
1848
|
+
setFocusedValueIndex(i);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
};
|
|
1852
|
+
|
|
1853
|
+
return jsxRuntime.jsxs("div", {
|
|
1854
|
+
ref: dropdownContainer,
|
|
1855
|
+
tabIndex: -1,
|
|
1856
|
+
class: "fjs-dropdownlist",
|
|
1857
|
+
style: {
|
|
1858
|
+
maxHeight: height
|
|
1859
|
+
},
|
|
1860
|
+
children: [!!values.length && values.map((v, i) => {
|
|
1861
|
+
return jsxRuntime.jsx("div", {
|
|
1862
|
+
class: 'fjs-dropdownlist-item' + (focusedValueIndex === i ? ' focused' : ''),
|
|
1863
|
+
onMouseMove: e => mouseMove(e, i),
|
|
1864
|
+
onMouseEnter: mouseControl ? () => setFocusedValueIndex(i) : undefined,
|
|
1865
|
+
onMouseDown: e => {
|
|
1866
|
+
e.preventDefault();
|
|
1867
|
+
onValueSelected(v);
|
|
1868
|
+
},
|
|
1869
|
+
children: getLabel(v)
|
|
1870
|
+
});
|
|
1871
|
+
}), !values.length && jsxRuntime.jsx("div", {
|
|
1872
|
+
class: "fjs-dropdownlist-empty",
|
|
1873
|
+
children: emptyListMessage
|
|
1874
|
+
})]
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
const type$2 = 'taglist';
|
|
1879
|
+
function Taglist(props) {
|
|
1880
|
+
const {
|
|
1881
|
+
disabled,
|
|
1882
|
+
errors = [],
|
|
1883
|
+
field,
|
|
1884
|
+
value: values = []
|
|
1885
|
+
} = props;
|
|
1886
|
+
const {
|
|
1887
|
+
description,
|
|
1888
|
+
id,
|
|
1889
|
+
label
|
|
1890
|
+
} = field;
|
|
1891
|
+
const {
|
|
1892
|
+
formId
|
|
1893
|
+
} = hooks.useContext(FormContext);
|
|
1894
|
+
const [filter, setFilter] = hooks.useState('');
|
|
1895
|
+
const [selectedValues, setSelectedValues] = hooks.useState([]);
|
|
1896
|
+
const [filteredValues, setFilteredValues] = hooks.useState([]);
|
|
1897
|
+
const [isDropdownExpanded, setIsDropdownExpanded] = hooks.useState(false);
|
|
1898
|
+
const [hasValuesLeft, setHasValuesLeft] = hooks.useState(true);
|
|
1899
|
+
const [isEscapeClosed, setIsEscapeClose] = hooks.useState(false);
|
|
1900
|
+
const searchbarRef = hooks.useRef();
|
|
1901
|
+
const {
|
|
1902
|
+
state: loadState,
|
|
1903
|
+
values: options
|
|
1904
|
+
} = useValuesAsync(field); // Usage of stringify is necessary here because we want this effect to only trigger when there is a value change to the array
|
|
1905
|
+
|
|
1906
|
+
hooks.useEffect(() => {
|
|
1907
|
+
if (loadState === LOAD_STATES.LOADED) {
|
|
1908
|
+
const selectedValues = values.map(v => options.find(o => o.value === v)).filter(v => v !== undefined);
|
|
1909
|
+
setSelectedValues(selectedValues);
|
|
1910
|
+
} else {
|
|
1911
|
+
setSelectedValues([]);
|
|
1912
|
+
}
|
|
1913
|
+
}, [JSON.stringify(values), options, loadState]);
|
|
1914
|
+
hooks.useEffect(() => {
|
|
1915
|
+
if (loadState === LOAD_STATES.LOADED) {
|
|
1916
|
+
setFilteredValues(options.filter(o => o.label && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value)));
|
|
1917
|
+
} else {
|
|
1918
|
+
setFilteredValues([]);
|
|
1919
|
+
}
|
|
1920
|
+
}, [filter, JSON.stringify(values), options]);
|
|
1921
|
+
hooks.useEffect(() => {
|
|
1922
|
+
setHasValuesLeft(selectedValues.length < options.length);
|
|
1923
|
+
}, [selectedValues.length, options.length]);
|
|
1924
|
+
|
|
1925
|
+
const onFilterChange = ({
|
|
1926
|
+
target
|
|
1927
|
+
}) => {
|
|
1928
|
+
setIsEscapeClose(false);
|
|
1929
|
+
setFilter(target.value);
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
const selectValue = option => {
|
|
1933
|
+
setFilter('');
|
|
1934
|
+
props.onChange({
|
|
1935
|
+
value: [...values, option.value],
|
|
1936
|
+
field
|
|
1937
|
+
});
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
const deselectValue = option => {
|
|
1941
|
+
props.onChange({
|
|
1942
|
+
value: values.filter(v => v != option.value),
|
|
1943
|
+
field
|
|
1944
|
+
});
|
|
1945
|
+
};
|
|
1946
|
+
|
|
1947
|
+
const onInputKeyDown = e => {
|
|
1948
|
+
switch (e.key) {
|
|
1949
|
+
case 'ArrowUp':
|
|
1950
|
+
case 'ArrowDown':
|
|
1951
|
+
// We do not want the cursor to seek in the search field when we press up and down
|
|
1952
|
+
e.preventDefault();
|
|
1953
|
+
break;
|
|
1954
|
+
|
|
1955
|
+
case 'Backspace':
|
|
1956
|
+
if (!filter && selectedValues.length) {
|
|
1957
|
+
deselectValue(selectedValues[selectedValues.length - 1]);
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1960
|
+
break;
|
|
1961
|
+
|
|
1962
|
+
case 'Escape':
|
|
1963
|
+
setIsEscapeClose(true);
|
|
1964
|
+
break;
|
|
1965
|
+
|
|
1966
|
+
case 'Enter':
|
|
1967
|
+
if (isEscapeClosed) {
|
|
1968
|
+
setIsEscapeClose(false);
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
break;
|
|
1972
|
+
}
|
|
1973
|
+
};
|
|
1974
|
+
|
|
1975
|
+
return jsxRuntime.jsxs("div", {
|
|
1976
|
+
class: formFieldClasses(type$2, errors),
|
|
1977
|
+
children: [jsxRuntime.jsx(Label, {
|
|
1978
|
+
label: label,
|
|
1979
|
+
id: prefixId(id, formId)
|
|
1980
|
+
}), jsxRuntime.jsxs("div", {
|
|
1981
|
+
class: classNames__default['default']('fjs-taglist', {
|
|
1982
|
+
'disabled': disabled
|
|
1983
|
+
}),
|
|
1984
|
+
children: [!disabled && loadState === LOAD_STATES.LOADED && selectedValues.map(sv => {
|
|
1985
|
+
return jsxRuntime.jsxs("div", {
|
|
1986
|
+
class: "fjs-taglist-tag",
|
|
1987
|
+
onMouseDown: e => e.preventDefault(),
|
|
1988
|
+
children: [jsxRuntime.jsx("span", {
|
|
1989
|
+
class: "fjs-taglist-tag-label",
|
|
1990
|
+
children: sv.label
|
|
1991
|
+
}), jsxRuntime.jsx("span", {
|
|
1992
|
+
class: "fjs-taglist-tag-remove",
|
|
1993
|
+
onMouseDown: () => deselectValue(sv),
|
|
1994
|
+
children: jsxRuntime.jsx(CloseIcon, {})
|
|
1995
|
+
})]
|
|
1996
|
+
});
|
|
1997
|
+
}), jsxRuntime.jsx("input", {
|
|
1998
|
+
disabled: disabled,
|
|
1999
|
+
class: "fjs-taglist-input",
|
|
2000
|
+
ref: searchbarRef,
|
|
2001
|
+
id: prefixId(`${id}-search`, formId),
|
|
2002
|
+
onChange: onFilterChange,
|
|
2003
|
+
type: "text",
|
|
2004
|
+
value: filter,
|
|
2005
|
+
placeholder: 'Search',
|
|
2006
|
+
autoComplete: "off",
|
|
2007
|
+
onKeyDown: e => onInputKeyDown(e),
|
|
2008
|
+
onMouseDown: () => setIsEscapeClose(false),
|
|
2009
|
+
onFocus: () => setIsDropdownExpanded(true),
|
|
2010
|
+
onBlur: () => {
|
|
2011
|
+
setIsDropdownExpanded(false);
|
|
2012
|
+
setFilter('');
|
|
2013
|
+
}
|
|
2014
|
+
})]
|
|
2015
|
+
}), jsxRuntime.jsx("div", {
|
|
2016
|
+
class: "fjs-taglist-anchor",
|
|
2017
|
+
children: !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed && jsxRuntime.jsx(DropdownList, {
|
|
2018
|
+
values: filteredValues,
|
|
2019
|
+
getLabel: v => v.label,
|
|
2020
|
+
onValueSelected: v => selectValue(v),
|
|
2021
|
+
emptyListMessage: hasValuesLeft ? 'No results' : 'All values selected',
|
|
2022
|
+
listenerElement: searchbarRef.current
|
|
2023
|
+
})
|
|
2024
|
+
}), jsxRuntime.jsx(Description, {
|
|
2025
|
+
description: description
|
|
2026
|
+
}), jsxRuntime.jsx(Errors, {
|
|
2027
|
+
errors: errors
|
|
2028
|
+
})]
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
Taglist.create = function (options = {}) {
|
|
2033
|
+
if (options.valuesKey) return options;
|
|
2034
|
+
return {
|
|
2035
|
+
values: [{
|
|
2036
|
+
label: 'Value',
|
|
2037
|
+
value: 'value'
|
|
2038
|
+
}],
|
|
2039
|
+
...options
|
|
2040
|
+
};
|
|
2041
|
+
};
|
|
2042
|
+
|
|
2043
|
+
Taglist.type = type$2;
|
|
2044
|
+
Taglist.label = 'Taglist';
|
|
2045
|
+
Taglist.keyed = true;
|
|
2046
|
+
Taglist.emptyValue = [];
|
|
2047
|
+
|
|
1582
2048
|
const type$1 = 'text';
|
|
1583
2049
|
function Text(props) {
|
|
1584
2050
|
const {
|
|
@@ -1667,7 +2133,7 @@ Textfield.label = 'Text Field';
|
|
|
1667
2133
|
Textfield.keyed = true;
|
|
1668
2134
|
Textfield.emptyValue = '';
|
|
1669
2135
|
|
|
1670
|
-
const formFields = [Button, Checkbox, Default, Number, Radio, Select, Text, Textfield];
|
|
2136
|
+
const formFields = [Button, Checkbox, Checklist, Default, Number, Radio, Select, Taglist, Text, Textfield];
|
|
1671
2137
|
|
|
1672
2138
|
class FormFields {
|
|
1673
2139
|
constructor() {
|
|
@@ -2154,7 +2620,7 @@ class Form {
|
|
|
2154
2620
|
|
|
2155
2621
|
}
|
|
2156
2622
|
|
|
2157
|
-
const schemaVersion =
|
|
2623
|
+
const schemaVersion = 5;
|
|
2158
2624
|
/**
|
|
2159
2625
|
* @typedef { import('./types').CreateFormOptions } CreateFormOptions
|
|
2160
2626
|
*/
|
|
@@ -2181,6 +2647,7 @@ function createForm(options) {
|
|
|
2181
2647
|
|
|
2182
2648
|
exports.Button = Button;
|
|
2183
2649
|
exports.Checkbox = Checkbox;
|
|
2650
|
+
exports.Checklist = Checklist;
|
|
2184
2651
|
exports.Default = Default;
|
|
2185
2652
|
exports.Form = Form;
|
|
2186
2653
|
exports.FormComponent = FormComponent;
|
|
@@ -2191,6 +2658,7 @@ exports.FormRenderContext = FormRenderContext;
|
|
|
2191
2658
|
exports.Number = Number;
|
|
2192
2659
|
exports.Radio = Radio;
|
|
2193
2660
|
exports.Select = Select;
|
|
2661
|
+
exports.Taglist = Taglist;
|
|
2194
2662
|
exports.Text = Text;
|
|
2195
2663
|
exports.Textfield = Textfield;
|
|
2196
2664
|
exports.clone = clone;
|