@bpmn-io/form-js-viewer 0.13.1 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/form-js-base.css +6 -3
- package/dist/assets/form-js.css +6 -3
- package/dist/index.cjs +285 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +287 -42
- package/dist/index.es.js.map +1 -1
- package/dist/types/features/expression-language/FeelExpressionLanguage.d.ts +3 -5
- package/dist/types/features/expression-language/FeelersTemplating.d.ts +42 -0
- package/dist/types/features/expression-language/variableExtractionHelpers.d.ts +1 -0
- package/dist/types/util/index.d.ts +2 -1
- package/package.json +2 -2
package/dist/index.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Ids from 'ids';
|
|
2
2
|
import { isString, isArray, isFunction, isNumber, bind, assign, isNil, groupBy, flatten, get, isUndefined, set, findIndex, isObject } from 'min-dash';
|
|
3
|
-
import {
|
|
4
|
-
import { evaluate as evaluate$1 } from 'feelers';
|
|
3
|
+
import { parseExpressions, parseUnaryTests, evaluate, unaryTest } from 'feelin';
|
|
4
|
+
import { evaluate as evaluate$1, parser, buildSimpleTree } from 'feelers';
|
|
5
5
|
import showdown from 'showdown';
|
|
6
6
|
import Big from 'big.js';
|
|
7
7
|
import classNames from 'classnames';
|
|
@@ -13,15 +13,164 @@ import flatpickr from 'flatpickr';
|
|
|
13
13
|
import Markup from 'preact-markup';
|
|
14
14
|
import { Injector } from 'didi';
|
|
15
15
|
|
|
16
|
+
const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) => {
|
|
17
|
+
const {
|
|
18
|
+
depth = 0,
|
|
19
|
+
specialDepthAccessors = {}
|
|
20
|
+
} = options;
|
|
21
|
+
if (!['expression', 'unaryTest'].includes(feelFlavour)) return [];
|
|
22
|
+
const tree = feelFlavour === 'expression' ? parseExpressions(feelString) : parseUnaryTests(feelString);
|
|
23
|
+
const simpleExpressionTree = _buildSimpleFeelStructureTree(tree, feelString);
|
|
24
|
+
return function _unfoldVariables(node) {
|
|
25
|
+
if (node.name === 'PathExpression') {
|
|
26
|
+
if (Object.keys(specialDepthAccessors).length === 0) {
|
|
27
|
+
return depth === 0 ? [_getVariableNameAtPathIndex(node, 0)] : [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// if using special depth accessors, use a more complex extraction
|
|
31
|
+
return Array.from(_smartExtractVariableNames(node, depth, specialDepthAccessors));
|
|
32
|
+
}
|
|
33
|
+
if (depth === 0 && node.name === 'VariableName') return [node.variableName];
|
|
34
|
+
|
|
35
|
+
// for any other kind of node, traverse its children and flatten the result
|
|
36
|
+
if (node.children) {
|
|
37
|
+
return node.children.reduce((acc, child) => {
|
|
38
|
+
return acc.concat(_unfoldVariables(child));
|
|
39
|
+
}, []);
|
|
40
|
+
}
|
|
41
|
+
return [];
|
|
42
|
+
}(simpleExpressionTree);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the variable name at the specified index in a given path expression.
|
|
47
|
+
*
|
|
48
|
+
* @param {Object} root - The root node of the path expression tree.
|
|
49
|
+
* @param {number} index - The index of the variable name to retrieve.
|
|
50
|
+
* @returns {string|null} The variable name at the specified index or null if index is out of bounds.
|
|
51
|
+
*/
|
|
52
|
+
const _getVariableNameAtPathIndex = (root, index) => {
|
|
53
|
+
const accessors = _deconstructPathExpression(root);
|
|
54
|
+
return accessors[index] || null;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Extracts the variables which are required of the external context for a given path expression.
|
|
59
|
+
* This is done by traversing the path expression tree and keeping track of the current depth relative to the external context.
|
|
60
|
+
*
|
|
61
|
+
* @param {Object} node - The root node of the path expression tree.
|
|
62
|
+
* @param {number} initialDepth - The depth at which the root node is located in the outer context.
|
|
63
|
+
* @param {Object} specialDepthAccessors - Definitions of special keywords which represent more complex accesses of the outer context.
|
|
64
|
+
* @returns {Set} - A set containing the extracted variable names.
|
|
65
|
+
*/
|
|
66
|
+
const _smartExtractVariableNames = (node, initialDepth, specialDepthAccessors) => {
|
|
67
|
+
// depth info represents the previous (initialised as null) and current depth of the current accessor in the path expression
|
|
68
|
+
// we track multiple of these to account for the fact that a path expression may be ambiguous due to special keywords
|
|
69
|
+
let accessorDepthInfos = [{
|
|
70
|
+
previous: null,
|
|
71
|
+
current: initialDepth - 1
|
|
72
|
+
}];
|
|
73
|
+
const extractedVariables = new Set();
|
|
74
|
+
const nodeAccessors = _deconstructPathExpression(node);
|
|
75
|
+
for (let i = 0; i < nodeAccessors.length; i++) {
|
|
76
|
+
const currentAccessor = nodeAccessors[i];
|
|
77
|
+
if (currentAccessor in specialDepthAccessors) {
|
|
78
|
+
const depthOffsets = specialDepthAccessors[currentAccessor];
|
|
79
|
+
|
|
80
|
+
// if the current accessor is a special keyword, we need to expand the current depth info set
|
|
81
|
+
// this is done to account for the ambiguity of keywords like parent, which may be used to access
|
|
82
|
+
// the parent of the current node, or a child variable of the same name
|
|
83
|
+
accessorDepthInfos = depthOffsets.reduce((accumulator, offset) => {
|
|
84
|
+
return [...accumulator, ...accessorDepthInfos.map(depthInfo => ({
|
|
85
|
+
previous: depthInfo.current,
|
|
86
|
+
current: depthInfo.current + offset
|
|
87
|
+
}))];
|
|
88
|
+
}, []).filter(depthInfo => depthInfo.current >= -1); // discard all depth infos which are out of bounds
|
|
89
|
+
} else {
|
|
90
|
+
// if the current accessor is not a special keyword, we know it's simply accessing a child
|
|
91
|
+
// hence we are now one level deeper in the tree and simply increment
|
|
92
|
+
accessorDepthInfos = accessorDepthInfos.map(depthInfo => ({
|
|
93
|
+
previous: depthInfo.current,
|
|
94
|
+
current: depthInfo.current + 1
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// finally, we check if for the current accessor, there is a scenario where:
|
|
99
|
+
// previous it was at depth -1 (i.e. the root context), and is now at depth 0 (i.e. a variable)
|
|
100
|
+
// these are the variables we need to request, so we add them to the set
|
|
101
|
+
if (accessorDepthInfos.some(depthInfo => depthInfo.previous === -1 && depthInfo.current === 0)) {
|
|
102
|
+
extractedVariables.add(currentAccessor);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// we return a set to avoid duplicates
|
|
107
|
+
return new Set(extractedVariables);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Deconstructs a path expression tree into an array of components.
|
|
112
|
+
*
|
|
113
|
+
* @param {Object} root - The root node of the path expression tree.
|
|
114
|
+
* @returns {Array<string>} An array of components in the path expression, in the correct order.
|
|
115
|
+
*/
|
|
116
|
+
const _deconstructPathExpression = root => {
|
|
117
|
+
let node = root;
|
|
118
|
+
let parts = [];
|
|
119
|
+
|
|
120
|
+
// Traverse the tree and collect path components
|
|
121
|
+
while (node.name === 'PathExpression') {
|
|
122
|
+
parts.push(node.children[1].variableName);
|
|
123
|
+
node = node.children[0];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Add the last component to the array
|
|
127
|
+
parts.push(node.variableName);
|
|
128
|
+
|
|
129
|
+
// Reverse and return the array to get the correct order
|
|
130
|
+
return parts.reverse();
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Builds a simplified feel structure tree from the given parse tree and feel string.
|
|
135
|
+
* The nodes follow this structure: `{ name: string, children: Array, variableName?: string }`
|
|
136
|
+
*
|
|
137
|
+
* @param {Object} parseTree - The parse tree generated by a parser.
|
|
138
|
+
* @param {string} feelString - The feel string used for parsing.
|
|
139
|
+
* @returns {Object} The simplified feel structure tree.
|
|
140
|
+
*/
|
|
141
|
+
const _buildSimpleFeelStructureTree = (parseTree, feelString) => {
|
|
142
|
+
const stack = [{
|
|
143
|
+
children: []
|
|
144
|
+
}];
|
|
145
|
+
parseTree.iterate({
|
|
146
|
+
enter: node => {
|
|
147
|
+
const nodeRepresentation = {
|
|
148
|
+
name: node.type.name,
|
|
149
|
+
children: []
|
|
150
|
+
};
|
|
151
|
+
if (node.type.name === 'VariableName') {
|
|
152
|
+
nodeRepresentation.variableName = feelString.slice(node.from, node.to);
|
|
153
|
+
}
|
|
154
|
+
stack.push(nodeRepresentation);
|
|
155
|
+
},
|
|
156
|
+
leave: () => {
|
|
157
|
+
const result = stack.pop();
|
|
158
|
+
const parent = stack[stack.length - 1];
|
|
159
|
+
parent.children.push(result);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
return stack[0].children[0];
|
|
163
|
+
};
|
|
164
|
+
|
|
16
165
|
class FeelExpressionLanguage {
|
|
17
166
|
constructor(eventBus) {
|
|
18
167
|
this._eventBus = eventBus;
|
|
19
168
|
}
|
|
20
169
|
|
|
21
170
|
/**
|
|
22
|
-
* Determines if the given
|
|
171
|
+
* Determines if the given value is a FEEL expression.
|
|
23
172
|
*
|
|
24
|
-
* @param {
|
|
173
|
+
* @param {any} value
|
|
25
174
|
* @returns {boolean}
|
|
26
175
|
*
|
|
27
176
|
*/
|
|
@@ -45,12 +194,10 @@ class FeelExpressionLanguage {
|
|
|
45
194
|
if (!this.isExpression(expression)) {
|
|
46
195
|
return [];
|
|
47
196
|
}
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
} else if (type === 'expression') {
|
|
51
|
-
return this._getExpressionVariableNames(expression);
|
|
197
|
+
if (!['unaryTest', 'expression'].includes(type)) {
|
|
198
|
+
throw new Error('Unknown expression type: ' + type);
|
|
52
199
|
}
|
|
53
|
-
|
|
200
|
+
return getFlavouredFeelVariableNames(expression, type);
|
|
54
201
|
}
|
|
55
202
|
|
|
56
203
|
/**
|
|
@@ -78,37 +225,52 @@ class FeelExpressionLanguage {
|
|
|
78
225
|
return null;
|
|
79
226
|
}
|
|
80
227
|
}
|
|
81
|
-
_getExpressionVariableNames(expression) {
|
|
82
|
-
const tree = parseExpressions(expression);
|
|
83
|
-
const cursor = tree.cursor();
|
|
84
|
-
const variables = new Set();
|
|
85
|
-
do {
|
|
86
|
-
const node = cursor.node;
|
|
87
|
-
if (node.type.name === 'VariableName') {
|
|
88
|
-
variables.add(expression.slice(node.from, node.to));
|
|
89
|
-
}
|
|
90
|
-
} while (cursor.next());
|
|
91
|
-
return Array.from(variables);
|
|
92
|
-
}
|
|
93
|
-
_getUnaryVariableNames(unaryTest) {
|
|
94
|
-
const tree = parseUnaryTests(unaryTest);
|
|
95
|
-
const cursor = tree.cursor();
|
|
96
|
-
const variables = new Set();
|
|
97
|
-
do {
|
|
98
|
-
const node = cursor.node;
|
|
99
|
-
if (node.type.name === 'VariableName') {
|
|
100
|
-
variables.add(unaryTest.slice(node.from, node.to));
|
|
101
|
-
}
|
|
102
|
-
} while (cursor.next());
|
|
103
|
-
return Array.from(variables);
|
|
104
|
-
}
|
|
105
228
|
}
|
|
106
229
|
FeelExpressionLanguage.$inject = ['eventBus'];
|
|
107
230
|
|
|
108
231
|
class FeelersTemplating {
|
|
109
232
|
constructor() {}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Determines if the given value is a feelers template.
|
|
236
|
+
*
|
|
237
|
+
* @param {any} value
|
|
238
|
+
* @returns {boolean}
|
|
239
|
+
*
|
|
240
|
+
*/
|
|
110
241
|
isTemplate(value) {
|
|
111
|
-
return isString(value) && (value.startsWith('=') || /{{/.test(value));
|
|
242
|
+
return isString(value) && (value.startsWith('=') || /{{.*?}}/.test(value));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Retrieve variable names from a given feelers template.
|
|
247
|
+
*
|
|
248
|
+
* @param {string} template
|
|
249
|
+
*
|
|
250
|
+
* @returns {string[]}
|
|
251
|
+
*/
|
|
252
|
+
getVariableNames(template) {
|
|
253
|
+
if (!this.isTemplate(template)) {
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
const expressions = this._extractExpressionsWithDepth(template);
|
|
257
|
+
|
|
258
|
+
// defines special accessors, and the change(s) in depth they could imply (e.g. parent can be used to access the parent context (depth - 1) or a child variable named parent (depth + 1)
|
|
259
|
+
const specialDepthAccessors = {
|
|
260
|
+
parent: [-1, 1],
|
|
261
|
+
_parent_: [-1],
|
|
262
|
+
this: [0, 1],
|
|
263
|
+
_this_: [0]
|
|
264
|
+
};
|
|
265
|
+
return expressions.reduce((variables, {
|
|
266
|
+
expression,
|
|
267
|
+
depth
|
|
268
|
+
}) => {
|
|
269
|
+
return variables.concat(getFlavouredFeelVariableNames(expression, 'expression', {
|
|
270
|
+
depth,
|
|
271
|
+
specialDepthAccessors
|
|
272
|
+
}));
|
|
273
|
+
}, []);
|
|
112
274
|
}
|
|
113
275
|
|
|
114
276
|
/**
|
|
@@ -135,6 +297,50 @@ class FeelersTemplating {
|
|
|
135
297
|
buildDebugString
|
|
136
298
|
});
|
|
137
299
|
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* @typedef {Object} ExpressionWithDepth
|
|
303
|
+
* @property {number} depth - The depth of the expression in the syntax tree.
|
|
304
|
+
* @property {string} expression - The extracted expression
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Extracts all feel expressions in the template along with their depth in the syntax tree.
|
|
309
|
+
* The depth is incremented for child expressions of loops to account for context drilling.
|
|
310
|
+
* @name extractExpressionsWithDepth
|
|
311
|
+
* @param {string} template - A feelers template string.
|
|
312
|
+
* @returns {Array<ExpressionWithDepth>} An array of objects, each containing the depth and the extracted expression.
|
|
313
|
+
*
|
|
314
|
+
* @example
|
|
315
|
+
* const template = "Hello {{user}}, you have:{{#loop items}}\n- {{amount}} {{name}}{{/loop}}.";
|
|
316
|
+
* const extractedExpressions = _extractExpressionsWithDepth(template);
|
|
317
|
+
*/
|
|
318
|
+
_extractExpressionsWithDepth(template) {
|
|
319
|
+
// build simplified feelers syntax tree
|
|
320
|
+
const parseTree = parser.parse(template);
|
|
321
|
+
const tree = buildSimpleTree(parseTree, template);
|
|
322
|
+
return function _traverse(n, depth = 0) {
|
|
323
|
+
if (['Feel', 'FeelBlock'].includes(n.name)) {
|
|
324
|
+
return [{
|
|
325
|
+
depth,
|
|
326
|
+
expression: n.content
|
|
327
|
+
}];
|
|
328
|
+
}
|
|
329
|
+
if (n.name === 'LoopSpanner') {
|
|
330
|
+
const loopExpression = n.children[0].content;
|
|
331
|
+
const childResults = n.children.slice(1).reduce((acc, child) => {
|
|
332
|
+
return acc.concat(_traverse(child, depth + 1));
|
|
333
|
+
}, []);
|
|
334
|
+
return [{
|
|
335
|
+
depth,
|
|
336
|
+
expression: loopExpression
|
|
337
|
+
}, ...childResults];
|
|
338
|
+
}
|
|
339
|
+
return n.children.reduce((acc, child) => {
|
|
340
|
+
return acc.concat(_traverse(child, depth));
|
|
341
|
+
}, []);
|
|
342
|
+
}(tree);
|
|
343
|
+
}
|
|
138
344
|
}
|
|
139
345
|
FeelersTemplating.$inject = [];
|
|
140
346
|
|
|
@@ -760,8 +966,13 @@ class Validator {
|
|
|
760
966
|
if (validate.pattern && value && !new RegExp(validate.pattern).test(value)) {
|
|
761
967
|
errors = [...errors, `Field must match pattern ${validate.pattern}.`];
|
|
762
968
|
}
|
|
763
|
-
if (validate.required
|
|
764
|
-
|
|
969
|
+
if (validate.required) {
|
|
970
|
+
const isUncheckedCheckbox = type === 'checkbox' && value === false;
|
|
971
|
+
const isUnsetValue = isNil(value) || value === '';
|
|
972
|
+
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
973
|
+
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
974
|
+
errors = [...errors, 'Field is required.'];
|
|
975
|
+
}
|
|
765
976
|
}
|
|
766
977
|
if ('min' in validate && (value || value === 0) && value < validate.min) {
|
|
767
978
|
errors = [...errors, `Field must have minimum value of ${validate.min}.`];
|
|
@@ -1063,6 +1274,7 @@ function createFormContainer(prefix = 'fjs') {
|
|
|
1063
1274
|
}
|
|
1064
1275
|
|
|
1065
1276
|
const EXPRESSION_PROPERTIES = ['alt', 'source', 'text'];
|
|
1277
|
+
const TEMPLATE_PROPERTIES = ['text'];
|
|
1066
1278
|
function findErrors(errors, path) {
|
|
1067
1279
|
return errors[pathStringify(path)];
|
|
1068
1280
|
}
|
|
@@ -1116,7 +1328,7 @@ function clone(data, replacer) {
|
|
|
1116
1328
|
*
|
|
1117
1329
|
* @return {string[]}
|
|
1118
1330
|
*/
|
|
1119
|
-
function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLanguage(null)) {
|
|
1331
|
+
function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLanguage(null), templating = new FeelersTemplating()) {
|
|
1120
1332
|
if (!schema.components) {
|
|
1121
1333
|
return [];
|
|
1122
1334
|
}
|
|
@@ -1151,6 +1363,13 @@ function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLangu
|
|
|
1151
1363
|
variables = [...variables, ...expressionVariables];
|
|
1152
1364
|
}
|
|
1153
1365
|
});
|
|
1366
|
+
TEMPLATE_PROPERTIES.forEach(prop => {
|
|
1367
|
+
const property = component[prop];
|
|
1368
|
+
if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
|
|
1369
|
+
const templateVariables = templating.getVariableNames(property);
|
|
1370
|
+
variables = [...variables, ...templateVariables];
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1154
1373
|
return variables;
|
|
1155
1374
|
}, []);
|
|
1156
1375
|
|
|
@@ -1465,8 +1684,12 @@ function Checkbox(props) {
|
|
|
1465
1684
|
const {
|
|
1466
1685
|
description,
|
|
1467
1686
|
id,
|
|
1468
|
-
label
|
|
1687
|
+
label,
|
|
1688
|
+
validate = {}
|
|
1469
1689
|
} = field;
|
|
1690
|
+
const {
|
|
1691
|
+
required
|
|
1692
|
+
} = validate;
|
|
1470
1693
|
const onChange = ({
|
|
1471
1694
|
target
|
|
1472
1695
|
}) => {
|
|
@@ -1488,7 +1711,7 @@ function Checkbox(props) {
|
|
|
1488
1711
|
children: [jsx(Label, {
|
|
1489
1712
|
id: prefixId(id, formId),
|
|
1490
1713
|
label: label,
|
|
1491
|
-
required:
|
|
1714
|
+
required: required,
|
|
1492
1715
|
children: jsx("input", {
|
|
1493
1716
|
checked: value,
|
|
1494
1717
|
class: "fjs-input",
|
|
@@ -1855,8 +2078,12 @@ function Checklist(props) {
|
|
|
1855
2078
|
const {
|
|
1856
2079
|
description,
|
|
1857
2080
|
id,
|
|
1858
|
-
label
|
|
2081
|
+
label,
|
|
2082
|
+
validate = {}
|
|
1859
2083
|
} = field;
|
|
2084
|
+
const {
|
|
2085
|
+
required
|
|
2086
|
+
} = validate;
|
|
1860
2087
|
const toggleCheckbox = v => {
|
|
1861
2088
|
let newValue = [...value];
|
|
1862
2089
|
if (!newValue.includes(v)) {
|
|
@@ -1882,7 +2109,8 @@ function Checklist(props) {
|
|
|
1882
2109
|
disabled
|
|
1883
2110
|
})),
|
|
1884
2111
|
children: [jsx(Label, {
|
|
1885
|
-
label: label
|
|
2112
|
+
label: label,
|
|
2113
|
+
required: required
|
|
1886
2114
|
}), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
|
|
1887
2115
|
return jsx(Label, {
|
|
1888
2116
|
id: prefixId(`${id}-${index}`, formId),
|
|
@@ -3704,6 +3932,12 @@ function Select(props) {
|
|
|
3704
3932
|
errors,
|
|
3705
3933
|
disabled
|
|
3706
3934
|
}),
|
|
3935
|
+
onKeyDown: event => {
|
|
3936
|
+
if (event.key === 'Enter') {
|
|
3937
|
+
event.preventDefault();
|
|
3938
|
+
event.stopPropagation();
|
|
3939
|
+
}
|
|
3940
|
+
},
|
|
3707
3941
|
children: [jsx(Label, {
|
|
3708
3942
|
id: prefixId(id, formId),
|
|
3709
3943
|
label: label,
|
|
@@ -3752,8 +3986,12 @@ function Taglist(props) {
|
|
|
3752
3986
|
const {
|
|
3753
3987
|
description,
|
|
3754
3988
|
id,
|
|
3755
|
-
label
|
|
3989
|
+
label,
|
|
3990
|
+
validate = {}
|
|
3756
3991
|
} = field;
|
|
3992
|
+
const {
|
|
3993
|
+
required
|
|
3994
|
+
} = validate;
|
|
3757
3995
|
const {
|
|
3758
3996
|
formId
|
|
3759
3997
|
} = useContext(FormContext$1);
|
|
@@ -3850,8 +4088,15 @@ function Taglist(props) {
|
|
|
3850
4088
|
errors,
|
|
3851
4089
|
disabled
|
|
3852
4090
|
}),
|
|
4091
|
+
onKeyDown: event => {
|
|
4092
|
+
if (event.key === 'Enter') {
|
|
4093
|
+
event.stopPropagation();
|
|
4094
|
+
event.preventDefault();
|
|
4095
|
+
}
|
|
4096
|
+
},
|
|
3853
4097
|
children: [jsx(Label, {
|
|
3854
4098
|
label: label,
|
|
4099
|
+
required: required,
|
|
3855
4100
|
id: prefixId(`${id}-search`, formId)
|
|
3856
4101
|
}), jsxs("div", {
|
|
3857
4102
|
class: classNames('fjs-taglist', {
|