@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.cjs CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  var Ids = require('ids');
4
4
  var minDash = require('min-dash');
5
+ var Big = require('big.js');
5
6
  var feelin = require('feelin');
6
7
  var feelers = require('feelers');
7
- var showdown = require('showdown');
8
- var Big = require('big.js');
9
8
  var classNames = require('classnames');
10
9
  var jsxRuntime = require('preact/jsx-runtime');
11
10
  var hooks = require('preact/hooks');
@@ -14,6 +13,7 @@ var React = require('preact/compat');
14
13
  var flatpickr = require('flatpickr');
15
14
  var Markup = require('preact-markup');
16
15
  var didi = require('didi');
16
+ var showdown = require('showdown');
17
17
 
18
18
  function _interopNamespaceDefault(e) {
19
19
  var n = Object.create(null);
@@ -34,15 +34,15 @@ function _interopNamespaceDefault(e) {
34
34
 
35
35
  var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
36
36
 
37
- const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) => {
37
+ const getFlavouredFeelVariableNames = (feelString, feelFlavour = 'expression', options = {}) => {
38
38
  const {
39
39
  depth = 0,
40
40
  specialDepthAccessors = {}
41
41
  } = options;
42
42
  if (!['expression', 'unaryTest'].includes(feelFlavour)) return [];
43
- const tree = feelFlavour === 'expression' ? feelin.parseExpressions(feelString) : feelin.parseUnaryTests(feelString);
43
+ const tree = feelFlavour === 'expression' ? feelin.parseExpression(feelString) : feelin.parseUnaryTests(feelString);
44
44
  const simpleExpressionTree = _buildSimpleFeelStructureTree(tree, feelString);
45
- return function _unfoldVariables(node) {
45
+ const variables = function _unfoldVariables(node) {
46
46
  if (node.name === 'PathExpression') {
47
47
  if (Object.keys(specialDepthAccessors).length === 0) {
48
48
  return depth === 0 ? [_getVariableNameAtPathIndex(node, 0)] : [];
@@ -55,12 +55,16 @@ const getFlavouredFeelVariableNames = (feelString, feelFlavour, options = {}) =>
55
55
 
56
56
  // for any other kind of node, traverse its children and flatten the result
57
57
  if (node.children) {
58
- return node.children.reduce((acc, child) => {
58
+ const variables = node.children.reduce((acc, child) => {
59
59
  return acc.concat(_unfoldVariables(child));
60
60
  }, []);
61
+
62
+ // if we are within a filter context, we need to remove the item variable as it is used for iteration there
63
+ return node.name === 'FilterContext' ? variables.filter(name => name !== 'item') : variables;
61
64
  }
62
65
  return [];
63
66
  }(simpleExpressionTree);
67
+ return [...new Set(variables)];
64
68
  };
65
69
 
66
70
  /**
@@ -180,7 +184,45 @@ const _buildSimpleFeelStructureTree = (parseTree, feelString) => {
180
184
  parent.children.push(result);
181
185
  }
182
186
  });
183
- return stack[0].children[0];
187
+ return _extractFilterExpressions(stack[0].children[0]);
188
+ };
189
+
190
+ /**
191
+ * Restructure the tree in such a way to bring filters (which create new contexts) to the root of the tree.
192
+ * This is done to simplify the extraction of variables and match the context hierarchy.
193
+ */
194
+ const _extractFilterExpressions = tree => {
195
+ const flattenedExpressionTree = {
196
+ name: 'Root',
197
+ children: [tree]
198
+ };
199
+ const iterate = node => {
200
+ if (node.children) {
201
+ for (let x = 0; x < node.children.length; x++) {
202
+ if (node.children[x].name === 'FilterExpression') {
203
+ const filterTarget = node.children[x].children[0];
204
+ const filterExpression = node.children[x].children[2];
205
+
206
+ // bypass the filter expression
207
+ node.children[x] = filterTarget;
208
+ const taggedFilterExpression = {
209
+ name: 'FilterContext',
210
+ children: [filterExpression]
211
+ };
212
+
213
+ // append the filter expression to the root
214
+ flattenedExpressionTree.children.push(taggedFilterExpression);
215
+
216
+ // recursively iterate the expression
217
+ iterate(filterExpression);
218
+ } else {
219
+ iterate(node.children[x]);
220
+ }
221
+ }
222
+ }
223
+ };
224
+ iterate(tree);
225
+ return flattenedExpressionTree;
184
226
  };
185
227
 
186
228
  class FeelExpressionLanguage {
@@ -411,84 +453,816 @@ class ConditionChecker {
411
453
  if (!condition) {
412
454
  return null;
413
455
  }
414
- if (!minDash.isString(condition) || !condition.startsWith('=')) {
415
- return null;
456
+ if (!minDash.isString(condition) || !condition.startsWith('=')) {
457
+ return null;
458
+ }
459
+ try {
460
+ // cut off initial '='
461
+ const result = feelin.unaryTest(condition.slice(1), data);
462
+ return result;
463
+ } catch (error) {
464
+ this._eventBus.fire('error', {
465
+ error
466
+ });
467
+ return null;
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Check if hide condition is met.
473
+ *
474
+ * @param {Condition} condition
475
+ * @param {Object<string, any>} data
476
+ * @returns {boolean}
477
+ */
478
+ _checkHideCondition(condition, data) {
479
+ if (!condition.hide) {
480
+ return false;
481
+ }
482
+ const result = this.check(condition.hide, data);
483
+ return result === true;
484
+ }
485
+ _getConditions() {
486
+ const formFields = this._formFieldRegistry.getAll();
487
+ return formFields.reduce((conditions, formField) => {
488
+ const {
489
+ key,
490
+ conditional: condition
491
+ } = formField;
492
+ if (key && condition) {
493
+ return [...conditions, {
494
+ key,
495
+ condition
496
+ }];
497
+ }
498
+ return conditions;
499
+ }, []);
500
+ }
501
+ }
502
+ ConditionChecker.$inject = ['formFieldRegistry', 'eventBus'];
503
+
504
+ var ExpressionLanguageModule = {
505
+ __init__: ['expressionLanguage', 'templating', 'conditionChecker'],
506
+ expressionLanguage: ['type', FeelExpressionLanguage],
507
+ templating: ['type', FeelersTemplating],
508
+ conditionChecker: ['type', ConditionChecker]
509
+ };
510
+
511
+ // bootstrap showdown to support github flavored markdown
512
+ showdown.setFlavor('github');
513
+ class MarkdownRenderer {
514
+ constructor() {
515
+ this._converter = new showdown.Converter();
516
+ }
517
+
518
+ /**
519
+ * Render markdown to HTML.
520
+ *
521
+ * @param {string} markdown - The markdown to render
522
+ *
523
+ * @returns {string} HTML
524
+ */
525
+ render(markdown) {
526
+ return this._converter.makeHtml(markdown);
527
+ }
528
+ }
529
+ MarkdownRenderer.$inject = [];
530
+
531
+ var MarkdownModule = {
532
+ __init__: ['markdownRenderer'],
533
+ markdownRenderer: ['type', MarkdownRenderer]
534
+ };
535
+
536
+ /**
537
+ * @typedef {import('didi').Injector} Injector
538
+ *
539
+ * @typedef {import('../core/Types').ElementLike} ElementLike
540
+ *
541
+ * @typedef {import('../core/EventBus').default} EventBus
542
+ * @typedef {import('./CommandHandler').default} CommandHandler
543
+ *
544
+ * @typedef { any } CommandContext
545
+ * @typedef { {
546
+ * new (...args: any[]) : CommandHandler
547
+ * } } CommandHandlerConstructor
548
+ * @typedef { {
549
+ * [key: string]: CommandHandler;
550
+ * } } CommandHandlerMap
551
+ * @typedef { {
552
+ * command: string;
553
+ * context: any;
554
+ * id?: any;
555
+ * } } CommandStackAction
556
+ * @typedef { {
557
+ * actions: CommandStackAction[];
558
+ * dirty: ElementLike[];
559
+ * trigger: 'execute' | 'undo' | 'redo' | 'clear' | null;
560
+ * atomic?: boolean;
561
+ * } } CurrentExecution
562
+ */
563
+
564
+ /**
565
+ * A service that offers un- and redoable execution of commands.
566
+ *
567
+ * The command stack is responsible for executing modeling actions
568
+ * in a un- and redoable manner. To do this it delegates the actual
569
+ * command execution to {@link CommandHandler}s.
570
+ *
571
+ * Command handlers provide {@link CommandHandler#execute(ctx)} and
572
+ * {@link CommandHandler#revert(ctx)} methods to un- and redo a command
573
+ * identified by a command context.
574
+ *
575
+ *
576
+ * ## Life-Cycle events
577
+ *
578
+ * In the process the command stack fires a number of life-cycle events
579
+ * that other components to participate in the command execution.
580
+ *
581
+ * * preExecute
582
+ * * preExecuted
583
+ * * execute
584
+ * * executed
585
+ * * postExecute
586
+ * * postExecuted
587
+ * * revert
588
+ * * reverted
589
+ *
590
+ * A special event is used for validating, whether a command can be
591
+ * performed prior to its execution.
592
+ *
593
+ * * canExecute
594
+ *
595
+ * Each of the events is fired as `commandStack.{eventName}` and
596
+ * `commandStack.{commandName}.{eventName}`, respectively. This gives
597
+ * components fine grained control on where to hook into.
598
+ *
599
+ * The event object fired transports `command`, the name of the
600
+ * command and `context`, the command context.
601
+ *
602
+ *
603
+ * ## Creating Command Handlers
604
+ *
605
+ * Command handlers should provide the {@link CommandHandler#execute(ctx)}
606
+ * and {@link CommandHandler#revert(ctx)} methods to implement
607
+ * redoing and undoing of a command.
608
+ *
609
+ * A command handler _must_ ensure undo is performed properly in order
610
+ * not to break the undo chain. It must also return the shapes that
611
+ * got changed during the `execute` and `revert` operations.
612
+ *
613
+ * Command handlers may execute other modeling operations (and thus
614
+ * commands) in their `preExecute(d)` and `postExecute(d)` phases. The command
615
+ * stack will properly group all commands together into a logical unit
616
+ * that may be re- and undone atomically.
617
+ *
618
+ * Command handlers must not execute other commands from within their
619
+ * core implementation (`execute`, `revert`).
620
+ *
621
+ *
622
+ * ## Change Tracking
623
+ *
624
+ * During the execution of the CommandStack it will keep track of all
625
+ * elements that have been touched during the command's execution.
626
+ *
627
+ * At the end of the CommandStack execution it will notify interested
628
+ * components via an 'elements.changed' event with all the dirty
629
+ * elements.
630
+ *
631
+ * The event can be picked up by components that are interested in the fact
632
+ * that elements have been changed. One use case for this is updating
633
+ * their graphical representation after moving / resizing or deletion.
634
+ *
635
+ * @see CommandHandler
636
+ *
637
+ * @param {EventBus} eventBus
638
+ * @param {Injector} injector
639
+ */
640
+ function CommandStack(eventBus, injector) {
641
+ /**
642
+ * A map of all registered command handlers.
643
+ *
644
+ * @type {CommandHandlerMap}
645
+ */
646
+ this._handlerMap = {};
647
+
648
+ /**
649
+ * A stack containing all re/undoable actions on the diagram
650
+ *
651
+ * @type {CommandStackAction[]}
652
+ */
653
+ this._stack = [];
654
+
655
+ /**
656
+ * The current index on the stack
657
+ *
658
+ * @type {number}
659
+ */
660
+ this._stackIdx = -1;
661
+
662
+ /**
663
+ * Current active commandStack execution
664
+ *
665
+ * @type {CurrentExecution}
666
+ */
667
+ this._currentExecution = {
668
+ actions: [],
669
+ dirty: [],
670
+ trigger: null
671
+ };
672
+
673
+ /**
674
+ * @type {Injector}
675
+ */
676
+ this._injector = injector;
677
+
678
+ /**
679
+ * @type EventBus
680
+ */
681
+ this._eventBus = eventBus;
682
+
683
+ /**
684
+ * @type { number }
685
+ */
686
+ this._uid = 1;
687
+ eventBus.on(['diagram.destroy', 'diagram.clear'], function () {
688
+ this.clear(false);
689
+ }, this);
690
+ }
691
+ CommandStack.$inject = ['eventBus', 'injector'];
692
+
693
+ /**
694
+ * Execute a command.
695
+ *
696
+ * @param {string} command The command to execute.
697
+ * @param {CommandContext} context The context with which to execute the command.
698
+ */
699
+ CommandStack.prototype.execute = function (command, context) {
700
+ if (!command) {
701
+ throw new Error('command required');
702
+ }
703
+ this._currentExecution.trigger = 'execute';
704
+ const action = {
705
+ command: command,
706
+ context: context
707
+ };
708
+ this._pushAction(action);
709
+ this._internalExecute(action);
710
+ this._popAction();
711
+ };
712
+
713
+ /**
714
+ * Check whether a command can be executed.
715
+ *
716
+ * Implementors may hook into the mechanism on two ways:
717
+ *
718
+ * * in event listeners:
719
+ *
720
+ * Users may prevent the execution via an event listener.
721
+ * It must prevent the default action for `commandStack.(<command>.)canExecute` events.
722
+ *
723
+ * * in command handlers:
724
+ *
725
+ * If the method {@link CommandHandler#canExecute} is implemented in a handler
726
+ * it will be called to figure out whether the execution is allowed.
727
+ *
728
+ * @param {string} command The command to execute.
729
+ * @param {CommandContext} context The context with which to execute the command.
730
+ *
731
+ * @return {boolean} Whether the command can be executed with the given context.
732
+ */
733
+ CommandStack.prototype.canExecute = function (command, context) {
734
+ const action = {
735
+ command: command,
736
+ context: context
737
+ };
738
+ const handler = this._getHandler(command);
739
+ let result = this._fire(command, 'canExecute', action);
740
+
741
+ // handler#canExecute will only be called if no listener
742
+ // decided on a result already
743
+ if (result === undefined) {
744
+ if (!handler) {
745
+ return false;
746
+ }
747
+ if (handler.canExecute) {
748
+ result = handler.canExecute(context);
749
+ }
750
+ }
751
+ return result;
752
+ };
753
+
754
+ /**
755
+ * Clear the command stack, erasing all undo / redo history.
756
+ *
757
+ * @param {boolean} [emit=true] Whether to fire an event. Defaults to `true`.
758
+ */
759
+ CommandStack.prototype.clear = function (emit) {
760
+ this._stack.length = 0;
761
+ this._stackIdx = -1;
762
+ if (emit !== false) {
763
+ this._fire('changed', {
764
+ trigger: 'clear'
765
+ });
766
+ }
767
+ };
768
+
769
+ /**
770
+ * Undo last command(s)
771
+ */
772
+ CommandStack.prototype.undo = function () {
773
+ let action = this._getUndoAction(),
774
+ next;
775
+ if (action) {
776
+ this._currentExecution.trigger = 'undo';
777
+ this._pushAction(action);
778
+ while (action) {
779
+ this._internalUndo(action);
780
+ next = this._getUndoAction();
781
+ if (!next || next.id !== action.id) {
782
+ break;
783
+ }
784
+ action = next;
785
+ }
786
+ this._popAction();
787
+ }
788
+ };
789
+
790
+ /**
791
+ * Redo last command(s)
792
+ */
793
+ CommandStack.prototype.redo = function () {
794
+ let action = this._getRedoAction(),
795
+ next;
796
+ if (action) {
797
+ this._currentExecution.trigger = 'redo';
798
+ this._pushAction(action);
799
+ while (action) {
800
+ this._internalExecute(action, true);
801
+ next = this._getRedoAction();
802
+ if (!next || next.id !== action.id) {
803
+ break;
804
+ }
805
+ action = next;
806
+ }
807
+ this._popAction();
808
+ }
809
+ };
810
+
811
+ /**
812
+ * Register a handler instance with the command stack.
813
+ *
814
+ * @param {string} command Command to be executed.
815
+ * @param {CommandHandler} handler Handler to execute the command.
816
+ */
817
+ CommandStack.prototype.register = function (command, handler) {
818
+ this._setHandler(command, handler);
819
+ };
820
+
821
+ /**
822
+ * Register a handler type with the command stack by instantiating it and
823
+ * injecting its dependencies.
824
+ *
825
+ * @param {string} command Command to be executed.
826
+ * @param {CommandHandlerConstructor} handlerCls Constructor to instantiate a {@link CommandHandler}.
827
+ */
828
+ CommandStack.prototype.registerHandler = function (command, handlerCls) {
829
+ if (!command || !handlerCls) {
830
+ throw new Error('command and handlerCls must be defined');
831
+ }
832
+ const handler = this._injector.instantiate(handlerCls);
833
+ this.register(command, handler);
834
+ };
835
+
836
+ /**
837
+ * @return {boolean}
838
+ */
839
+ CommandStack.prototype.canUndo = function () {
840
+ return !!this._getUndoAction();
841
+ };
842
+
843
+ /**
844
+ * @return {boolean}
845
+ */
846
+ CommandStack.prototype.canRedo = function () {
847
+ return !!this._getRedoAction();
848
+ };
849
+
850
+ // stack access //////////////////////
851
+
852
+ CommandStack.prototype._getRedoAction = function () {
853
+ return this._stack[this._stackIdx + 1];
854
+ };
855
+ CommandStack.prototype._getUndoAction = function () {
856
+ return this._stack[this._stackIdx];
857
+ };
858
+
859
+ // internal functionality //////////////////////
860
+
861
+ CommandStack.prototype._internalUndo = function (action) {
862
+ const command = action.command,
863
+ context = action.context;
864
+ const handler = this._getHandler(command);
865
+
866
+ // guard against illegal nested command stack invocations
867
+ this._atomicDo(() => {
868
+ this._fire(command, 'revert', action);
869
+ if (handler.revert) {
870
+ this._markDirty(handler.revert(context));
871
+ }
872
+ this._revertedAction(action);
873
+ this._fire(command, 'reverted', action);
874
+ });
875
+ };
876
+ CommandStack.prototype._fire = function (command, qualifier, event) {
877
+ if (arguments.length < 3) {
878
+ event = qualifier;
879
+ qualifier = null;
880
+ }
881
+ const names = qualifier ? [command + '.' + qualifier, qualifier] : [command];
882
+ let result;
883
+ event = this._eventBus.createEvent(event);
884
+ for (const name of names) {
885
+ result = this._eventBus.fire('commandStack.' + name, event);
886
+ if (event.cancelBubble) {
887
+ break;
888
+ }
889
+ }
890
+ return result;
891
+ };
892
+ CommandStack.prototype._createId = function () {
893
+ return this._uid++;
894
+ };
895
+ CommandStack.prototype._atomicDo = function (fn) {
896
+ const execution = this._currentExecution;
897
+ execution.atomic = true;
898
+ try {
899
+ fn();
900
+ } finally {
901
+ execution.atomic = false;
902
+ }
903
+ };
904
+ CommandStack.prototype._internalExecute = function (action, redo) {
905
+ const command = action.command,
906
+ context = action.context;
907
+ const handler = this._getHandler(command);
908
+ if (!handler) {
909
+ throw new Error('no command handler registered for <' + command + '>');
910
+ }
911
+ this._pushAction(action);
912
+ if (!redo) {
913
+ this._fire(command, 'preExecute', action);
914
+ if (handler.preExecute) {
915
+ handler.preExecute(context);
916
+ }
917
+ this._fire(command, 'preExecuted', action);
918
+ }
919
+
920
+ // guard against illegal nested command stack invocations
921
+ this._atomicDo(() => {
922
+ this._fire(command, 'execute', action);
923
+ if (handler.execute) {
924
+ // actual execute + mark return results as dirty
925
+ this._markDirty(handler.execute(context));
926
+ }
927
+
928
+ // log to stack
929
+ this._executedAction(action, redo);
930
+ this._fire(command, 'executed', action);
931
+ });
932
+ if (!redo) {
933
+ this._fire(command, 'postExecute', action);
934
+ if (handler.postExecute) {
935
+ handler.postExecute(context);
936
+ }
937
+ this._fire(command, 'postExecuted', action);
938
+ }
939
+ this._popAction();
940
+ };
941
+ CommandStack.prototype._pushAction = function (action) {
942
+ const execution = this._currentExecution,
943
+ actions = execution.actions;
944
+ const baseAction = actions[0];
945
+ if (execution.atomic) {
946
+ throw new Error('illegal invocation in <execute> or <revert> phase (action: ' + action.command + ')');
947
+ }
948
+ if (!action.id) {
949
+ action.id = baseAction && baseAction.id || this._createId();
950
+ }
951
+ actions.push(action);
952
+ };
953
+ CommandStack.prototype._popAction = function () {
954
+ const execution = this._currentExecution,
955
+ trigger = execution.trigger,
956
+ actions = execution.actions,
957
+ dirty = execution.dirty;
958
+ actions.pop();
959
+ if (!actions.length) {
960
+ this._eventBus.fire('elements.changed', {
961
+ elements: minDash.uniqueBy('id', dirty.reverse())
962
+ });
963
+ dirty.length = 0;
964
+ this._fire('changed', {
965
+ trigger: trigger
966
+ });
967
+ execution.trigger = null;
968
+ }
969
+ };
970
+ CommandStack.prototype._markDirty = function (elements) {
971
+ const execution = this._currentExecution;
972
+ if (!elements) {
973
+ return;
974
+ }
975
+ elements = minDash.isArray(elements) ? elements : [elements];
976
+ execution.dirty = execution.dirty.concat(elements);
977
+ };
978
+ CommandStack.prototype._executedAction = function (action, redo) {
979
+ const stackIdx = ++this._stackIdx;
980
+ if (!redo) {
981
+ this._stack.splice(stackIdx, this._stack.length, action);
982
+ }
983
+ };
984
+ CommandStack.prototype._revertedAction = function (action) {
985
+ this._stackIdx--;
986
+ };
987
+ CommandStack.prototype._getHandler = function (command) {
988
+ return this._handlerMap[command];
989
+ };
990
+ CommandStack.prototype._setHandler = function (command, handler) {
991
+ if (!command || !handler) {
992
+ throw new Error('command and handler required');
993
+ }
994
+ if (this._handlerMap[command]) {
995
+ throw new Error('overriding handler for command <' + command + '>');
996
+ }
997
+ this._handlerMap[command] = handler;
998
+ };
999
+
1000
+ /**
1001
+ * @type { import('didi').ModuleDeclaration }
1002
+ */
1003
+ var commandModule = {
1004
+ commandStack: ['type', CommandStack]
1005
+ };
1006
+
1007
+ // config ///////////////////
1008
+
1009
+ const MINUTES_IN_DAY = 60 * 24;
1010
+ const DATETIME_SUBTYPES = {
1011
+ DATE: 'date',
1012
+ TIME: 'time',
1013
+ DATETIME: 'datetime'
1014
+ };
1015
+ const TIME_SERIALISING_FORMATS = {
1016
+ UTC_OFFSET: 'utc_offset',
1017
+ UTC_NORMALIZED: 'utc_normalized',
1018
+ NO_TIMEZONE: 'no_timezone'
1019
+ };
1020
+ const DATETIME_SUBTYPES_LABELS = {
1021
+ [DATETIME_SUBTYPES.DATE]: 'Date',
1022
+ [DATETIME_SUBTYPES.TIME]: 'Time',
1023
+ [DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
1024
+ };
1025
+ const TIME_SERIALISINGFORMAT_LABELS = {
1026
+ [TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
1027
+ [TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
1028
+ [TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
1029
+ };
1030
+ const DATETIME_SUBTYPE_PATH = ['subtype'];
1031
+ const DATE_LABEL_PATH = ['dateLabel'];
1032
+ const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
1033
+ const TIME_LABEL_PATH = ['timeLabel'];
1034
+ const TIME_USE24H_PATH = ['use24h'];
1035
+ const TIME_INTERVAL_PATH = ['timeInterval'];
1036
+ const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
1037
+
1038
+ // config ///////////////////
1039
+
1040
+ const VALUES_SOURCES = {
1041
+ STATIC: 'static',
1042
+ INPUT: 'input',
1043
+ EXPRESSION: 'expression'
1044
+ };
1045
+ const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
1046
+ const VALUES_SOURCES_LABELS = {
1047
+ [VALUES_SOURCES.STATIC]: 'Static',
1048
+ [VALUES_SOURCES.INPUT]: 'Input data',
1049
+ [VALUES_SOURCES.EXPRESSION]: 'Expression'
1050
+ };
1051
+ const VALUES_SOURCES_PATHS = {
1052
+ [VALUES_SOURCES.STATIC]: ['values'],
1053
+ [VALUES_SOURCES.INPUT]: ['valuesKey'],
1054
+ [VALUES_SOURCES.EXPRESSION]: ['valuesExpression']
1055
+ };
1056
+ const VALUES_SOURCES_DEFAULTS = {
1057
+ [VALUES_SOURCES.STATIC]: [{
1058
+ label: 'Value',
1059
+ value: 'value'
1060
+ }],
1061
+ [VALUES_SOURCES.INPUT]: '',
1062
+ [VALUES_SOURCES.EXPRESSION]: '='
1063
+ };
1064
+
1065
+ // helpers ///////////////////
1066
+
1067
+ function getValuesSource(field) {
1068
+ for (const source of Object.values(VALUES_SOURCES)) {
1069
+ if (minDash.get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
1070
+ return source;
1071
+ }
1072
+ }
1073
+ return VALUES_SOURCE_DEFAULT;
1074
+ }
1075
+
1076
+ function createInjector(bootstrapModules) {
1077
+ const injector = new didi.Injector(bootstrapModules);
1078
+ injector.init();
1079
+ return injector;
1080
+ }
1081
+
1082
+ /**
1083
+ * @param {string?} prefix
1084
+ *
1085
+ * @returns Element
1086
+ */
1087
+ function createFormContainer(prefix = 'fjs') {
1088
+ const container = document.createElement('div');
1089
+ container.classList.add(`${prefix}-container`);
1090
+ return container;
1091
+ }
1092
+
1093
+ const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression'];
1094
+ const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text'];
1095
+ function findErrors(errors, path) {
1096
+ return errors[pathStringify(path)];
1097
+ }
1098
+ function isRequired(field) {
1099
+ return field.required;
1100
+ }
1101
+ function pathParse(path) {
1102
+ if (!path) {
1103
+ return [];
1104
+ }
1105
+ return path.split('.').map(key => {
1106
+ return isNaN(parseInt(key)) ? key : parseInt(key);
1107
+ });
1108
+ }
1109
+ function pathsEqual(a, b) {
1110
+ return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
1111
+ }
1112
+ function pathStringify(path) {
1113
+ if (!path) {
1114
+ return '';
1115
+ }
1116
+ return path.join('.');
1117
+ }
1118
+ const indices = {};
1119
+ function generateIndexForType(type) {
1120
+ if (type in indices) {
1121
+ indices[type]++;
1122
+ } else {
1123
+ indices[type] = 1;
1124
+ }
1125
+ return indices[type];
1126
+ }
1127
+ function generateIdForType(type) {
1128
+ return `${type}${generateIndexForType(type)}`;
1129
+ }
1130
+
1131
+ /**
1132
+ * @template T
1133
+ * @param {T} data
1134
+ * @param {(this: any, key: string, value: any) => any} [replacer]
1135
+ * @return {T}
1136
+ */
1137
+ function clone(data, replacer) {
1138
+ return JSON.parse(JSON.stringify(data, replacer));
1139
+ }
1140
+
1141
+ /**
1142
+ * Parse the schema for input variables a form might make use of
1143
+ *
1144
+ * @param {any} schema
1145
+ *
1146
+ * @return {string[]}
1147
+ */
1148
+ function getSchemaVariables(schema, options = {}) {
1149
+ const {
1150
+ expressionLanguage = new FeelExpressionLanguage(null),
1151
+ templating = new FeelersTemplating(),
1152
+ inputs = true,
1153
+ outputs = true
1154
+ } = options;
1155
+ if (!schema.components) {
1156
+ return [];
1157
+ }
1158
+ const variables = schema.components.reduce((variables, component) => {
1159
+ const {
1160
+ key,
1161
+ valuesKey,
1162
+ type
1163
+ } = component;
1164
+ if (['button'].includes(type)) {
1165
+ return variables;
1166
+ }
1167
+
1168
+ // collect bi-directional variables
1169
+ if (inputs || outputs) {
1170
+ if (key) {
1171
+ variables = [...variables, key];
1172
+ }
416
1173
  }
417
- try {
418
- // cut off initial '='
419
- const result = feelin.unaryTest(condition.slice(1), data);
420
- return result;
421
- } catch (error) {
422
- this._eventBus.fire('error', {
423
- error
1174
+
1175
+ // collect input-only variables
1176
+ if (inputs) {
1177
+ if (valuesKey) {
1178
+ variables = [...variables, valuesKey];
1179
+ }
1180
+ EXPRESSION_PROPERTIES.forEach(prop => {
1181
+ const property = minDash.get(component, prop.split('.'));
1182
+ if (property && expressionLanguage.isExpression(property)) {
1183
+ const expressionVariables = expressionLanguage.getVariableNames(property, {
1184
+ type: 'expression'
1185
+ });
1186
+ variables = [...variables, ...expressionVariables];
1187
+ }
1188
+ });
1189
+ TEMPLATE_PROPERTIES.forEach(prop => {
1190
+ const property = minDash.get(component, prop.split('.'));
1191
+ if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
1192
+ const templateVariables = templating.getVariableNames(property);
1193
+ variables = [...variables, ...templateVariables];
1194
+ }
424
1195
  });
425
- return null;
426
1196
  }
427
- }
1197
+ return variables.filter(variable => variable !== undefined || variable !== null);
1198
+ }, []);
428
1199
 
429
- /**
430
- * Check if hide condition is met.
431
- *
432
- * @param {Condition} condition
433
- * @param {Object<string, any>} data
434
- * @returns {boolean}
435
- */
436
- _checkHideCondition(condition, data) {
437
- if (!condition.hide) {
438
- return false;
439
- }
440
- const result = this.check(condition.hide, data);
441
- return result === true;
1200
+ // remove duplicates
1201
+ return Array.from(new Set(variables));
1202
+ }
1203
+
1204
+ class UpdateFieldValidationHandler {
1205
+ constructor(form, validator) {
1206
+ this._form = form;
1207
+ this._validator = validator;
442
1208
  }
443
- _getConditions() {
444
- const formFields = this._formFieldRegistry.getAll();
445
- return formFields.reduce((conditions, formField) => {
446
- const {
447
- key,
448
- conditional: condition
449
- } = formField;
450
- if (key && condition) {
451
- return [...conditions, {
452
- key,
453
- condition
454
- }];
455
- }
456
- return conditions;
457
- }, []);
1209
+ execute(context) {
1210
+ const {
1211
+ field,
1212
+ value
1213
+ } = context;
1214
+ const {
1215
+ _path
1216
+ } = field;
1217
+ const {
1218
+ errors
1219
+ } = this._form._getState();
1220
+ context.oldErrors = clone(errors);
1221
+ const fieldErrors = this._validator.validateField(field, value);
1222
+ const updatedErrors = minDash.set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined);
1223
+ this._form._setState({
1224
+ errors: updatedErrors
1225
+ });
1226
+ }
1227
+ revert(context) {
1228
+ this._form._setState({
1229
+ errors: context.oldErrors
1230
+ });
458
1231
  }
459
1232
  }
460
- ConditionChecker.$inject = ['formFieldRegistry', 'eventBus'];
461
-
462
- var ExpressionLanguageModule = {
463
- __init__: ['expressionLanguage', 'templating', 'conditionChecker'],
464
- expressionLanguage: ['type', FeelExpressionLanguage],
465
- templating: ['type', FeelersTemplating],
466
- conditionChecker: ['type', ConditionChecker]
467
- };
1233
+ UpdateFieldValidationHandler.$inject = ['form', 'validator'];
468
1234
 
469
- // bootstrap showdown to support github flavored markdown
470
- showdown.setFlavor('github');
471
- class MarkdownRenderer {
472
- constructor() {
473
- this._converter = new showdown.Converter();
1235
+ class ViewerCommands {
1236
+ constructor(commandStack, eventBus) {
1237
+ this._commandStack = commandStack;
1238
+ eventBus.on('form.init', () => {
1239
+ this.registerHandlers();
1240
+ });
474
1241
  }
475
-
476
- /**
477
- * Render markdown to HTML.
478
- *
479
- * @param {string} markdown - The markdown to render
480
- *
481
- * @returns {string} HTML
482
- */
483
- render(markdown) {
484
- return this._converter.makeHtml(markdown);
1242
+ registerHandlers() {
1243
+ Object.entries(this.getHandlers()).forEach(([id, handler]) => {
1244
+ this._commandStack.registerHandler(id, handler);
1245
+ });
1246
+ }
1247
+ getHandlers() {
1248
+ return {
1249
+ 'formField.validation.update': UpdateFieldValidationHandler
1250
+ };
1251
+ }
1252
+ updateFieldValidation(field, value) {
1253
+ const context = {
1254
+ field,
1255
+ value
1256
+ };
1257
+ this._commandStack.execute('formField.validation.update', context);
485
1258
  }
486
1259
  }
487
- MarkdownRenderer.$inject = [];
1260
+ ViewerCommands.$inject = ['commandStack', 'eventBus'];
488
1261
 
489
- var MarkdownModule = {
490
- __init__: ['markdownRenderer'],
491
- markdownRenderer: ['type', MarkdownRenderer]
1262
+ var ViewerCommandsModule = {
1263
+ __depends__: [commandModule],
1264
+ __init__: ['viewerCommands'],
1265
+ viewerCommands: ['type', ViewerCommands]
492
1266
  };
493
1267
 
494
1268
  var FN_REF = '__fn';
@@ -1280,229 +2054,46 @@ class FormLayouter {
1280
2054
  components: components.map(c => c.id)
1281
2055
  });
1282
2056
  });
1283
-
1284
- // (3) traverse through nested components
1285
- components.forEach(field => this.calculateLayout(field));
1286
-
1287
- // (4) fire event to notify interested parties
1288
- this._eventBus.fire('form.layoutCalculated', {
1289
- rows: this._rows
1290
- });
1291
- }
1292
- clear() {
1293
- this._rows = [];
1294
- this._ids.clear();
1295
-
1296
- // fire event to notify interested parties
1297
- this._eventBus.fire('form.layoutCleared');
1298
- }
1299
- }
1300
- FormLayouter.$inject = ['eventBus'];
1301
-
1302
- // helpers //////
1303
-
1304
- function groupByRow(components, ids) {
1305
- return minDash.groupBy(components, c => {
1306
- // mitigate missing row by creating new (handle legacy)
1307
- const {
1308
- layout
1309
- } = c;
1310
- if (!layout || !layout.row) {
1311
- return ids.nextPrefixed('Row_');
1312
- }
1313
- return layout.row;
1314
- });
1315
- }
1316
-
1317
- /**
1318
- * @param {Array<FormRows>} formRows
1319
- * @returns {Array<FormRow>}
1320
- */
1321
- function allRows(formRows) {
1322
- return minDash.flatten(formRows.map(c => c.rows));
1323
- }
1324
-
1325
- // config ///////////////////
1326
-
1327
- const MINUTES_IN_DAY = 60 * 24;
1328
- const DATETIME_SUBTYPES = {
1329
- DATE: 'date',
1330
- TIME: 'time',
1331
- DATETIME: 'datetime'
1332
- };
1333
- const TIME_SERIALISING_FORMATS = {
1334
- UTC_OFFSET: 'utc_offset',
1335
- UTC_NORMALIZED: 'utc_normalized',
1336
- NO_TIMEZONE: 'no_timezone'
1337
- };
1338
- const DATETIME_SUBTYPES_LABELS = {
1339
- [DATETIME_SUBTYPES.DATE]: 'Date',
1340
- [DATETIME_SUBTYPES.TIME]: 'Time',
1341
- [DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
1342
- };
1343
- const TIME_SERIALISINGFORMAT_LABELS = {
1344
- [TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
1345
- [TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
1346
- [TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
1347
- };
1348
- const DATETIME_SUBTYPE_PATH = ['subtype'];
1349
- const DATE_LABEL_PATH = ['dateLabel'];
1350
- const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
1351
- const TIME_LABEL_PATH = ['timeLabel'];
1352
- const TIME_USE24H_PATH = ['use24h'];
1353
- const TIME_INTERVAL_PATH = ['timeInterval'];
1354
- const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
1355
-
1356
- // config ///////////////////
1357
-
1358
- const VALUES_SOURCES = {
1359
- STATIC: 'static',
1360
- INPUT: 'input',
1361
- EXPRESSION: 'expression'
1362
- };
1363
- const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
1364
- const VALUES_SOURCES_LABELS = {
1365
- [VALUES_SOURCES.STATIC]: 'Static',
1366
- [VALUES_SOURCES.INPUT]: 'Input data',
1367
- [VALUES_SOURCES.EXPRESSION]: 'Expression'
1368
- };
1369
- const VALUES_SOURCES_PATHS = {
1370
- [VALUES_SOURCES.STATIC]: ['values'],
1371
- [VALUES_SOURCES.INPUT]: ['valuesKey'],
1372
- [VALUES_SOURCES.EXPRESSION]: ['valuesExpression']
1373
- };
1374
- const VALUES_SOURCES_DEFAULTS = {
1375
- [VALUES_SOURCES.STATIC]: [{
1376
- label: 'Value',
1377
- value: 'value'
1378
- }],
1379
- [VALUES_SOURCES.INPUT]: '',
1380
- [VALUES_SOURCES.EXPRESSION]: '='
1381
- };
1382
-
1383
- // helpers ///////////////////
1384
-
1385
- function getValuesSource(field) {
1386
- for (const source of Object.values(VALUES_SOURCES)) {
1387
- if (minDash.get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
1388
- return source;
1389
- }
1390
- }
1391
- return VALUES_SOURCE_DEFAULT;
1392
- }
1393
-
1394
- function createInjector(bootstrapModules) {
1395
- const injector = new didi.Injector(bootstrapModules);
1396
- injector.init();
1397
- return injector;
1398
- }
1399
-
1400
- /**
1401
- * @param {string?} prefix
1402
- *
1403
- * @returns Element
1404
- */
1405
- function createFormContainer(prefix = 'fjs') {
1406
- const container = document.createElement('div');
1407
- container.classList.add(`${prefix}-container`);
1408
- return container;
1409
- }
1410
-
1411
- const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression'];
1412
- const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text'];
1413
- function findErrors(errors, path) {
1414
- return errors[pathStringify(path)];
1415
- }
1416
- function isRequired(field) {
1417
- return field.required;
1418
- }
1419
- function pathParse(path) {
1420
- if (!path) {
1421
- return [];
1422
- }
1423
- return path.split('.').map(key => {
1424
- return isNaN(parseInt(key)) ? key : parseInt(key);
1425
- });
1426
- }
1427
- function pathsEqual(a, b) {
1428
- return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
1429
- }
1430
- function pathStringify(path) {
1431
- if (!path) {
1432
- return '';
2057
+
2058
+ // (3) traverse through nested components
2059
+ components.forEach(field => this.calculateLayout(field));
2060
+
2061
+ // (4) fire event to notify interested parties
2062
+ this._eventBus.fire('form.layoutCalculated', {
2063
+ rows: this._rows
2064
+ });
1433
2065
  }
1434
- return path.join('.');
1435
- }
1436
- const indices = {};
1437
- function generateIndexForType(type) {
1438
- if (type in indices) {
1439
- indices[type]++;
1440
- } else {
1441
- indices[type] = 1;
2066
+ clear() {
2067
+ this._rows = [];
2068
+ this._ids.clear();
2069
+
2070
+ // fire event to notify interested parties
2071
+ this._eventBus.fire('form.layoutCleared');
1442
2072
  }
1443
- return indices[type];
1444
- }
1445
- function generateIdForType(type) {
1446
- return `${type}${generateIndexForType(type)}`;
1447
2073
  }
2074
+ FormLayouter.$inject = ['eventBus'];
1448
2075
 
1449
- /**
1450
- * @template T
1451
- * @param {T} data
1452
- * @param {(this: any, key: string, value: any) => any} [replacer]
1453
- * @return {T}
1454
- */
1455
- function clone(data, replacer) {
1456
- return JSON.parse(JSON.stringify(data, replacer));
1457
- }
2076
+ // helpers //////
1458
2077
 
1459
- /**
1460
- * Parse the schema for input variables a form might make use of
1461
- *
1462
- * @param {any} schema
1463
- *
1464
- * @return {string[]}
1465
- */
1466
- function getSchemaVariables(schema, expressionLanguage = new FeelExpressionLanguage(null), templating = new FeelersTemplating()) {
1467
- if (!schema.components) {
1468
- return [];
1469
- }
1470
- const variables = schema.components.reduce((variables, component) => {
2078
+ function groupByRow(components, ids) {
2079
+ return minDash.groupBy(components, c => {
2080
+ // mitigate missing row by creating new (handle legacy)
1471
2081
  const {
1472
- key,
1473
- valuesKey,
1474
- type
1475
- } = component;
1476
- if (['button'].includes(type)) {
1477
- return variables;
1478
- }
1479
- if (key) {
1480
- variables = [...variables, key];
1481
- }
1482
- if (valuesKey) {
1483
- variables = [...variables, valuesKey];
2082
+ layout
2083
+ } = c;
2084
+ if (!layout || !layout.row) {
2085
+ return ids.nextPrefixed('Row_');
1484
2086
  }
1485
- EXPRESSION_PROPERTIES.forEach(prop => {
1486
- const property = minDash.get(component, prop.split('.'));
1487
- if (property && expressionLanguage.isExpression(property)) {
1488
- const expressionVariables = expressionLanguage.getVariableNames(property, {
1489
- type: 'expression'
1490
- });
1491
- variables = [...variables, ...expressionVariables];
1492
- }
1493
- });
1494
- TEMPLATE_PROPERTIES.forEach(prop => {
1495
- const property = minDash.get(component, prop.split('.'));
1496
- if (property && !expressionLanguage.isExpression(property) && templating.isTemplate(property)) {
1497
- const templateVariables = templating.getVariableNames(property);
1498
- variables = [...variables, ...templateVariables];
1499
- }
1500
- });
1501
- return variables;
1502
- }, []);
2087
+ return layout.row;
2088
+ });
2089
+ }
1503
2090
 
1504
- // remove duplicates
1505
- return Array.from(new Set(variables));
2091
+ /**
2092
+ * @param {Array<FormRows>} formRows
2093
+ * @returns {Array<FormRow>}
2094
+ */
2095
+ function allRows(formRows) {
2096
+ return minDash.flatten(formRows.map(c => c.rows));
1506
2097
  }
1507
2098
 
1508
2099
  class Importer {
@@ -1679,7 +2270,7 @@ function prefixId(id, formId) {
1679
2270
  return `fjs-form-${id}`;
1680
2271
  }
1681
2272
 
1682
- const type$b = 'button';
2273
+ const type$c = 'button';
1683
2274
  function Button(props) {
1684
2275
  const {
1685
2276
  disabled,
@@ -1689,7 +2280,7 @@ function Button(props) {
1689
2280
  action = 'submit'
1690
2281
  } = field;
1691
2282
  return jsxRuntime.jsx("div", {
1692
- class: formFieldClasses(type$b),
2283
+ class: formFieldClasses(type$c),
1693
2284
  children: jsxRuntime.jsx("button", {
1694
2285
  class: "fjs-button",
1695
2286
  type: action,
@@ -1699,7 +2290,7 @@ function Button(props) {
1699
2290
  });
1700
2291
  }
1701
2292
  Button.config = {
1702
- type: type$b,
2293
+ type: type$c,
1703
2294
  keyed: true,
1704
2295
  label: 'Button',
1705
2296
  group: 'action',
@@ -1959,11 +2550,12 @@ function Label(props) {
1959
2550
  });
1960
2551
  }
1961
2552
 
1962
- const type$a = 'checkbox';
2553
+ const type$b = 'checkbox';
1963
2554
  function Checkbox(props) {
1964
2555
  const {
1965
2556
  disabled,
1966
2557
  errors = [],
2558
+ onBlur,
1967
2559
  field,
1968
2560
  readonly,
1969
2561
  value = false
@@ -1990,7 +2582,7 @@ function Checkbox(props) {
1990
2582
  } = hooks.useContext(FormContext$1);
1991
2583
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
1992
2584
  return jsxRuntime.jsxs("div", {
1993
- class: classNames(formFieldClasses(type$a, {
2585
+ class: classNames(formFieldClasses(type$b, {
1994
2586
  errors,
1995
2587
  disabled,
1996
2588
  readonly
@@ -2009,6 +2601,7 @@ function Checkbox(props) {
2009
2601
  id: prefixId(id, formId),
2010
2602
  type: "checkbox",
2011
2603
  onChange: onChange,
2604
+ onBlur: onBlur,
2012
2605
  "aria-describedby": errorMessageId
2013
2606
  })
2014
2607
  }), jsxRuntime.jsx(Description, {
@@ -2020,7 +2613,7 @@ function Checkbox(props) {
2020
2613
  });
2021
2614
  }
2022
2615
  Checkbox.config = {
2023
- type: type$a,
2616
+ type: type$b,
2024
2617
  keyed: true,
2025
2618
  label: 'Checkbox',
2026
2619
  group: 'selection',
@@ -2363,11 +2956,12 @@ function sanitizeMultiSelectValue(options) {
2363
2956
  }
2364
2957
  }
2365
2958
 
2366
- const type$9 = 'checklist';
2959
+ const type$a = 'checklist';
2367
2960
  function Checklist(props) {
2368
2961
  const {
2369
2962
  disabled,
2370
2963
  errors = [],
2964
+ onBlur,
2371
2965
  field,
2372
2966
  readonly,
2373
2967
  value = []
@@ -2378,6 +2972,7 @@ function Checklist(props) {
2378
2972
  label,
2379
2973
  validate = {}
2380
2974
  } = field;
2975
+ const outerDivRef = hooks.useRef();
2381
2976
  const {
2382
2977
  required
2383
2978
  } = validate;
@@ -2393,6 +2988,12 @@ function Checklist(props) {
2393
2988
  value: newValue
2394
2989
  });
2395
2990
  };
2991
+ const onCheckboxBlur = e => {
2992
+ if (outerDivRef.current.contains(e.relatedTarget)) {
2993
+ return;
2994
+ }
2995
+ onBlur();
2996
+ };
2396
2997
  const {
2397
2998
  state: loadState,
2398
2999
  values: options
@@ -2402,11 +3003,12 @@ function Checklist(props) {
2402
3003
  } = hooks.useContext(FormContext$1);
2403
3004
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
2404
3005
  return jsxRuntime.jsxs("div", {
2405
- class: classNames(formFieldClasses(type$9, {
3006
+ class: classNames(formFieldClasses(type$a, {
2406
3007
  errors,
2407
3008
  disabled,
2408
3009
  readonly
2409
3010
  })),
3011
+ ref: outerDivRef,
2410
3012
  children: [jsxRuntime.jsx(Label, {
2411
3013
  label: label,
2412
3014
  required: required
@@ -2426,6 +3028,7 @@ function Checklist(props) {
2426
3028
  id: prefixId(`${id}-${index}`, formId),
2427
3029
  type: "checkbox",
2428
3030
  onClick: () => toggleCheckbox(v.value),
3031
+ onBlur: onCheckboxBlur,
2429
3032
  "aria-describedby": errorMessageId
2430
3033
  })
2431
3034
  }, `${id}-${index}`);
@@ -2438,7 +3041,7 @@ function Checklist(props) {
2438
3041
  });
2439
3042
  }
2440
3043
  Checklist.config = {
2441
- type: type$9,
3044
+ type: type$a,
2442
3045
  keyed: true,
2443
3046
  label: 'Checklist',
2444
3047
  group: 'selection',
@@ -2468,8 +3071,10 @@ function FormField(props) {
2468
3071
  onChange
2469
3072
  } = props;
2470
3073
  const formFields = useService('formFields'),
3074
+ viewerCommands = useService('viewerCommands', false),
2471
3075
  form = useService('form');
2472
3076
  const {
3077
+ initialData,
2473
3078
  data,
2474
3079
  errors,
2475
3080
  properties
@@ -2483,12 +3088,23 @@ function FormField(props) {
2483
3088
  if (!FormFieldComponent) {
2484
3089
  throw new Error(`cannot render field <${field.type}>`);
2485
3090
  }
3091
+ const initialValue = hooks.useMemo(() => minDash.get(initialData, field._path), [initialData, field._path]);
2486
3092
  const value = minDash.get(data, field._path);
2487
3093
  const fieldErrors = findErrors(errors, field._path);
2488
3094
  const readonly = useReadonly(field, properties);
2489
3095
 
2490
3096
  // add precedence: global readonly > form field disabled
2491
3097
  const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
3098
+ const onBlur = hooks.useCallback(() => {
3099
+ if (viewerCommands) {
3100
+ viewerCommands.updateFieldValidation(field, value);
3101
+ }
3102
+ }, [viewerCommands, field, value]);
3103
+ hooks.useEffect(() => {
3104
+ if (viewerCommands && initialValue) {
3105
+ viewerCommands.updateFieldValidation(field, initialValue);
3106
+ }
3107
+ }, [viewerCommands, field, initialValue]);
2492
3108
  const hidden = useCondition(field.conditional && field.conditional.hide || null);
2493
3109
  if (hidden) {
2494
3110
  return jsxRuntime.jsx(Empty, {});
@@ -2504,6 +3120,7 @@ function FormField(props) {
2504
3120
  disabled: disabled,
2505
3121
  errors: fieldErrors,
2506
3122
  onChange: disabled || readonly ? noop$1 : onChange,
3123
+ onBlur: disabled || readonly ? noop$1 : onBlur,
2507
3124
  readonly: readonly,
2508
3125
  value: value
2509
3126
  })
@@ -2566,16 +3183,16 @@ Default.config = {
2566
3183
  })
2567
3184
  };
2568
3185
 
2569
- var _path$g;
2570
- 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); }
3186
+ var _path$h;
3187
+ 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); }
2571
3188
  var SvgCalendar = function SvgCalendar(props) {
2572
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$j({
3189
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$k({
2573
3190
  xmlns: "http://www.w3.org/2000/svg",
2574
3191
  width: 14,
2575
3192
  height: 15,
2576
3193
  fill: "none",
2577
3194
  viewBox: "0 0 28 30"
2578
- }, props), _path$g || (_path$g = /*#__PURE__*/React__namespace.createElement("path", {
3195
+ }, props), _path$h || (_path$h = /*#__PURE__*/React__namespace.createElement("path", {
2579
3196
  fill: "currentColor",
2580
3197
  fillRule: "evenodd",
2581
3198
  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",
@@ -2627,6 +3244,7 @@ function Datepicker(props) {
2627
3244
  id,
2628
3245
  label,
2629
3246
  collapseLabelOnEmpty,
3247
+ onDateTimeBlur,
2630
3248
  formId,
2631
3249
  required,
2632
3250
  disabled,
@@ -2721,7 +3339,8 @@ function Datepicker(props) {
2721
3339
  if (!isInputDirty || e.relatedTarget && e.relatedTarget.classList.contains('flatpickr-day')) return;
2722
3340
  dateInputRef.current.dispatchEvent(ENTER_KEYDOWN_EVENT);
2723
3341
  setIsInputDirty(false);
2724
- }, [isInputDirty]);
3342
+ onDateTimeBlur(e);
3343
+ }, [isInputDirty, onDateTimeBlur]);
2725
3344
  const fullId = `${prefixId(id, formId)}--date`;
2726
3345
  return jsxRuntime.jsxs("div", {
2727
3346
  class: "fjs-datetime-subsection",
@@ -2763,19 +3382,19 @@ function Datepicker(props) {
2763
3382
  });
2764
3383
  }
2765
3384
 
2766
- var _path$f, _path2$3;
2767
- 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); }
3385
+ var _path$g, _path2$4;
3386
+ 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); }
2768
3387
  var SvgClock = function SvgClock(props) {
2769
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$i({
3388
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$j({
2770
3389
  xmlns: "http://www.w3.org/2000/svg",
2771
3390
  width: 16,
2772
3391
  height: 16,
2773
3392
  fill: "none",
2774
3393
  viewBox: "0 0 28 29"
2775
- }, props), _path$f || (_path$f = /*#__PURE__*/React__namespace.createElement("path", {
3394
+ }, props), _path$g || (_path$g = /*#__PURE__*/React__namespace.createElement("path", {
2776
3395
  fill: "currentColor",
2777
3396
  d: "M13 14.41 18.59 20 20 18.59l-5-5.01V5h-2v9.41Z"
2778
- })), _path2$3 || (_path2$3 = /*#__PURE__*/React__namespace.createElement("path", {
3397
+ })), _path2$4 || (_path2$4 = /*#__PURE__*/React__namespace.createElement("path", {
2779
3398
  fill: "currentColor",
2780
3399
  fillRule: "evenodd",
2781
3400
  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",
@@ -2884,6 +3503,7 @@ function Timepicker(props) {
2884
3503
  id,
2885
3504
  label,
2886
3505
  collapseLabelOnEmpty,
3506
+ onDateTimeBlur,
2887
3507
  formId,
2888
3508
  required,
2889
3509
  disabled,
@@ -2983,6 +3603,7 @@ function Timepicker(props) {
2983
3603
  const onInputBlur = e => {
2984
3604
  setDropdownIsOpen(false);
2985
3605
  propagateRawToMinute();
3606
+ onDateTimeBlur(e);
2986
3607
  };
2987
3608
  const onDropdownValueSelected = value => {
2988
3609
  setDropdownIsOpen(false);
@@ -3038,11 +3659,12 @@ function Timepicker(props) {
3038
3659
  });
3039
3660
  }
3040
3661
 
3041
- const type$8 = 'datetime';
3662
+ const type$9 = 'datetime';
3042
3663
  function Datetime(props) {
3043
3664
  const {
3044
3665
  disabled,
3045
3666
  errors = [],
3667
+ onBlur,
3046
3668
  field,
3047
3669
  onChange,
3048
3670
  readonly,
@@ -3066,6 +3688,7 @@ function Datetime(props) {
3066
3688
  const {
3067
3689
  formId
3068
3690
  } = hooks.useContext(FormContext$1);
3691
+ const dateTimeGroupRef = hooks.useRef();
3069
3692
  const getNullDateTime = () => ({
3070
3693
  date: new Date(Date.parse(null)),
3071
3694
  time: null
@@ -3076,6 +3699,12 @@ function Datetime(props) {
3076
3699
  const isValidTime = time => !isNaN(parseInt(time));
3077
3700
  const useDatePicker = hooks.useMemo(() => subtype === DATETIME_SUBTYPES.DATE || subtype === DATETIME_SUBTYPES.DATETIME, [subtype]);
3078
3701
  const useTimePicker = hooks.useMemo(() => subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME, [subtype]);
3702
+ const onDateTimeBlur = hooks.useCallback(e => {
3703
+ if (e.relatedTarget && dateTimeGroupRef.current.contains(e.relatedTarget)) {
3704
+ return;
3705
+ }
3706
+ onBlur();
3707
+ }, [onBlur]);
3079
3708
  hooks.useEffect(() => {
3080
3709
  let {
3081
3710
  date,
@@ -3167,6 +3796,7 @@ function Datetime(props) {
3167
3796
  id,
3168
3797
  label: dateLabel,
3169
3798
  collapseLabelOnEmpty: !timeLabel,
3799
+ onDateTimeBlur,
3170
3800
  formId,
3171
3801
  required,
3172
3802
  disabled,
@@ -3180,6 +3810,7 @@ function Datetime(props) {
3180
3810
  id,
3181
3811
  label: timeLabel,
3182
3812
  collapseLabelOnEmpty: !dateLabel,
3813
+ onDateTimeBlur,
3183
3814
  formId,
3184
3815
  required,
3185
3816
  disabled,
@@ -3191,13 +3822,14 @@ function Datetime(props) {
3191
3822
  'aria-describedby': errorMessageId
3192
3823
  };
3193
3824
  return jsxRuntime.jsxs("div", {
3194
- class: formFieldClasses(type$8, {
3825
+ class: formFieldClasses(type$9, {
3195
3826
  errors: allErrors,
3196
3827
  disabled,
3197
3828
  readonly
3198
3829
  }),
3199
3830
  children: [jsxRuntime.jsxs("div", {
3200
3831
  class: classNames('fjs-vertical-group'),
3832
+ ref: dateTimeGroupRef,
3201
3833
  children: [useDatePicker && jsxRuntime.jsx(Datepicker, {
3202
3834
  ...datePickerProps
3203
3835
  }), useTimePicker && useDatePicker && jsxRuntime.jsx("div", {
@@ -3214,7 +3846,7 @@ function Datetime(props) {
3214
3846
  });
3215
3847
  }
3216
3848
  Datetime.config = {
3217
- type: type$8,
3849
+ type: type$9,
3218
3850
  keyed: true,
3219
3851
  label: 'Date time',
3220
3852
  group: 'basic-input',
@@ -3483,9 +4115,9 @@ function isValidAttribute(lcTag, lcName, value) {
3483
4115
  return true;
3484
4116
  }
3485
4117
 
3486
- 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); }
4118
+ 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); }
3487
4119
  var SvgImagePlaceholder = function SvgImagePlaceholder(props) {
3488
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$h({
4120
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$i({
3489
4121
  xmlns: "http://www.w3.org/2000/svg",
3490
4122
  xmlSpace: "preserve",
3491
4123
  width: 64,
@@ -3524,7 +4156,7 @@ var SvgImagePlaceholder = function SvgImagePlaceholder(props) {
3524
4156
  };
3525
4157
  var ImagePlaceholder = SvgImagePlaceholder;
3526
4158
 
3527
- const type$7 = 'image';
4159
+ const type$8 = 'image';
3528
4160
  function Image(props) {
3529
4161
  const {
3530
4162
  field
@@ -3545,7 +4177,7 @@ function Image(props) {
3545
4177
  formId
3546
4178
  } = hooks.useContext(FormContext$1);
3547
4179
  return jsxRuntime.jsx("div", {
3548
- class: formFieldClasses(type$7),
4180
+ class: formFieldClasses(type$8),
3549
4181
  children: jsxRuntime.jsxs("div", {
3550
4182
  class: "fjs-image-container",
3551
4183
  children: [safeSource && jsxRuntime.jsx("img", {
@@ -3563,7 +4195,7 @@ function Image(props) {
3563
4195
  });
3564
4196
  }
3565
4197
  Image.config = {
3566
- type: type$7,
4198
+ type: type$8,
3567
4199
  keyed: false,
3568
4200
  label: 'Image view',
3569
4201
  group: 'presentation',
@@ -3590,14 +4222,14 @@ function TemplatedInputAdorner(props) {
3590
4222
  });
3591
4223
  }
3592
4224
 
3593
- var _path$e;
3594
- 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); }
4225
+ var _path$f;
4226
+ 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); }
3595
4227
  var SvgAngelDown = function SvgAngelDown(props) {
3596
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$g({
4228
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$h({
3597
4229
  xmlns: "http://www.w3.org/2000/svg",
3598
4230
  width: 8,
3599
4231
  height: 8
3600
- }, props), _path$e || (_path$e = /*#__PURE__*/React__namespace.createElement("path", {
4232
+ }, props), _path$f || (_path$f = /*#__PURE__*/React__namespace.createElement("path", {
3601
4233
  fill: "currentColor",
3602
4234
  fillRule: "evenodd",
3603
4235
  stroke: "currentColor",
@@ -3608,14 +4240,14 @@ var SvgAngelDown = function SvgAngelDown(props) {
3608
4240
  };
3609
4241
  var AngelDownIcon = SvgAngelDown;
3610
4242
 
3611
- var _path$d;
3612
- 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); }
4243
+ var _path$e;
4244
+ 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); }
3613
4245
  var SvgAngelUp = function SvgAngelUp(props) {
3614
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$f({
4246
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$g({
3615
4247
  xmlns: "http://www.w3.org/2000/svg",
3616
4248
  width: 8,
3617
4249
  height: 8
3618
- }, props), _path$d || (_path$d = /*#__PURE__*/React__namespace.createElement("path", {
4250
+ }, props), _path$e || (_path$e = /*#__PURE__*/React__namespace.createElement("path", {
3619
4251
  fill: "currentColor",
3620
4252
  fillRule: "evenodd",
3621
4253
  stroke: "currentColor",
@@ -3626,11 +4258,12 @@ var SvgAngelUp = function SvgAngelUp(props) {
3626
4258
  };
3627
4259
  var AngelUpIcon = SvgAngelUp;
3628
4260
 
3629
- const type$6 = 'number';
4261
+ const type$7 = 'number';
3630
4262
  function Numberfield(props) {
3631
4263
  const {
3632
4264
  disabled,
3633
4265
  errors = [],
4266
+ onBlur,
3634
4267
  field,
3635
4268
  value,
3636
4269
  readonly,
@@ -3763,7 +4396,7 @@ function Numberfield(props) {
3763
4396
  } = hooks.useContext(FormContext$1);
3764
4397
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3765
4398
  return jsxRuntime.jsxs("div", {
3766
- class: formFieldClasses(type$6, {
4399
+ class: formFieldClasses(type$7, {
3767
4400
  errors,
3768
4401
  disabled,
3769
4402
  readonly
@@ -3791,7 +4424,8 @@ function Numberfield(props) {
3791
4424
  readOnly: readonly,
3792
4425
  id: prefixId(id, formId),
3793
4426
  onKeyDown: onKeyDown,
3794
- onKeyPress: onKeyPress
4427
+ onKeyPress: onKeyPress,
4428
+ onBlur: onBlur
3795
4429
 
3796
4430
  // @ts-ignore
3797
4431
  ,
@@ -3834,7 +4468,7 @@ function Numberfield(props) {
3834
4468
  });
3835
4469
  }
3836
4470
  Numberfield.config = {
3837
- type: type$6,
4471
+ type: type$7,
3838
4472
  keyed: true,
3839
4473
  label: 'Number',
3840
4474
  group: 'basic-input',
@@ -3857,11 +4491,12 @@ Numberfield.config = {
3857
4491
  })
3858
4492
  };
3859
4493
 
3860
- const type$5 = 'radio';
4494
+ const type$6 = 'radio';
3861
4495
  function Radio(props) {
3862
4496
  const {
3863
4497
  disabled,
3864
4498
  errors = [],
4499
+ onBlur,
3865
4500
  field,
3866
4501
  readonly,
3867
4502
  value
@@ -3872,6 +4507,7 @@ function Radio(props) {
3872
4507
  label,
3873
4508
  validate = {}
3874
4509
  } = field;
4510
+ const outerDivRef = hooks.useRef();
3875
4511
  const {
3876
4512
  required
3877
4513
  } = validate;
@@ -3881,6 +4517,12 @@ function Radio(props) {
3881
4517
  value: v
3882
4518
  });
3883
4519
  };
4520
+ const onRadioBlur = e => {
4521
+ if (outerDivRef.current.contains(e.relatedTarget)) {
4522
+ return;
4523
+ }
4524
+ onBlur();
4525
+ };
3884
4526
  const {
3885
4527
  state: loadState,
3886
4528
  values: options
@@ -3890,11 +4532,12 @@ function Radio(props) {
3890
4532
  } = hooks.useContext(FormContext$1);
3891
4533
  const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3892
4534
  return jsxRuntime.jsxs("div", {
3893
- class: formFieldClasses(type$5, {
4535
+ class: formFieldClasses(type$6, {
3894
4536
  errors,
3895
4537
  disabled,
3896
4538
  readonly
3897
4539
  }),
4540
+ ref: outerDivRef,
3898
4541
  children: [jsxRuntime.jsx(Label, {
3899
4542
  label: label,
3900
4543
  required: required
@@ -3914,6 +4557,7 @@ function Radio(props) {
3914
4557
  id: prefixId(`${id}-${index}`, formId),
3915
4558
  type: "radio",
3916
4559
  onClick: () => onChange(option.value),
4560
+ onBlur: onRadioBlur,
3917
4561
  "aria-describedby": errorMessageId
3918
4562
  })
3919
4563
  }, `${id}-${index}`);
@@ -3926,7 +4570,7 @@ function Radio(props) {
3926
4570
  });
3927
4571
  }
3928
4572
  Radio.config = {
3929
- type: type$5,
4573
+ type: type$6,
3930
4574
  keyed: true,
3931
4575
  label: 'Radio',
3932
4576
  group: 'selection',
@@ -3949,14 +4593,14 @@ Radio.config = {
3949
4593
  }
3950
4594
  };
3951
4595
 
3952
- var _path$c;
3953
- 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); }
4596
+ var _path$d;
4597
+ 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); }
3954
4598
  var SvgXMark = function SvgXMark(props) {
3955
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$e({
4599
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$f({
3956
4600
  xmlns: "http://www.w3.org/2000/svg",
3957
4601
  width: 8,
3958
4602
  height: 8
3959
- }, props), _path$c || (_path$c = /*#__PURE__*/React__namespace.createElement("path", {
4603
+ }, props), _path$d || (_path$d = /*#__PURE__*/React__namespace.createElement("path", {
3960
4604
  fill: "currentColor",
3961
4605
  fillRule: "evenodd",
3962
4606
  stroke: "currentColor",
@@ -3972,6 +4616,7 @@ function SearchableSelect(props) {
3972
4616
  id,
3973
4617
  disabled,
3974
4618
  errors,
4619
+ onBlur,
3975
4620
  field,
3976
4621
  readonly,
3977
4622
  value
@@ -4091,6 +4736,7 @@ function SearchableSelect(props) {
4091
4736
  onBlur: () => {
4092
4737
  setIsDropdownExpanded(false);
4093
4738
  setFilter(valueLabel);
4739
+ onBlur();
4094
4740
  },
4095
4741
  "aria-describedby": props['aria-describedby']
4096
4742
  }), displayState.displayCross && jsxRuntime.jsxs("span", {
@@ -4125,6 +4771,7 @@ function SimpleSelect(props) {
4125
4771
  id,
4126
4772
  disabled,
4127
4773
  errors,
4774
+ onBlur,
4128
4775
  field,
4129
4776
  readonly,
4130
4777
  value
@@ -4179,7 +4826,10 @@ function SimpleSelect(props) {
4179
4826
  'hasErrors': errors.length
4180
4827
  }),
4181
4828
  onFocus: () => setIsDropdownExpanded(true),
4182
- onBlur: () => setIsDropdownExpanded(false),
4829
+ onBlur: () => {
4830
+ setIsDropdownExpanded(false);
4831
+ onBlur();
4832
+ },
4183
4833
  onMouseDown: onMouseDown,
4184
4834
  children: [jsxRuntime.jsx("div", {
4185
4835
  class: classNames('fjs-select-display', {
@@ -4221,11 +4871,12 @@ function SimpleSelect(props) {
4221
4871
  });
4222
4872
  }
4223
4873
 
4224
- const type$4 = 'select';
4874
+ const type$5 = 'select';
4225
4875
  function Select(props) {
4226
4876
  const {
4227
4877
  disabled,
4228
4878
  errors = [],
4879
+ onBlur,
4229
4880
  field,
4230
4881
  onChange,
4231
4882
  readonly,
@@ -4249,14 +4900,15 @@ function Select(props) {
4249
4900
  id,
4250
4901
  disabled,
4251
4902
  errors,
4903
+ onBlur,
4252
4904
  field,
4253
4905
  value,
4254
4906
  onChange,
4255
4907
  readonly,
4256
4908
  'aria-describedby': errorMessageId
4257
- }), [disabled, errors, field, id, value, onChange, readonly, errorMessageId]);
4909
+ }), [disabled, errors, field, id, value, onChange, onBlur, readonly, errorMessageId]);
4258
4910
  return jsxRuntime.jsxs("div", {
4259
- class: formFieldClasses(type$4, {
4911
+ class: formFieldClasses(type$5, {
4260
4912
  errors,
4261
4913
  disabled,
4262
4914
  readonly
@@ -4284,7 +4936,7 @@ function Select(props) {
4284
4936
  });
4285
4937
  }
4286
4938
  Select.config = {
4287
- type: type$4,
4939
+ type: type$5,
4288
4940
  keyed: true,
4289
4941
  label: 'Select',
4290
4942
  group: 'selection',
@@ -4307,11 +4959,38 @@ Select.config = {
4307
4959
  }
4308
4960
  };
4309
4961
 
4962
+ const type$4 = 'spacer';
4963
+ function Spacer(props) {
4964
+ const {
4965
+ field
4966
+ } = props;
4967
+ const {
4968
+ height = 60
4969
+ } = field;
4970
+ return jsxRuntime.jsx("div", {
4971
+ class: formFieldClasses(type$4),
4972
+ style: {
4973
+ height: height
4974
+ }
4975
+ });
4976
+ }
4977
+ Spacer.config = {
4978
+ type: type$4,
4979
+ keyed: false,
4980
+ label: 'Spacer',
4981
+ group: 'presentation',
4982
+ create: (options = {}) => ({
4983
+ height: 60,
4984
+ ...options
4985
+ })
4986
+ };
4987
+
4310
4988
  const type$3 = 'taglist';
4311
4989
  function Taglist(props) {
4312
4990
  const {
4313
4991
  disabled,
4314
4992
  errors = [],
4993
+ onBlur,
4315
4994
  field,
4316
4995
  readonly,
4317
4996
  value: values = []
@@ -4404,9 +5083,10 @@ function Taglist(props) {
4404
5083
  break;
4405
5084
  }
4406
5085
  };
4407
- const onBlur = () => {
5086
+ const onComponentBlur = () => {
4408
5087
  setIsDropdownExpanded(false);
4409
5088
  setFilter('');
5089
+ onBlur();
4410
5090
  };
4411
5091
  const onTagRemoveClick = (event, value) => {
4412
5092
  const {
@@ -4477,9 +5157,7 @@ function Taglist(props) {
4477
5157
  onKeyDown: onInputKeyDown,
4478
5158
  onMouseDown: () => setIsEscapeClose(false),
4479
5159
  onFocus: () => !readonly && setIsDropdownExpanded(true),
4480
- onBlur: () => {
4481
- !readonly && onBlur();
4482
- },
5160
+ onBlur: () => !readonly && onComponentBlur(),
4483
5161
  "aria-describedby": errorMessageId
4484
5162
  })]
4485
5163
  }), jsxRuntime.jsx("div", {
@@ -4612,6 +5290,7 @@ function Textfield(props) {
4612
5290
  const {
4613
5291
  disabled,
4614
5292
  errors = [],
5293
+ onBlur,
4615
5294
  field,
4616
5295
  readonly,
4617
5296
  value = ''
@@ -4663,6 +5342,7 @@ function Textfield(props) {
4663
5342
  readOnly: readonly,
4664
5343
  id: prefixId(id, formId),
4665
5344
  onInput: onChange,
5345
+ onBlur: onBlur,
4666
5346
  type: "text",
4667
5347
  value: value,
4668
5348
  "aria-describedby": errorMessageId
@@ -4704,6 +5384,7 @@ function Textarea(props) {
4704
5384
  const {
4705
5385
  disabled,
4706
5386
  errors = [],
5387
+ onBlur,
4707
5388
  field,
4708
5389
  readonly,
4709
5390
  value = ''
@@ -4726,22 +5407,12 @@ function Textarea(props) {
4726
5407
  value: target.value
4727
5408
  });
4728
5409
  };
4729
- const autoSizeTextarea = hooks.useCallback(textarea => {
4730
- // Ensures the textarea shrinks back, and improves resizing behavior consistency
4731
- textarea.style.height = '0px';
4732
- const computed = window.getComputedStyle(textarea);
4733
- 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'));
4734
- const minHeight = 75;
4735
- const maxHeight = 350;
4736
- const displayHeight = Math.max(Math.min(calculatedHeight, maxHeight), minHeight);
4737
- textarea.style.height = `${displayHeight}px`;
4738
-
4739
- // Overflow is hidden by default to hide scrollbar flickering
4740
- textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
4741
- }, []);
5410
+ hooks.useLayoutEffect(() => {
5411
+ autoSizeTextarea(textareaRef.current);
5412
+ }, [value]);
4742
5413
  hooks.useEffect(() => {
4743
5414
  autoSizeTextarea(textareaRef.current);
4744
- }, [autoSizeTextarea, value]);
5415
+ }, []);
4745
5416
  const {
4746
5417
  formId
4747
5418
  } = hooks.useContext(FormContext$1);
@@ -4762,6 +5433,7 @@ function Textarea(props) {
4762
5433
  readonly: readonly,
4763
5434
  id: prefixId(id, formId),
4764
5435
  onInput: onInput,
5436
+ onBlur: onBlur,
4765
5437
  value: value,
4766
5438
  ref: textareaRef,
4767
5439
  "aria-describedby": errorMessageId
@@ -4786,40 +5458,58 @@ Textarea.config = {
4786
5458
  ...options
4787
5459
  })
4788
5460
  };
5461
+ const autoSizeTextarea = textarea => {
5462
+ // Ensures the textarea shrinks back, and improves resizing behavior consistency
5463
+ textarea.style.height = '0px';
5464
+ const computed = window.getComputedStyle(textarea);
5465
+ const heightFromLines = () => {
5466
+ const lineHeight = parseInt(computed.getPropertyValue('line-height').replace('px', '')) || 0;
5467
+ const lines = textarea.value ? textarea.value.toString().split('\n').length : 0;
5468
+ return lines * lineHeight;
5469
+ };
5470
+ 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'));
5471
+ const minHeight = 75;
5472
+ const maxHeight = 350;
5473
+ const displayHeight = Math.max(Math.min(calculatedHeight || 0, maxHeight), minHeight);
5474
+ textarea.style.height = `${displayHeight}px`;
5475
+
5476
+ // Overflow is hidden by default to hide scrollbar flickering
5477
+ textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
5478
+ };
4789
5479
 
4790
- var _path$b;
4791
- 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); }
5480
+ var _path$c;
5481
+ 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); }
4792
5482
  var SvgButton = function SvgButton(props) {
4793
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$d({
5483
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$e({
4794
5484
  xmlns: "http://www.w3.org/2000/svg",
4795
5485
  width: 54,
4796
5486
  height: 54,
4797
5487
  fill: "currentcolor"
4798
- }, props), _path$b || (_path$b = /*#__PURE__*/React__namespace.createElement("path", {
5488
+ }, props), _path$c || (_path$c = /*#__PURE__*/React__namespace.createElement("path", {
4799
5489
  fillRule: "evenodd",
4800
5490
  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"
4801
5491
  })));
4802
5492
  };
4803
5493
  var ButtonIcon = SvgButton;
4804
5494
 
4805
- var _path$a;
4806
- 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); }
5495
+ var _path$b;
5496
+ 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); }
4807
5497
  var SvgCheckbox = function SvgCheckbox(props) {
4808
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$c({
5498
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$d({
4809
5499
  xmlns: "http://www.w3.org/2000/svg",
4810
5500
  width: 54,
4811
5501
  height: 54,
4812
5502
  fill: "currentcolor"
4813
- }, props), _path$a || (_path$a = /*#__PURE__*/React__namespace.createElement("path", {
5503
+ }, props), _path$b || (_path$b = /*#__PURE__*/React__namespace.createElement("path", {
4814
5504
  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"
4815
5505
  })));
4816
5506
  };
4817
5507
  var CheckboxIcon = SvgCheckbox;
4818
5508
 
4819
5509
  var _g, _use, _use2, _use3, _defs;
4820
- 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); }
5510
+ 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); }
4821
5511
  var SvgChecklist = function SvgChecklist(props) {
4822
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$b({
5512
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$c({
4823
5513
  xmlns: "http://www.w3.org/2000/svg",
4824
5514
  xmlnsXlink: "http://www.w3.org/1999/xlink",
4825
5515
  width: 54,
@@ -4853,18 +5543,18 @@ var SvgChecklist = function SvgChecklist(props) {
4853
5543
  };
4854
5544
  var ChecklistIcon = SvgChecklist;
4855
5545
 
4856
- var _path$9, _path2$2, _path3;
4857
- 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); }
5546
+ var _path$a, _path2$3, _path3;
5547
+ 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); }
4858
5548
  var SvgDatetime = function SvgDatetime(props) {
4859
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$a({
5549
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$b({
4860
5550
  xmlns: "http://www.w3.org/2000/svg",
4861
5551
  width: 54,
4862
5552
  height: 54,
4863
5553
  fill: "currentcolor"
4864
- }, props), _path$9 || (_path$9 = /*#__PURE__*/React__namespace.createElement("path", {
5554
+ }, props), _path$a || (_path$a = /*#__PURE__*/React__namespace.createElement("path", {
4865
5555
  fillRule: "evenodd",
4866
5556
  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"
4867
- })), _path2$2 || (_path2$2 = /*#__PURE__*/React__namespace.createElement("path", {
5557
+ })), _path2$3 || (_path2$3 = /*#__PURE__*/React__namespace.createElement("path", {
4868
5558
  d: "m35.13 37.603 1.237-1.237-3.468-3.475v-5.926h-1.754v6.654l3.984 3.984Z"
4869
5559
  })), _path3 || (_path3 = /*#__PURE__*/React__namespace.createElement("path", {
4870
5560
  fillRule: "evenodd",
@@ -4873,27 +5563,27 @@ var SvgDatetime = function SvgDatetime(props) {
4873
5563
  };
4874
5564
  var DatetimeIcon = SvgDatetime;
4875
5565
 
4876
- var _path$8, _path2$1;
4877
- 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); }
5566
+ var _path$9, _path2$2;
5567
+ 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); }
4878
5568
  var SvgTaglist = function SvgTaglist(props) {
4879
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$9({
5569
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$a({
4880
5570
  xmlns: "http://www.w3.org/2000/svg",
4881
5571
  width: 54,
4882
5572
  height: 54,
4883
5573
  fill: "currentcolor"
4884
- }, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", {
5574
+ }, props), _path$9 || (_path$9 = /*#__PURE__*/React__namespace.createElement("path", {
4885
5575
  fillRule: "evenodd",
4886
5576
  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"
4887
- })), _path2$1 || (_path2$1 = /*#__PURE__*/React__namespace.createElement("path", {
5577
+ })), _path2$2 || (_path2$2 = /*#__PURE__*/React__namespace.createElement("path", {
4888
5578
  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"
4889
5579
  })));
4890
5580
  };
4891
5581
  var TaglistIcon = SvgTaglist;
4892
5582
 
4893
5583
  var _rect, _rect2, _rect3;
4894
- 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); }
5584
+ 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); }
4895
5585
  var SvgForm = function SvgForm(props) {
4896
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$8({
5586
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$9({
4897
5587
  xmlns: "http://www.w3.org/2000/svg",
4898
5588
  width: 54,
4899
5589
  height: 54
@@ -4919,64 +5609,87 @@ var SvgForm = function SvgForm(props) {
4919
5609
  };
4920
5610
  var FormIcon = SvgForm;
4921
5611
 
4922
- var _path$7;
4923
- 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); }
5612
+ var _path$8;
5613
+ 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); }
4924
5614
  var SvgGroup = function SvgGroup(props) {
4925
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$7({
5615
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$8({
4926
5616
  xmlns: "http://www.w3.org/2000/svg",
4927
5617
  width: 54,
4928
5618
  height: 54
4929
- }, props), _path$7 || (_path$7 = /*#__PURE__*/React__namespace.createElement("path", {
5619
+ }, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", {
4930
5620
  fillRule: "evenodd",
4931
5621
  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"
4932
5622
  })));
4933
5623
  };
4934
5624
  var ColumnsIcon = SvgGroup;
4935
5625
 
4936
- var _path$6;
4937
- 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); }
5626
+ var _path$7;
5627
+ 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); }
4938
5628
  var SvgNumber = function SvgNumber(props) {
4939
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$6({
5629
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$7({
4940
5630
  xmlns: "http://www.w3.org/2000/svg",
4941
5631
  width: 54,
4942
5632
  height: 54,
4943
5633
  fill: "currentcolor"
4944
- }, props), _path$6 || (_path$6 = /*#__PURE__*/React__namespace.createElement("path", {
5634
+ }, props), _path$7 || (_path$7 = /*#__PURE__*/React__namespace.createElement("path", {
4945
5635
  fillRule: "evenodd",
4946
5636
  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"
4947
5637
  })));
4948
5638
  };
4949
5639
  var NumberIcon = SvgNumber;
4950
5640
 
4951
- var _path$5;
4952
- 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); }
5641
+ var _path$6;
5642
+ 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); }
4953
5643
  var SvgRadio = function SvgRadio(props) {
4954
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$5({
5644
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$6({
4955
5645
  xmlns: "http://www.w3.org/2000/svg",
4956
5646
  width: 54,
4957
5647
  height: 54,
4958
5648
  fill: "currentcolor"
4959
- }, props), _path$5 || (_path$5 = /*#__PURE__*/React__namespace.createElement("path", {
5649
+ }, props), _path$6 || (_path$6 = /*#__PURE__*/React__namespace.createElement("path", {
4960
5650
  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"
4961
5651
  })));
4962
5652
  };
4963
5653
  var RadioIcon = SvgRadio;
4964
5654
 
4965
- var _path$4;
4966
- 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); }
5655
+ var _path$5;
5656
+ 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); }
4967
5657
  var SvgSelect = function SvgSelect(props) {
4968
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$4({
5658
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$5({
4969
5659
  xmlns: "http://www.w3.org/2000/svg",
4970
5660
  width: 54,
4971
5661
  height: 54,
4972
5662
  fill: "currentcolor"
4973
- }, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", {
5663
+ }, props), _path$5 || (_path$5 = /*#__PURE__*/React__namespace.createElement("path", {
4974
5664
  fillRule: "evenodd",
4975
5665
  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"
4976
5666
  })));
4977
5667
  };
4978
5668
  var SelectIcon = SvgSelect;
4979
5669
 
5670
+ var _path$4, _path2$1;
5671
+ 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); }
5672
+ var SvgSpacer = function SvgSpacer(props) {
5673
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$4({
5674
+ xmlns: "http://www.w3.org/2000/svg",
5675
+ width: 54,
5676
+ height: 54,
5677
+ fill: "none"
5678
+ }, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", {
5679
+ stroke: "#000",
5680
+ strokeLinecap: "square",
5681
+ strokeWidth: 2,
5682
+ d: "M9 23h36M9 31h36"
5683
+ })), _path2$1 || (_path2$1 = /*#__PURE__*/React__namespace.createElement("path", {
5684
+ stroke: "#000",
5685
+ strokeLinecap: "round",
5686
+ strokeLinejoin: "round",
5687
+ strokeWidth: 2,
5688
+ d: "m23 17 4-4 4 4M31 37l-4 4-4-4"
5689
+ })));
5690
+ };
5691
+ var SpacerIcon = SvgSpacer;
5692
+
4980
5693
  var _path$3;
4981
5694
  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); }
4982
5695
  var SvgText = function SvgText(props) {
@@ -5052,6 +5765,7 @@ const iconsByType = type => {
5052
5765
  number: NumberIcon,
5053
5766
  radio: RadioIcon,
5054
5767
  select: SelectIcon,
5768
+ spacer: SpacerIcon,
5055
5769
  taglist: TaglistIcon,
5056
5770
  text: TextIcon,
5057
5771
  textfield: TextfieldIcon,
@@ -5060,7 +5774,7 @@ const iconsByType = type => {
5060
5774
  }[type];
5061
5775
  };
5062
5776
 
5063
- const formFields = [Button, Checkbox, Checklist, Default, Image, Numberfield, Datetime, Radio, Select, Taglist, Text, Textfield, Textarea];
5777
+ const formFields = [Button, Checkbox, Checklist, Default, Image, Numberfield, Datetime, Radio, Select, Spacer, Taglist, Text, Textfield, Textarea];
5064
5778
 
5065
5779
  class FormFields {
5066
5780
  constructor() {
@@ -5471,7 +6185,7 @@ class Form {
5471
6185
  * @internal
5472
6186
  */
5473
6187
  _getModules() {
5474
- return [ExpressionLanguageModule, MarkdownModule];
6188
+ return [ExpressionLanguageModule, MarkdownModule, ViewerCommandsModule];
5475
6189
  }
5476
6190
 
5477
6191
  /**
@@ -5516,7 +6230,7 @@ class Form {
5516
6230
  }
5517
6231
  }
5518
6232
 
5519
- const schemaVersion = 9;
6233
+ const schemaVersion = 10;
5520
6234
 
5521
6235
  /**
5522
6236
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
@@ -5569,6 +6283,7 @@ exports.MarkdownRenderer = MarkdownRenderer;
5569
6283
  exports.Numberfield = Numberfield;
5570
6284
  exports.Radio = Radio;
5571
6285
  exports.Select = Select;
6286
+ exports.Spacer = Spacer;
5572
6287
  exports.TIME_INTERVAL_PATH = TIME_INTERVAL_PATH;
5573
6288
  exports.TIME_LABEL_PATH = TIME_LABEL_PATH;
5574
6289
  exports.TIME_SERIALISINGFORMAT_LABELS = TIME_SERIALISINGFORMAT_LABELS;
@@ -5584,6 +6299,8 @@ exports.VALUES_SOURCES_DEFAULTS = VALUES_SOURCES_DEFAULTS;
5584
6299
  exports.VALUES_SOURCES_LABELS = VALUES_SOURCES_LABELS;
5585
6300
  exports.VALUES_SOURCES_PATHS = VALUES_SOURCES_PATHS;
5586
6301
  exports.VALUES_SOURCE_DEFAULT = VALUES_SOURCE_DEFAULT;
6302
+ exports.ViewerCommands = ViewerCommands;
6303
+ exports.ViewerCommandsModule = ViewerCommandsModule;
5587
6304
  exports.clone = clone;
5588
6305
  exports.createForm = createForm;
5589
6306
  exports.createFormContainer = createFormContainer;