@bpmn-io/form-js-viewer 1.0.0 → 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,28 +1,28 @@
1
1
  import Ids from 'ids';
2
- import { isString, isArray, isFunction, isNumber, bind, assign, isNil, get, set, groupBy, flatten, isUndefined, 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
10
  import * as React from 'preact/compat';
12
11
  import { createPortal } from 'preact/compat';
13
12
  import flatpickr from 'flatpickr';
14
13
  import Markup from 'preact-markup';
15
14
  import { Injector } from 'didi';
15
+ import showdown from 'showdown';
16
16
 
17
- const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) => {
17
+ const getFlavouredFeelVariableNames = (feelString, feelFlavour = 'expression', options = {}) => {
18
18
  const {
19
19
  depth = 0,
20
20
  specialDepthAccessors = {}
21
21
  } = options;
22
22
  if (!['expression', 'unaryTest'].includes(feelFlavour)) return [];
23
- const tree = feelFlavour === 'expression' ? parseExpressions(feelString) : parseUnaryTests(feelString);
23
+ const tree = feelFlavour === 'expression' ? parseExpression(feelString) : parseUnaryTests(feelString);
24
24
  const simpleExpressionTree = _buildSimpleFeelStructureTree(tree, feelString);
25
- return function _unfoldVariables(node) {
25
+ const variables = function _unfoldVariables(node) {
26
26
  if (node.name === 'PathExpression') {
27
27
  if (Object.keys(specialDepthAccessors).length === 0) {
28
28
  return depth === 0 ? [_getVariableNameAtPathIndex(node, 0)] : [];
@@ -35,12 +35,16 @@ const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) =>
35
35
 
36
36
  // for any other kind of node, traverse its children and flatten the result
37
37
  if (node.children) {
38
- return node.children.reduce((acc, child) => {
38
+ const variables = node.children.reduce((acc, child) => {
39
39
  return acc.concat(_unfoldVariables(child));
40
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;
41
44
  }
42
45
  return [];
43
46
  }(simpleExpressionTree);
47
+ return [...new Set(variables)];
44
48
  };
45
49
 
46
50
  /**
@@ -160,7 +164,45 @@ const _buildSimpleFeelStructureTree = (parseTree, feelString) => {
160
164
  parent.children.push(result);
161
165
  }
162
166
  });
163
- 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;
164
206
  };
165
207
 
166
208
  class FeelExpressionLanguage {
@@ -391,84 +433,816 @@ class ConditionChecker {
391
433
  if (!condition) {
392
434
  return null;
393
435
  }
394
- if (!isString(condition) || !condition.startsWith('=')) {
395
- return null;
436
+ if (!isString(condition) || !condition.startsWith('=')) {
437
+ return null;
438
+ }
439
+ try {
440
+ // cut off initial '='
441
+ const result = unaryTest(condition.slice(1), data);
442
+ return result;
443
+ } catch (error) {
444
+ this._eventBus.fire('error', {
445
+ error
446
+ });
447
+ return null;
448
+ }
449
+ }
450
+
451
+ /**
452
+ * Check if hide condition is met.
453
+ *
454
+ * @param {Condition} condition
455
+ * @param {Object<string, any>} data
456
+ * @returns {boolean}
457
+ */
458
+ _checkHideCondition(condition, data) {
459
+ if (!condition.hide) {
460
+ return false;
461
+ }
462
+ const result = this.check(condition.hide, data);
463
+ return result === true;
464
+ }
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
+ }
396
1153
  }
397
- try {
398
- // cut off initial '='
399
- const result = unaryTest(condition.slice(1), data);
400
- return result;
401
- } catch (error) {
402
- this._eventBus.fire('error', {
403
- error
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
+ }
404
1175
  });
405
- return null;
406
1176
  }
407
- }
1177
+ return variables.filter(variable => variable !== undefined || variable !== null);
1178
+ }, []);
408
1179
 
409
- /**
410
- * Check if hide condition is met.
411
- *
412
- * @param {Condition} condition
413
- * @param {Object<string, any>} data
414
- * @returns {boolean}
415
- */
416
- _checkHideCondition(condition, data) {
417
- if (!condition.hide) {
418
- return false;
419
- }
420
- const result = this.check(condition.hide, data);
421
- return result === true;
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;
422
1188
  }
423
- _getConditions() {
424
- const formFields = this._formFieldRegistry.getAll();
425
- return formFields.reduce((conditions, formField) => {
426
- const {
427
- key,
428
- conditional: condition
429
- } = formField;
430
- if (key && condition) {
431
- return [...conditions, {
432
- key,
433
- condition
434
- }];
435
- }
436
- return conditions;
437
- }, []);
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
+ });
438
1211
  }
439
1212
  }
440
- ConditionChecker.$inject = ['formFieldRegistry', 'eventBus'];
441
-
442
- var ExpressionLanguageModule = {
443
- __init__: ['expressionLanguage', 'templating', 'conditionChecker'],
444
- expressionLanguage: ['type', FeelExpressionLanguage],
445
- templating: ['type', FeelersTemplating],
446
- conditionChecker: ['type', ConditionChecker]
447
- };
1213
+ UpdateFieldValidationHandler.$inject = ['form', 'validator'];
448
1214
 
449
- // bootstrap showdown to support github flavored markdown
450
- showdown.setFlavor('github');
451
- class MarkdownRenderer {
452
- constructor() {
453
- 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
+ });
454
1221
  }
455
-
456
- /**
457
- * Render markdown to HTML.
458
- *
459
- * @param {string} markdown - The markdown to render
460
- *
461
- * @returns {string} HTML
462
- */
463
- render(markdown) {
464
- 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);
465
1238
  }
466
1239
  }
467
- MarkdownRenderer.$inject = [];
1240
+ ViewerCommands.$inject = ['commandStack', 'eventBus'];
468
1241
 
469
- var MarkdownModule = {
470
- __init__: ['markdownRenderer'],
471
- markdownRenderer: ['type', MarkdownRenderer]
1242
+ var ViewerCommandsModule = {
1243
+ __depends__: [commandModule],
1244
+ __init__: ['viewerCommands'],
1245
+ viewerCommands: ['type', ViewerCommands]
472
1246
  };
473
1247
 
474
1248
  var FN_REF = '__fn';
@@ -1260,229 +2034,46 @@ class FormLayouter {
1260
2034
  components: components.map(c => c.id)
1261
2035
  });
1262
2036
  });
