@bpmn-io/form-js-viewer 1.0.0-alpha.9 → 1.1.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/index.es.js CHANGED
@@ -1,27 +1,28 @@
1
1
  import Ids from 'ids';
2
- import { isString, isArray, isFunction, isNumber, bind, assign, isNil, groupBy, flatten, get, isUndefined, set, findIndex, isObject } from 'min-dash';
3
- import { parseExpressions, parseUnaryTests, evaluate, unaryTest } from 'feelin';
4
- import { evaluate as evaluate$1, parser, buildSimpleTree } from 'feelers';
5
- import showdown from 'showdown';
2
+ import { isString, uniqueBy, isArray, get, set, isFunction, isNumber, bind, assign, isNil, groupBy, flatten, isUndefined, findIndex, isObject } from 'min-dash';
6
3
  import Big from 'big.js';
4
+ import { parseExpression, parseUnaryTests, evaluate, unaryTest } from 'feelin';
5
+ import { evaluate as evaluate$1, parser, buildSimpleTree } from 'feelers';
7
6
  import classNames from 'classnames';
8
7
  import { jsx, jsxs, Fragment as Fragment$1 } from 'preact/jsx-runtime';
9
- import { useContext, useMemo, useEffect, useState, useRef, useCallback } from 'preact/hooks';
8
+ import { useContext, useMemo, useEffect, useState, useRef, useCallback, useLayoutEffect } from 'preact/hooks';
10
9
  import { createContext, createElement, Fragment, render } from 'preact';
11
- import React, { createPortal } from 'preact/compat';
10
+ import * as React from 'preact/compat';
11
+ import { createPortal } from 'preact/compat';
12
12
  import flatpickr from 'flatpickr';
13
13
  import Markup from 'preact-markup';
14
14
  import { Injector } from 'didi';
15
+ import showdown from 'showdown';
15
16
 
