@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
|
@@ -93,10 +93,9 @@
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
.fjs-container .fjs-layout-row {
|
|
96
|
-
|
|
96
|
+
flex: auto;
|
|
97
97
|
padding: 9px 0;
|
|
98
98
|
position: relative;
|
|
99
|
-
margin-left: 1px;
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
.fjs-container .fjs-column {
|
|
@@ -114,6 +113,8 @@
|
|
|
114
113
|
|
|
115
114
|
.fjs-container .cds--grid .cds--row {
|
|
116
115
|
align-items: start;
|
|
116
|
+
margin-left: 0;
|
|
117
|
+
margin-right: 0;
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
@media (max-width: 66rem) {
|
|
@@ -134,6 +135,7 @@
|
|
|
134
135
|
color: var(--color-text);
|
|
135
136
|
background-color: var(--color-background);
|
|
136
137
|
position: relative;
|
|
138
|
+
padding: 0 4px;
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
.fjs-container .fjs-form * {
|
|
@@ -270,7 +272,6 @@
|
|
|
270
272
|
padding: 8px;
|
|
271
273
|
width: auto !important;
|
|
272
274
|
min-width: 34px;
|
|
273
|
-
max-width: 30%;
|
|
274
275
|
display: flex;
|
|
275
276
|
overflow: hidden;
|
|
276
277
|
}
|
|
@@ -352,6 +353,7 @@
|
|
|
352
353
|
.fjs-container .fjs-input-group .fjs-taglist,
|
|
353
354
|
.fjs-container .fjs-input-group .fjs-select {
|
|
354
355
|
height: unset;
|
|
356
|
+
min-width: min(60px, 50%);
|
|
355
357
|
width: 100%;
|
|
356
358
|
}
|
|
357
359
|
|
|
@@ -540,6 +542,7 @@
|
|
|
540
542
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-input,
|
|
541
543
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-select,
|
|
542
544
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-textarea,
|
|
545
|
+
.fjs-container .fjs-form-field.fjs-has-errors .fjs-taglist,
|
|
543
546
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-input-group,
|
|
544
547
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-input-group .fjs-input {
|
|
545
548
|
border-color: var(--color-warning);
|
package/dist/assets/form-js.css
CHANGED
|
@@ -81,10 +81,9 @@
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
.fjs-container .fjs-layout-row {
|
|
84
|
-
|
|
84
|
+
flex: auto;
|
|
85
85
|
padding: 9px 0;
|
|
86
86
|
position: relative;
|
|
87
|
-
margin-left: 1px;
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
.fjs-container .fjs-column {
|
|
@@ -102,6 +101,8 @@
|
|
|
102
101
|
|
|
103
102
|
.fjs-container .cds--grid .cds--row {
|
|
104
103
|
align-items: start;
|
|
104
|
+
margin-left: 0;
|
|
105
|
+
margin-right: 0;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
@media (max-width: 66rem) {
|
|
@@ -121,6 +122,7 @@
|
|
|
121
122
|
color: var(--color-text);
|
|
122
123
|
background-color: var(--color-background);
|
|
123
124
|
position: relative;
|
|
125
|
+
padding: 0 4px;
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
.fjs-container .fjs-form * {
|
|
@@ -257,7 +259,6 @@
|
|
|
257
259
|
padding: 8px;
|
|
258
260
|
width: auto !important;
|
|
259
261
|
min-width: 34px;
|
|
260
|
-
max-width: 30%;
|
|
261
262
|
display: flex;
|
|
262
263
|
overflow: hidden;
|
|
263
264
|
}
|
|
@@ -337,6 +338,7 @@
|
|
|
337
338
|
.fjs-container .fjs-input-group .fjs-taglist,
|
|
338
339
|
.fjs-container .fjs-input-group .fjs-select {
|
|
339
340
|
height: unset;
|
|
341
|
+
min-width: min(60px, 50%);
|
|
340
342
|
width: 100%;
|
|
341
343
|
}
|
|
342
344
|
|
|
@@ -523,6 +525,7 @@
|
|
|
523
525
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-input,
|
|
524
526
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-select,
|
|
525
527
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-textarea,
|
|
528
|
+
.fjs-container .fjs-form-field.fjs-has-errors .fjs-taglist,
|
|
526
529
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-input-group,
|
|
527
530
|
.fjs-container .fjs-form-field.fjs-has-errors .fjs-input-group .fjs-input {
|
|
528
531
|
border-color: var(--color-warning);
|
package/dist/index.cjs
CHANGED
|
@@ -15,15 +15,164 @@ var flatpickr = require('flatpickr');
|
|
|
15
15
|
var Markup = require('preact-markup');
|
|
16
16
|
var didi = require('didi');
|
|
17
17
|
|
|
18
|
+
const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) => {
|
|
19
|
+
const {
|
|
20
|
+
depth = 0,
|
|
21
|
+
specialDepthAccessors = {}
|
|
22
|
+
} = options;
|
|
23
|
+
if (!['expression', 'unaryTest'].includes(feelFlavour)) return [];
|
|
24
|
+
const tree = feelFlavour === 'expression' ? feelin.parseExpressions(feelString) : feelin.parseUnaryTests(feelString);
|
|
25
|
+
const simpleExpressionTree = _buildSimpleFeelStructureTree(tree, feelString);
|
|
26
|
+
return function _unfoldVariables(node) {
|
|
27
|
+
if (node.name === 'PathExpression') {
|
|
28
|
+
if (Object.keys(specialDepthAccessors).length === 0) {
|
|
29
|
+
return depth === 0 ? [_getVariableNameAtPathIndex(node, 0)] : [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// if using special depth accessors, use a more complex extraction
|
|
33
|
+
return Array.from(_smartExtractVariableNames(node, depth, specialDepthAccessors));
|
|
34
|
+
}
|
|
35
|
+
if (depth === 0 && node.name === 'VariableName') return [node.variableName];
|
|
36
|
+
|
|
37
|
+
// for any other kind of node, traverse its children and flatten the result
|
|
38
|
+
if (node.children) {
|
|
39
|
+
return node.children.reduce((acc, child) => {
|
|
40
|
+
return acc.concat(_unfoldVariables(child));
|
|
41
|
+
}, []);
|
|
42
|
+
}
|
|
43
|
+
return [];
|
|
44
|
+
}(simpleExpressionTree);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get the variable name at the specified index in a given path expression.
|
|
49
|
+
*
|
|
50
|
+
* @param {Object} root - The root node of the path expression tree.
|
|
51
|
+
* @param {number} index - The index of the variable name to retrieve.
|
|
52
|
+
* @returns {string|null} The variable name at the specified index or null if index is out of bounds.
|
|
53
|
+
*/
|
|
54
|
+
const _getVariableNameAtPathIndex = (root, index) => {
|
|
55
|
+
const accessors = _deconstructPathExpression(root);
|
|
56
|
+
return accessors[index] || null;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extracts the variables which are required of the external context for a given path expression.
|
|
61
|
+
* This is done by traversing the path expression tree and keeping track of the current depth relative to the external context.
|
|
62
|
+
*
|
|
63
|
+
* @param {Object} node - The root node of the path expression tree.
|
|
64
|
+
* @param {number} initialDepth - The depth at which the root node is located in the outer context.
|
|
65
|
+
* @param {Object} specialDepthAccessors - Definitions of special keywords which represent more complex accesses of the outer context.
|
|
66
|
+
* @returns {Set} - A set containing the extracted variable names.
|
|
67
|
+
*/
|
|
68
|
+
const _smartExtractVariableNames = (node, initialDepth, specialDepthAccessors) => {
|
|
69
|
+
// depth info represents the previous (initialised as null) and current depth of the current accessor in the path expression
|
|
70
|
+
// we track multiple of these to account for the fact that a path expression may be ambiguous due to special keywords
|
|
71
|
+
let accessorDepthInfos = [{
|
|
72
|
+
previous: null,
|
|
73
|
+
current: initialDepth - 1
|
|
74
|
+
}];
|
|
75
|
+
const extractedVariables = new Set();
|
|
76
|
+
const nodeAccessors = _deconstructPathExpression(node);
|
|
77
|
+
for (let i = 0; i < nodeAccessors.length; i++) {
|
|
78
|
+
const currentAccessor = nodeAccessors[i];
|
|
79
|
+
if (currentAccessor in specialDepthAccessors) {
|
|
80
|
+
const depthOffsets = specialDepthAccessors[currentAccessor];
|
|
81
|
+
|
|
82
|
+
// if the current accessor is a special keyword, we need to expand the current depth info set
|
|
83
|
+
// this is done to account for the ambiguity of keywords like parent, which may be used to access
|
|
84
|
+
// the parent of the current node, or a child variable of the same name
|
|
85
|
+
accessorDepthInfos = depthOffsets.reduce((accumulator, offset) => {
|
|
86
|
+
return [...accumulator, ...accessorDepthInfos.map(depthInfo => ({
|
|
87
|
+
previous: depthInfo.current,
|
|
88
|
+
current: depthInfo.current + offset
|
|
89
|
+
}))];
|
|
90
|
+
}, []).filter(depthInfo => depthInfo.current >= -1); // discard all depth infos which are out of bounds
|
|
91
|
+
} else {
|
|
92
|
+
// if the current accessor is not a special keyword, we know it's simply accessing a child
|
|
93
|
+
// hence we are now one level deeper in the tree and simply increment
|
|
94
|
+
accessorDepthInfos = accessorDepthInfos.map(depthInfo => ({
|
|
95
|
+
previous: depthInfo.current,
|
|
96
|
+
current: depthInfo.current + 1
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// finally, we check if for the current accessor, there is a scenario where:
|
|
101
|
+
// previous it was at depth -1 (i.e. the root context), and is now at depth 0 (i.e. a variable)
|
|
102
|
+
// these are the variables we need to request, so we add them to the set
|
|
103
|
+
if (accessorDepthInfos.some(depthInfo => depthInfo.previous === -1 && depthInfo.current === 0)) {
|
|
104
|
+
extractedVariables.add(currentAccessor);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// we return a set to avoid duplicates
|
|
109
|
+
return new Set(extractedVariables);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Deconstructs a path expression tree into an array of components.
|
|
114
|
+
*
|
|
115
|
+
* @param {Object} root - The root node of the path expression tree.
|
|
116
|
+
* @returns {Array<string>} An array of components in the path expression, in the correct order.
|
|
117
|
+
*/
|
|
118
|
+
const _deconstructPathExpression = root => {
|
|
119
|
+
let node = root;
|
|
120
|
+
let parts = [];
|
|
121
|
+
|
|
122
|
+
// Traverse the tree and collect path components
|
|
123
|
+
while (node.name === 'PathExpression') {
|
|
124
|
+
parts.push(node.children[1].variableName);
|
|
125
|
+
node = node.children[0];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Add the last component to the array
|
|
129
|
+
parts.push(node.variableName);
|
|
130
|
+
|
|
131
|
+
// Reverse and return the array to get the correct order
|
|
132
|
+
return parts.reverse();
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Builds a simplified feel structure tree from the given parse tree and feel string.
|
|
137
|
+
* The nodes follow this structure: `{ name: string, children: Array, variableName?: string }`
|
|
138
|
+
*
|
|
139
|
+
* @param {Object} parseTree - The parse tree generated by a parser.
|
|
140
|
+
* @param {string} feelString - The feel string used for parsing.
|
|
141
|
+
* @returns {Object} The simplified feel structure tree.
|
|
142
|
+
*/
|
|
143
|
+
const _buildSimpleFeelStructureTree = (parseTree, feelString) => {
|
|
144
|
+
const stack = [{
|
|
145
|
+
children: []
|
|
146
|
+
}];
|
|
147
|
+
parseTree.iterate({
|
|
148
|
+
enter: node => {
|
|
149
|
+
const nodeRepresentation = {
|
|
150
|
+
name: node.type.name,
|
|
151
|
+
children: []
|
|
152
|
+
};
|
|
153
|
+
if (node.type.name === 'VariableName') {
|
|
154
|
+
nodeRepresentation.variableName = feelString.slice(node.from, node.to);
|
|
155
|
+
}
|
|
156
|
+
stack.push(nodeRepresentation);
|
|
157
|
+
},
|
|
158
|
+
leave: () => {
|
|
159
|
+
const result = stack.pop();
|
|
160
|
+
const parent = stack[stack.length - 1];
|
|
161
|
+
parent.children.push(result);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
return stack[0].children[0];
|
|
165
|
+
};
|
|
166
|
+
|
|
18
167
|
class FeelExpressionLanguage {
|
|
19
168
|
constructor(eventBus) {
|
|
20
169
|
this._eventBus = eventBus;
|
|
21
170
|
}
|
|
22
171
|
|
|
23
172
|
/**
|
|
24
|
-
* Determines if the given
|
|
173
|
+
* Determines if the given value is a FEEL expression.
|
|
25
174
|
*
|
|
26
|
-
* @param {
|
|
175
|
+
* @param {any} value
|
|
27
176
|
* @returns {boolean}
|
|
28
177
|
*
|
|
29
178
|
*/
|
|
@@ -47,12 +196,10 @@ class FeelExpressionLanguage {
|
|
|
47
196
|
if (!this.isExpression(expression)) {
|
|
48
197
|
return [];
|
|
49
198
|
}
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
} else if (type === 'expression') {
|
|
53
|
-
return this._getExpressionVariableNames(expression);
|
|
199
|
+
if (!['unaryTest', 'expression'].includes(type)) {
|
|
200
|
+
throw new Error('Unknown expression type: ' + type);
|
|
54
201
|
}
|
|
55
|
-
|
|
202
|
+
return getFlavouredFeelVariableNames(expression, type);
|
|
56
203
|
}
|
|
57
204
|
|
|
58
205
|
/**
|
|
@@ -80,37 +227,52 @@ class FeelExpressionLanguage {
|
|
|
80
227
|
return null;
|
|
81
228
|
}
|
|
82
229
|
}
|
|
83
|
-
_getExpressionVariableNames(expression) {
|
|
84
|
-
const tree = feelin.parseExpressions(expression);
|
|
85
|
-
const cursor = tree.cursor();
|
|
86
|
-
const variables = new Set();
|
|
87
|
-
do {
|
|
88
|
-
const node = cursor.node;
|
|
89
|
-
if (node.type.name === 'VariableName') {
|
|
90
|
-
variables.add(expression.slice(node.from, node.to));
|
|
91
|
-
}
|
|
92
|
-
} while (cursor.next());
|
|
93
|
-
return Array.from(variables);
|
|
94
|
-
}
|
|
95
|
-
_getUnaryVariableNames(unaryTest) {
|
|
96
|
-
const tree = feelin.parseUnaryTests(unaryTest);
|
|
97
|
-
const cursor = tree.cursor();
|
|
98
|
-
const variables = new Set();
|
|
99
|
-
do {
|
|
100
|
-
const node = cursor.node;
|
|
101
|
-
if (node.type.name === 'VariableName') {
|
|
102
|
-
variables.add(unaryTest.slice(node.from, node.to));
|
|
103
|
-
}
|
|
104
|
-
} while (cursor.next());
|
|
105
|
-
return Array.from(variables);
|
|
106
|
-
}
|
|
107
230
|
}
|
|
108
231
|
FeelExpressionLanguage.$inject = ['eventBus'];
|
|
109
232
|
|
|
110
233
|
class FeelersTemplating {
|
|
111
234
|
constructor() {}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Determines if the given value is a feelers template.
|
|
238
|
+
*
|
|
239
|
+
* @param {any} value
|
|
240
|
+
* @returns {boolean}
|
|
241
|
+
*
|
|
242
|
+
*/
|
|
112
243
|
isTemplate(value) {
|
|
113
|
-
return minDash.isString(value) && (value.startsWith('=') || /{{/.test(value));
|
|
244
|
+
return minDash.isString(value) && (value.startsWith('=') || /{{.*?}}/.test(value));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Retrieve variable names from a given feelers template.
|
|
249
|
+
*
|
|
250
|
+
* @param {string} template
|
|
251
|
+
*
|
|
252
|
+
* @returns {string[]}
|
|
253
|
+
*/
|
|
254
|
+
getVariableNames(template) {
|
|
255
|
+
if (!this.isTemplate(template)) {
|
|
256
|
+
return [];
|
|
257
|
+
}
|
|
258
|
+
const expressions = this._extractExpressionsWithDepth(template);
|
|
259
|
+
|
|
260
|
+
// 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)
|
|
261
|
+
const specialDepthAccessors = {
|
|
262
|
+
parent: [-1, 1],
|
|
263
|
+
_parent_: [-1],
|
|
264
|
+
this: [0, 1],
|
|
265
|
+
_this_: [0]
|
|
266
|
+
};
|
|
267
|
+
return expressions.reduce((variables, {
|
|
268
|
+
expression,
|
|
269
|
+
depth
|
|
270
|
+
}) => {
|
|
271
|
+
return variables.concat(getFlavouredFeelVariableNames(expression, 'expression', {
|
|
272
|
+
depth,
|
|
273
|
+
specialDepthAccessors
|
|
274
|
+
}));
|
|
275
|
+
}, []);
|
|
114
276
|
}
|
|
115
277
|
|
|
116
278
|
/**
|
|
@@ -137,6 +299,50 @@ class FeelersTemplating {
|
|
|
137
299
|
buildDebugString
|
|
138
300
|
});
|
|
139
301
|
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* @typedef {Object} ExpressionWithDepth
|
|
305
|
+
* @property {number} depth - The depth of the expression in the syntax tree.
|
|
306
|
+
* @property {string} expression - The extracted expression
|
|
307
|
+
*/
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Extracts all feel expressions in the template along with their depth in the syntax tree.
|
|
311
|
+
* The depth is incremented for child expressions of loops to account for context drilling.
|
|
312
|
+
* @name extractExpressionsWithDepth
|
|
313
|
+
* @param {string} template - A feelers template string.
|
|
314
|
+
* @returns {Array<ExpressionWithDepth>} An array of objects, each containing the depth and the extracted expression.
|
|
315
|
+
*
|
|
316
|
+
* @example
|
|
317
|
+
* const template = "Hello {{user}}, you have:{{#loop items}}\n- {{amount}} {{name}}{{/loop}}.";
|
|
318
|
+
* const extractedExpressions = _extractExpressionsWithDepth(template);
|
|
319
|
+
*/
|
|
320
|
+
_extractExpressionsWithDepth(template) {
|
|
321
|
+
// build simplified feelers syntax tree
|
|
322
|
+
const parseTree = feelers.parser.parse(template);
|
|
323
|
+
const tree = feelers.buildSimpleTree(parseTree, template);
|
|
324
|
+
return function _traverse(n, depth = 0) {
|
|
325
|
+
if (['Feel', 'FeelBlock'].includes(n.name)) {
|
|
326
|
+
return [{
|
|
327
|
+
depth,
|
|
328
|
+
expression: n.content
|
|
329
|
+
}];
|
|
330
|
+
}
|
|
331
|
+
if (n.name === 'LoopSpanner') {
|
|
332
|
+
const loopExpression = n.children[0].content;
|
|
333
|
+
const childResults = n.children.slice(1).reduce((acc, child) => {
|
|
334
|
+
return acc.concat(_traverse(child, depth + 1));
|
|
335
|
+
}, []);
|
|
336
|
+
return [{
|
|
337
|
+
depth,
|
|
338
|
+
expression: loopExpression
|
|
339
|
+
}, ...childResults];
|
|
340
|
+
}
|
|
341
|
+
return n.children.reduce((acc, child) => {
|
|
342
|
+
return acc.concat(_traverse(child, depth));
|
|
343
|
+
}, []);
|
|
344
|
+
}(tree);
|
|
345
|
+
}
|
|
140
346
|
}
|
|
141
347
|
FeelersTemplating.$inject = [];
|
|
142
348
|
|
|
@@ -762,8 +968,13 @@ class Validator {
|
|
|
762
968
|
if (validate.pattern && value && !new RegExp(validate.pattern).test(value)) {
|
|
763
969
|
errors = [...errors, `Field must match pattern ${validate.pattern}.`];
|
|
764
970
|
}
|
|
765
|
-
if (validate.required
|
|
766
|
-
|
|
971
|
+
if (validate.required) {
|
|
972
|
+
const isUncheckedCheckbox = type === 'checkbox' && value === false;
|
|
973
|
+
const isUnsetValue = minDash.isNil(value) || value === '';
|
|
974
|
+
const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
|
|
975
|
+
if (isUncheckedCheckbox || isUnsetValue || isEmptyMultiselect) {
|
|
976
|
+
errors = [...errors, 'Field is required.'];
|
|
977
|
+
}
|
|
767
978
|
}
|
|
768
979
|
if ('min' in validate && (value || value === 0) && value < validate.min) {
|
|
769
980
|
errors = [...errors, `Field must have minimum value of ${validate.min}.`];
|
|
@@ -1065,6 +1276,7 @@ function createFormContainer(prefix = 'fjs') {
|
|
|
1065
1276
|
}
|
|
1066
1277
|
|
|
1067
1278
|
const EXPRESSION_PROPERTIES = ['alt', 'source', 'text'];
|
|
1279
|
+
const TEMPLATE_PROPERTIES = ['text'];
|
|
1068
1280
|
function findErrors(errors, path) {
|
|
1069
1281
|
return errors[pathStringify(path)];
|
|
1070
1282
|
}
|
|
@@ -1118,7 +1330,7 @@ function clone(data, replacer) {
|
|
|
1118
1330
|
*
|
|
1119
1331
|
* @return {string[]}
|
|
1120
1332
|
*/
|
|
1121
|
-
function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLanguage(null)) {
|
|
1333
|
+
function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLanguage(null), templating = new FeelersTemplating()) {
|
|
1122
1334
|
if (!schema.components) {
|
|
1123
1335
|
return [];
|
|
1124
1336
|
}
|
|
@@ -1153,6 +1365,13 @@ function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLangu
|
|
|
1153
1365
|
variables = [...variables, ...expressionVariables];
|
|
1154
1366
|
}
|
|
1155
1367
|
});
|
|
1368
|
+
TEMPLATE_PROPERTIES.forEach(prop => {
|
|
1369
|
+
const property = component[prop];
|
|
1370
|
+
if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
|
|
1371
|
+
const templateVariables = templating.getVariableNames(property);
|
|
1372
|
+
variables = [...variables, ...templateVariables];
|
|
1373
|
+
}
|
|
1374
|
+
});
|
|
1156
1375
|
return variables;
|
|
1157
1376
|
}, []);
|
|
1158
1377
|
|
|
@@ -1467,8 +1686,12 @@ function Checkbox(props) {
|
|
|
1467
1686
|
const {
|
|
1468
1687
|
description,
|
|
1469
1688
|
id,
|
|
1470
|
-
label
|
|
1689
|
+
label,
|
|
1690
|
+
validate = {}
|
|
1471
1691
|
} = field;
|
|
1692
|
+
const {
|
|
1693
|
+
required
|
|
1694
|
+
} = validate;
|
|
1472
1695
|
const onChange = ({
|
|
1473
1696
|
target
|
|
1474
1697
|
}) => {
|
|
@@ -1490,7 +1713,7 @@ function Checkbox(props) {
|
|
|
1490
1713
|
children: [jsxRuntime.jsx(Label, {
|
|
1491
1714
|
id: prefixId(id, formId),
|
|
1492
1715
|
label: label,
|
|
1493
|
-
required:
|
|
1716
|
+
required: required,
|
|
1494
1717
|
children: jsxRuntime.jsx("input", {
|
|
1495
1718
|
checked: value,
|
|
1496
1719
|
class: "fjs-input",
|
|
@@ -1857,8 +2080,12 @@ function Checklist(props) {
|
|
|
1857
2080
|
const {
|
|
1858
2081
|
description,
|
|
1859
2082
|
id,
|
|
1860
|
-
label
|
|
2083
|
+
label,
|
|
2084
|
+
validate = {}
|
|
1861
2085
|
} = field;
|
|
2086
|
+
const {
|
|
2087
|
+
required
|
|
2088
|
+
} = validate;
|
|
1862
2089
|
const toggleCheckbox = v => {
|
|
1863
2090
|
let newValue = [...value];
|
|
1864
2091
|
if (!newValue.includes(v)) {
|
|
@@ -1884,7 +2111,8 @@ function Checklist(props) {
|
|
|
1884
2111
|
disabled
|
|
1885
2112
|
})),
|
|
1886
2113
|
children: [jsxRuntime.jsx(Label, {
|
|
1887
|
-
label: label
|
|
2114
|
+
label: label,
|
|
2115
|
+
required: required
|
|
1888
2116
|
}), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
|
|
1889
2117
|
return jsxRuntime.jsx(Label, {
|
|
1890
2118
|
id: prefixId(`${id}-${index}`, formId),
|
|
@@ -3706,6 +3934,12 @@ function Select(props) {
|
|
|
3706
3934
|
errors,
|
|
3707
3935
|
disabled
|
|
3708
3936
|
}),
|
|
3937
|
+
onKeyDown: event => {
|
|
3938
|
+
if (event.key === 'Enter') {
|
|
3939
|
+
event.preventDefault();
|
|
3940
|
+
event.stopPropagation();
|
|
3941
|
+
}
|
|
3942
|
+
},
|
|
3709
3943
|
children: [jsxRuntime.jsx(Label, {
|
|
3710
3944
|
id: prefixId(id, formId),
|
|
3711
3945
|
label: label,
|
|
@@ -3754,8 +3988,12 @@ function Taglist(props) {
|
|
|
3754
3988
|
const {
|
|
3755
3989
|
description,
|
|
3756
3990
|
id,
|
|
3757
|
-
label
|
|
3991
|
+
label,
|
|
3992
|
+
validate = {}
|
|
3758
3993
|
} = field;
|
|
3994
|
+
const {
|
|
3995
|
+
required
|
|
3996
|
+
} = validate;
|
|
3759
3997
|
const {
|
|
3760
3998
|
formId
|
|
3761
3999
|
} = hooks.useContext(FormContext$1);
|
|
@@ -3852,8 +4090,15 @@ function Taglist(props) {
|
|
|
3852
4090
|
errors,
|
|
3853
4091
|
disabled
|
|
3854
4092
|
}),
|
|
4093
|
+
onKeyDown: event => {
|
|
4094
|
+
if (event.key === 'Enter') {
|
|
4095
|
+
event.stopPropagation();
|
|
4096
|
+
event.preventDefault();
|
|
4097
|
+
}
|
|
4098
|
+
},
|
|
3855
4099
|
children: [jsxRuntime.jsx(Label, {
|
|
3856
4100
|
label: label,
|
|
4101
|
+
required: required,
|
|
3857
4102
|
id: prefixId(`${id}-search`, formId)
|
|
3858
4103
|
}), jsxRuntime.jsxs("div", {
|
|
3859
4104
|
class: classNames('fjs-taglist', {
|