1263
-
1264
- // (3) traverse through nested components
1265
- components.forEach(field => this.calculateLayout(field));
1266
-
1267
- // (4) fire event to notify interested parties
1268
- this._eventBus.fire('form.layoutCalculated', {
1269
- rows: this._rows
1270
- });
1271
- }
1272
- clear() {
1273
- this._rows = [];
1274
- this._ids.clear();
1275
-
1276
- // fire event to notify interested parties
1277
- this._eventBus.fire('form.layoutCleared');
1278
- }
1279
- }
1280
- FormLayouter.$inject = ['eventBus'];
1281
-
1282
- // helpers //////
1283
-
1284
- function groupByRow(components, ids) {
1285
- return groupBy(components, c => {
1286
- // mitigate missing row by creating new (handle legacy)
1287
- const {
1288
- layout
1289
- } = c;
1290
- if (!layout || !layout.row) {
1291
- return ids.nextPrefixed('Row_');
1292
- }
1293
- return layout.row;
1294
- });
1295
- }
1296
-
1297
- /**
1298
- * @param {Array<FormRows>} formRows
1299
- * @returns {Array<FormRow>}
1300
- */
1301
- function allRows(formRows) {
1302
- return flatten(formRows.map(c => c.rows));
1303
- }
1304
-
1305
- // config ///////////////////
1306
-
1307
- const MINUTES_IN_DAY = 60 * 24;
1308
- const DATETIME_SUBTYPES = {
1309
- DATE: 'date',
1310
- TIME: 'time',
1311
- DATETIME: 'datetime'
1312
- };
1313
- const TIME_SERIALISING_FORMATS = {
1314
- UTC_OFFSET: 'utc_offset',
1315
- UTC_NORMALIZED: 'utc_normalized',
1316
- NO_TIMEZONE: 'no_timezone'
1317
- };
1318
- const DATETIME_SUBTYPES_LABELS = {
1319
- [DATETIME_SUBTYPES.DATE]: 'Date',
1320
- [DATETIME_SUBTYPES.TIME]: 'Time',
1321
- [DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
1322
- };
1323
- const TIME_SERIALISINGFORMAT_LABELS = {
1324
- [TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
1325
- [TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
1326
- [TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
1327
- };
1328
- const DATETIME_SUBTYPE_PATH = ['subtype'];
1329
- const DATE_LABEL_PATH = ['dateLabel'];
1330
- const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
1331
- const TIME_LABEL_PATH = ['timeLabel'];
1332
- const TIME_USE24H_PATH = ['use24h'];
1333
- const TIME_INTERVAL_PATH = ['timeInterval'];
1334
- const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
1335
-
1336
- // config ///////////////////
1337
-
1338
- const VALUES_SOURCES = {
1339
- STATIC: 'static',
1340
- INPUT: 'input',
1341
- EXPRESSION: 'expression'
1342
- };
1343
- const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
1344
- const VALUES_SOURCES_LABELS = {
1345
- [VALUES_SOURCES.STATIC]: 'Static',
1346
- [VALUES_SOURCES.INPUT]: 'Input data',
1347
- [VALUES_SOURCES.EXPRESSION]: 'Expression'
1348
- };
1349
- const VALUES_SOURCES_PATHS = {
1350
- [VALUES_SOURCES.STATIC]: ['values'],
1351
- [VALUES_SOURCES.INPUT]: ['valuesKey'],
1352
- [VALUES_SOURCES.EXPRESSION]: ['valuesExpression']
1353
- };
1354
- const VALUES_SOURCES_DEFAULTS = {
1355
- [VALUES_SOURCES.STATIC]: [{
1356
- label: 'Value',
1357
- value: 'value'
1358
- }],
1359
- [VALUES_SOURCES.INPUT]: '',
1360
- [VALUES_SOURCES.EXPRESSION]: '='
1361
- };
1362
-
1363
- // helpers ///////////////////
1364
-
1365
- function getValuesSource(field) {
1366
- for (const source of Object.values(VALUES_SOURCES)) {
1367
- if (get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
1368
- return source;
1369
- }
1370
- }
1371
- return VALUES_SOURCE_DEFAULT;
1372
- }
1373
-
1374
- function createInjector(bootstrapModules) {
1375
- const injector = new Injector(bootstrapModules);
1376
- injector.init();
1377
- return injector;
1378
- }
1379
-
1380
- /**
1381
- * @param {string?} prefix
1382
- *
1383
- * @returns Element
1384
- */
1385
- function createFormContainer(prefix = 'fjs') {
1386
- const container = document.createElement('div');
1387
- container.classList.add(`${prefix}-container`);
1388
- return container;
1389
- }
1390
-
1391
- const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression'];
1392
- const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text'];
1393
- function findErrors(errors, path) {
1394
- return errors[pathStringify(path)];
1395
- }
1396
- function isRequired(field) {
1397
- return field.required;
1398
- }
1399
- function pathParse(path) {
1400
- if (!path) {
1401
- return [];
1402
- }
1403
- return path.split('.').map(key => {
1404
- return isNaN(parseInt(key)) ? key : parseInt(key);
1405
- });
1406
- }
1407
- function pathsEqual(a, b) {
1408
- return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
1409
- }
1410
- function pathStringify(path) {
1411
- if (!path) {
1412
- return '';
2037
+
2038
+ // (3) traverse through nested components
2039
+ components.forEach(field => this.calculateLayout(field));
2040
+
2041
+ // (4) fire event to notify interested parties
2042
+ this._eventBus.fire('form.layoutCalculated', {
2043
+ rows: this._rows
2044
+ });
1413
2045
  }
1414
- return path.join('.');
1415
- }
1416
- const indices = {};
1417
- function generateIndexForType(type) {
1418
- if (type in indices) {
1419
- indices[type]++;
1420
- } else {
1421
- indices[type] = 1;
2046
+ clear() {
2047
+ this._rows = [];
2048
+ this._ids.clear();
2049
+
2050
+ // fire event to notify interested parties
2051
+ this._eventBus.fire('form.layoutCleared');
1422
2052
  }
1423
- return indices[type];
1424
- }
1425
- function generateIdForType(type) {
1426
- return `${type}${generateIndexForType(type)}`;
1427
2053
  }
2054
+ FormLayouter.$inject = ['eventBus'];
1428
2055
 
1429
- /**
1430
- * @template T
1431
- * @param {T} data
1432
- * @param {(this: any, key: string, value: any) => any} [replacer]
1433
- * @return {T}
1434
- */
1435
- function clone(data, replacer) {
1436
- return JSON.parse(JSON.stringify(data, replacer));
1437
- }
2056
+ // helpers //////
1438
2057
 
1439
- /**
1440
- * Parse the schema for input variables a form might make use of
1441
- *
1442
- * @param {any} schema
1443
- *
1444
- * @return {string[]}
1445
- */
1446
- function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLanguage(null), templating = new FeelersTemplating()) {
1447
- if (!schema.components) {
1448
- return [];
1449
- }
1450
- const variables = schema.components.reduce((variables, component) => {
2058
+ function groupByRow(components, ids) {
2059
+ return groupBy(components, c => {
2060
+ // mitigate missing row by creating new (handle legacy)
1451
2061
  const {
1452
- key,
1453
- valuesKey,
1454
- type
1455
- } = component;
1456
- if (['button'].includes(type)) {
1457
- return variables;
1458
- }
1459
- if (key) {
1460
- variables = [...variables, key];
1461
- }
1462
- if (valuesKey) {
1463
- variables = [...variables, valuesKey];
2062
+ layout
2063
+ } = c;
2064
+ if (!layout || !layout.row) {
2065
+ return ids.nextPrefixed('Row_');
1464
2066
  }
1465
- EXPRESSION_PROPERTIES.forEach(prop => {
1466
- const property = get(component, prop.split('.'));
1467
- if (property && expressionLanguage.isExpression(property)) {
1468
- const expressionVariables = expressionLanguage.getVariableNames(property, {
1469
- type: 'expression'
1470
- });
1471
- variables = [...variables, ...expressionVariables];
1472
- }
1473
- });
1474
- TEMPLATE_PROPERTIES.forEach(prop => {
1475
- const property = get(component, prop.split('.'));
1476
- if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
1477
- const templateVariables = templating.getVariableNames(property);
1478
- variables = [...variables, ...templateVariables];
1479
- }
1480
- });
1481
- return variables;
1482
- }, []);
2067
+ return layout.row;
2068
+ });
2069
+ }
1483
2070
 
1484
- // remove duplicates
1485
- 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));
1486
2077
  }
1487
2078
 
1488
2079
  class Importer {
@@ -1659,7 +2250,7 @@ function prefixId(id, formId) {
1659
2250
  return `fjs-form-${id}`;
1660
2251
  }
1661
2252
 
1662
- const type$b = 'button';
2253
+ const type$c = 'button';
1663
2254
  function Button(props) {
1664
2255
  const {
1665
2256
  disabled,
@@ -1669,7 +2260,7 @@ function Button(props) {
1669
2260
  action = 'submit'
1670
2261
  } = field;
1671
2262
  return jsx("div", {
1672
- class: formFieldClasses(type$b),
2263
+ class: formFieldClasses(type$c),
1673
2264
  children: jsx("button", {
1674
2265
  class: "fjs-button",
1675
2266
  type: action,
@@ -1679,7 +2270,7 @@ function Button(props) {
1679
2270
  });
1680
2271
  }
1681
2272
  Button.config = {
1682
- type: type$b,
2273
+ type: type$c,
1683
2274
  keyed: true,
1684
2275
  label: 'Button',
1685
2276
  group: 'action',
@@ -1939,11 +2530,12 @@ function Label(props) {
1939
2530
  });
1940
2531
  }
1941
2532
 
1942
- const type$a = 'checkbox';
2533
+ const type$b = 'checkbox';
1943
2534
  function Checkbox(props) {
1944
2535
  const {
1945
2536
  disabled,
1946
2537
  errors = [],
2538
+ onBlur,
1947
2539
  field,
1948
2540
  readonly,
1949
2541
  value = false
@@ -1970,7 +2562,7 @@ function Checkbox(props) {
1970
2562
  } = useContext(FormContext$1);
1971
2563
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
1972
2564
  return jsxs("div", {
1973
- class: classNames(formFieldClasses(type$a, {
2565
+ class: classNames(formFieldClasses(type$b, {
1974
2566
  errors,
1975
2567
  disabled,
1976
2568
  readonly
@@ -1989,6 +2581,7 @@ function Checkbox(props) {
1989
2581
  id: prefixId(id, formId),
1990
2582
  type: "checkbox",
1991
2583
  onChange: onChange,
2584
+ onBlur: onBlur,
1992
2585
  "aria-describedby": errorMessageId
1993
2586
  })
1994
2587
  }), jsx(Description, {
@@ -2000,7 +2593,7 @@ function Checkbox(props) {
2000
2593
  });
2001
2594
  }
2002
2595
  Checkbox.config = {
2003
- type: type$a,
2596
+ type: type$b,
2004
2597
  keyed: true,
2005
2598
  label: 'Checkbox',
2006
2599
  group: 'selection',
@@ -2343,11 +2936,12 @@ function sanitizeMultiSelectValue(options) {
2343
2936
  }
2344
2937
  }
2345
2938
 
2346
- const type$9 = 'checklist';
2939
+ const type$a = 'checklist';
2347
2940
  function Checklist(props) {
2348
2941
  const {
2349
2942
  disabled,
2350
2943
  errors = [],
2944
+ onBlur,
2351
2945
  field,
2352
2946
  readonly,
2353
2947
  value = []
@@ -2358,6 +2952,7 @@ function Checklist(props) {
2358
2952
  label,
2359
2953
  validate = {}
2360
2954
  } = field;
2955
+ const outerDivRef = useRef();
2361
2956
  const {
2362
2957
  required
2363
2958
  } = validate;
@@ -2373,6 +2968,12 @@ function Checklist(props) {
2373
2968
  value: newValue
2374
2969
  });
2375
2970
  };
2971
+ const onCheckboxBlur = e => {
2972
+ if (outerDivRef.current.contains(e.relatedTarget)) {
2973
+ return;
2974
+ }
2975
+ onBlur();
2976
+ };
2376
2977
  const {
2377
2978
  state: loadState,
2378
2979
  values: options
@@ -2382,11 +2983,12 @@ function Checklist(props) {
2382
2983
  } = useContext(FormContext$1);
2383
2984
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
2384
2985
  return jsxs("div", {
2385
- class: classNames(formFieldClasses(type$9, {
2986
+ class: classNames(formFieldClasses(type$a, {
2386
2987
  errors,
2387
2988
  disabled,
2388
2989
  readonly
2389
2990
  })),
2991
+ ref: outerDivRef,
2390
2992
  children: [jsx(Label, {
2391
2993
  label: label,
2392
2994
  required: required
@@ -2406,6 +3008,7 @@ function Checklist(props) {
2406
3008
  id: prefixId(`${id}-${index}`, formId),
2407
3009
  type: "checkbox",
2408
3010
  onClick: () => toggleCheckbox(v.value),
3011
+ onBlur: onCheckboxBlur,
2409
3012
  "aria-describedby": errorMessageId
2410
3013
  })
2411
3014
  }, `${id}-${index}`);
@@ -2418,7 +3021,7 @@ function Checklist(props) {
2418
3021
  });
2419
3022
  }
2420
3023
  Checklist.config = {
2421
- type: type$9,
3024
+ type: type$a,
2422
3025
  keyed: true,
2423
3026
  label: 'Checklist',
2424
3027
  group: 'selection',
@@ -2448,8 +3051,10 @@ function FormField(props) {
2448
3051
  onChange
2449
3052
  } = props;
2450
3053
  const formFields = useService('formFields'),
3054
+ viewerCommands = useService('viewerCommands', false),
2451
3055
  form = useService('form');
2452
3056
  const {
3057
+ initialData,
2453
3058
  data,
2454
3059
  errors,
2455
3060
  properties
@@ -2463,12 +3068,23 @@ function FormField(props) {
2463
3068
  if (!FormFieldComponent) {
2464
3069
  throw new Error(`cannot render field <${field.type}>`);
2465
3070
  }
3071
+ const initialValue = useMemo(() => get(initialData, field._path), [initialData, field._path]);
2466
3072
  const value = get(data, field._path);
2467
3073
  const fieldErrors = findErrors(errors, field._path);
2468
3074
  const readonly = useReadonly(field, properties);
2469
3075
 
2470
3076
  // add precedence: global readonly > form field disabled
2471
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]);
2472
3088
  const hidden = useCondition(field.conditional && field.conditional.hide || null);
2473
3089
  if (hidden) {
2474
3090
  return jsx(Empty, {});
@@ -2484,6 +3100,7 @@ function FormField(props) {
2484
3100
  disabled: disabled,
2485
3101
  errors: fieldErrors,
2486
3102
  onChange: disabled || readonly ? noop$1 : onChange,
3103
+ onBlur: disabled || readonly ? noop$1 : onBlur,
2487
3104
  readonly: readonly,
2488
3105
  value: value
2489
3106
  })
@@ -2546,16 +3163,16 @@ Default.config = {
2546
3163
  })
2547
3164
  };
2548
3165
 
2549
- var _path$g;
2550
- 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); }
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); }
2551
3168
  var SvgCalendar = function SvgCalendar(props) {
2552
- return /*#__PURE__*/React.createElement("svg", _extends$j({
3169
+ return /*#__PURE__*/React.createElement("svg", _extends$k({
2553
3170
  xmlns: "http://www.w3.org/2000/svg",
2554
3171
  width: 14,
2555
3172
  height: 15,
2556
3173
  fill: "none",
2557
3174
  viewBox: "0 0 28 30"
2558
- }, props), _path$g || (_path$g = /*#__PURE__*/React.createElement("path", {
3175
+ }, props), _path$h || (_path$h = /*#__PURE__*/React.createElement("path", {
2559
3176
  fill: "currentColor",
2560
3177
  fillRule: "evenodd",
2561
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",
@@ -2607,6 +3224,7 @@ function Datepicker(props) {
2607
3224
  id,
2608
3225
  label,
2609
3226
  collapseLabelOnEmpty,
3227
+ onDateTimeBlur,
2610
3228
  formId,
2611
3229
  required,
2612
3230
  disabled,
@@ -2701,7 +3319,8 @@ function Datepicker(props) {
2701
3319
  if (!isInputDirty || e.relatedTarget && e.relatedTarget.classList.contains('flatpickr-day')) return;
2702
3320
  dateInputRef.current.dispatchEvent(ENTER_KEYDOWN_EVENT);
2703
3321
  setIsInputDirty(false);
2704
- }, [isInputDirty]);
3322
+ onDateTimeBlur(e);
3323
+ }, [isInputDirty, onDateTimeBlur]);
2705
3324
  const fullId = `${prefixId(id, formId)}--date`;
2706
3325
  return jsxs("div", {
2707
3326
  class: "fjs-datetime-subsection",
@@ -2743,19 +3362,19 @@ function Datepicker(props) {
2743
3362
  });
2744
3363
  }
2745
3364
 
2746
- var _path$f, _path2$3;
2747
- 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); }
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); }
2748
3367
  var SvgClock = function SvgClock(props) {
2749
- return /*#__PURE__*/React.createElement("svg", _extends$i({
3368
+ return /*#__PURE__*/React.createElement("svg", _extends$j({
2750
3369
  xmlns: "http://www.w3.org/2000/svg",
2751
3370
  width: 16,
2752
3371
  height: 16,
2753
3372
  fill: "none",
2754
3373
  viewBox: "0 0 28 29"
2755
- }, props), _path$f || (_path$f = /*#__PURE__*/React.createElement("path", {
3374
+ }, props), _path$g || (_path$g = /*#__PURE__*/React.createElement("path", {
2756
3375
  fill: "currentColor",
2757
3376
  d: "M13 14.41 18.59 20 20 18.59l-5-5.01V5h-2v9.41Z"
2758
- })), _path2$3 || (_path2$3 = /*#__PURE__*/React.createElement("path", {
3377
+ })), _path2$4 || (_path2$4 = /*#__PURE__*/React.createElement("path", {
2759
3378
  fill: "currentColor",
2760
3379
  fillRule: "evenodd",
2761
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",
@@ -2864,6 +3483,7 @@ function Timepicker(props) {
2864
3483
  id,
2865
3484
  label,
2866
3485
  collapseLabelOnEmpty,
3486
+ onDateTimeBlur,
2867
3487
  formId,
2868
3488
  required,
2869
3489
  disabled,
@@ -2963,6 +3583,7 @@ function Timepicker(props) {
2963
3583
  const onInputBlur = e => {
2964
3584
  setDropdownIsOpen(false);
2965
3585
  propagateRawToMinute();
3586
+ onDateTimeBlur(e);
2966
3587
  };
2967
3588
  const onDropdownValueSelected = value => {
2968
3589
  setDropdownIsOpen(false);
@@ -3018,11 +3639,12 @@ function Timepicker(props) {
3018
3639
  });
3019
3640
  }
3020
3641
 
3021
- const type$8 = 'datetime';
3642
+ const type$9 = 'datetime';
3022
3643
  function Datetime(props) {
3023
3644
  const {
3024
3645
  disabled,
3025
3646
  errors = [],
3647
+ onBlur,
3026
3648
  field,
3027
3649
  onChange,
3028
3650
  readonly,
@@ -3046,6 +3668,7 @@ function Datetime(props) {
3046
3668
  const {
3047
3669
  formId
3048
3670
  } = useContext(FormContext$1);
3671
+ const dateTimeGroupRef = useRef();
3049
3672
  const getNullDateTime = () => ({
3050
3673
  date: new Date(Date.parse(null)),
3051
3674
  time: null
@@ -3056,6 +3679,12 @@ function Datetime(props) {
3056
3679
  const isValidTime = time => !isNaN(parseInt(time));
3057
3680
  const useDatePicker = useMemo(() => subtype === DATETIME_SUBTYPES.DATE || subtype === DATETIME_SUBTYPES.DATETIME, [subtype]);
3058
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]);
3059
3688
  useEffect(() => {
3060
3689
  let {
3061
3690
  date,
@@ -3147,6 +3776,7 @@ function Datetime(props) {
3147
3776
  id,
3148
3777
  label: dateLabel,
3149
3778
  collapseLabelOnEmpty: !timeLabel,
3779
+ onDateTimeBlur,
3150
3780
  formId,
3151
3781
  required,
3152
3782
  disabled,
@@ -3160,6 +3790,7 @@ function Datetime(props) {
3160
3790
  id,
3161
3791
  label: timeLabel,
3162
3792
  collapseLabelOnEmpty: !dateLabel,
3793
+ onDateTimeBlur,
3163
3794
  formId,
3164
3795
  required,
3165
3796
  disabled,
@@ -3171,13 +3802,14 @@ function Datetime(props) {
3171
3802
  'aria-describedby': errorMessageId
3172
3803
  };
3173
3804
  return jsxs("div", {
3174
- class: formFieldClasses(type$8, {
3805
+ class: formFieldClasses(type$9, {
3175
3806
  errors: allErrors,
3176
3807
  disabled,
3177
3808
  readonly
3178
3809
  }),
3179
3810
  children: [jsxs("div", {
3180
3811
  class: classNames('fjs-vertical-group'),
3812
+ ref: dateTimeGroupRef,
3181
3813
  children: [useDatePicker && jsx(Datepicker, {
3182
3814
  ...datePickerProps
3183
3815
  }), useTimePicker && useDatePicker && jsx("div", {
@@ -3194,7 +3826,7 @@ function Datetime(props) {
3194
3826
  });
3195
3827
  }
3196
3828
  Datetime.config = {
3197
- type: type$8,
3829
+ type: type$9,
3198
3830
  keyed: true,
3199
3831
  label: 'Date time',
3200
3832
  group: 'basic-input',
@@ -3463,9 +4095,9 @@ function isValidAttribute(lcTag, lcName, value) {
3463
4095
  return true;
3464
4096
  }
3465
4097
 
3466
- 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); }
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); }
3467
4099
  var SvgImagePlaceholder = function SvgImagePlaceholder(props) {
3468
- return /*#__PURE__*/React.createElement("svg", _extends$h({
4100
+ return /*#__PURE__*/React.createElement("svg", _extends$i({
3469
4101
  xmlns: "http://www.w3.org/2000/svg",
3470
4102
  xmlSpace: "preserve",
3471
4103
  width: 64,
@@ -3504,7 +4136,7 @@ var SvgImagePlaceholder = function SvgImagePlaceholder(props) {
3504
4136
  };
3505
4137
  var ImagePlaceholder = SvgImagePlaceholder;
3506
4138
 
3507
- const type$7 = 'image';
4139
+ const type$8 = 'image';
3508
4140
  function Image(props) {
3509
4141
  const {
3510
4142
  field
@@ -3525,7 +4157,7 @@ function Image(props) {
3525
4157
  formId
3526
4158
  } = useContext(FormContext$1);
3527
4159
  return jsx("div", {
3528
- class: formFieldClasses(type$7),
4160
+ class: formFieldClasses(type$8),
3529
4161
  children: jsxs("div", {
3530
4162
  class: "fjs-image-container",
3531
4163
  children: [safeSource && jsx("img", {
@@ -3543,7 +4175,7 @@ function Image(props) {
3543
4175
  });
3544
4176
  }
3545
4177
  Image.config = {
3546
- type: type$7,
4178
+ type: type$8,
3547
4179
  keyed: false,
3548
4180
  label: 'Image view',
3549
4181
  group: 'presentation',
@@ -3570,14 +4202,14 @@ function TemplatedInputAdorner(props) {
3570
4202
  });
3571
4203
  }
3572
4204
 
3573
- var _path$e;
3574
- 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); }
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); }
3575
4207
  var SvgAngelDown = function SvgAngelDown(props) {
3576
- return /*#__PURE__*/React.createElement("svg", _extends$g({
4208
+ return /*#__PURE__*/React.createElement("svg", _extends$h({
3577
4209
  xmlns: "http://www.w3.org/2000/svg",
3578
4210
  width: 8,
3579
4211
  height: 8
3580
- }, props), _path$e || (_path$e = /*#__PURE__*/React.createElement("path", {
4212
+ }, props), _path$f || (_path$f = /*#__PURE__*/React.createElement("path", {
3581
4213
  fill: "currentColor",
3582
4214
  fillRule: "evenodd",
3583
4215
  stroke: "currentColor",
@@ -3588,14 +4220,14 @@ var SvgAngelDown = function SvgAngelDown(props) {
3588
4220
  };
3589
4221
  var AngelDownIcon = SvgAngelDown;
3590
4222
 
3591
- var _path$d;
3592
- 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); }
4223
+ var _path$e;
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); }
3593
4225
  var SvgAngelUp = function SvgAngelUp(props) {
3594
- return /*#__PURE__*/React.createElement("svg", _extends$f({
4226
+ return /*#__PURE__*/React.createElement("svg", _extends$g({
3595
4227
  xmlns: "http://www.w3.org/2000/svg",
3596
4228
  width: 8,
3597
4229
  height: 8
3598
- }, props), _path$d || (_path$d = /*#__PURE__*/React.createElement("path", {
4230
+ }, props), _path$e || (_path$e = /*#__PURE__*/React.createElement("path", {
3599
4231
  fill: "currentColor",
3600
4232
  fillRule: "evenodd",
3601
4233
  stroke: "currentColor",
@@ -3606,11 +4238,12 @@ var SvgAngelUp = function SvgAngelUp(props) {
3606
4238
  };
3607
4239
  var AngelUpIcon = SvgAngelUp;
3608
4240
 
3609
- const type$6 = 'number';
4241
+ const type$7 = 'number';
3610
4242
  function Numberfield(props) {
3611
4243
  const {
3612
4244
  disabled,
3613
4245
  errors = [],
4246
+ onBlur,
3614
4247
  field,
3615
4248
  value,
3616
4249
  readonly,
@@ -3743,7 +4376,7 @@ function Numberfield(props) {
3743
4376
  } = useContext(FormContext$1);
3744
4377
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3745
4378
  return jsxs("div", {
3746
- class: formFieldClasses(type$6, {
4379
+ class: formFieldClasses(type$7, {
3747
4380
  errors,
3748
4381
  disabled,
3749
4382
  readonly
@@ -3771,7 +4404,8 @@ function Numberfield(props) {
3771
4404
  readOnly: readonly,
3772
4405
  id: prefixId(id, formId),
3773
4406
  onKeyDown: onKeyDown,
3774
- onKeyPress: onKeyPress
4407
+ onKeyPress: onKeyPress,
4408
+ onBlur: onBlur
3775
4409
 
3776
4410
  // @ts-ignore
3777
4411
  ,
@@ -3814,7 +4448,7 @@ function Numberfield(props) {
3814
4448
  });
3815
4449
  }
3816
4450
  Numberfield.config = {
3817
- type: type$6,
4451
+ type: type$7,
3818
4452
  keyed: true,
3819
4453
  label: 'Number',
3820
4454
  group: 'basic-input',
@@ -3837,11 +4471,12 @@ Numberfield.config = {
3837
4471
  })
3838
4472
  };
3839
4473
 
3840
- const type$5 = 'radio';
4474
+ const type$6 = 'radio';
3841
4475
  function Radio(props) {
3842
4476
  const {
3843
4477
  disabled,
3844
4478
  errors = [],
4479
+ onBlur,
3845
4480
  field,
3846
4481
  readonly,
3847
4482
  value
@@ -3852,6 +4487,7 @@ function Radio(props) {
3852
4487
  label,
3853
4488
  validate = {}
3854
4489
  } = field;
4490
+ const outerDivRef = useRef();
3855
4491
  const {
3856
4492
  required
3857
4493
  } = validate;
@@ -3861,6 +4497,12 @@ function Radio(props) {
3861
4497
  value: v
3862
4498
  });
3863
4499
  };
4500
+ const onRadioBlur = e => {
4501
+ if (outerDivRef.current.contains(e.relatedTarget)) {
4502
+ return;
4503
+ }
4504
+ onBlur();
4505
+ };
3864
4506
  const {
3865
4507
  state: loadState,
3866
4508
  values: options
@@ -3870,11 +4512,12 @@ function Radio(props) {
3870
4512
  } = useContext(FormContext$1);
3871
4513
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3872
4514
  return jsxs("div", {
3873
- class: formFieldClasses(type$5, {
4515
+ class: formFieldClasses(type$6, {
3874
4516
  errors,
3875
4517
  disabled,
3876
4518
  readonly
3877
4519
  }),
4520
+ ref: outerDivRef,
3878
4521
  children: [jsx(Label, {
3879
4522
  label: label,
3880
4523
  required: required
@@ -3894,6 +4537,7 @@ function Radio(props) {
3894
4537
  id: prefixId(`${id}-${index}`, formId),
3895
4538
  type: "radio",
3896
4539
  onClick: () => onChange(option.value),
4540
+ onBlur: onRadioBlur,
3897
4541
  "aria-describedby": errorMessageId
3898
4542
  })
3899
4543
  }, `${id}-${index}`);
@@ -3906,7 +4550,7 @@ function Radio(props) {
3906
4550
  });
3907
4551
  }
3908
4552
  Radio.config = {
3909
- type: type$5,
4553
+ type: type$6,
3910
4554
  keyed: true,
3911
4555
  label: 'Radio',
3912
4556
  group: 'selection',
@@ -3929,14 +4573,14 @@ Radio.config = {
3929
4573
  }
3930
4574
  };
3931
4575
 
3932
- var _path$c;
3933
- 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); }
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); }
3934
4578
  var SvgXMark = function SvgXMark(props) {
3935
- return /*#__PURE__*/React.createElement("svg", _extends$e({
4579
+ return /*#__PURE__*/React.createElement("svg", _extends$f({
3936
4580
  xmlns: "http://www.w3.org/2000/svg",
3937
4581
  width: 8,
3938
4582
  height: 8
3939
- }, props), _path$c || (_path$c = /*#__PURE__*/React.createElement("path", {
4583
+ }, props), _path$d || (_path$d = /*#__PURE__*/React.createElement("path", {
3940
4584
  fill: "currentColor",
3941
4585
  fillRule: "evenodd",
3942
4586
  stroke: "currentColor",
@@ -3952,6 +4596,7 @@ function SearchableSelect(props) {
3952
4596
  id,
3953
4597
  disabled,
3954
4598
  errors,
4599
+ onBlur,
3955
4600
  field,
3956
4601
  readonly,
3957
4602
  value
@@ -4071,6 +4716,7 @@ function SearchableSelect(props) {
4071
4716
  onBlur: () => {
4072
4717
  setIsDropdownExpanded(false);
4073
4718
  setFilter(valueLabel);
4719
+ onBlur();
4074
4720
  },
4075
4721
  "aria-describedby": props['aria-describedby']
4076
4722
  }), displayState.displayCross && jsxs("span", {
@@ -4105,6 +4751,7 @@ function SimpleSelect(props) {
4105
4751
  id,
4106
4752
  disabled,
4107
4753
  errors,
4754
+ onBlur,
4108
4755
  field,
4109
4756
  readonly,
4110
4757
  value
@@ -4159,7 +4806,10 @@ function SimpleSelect(props) {
4159
4806
  'hasErrors': errors.length
4160
4807
  }),
4161
4808
  onFocus: () => setIsDropdownExpanded(true),
4162
- onBlur: () => setIsDropdownExpanded(false),
4809
+ onBlur: () => {
4810
+ setIsDropdownExpanded(false);
4811
+ onBlur();
4812
+ },
4163
4813
  onMouseDown: onMouseDown,
4164
4814
  children: [jsx("div", {
4165
4815
  class: classNames('fjs-select-display', {
@@ -4201,11 +4851,12 @@ function SimpleSelect(props) {
4201
4851
  });
4202
4852
  }
4203
4853
 
4204
- const type$4 = 'select';
4854
+ const type$5 = 'select';
4205
4855
  function Select(props) {
4206
4856
  const {
4207
4857
  disabled,
4208
4858
  errors = [],
4859
+ onBlur,
4209
4860
  field,
4210
4861
  onChange,
4211
4862
  readonly,
@@ -4229,14 +4880,15 @@ function Select(props) {
4229
4880
  id,
4230
4881
  disabled,
4231
4882
  errors,
4883
+ onBlur,
4232
4884
  field,
4233
4885
  value,
4234
4886
  onChange,
4235
4887
  readonly,
4236
4888
  'aria-describedby': errorMessageId
4237
- }), [disabled, errors, field, id, value, onChange, readonly, errorMessageId]);
4889
+ }), [disabled, errors, field, id, value, onChange, onBlur, readonly, errorMessageId]);
4238
4890
  return jsxs("div", {
4239
- class: formFieldClasses(type$4, {
4891
+ class: formFieldClasses(type$5, {
4240
4892
  errors,
4241
4893
  disabled,
4242
4894
  readonly
@@ -4264,7 +4916,7 @@ function Select(props) {
4264
4916
  });
4265
4917
  }
4266
4918
  Select.config = {
4267
- type: type$4,
4919
+ type: type$5,
4268
4920
  keyed: true,
4269
4921
  label: 'Select',
4270
4922
  group: 'selection',
@@ -4287,11 +4939,38 @@ Select.config = {
4287
4939
  }
4288
4940
  };
4289
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
+
4290
4968
  const type$3 = 'taglist';
4291
4969
  function Taglist(props) {
4292
4970
  const {
4293
4971
  disabled,
4294
4972
  errors = [],
4973
+ onBlur,
4295
4974
  field,
4296
4975
  readonly,
4297
4976
  value: values = []
@@ -4384,9 +5063,10 @@ function Taglist(props) {
4384
5063
  break;
4385
5064
  }
4386
5065
  };
4387
- const onBlur = () => {
5066
+ const onComponentBlur = () => {
4388
5067
  setIsDropdownExpanded(false);
4389
5068
  setFilter('');
5069
+ onBlur();
4390
5070
  };
4391
5071
  const onTagRemoveClick = (event, value) => {
4392
5072
  const {
@@ -4457,9 +5137,7 @@ function Taglist(props) {
4457
5137
  onKeyDown: onInputKeyDown,
4458
5138
  onMouseDown: () => setIsEscapeClose(false),
4459
5139
  onFocus: () => !readonly && setIsDropdownExpanded(true),
4460
- onBlur: () => {
4461
- !readonly && onBlur();
4462
- },
5140
+ onBlur: () => !readonly && onComponentBlur(),
4463
5141
  "aria-describedby": errorMessageId
4464
5142
  })]
4465
5143
  }), jsx("div", {
@@ -4592,6 +5270,7 @@ function Textfield(props) {
4592
5270
  const {
4593
5271
  disabled,
4594
5272
  errors = [],
5273
+ onBlur,
4595
5274
  field,
4596
5275
  readonly,
4597
5276
  value = ''
@@ -4643,6 +5322,7 @@ function Textfield(props) {
4643
5322
  readOnly: readonly,
4644
5323
  id: prefixId(id, formId),
4645
5324
  onInput: onChange,
5325
+ onBlur: onBlur,
4646
5326
  type: "text",
4647
5327
  value: value,
4648
5328
  "aria-describedby": errorMessageId
@@ -4684,6 +5364,7 @@ function Textarea(props) {
4684
5364
  const {
4685
5365
  disabled,
4686
5366
  errors = [],
5367
+ onBlur,
4687
5368
  field,
4688
5369
  readonly,
4689
5370
  value = ''
@@ -4706,22 +5387,12 @@ function Textarea(props) {
4706
5387
  value: target.value
4707
5388
  });
4708
5389
  };
4709
- const autoSizeTextarea = useCallback(textarea => {
4710
- // Ensures the textarea shrinks back, and improves resizing behavior consistency
4711
- textarea.style.height = '0px';
4712
- const computed = window.getComputedStyle(textarea);
4713
- 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'));
4714
- const minHeight = 75;
4715
- const maxHeight = 350;
4716
- const displayHeight = Math.max(Math.min(calculatedHeight, maxHeight), minHeight);
4717
- textarea.style.height = `${displayHeight}px`;
4718
-
4719
- // Overflow is hidden by default to hide scrollbar flickering
4720
- textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
4721
- }, []);
5390
+ useLayoutEffect(() => {
5391
+ autoSizeTextarea(textareaRef.current);
5392
+ }, [value]);
4722
5393
  useEffect(() => {
4723
5394
  autoSizeTextarea(textareaRef.current);
4724
- }, [autoSizeTextarea, value]);
5395
+ }, []);
4725
5396
  const {
4726
5397
  formId
4727
5398
  } = useContext(FormContext$1);
@@ -4742,6 +5413,7 @@ function Textarea(props) {
4742
5413
  readonly: readonly,
4743
5414
  id: prefixId(id, formId),
4744
5415
  onInput: onInput,
5416
+ onBlur: onBlur,
4745
5417
  value: value,
4746
5418
  ref: textareaRef,
4747
5419
  "aria-describedby": errorMessageId
@@ -4766,40 +5438,58 @@ Textarea.config = {
4766
5438
  ...options
4767
5439
  })
4768
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
+ };
4769
5459
 
4770
- var _path$b;
4771
- 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); }
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); }
4772
5462
  var SvgButton = function SvgButton(props) {
4773
- return /*#__PURE__*/React.createElement("svg", _extends$d({
5463
+ return /*#__PURE__*/React.createElement("svg", _extends$e({
4774
5464
  xmlns: "http://www.w3.org/2000/svg",
4775
5465
  width: 54,
4776
5466
  height: 54,
4777
5467
  fill: "currentcolor"
4778
- }, props), _path$b || (_path$b = /*#__PURE__*/React.createElement("path", {
5468
+ }, props), _path$c || (_path$c = /*#__PURE__*/React.createElement("path", {
4779
5469
  fillRule: "evenodd",
4780
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"
4781
5471
  })));
4782
5472
  };
4783
5473
  var ButtonIcon = SvgButton;
4784
5474
 
4785
- var _path$a;
4786
- 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); }
5475
+ var _path$b;
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); }
4787
5477
  var SvgCheckbox = function SvgCheckbox(props) {
4788
- return /*#__PURE__*/React.createElement("svg", _extends$c({
5478
+ return /*#__PURE__*/React.createElement("svg", _extends$d({
4789
5479
  xmlns: "http://www.w3.org/2000/svg",
4790
5480
  width: 54,
4791
5481
  height: 54,
4792
5482
  fill: "currentcolor"
4793
- }, props), _path$a || (_path$a = /*#__PURE__*/React.createElement("path", {
5483
+ }, props), _path$b || (_path$b = /*#__PURE__*/React.createElement("path", {
4794
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"
4795
5485
  })));
4796
5486
  };
4797
5487
  var CheckboxIcon = SvgCheckbox;
4798
5488
 
4799
5489
  var _g, _use, _use2, _use3, _defs;
4800
- 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); }
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); }
4801
5491
  var SvgChecklist = function SvgChecklist(props) {
4802
- return /*#__PURE__*/React.createElement("svg", _extends$b({
5492
+ return /*#__PURE__*/React.createElement("svg", _extends$c({
4803
5493
  xmlns: "http://www.w3.org/2000/svg",
4804
5494
  xmlnsXlink: "http://www.w3.org/1999/xlink",
4805
5495
  width: 54,
@@ -4833,18 +5523,18 @@ var SvgChecklist = function SvgChecklist(props) {
4833
5523
  };
4834
5524
  var ChecklistIcon = SvgChecklist;
4835
5525
 
4836
- var _path$9, _path2$2, _path3;
4837
- 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); }
5526
+ var _path$a, _path2$3, _path3;
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); }
4838
5528
  var SvgDatetime = function SvgDatetime(props) {
4839
- return /*#__PURE__*/React.createElement("svg", _extends$a({
5529
+ return /*#__PURE__*/React.createElement("svg", _extends$b({
4840
5530
  xmlns: "http://www.w3.org/2000/svg",
4841
5531
  width: 54,
4842
5532
  height: 54,
4843
5533
  fill: "currentcolor"
4844
- }, props), _path$9 || (_path$9 = /*#__PURE__*/React.createElement("path", {
5534
+ }, props), _path$a || (_path$a = /*#__PURE__*/React.createElement("path", {
4845
5535
  fillRule: "evenodd",
4846
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"
4847
- })), _path2$2 || (_path2$2 = /*#__PURE__*/React.createElement("path", {
5537
+ })), _path2$3 || (_path2$3 = /*#__PURE__*/React.createElement("path", {
4848
5538
  d: "m35.13 37.603 1.237-1.237-3.468-3.475v-5.926h-1.754v6.654l3.984 3.984Z"
4849
5539
  })), _path3 || (_path3 = /*#__PURE__*/React.createElement("path", {
4850
5540
  fillRule: "evenodd",
@@ -4853,27 +5543,27 @@ var SvgDatetime = function SvgDatetime(props) {
4853
5543
  };
4854
5544
  var DatetimeIcon = SvgDatetime;
4855
5545
 
4856
- var _path$8, _path2$1;
4857
- 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); }
5546
+ var _path$9, _path2$2;
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); }
4858
5548
  var SvgTaglist = function SvgTaglist(props) {
4859
- return /*#__PURE__*/React.createElement("svg", _extends$9({
5549
+ return /*#__PURE__*/React.createElement("svg", _extends$a({
4860
5550
  xmlns: "http://www.w3.org/2000/svg",
4861
5551
  width: 54,
4862
5552
  height: 54,
4863
5553
  fill: "currentcolor"
4864
- }, props), _path$8 || (_path$8 = /*#__PURE__*/React.createElement("path", {
5554
+ }, props), _path$9 || (_path$9 = /*#__PURE__*/React.createElement("path", {
4865
5555
  fillRule: "evenodd",
4866
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"
4867
- })), _path2$1 || (_path2$1 = /*#__PURE__*/React.createElement("path", {
5557
+ })), _path2$2 || (_path2$2 = /*#__PURE__*/React.createElement("path", {
4868
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"
4869
5559
  })));
4870
5560
  };
4871
5561
  var TaglistIcon = SvgTaglist;
4872
5562
 
4873
5563
  var _rect, _rect2, _rect3;
4874
- 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); }
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); }
4875
5565
  var SvgForm = function SvgForm(props) {
4876
- return /*#__PURE__*/React.createElement("svg", _extends$8({
5566
+ return /*#__PURE__*/React.createElement("svg", _extends$9({
4877
5567
  xmlns: "http://www.w3.org/2000/svg",
4878
5568
  width: 54,
4879
5569
  height: 54
@@ -4899,64 +5589,87 @@ var SvgForm = function SvgForm(props) {
4899
5589
  };
4900
5590
  var FormIcon = SvgForm;
4901
5591
 
4902
- var _path$7;
4903
- 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); }
5592
+ var _path$8;
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); }
4904
5594
  var SvgGroup = function SvgGroup(props) {
4905
- return /*#__PURE__*/React.createElement("svg", _extends$7({
5595
+ return /*#__PURE__*/React.createElement("svg", _extends$8({
4906
5596
  xmlns: "http://www.w3.org/2000/svg",
4907
5597
  width: 54,
4908
5598
  height: 54
4909
- }, props), _path$7 || (_path$7 = /*#__PURE__*/React.createElement("path", {
5599
+ }, props), _path$8 || (_path$8 = /*#__PURE__*/React.createElement("path", {
4910
5600
  fillRule: "evenodd",
4911
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"
4912
5602
  })));
4913
5603
  };
4914
5604
  var ColumnsIcon = SvgGroup;
4915
5605
 
4916
- var _path$6;
4917
- 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); }
5606
+ var _path$7;
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); }
4918
5608
  var SvgNumber = function SvgNumber(props) {
4919
- return /*#__PURE__*/React.createElement("svg", _extends$6({
5609
+ return /*#__PURE__*/React.createElement("svg", _extends$7({
4920
5610
  xmlns: "http://www.w3.org/2000/svg",
4921
5611
  width: 54,
4922
5612
  height: 54,
4923
5613
  fill: "currentcolor"
4924
- }, props), _path$6 || (_path$6 = /*#__PURE__*/React.createElement("path", {
5614
+ }, props), _path$7 || (_path$7 = /*#__PURE__*/React.createElement("path", {
4925
5615
  fillRule: "evenodd",
4926
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"
4927
5617
  })));
4928
5618
  };
4929
5619
  var NumberIcon = SvgNumber;
4930
5620
 
4931
- var _path$5;
4932
- 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); }
5621
+ var _path$6;
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); }
4933
5623
  var SvgRadio = function SvgRadio(props) {
4934
- return /*#__PURE__*/React.createElement("svg", _extends$5({
5624
+ return /*#__PURE__*/React.createElement("svg", _extends$6({
4935
5625
  xmlns: "http://www.w3.org/2000/svg",
4936
5626
  width: 54,
4937
5627
  height: 54,
4938
5628
  fill: "currentcolor"
4939
- }, props), _path$5 || (_path$5 = /*#__PURE__*/React.createElement("path", {
5629
+ }, props), _path$6 || (_path$6 = /*#__PURE__*/React.createElement("path", {
4940
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"
4941
5631
  })));
4942
5632
  };
4943
5633
  var RadioIcon = SvgRadio;
4944
5634
 
4945
- var _path$4;
4946
- 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); }
5635
+ var _path$5;
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); }
4947
5637
  var SvgSelect = function SvgSelect(props) {
4948
- return /*#__PURE__*/React.createElement("svg", _extends$4({
5638
+ return /*#__PURE__*/React.createElement("svg", _extends$5({
4949
5639
  xmlns: "http://www.w3.org/2000/svg",
4950
5640
  width: 54,
4951
5641
  height: 54,
4952
5642
  fill: "currentcolor"
4953
- }, props), _path$4 || (_path$4 = /*#__PURE__*/React.createElement("path", {
5643
+ }, props), _path$5 || (_path$5 = /*#__PURE__*/React.createElement("path", {
4954
5644
  fillRule: "evenodd",
4955
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"
4956
5646
  })));
4957
5647
  };
4958
5648
  var SelectIcon = SvgSelect;
4959
5649
 
5650
+ var _path$4, _path2$1;
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); }
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;
5672
+
4960
5673
  var _path$3;
4961
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); }
4962
5675
  var SvgText = function SvgText(props) {
@@ -5032,6 +5745,7 @@ const iconsByType = type => {
5032
5745
  number: NumberIcon,
5033
5746
  radio: RadioIcon,
5034
5747
  select: SelectIcon,
5748
+ spacer: SpacerIcon,
5035
5749
  taglist: TaglistIcon,
5036
5750
  text: TextIcon,
5037
5751
  textfield: TextfieldIcon,
@@ -5040,7 +5754,7 @@ const iconsByType = type => {
5040
5754
  }[type];
5041
5755
  };
5042
5756
 
5043
- 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];
5044
5758
 
5045
5759
  class FormFields {
5046
5760
  constructor() {
@@ -5451,7 +6165,7 @@ class Form {
5451
6165
  * @internal
5452
6166
  */
5453
6167
  _getModules() {
5454
- return [ExpressionLanguageModule, MarkdownModule];
6168
+ return [ExpressionLanguageModule, MarkdownModule, ViewerCommandsModule];
5455
6169
  }
5456
6170
 
5457
6171
  /**
@@ -5496,7 +6210,7 @@ class Form {
5496
6210
  }
5497
6211
  }
5498
6212
 
5499
- const schemaVersion = 9;
6213
+ const schemaVersion = 10;
5500
6214
 
5501
6215
  /**
5502
6216
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
@@ -5521,5 +6235,5 @@ function createForm(options) {
5521
6235
  });
5522
6236
  }
5523
6237
 
5524
- 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 };
5525
6239
  //# sourceMappingURL=index.es.js.map