16
- const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) => {
17
+ const getFlavouredFeelVariableNames = (feelString, feelFlavour = 'expression', options = {}) => {
17
18
  const {
18
19
  depth = 0,
19
20
  specialDepthAccessors = {}
20
21
  } = options;
21
22
  if (!['expression', 'unaryTest'].includes(feelFlavour)) return [];
22
- const tree = feelFlavour === 'expression' ? parseExpressions(feelString) : parseUnaryTests(feelString);
23
+ const tree = feelFlavour === 'expression' ? parseExpression(feelString) : parseUnaryTests(feelString);
23
24
  const simpleExpressionTree = _buildSimpleFeelStructureTree(tree, feelString);
24
- return function _unfoldVariables(node) {
25
+ const variables = function _unfoldVariables(node) {
25
26
  if (node.name === 'PathExpression') {
26
27
  if (Object.keys(specialDepthAccessors).length === 0) {
27
28
  return depth === 0 ? [_getVariableNameAtPathIndex(node, 0)] : [];
@@ -34,34 +35,38 @@ const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) =>
34
35
 
35
36
  // for any other kind of node, traverse its children and flatten the result
36
37
  if (node.children) {
37
- return node.children.reduce((acc, child) => {
38
+ const variables = node.children.reduce((acc, child) => {
38
39
  return acc.concat(_unfoldVariables(child));
39
40
  }, []);
41
+
42
+ // if we are within a filter context, we need to remove the item variable as it is used for iteration there
43
+ return node.name === 'FilterContext' ? variables.filter(name => name !== 'item') : variables;
40
44
  }
41
45
  return [];
42
46
  }(simpleExpressionTree);
47
+ return [...new Set(variables)];
43
48
  };
44
49
 
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.
50
+ /**
51
+ * Get the variable name at the specified index in a given path expression.
52
+ *
53
+ * @param {Object} root - The root node of the path expression tree.
54
+ * @param {number} index - The index of the variable name to retrieve.
55
+ * @returns {string|null} The variable name at the specified index or null if index is out of bounds.
51
56
  */
52
57
  const _getVariableNameAtPathIndex = (root, index) => {
53
58
  const accessors = _deconstructPathExpression(root);
54
59
  return accessors[index] || null;
55
60
  };
56
61
 
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.
62
+ /**
63
+ * Extracts the variables which are required of the external context for a given path expression.
64
+ * This is done by traversing the path expression tree and keeping track of the current depth relative to the external context.
65
+ *
66
+ * @param {Object} node - The root node of the path expression tree.
67
+ * @param {number} initialDepth - The depth at which the root node is located in the outer context.
68
+ * @param {Object} specialDepthAccessors - Definitions of special keywords which represent more complex accesses of the outer context.
69
+ * @returns {Set} - A set containing the extracted variable names.
65
70
  */
66
71
  const _smartExtractVariableNames = (node, initialDepth, specialDepthAccessors) => {
67
72
  // depth info represents the previous (initialised as null) and current depth of the current accessor in the path expression
@@ -107,11 +112,11 @@ const _smartExtractVariableNames = (node, initialDepth, specialDepthAccessors) =
107
112
  return new Set(extractedVariables);
108
113
  };
109
114
 
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
+ * Deconstructs a path expression tree into an array of components.
117
+ *
118
+ * @param {Object} root - The root node of the path expression tree.
119
+ * @returns {Array<string>} An array of components in the path expression, in the correct order.
115
120
  */
116
121
  const _deconstructPathExpression = root => {
117
122
  let node = root;
@@ -130,13 +135,13 @@ const _deconstructPathExpression = root => {
130
135
  return parts.reverse();
131
136
  };
132
137
 
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.
138
+ /**
139
+ * Builds a simplified feel structure tree from the given parse tree and feel string.
140
+ * The nodes follow this structure: `{ name: string, children: Array, variableName?: string }`
141
+ *
142
+ * @param {Object} parseTree - The parse tree generated by a parser.
143
+ * @param {string} feelString - The feel string used for parsing.
144
+ * @returns {Object} The simplified feel structure tree.
140
145
  */
141
146
  const _buildSimpleFeelStructureTree = (parseTree, feelString) => {
142
147
  const stack = [{
@@ -159,7 +164,45 @@ const _buildSimpleFeelStructureTree = (parseTree, feelString) => {
159
164
  parent.children.push(result);
160
165
  }
161
166
  });
162
- return stack[0].children[0];
167
+ return _extractFilterExpressions(stack[0].children[0]);
168
+ };
169
+
170
+ /**
171
+ * Restructure the tree in such a way to bring filters (which create new contexts) to the root of the tree.
172
+ * This is done to simplify the extraction of variables and match the context hierarchy.
173
+ */
174
+ const _extractFilterExpressions = tree => {
175
+ const flattenedExpressionTree = {
176
+ name: 'Root',
177
+ children: [tree]
178
+ };
179
+ const iterate = node => {
180
+ if (node.children) {
181
+ for (let x = 0; x < node.children.length; x++) {
182
+ if (node.children[x].name === 'FilterExpression') {
183
+ const filterTarget = node.children[x].children[0];
184
+ const filterExpression = node.children[x].children[2];
185
+
186
+ // bypass the filter expression
187
+ node.children[x] = filterTarget;
188
+ const taggedFilterExpression = {
189
+ name: 'FilterContext',
190
+ children: [filterExpression]
191
+ };
192
+
193
+ // append the filter expression to the root
194
+ flattenedExpressionTree.children.push(taggedFilterExpression);
195
+
196
+ // recursively iterate the expression
197
+ iterate(filterExpression);
198
+ } else {
199
+ iterate(node.children[x]);
200
+ }
201
+ }
202
+ }
203
+ };
204
+ iterate(tree);
205
+ return flattenedExpressionTree;
163
206
  };
164
207
 
165
208
  class FeelExpressionLanguage {
@@ -167,25 +210,25 @@ class FeelExpressionLanguage {
167
210
  this._eventBus = eventBus;
168
211
  }
169
212
 
170
- /**
171
- * Determines if the given value is a FEEL expression.
172
- *
173
- * @param {any} value
174
- * @returns {boolean}
175
- *
213
+ /**
214
+ * Determines if the given value is a FEEL expression.
215
+ *
216
+ * @param {any} value
217
+ * @returns {boolean}
218
+ *
176
219
  */
177
220
  isExpression(value) {
178
221
  return isString(value) && value.startsWith('=');
179
222
  }
180
223
 
181
- /**
182
- * Retrieve variable names from a given FEEL expression.
183
- *
184
- * @param {string} expression
185
- * @param {object} [options]
186
- * @param {string} [options.type]
187
- *
188
- * @returns {string[]}
224
+ /**
225
+ * Retrieve variable names from a given FEEL expression.
226
+ *
227
+ * @param {string} expression
228
+ * @param {object} [options]
229
+ * @param {string} [options.type]
230
+ *
231
+ * @returns {string[]}
189
232
  */
190
233
  getVariableNames(expression, options = {}) {
191
234
  const {
@@ -200,13 +243,13 @@ class FeelExpressionLanguage {
200
243
  return getFlavouredFeelVariableNames(expression, type);
201
244
  }
202
245
 
203
- /**
204
- * Evaluate an expression.
205
- *
206
- * @param {string} expression
207
- * @param {import('../../types').Data} [data]
208
- *
209
- * @returns {any}
246
+ /**
247
+ * Evaluate an expression.
248
+ *
249
+ * @param {string} expression
250
+ * @param {import('../../types').Data} [data]
251
+ *
252
+ * @returns {any}
210
253
  */
211
254
  evaluate(expression, data = {}) {
212
255
  if (!expression) {
@@ -231,23 +274,23 @@ FeelExpressionLanguage.$inject = ['eventBus'];
231
274
  class FeelersTemplating {
232
275
  constructor() {}
233
276
 
234
- /**
235
- * Determines if the given value is a feelers template.
236
- *
237
- * @param {any} value
238
- * @returns {boolean}
239
- *
277
+ /**
278
+ * Determines if the given value is a feelers template.
279
+ *
280
+ * @param {any} value
281
+ * @returns {boolean}
282
+ *
240
283
  */
241
284
  isTemplate(value) {
242
285
  return isString(value) && (value.startsWith('=') || /{{.*?}}/.test(value));
243
286
  }
244
287
 
245
- /**
246
- * Retrieve variable names from a given feelers template.
247
- *
248
- * @param {string} template
249
- *
250
- * @returns {string[]}
288
+ /**
289
+ * Retrieve variable names from a given feelers template.
290
+ *
291
+ * @param {string} template
292
+ *
293
+ * @returns {string[]}
251
294
  */
252
295
  getVariableNames(template) {
253
296
  if (!this.isTemplate(template)) {
@@ -273,17 +316,17 @@ class FeelersTemplating {
273
316
  }, []);
274
317
  }
275
318
 
276
- /**
277
- * Evaluate a template.
278
- *
279
- * @param {string} template
280
- * @param {Object<string, any>} context
281
- * @param {Object} options
282
- * @param {boolean} [options.debug = false]
283
- * @param {boolean} [options.strict = false]
284
- * @param {Function} [options.buildDebugString]
285
- *
286
- * @returns
319
+ /**
320
+ * Evaluate a template.
321
+ *
322
+ * @param {string} template
323
+ * @param {Object<string, any>} context
324
+ * @param {Object} options
325
+ * @param {boolean} [options.debug = false]
326
+ * @param {boolean} [options.strict = false]
327
+ * @param {Function} [options.buildDebugString]
328
+ *
329
+ * @returns
287
330
  */
288
331
  evaluate(template, context = {}, options = {}) {
289
332
  const {
@@ -298,22 +341,22 @@ class FeelersTemplating {
298
341
  });
299
342
  }
300
343
 
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
344
+ /**
345
+ * @typedef {Object} ExpressionWithDepth
346
+ * @property {number} depth - The depth of the expression in the syntax tree.
347
+ * @property {string} expression - The extracted expression
305
348
  */
306
349
 
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);
350
+ /**
351
+ * Extracts all feel expressions in the template along with their depth in the syntax tree.
352
+ * The depth is incremented for child expressions of loops to account for context drilling.
353
+ * @name extractExpressionsWithDepth
354
+ * @param {string} template - A feelers template string.
355
+ * @returns {Array<ExpressionWithDepth>} An array of objects, each containing the depth and the extracted expression.
356
+ *
357
+ * @example
358
+ * const template = "Hello {{user}}, you have:{{#loop items}}\n- {{amount}} {{name}}{{/loop}}.";
359
+ * const extractedExpressions = _extractExpressionsWithDepth(template);
317
360
  */
318
361
  _extractExpressionsWithDepth(template) {
319
362
  // build simplified feelers syntax tree
@@ -344,9 +387,9 @@ class FeelersTemplating {
344
387
  }
345
388
  FeelersTemplating.$inject = [];
346
389
 
347
- /**
348
- * @typedef {object} Condition
349
- * @property {string} [hide]
390
+ /**
391
+ * @typedef {object} Condition
392
+ * @property {string} [hide]
350
393
  */
351
394
 
352
395
  class ConditionChecker {
@@ -355,11 +398,11 @@ class ConditionChecker {
355
398
  this._eventBus = eventBus;
356
399
  }
357
400
 
358
- /**
359
- * For given data, remove properties based on condition.
360
- *
361
- * @param {Object<string, any>} properties
362
- * @param {Object<string, any>} data
401
+ /**
402
+ * For given data, remove properties based on condition.
403
+ *
404
+ * @param {Object<string, any>} properties
405
+ * @param {Object<string, any>} data
363
406
  */
364
407
  applyConditions(properties, data = {}) {
365
408
  const conditions = this._getConditions();
@@ -378,13 +421,13 @@ class ConditionChecker {
378
421
  return newProperties;
379
422
  }
380
423
 
381
- /**
382
- * Check if given condition is met. Returns null for invalid/missing conditions.
383
- *
384
- * @param {string} condition
385
- * @param {import('../../types').Data} [data]
386
- *
387
- * @returns {boolean|null}
424
+ /**
425
+ * Check if given condition is met. Returns null for invalid/missing conditions.
426
+ *
427
+ * @param {string} condition
428
+ * @param {import('../../types').Data} [data]
429
+ *
430
+ * @returns {boolean|null}
388
431
  */
389
432
  check(condition, data = {}) {
390
433
  if (!condition) {
@@ -405,12 +448,12 @@ class ConditionChecker {
405
448
  }
406
449
  }
407
450
 
408
- /**
409
- * Check if hide condition is met.
410
- *
411
- * @param {Condition} condition
412
- * @param {Object<string, any>} data
413
- * @returns {boolean}
451
+ /**
452
+ * Check if hide condition is met.
453
+ *
454
+ * @param {Condition} condition
455
+ * @param {Object<string, any>} data
456
+ * @returns {boolean}
414
457
  */
415
458
  _checkHideCondition(condition, data) {
416
459
  if (!condition.hide) {
@@ -419,55 +462,787 @@ class ConditionChecker {
419
462
  const result = this.check(condition.hide, data);
420
463
  return result === true;
421
464
  }
422
- _getConditions() {
423
- const formFields = this._formFieldRegistry.getAll();
424
- return formFields.reduce((conditions, formField) => {
425
- const {
426
- key,
427
- conditional: condition
428
- } = formField;
429
- if (key && condition) {
430
- return [...conditions, {
431
- key,
432
- condition
433
- }];
434
- }
435
- return conditions;
436
- }, []);
465
+ _getConditions() {
466
+ const formFields = this._formFieldRegistry.getAll();
467
+ return formFields.reduce((conditions, formField) => {
468
+ const {
469
+ key,
470
+ conditional: condition
471
+ } = formField;
472
+ if (key && condition) {
473
+ return [...conditions, {
474
+ key,
475
+ condition
476
+ }];
477
+ }
478
+ return conditions;
479
+ }, []);
480
+ }
481
+ }
482
+ ConditionChecker.$inject = ['formFieldRegistry', 'eventBus'];
483
+
484
+ var ExpressionLanguageModule = {
485
+ __init__: ['expressionLanguage', 'templating', 'conditionChecker'],
486
+ expressionLanguage: ['type', FeelExpressionLanguage],
487
+ templating: ['type', FeelersTemplating],
488
+ conditionChecker: ['type', ConditionChecker]
489
+ };
490
+
491
+ // bootstrap showdown to support github flavored markdown
492
+ showdown.setFlavor('github');
493
+ class MarkdownRenderer {
494
+ constructor() {
495
+ this._converter = new showdown.Converter();
496
+ }
497
+
498
+ /**
499
+ * Render markdown to HTML.
500
+ *
501
+ * @param {string} markdown - The markdown to render
502
+ *
503
+ * @returns {string} HTML
504
+ */
505
+ render(markdown) {
506
+ return this._converter.makeHtml(markdown);
507
+ }
508
+ }
509
+ MarkdownRenderer.$inject = [];
510
+
511
+ var MarkdownModule = {
512
+ __init__: ['markdownRenderer'],
513
+ markdownRenderer: ['type', MarkdownRenderer]
514
+ };
515
+
516
+ /**
517
+ * @typedef {import('didi').Injector} Injector
518
+ *
519
+ * @typedef {import('../core/Types').ElementLike} ElementLike
520
+ *
521
+ * @typedef {import('../core/EventBus').default} EventBus
522
+ * @typedef {import('./CommandHandler').default} CommandHandler
523
+ *
524
+ * @typedef { any } CommandContext
525
+ * @typedef { {
526
+ * new (...args: any[]) : CommandHandler
527
+ * } } CommandHandlerConstructor
528
+ * @typedef { {
529
+ * [key: string]: CommandHandler;
530
+ * } } CommandHandlerMap
531
+ * @typedef { {
532
+ * command: string;
533
+ * context: any;
534
+ * id?: any;
535
+ * } } CommandStackAction
536
+ * @typedef { {
537
+ * actions: CommandStackAction[];
538
+ * dirty: ElementLike[];
539
+ * trigger: 'execute' | 'undo' | 'redo' | 'clear' | null;
540
+ * atomic?: boolean;
541
+ * } } CurrentExecution
542
+ */
543
+
544
+ /**
545
+ * A service that offers un- and redoable execution of commands.
546
+ *
547
+ * The command stack is responsible for executing modeling actions
548
+ * in a un- and redoable manner. To do this it delegates the actual
549
+ * command execution to {@link CommandHandler}s.
550
+ *
551
+ * Command handlers provide {@link CommandHandler#execute(ctx)} and
552
+ * {@link CommandHandler#revert(ctx)} methods to un- and redo a command
553
+ * identified by a command context.
554
+ *
555
+ *
556
+ * ## Life-Cycle events
557
+ *
558
+ * In the process the command stack fires a number of life-cycle events
559
+ * that other components to participate in the command execution.
560
+ *
561
+ * * preExecute
562
+ * * preExecuted
563
+ * * execute
564
+ * * executed
565
+ * * postExecute
566
+ * * postExecuted
567
+ * * revert
568
+ * * reverted
569
+ *
570
+ * A special event is used for validating, whether a command can be
571
+ * performed prior to its execution.
572
+ *
573
+ * * canExecute
574
+ *
575
+ * Each of the events is fired as `commandStack.{eventName}` and
576
+ * `commandStack.{commandName}.{eventName}`, respectively. This gives
577
+ * components fine grained control on where to hook into.
578
+ *
579
+ * The event object fired transports `command`, the name of the
580
+ * command and `context`, the command context.
581
+ *
582
+ *
583
+ * ## Creating Command Handlers
584
+ *
585
+ * Command handlers should provide the {@link CommandHandler#execute(ctx)}
586
+ * and {@link CommandHandler#revert(ctx)} methods to implement
587
+ * redoing and undoing of a command.
588
+ *
589
+ * A command handler _must_ ensure undo is performed properly in order
590
+ * not to break the undo chain. It must also return the shapes that
591
+ * got changed during the `execute` and `revert` operations.
592
+ *
593
+ * Command handlers may execute other modeling operations (and thus
594
+ * commands) in their `preExecute(d)` and `postExecute(d)` phases. The command
595
+ * stack will properly group all commands together into a logical unit
596
+ * that may be re- and undone atomically.
597
+ *
598
+ * Command handlers must not execute other commands from within their
599
+ * core implementation (`execute`, `revert`).
600
+ *
601
+ *
602
+ * ## Change Tracking
603
+ *
604
+ * During the execution of the CommandStack it will keep track of all
605
+ * elements that have been touched during the command's execution.
606
+ *
607
+ * At the end of the CommandStack execution it will notify interested
608
+ * components via an 'elements.changed' event with all the dirty
609
+ * elements.
610
+ *
611
+ * The event can be picked up by components that are interested in the fact
612
+ * that elements have been changed. One use case for this is updating
613
+ * their graphical representation after moving / resizing or deletion.
614
+ *
615
+ * @see CommandHandler
616
+ *
617
+ * @param {EventBus} eventBus
618
+ * @param {Injector} injector
619
+ */
620
+ function CommandStack(eventBus, injector) {
621
+ /**
622
+ * A map of all registered command handlers.
623
+ *
624
+ * @type {CommandHandlerMap}
625
+ */
626
+ this._handlerMap = {};
627
+
628
+ /**
629
+ * A stack containing all re/undoable actions on the diagram
630
+ *
631
+ * @type {CommandStackAction[]}
632
+ */
633
+ this._stack = [];
634
+
635
+ /**
636
+ * The current index on the stack
637
+ *
638
+ * @type {number}
639
+ */
640
+ this._stackIdx = -1;
641
+
642
+ /**
643
+ * Current active commandStack execution
644
+ *
645
+ * @type {CurrentExecution}
646
+ */
647
+ this._currentExecution = {
648
+ actions: [],
649
+ dirty: [],
650
+ trigger: null
651
+ };
652
+
653
+ /**
654
+ * @type {Injector}
655
+ */
656
+ this._injector = injector;
657
+
658
+ /**
659
+ * @type EventBus
660
+ */
661
+ this._eventBus = eventBus;
662
+
663
+ /**
664
+ * @type { number }
665
+ */
666
+ this._uid = 1;
667
+ eventBus.on(['diagram.destroy', 'diagram.clear'], function () {
668
+ this.clear(false);
669
+ }, this);
670
+ }
671
+ CommandStack.$inject = ['eventBus', 'injector'];
672
+
673
+ /**
674
+ * Execute a command.
675
+ *
676
+ * @param {string} command The command to execute.
677
+ * @param {CommandContext} context The context with which to execute the command.
678
+ */
679
+ CommandStack.prototype.execute = function (command, context) {
680
+ if (!command) {
681
+ throw new Error('command required');
682
+ }
683
+ this._currentExecution.trigger = 'execute';
684
+ const action = {
685
+ command: command,
686
+ context: context
687
+ };
688
+ this._pushAction(action);
689
+ this._internalExecute(action);
690
+ this._popAction();
691
+ };
692
+
693
+ /**
694
+ * Check whether a command can be executed.
695
+ *
696
+ * Implementors may hook into the mechanism on two ways:
697
+ *
698
+ * * in event listeners:
699
+ *
700
+ * Users may prevent the execution via an event listener.
701
+ * It must prevent the default action for `commandStack.(<command>.)canExecute` events.
702
+ *
703
+ * * in command handlers:
704
+ *
705
+ * If the method {@link CommandHandler#canExecute} is implemented in a handler
706
+ * it will be called to figure out whether the execution is allowed.
707
+ *
708
+ * @param {string} command The command to execute.
709
+ * @param {CommandContext} context The context with which to execute the command.
710
+ *
711
+ * @return {boolean} Whether the command can be executed with the given context.
712
+ */
713
+ CommandStack.prototype.canExecute = function (command, context) {
714
+ const action = {
715
+ command: command,
716
+ context: context
717
+ };
718
+ const handler = this._getHandler(command);
719
+ let result = this._fire(command, 'canExecute', action);
720
+
721
+ // handler#canExecute will only be called if no listener
722
+ // decided on a result already
723
+ if (result === undefined) {
724
+ if (!handler) {
725
+ return false;
726
+ }
727
+ if (handler.canExecute) {
728
+ result = handler.canExecute(context);
729
+ }
730
+ }
731
+ return result;
732
+ };
733
+
734
+ /**
735
+ * Clear the command stack, erasing all undo / redo history.
736
+ *
737
+ * @param {boolean} [emit=true] Whether to fire an event. Defaults to `true`.
738
+ */
739
+ CommandStack.prototype.clear = function (emit) {
740
+ this._stack.length = 0;
741
+ this._stackIdx = -1;
742
+ if (emit !== false) {
743
+ this._fire('changed', {
744
+ trigger: 'clear'
745
+ });
746
+ }
747
+ };
748
+
749
+ /**
750
+ * Undo last command(s)
751
+ */
752
+ CommandStack.prototype.undo = function () {
753
+ let action = this._getUndoAction(),
754
+ next;
755
+ if (action) {
756
+ this._currentExecution.trigger = 'undo';
757
+ this._pushAction(action);
758
+ while (action) {
759
+ this._internalUndo(action);
760
+ next = this._getUndoAction();
761
+ if (!next || next.id !== action.id) {
762
+ break;
763
+ }
764
+ action = next;
765
+ }
766
+ this._popAction();
767
+ }
768
+ };
769
+
770
+ /**
771
+ * Redo last command(s)
772
+ */
773
+ CommandStack.prototype.redo = function () {
774
+ let action = this._getRedoAction(),
775
+ next;
776
+ if (action) {
777
+ this._currentExecution.trigger = 'redo';
778
+ this._pushAction(action);
779
+ while (action) {
780
+ this._internalExecute(action, true);
781
+ next = this._getRedoAction();
782
+ if (!next || next.id !== action.id) {
783
+ break;
784
+ }
785
+ action = next;
786
+ }
787
+ this._popAction();
788
+ }
789
+ };
790
+
791
+ /**
792
+ * Register a handler instance with the command stack.
793
+ *
794
+ * @param {string} command Command to be executed.
795
+ * @param {CommandHandler} handler Handler to execute the command.
796
+ */
797
+ CommandStack.prototype.register = function (command, handler) {
798
+ this._setHandler(command, handler);
799
+ };
800
+
801
+ /**
802
+ * Register a handler type with the command stack by instantiating it and
803
+ * injecting its dependencies.
804
+ *
805
+ * @param {string} command Command to be executed.
806
+ * @param {CommandHandlerConstructor} handlerCls Constructor to instantiate a {@link CommandHandler}.
807
+ */
808
+ CommandStack.prototype.registerHandler = function (command, handlerCls) {
809
+ if (!command || !handlerCls) {
810
+ throw new Error('command and handlerCls must be defined');
811
+ }
812
+ const handler = this._injector.instantiate(handlerCls);
813
+ this.register(command, handler);
814
+ };
815
+
816
+ /**
817
+ * @return {boolean}
818
+ */
819
+ CommandStack.prototype.canUndo = function () {
820
+ return !!this._getUndoAction();
821
+ };
822
+
823
+ /**
824
+ * @return {boolean}
825
+ */
826
+ CommandStack.prototype.canRedo = function () {
827
+ return !!this._getRedoAction();
828
+ };
829
+
830
+ // stack access //////////////////////
831
+
832
+ CommandStack.prototype._getRedoAction = function () {
833
+ return this._stack[this._stackIdx + 1];
834
+ };
835
+ CommandStack.prototype._getUndoAction = function () {
836
+ return this._stack[this._stackIdx];
837
+ };
838
+
839
+ // internal functionality //////////////////////
840
+
841
+ CommandStack.prototype._internalUndo = function (action) {
842
+ const command = action.command,
843
+ context = action.context;
844
+ const handler = this._getHandler(command);
845
+
846
+ // guard against illegal nested command stack invocations
847
+ this._atomicDo(() => {
848
+ this._fire(command, 'revert', action);
849
+ if (handler.revert) {
850
+ this._markDirty(handler.revert(context));
851
+ }
852
+ this._revertedAction(action);
853
+ this._fire(command, 'reverted', action);
854
+ });
855
+ };
856
+ CommandStack.prototype._fire = function (command, qualifier, event) {
857
+ if (arguments.length < 3) {
858
+ event = qualifier;
859
+ qualifier = null;
860
+ }
861
+ const names = qualifier ? [command + '.' + qualifier, qualifier] : [command];
862
+ let result;
863
+ event = this._eventBus.createEvent(event);
864
+ for (const name of names) {
865
+ result = this._eventBus.fire('commandStack.' + name, event);
866
+ if (event.cancelBubble) {
867
+ break;
868
+ }
869
+ }
870
+ return result;
871
+ };
872
+ CommandStack.prototype._createId = function () {
873
+ return this._uid++;
874
+ };
875
+ CommandStack.prototype._atomicDo = function (fn) {
876
+ const execution = this._currentExecution;
877
+ execution.atomic = true;
878
+ try {
879
+ fn();
880
+ } finally {
881
+ execution.atomic = false;
882
+ }
883
+ };
884
+ CommandStack.prototype._internalExecute = function (action, redo) {
885
+ const command = action.command,
886
+ context = action.context;
887
+ const handler = this._getHandler(command);
888
+ if (!handler) {
889
+ throw new Error('no command handler registered for <' + command + '>');
890
+ }
891
+ this._pushAction(action);
892
+ if (!redo) {
893
+ this._fire(command, 'preExecute', action);
894
+ if (handler.preExecute) {
895
+ handler.preExecute(context);
896
+ }
897
+ this._fire(command, 'preExecuted', action);
898
+ }
899
+
900
+ // guard against illegal nested command stack invocations
901
+ this._atomicDo(() => {
902
+ this._fire(command, 'execute', action);
903
+ if (handler.execute) {
904
+ // actual execute + mark return results as dirty
905
+ this._markDirty(handler.execute(context));
906
+ }
907
+
908
+ // log to stack
909
+ this._executedAction(action, redo);
910
+ this._fire(command, 'executed', action);
911
+ });
912
+ if (!redo) {
913
+ this._fire(command, 'postExecute', action);
914
+ if (handler.postExecute) {
915
+ handler.postExecute(context);
916
+ }
917
+ this._fire(command, 'postExecuted', action);
918
+ }
919
+ this._popAction();
920
+ };
921
+ CommandStack.prototype._pushAction = function (action) {
922
+ const execution = this._currentExecution,
923
+ actions = execution.actions;
924
+ const baseAction = actions[0];
925
+ if (execution.atomic) {
926
+ throw new Error('illegal invocation in <execute> or <revert> phase (action: ' + action.command + ')');
927
+ }
928
+ if (!action.id) {
929
+ action.id = baseAction && baseAction.id || this._createId();
930
+ }
931
+ actions.push(action);
932
+ };
933
+ CommandStack.prototype._popAction = function () {
934
+ const execution = this._currentExecution,
935
+ trigger = execution.trigger,
936
+ actions = execution.actions,
937
+ dirty = execution.dirty;
938
+ actions.pop();
939
+ if (!actions.length) {
940
+ this._eventBus.fire('elements.changed', {
941
+ elements: uniqueBy('id', dirty.reverse())
942
+ });
943
+ dirty.length = 0;
944
+ this._fire('changed', {
945
+ trigger: trigger
946
+ });
947
+ execution.trigger = null;
948
+ }
949
+ };
950
+ CommandStack.prototype._markDirty = function (elements) {
951
+ const execution = this._currentExecution;
952
+ if (!elements) {
953
+ return;
954
+ }
955
+ elements = isArray(elements) ? elements : [elements];
956
+ execution.dirty = execution.dirty.concat(elements);
957
+ };
958
+ CommandStack.prototype._executedAction = function (action, redo) {
959
+ const stackIdx = ++this._stackIdx;
960
+ if (!redo) {
961
+ this._stack.splice(stackIdx, this._stack.length, action);
962
+ }
963
+ };
964
+ CommandStack.prototype._revertedAction = function (action) {
965
+ this._stackIdx--;
966
+ };
967
+ CommandStack.prototype._getHandler = function (command) {
968
+ return this._handlerMap[command];
969
+ };
970
+ CommandStack.prototype._setHandler = function (command, handler) {
971
+ if (!command || !handler) {
972
+ throw new Error('command and handler required');
973
+ }
974
+ if (this._handlerMap[command]) {
975
+ throw new Error('overriding handler for command <' + command + '>');
976
+ }
977
+ this._handlerMap[command] = handler;
978
+ };
979
+
980
+ /**
981
+ * @type { import('didi').ModuleDeclaration }
982
+ */
983
+ var commandModule = {
984
+ commandStack: ['type', CommandStack]
985
+ };
986
+
987
+ // config ///////////////////
988
+
989
+ const MINUTES_IN_DAY = 60 * 24;
990
+ const DATETIME_SUBTYPES = {
991
+ DATE: 'date',
992
+ TIME: 'time',
993
+ DATETIME: 'datetime'
994
+ };
995
+ const TIME_SERIALISING_FORMATS = {
996
+ UTC_OFFSET: 'utc_offset',
997
+ UTC_NORMALIZED: 'utc_normalized',
998
+ NO_TIMEZONE: 'no_timezone'
999
+ };
1000
+ const DATETIME_SUBTYPES_LABELS = {
1001
+ [DATETIME_SUBTYPES.DATE]: 'Date',
1002
+ [DATETIME_SUBTYPES.TIME]: 'Time',
1003
+ [DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
1004
+ };
1005
+ const TIME_SERIALISINGFORMAT_LABELS = {
1006
+ [TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
1007
+ [TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
1008
+ [TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
1009
+ };
1010
+ const DATETIME_SUBTYPE_PATH = ['subtype'];
1011
+ const DATE_LABEL_PATH = ['dateLabel'];
1012
+ const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
1013
+ const TIME_LABEL_PATH = ['timeLabel'];
1014
+ const TIME_USE24H_PATH = ['use24h'];
1015
+ const TIME_INTERVAL_PATH = ['timeInterval'];
1016
+ const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
1017
+
1018
+ // config ///////////////////
1019
+
1020
+ const VALUES_SOURCES = {
1021
+ STATIC: 'static',
1022
+ INPUT: 'input',
1023
+ EXPRESSION: 'expression'
1024
+ };
1025
+ const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
1026
+ const VALUES_SOURCES_LABELS = {
1027
+ [VALUES_SOURCES.STATIC]: 'Static',
1028
+ [VALUES_SOURCES.INPUT]: 'Input data',
1029
+ [VALUES_SOURCES.EXPRESSION]: 'Expression'
1030
+ };
1031
+ const VALUES_SOURCES_PATHS = {
1032
+ [VALUES_SOURCES.STATIC]: ['values'],
1033
+ [VALUES_SOURCES.INPUT]: ['valuesKey'],
1034
+ [VALUES_SOURCES.EXPRESSION]: ['valuesExpression']
1035
+ };
1036
+ const VALUES_SOURCES_DEFAULTS = {
1037
+ [VALUES_SOURCES.STATIC]: [{
1038
+ label: 'Value',
1039
+ value: 'value'
1040
+ }],
1041
+ [VALUES_SOURCES.INPUT]: '',
1042
+ [VALUES_SOURCES.EXPRESSION]: '='
1043
+ };
1044
+
1045
+ // helpers ///////////////////
1046
+
1047
+ function getValuesSource(field) {
1048
+ for (const source of Object.values(VALUES_SOURCES)) {
1049
+ if (get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
1050
+ return source;
1051
+ }
1052
+ }
1053
+ return VALUES_SOURCE_DEFAULT;
1054
+ }
1055
+
1056
+ function createInjector(bootstrapModules) {
1057
+ const injector = new Injector(bootstrapModules);
1058
+ injector.init();
1059
+ return injector;
1060
+ }
1061
+
1062
+ /**
1063
+ * @param {string?} prefix
1064
+ *
1065
+ * @returns Element
1066
+ */
1067
+ function createFormContainer(prefix = 'fjs') {
1068
+ const container = document.createElement('div');
1069
+ container.classList.add(`${prefix}-container`);
1070
+ return container;
1071
+ }
1072
+
1073
+ const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression'];
1074
+ const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text'];
1075
+ function findErrors(errors, path) {
1076
+ return errors[pathStringify(path)];
1077
+ }
1078
+ function isRequired(field) {
1079
+ return field.required;
1080
+ }
1081
+ function pathParse(path) {
1082
+ if (!path) {
1083
+ return [];
1084
+ }
1085
+ return path.split('.').map(key => {
1086
+ return isNaN(parseInt(key)) ? key : parseInt(key);
1087
+ });
1088
+ }
1089
+ function pathsEqual(a, b) {
1090
+ return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
1091
+ }
1092
+ function pathStringify(path) {
1093
+ if (!path) {
1094
+ return '';
1095
+ }
1096
+ return path.join('.');
1097
+ }
1098
+ const indices = {};
1099
+ function generateIndexForType(type) {
1100
+ if (type in indices) {
1101
+ indices[type]++;
1102
+ } else {
1103
+ indices[type] = 1;
1104
+ }
1105
+ return indices[type];
1106
+ }
1107
+ function generateIdForType(type) {
1108
+ return `${type}${generateIndexForType(type)}`;
1109
+ }
1110
+
1111
+ /**
1112
+ * @template T
1113
+ * @param {T} data
1114
+ * @param {(this: any, key: string, value: any) => any} [replacer]
1115
+ * @return {T}
1116
+ */
1117
+ function clone(data, replacer) {
1118
+ return JSON.parse(JSON.stringify(data, replacer));
1119
+ }
1120
+
1121
+ /**
1122
+ * Parse the schema for input variables a form might make use of
1123
+ *
1124
+ * @param {any} schema
1125
+ *
1126
+ * @return {string[]}
1127
+ */
1128
+ function getSchemaVariables(schema, options = {}) {
1129
+ const {
1130
+ expressionLanguage = new FeelExpressionLanguage(null),
1131
+ templating = new FeelersTemplating(),
1132
+ inputs = true,
1133
+ outputs = true
1134
+ } = options;
1135
+ if (!schema.components) {
1136
+ return [];
1137
+ }
1138
+ const variables = schema.components.reduce((variables, component) => {
1139
+ const {
1140
+ key,
1141
+ valuesKey,
1142
+ type
1143
+ } = component;
1144
+ if (['button'].includes(type)) {
1145
+ return variables;
1146
+ }
1147
+
1148
+ // collect bi-directional variables
1149
+ if (inputs || outputs) {
1150
+ if (key) {
1151
+ variables = [...variables, key];
1152
+ }
1153
+ }
1154
+
1155
+ // collect input-only variables
1156
+ if (inputs) {
1157
+ if (valuesKey) {
1158
+ variables = [...variables, valuesKey];
1159
+ }
1160
+ EXPRESSION_PROPERTIES.forEach(prop => {
1161
+ const property = get(component, prop.split('.'));
1162
+ if (property && expressionLanguage.isExpression(property)) {
1163
+ const expressionVariables = expressionLanguage.getVariableNames(property, {
1164
+ type: 'expression'
1165
+ });
1166
+ variables = [...variables, ...expressionVariables];
1167
+ }
1168
+ });
1169
+ TEMPLATE_PROPERTIES.forEach(prop => {
1170
+ const property = get(component, prop.split('.'));
1171
+ if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
1172
+ const templateVariables = templating.getVariableNames(property);
1173
+ variables = [...variables, ...templateVariables];
1174
+ }
1175
+ });
1176
+ }
1177
+ return variables.filter(variable => variable !== undefined || variable !== null);
1178
+ }, []);
1179
+
1180
+ // remove duplicates
1181
+ return Array.from(new Set(variables));
1182
+ }
1183
+
1184
+ class UpdateFieldValidationHandler {
1185
+ constructor(form, validator) {
1186
+ this._form = form;
1187
+ this._validator = validator;
1188
+ }
1189
+ execute(context) {
1190
+ const {
1191
+ field,
1192
+ value
1193
+ } = context;
1194
+ const {
1195
+ _path
1196
+ } = field;
1197
+ const {
1198
+ errors
1199
+ } = this._form._getState();
1200
+ context.oldErrors = clone(errors);
1201
+ const fieldErrors = this._validator.validateField(field, value);
1202
+ const updatedErrors = set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined);
1203
+ this._form._setState({
1204
+ errors: updatedErrors
1205
+ });
1206
+ }
1207
+ revert(context) {
1208
+ this._form._setState({
1209
+ errors: context.oldErrors
1210
+ });
437
1211
  }
438
1212
  }
439
- ConditionChecker.$inject = ['formFieldRegistry', 'eventBus'];
1213
+ UpdateFieldValidationHandler.$inject = ['form', 'validator'];
440
1214
 
441
- var ExpressionLanguageModule = {
442
- __init__: ['expressionLanguage', 'templating', 'conditionChecker'],
443
- expressionLanguage: ['type', FeelExpressionLanguage],
444
- templating: ['type', FeelersTemplating],
445
- conditionChecker: ['type', ConditionChecker]
446
- };
447
-
448
- // bootstrap showdown to support github flavored markdown
449
- showdown.setFlavor('github');
450
- class MarkdownRenderer {
451
- constructor() {
452
- this._converter = new showdown.Converter();
1215
+ class ViewerCommands {
1216
+ constructor(commandStack, eventBus) {
1217
+ this._commandStack = commandStack;
1218
+ eventBus.on('form.init', () => {
1219
+ this.registerHandlers();
1220
+ });
453
1221
  }
454
-
455
- /**
456
- * Render markdown to HTML.
457
- *
458
- * @param {string} markdown - The markdown to render
459
- *
460
- * @returns {string} HTML
461
- */
462
- render(markdown) {
463
- return this._converter.makeHtml(markdown);
1222
+ registerHandlers() {
1223
+ Object.entries(this.getHandlers()).forEach(([id, handler]) => {
1224
+ this._commandStack.registerHandler(id, handler);
1225
+ });
1226
+ }
1227
+ getHandlers() {
1228
+ return {
1229
+ 'formField.validation.update': UpdateFieldValidationHandler
1230
+ };
1231
+ }
1232
+ updateFieldValidation(field, value) {
1233
+ const context = {
1234
+ field,
1235
+ value
1236
+ };
1237
+ this._commandStack.execute('formField.validation.update', context);
464
1238
  }
465
1239
  }
466
- MarkdownRenderer.$inject = [];
1240
+ ViewerCommands.$inject = ['commandStack', 'eventBus'];
467
1241
 
468
- var MarkdownModule = {
469
- __init__: ['markdownRenderer'],
470
- markdownRenderer: ['type', MarkdownRenderer]
1242
+ var ViewerCommandsModule = {
1243
+ __depends__: [commandModule],
1244
+ __init__: ['viewerCommands'],
1245
+ viewerCommands: ['type', ViewerCommands]
471
1246
  };
472
1247
 
473
1248
  var FN_REF = '__fn';
@@ -997,7 +1772,13 @@ function isNullEquivalentValue(value) {
997
1772
 
998
1773
  const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
999
1774
  const PHONE_PATTERN = /(\+|00)(297|93|244|1264|358|355|376|971|54|374|1684|1268|61|43|994|257|32|229|226|880|359|973|1242|387|590|375|501|1441|591|55|1246|673|975|267|236|1|61|41|56|86|225|237|243|242|682|57|269|238|506|53|5999|61|1345|357|420|49|253|1767|45|1809|1829|1849|213|593|20|291|212|34|372|251|358|679|500|33|298|691|241|44|995|44|233|350|224|590|220|245|240|30|1473|299|502|594|1671|592|852|504|385|509|36|62|44|91|246|353|98|964|354|972|39|1876|44|962|81|76|77|254|996|855|686|1869|82|383|965|856|961|231|218|1758|423|94|266|370|352|371|853|590|212|377|373|261|960|52|692|389|223|356|95|382|976|1670|258|222|1664|596|230|265|60|262|264|687|227|672|234|505|683|31|47|977|674|64|968|92|507|64|51|63|680|675|48|1787|1939|850|351|595|970|689|974|262|40|7|250|966|249|221|65|500|4779|677|232|503|378|252|508|381|211|239|597|421|386|46|268|1721|248|963|1649|235|228|66|992|690|993|670|676|1868|216|90|688|886|255|256|380|598|1|998|3906698|379|1784|58|1284|1340|84|678|681|685|967|27|260|263)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{4,20}$/;
1775
+ const VALIDATE_FEEL_PROPERTIES = ['min', 'max', 'minLength', 'maxLength'];
1000
1776
  class Validator {
1777
+ constructor(expressionLanguage, conditionChecker, form) {
1778
+ this._expressionLanguage = expressionLanguage;
1779
+ this._conditionChecker = conditionChecker;
1780
+ this._form = form;
1781
+ }
1001
1782
  validateField(field, value) {
1002
1783
  const {
1003
1784
  type,
@@ -1030,10 +1811,11 @@ class Validator {
1030
1811
  if (!validate) {
1031
1812
  return errors;
1032
1813
  }
1033
- if (validate.pattern && value && !new RegExp(validate.pattern).test(value)) {
1034
- errors = [...errors, `Field must match pattern ${validate.pattern}.`];
1814
+ const evaluatedValidation = evaluateFEELValues(validate, this._expressionLanguage, this._conditionChecker, this._form);
1815
+ if (evaluatedValidation.pattern && value && !new RegExp(evaluatedValidation.pattern).test(value)) {
1816
+ errors = [...errors, `Field must match pattern ${evaluatedValidation.pattern}.`];
1035
1817
  }
1036
- if (validate.required) {
1818
+ if (evaluatedValidation.required) {
1037
1819
  const isUncheckedCheckbox = type === 'checkbox' && value === false;
1038
1820
  const isUnsetValue = isNil(value) || value === '';
1039
1821
  const isEmptyMultiselect = Array.isArray(value) && value.length === 0;
@@ -1041,28 +1823,64 @@ class Validator {
1041
1823
  errors = [...errors, 'Field is required.'];
1042
1824
  }
1043
1825
  }
1044
- if ('min' in validate && (value || value === 0) && value < validate.min) {
1045
- errors = [...errors, `Field must have minimum value of ${validate.min}.`];
1826
+ if ('min' in evaluatedValidation && (value || value === 0) && value < evaluatedValidation.min) {
1827
+ errors = [...errors, `Field must have minimum value of ${evaluatedValidation.min}.`];
1046
1828
  }
1047
- if ('max' in validate && (value || value === 0) && value > validate.max) {
1048
- errors = [...errors, `Field must have maximum value of ${validate.max}.`];
1829
+ if ('max' in evaluatedValidation && (value || value === 0) && value > evaluatedValidation.max) {
1830
+ errors = [...errors, `Field must have maximum value of ${evaluatedValidation.max}.`];
1049
1831
  }
1050
- if ('minLength' in validate && value && value.trim().length < validate.minLength) {
1051
- errors = [...errors, `Field must have minimum length of ${validate.minLength}.`];
1832
+ if ('minLength' in evaluatedValidation && value && value.trim().length < evaluatedValidation.minLength) {
1833
+ errors = [...errors, `Field must have minimum length of ${evaluatedValidation.minLength}.`];
1052
1834
  }
1053
- if ('maxLength' in validate && value && value.trim().length > validate.maxLength) {
1054
- errors = [...errors, `Field must have maximum length of ${validate.maxLength}.`];
1835
+ if ('maxLength' in evaluatedValidation && value && value.trim().length > evaluatedValidation.maxLength) {
1836
+ errors = [...errors, `Field must have maximum length of ${evaluatedValidation.maxLength}.`];
1055
1837
  }
1056
- if ('validationType' in validate && value && validate.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
1838
+ if ('validationType' in evaluatedValidation && value && evaluatedValidation.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
1057
1839
  errors = [...errors, 'Field must be a valid international phone number. (e.g. +4930664040900)'];
1058
1840
  }
1059
- if ('validationType' in validate && value && validate.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
1841
+ if ('validationType' in evaluatedValidation && value && evaluatedValidation.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
1060
1842
  errors = [...errors, 'Field must be a valid email.'];
1061
1843
  }
1062
1844
  return errors;
1063
1845
  }
1064
1846
  }
1065
- Validator.$inject = [];
1847
+ Validator.$inject = ['expressionLanguage', 'conditionChecker', 'form'];
1848
+
1849
+ // helpers //////////
1850
+
1851
+ /**
1852
+ * Helper function to evaluate optional FEEL validation values.
1853
+ */
1854
+ function evaluateFEELValues(validate, expressionLanguage, conditionChecker, form) {
1855
+ const evaluatedValidate = {
1856
+ ...validate
1857
+ };
1858
+ VALIDATE_FEEL_PROPERTIES.forEach(property => {
1859
+ const path = property.split('.');
1860
+ const value = get(evaluatedValidate, path);
1861
+
1862
+ // mirroring FEEL evaluation of our hooks
1863
+ if (!expressionLanguage || !expressionLanguage.isExpression(value)) {
1864
+ return value;
1865
+ }
1866
+ const {
1867
+ initialData,
1868
+ data
1869
+ } = form._getState();
1870
+ const newData = conditionChecker ? conditionChecker.applyConditions(data, data) : data;
1871
+ const filteredData = {
1872
+ ...initialData,
1873
+ ...newData
1874
+ };
1875
+ const evaluatedValue = expressionLanguage.evaluate(value, filteredData);
1876
+
1877
+ // replace validate property with evaluated value
1878
+ if (evaluatedValue) {
1879
+ set(evaluatedValidate, path, evaluatedValue);
1880
+ }
1881
+ });
1882
+ return evaluatedValidate;
1883
+ }
1066
1884
 
1067
1885
  class FormFieldRegistry {
1068
1886
  constructor(eventBus) {
@@ -1113,23 +1931,23 @@ class FormFieldRegistry {
1113
1931
  }
1114
1932
  FormFieldRegistry.$inject = ['eventBus'];
1115
1933
 
1116
- /**
1117
- * @typedef { { id: String, components: Array<String> } } FormRow
1118
- * @typedef { { formFieldId: String, rows: Array<FormRow> } } FormRows
1934
+ /**
1935
+ * @typedef { { id: String, components: Array<String> } } FormRow
1936
+ * @typedef { { formFieldId: String, rows: Array<FormRow> } } FormRows
1119
1937
  */
1120
1938
 
1121
- /**
1122
- * Maintains the Form layout in a given structure, for example
1123
- *
1124
- * [
1125
- * {
1126
- * formFieldId: 'FormField_1',
1127
- * rows: [
1128
- * { id: 'Row_1', components: [ 'Text_1', 'Textdield_1', ... ] }
1129
- * ]
1130
- * }
1131
- * ]
1132
- *
1939
+ /**
1940
+ * Maintains the Form layout in a given structure, for example
1941
+ *
1942
+ * [
1943
+ * {
1944
+ * formFieldId: 'FormField_1',
1945
+ * rows: [
1946
+ * { id: 'Row_1', components: [ 'Text_1', 'Textdield_1', ... ] }
1947
+ * ]
1948
+ * }
1949
+ * ]
1950
+ *
1133
1951
  */
1134
1952
  class FormLayouter {
1135
1953
  constructor(eventBus) {
@@ -1139,8 +1957,8 @@ class FormLayouter {
1139
1957
  this._eventBus = eventBus;
1140
1958
  }
1141
1959
 
1142
- /**
1143
- * @param {FormRow} row
1960
+ /**
1961
+ * @param {FormRow} row
1144
1962
  */
1145
1963
  addRow(formFieldId, row) {
1146
1964
  let rowsPerComponent = this._rows.find(r => r.formFieldId === formFieldId);
@@ -1154,18 +1972,18 @@ class FormLayouter {
1154
1972
  rowsPerComponent.rows.push(row);
1155
1973
  }
1156
1974
 
1157
- /**
1158
- * @param {String} id
1159
- * @returns {FormRow}
1975
+ /**
1976
+ * @param {String} id
1977
+ * @returns {FormRow}
1160
1978
  */
1161
1979
  getRow(id) {
1162
1980
  const rows = allRows(this._rows);
1163
1981
  return rows.find(r => r.id === id);
1164
1982
  }
1165
1983
 
1166
- /**
1167
- * @param {any} formField
1168
- * @returns {FormRow}
1984
+ /**
1985
+ * @param {any} formField
1986
+ * @returns {FormRow}
1169
1987
  */
1170
1988
  getRowForField(formField) {
1171
1989
  return allRows(this._rows).find(r => {
@@ -1176,9 +1994,9 @@ class FormLayouter {
1176
1994
  });
1177
1995
  }
1178
1996
 
1179
- /**
1180
- * @param {String} formFieldId
1181
- * @returns { Array<FormRow> }
1997
+ /**
1998
+ * @param {String} formFieldId
1999
+ * @returns { Array<FormRow> }
1182
2000
  */
1183
2001
  getRows(formFieldId) {
1184
2002
  const rowsForField = this._rows.find(r => formFieldId === r.formFieldId);
@@ -1188,15 +2006,15 @@ class FormLayouter {
1188
2006
  return rowsForField.rows;
1189
2007
  }
1190
2008
 
1191
- /**
1192
- * @returns {string}
2009
+ /**
2010
+ * @returns {string}
1193
2011
  */
1194
2012
  nextRowId() {
1195
2013
  return this._ids.nextPrefixed('Row_');
1196
2014
  }
1197
2015
 
1198
- /**
1199
- * @param {any} formField
2016
+ /**
2017
+ * @param {any} formField
1200
2018
  */
1201
2019
  calculateLayout(formField) {
1202
2020
  const {
@@ -1232,224 +2050,38 @@ class FormLayouter {
1232
2050
  // fire event to notify interested parties
1233
2051
  this._eventBus.fire('form.layoutCleared');
1234
2052
  }
1235
- }
1236
- FormLayouter.$inject = ['eventBus'];
1237
-
1238
- // helpers //////
1239
-
1240
- function groupByRow(components, ids) {
1241
- return groupBy(components, c => {
1242
- // mitigate missing row by creating new (handle legacy)
1243
- const {
1244
- layout
1245
- } = c;
1246
- if (!layout || !layout.row) {
1247
- return ids.nextPrefixed('Row_');
1248
- }
1249
- return layout.row;
1250
- });
1251
- }
1252
-
1253
- /**
1254
- * @param {Array<FormRows>} formRows
1255
- * @returns {Array<FormRow>}
1256
- */
1257
- function allRows(formRows) {
1258
- return flatten(formRows.map(c => c.rows));
1259
- }
1260
-
1261
- // config ///////////////////
1262
-
1263
- const MINUTES_IN_DAY = 60 * 24;
1264
- const DATETIME_SUBTYPES = {
1265
- DATE: 'date',
1266
- TIME: 'time',
1267
- DATETIME: 'datetime'
1268
- };
1269
- const TIME_SERIALISING_FORMATS = {
1270
- UTC_OFFSET: 'utc_offset',
1271
- UTC_NORMALIZED: 'utc_normalized',
1272
- NO_TIMEZONE: 'no_timezone'
1273
- };
1274
- const DATETIME_SUBTYPES_LABELS = {
1275
- [DATETIME_SUBTYPES.DATE]: 'Date',
1276
- [DATETIME_SUBTYPES.TIME]: 'Time',
1277
- [DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
1278
- };
1279
- const TIME_SERIALISINGFORMAT_LABELS = {
1280
- [TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
1281
- [TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
1282
- [TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
1283
- };
1284
- const DATETIME_SUBTYPE_PATH = ['subtype'];
1285
- const DATE_LABEL_PATH = ['dateLabel'];
1286
- const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
1287
- const TIME_LABEL_PATH = ['timeLabel'];
1288
- const TIME_USE24H_PATH = ['use24h'];
1289
- const TIME_INTERVAL_PATH = ['timeInterval'];
1290
- const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
1291
-
1292
- // config ///////////////////
1293
-
1294
- const VALUES_SOURCES = {
1295
- STATIC: 'static',
1296
- INPUT: 'input'
1297
- };
1298
- const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
1299
- const VALUES_SOURCES_LABELS = {
1300
- [VALUES_SOURCES.STATIC]: 'Static',
1301
- [VALUES_SOURCES.INPUT]: 'Input data'
1302
- };
1303
- const VALUES_SOURCES_PATHS = {
1304
- [VALUES_SOURCES.STATIC]: ['values'],
1305
- [VALUES_SOURCES.INPUT]: ['valuesKey']
1306
- };
1307
- const VALUES_SOURCES_DEFAULTS = {
1308
- [VALUES_SOURCES.STATIC]: [{
1309
- label: 'Value',
1310
- value: 'value'
1311
- }],
1312
- [VALUES_SOURCES.INPUT]: ''
1313
- };
1314
-
1315
- // helpers ///////////////////
1316
-
1317
- function getValuesSource(field) {
1318
- for (const source of Object.values(VALUES_SOURCES)) {
1319
- if (get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
1320
- return source;
1321
- }
1322
- }
1323
- return VALUES_SOURCE_DEFAULT;
1324
- }
1325
-
1326
- function createInjector(bootstrapModules) {
1327
- const injector = new Injector(bootstrapModules);
1328
- injector.init();
1329
- return injector;
1330
- }
1331
-
1332
- /**
1333
- * @param {string?} prefix
1334
- *
1335
- * @returns Element
1336
- */
1337
- function createFormContainer(prefix = 'fjs') {
1338
- const container = document.createElement('div');
1339
- container.classList.add(`${prefix}-container`);
1340
- return container;
1341
- }
1342
-
1343
- const EXPRESSION_PROPERTIES = ['alt', 'description', 'label', 'source', 'readonly', 'text'];
1344
- const TEMPLATE_PROPERTIES = ['description', 'label', 'text'];
1345
- function findErrors(errors, path) {
1346
- return errors[pathStringify(path)];
1347
- }
1348
- function isRequired(field) {
1349
- return field.required;
1350
- }
1351
- function pathParse(path) {
1352
- if (!path) {
1353
- return [];
1354
- }
1355
- return path.split('.').map(key => {
1356
- return isNaN(parseInt(key)) ? key : parseInt(key);
1357
- });
1358
- }
1359
- function pathsEqual(a, b) {
1360
- return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
1361
- }
1362
- function pathStringify(path) {
1363
- if (!path) {
1364
- return '';
1365
- }
1366
- return path.join('.');
1367
- }
1368
- const indices = {};
1369
- function generateIndexForType(type) {
1370
- if (type in indices) {
1371
- indices[type]++;
1372
- } else {
1373
- indices[type] = 1;
1374
- }
1375
- return indices[type];
1376
- }
1377
- function generateIdForType(type) {
1378
- return `${type}${generateIndexForType(type)}`;
1379
- }
1380
-
1381
- /**
1382
- * @template T
1383
- * @param {T} data
1384
- * @param {(this: any, key: string, value: any) => any} [replacer]
1385
- * @return {T}
1386
- */
1387
- function clone(data, replacer) {
1388
- return JSON.parse(JSON.stringify(data, replacer));
1389
- }
1390
-
1391
- /**
1392
- * Parse the schema for input variables a form might make use of
1393
- *
1394
- * @param {any} schema
1395
- *
1396
- * @return {string[]}
1397
- */
1398
- function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLanguage(null), templating = new FeelersTemplating()) {
1399
- if (!schema.components) {
1400
- return [];
1401
- }
1402
- const variables = schema.components.reduce((variables, component) => {
1403
- const {
1404
- key,
1405
- valuesKey,
1406
- type,
1407
- conditional
1408
- } = component;
1409
- if (['button'].includes(type)) {
1410
- return variables;
1411
- }
1412
- if (key) {
1413
- variables = [...variables, key];
1414
- }
1415
- if (valuesKey) {
1416
- variables = [...variables, valuesKey];
1417
- }
1418
- if (conditional && conditional.hide) {
1419
- const conditionVariables = expressionLanguage.getVariableNames(conditional.hide, {
1420
- type: 'unaryTest'
1421
- });
1422
- variables = [...variables, ...conditionVariables];
2053
+ }
2054
+ FormLayouter.$inject = ['eventBus'];
2055
+
2056
+ // helpers //////
2057
+
2058
+ function groupByRow(components, ids) {
2059
+ return groupBy(components, c => {
2060
+ // mitigate missing row by creating new (handle legacy)
2061
+ const {
2062
+ layout
2063
+ } = c;
2064
+ if (!layout || !layout.row) {
2065
+ return ids.nextPrefixed('Row_');
1423
2066
  }
1424
- EXPRESSION_PROPERTIES.forEach(prop => {
1425
- const property = component[prop];
1426
- if (property && expressionLanguage.isExpression(property)) {
1427
- const expressionVariables = expressionLanguage.getVariableNames(property, {
1428
- type: 'expression'
1429
- });
1430
- variables = [...variables, ...expressionVariables];
1431
- }
1432
- });
1433
- TEMPLATE_PROPERTIES.forEach(prop => {
1434
- const property = component[prop];
1435
- if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
1436
- const templateVariables = templating.getVariableNames(property);
1437
- variables = [...variables, ...templateVariables];
1438
- }
1439
- });
1440
- return variables;
1441
- }, []);
2067
+ return layout.row;
2068
+ });
2069
+ }
1442
2070
 
1443
- // remove duplicates
1444
- return Array.from(new Set(variables));
2071
+ /**
2072
+ * @param {Array<FormRows>} formRows
2073
+ * @returns {Array<FormRow>}
2074
+ */
2075
+ function allRows(formRows) {
2076
+ return flatten(formRows.map(c => c.rows));
1445
2077
  }
1446
2078
 
1447
2079
  class Importer {
1448
- /**
1449
- * @constructor
1450
- * @param { import('../core').FormFieldRegistry } formFieldRegistry
1451
- * @param { import('../render/FormFields').default } formFields
1452
- * @param { import('../core').FormLayouter } formLayouter
2080
+ /**
2081
+ * @constructor
2082
+ * @param { import('../core').FormFieldRegistry } formFieldRegistry
2083
+ * @param { import('../render/FormFields').default } formFields
2084
+ * @param { import('../core').FormLayouter } formLayouter
1453
2085
  */
1454
2086
  constructor(formFieldRegistry, formFields, formLayouter) {
1455
2087
  this._formFieldRegistry = formFieldRegistry;
@@ -1457,15 +2089,15 @@ class Importer {
1457
2089
  this._formLayouter = formLayouter;
1458
2090
  }
1459
2091
 
1460
- /**
1461
- * Import schema adding `id`, `_parent` and `_path`
1462
- * information to each field and adding it to the
1463
- * form field registry.
1464
- *
1465
- * @param {any} schema
1466
- * @param {any} [data]
1467
- *
1468
- * @return { { warnings: Array<any>, schema: any, data: any } }
2092
+ /**
2093
+ * Import schema adding `id`, `_parent` and `_path`
2094
+ * information to each field and adding it to the
2095
+ * form field registry.
2096
+ *
2097
+ * @param {any} schema
2098
+ * @param {any} [data]
2099
+ *
2100
+ * @return { { warnings: Array<any>, schema: any, data: any } }
1469
2101
  */
1470
2102
  importSchema(schema, data = {}) {
1471
2103
  // TODO: Add warnings - https://github.com/bpmn-io/form-js/issues/289
@@ -1486,11 +2118,11 @@ class Importer {
1486
2118
  }
1487
2119
  }
1488
2120
 
1489
- /**
1490
- * @param {any} formField
1491
- * @param {string} [parentId]
1492
- *
1493
- * @return {any} importedField
2121
+ /**
2122
+ * @param {any} formField
2123
+ * @param {string} [parentId]
2124
+ *
2125
+ * @return {any} importedField
1494
2126
  */
1495
2127
  importFormField(formField, parentId) {
1496
2128
  const {
@@ -1541,10 +2173,10 @@ class Importer {
1541
2173
  });
1542
2174
  }
1543
2175
 
1544
- /**
1545
- * @param {Object} data
1546
- *
1547
- * @return {Object} initializedData
2176
+ /**
2177
+ * @param {Object} data
2178
+ *
2179
+ * @return {Object} initializedData
1548
2180
  */
1549
2181
  initializeFieldValues(data) {
1550
2182
  return this._formFieldRegistry.getAll().reduce((initializedData, formField) => {
@@ -1618,7 +2250,7 @@ function prefixId(id, formId) {
1618
2250
  return `fjs-form-${id}`;
1619
2251
  }
1620
2252
 
1621
- const type$b = 'button';
2253
+ const type$c = 'button';
1622
2254
  function Button(props) {
1623
2255
  const {
1624
2256
  disabled,
@@ -1628,7 +2260,7 @@ function Button(props) {
1628
2260
  action = 'submit'
1629
2261
  } = field;
1630
2262
  return jsx("div", {
1631
- class: formFieldClasses(type$b),
2263
+ class: formFieldClasses(type$c),
1632
2264
  children: jsx("button", {
1633
2265
  class: "fjs-button",
1634
2266
  type: action,
@@ -1638,7 +2270,7 @@ function Button(props) {
1638
2270
  });
1639
2271
  }
1640
2272
  Button.config = {
1641
- type: type$b,
2273
+ type: type$c,
1642
2274
  keyed: true,
1643
2275
  label: 'Button',
1644
2276
  group: 'action',
@@ -1682,11 +2314,11 @@ const FormRenderContext = createContext({
1682
2314
  });
1683
2315
  var FormRenderContext$1 = FormRenderContext;
1684
2316
 
1685
- /**
1686
- * @param {string} type
1687
- * @param {boolean} [strict]
1688
- *
1689
- * @returns {any}
2317
+ /**
2318
+ * @param {string} type
2319
+ * @param {boolean} [strict]
2320
+ *
2321
+ * @returns {any}
1690
2322
  */
1691
2323
  function getService(type, strict) {}
1692
2324
  const FormContext = createContext({
@@ -1702,10 +2334,10 @@ function useService(type, strict) {
1702
2334
  return getService(type, strict);
1703
2335
  }
1704
2336
 
1705
- /**
1706
- * Returns the conditionally filtered data of a form reactively.
1707
- * Memoised to minimize re-renders
1708
- *
2337
+ /**
2338
+ * Returns the conditionally filtered data of a form reactively.
2339
+ * Memoised to minimize re-renders
2340
+ *
1709
2341
  */
1710
2342
  function useFilteredFormData() {
1711
2343
  const {
@@ -1722,12 +2354,12 @@ function useFilteredFormData() {
1722
2354
  }, [conditionChecker, data, initialData]);
1723
2355
  }
1724
2356
 
1725
- /**
1726
- * Evaluate if condition is met reactively based on the conditionChecker and form data.
1727
- *
1728
- * @param {string | undefined} condition
1729
- *
1730
- * @returns {boolean} true if condition is met or no condition or condition checker exists
2357
+ /**
2358
+ * Evaluate if condition is met reactively based on the conditionChecker and form data.
2359
+ *
2360
+ * @param {string | undefined} condition
2361
+ *
2362
+ * @returns {boolean} true if condition is met or no condition or condition checker exists
1731
2363
  */
1732
2364
  function useCondition(condition) {
1733
2365
  const conditionChecker = useService('conditionChecker', false);
@@ -1737,13 +2369,13 @@ function useCondition(condition) {
1737
2369
  }, [conditionChecker, condition, filteredData]);
1738
2370
  }
1739
2371
 
1740
- /**
1741
- * Evaluate a string reactively based on the expressionLanguage and form data.
1742
- * If the string is not an expression, it is returned as is.
1743
- * Memoised to minimize re-renders.
1744
- *
1745
- * @param {string} value
1746
- *
2372
+ /**
2373
+ * Evaluate a string reactively based on the expressionLanguage and form data.
2374
+ * If the string is not an expression, it is returned as is.
2375
+ * Memoised to minimize re-renders.
2376
+ *
2377
+ * @param {string} value
2378
+ *
1747
2379
  */
1748
2380
  function useExpressionEvaluation(value) {
1749
2381
  const formData = useFilteredFormData();
@@ -1772,16 +2404,16 @@ function useKeyDownAction(targetKey, action, listenerElement = window) {
1772
2404
  });
1773
2405
  }
1774
2406
 
1775
- /**
1776
- * Retrieve readonly value of a form field, given it can be an
1777
- * expression optionally or configured globally.
1778
- *
1779
- * @typedef { import('../../types').FormProperties } FormProperties
1780
- *
1781
- * @param {any} formField
1782
- * @param {FormProperties} properties
1783
- *
1784
- * @returns {boolean}
2407
+ /**
2408
+ * Retrieve readonly value of a form field, given it can be an
2409
+ * expression optionally or configured globally.
2410
+ *
2411
+ * @typedef { import('../../types').FormProperties } FormProperties
2412
+ *
2413
+ * @param {any} formField
2414
+ * @param {FormProperties} properties
2415
+ *
2416
+ * @returns {boolean}
1785
2417
  */
1786
2418
  function useReadonly(formField, properties = {}) {
1787
2419
  const expressionLanguage = useService('expressionLanguage');
@@ -1799,16 +2431,16 @@ function useReadonly(formField, properties = {}) {
1799
2431
  return readonly || false;
1800
2432
  }
1801
2433
 
1802
- /**
1803
- * Template a string reactively based on form data. If the string is not a template, it is returned as is.
1804
- * Memoised to minimize re-renders
1805
- *
1806
- * @param {string} value
1807
- * @param {Object} options
1808
- * @param {boolean} [options.debug = false]
1809
- * @param {boolean} [options.strict = false]
1810
- * @param {Function} [options.buildDebugString]
1811
- *
2434
+ /**
2435
+ * Template a string reactively based on form data. If the string is not a template, it is returned as is.
2436
+ * Memoised to minimize re-renders
2437
+ *
2438
+ * @param {string} value
2439
+ * @param {Object} options
2440
+ * @param {boolean} [options.debug = false]
2441
+ * @param {boolean} [options.strict = false]
2442
+ * @param {Function} [options.buildDebugString]
2443
+ *
1812
2444
  */
1813
2445
  function useTemplateEvaluation(value, options) {
1814
2446
  const filteredData = useFilteredFormData();
@@ -1821,17 +2453,17 @@ function useTemplateEvaluation(value, options) {
1821
2453
  }, [filteredData, templating, value, options]);
1822
2454
  }
1823
2455
 
1824
- /**
1825
- * Template a string reactively based on form data. If the string is not a template, it is returned as is.
1826
- * If the string contains multiple lines, only the first line is returned.
1827
- * Memoised to minimize re-renders
1828
- *
1829
- * @param {string} value
1830
- * @param {Object} [options]
1831
- * @param {boolean} [options.debug = false]
1832
- * @param {boolean} [options.strict = false]
1833
- * @param {Function} [options.buildDebugString]
1834
- *
2456
+ /**
2457
+ * Template a string reactively based on form data. If the string is not a template, it is returned as is.
2458
+ * If the string contains multiple lines, only the first line is returned.
2459
+ * Memoised to minimize re-renders
2460
+ *
2461
+ * @param {string} value
2462
+ * @param {Object} [options]
2463
+ * @param {boolean} [options.debug = false]
2464
+ * @param {boolean} [options.strict = false]
2465
+ * @param {Function} [options.buildDebugString]
2466
+ *
1835
2467
  */
1836
2468
  function useSingleLineTemplateEvaluation(value, options = {}) {
1837
2469
  const evaluatedTemplate = useTemplateEvaluation(value, options);
@@ -1898,11 +2530,12 @@ function Label(props) {
1898
2530
  });
1899
2531
  }
1900
2532
 
1901
- const type$a = 'checkbox';
2533
+ const type$b = 'checkbox';
1902
2534
  function Checkbox(props) {
1903
2535
  const {
1904
2536
  disabled,
1905
2537
  errors = [],
2538
+ onBlur,
1906
2539
  field,
1907
2540
  readonly,
1908
2541
  value = false
@@ -1929,7 +2562,7 @@ function Checkbox(props) {
1929
2562
  } = useContext(FormContext$1);
1930
2563
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
1931
2564
  return jsxs("div", {
1932
- class: classNames(formFieldClasses(type$a, {
2565
+ class: classNames(formFieldClasses(type$b, {
1933
2566
  errors,
1934
2567
  disabled,
1935
2568
  readonly
@@ -1948,6 +2581,7 @@ function Checkbox(props) {
1948
2581
  id: prefixId(id, formId),
1949
2582
  type: "checkbox",
1950
2583
  onChange: onChange,
2584
+ onBlur: onBlur,
1951
2585
  "aria-describedby": errorMessageId
1952
2586
  })
1953
2587
  }), jsx(Description, {
@@ -1959,7 +2593,7 @@ function Checkbox(props) {
1959
2593
  });
1960
2594
  }
1961
2595
  Checkbox.config = {
1962
- type: type$a,
2596
+ type: type$b,
1963
2597
  keyed: true,
1964
2598
  label: 'Checkbox',
1965
2599
  group: 'selection',
@@ -2018,8 +2652,8 @@ function _isValueSomething(value) {
2018
2652
  return value || value === 0 || value === false;
2019
2653
  }
2020
2654
 
2021
- /**
2022
- * @enum { String }
2655
+ /**
2656
+ * @enum { String }
2023
2657
  */
2024
2658
  const LOAD_STATES = {
2025
2659
  LOADING: 'loading',
@@ -2027,20 +2661,21 @@ const LOAD_STATES = {
2027
2661
  ERROR: 'error'
2028
2662
  };
2029
2663
 
2030
- /**
2031
- * @typedef {Object} ValuesGetter
2032
- * @property {Object[]} values - The values data
2033
- * @property {(LOAD_STATES)} state - The values data's loading state, to use for conditional rendering
2664
+ /**
2665
+ * @typedef {Object} ValuesGetter
2666
+ * @property {Object[]} values - The values data
2667
+ * @property {(LOAD_STATES)} state - The values data's loading state, to use for conditional rendering
2034
2668
  */
2035
2669
 
2036
- /**
2037
- * A hook to load values for single and multiselect components.
2038
- *
2039
- * @param {Object} field - The form field to handle values for
2040
- * @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
2670
+ /**
2671
+ * A hook to load values for single and multiselect components.
2672
+ *
2673
+ * @param {Object} field - The form field to handle values for
2674
+ * @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
2041
2675
  */
2042
2676
  function useValuesAsync (field) {
2043
2677
  const {
2678
+ valuesExpression,
2044
2679
  valuesKey,
2045
2680
  values: staticValues
2046
2681
  } = field;
@@ -2050,6 +2685,11 @@ function useValuesAsync (field) {
2050
2685
  state: LOAD_STATES.LOADING
2051
2686
  });
2052
2687
  const initialData = useService('form')._getState().initialData;
2688
+ const evaluatedValues = useMemo(() => {
2689
+ if (valuesExpression) {
2690
+ return useExpressionEvaluation(valuesExpression);
2691
+ }
2692
+ }, [valuesExpression]);
2053
2693
  useEffect(() => {
2054
2694
  let values = [];
2055
2695
 
@@ -2059,11 +2699,14 @@ function useValuesAsync (field) {
2059
2699
  if (keyedValues && Array.isArray(keyedValues)) {
2060
2700
  values = keyedValues;
2061
2701
  }
2062
- }
2063
2702
 
2064
- // static values
2065
- else if (staticValues !== undefined) {
2703
+ // static values
2704
+ } else if (staticValues !== undefined) {
2066
2705
  values = Array.isArray(staticValues) ? staticValues : [];
2706
+
2707
+ // expression
2708
+ } else if (evaluatedValues && Array.isArray(evaluatedValues)) {
2709
+ values = evaluatedValues;
2067
2710
  } else {
2068
2711
  setValuesGetter(buildErrorState('No values source defined in the form definition'));
2069
2712
  return;
@@ -2293,11 +2936,12 @@ function sanitizeMultiSelectValue(options) {
2293
2936
  }
2294
2937
  }
2295
2938
 
2296
- const type$9 = 'checklist';
2939
+ const type$a = 'checklist';
2297
2940
  function Checklist(props) {
2298
2941
  const {
2299
2942
  disabled,
2300
2943
  errors = [],
2944
+ onBlur,
2301
2945
  field,
2302
2946
  readonly,
2303
2947
  value = []
@@ -2308,6 +2952,7 @@ function Checklist(props) {
2308
2952
  label,
2309
2953
  validate = {}
2310
2954
  } = field;
2955
+ const outerDivRef = useRef();
2311
2956
  const {
2312
2957
  required
2313
2958
  } = validate;
@@ -2323,6 +2968,12 @@ function Checklist(props) {
2323
2968
  value: newValue
2324
2969
  });
2325
2970
  };
2971
+ const onCheckboxBlur = e => {
2972
+ if (outerDivRef.current.contains(e.relatedTarget)) {
2973
+ return;
2974
+ }
2975
+ onBlur();
2976
+ };
2326
2977
  const {
2327
2978
  state: loadState,
2328
2979
  values: options
@@ -2332,11 +2983,12 @@ function Checklist(props) {
2332
2983
  } = useContext(FormContext$1);
2333
2984
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
2334
2985
  return jsxs("div", {
2335
- class: classNames(formFieldClasses(type$9, {
2986
+ class: classNames(formFieldClasses(type$a, {
2336
2987
  errors,
2337
2988
  disabled,
2338
2989
  readonly
2339
2990
  })),
2991
+ ref: outerDivRef,
2340
2992
  children: [jsx(Label, {
2341
2993
  label: label,
2342
2994
  required: required
@@ -2356,6 +3008,7 @@ function Checklist(props) {
2356
3008
  id: prefixId(`${id}-${index}`, formId),
2357
3009
  type: "checkbox",
2358
3010
  onClick: () => toggleCheckbox(v.value),
3011
+ onBlur: onCheckboxBlur,
2359
3012
  "aria-describedby": errorMessageId
2360
3013
  })
2361
3014
  }, `${id}-${index}`);
@@ -2368,7 +3021,7 @@ function Checklist(props) {
2368
3021
  });
2369
3022
  }
2370
3023
  Checklist.config = {
2371
- type: type$9,
3024
+ type: type$a,
2372
3025
  keyed: true,
2373
3026
  label: 'Checklist',
2374
3027
  group: 'selection',
@@ -2398,8 +3051,10 @@ function FormField(props) {
2398
3051
  onChange
2399
3052
  } = props;
2400
3053
  const formFields = useService('formFields'),
3054
+ viewerCommands = useService('viewerCommands', false),
2401
3055
  form = useService('form');
2402
3056
  const {
3057
+ initialData,
2403
3058
  data,
2404
3059
  errors,
2405
3060
  properties
@@ -2413,12 +3068,23 @@ function FormField(props) {
2413
3068
  if (!FormFieldComponent) {
2414
3069
  throw new Error(`cannot render field <${field.type}>`);
2415
3070
  }
3071
+ const initialValue = useMemo(() => get(initialData, field._path), [initialData, field._path]);
2416
3072
  const value = get(data, field._path);
2417
3073
  const fieldErrors = findErrors(errors, field._path);
2418
3074
  const readonly = useReadonly(field, properties);
2419
3075
 
2420
3076
  // add precedence: global readonly > form field disabled
2421
3077
  const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
3078
+ const onBlur = useCallback(() => {
3079
+ if (viewerCommands) {
3080
+ viewerCommands.updateFieldValidation(field, value);
3081
+ }
3082
+ }, [viewerCommands, field, value]);
3083
+ useEffect(() => {
3084
+ if (viewerCommands && initialValue) {
3085
+ viewerCommands.updateFieldValidation(field, initialValue);
3086
+ }
3087
+ }, [viewerCommands, field, initialValue]);
2422
3088
  const hidden = useCondition(field.conditional && field.conditional.hide || null);
2423
3089
  if (hidden) {
2424
3090
  return jsx(Empty, {});
@@ -2434,6 +3100,7 @@ function FormField(props) {
2434
3100
  disabled: disabled,
2435
3101
  errors: fieldErrors,
2436
3102
  onChange: disabled || readonly ? noop$1 : onChange,
3103
+ onBlur: disabled || readonly ? noop$1 : onBlur,
2437
3104
  readonly: readonly,
2438
3105
  value: value
2439
3106
  })
@@ -2496,22 +3163,23 @@ Default.config = {
2496
3163
  })
2497
3164
  };
2498
3165
 
2499
- function _extends$j() { _extends$j = Object.assign ? Object.assign.bind() : 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$j.apply(this, arguments); }
2500
- var CalendarIcon = (({
2501
- styles = {},
2502
- ...props
2503
- }) => /*#__PURE__*/React.createElement("svg", _extends$j({
2504
- width: "14",
2505
- height: "15",
2506
- viewBox: "0 0 28 30",
2507
- fill: "none",
2508
- xmlns: "http://www.w3.org/2000/svg"
2509
- }, props), /*#__PURE__*/React.createElement("path", {
2510
- fillRule: "evenodd",
2511
- clipRule: "evenodd",
2512
- fill: "currentColor",
2513
- d: "M19 2H9V0H7v2H2a2 2 0 00-2 2v24a2 2 0 002 2h24a2 2 0 002-2V4a2 2 0 00-2-2h-5V0h-2v2zM7 7V4H2v5h24V4h-5v3h-2V4H9v3H7zm-5 4v17h24V11H2z"
2514
- })));
3166
+ var _path$h;
3167
+ function _extends$k() { _extends$k = Object.assign ? Object.assign.bind() : 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$k.apply(this, arguments); }
3168
+ var SvgCalendar = function SvgCalendar(props) {
3169
+ return /*#__PURE__*/React.createElement("svg", _extends$k({
3170
+ xmlns: "http://www.w3.org/2000/svg",
3171
+ width: 14,
3172
+ height: 15,
3173
+ fill: "none",
3174
+ viewBox: "0 0 28 30"
3175
+ }, props), _path$h || (_path$h = /*#__PURE__*/React.createElement("path", {
3176
+ fill: "currentColor",
3177
+ fillRule: "evenodd",
3178
+ d: "M19 2H9V0H7v2H2a2 2 0 0 0-2 2v24a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2h-5V0h-2v2ZM7 7V4H2v5h24V4h-5v3h-2V4H9v3H7Zm-5 4v17h24V11H2Z",
3179
+ clipRule: "evenodd"
3180
+ })));
3181
+ };
3182
+ var CalendarIcon = SvgCalendar;
2515
3183
 
2516
3184
  function InputAdorner(props) {
2517
3185
  const {
@@ -2556,6 +3224,7 @@ function Datepicker(props) {
2556
3224
  id,
2557
3225
  label,
2558
3226
  collapseLabelOnEmpty,
3227
+ onDateTimeBlur,
2559
3228
  formId,
2560
3229
  required,
2561
3230
  disabled,
@@ -2650,7 +3319,8 @@ function Datepicker(props) {
2650
3319
  if (!isInputDirty || e.relatedTarget && e.relatedTarget.classList.contains('flatpickr-day')) return;
2651
3320
  dateInputRef.current.dispatchEvent(ENTER_KEYDOWN_EVENT);
2652
3321
  setIsInputDirty(false);
2653
- }, [isInputDirty]);
3322
+ onDateTimeBlur(e);
3323
+ }, [isInputDirty, onDateTimeBlur]);
2654
3324
  const fullId = `${prefixId(id, formId)}--date`;
2655
3325
  return jsxs("div", {
2656
3326
  class: "fjs-datetime-subsection",
@@ -2692,25 +3362,26 @@ function Datepicker(props) {
2692
3362
  });
2693
3363
  }
2694
3364
 
2695
- function _extends$i() { _extends$i = Object.assign ? Object.assign.bind() : 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$i.apply(this, arguments); }
2696
- var ClockIcon = (({
2697
- styles = {},
2698
- ...props
2699
- }) => /*#__PURE__*/React.createElement("svg", _extends$i({
2700
- width: "16",
2701
- height: "16",
2702
- viewBox: "0 0 28 29",
2703
- fill: "none",
2704
- xmlns: "http://www.w3.org/2000/svg"
2705
- }, props), /*#__PURE__*/React.createElement("path", {
2706
- fill: "currentColor",
2707
- d: "M13 14.41L18.59 20 20 18.59l-5-5.01V5h-2v9.41z"
2708
- }), /*#__PURE__*/React.createElement("path", {
2709
- fillRule: "evenodd",
2710
- clipRule: "evenodd",
2711
- fill: "currentColor",
2712
- d: "M6.222 25.64A14 14 0 1021.778 2.36 14 14 0 006.222 25.64zM7.333 4.023a12 12 0 1113.334 19.955A12 12 0 017.333 4.022z"
2713
- })));
3365
+ var _path$g, _path2$4;
3366
+ function _extends$j() { _extends$j = Object.assign ? Object.assign.bind() : 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$j.apply(this, arguments); }
3367
+ var SvgClock = function SvgClock(props) {
3368
+ return /*#__PURE__*/React.createElement("svg", _extends$j({
3369
+ xmlns: "http://www.w3.org/2000/svg",
3370
+ width: 16,
3371
+ height: 16,
3372
+ fill: "none",
3373
+ viewBox: "0 0 28 29"
3374
+ }, props), _path$g || (_path$g = /*#__PURE__*/React.createElement("path", {
3375
+ fill: "currentColor",
3376
+ d: "M13 14.41 18.59 20 20 18.59l-5-5.01V5h-2v9.41Z"
3377
+ })), _path2$4 || (_path2$4 = /*#__PURE__*/React.createElement("path", {
3378
+ fill: "currentColor",
3379
+ fillRule: "evenodd",
3380
+ d: "M6.222 25.64A14 14 0 1 0 21.778 2.36 14 14 0 0 0 6.222 25.64ZM7.333 4.023a12 12 0 1 1 13.334 19.955A12 12 0 0 1 7.333 4.022Z",
3381
+ clipRule: "evenodd"
3382
+ })));
3383
+ };
3384
+ var ClockIcon = SvgClock;
2714
3385
 
2715
3386
  const DEFAULT_LABEL_GETTER = value => value;
2716
3387
  const NOOP = () => {};
@@ -2812,6 +3483,7 @@ function Timepicker(props) {
2812
3483
  id,
2813
3484
  label,
2814
3485
  collapseLabelOnEmpty,
3486
+ onDateTimeBlur,
2815
3487
  formId,
2816
3488
  required,
2817
3489
  disabled,
@@ -2911,6 +3583,7 @@ function Timepicker(props) {
2911
3583
  const onInputBlur = e => {
2912
3584
  setDropdownIsOpen(false);
2913
3585
  propagateRawToMinute();
3586
+ onDateTimeBlur(e);
2914
3587
  };
2915
3588
  const onDropdownValueSelected = value => {
2916
3589
  setDropdownIsOpen(false);
@@ -2966,11 +3639,12 @@ function Timepicker(props) {
2966
3639
  });
2967
3640
  }
2968
3641
 
2969
- const type$8 = 'datetime';
3642
+ const type$9 = 'datetime';
2970
3643
  function Datetime(props) {
2971
3644
  const {
2972
3645
  disabled,
2973
3646
  errors = [],
3647
+ onBlur,
2974
3648
  field,
2975
3649
  onChange,
2976
3650
  readonly,
@@ -2994,6 +3668,7 @@ function Datetime(props) {
2994
3668
  const {
2995
3669
  formId
2996
3670
  } = useContext(FormContext$1);
3671
+ const dateTimeGroupRef = useRef();
2997
3672
  const getNullDateTime = () => ({
2998
3673
  date: new Date(Date.parse(null)),
2999
3674
  time: null
@@ -3004,6 +3679,12 @@ function Datetime(props) {
3004
3679
  const isValidTime = time => !isNaN(parseInt(time));
3005
3680
  const useDatePicker = useMemo(() => subtype === DATETIME_SUBTYPES.DATE || subtype === DATETIME_SUBTYPES.DATETIME, [subtype]);
3006
3681
  const useTimePicker = useMemo(() => subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME, [subtype]);
3682
+ const onDateTimeBlur = useCallback(e => {
3683
+ if (e.relatedTarget && dateTimeGroupRef.current.contains(e.relatedTarget)) {
3684
+ return;
3685
+ }
3686
+ onBlur();
3687
+ }, [onBlur]);
3007
3688
  useEffect(() => {
3008
3689
  let {
3009
3690
  date,
@@ -3095,6 +3776,7 @@ function Datetime(props) {
3095
3776
  id,
3096
3777
  label: dateLabel,
3097
3778
  collapseLabelOnEmpty: !timeLabel,
3779
+ onDateTimeBlur,
3098
3780
  formId,
3099
3781
  required,
3100
3782
  disabled,
@@ -3108,6 +3790,7 @@ function Datetime(props) {
3108
3790
  id,
3109
3791
  label: timeLabel,
3110
3792
  collapseLabelOnEmpty: !dateLabel,
3793
+ onDateTimeBlur,
3111
3794
  formId,
3112
3795
  required,
3113
3796
  disabled,
@@ -3119,13 +3802,14 @@ function Datetime(props) {
3119
3802
  'aria-describedby': errorMessageId
3120
3803
  };
3121
3804
  return jsxs("div", {
3122
- class: formFieldClasses(type$8, {
3805
+ class: formFieldClasses(type$9, {
3123
3806
  errors: allErrors,
3124
3807
  disabled,
3125
3808
  readonly
3126
3809
  }),
3127
3810
  children: [jsxs("div", {
3128
3811
  class: classNames('fjs-vertical-group'),
3812
+ ref: dateTimeGroupRef,
3129
3813
  children: [useDatePicker && jsx(Datepicker, {
3130
3814
  ...datePickerProps
3131
3815
  }), useTimePicker && useDatePicker && jsx("div", {
@@ -3142,7 +3826,7 @@ function Datetime(props) {
3142
3826
  });
3143
3827
  }
3144
3828
  Datetime.config = {
3145
- type: type$8,
3829
+ type: type$9,
3146
3830
  keyed: true,
3147
3831
  label: 'Date time',
3148
3832
  group: 'basic-input',
@@ -3159,10 +3843,10 @@ Datetime.config = {
3159
3843
  }
3160
3844
  };
3161
3845
 
3162
- /**
3163
- * This file must not be changed or exchanged.
3164
- *
3165
- * @see http://bpmn.io/license for more information.
3846
+ /**
3847
+ * This file must not be changed or exchanged.
3848
+ *
3849
+ * @see http://bpmn.io/license for more information.
3166
3850
  */
3167
3851
  function Logo() {
3168
3852
  return jsxs("svg", {
@@ -3294,11 +3978,11 @@ const ATTR_WHITESPACE_PATTERN = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u
3294
3978
 
3295
3979
  const FORM_ELEMENT = document.createElement('form');
3296
3980
 
3297
- /**
3298
- * Sanitize a HTML string and return the cleaned, safe version.
3299
- *
3300
- * @param {string} html
3301
- * @return {string}
3981
+ /**
3982
+ * Sanitize a HTML string and return the cleaned, safe version.
3983
+ *
3984
+ * @param {string} html
3985
+ * @return {string}
3302
3986
  */
3303
3987
 
3304
3988
  // see https://github.com/developit/snarkdown/issues/70
@@ -3316,29 +4000,29 @@ function sanitizeHTML(html) {
3316
4000
  }
3317
4001
  }
3318
4002
 
3319
- /**
3320
- * Sanitizes an image source to ensure we only allow for data URI and links
3321
- * that start with http(s).
3322
- *
3323
- * Note: Most browsers anyway do not support script execution in <img> elements.
3324
- *
3325
- * @param {string} src
3326
- * @returns {string}
4003
+ /**
4004
+ * Sanitizes an image source to ensure we only allow for data URI and links
4005
+ * that start with http(s).
4006
+ *
4007
+ * Note: Most browsers anyway do not support script execution in <img> elements.
4008
+ *
4009
+ * @param {string} src
4010
+ * @returns {string}
3327
4011
  */
3328
4012
  function sanitizeImageSource(src) {
3329
4013
  const valid = ALLOWED_IMAGE_SRC_PATTERN.test(src);
3330
4014
  return valid ? src : '';
3331
4015
  }
3332
4016
 
3333
- /**
3334
- * Recursively sanitize a HTML node, potentially
3335
- * removing it, its children or attributes.
3336
- *
3337
- * Inspired by https://github.com/developit/snarkdown/issues/70
3338
- * and https://github.com/cure53/DOMPurify. Simplified
3339
- * for our use-case.
3340
- *
3341
- * @param {Element} node
4017
+ /**
4018
+ * Recursively sanitize a HTML node, potentially
4019
+ * removing it, its children or attributes.
4020
+ *
4021
+ * Inspired by https://github.com/developit/snarkdown/issues/70
4022
+ * and https://github.com/cure53/DOMPurify. Simplified
4023
+ * for our use-case.
4024
+ *
4025
+ * @param {Element} node
3342
4026
  */
3343
4027
  function sanitizeNode(node) {
3344
4028
  // allow text nodes
@@ -3382,13 +4066,13 @@ function sanitizeNode(node) {
3382
4066
  }
3383
4067
  }
3384
4068
 
3385
- /**
3386
- * Validates attributes for validity.
3387
- *
3388
- * @param {string} lcTag
3389
- * @param {string} lcName
3390
- * @param {string} value
3391
- * @return {boolean}
4069
+ /**
4070
+ * Validates attributes for validity.
4071
+ *
4072
+ * @param {string} lcTag
4073
+ * @param {string} lcName
4074
+ * @param {string} value
4075
+ * @return {boolean}
3392
4076
  */
3393
4077
  function isValidAttribute(lcTag, lcName, value) {
3394
4078
  // disallow most attributes based on whitelist
@@ -3411,37 +4095,48 @@ function isValidAttribute(lcTag, lcName, value) {
3411
4095
  return true;
3412
4096
  }
3413
4097
 
3414
- function _extends$h() { _extends$h = Object.assign ? Object.assign.bind() : 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$h.apply(this, arguments); }
3415
- var ImagePlaceholder = (({
3416
- styles = {},
3417
- ...props
3418
- }) => /*#__PURE__*/React.createElement("svg", _extends$h({
3419
- width: "64",
3420
- height: "64",
3421
- viewBox: "0 0 1280 1280",
3422
- xmlns: "http://www.w3.org/2000/svg",
3423
- fillRule: "evenodd",
3424
- clipRule: "evenodd",
3425
- strokeLinejoin: "round",
3426
- strokeMiterlimit: "2"
3427
- }, props), /*#__PURE__*/React.createElement("path", {
3428
- fill: "#e5e9ed",
3429
- d: "M0 0h1280v1280H0z"
3430
- }), /*#__PURE__*/React.createElement("path", {
3431
- d: "M910 410H370v470h540V410zm-57.333 57.333v355.334H427.333V467.333h425.334z",
3432
- fill: "#cad3db"
3433
- }), /*#__PURE__*/React.createElement("path", {
3434
- d: "M810 770H480v-60l100-170 130 170 100-65v125z",
3435
- fill: "#cad3db"
3436
- }), /*#__PURE__*/React.createElement("circle", {
3437
- cx: "750",
3438
- cy: "550",
3439
- r: "50",
3440
- fill: "#cad3db",
3441
- transform: "translate(10 10)"
3442
- })));
3443
-
3444
- const type$7 = 'image';
4098
+ function _extends$i() { _extends$i = Object.assign ? Object.assign.bind() : 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$i.apply(this, arguments); }
4099
+ var SvgImagePlaceholder = function SvgImagePlaceholder(props) {
4100
+ return /*#__PURE__*/React.createElement("svg", _extends$i({
4101
+ xmlns: "http://www.w3.org/2000/svg",
4102
+ xmlSpace: "preserve",
4103
+ width: 64,
4104
+ height: 64,
4105
+ style: {
4106
+ fillRule: "evenodd",
4107
+ clipRule: "evenodd",
4108
+ strokeLinejoin: "round",
4109
+ strokeMiterlimit: 2
4110
+ },
4111
+ viewBox: "0 0 1280 1280"
4112
+ }, props), /*#__PURE__*/React.createElement("path", {
4113
+ d: "M0 0h1280v1280H0z",
4114
+ style: {
4115
+ fill: "#e5e9ed"
4116
+ }
4117
+ }), /*#__PURE__*/React.createElement("path", {
4118
+ d: "M910 410H370v470h540V410Zm-57.333 57.333v355.334H427.333V467.333h425.334Z",
4119
+ style: {
4120
+ fill: "#cad3db"
4121
+ }
4122
+ }), /*#__PURE__*/React.createElement("path", {
4123
+ d: "M810 770H480v-60l100-170 130 170 100-65v125Z",
4124
+ style: {
4125
+ fill: "#cad3db"
4126
+ }
4127
+ }), /*#__PURE__*/React.createElement("circle", {
4128
+ cx: 750,
4129
+ cy: 550,
4130
+ r: 50,
4131
+ style: {
4132
+ fill: "#cad3db"
4133
+ },
4134
+ transform: "translate(10 10)"
4135
+ }));
4136
+ };
4137
+ var ImagePlaceholder = SvgImagePlaceholder;
4138
+
4139
+ const type$8 = 'image';
3445
4140
  function Image(props) {
3446
4141
  const {
3447
4142
  field
@@ -3451,14 +4146,18 @@ function Image(props) {
3451
4146
  id,
3452
4147
  source
3453
4148
  } = field;
3454
- const evaluatedImageSource = useExpressionEvaluation(source);
4149
+ const evaluatedImageSource = useSingleLineTemplateEvaluation(source, {
4150
+ debug: true
4151
+ });
3455
4152
  const safeSource = useMemo(() => sanitizeImageSource(evaluatedImageSource), [evaluatedImageSource]);
3456
- const altText = useExpressionEvaluation(alt);
4153
+ const altText = useSingleLineTemplateEvaluation(alt, {
4154
+ debug: true
4155
+ });
3457
4156
  const {
3458
4157
  formId
3459
4158
  } = useContext(FormContext$1);
3460
4159
  return jsx("div", {
3461
- class: formFieldClasses(type$7),
4160
+ class: formFieldClasses(type$8),
3462
4161
  children: jsxs("div", {
3463
4162
  class: "fjs-image-container",
3464
4163
  children: [safeSource && jsx("img", {
@@ -3476,7 +4175,7 @@ function Image(props) {
3476
4175
  });
3477
4176
  }
3478
4177
  Image.config = {
3479
- type: type$7,
4178
+ type: type$8,
3480
4179
  keyed: false,
3481
4180
  label: 'Image view',
3482
4181
  group: 'presentation',
@@ -3485,45 +4184,66 @@ Image.config = {
3485
4184
  })
3486
4185
  };
3487
4186
 
4187
+ function TemplatedInputAdorner(props) {
4188
+ const {
4189
+ pre,
4190
+ post
4191
+ } = props;
4192
+ const evaluatedPre = useSingleLineTemplateEvaluation(pre, {
4193
+ debug: true
4194
+ });
4195
+ const evaluatedPost = useSingleLineTemplateEvaluation(post, {
4196
+ debug: true
4197
+ });
4198
+ return jsx(InputAdorner, {
4199
+ ...props,
4200
+ pre: evaluatedPre,
4201
+ post: evaluatedPost
4202
+ });
4203
+ }
4204
+
4205
+ var _path$f;
4206
+ function _extends$h() { _extends$h = Object.assign ? Object.assign.bind() : 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$h.apply(this, arguments); }
4207
+ var SvgAngelDown = function SvgAngelDown(props) {
4208
+ return /*#__PURE__*/React.createElement("svg", _extends$h({
4209
+ xmlns: "http://www.w3.org/2000/svg",
4210
+ width: 8,
4211
+ height: 8
4212
+ }, props), _path$f || (_path$f = /*#__PURE__*/React.createElement("path", {
4213
+ fill: "currentColor",
4214
+ fillRule: "evenodd",
4215
+ stroke: "currentColor",
4216
+ strokeWidth: 0.5,
4217
+ d: "M7.75 1.336 4 6.125.258 1.335 0 1.54l4 5.125L8 1.54Zm0 0",
4218
+ clipRule: "evenodd"
4219
+ })));
4220
+ };
4221
+ var AngelDownIcon = SvgAngelDown;
4222
+
4223
+ var _path$e;
3488
4224
  function _extends$g() { _extends$g = Object.assign ? Object.assign.bind() : 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$g.apply(this, arguments); }
3489
- var AngelDownIcon = (({
3490
- styles = {},
3491
- ...props
3492
- }) => /*#__PURE__*/React.createElement("svg", _extends$g({
3493
- xmlns: "http://www.w3.org/2000/svg",
3494
- width: "8",
3495
- height: "8"
3496
- }, props), /*#__PURE__*/React.createElement("path", {
3497
- fillRule: "evenodd",
3498
- clipRule: "evenodd",
3499
- fill: "currentColor",
3500
- stroke: "currentColor",
3501
- strokeWidth: ".5",
3502
- d: "M7.75 1.336L4 6.125.258 1.335 0 1.54l4 5.125L8 1.54zm0 0"
3503
- })));
4225
+ var SvgAngelUp = function SvgAngelUp(props) {
4226
+ return /*#__PURE__*/React.createElement("svg", _extends$g({
4227
+ xmlns: "http://www.w3.org/2000/svg",
4228
+ width: 8,
4229
+ height: 8
4230
+ }, props), _path$e || (_path$e = /*#__PURE__*/React.createElement("path", {
4231
+ fill: "currentColor",
4232
+ fillRule: "evenodd",
4233
+ stroke: "currentColor",
4234
+ strokeWidth: 0.5,
4235
+ d: "M7.75 6.664 4 1.875.258 6.665 0 6.46l4-5.125L8 6.46Zm0 0",
4236
+ clipRule: "evenodd"
4237
+ })));
4238
+ };
4239
+ var AngelUpIcon = SvgAngelUp;
3504
4240
 
3505
- function _extends$f() { _extends$f = Object.assign ? Object.assign.bind() : 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$f.apply(this, arguments); }
3506
- var AngelUpIcon = (({
3507
- styles = {},
3508
- ...props
3509
- }) => /*#__PURE__*/React.createElement("svg", _extends$f({
3510
- xmlns: "http://www.w3.org/2000/svg",
3511
- width: "8",
3512
- height: "8"
3513
- }, props), /*#__PURE__*/React.createElement("path", {
3514
- fillRule: "evenodd",
3515
- clipRule: "evenodd",
3516
- fill: "currentColor",
3517
- stroke: "currentColor",
3518
- strokeWidth: ".5",
3519
- d: "M7.75 6.664L4 1.875.258 6.665 0 6.46l4-5.125L8 6.46zm0 0"
3520
- })));
3521
-
3522
- const type$6 = 'number';
4241
+ const type$7 = 'number';
3523
4242
  function Numberfield(props) {
3524
4243
  const {
3525
4244
  disabled,
3526
4245
  errors = [],
4246
+ onBlur,
3527
4247
  field,
3528
4248
  value,
3529
4249
  readonly,
@@ -3656,7 +4376,7 @@ function Numberfield(props) {
3656
4376
  } = useContext(FormContext$1);
3657
4377
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3658
4378
  return jsxs("div", {
3659
- class: formFieldClasses(type$6, {
4379
+ class: formFieldClasses(type$7, {
3660
4380
  errors,
3661
4381
  disabled,
3662
4382
  readonly
@@ -3665,7 +4385,7 @@ function Numberfield(props) {
3665
4385
  id: prefixId(id, formId),
3666
4386
  label: label,
3667
4387
  required: required
3668
- }), jsx(InputAdorner, {
4388
+ }), jsx(TemplatedInputAdorner, {
3669
4389
  disabled: disabled,
3670
4390
  readonly: readonly,
3671
4391
  pre: prefixAdorner,
@@ -3684,7 +4404,8 @@ function Numberfield(props) {
3684
4404
  readOnly: readonly,
3685
4405
  id: prefixId(id, formId),
3686
4406
  onKeyDown: onKeyDown,
3687
- onKeyPress: onKeyPress
4407
+ onKeyPress: onKeyPress,
4408
+ onBlur: onBlur
3688
4409
 
3689
4410
  // @ts-ignore
3690
4411
  ,
@@ -3727,7 +4448,7 @@ function Numberfield(props) {
3727
4448
  });
3728
4449
  }
3729
4450
  Numberfield.config = {
3730
- type: type$6,
4451
+ type: type$7,
3731
4452
  keyed: true,
3732
4453
  label: 'Number',
3733
4454
  group: 'basic-input',
@@ -3750,11 +4471,12 @@ Numberfield.config = {
3750
4471
  })
3751
4472
  };
3752
4473
 
3753
- const type$5 = 'radio';
4474
+ const type$6 = 'radio';
3754
4475
  function Radio(props) {
3755
4476
  const {
3756
4477
  disabled,
3757
4478
  errors = [],
4479
+ onBlur,
3758
4480
  field,
3759
4481
  readonly,
3760
4482
  value
@@ -3765,6 +4487,7 @@ function Radio(props) {
3765
4487
  label,
3766
4488
  validate = {}
3767
4489
  } = field;
4490
+ const outerDivRef = useRef();
3768
4491
  const {
3769
4492
  required
3770
4493
  } = validate;
@@ -3774,6 +4497,12 @@ function Radio(props) {
3774
4497
  value: v
3775
4498
  });
3776
4499
  };
4500
+ const onRadioBlur = e => {
4501
+ if (outerDivRef.current.contains(e.relatedTarget)) {
4502
+ return;
4503
+ }
4504
+ onBlur();
4505
+ };
3777
4506
  const {
3778
4507
  state: loadState,
3779
4508
  values: options
@@ -3783,11 +4512,12 @@ function Radio(props) {
3783
4512
  } = useContext(FormContext$1);
3784
4513
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3785
4514
  return jsxs("div", {
3786
- class: formFieldClasses(type$5, {
4515
+ class: formFieldClasses(type$6, {
3787
4516
  errors,
3788
4517
  disabled,
3789
4518
  readonly
3790
4519
  }),
4520
+ ref: outerDivRef,
3791
4521
  children: [jsx(Label, {
3792
4522
  label: label,
3793
4523
  required: required
@@ -3807,6 +4537,7 @@ function Radio(props) {
3807
4537
  id: prefixId(`${id}-${index}`, formId),
3808
4538
  type: "radio",
3809
4539
  onClick: () => onChange(option.value),
4540
+ onBlur: onRadioBlur,
3810
4541
  "aria-describedby": errorMessageId
3811
4542
  })
3812
4543
  }, `${id}-${index}`);
@@ -3819,7 +4550,7 @@ function Radio(props) {
3819
4550
  });
3820
4551
  }
3821
4552
  Radio.config = {
3822
- type: type$5,
4553
+ type: type$6,
3823
4554
  keyed: true,
3824
4555
  label: 'Radio',
3825
4556
  group: 'selection',
@@ -3842,28 +4573,30 @@ Radio.config = {
3842
4573
  }
3843
4574
  };
3844
4575
 
3845
- function _extends$e() { _extends$e = Object.assign ? Object.assign.bind() : 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$e.apply(this, arguments); }
3846
- var XMarkIcon = (({
3847
- styles = {},
3848
- ...props
3849
- }) => /*#__PURE__*/React.createElement("svg", _extends$e({
3850
- xmlns: "http://www.w3.org/2000/svg",
3851
- width: "8",
3852
- height: "8"
3853
- }, props), /*#__PURE__*/React.createElement("path", {
3854
- fillRule: "evenodd",
3855
- clipRule: "evenodd",
3856
- fill: "currentColor",
3857
- stroke: "currentColor",
3858
- strokeWidth: ".5",
3859
- d: "M4 3.766L7.43.336l.234.234L4.234 4l3.43 3.43-.234.234L4 4.234.57 7.664.336 7.43 3.766 4 .336.57.57.336zm0 0"
3860
- })));
4576
+ var _path$d;
4577
+ function _extends$f() { _extends$f = Object.assign ? Object.assign.bind() : 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$f.apply(this, arguments); }
4578
+ var SvgXMark = function SvgXMark(props) {
4579
+ return /*#__PURE__*/React.createElement("svg", _extends$f({
4580
+ xmlns: "http://www.w3.org/2000/svg",
4581
+ width: 8,
4582
+ height: 8
4583
+ }, props), _path$d || (_path$d = /*#__PURE__*/React.createElement("path", {
4584
+ fill: "currentColor",
4585
+ fillRule: "evenodd",
4586
+ stroke: "currentColor",
4587
+ strokeWidth: 0.5,
4588
+ d: "M4 3.766 7.43.336l.234.234L4.234 4l3.43 3.43-.234.234L4 4.234.57 7.664.336 7.43 3.766 4 .336.57.57.336Zm0 0",
4589
+ clipRule: "evenodd"
4590
+ })));
4591
+ };
4592
+ var XMarkIcon = SvgXMark;
3861
4593
 
3862
4594
  function SearchableSelect(props) {
3863
4595
  const {
3864
4596
  id,
3865
4597
  disabled,
3866
4598
  errors,
4599
+ onBlur,
3867
4600
  field,
3868
4601
  readonly,
3869
4602
  value
@@ -3983,6 +4716,7 @@ function SearchableSelect(props) {
3983
4716
  onBlur: () => {
3984
4717
  setIsDropdownExpanded(false);
3985
4718
  setFilter(valueLabel);
4719
+ onBlur();
3986
4720
  },
3987
4721
  "aria-describedby": props['aria-describedby']
3988
4722
  }), displayState.displayCross && jsxs("span", {
@@ -4017,6 +4751,7 @@ function SimpleSelect(props) {
4017
4751
  id,
4018
4752
  disabled,
4019
4753
  errors,
4754
+ onBlur,
4020
4755
  field,
4021
4756
  readonly,
4022
4757
  value
@@ -4071,7 +4806,10 @@ function SimpleSelect(props) {
4071
4806
  'hasErrors': errors.length
4072
4807
  }),
4073
4808
  onFocus: () => setIsDropdownExpanded(true),
4074
- onBlur: () => setIsDropdownExpanded(false),
4809
+ onBlur: () => {
4810
+ setIsDropdownExpanded(false);
4811
+ onBlur();
4812
+ },
4075
4813
  onMouseDown: onMouseDown,
4076
4814
  children: [jsx("div", {
4077
4815
  class: classNames('fjs-select-display', {
@@ -4113,11 +4851,12 @@ function SimpleSelect(props) {
4113
4851
  });
4114
4852
  }
4115
4853
 
4116
- const type$4 = 'select';
4854
+ const type$5 = 'select';
4117
4855
  function Select(props) {
4118
4856
  const {
4119
4857
  disabled,
4120
4858
  errors = [],
4859
+ onBlur,
4121
4860
  field,
4122
4861
  onChange,
4123
4862
  readonly,
@@ -4141,14 +4880,15 @@ function Select(props) {
4141
4880
  id,
4142
4881
  disabled,
4143
4882
  errors,
4883
+ onBlur,
4144
4884
  field,
4145
4885
  value,
4146
4886
  onChange,
4147
4887
  readonly,
4148
4888
  'aria-describedby': errorMessageId
4149
- }), [disabled, errors, field, id, value, onChange, readonly, errorMessageId]);
4889
+ }), [disabled, errors, field, id, value, onChange, onBlur, readonly, errorMessageId]);
4150
4890
  return jsxs("div", {
4151
- class: formFieldClasses(type$4, {
4891
+ class: formFieldClasses(type$5, {
4152
4892
  errors,
4153
4893
  disabled,
4154
4894
  readonly
@@ -4176,7 +4916,7 @@ function Select(props) {
4176
4916
  });
4177
4917
  }
4178
4918
  Select.config = {
4179
- type: type$4,
4919
+ type: type$5,
4180
4920
  keyed: true,
4181
4921
  label: 'Select',
4182
4922
  group: 'selection',
@@ -4199,11 +4939,38 @@ Select.config = {
4199
4939
  }
4200
4940
  };
4201
4941
 
4942
+ const type$4 = 'spacer';
4943
+ function Spacer(props) {
4944
+ const {
4945
+ field
4946
+ } = props;
4947
+ const {
4948
+ height = 60
4949
+ } = field;
4950
+ return jsx("div", {
4951
+ class: formFieldClasses(type$4),
4952
+ style: {
4953
+ height: height
4954
+ }
4955
+ });
4956
+ }
4957
+ Spacer.config = {
4958
+ type: type$4,
4959
+ keyed: false,
4960
+ label: 'Spacer',
4961
+ group: 'presentation',
4962
+ create: (options = {}) => ({
4963
+ height: 60,
4964
+ ...options
4965
+ })
4966
+ };
4967
+
4202
4968
  const type$3 = 'taglist';
4203
4969
  function Taglist(props) {
4204
4970
  const {
4205
4971
  disabled,
4206
4972
  errors = [],
4973
+ onBlur,
4207
4974
  field,
4208
4975
  readonly,
4209
4976
  value: values = []
@@ -4296,9 +5063,10 @@ function Taglist(props) {
4296
5063
  break;
4297
5064
  }
4298
5065
  };
4299
- const onBlur = () => {
5066
+ const onComponentBlur = () => {
4300
5067
  setIsDropdownExpanded(false);
4301
5068
  setFilter('');
5069
+ onBlur();
4302
5070
  };
4303
5071
  const onTagRemoveClick = (event, value) => {
4304
5072
  const {
@@ -4369,9 +5137,7 @@ function Taglist(props) {
4369
5137
  onKeyDown: onInputKeyDown,
4370
5138
  onMouseDown: () => setIsEscapeClose(false),
4371
5139
  onFocus: () => !readonly && setIsDropdownExpanded(true),
4372
- onBlur: () => {
4373
- !readonly && onBlur();
4374
- },
5140
+ onBlur: () => !readonly && onComponentBlur(),
4375
5141
  "aria-describedby": errorMessageId
4376
5142
  })]
4377
5143
  }), jsx("div", {
@@ -4504,6 +5270,7 @@ function Textfield(props) {
4504
5270
  const {
4505
5271
  disabled,
4506
5272
  errors = [],
5273
+ onBlur,
4507
5274
  field,
4508
5275
  readonly,
4509
5276
  value = ''
@@ -4544,7 +5311,7 @@ function Textfield(props) {
4544
5311
  id: prefixId(id, formId),
4545
5312
  label: label,
4546
5313
  required: required
4547
- }), jsx(InputAdorner, {
5314
+ }), jsx(TemplatedInputAdorner, {
4548
5315
  disabled: disabled,
4549
5316
  readonly: readonly,
4550
5317
  pre: prefixAdorner,
@@ -4555,6 +5322,7 @@ function Textfield(props) {
4555
5322
  readOnly: readonly,
4556
5323
  id: prefixId(id, formId),
4557
5324
  onInput: onChange,
5325
+ onBlur: onBlur,
4558
5326
  type: "text",
4559
5327
  value: value,
4560
5328
  "aria-describedby": errorMessageId
@@ -4596,6 +5364,7 @@ function Textarea(props) {
4596
5364
  const {
4597
5365
  disabled,
4598
5366
  errors = [],
5367
+ onBlur,
4599
5368
  field,
4600
5369
  readonly,
4601
5370
  value = ''
@@ -4618,22 +5387,12 @@ function Textarea(props) {
4618
5387
  value: target.value
4619
5388
  });
4620
5389
  };
4621
- const autoSizeTextarea = useCallback(textarea => {
4622
- // Ensures the textarea shrinks back, and improves resizing behavior consistency
4623
- textarea.style.height = '0px';
4624
- const computed = window.getComputedStyle(textarea);
4625
- const calculatedHeight = parseInt(computed.getPropertyValue('border-top-width')) + parseInt(computed.getPropertyValue('padding-top')) + textarea.scrollHeight + parseInt(computed.getPropertyValue('padding-bottom')) + parseInt(computed.getPropertyValue('border-bottom-width'));
4626
- const minHeight = 75;
4627
- const maxHeight = 350;
4628
- const displayHeight = Math.max(Math.min(calculatedHeight, maxHeight), minHeight);
4629
- textarea.style.height = `${displayHeight}px`;
4630
-
4631
- // Overflow is hidden by default to hide scrollbar flickering
4632
- textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
4633
- }, []);
5390
+ useLayoutEffect(() => {
5391
+ autoSizeTextarea(textareaRef.current);
5392
+ }, [value]);
4634
5393
  useEffect(() => {
4635
5394
  autoSizeTextarea(textareaRef.current);
4636
- }, [autoSizeTextarea, value]);
5395
+ }, []);
4637
5396
  const {
4638
5397
  formId
4639
5398
  } = useContext(FormContext$1);
@@ -4654,6 +5413,7 @@ function Textarea(props) {
4654
5413
  readonly: readonly,
4655
5414
  id: prefixId(id, formId),
4656
5415
  onInput: onInput,
5416
+ onBlur: onBlur,
4657
5417
  value: value,
4658
5418
  ref: textareaRef,
4659
5419
  "aria-describedby": errorMessageId
@@ -4678,246 +5438,301 @@ Textarea.config = {
4678
5438
  ...options
4679
5439
  })
4680
5440
  };
5441
+ const autoSizeTextarea = textarea => {
5442
+ // Ensures the textarea shrinks back, and improves resizing behavior consistency
5443
+ textarea.style.height = '0px';
5444
+ const computed = window.getComputedStyle(textarea);
5445
+ const heightFromLines = () => {
5446
+ const lineHeight = parseInt(computed.getPropertyValue('line-height').replace('px', '')) || 0;
5447
+ const lines = textarea.value ? textarea.value.toString().split('\n').length : 0;
5448
+ return lines * lineHeight;
5449
+ };
5450
+ const calculatedHeight = parseInt(computed.getPropertyValue('border-top-width')) + parseInt(computed.getPropertyValue('padding-top')) + (textarea.scrollHeight || heightFromLines()) + parseInt(computed.getPropertyValue('padding-bottom')) + parseInt(computed.getPropertyValue('border-bottom-width'));
5451
+ const minHeight = 75;
5452
+ const maxHeight = 350;
5453
+ const displayHeight = Math.max(Math.min(calculatedHeight || 0, maxHeight), minHeight);
5454
+ textarea.style.height = `${displayHeight}px`;
5455
+
5456
+ // Overflow is hidden by default to hide scrollbar flickering
5457
+ textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
5458
+ };
4681
5459
 
5460
+ var _path$c;
5461
+ function _extends$e() { _extends$e = Object.assign ? Object.assign.bind() : 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$e.apply(this, arguments); }
5462
+ var SvgButton = function SvgButton(props) {
5463
+ return /*#__PURE__*/React.createElement("svg", _extends$e({
5464
+ xmlns: "http://www.w3.org/2000/svg",
5465
+ width: 54,
5466
+ height: 54,
5467
+ fill: "currentcolor"
5468
+ }, props), _path$c || (_path$c = /*#__PURE__*/React.createElement("path", {
5469
+ fillRule: "evenodd",
5470
+ d: "M45 17a3 3 0 0 1 3 3v14a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V20a3 3 0 0 1 3-3h36zm-9 8.889H18v2.222h18v-2.222z"
5471
+ })));
5472
+ };
5473
+ var ButtonIcon = SvgButton;
5474
+
5475
+ var _path$b;
4682
5476
  function _extends$d() { _extends$d = Object.assign ? Object.assign.bind() : 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$d.apply(this, arguments); }
4683
- var ButtonIcon = (({
4684
- styles = {},
4685
- ...props
4686
- }) => /*#__PURE__*/React.createElement("svg", _extends$d({
4687
- xmlns: "http://www.w3.org/2000/svg",
4688
- width: "54",
4689
- height: "54",
4690
- fill: "currentcolor"
4691
- }, props), /*#__PURE__*/React.createElement("path", {
4692
- fillRule: "evenodd",
4693
- d: "M45 17a3 3 0 013 3v14a3 3 0 01-3 3H9a3 3 0 01-3-3V20a3 3 0 013-3h36zm-9 8.889H18v2.222h18v-2.222z"
4694
- })));
5477
+ var SvgCheckbox = function SvgCheckbox(props) {
5478
+ return /*#__PURE__*/React.createElement("svg", _extends$d({
5479
+ xmlns: "http://www.w3.org/2000/svg",
5480
+ width: 54,
5481
+ height: 54,
5482
+ fill: "currentcolor"
5483
+ }, props), _path$b || (_path$b = /*#__PURE__*/React.createElement("path", {
5484
+ d: "M34 18H20a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V20a2 2 0 0 0-2-2zm-9 14-5-5 1.41-1.41L25 29.17l7.59-7.59L34 23l-9 9z"
5485
+ })));
5486
+ };
5487
+ var CheckboxIcon = SvgCheckbox;
4695
5488
 
5489
+ var _g, _use, _use2, _use3, _defs;
4696
5490
  function _extends$c() { _extends$c = Object.assign ? Object.assign.bind() : 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$c.apply(this, arguments); }
4697
- var CheckboxIcon = (({
4698
- styles = {},
4699
- ...props
4700
- }) => /*#__PURE__*/React.createElement("svg", _extends$c({
4701
- xmlns: "http://www.w3.org/2000/svg",
4702
- width: "54",
4703
- height: "54",
4704
- fill: "currentcolor"
4705
- }, props), /*#__PURE__*/React.createElement("path", {
4706
- d: "M34 18H20a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V20a2 2 0 00-2-2zm-9 14l-5-5 1.41-1.41L25 29.17l7.59-7.59L34 23l-9 9z"
4707
- })));
5491
+ var SvgChecklist = function SvgChecklist(props) {
5492
+ return /*#__PURE__*/React.createElement("svg", _extends$c({
5493
+ xmlns: "http://www.w3.org/2000/svg",
5494
+ xmlnsXlink: "http://www.w3.org/1999/xlink",
5495
+ width: 54,
5496
+ height: 54,
5497
+ fill: "currentcolor"
5498
+ }, props), _g || (_g = /*#__PURE__*/React.createElement("g", {
5499
+ fillRule: "evenodd"
5500
+ }, /*#__PURE__*/React.createElement("use", {
5501
+ xlinkHref: "#Checklist_svg__a"
5502
+ }), /*#__PURE__*/React.createElement("use", {
5503
+ xlinkHref: "#Checklist_svg__a",
5504
+ y: 24
5505
+ }), /*#__PURE__*/React.createElement("use", {
5506
+ xlinkHref: "#Checklist_svg__a",
5507
+ y: 12
5508
+ }))), _use || (_use = /*#__PURE__*/React.createElement("use", {
5509
+ xlinkHref: "#Checklist_svg__b"
5510
+ })), _use2 || (_use2 = /*#__PURE__*/React.createElement("use", {
5511
+ xlinkHref: "#Checklist_svg__b",
5512
+ y: 12
5513
+ })), _use3 || (_use3 = /*#__PURE__*/React.createElement("use", {
5514
+ xlinkHref: "#Checklist_svg__b",
5515
+ y: 24
5516
+ })), _defs || (_defs = /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
5517
+ id: "Checklist_svg__a",
5518
+ d: "M18 12h-6v6h6v-6zm-6-2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2h-6z"
5519
+ }), /*#__PURE__*/React.createElement("path", {
5520
+ id: "Checklist_svg__b",
5521
+ d: "M23 14.5a1 1 0 0 1 1-1h19a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H24a1 1 0 0 1-1-1v-1z"
5522
+ }))));
5523
+ };
5524
+ var ChecklistIcon = SvgChecklist;
4708
5525
 
5526
+ var _path$a, _path2$3, _path3;
4709
5527
  function _extends$b() { _extends$b = Object.assign ? Object.assign.bind() : 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$b.apply(this, arguments); }
4710
- var ChecklistIcon = (({
4711
- styles = {},
4712
- ...props
4713
- }) => /*#__PURE__*/React.createElement("svg", _extends$b({
4714
- xmlns: "http://www.w3.org/2000/svg",
4715
- xmlnsXlink: "http://www.w3.org/1999/xlink",
4716
- width: "54",
4717
- height: "54",
4718
- fill: "currentcolor"
4719
- }, props), /*#__PURE__*/React.createElement("g", {
4720
- fillRule: "evenodd"
4721
- }, /*#__PURE__*/React.createElement("use", {
4722
- xlinkHref: "#a"
4723
- }), /*#__PURE__*/React.createElement("use", {
4724
- xlinkHref: "#a",
4725
- y: "24"
4726
- }), /*#__PURE__*/React.createElement("use", {
4727
- xlinkHref: "#a",
4728
- y: "12"
4729
- })), /*#__PURE__*/React.createElement("use", {
4730
- xlinkHref: "#b"
4731
- }), /*#__PURE__*/React.createElement("use", {
4732
- xlinkHref: "#b",
4733
- y: "12"
4734
- }), /*#__PURE__*/React.createElement("use", {
4735
- xlinkHref: "#b",
4736
- y: "24"
4737
- }), /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("path", {
4738
- id: "a",
4739
- d: "M18 12h-6v6h6v-6zm-6-2a2 2 0 00-2 2v6a2 2 0 002 2h6a2 2 0 002-2v-6a2 2 0 00-2-2h-6z"
4740
- }), /*#__PURE__*/React.createElement("path", {
4741
- id: "b",
4742
- d: "M23 14.5a1 1 0 011-1h19a1 1 0 011 1v1a1 1 0 01-1 1H24a1 1 0 01-1-1v-1z"
4743
- }))));
5528
+ var SvgDatetime = function SvgDatetime(props) {
5529
+ return /*#__PURE__*/React.createElement("svg", _extends$b({
5530
+ xmlns: "http://www.w3.org/2000/svg",
5531
+ width: 54,
5532
+ height: 54,
5533
+ fill: "currentcolor"
5534
+ }, props), _path$a || (_path$a = /*#__PURE__*/React.createElement("path", {
5535
+ fillRule: "evenodd",
5536
+ d: "M37.908 13.418h-5.004v-2.354h-1.766v2.354H21.13v-2.354h-1.766v2.354H14.36a2.07 2.07 0 0 0-2.06 2.06v23.549a2.07 2.07 0 0 0 2.06 2.06h6.77v-1.766h-6.358a.707.707 0 0 1-.706-.706V15.89c0-.39.316-.707.706-.707h4.592v2.355h1.766v-2.355h10.008v2.355h1.766v-2.355h4.592a.71.71 0 0 1 .707.707v6.358h1.765v-6.77c0-1.133-.927-2.06-2.06-2.06z"
5537
+ })), _path2$3 || (_path2$3 = /*#__PURE__*/React.createElement("path", {
5538
+ d: "m35.13 37.603 1.237-1.237-3.468-3.475v-5.926h-1.754v6.654l3.984 3.984Z"
5539
+ })), _path3 || (_path3 = /*#__PURE__*/React.createElement("path", {
5540
+ fillRule: "evenodd",
5541
+ d: "M23.08 36.962a9.678 9.678 0 1 0 17.883-7.408 9.678 9.678 0 0 0-17.882 7.408Zm4.54-10.292a7.924 7.924 0 1 1 8.805 13.177A7.924 7.924 0 0 1 27.62 26.67Z"
5542
+ })));
5543
+ };
5544
+ var DatetimeIcon = SvgDatetime;
4744
5545
 
5546
+ var _path$9, _path2$2;
4745
5547
  function _extends$a() { _extends$a = Object.assign ? Object.assign.bind() : 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$a.apply(this, arguments); }
4746
- var DatetimeIcon = (({
4747
- styles = {},
4748
- ...props
4749
- }) => /*#__PURE__*/React.createElement("svg", _extends$a({
4750
- xmlns: "http://www.w3.org/2000/svg",
4751
- width: "54",
4752
- height: "54",
4753
- fill: "currentcolor"
4754
- }, props), /*#__PURE__*/React.createElement("path", {
4755
- fillRule: "evenodd",
4756
- d: "M37.908 13.418h-5.004v-2.354h-1.766v2.354H21.13v-2.354h-1.766v2.354H14.36a2.07 2.07 0 00-2.06 2.06v23.549a2.07 2.07 0 002.06 2.06h6.77v-1.766h-6.358a.707.707 0 01-.706-.706V15.89c0-.39.316-.707.706-.707h4.592v2.355h1.766v-2.355h10.008v2.355h1.766v-2.355h4.592a.71.71 0 01.707.707v6.358h1.765v-6.77c0-1.133-.927-2.06-2.06-2.06z"
4757
- }), /*#__PURE__*/React.createElement("path", {
4758
- d: "M35.13 37.603l1.237-1.237-3.468-3.475v-5.926h-1.754v6.654l3.984 3.984z"
4759
- }), /*#__PURE__*/React.createElement("path", {
4760
- fillRule: "evenodd",
4761
- d: "M23.08 36.962a9.678 9.678 0 1017.883-7.408 9.678 9.678 0 00-17.882 7.408zm4.54-10.292a7.924 7.924 0 118.805 13.177A7.924 7.924 0 0127.62 26.67z"
4762
- })));
5548
+ var SvgTaglist = function SvgTaglist(props) {
5549
+ return /*#__PURE__*/React.createElement("svg", _extends$a({
5550
+ xmlns: "http://www.w3.org/2000/svg",
5551
+ width: 54,
5552
+ height: 54,
5553
+ fill: "currentcolor"
5554
+ }, props), _path$9 || (_path$9 = /*#__PURE__*/React.createElement("path", {
5555
+ fillRule: "evenodd",
5556
+ d: "M45 16a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V19a3 3 0 0 1 3-3h36Zm0 2H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V19a1 1 0 0 0-1-1Z"
5557
+ })), _path2$2 || (_path2$2 = /*#__PURE__*/React.createElement("path", {
5558
+ d: "M11 22a1 1 0 0 1 1-1h19a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H12a1 1 0 0 1-1-1V22Z"
5559
+ })));
5560
+ };
5561
+ var TaglistIcon = SvgTaglist;
4763
5562
 
5563
+ var _rect, _rect2, _rect3;
4764
5564
  function _extends$9() { _extends$9 = Object.assign ? Object.assign.bind() : 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$9.apply(this, arguments); }
4765
- var TaglistIcon = (({
4766
- styles = {},
4767
- ...props
4768
- }) => /*#__PURE__*/React.createElement("svg", _extends$9({
4769
- xmlns: "http://www.w3.org/2000/svg",
4770
- width: "54",
4771
- height: "54",
4772
- fill: "currentcolor"
4773
- }, props), /*#__PURE__*/React.createElement("path", {
4774
- fillRule: "evenodd",
4775
- d: "M45 16a3 3 0 013 3v16a3 3 0 01-3 3H9a3 3 0 01-3-3V19a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v16a1 1 0 001 1h36a1 1 0 001-1V19a1 1 0 00-1-1z"
4776
- }), /*#__PURE__*/React.createElement("path", {
4777
- d: "M11 22a1 1 0 011-1h19a1 1 0 011 1v10a1 1 0 01-1 1H12a1 1 0 01-1-1V22z"
4778
- })));
5565
+ var SvgForm = function SvgForm(props) {
5566
+ return /*#__PURE__*/React.createElement("svg", _extends$9({
5567
+ xmlns: "http://www.w3.org/2000/svg",
5568
+ width: 54,
5569
+ height: 54
5570
+ }, props), _rect || (_rect = /*#__PURE__*/React.createElement("rect", {
5571
+ width: 24,
5572
+ height: 4,
5573
+ x: 15,
5574
+ y: 17,
5575
+ rx: 1
5576
+ })), _rect2 || (_rect2 = /*#__PURE__*/React.createElement("rect", {
5577
+ width: 24,
5578
+ height: 4,
5579
+ x: 15,
5580
+ y: 25,
5581
+ rx: 1
5582
+ })), _rect3 || (_rect3 = /*#__PURE__*/React.createElement("rect", {
5583
+ width: 13,
5584
+ height: 4,
5585
+ x: 15,
5586
+ y: 33,
5587
+ rx: 1
5588
+ })));
5589
+ };
5590
+ var FormIcon = SvgForm;
4779
5591
 
5592
+ var _path$8;
4780
5593
  function _extends$8() { _extends$8 = Object.assign ? Object.assign.bind() : 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$8.apply(this, arguments); }
4781
- var FormIcon = (({
4782
- styles = {},
4783
- ...props
4784
- }) => /*#__PURE__*/React.createElement("svg", _extends$8({
4785
- xmlns: "http://www.w3.org/2000/svg",
4786
- width: "54",
4787
- height: "54"
4788
- }, props), /*#__PURE__*/React.createElement("rect", {
4789
- width: "24",
4790
- height: "4",
4791
- x: "15",
4792
- y: "17",
4793
- rx: "1"
4794
- }), /*#__PURE__*/React.createElement("rect", {
4795
- width: "24",
4796
- height: "4",
4797
- x: "15",
4798
- y: "25",
4799
- rx: "1"
4800
- }), /*#__PURE__*/React.createElement("rect", {
4801
- width: "13",
4802
- height: "4",
4803
- x: "15",
4804
- y: "33",
4805
- rx: "1"
4806
- })));
5594
+ var SvgGroup = function SvgGroup(props) {
5595
+ return /*#__PURE__*/React.createElement("svg", _extends$8({
5596
+ xmlns: "http://www.w3.org/2000/svg",
5597
+ width: 54,
5598
+ height: 54
5599
+ }, props), _path$8 || (_path$8 = /*#__PURE__*/React.createElement("path", {
5600
+ fillRule: "evenodd",
5601
+ d: "M8 33v5a1 1 0 0 0 1 1h4v2H9a3 3 0 0 1-3-3v-5h2Zm18 6v2H15v-2h11Zm13 0v2H28v-2h11Zm9-6v5a3 3 0 0 1-3 3h-4v-2h4a1 1 0 0 0 .993-.883L46 38v-5h2ZM8 22v9H6v-9h2Zm40 0v9h-2v-9h2Zm-35-9v2H9a1 1 0 0 0-.993.883L8 16v4H6v-4a3 3 0 0 1 3-3h4Zm32 0a3 3 0 0 1 3 3v4h-2v-4a1 1 0 0 0-.883-.993L45 15h-4v-2h4Zm-6 0v2H28v-2h11Zm-13 0v2H15v-2h11Z"
5602
+ })));
5603
+ };
5604
+ var ColumnsIcon = SvgGroup;
4807
5605
 
5606
+ var _path$7;
4808
5607
  function _extends$7() { _extends$7 = Object.assign ? Object.assign.bind() : 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$7.apply(this, arguments); }
4809
- var ColumnsIcon = (({
4810
- styles = {},
4811
- ...props
4812
- }) => /*#__PURE__*/React.createElement("svg", _extends$7({
4813
- xmlns: "http://www.w3.org/2000/svg",
4814
- width: "54",
4815
- height: "54"
4816
- }, props), /*#__PURE__*/React.createElement("path", {
4817
- fillRule: "evenodd",
4818
- d: "M8 33v5a1 1 0 001 1h4v2H9a3 3 0 01-3-3v-5h2zm18 6v2H15v-2h11zm13 0v2H28v-2h11zm9-6v5a3 3 0 01-3 3h-4v-2h4a1 1 0 00.993-.883L46 38v-5h2zM8 22v9H6v-9h2zm40 0v9h-2v-9h2zm-35-9v2H9a1 1 0 00-.993.883L8 16v4H6v-4a3 3 0 013-3h4zm32 0a3 3 0 013 3v4h-2v-4a1 1 0 00-.883-.993L45 15h-4v-2h4zm-6 0v2H28v-2h11zm-13 0v2H15v-2h11z"
4819
- })));
5608
+ var SvgNumber = function SvgNumber(props) {
5609
+ return /*#__PURE__*/React.createElement("svg", _extends$7({
5610
+ xmlns: "http://www.w3.org/2000/svg",
5611
+ width: 54,
5612
+ height: 54,
5613
+ fill: "currentcolor"
5614
+ }, props), _path$7 || (_path$7 = /*#__PURE__*/React.createElement("path", {
5615
+ fillRule: "evenodd",
5616
+ d: "M45 16a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V19a3 3 0 0 1 3-3h36zm0 2H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V19a1 1 0 0 0-1-1zM35 28.444h7l-3.5 4-3.5-4zM35 26h7l-3.5-4-3.5 4z"
5617
+ })));
5618
+ };
5619
+ var NumberIcon = SvgNumber;
4820
5620
 
5621
+ var _path$6;
4821
5622
  function _extends$6() { _extends$6 = Object.assign ? Object.assign.bind() : 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$6.apply(this, arguments); }
4822
- var NumberIcon = (({
4823
- styles = {},
4824
- ...props
4825
- }) => /*#__PURE__*/React.createElement("svg", _extends$6({
4826
- xmlns: "http://www.w3.org/2000/svg",
4827
- width: "54",
4828
- height: "54",
4829
- fill: "currentcolor"
4830
- }, props), /*#__PURE__*/React.createElement("path", {
4831
- fillRule: "evenodd",
4832
- d: "M45 16a3 3 0 013 3v16a3 3 0 01-3 3H9a3 3 0 01-3-3V19a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v16a1 1 0 001 1h36a1 1 0 001-1V19a1 1 0 00-1-1zM35 28.444h7l-3.5 4-3.5-4zM35 26h7l-3.5-4-3.5 4z"
4833
- })));
5623
+ var SvgRadio = function SvgRadio(props) {
5624
+ return /*#__PURE__*/React.createElement("svg", _extends$6({
5625
+ xmlns: "http://www.w3.org/2000/svg",
5626
+ width: 54,
5627
+ height: 54,
5628
+ fill: "currentcolor"
5629
+ }, props), _path$6 || (_path$6 = /*#__PURE__*/React.createElement("path", {
5630
+ d: "M27 22c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 18a8 8 0 1 1 0-16 8 8 0 1 1 0 16z"
5631
+ })));
5632
+ };
5633
+ var RadioIcon = SvgRadio;
4834
5634
 
5635
+ var _path$5;
4835
5636
  function _extends$5() { _extends$5 = Object.assign ? Object.assign.bind() : 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$5.apply(this, arguments); }
4836
- var RadioIcon = (({
4837
- styles = {},
4838
- ...props
4839
- }) => /*#__PURE__*/React.createElement("svg", _extends$5({
4840
- xmlns: "http://www.w3.org/2000/svg",
4841
- width: "54",
4842
- height: "54",
4843
- fill: "currentcolor"
4844
- }, props), /*#__PURE__*/React.createElement("path", {
4845
- d: "M27 22c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 18a8 8 0 110-16 8 8 0 110 16z"
4846
- })));
5637
+ var SvgSelect = function SvgSelect(props) {
5638
+ return /*#__PURE__*/React.createElement("svg", _extends$5({
5639
+ xmlns: "http://www.w3.org/2000/svg",
5640
+ width: 54,
5641
+ height: 54,
5642
+ fill: "currentcolor"
5643
+ }, props), _path$5 || (_path$5 = /*#__PURE__*/React.createElement("path", {
5644
+ fillRule: "evenodd",
5645
+ d: "M45 16a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V19a3 3 0 0 1 3-3h36zm0 2H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V19a1 1 0 0 0-1-1zm-12 7h9l-4.5 6-4.5-6z"
5646
+ })));
5647
+ };
5648
+ var SelectIcon = SvgSelect;
4847
5649
 
5650
+ var _path$4, _path2$1;
4848
5651
  function _extends$4() { _extends$4 = Object.assign ? Object.assign.bind() : 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$4.apply(this, arguments); }
4849
- var SelectIcon = (({
4850
- styles = {},
4851
- ...props
4852
- }) => /*#__PURE__*/React.createElement("svg", _extends$4({
4853
- xmlns: "http://www.w3.org/2000/svg",
4854
- width: "54",
4855
- height: "54",
4856
- fill: "currentcolor"
4857
- }, props), /*#__PURE__*/React.createElement("path", {
4858
- fillRule: "evenodd",
4859
- d: "M45 16a3 3 0 013 3v16a3 3 0 01-3 3H9a3 3 0 01-3-3V19a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v16a1 1 0 001 1h36a1 1 0 001-1V19a1 1 0 00-1-1zm-12 7h9l-4.5 6-4.5-6z"
4860
- })));
5652
+ var SvgSpacer = function SvgSpacer(props) {
5653
+ return /*#__PURE__*/React.createElement("svg", _extends$4({
5654
+ xmlns: "http://www.w3.org/2000/svg",
5655
+ width: 54,
5656
+ height: 54,
5657
+ fill: "none"
5658
+ }, props), _path$4 || (_path$4 = /*#__PURE__*/React.createElement("path", {
5659
+ stroke: "#000",
5660
+ strokeLinecap: "square",
5661
+ strokeWidth: 2,
5662
+ d: "M9 23h36M9 31h36"
5663
+ })), _path2$1 || (_path2$1 = /*#__PURE__*/React.createElement("path", {
5664
+ stroke: "#000",
5665
+ strokeLinecap: "round",
5666
+ strokeLinejoin: "round",
5667
+ strokeWidth: 2,
5668
+ d: "m23 17 4-4 4 4M31 37l-4 4-4-4"
5669
+ })));
5670
+ };
5671
+ var SpacerIcon = SvgSpacer;
4861
5672
 
5673
+ var _path$3;
4862
5674
  function _extends$3() { _extends$3 = Object.assign ? Object.assign.bind() : 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$3.apply(this, arguments); }
4863
- var TextIcon = (({
4864
- styles = {},
4865
- ...props
4866
- }) => /*#__PURE__*/React.createElement("svg", _extends$3({
4867
- xmlns: "http://www.w3.org/2000/svg",
4868
- width: "54",
4869
- height: "54",
4870
- fill: "currentcolor"
4871
- }, props), /*#__PURE__*/React.createElement("path", {
4872
- d: "M20.58 33.77h-3l-1.18-3.08H11l-1.1 3.08H7l5.27-13.54h2.89zm-5-5.36l-1.86-5-1.83 5zM22 20.23h5.41a15.47 15.47 0 012.4.14 3.42 3.42 0 011.41.55 3.47 3.47 0 011 1.14 3 3 0 01.42 1.58 3.26 3.26 0 01-1.91 2.94 3.63 3.63 0 011.91 1.22 3.28 3.28 0 01.66 2 4 4 0 01-.43 1.8 3.63 3.63 0 01-1.09 1.4 3.89 3.89 0 01-1.83.65q-.69.07-3.3.09H22zm2.73 2.25v3.13h3.8a1.79 1.79 0 001.1-.49 1.41 1.41 0 00.41-1 1.49 1.49 0 00-.35-1 1.54 1.54 0 00-1-.48c-.27 0-1.05-.05-2.34-.05zm0 5.39v3.62h2.57a11.52 11.52 0 001.88-.09 1.65 1.65 0 001-.54 1.6 1.6 0 00.38-1.14 1.75 1.75 0 00-.29-1 1.69 1.69 0 00-.86-.62 9.28 9.28 0 00-2.41-.23zm19.62.92l2.65.84a5.94 5.94 0 01-2 3.29A5.74 5.74 0 0141.38 34a5.87 5.87 0 01-4.44-1.84 7.09 7.09 0 01-1.73-5A7.43 7.43 0 0137 21.87 6 6 0 0141.54 20a5.64 5.64 0 014 1.47A5.33 5.33 0 0147 24l-2.7.65a2.8 2.8 0 00-2.86-2.27A3.09 3.09 0 0039 23.42a5.31 5.31 0 00-.93 3.5 5.62 5.62 0 00.93 3.65 3 3 0 002.4 1.09 2.72 2.72 0 001.82-.66 4 4 0 001.13-2.21z"
4873
- })));
5675
+ var SvgText = function SvgText(props) {
5676
+ return /*#__PURE__*/React.createElement("svg", _extends$3({
5677
+ xmlns: "http://www.w3.org/2000/svg",
5678
+ width: 54,
5679
+ height: 54,
5680
+ fill: "currentcolor"
5681
+ }, props), _path$3 || (_path$3 = /*#__PURE__*/React.createElement("path", {
5682
+ d: "M20.58 33.77h-3l-1.18-3.08H11l-1.1 3.08H7l5.27-13.54h2.89zm-5-5.36-1.86-5-1.83 5zM22 20.23h5.41a15.47 15.47 0 0 1 2.4.14 3.42 3.42 0 0 1 1.41.55 3.47 3.47 0 0 1 1 1.14 3 3 0 0 1 .42 1.58 3.26 3.26 0 0 1-1.91 2.94 3.63 3.63 0 0 1 1.91 1.22 3.28 3.28 0 0 1 .66 2 4 4 0 0 1-.43 1.8 3.63 3.63 0 0 1-1.09 1.4 3.89 3.89 0 0 1-1.83.65q-.69.07-3.3.09H22zm2.73 2.25v3.13h3.8a1.79 1.79 0 0 0 1.1-.49 1.41 1.41 0 0 0 .41-1 1.49 1.49 0 0 0-.35-1 1.54 1.54 0 0 0-1-.48c-.27 0-1.05-.05-2.34-.05zm0 5.39v3.62h2.57a11.52 11.52 0 0 0 1.88-.09 1.65 1.65 0 0 0 1-.54 1.6 1.6 0 0 0 .38-1.14 1.75 1.75 0 0 0-.29-1 1.69 1.69 0 0 0-.86-.62 9.28 9.28 0 0 0-2.41-.23zm19.62.92 2.65.84a5.94 5.94 0 0 1-2 3.29A5.74 5.74 0 0 1 41.38 34a5.87 5.87 0 0 1-4.44-1.84 7.09 7.09 0 0 1-1.73-5A7.43 7.43 0 0 1 37 21.87 6 6 0 0 1 41.54 20a5.64 5.64 0 0 1 4 1.47A5.33 5.33 0 0 1 47 24l-2.7.65a2.8 2.8 0 0 0-2.86-2.27A3.09 3.09 0 0 0 39 23.42a5.31 5.31 0 0 0-.93 3.5 5.62 5.62 0 0 0 .93 3.65 3 3 0 0 0 2.4 1.09 2.72 2.72 0 0 0 1.82-.66 4 4 0 0 0 1.13-2.21z"
5683
+ })));
5684
+ };
5685
+ var TextIcon = SvgText;
4874
5686
 
5687
+ var _path$2;
4875
5688
  function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : 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$2.apply(this, arguments); }
4876
- var TextfieldIcon = (({
4877
- styles = {},
4878
- ...props
4879
- }) => /*#__PURE__*/React.createElement("svg", _extends$2({
4880
- xmlns: "http://www.w3.org/2000/svg",
4881
- width: "54",
4882
- height: "54",
4883
- fill: "currentcolor"
4884
- }, props), /*#__PURE__*/React.createElement("path", {
4885
- fillRule: "evenodd",
4886
- d: "M45 16a3 3 0 013 3v16a3 3 0 01-3 3H9a3 3 0 01-3-3V19a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v16a1 1 0 001 1h36a1 1 0 001-1V19a1 1 0 00-1-1zm-32 4v10h-2V22h2z"
4887
- })));
5689
+ var SvgTextfield = function SvgTextfield(props) {
5690
+ return /*#__PURE__*/React.createElement("svg", _extends$2({
5691
+ xmlns: "http://www.w3.org/2000/svg",
5692
+ width: 54,
5693
+ height: 54,
5694
+ fill: "currentcolor"
5695
+ }, props), _path$2 || (_path$2 = /*#__PURE__*/React.createElement("path", {
5696
+ fillRule: "evenodd",
5697
+ d: "M45 16a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V19a3 3 0 0 1 3-3h36zm0 2H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V19a1 1 0 0 0-1-1zm-32 4v10h-2V22h2z"
5698
+ })));
5699
+ };
5700
+ var TextfieldIcon = SvgTextfield;
4888
5701
 
5702
+ var _path$1;
4889
5703
  function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : 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$1.apply(this, arguments); }
4890
- var TextareaIcon = (({
4891
- styles = {},
4892
- ...props
4893
- }) => /*#__PURE__*/React.createElement("svg", _extends$1({
4894
- xmlns: "http://www.w3.org/2000/svg",
4895
- width: "54",
4896
- height: "54",
4897
- fill: "currentcolor"
4898
- }, props), /*#__PURE__*/React.createElement("path", {
4899
- fillRule: "evenodd",
4900
- d: "M45 13a3 3 0 013 3v22a3 3 0 01-3 3H9a3 3 0 01-3-3V16a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v22a1 1 0 001 1h36a1 1 0 001-1V16a1 1 0 00-1-1zm-1.136 15.5l.849.849-6.364 6.364-.849-.849 6.364-6.364zm.264 3.5l.849.849-2.828 2.828-.849-.849L44.128 34zM13 19v10h-2V19h2z"
4901
- })));
5704
+ var SvgTextarea = function SvgTextarea(props) {
5705
+ return /*#__PURE__*/React.createElement("svg", _extends$1({
5706
+ xmlns: "http://www.w3.org/2000/svg",
5707
+ width: 54,
5708
+ height: 54,
5709
+ fill: "currentcolor"
5710
+ }, props), _path$1 || (_path$1 = /*#__PURE__*/React.createElement("path", {
5711
+ fillRule: "evenodd",
5712
+ d: "M45 13a3 3 0 0 1 3 3v22a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V16a3 3 0 0 1 3-3h36zm0 2H9a1 1 0 0 0-1 1v22a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V16a1 1 0 0 0-1-1zm-1.136 15.5.849.849-6.364 6.364-.849-.849 6.364-6.364zm.264 3.5.849.849-2.828 2.828-.849-.849L44.128 34zM13 19v10h-2V19h2z"
5713
+ })));
5714
+ };
5715
+ var TextareaIcon = SvgTextarea;
4902
5716
 
5717
+ var _path, _path2;
4903
5718
  function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); }
4904
- var ImageIcon = (({
4905
- styles = {},
4906
- ...props
4907
- }) => /*#__PURE__*/React.createElement("svg", _extends({
4908
- xmlns: "http://www.w3.org/2000/svg",
4909
- width: "54",
4910
- height: "54",
4911
- fill: "currentcolor"
4912
- }, props), /*#__PURE__*/React.createElement("path", {
4913
- fillRule: "evenodd",
4914
- d: "M34.636 21.91A3.818 3.818 0 1127 21.908a3.818 3.818 0 017.636 0zm-2 0A1.818 1.818 0 1129 21.908a1.818 1.818 0 013.636 0z",
4915
- clipRule: "evenodd"
4916
- }), /*#__PURE__*/React.createElement("path", {
4917
- fillRule: "evenodd",
4918
- d: "M15 13a2 2 0 00-2 2v24a2 2 0 002 2h24a2 2 0 002-2V15a2 2 0 00-2-2H15zm24 2H15v12.45l4.71-4.709a1.91 1.91 0 012.702 0l6.695 6.695 2.656-1.77a1.91 1.91 0 012.411.239L39 32.73V15zM15 39v-8.754a.975.975 0 00.168-.135l5.893-5.893 6.684 6.685a1.911 1.911 0 002.41.238l2.657-1.77 6.02 6.02c.052.051.108.097.168.135V39H15z",
4919
- clipRule: "evenodd"
4920
- })));
5719
+ var SvgImage = function SvgImage(props) {
5720
+ return /*#__PURE__*/React.createElement("svg", _extends({
5721
+ xmlns: "http://www.w3.org/2000/svg",
5722
+ width: 54,
5723
+ height: 54,
5724
+ fill: "currentcolor"
5725
+ }, props), _path || (_path = /*#__PURE__*/React.createElement("path", {
5726
+ fillRule: "evenodd",
5727
+ d: "M34.636 21.91A3.818 3.818 0 1 1 27 21.908a3.818 3.818 0 0 1 7.636 0Zm-2 0A1.818 1.818 0 1 1 29 21.908a1.818 1.818 0 0 1 3.636 0Z",
5728
+ clipRule: "evenodd"
5729
+ })), _path2 || (_path2 = /*#__PURE__*/React.createElement("path", {
5730
+ fillRule: "evenodd",
5731
+ d: "M15 13a2 2 0 0 0-2 2v24a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V15a2 2 0 0 0-2-2H15Zm24 2H15v12.45l4.71-4.709a1.91 1.91 0 0 1 2.702 0l6.695 6.695 2.656-1.77a1.91 1.91 0 0 1 2.411.239L39 32.73V15ZM15 39v-8.754a.975.975 0 0 0 .168-.135l5.893-5.893 6.684 6.685a1.911 1.911 0 0 0 2.41.238l2.657-1.77 6.02 6.02c.052.051.108.097.168.135V39H15Z",
5732
+ clipRule: "evenodd"
5733
+ })));
5734
+ };
5735
+ var ImageIcon = SvgImage;
4921
5736
 
4922
5737
  const iconsByType = type => {
4923
5738
  return {
@@ -4930,6 +5745,7 @@ const iconsByType = type => {
4930
5745
  number: NumberIcon,
4931
5746
  radio: RadioIcon,
4932
5747
  select: SelectIcon,
5748
+ spacer: SpacerIcon,
4933
5749
  taglist: TaglistIcon,
4934
5750
  text: TextIcon,
4935
5751
  textfield: TextfieldIcon,
@@ -4938,7 +5754,7 @@ const iconsByType = type => {
4938
5754
  }[type];
4939
5755
  };
4940
5756
 
4941
- const formFields = [Button, Checkbox, Checklist, Default, Image, Numberfield, Datetime, Radio, Select, Taglist, Text, Textfield, Textarea];
5757
+ const formFields = [Button, Checkbox, Checklist, Default, Image, Numberfield, Datetime, Radio, Select, Spacer, Taglist, Text, Textfield, Textarea];
4942
5758
 
4943
5759
  class FormFields {
4944
5760
  constructor() {
@@ -5349,7 +6165,7 @@ class Form {
5349
6165
  * @internal
5350
6166
  */
5351
6167
  _getModules() {
5352
- return [ExpressionLanguageModule, MarkdownModule];
6168
+ return [ExpressionLanguageModule, MarkdownModule, ViewerCommandsModule];
5353
6169
  }
5354
6170
 
5355
6171
  /**
@@ -5394,7 +6210,7 @@ class Form {
5394
6210
  }
5395
6211
  }
5396
6212
 
5397
- const schemaVersion = 9;
6213
+ const schemaVersion = 10;
5398
6214
 
5399
6215
  /**
5400
6216
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
@@ -5419,5 +6235,5 @@ function createForm(options) {
5419
6235
  });
5420
6236
  }
5421
6237
 
5422
- export { Button, Checkbox, Checklist, ConditionChecker, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, Default, ExpressionLanguageModule, FeelExpressionLanguage, FeelersTemplating, Form, FormComponent, FormContext$1 as FormContext, FormFieldRegistry, FormFields, FormLayouter, FormRenderContext$1 as FormRenderContext, Image, MINUTES_IN_DAY, MarkdownModule, MarkdownRenderer, Numberfield, Radio, Select, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Taglist, Text, Textarea, Textfield, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_LABELS, VALUES_SOURCES_PATHS, VALUES_SOURCE_DEFAULT, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, getValuesSource, iconsByType, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
6238
+ export { Button, Checkbox, Checklist, ConditionChecker, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, Default, ExpressionLanguageModule, FeelExpressionLanguage, FeelersTemplating, Form, FormComponent, FormContext$1 as FormContext, FormFieldRegistry, FormFields, FormLayouter, FormRenderContext$1 as FormRenderContext, Image, MINUTES_IN_DAY, MarkdownModule, MarkdownRenderer, Numberfield, Radio, Select, Spacer, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Taglist, Text, Textarea, Textfield, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_LABELS, VALUES_SOURCES_PATHS, VALUES_SOURCE_DEFAULT, ViewerCommands, ViewerCommandsModule, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, getValuesSource, iconsByType, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
5423
6239
  //# sourceMappingURL=index.es.js.map