@bpmn-io/form-js-viewer 1.5.0-alpha.0 → 1.6.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.
Files changed (78) hide show
  1. package/dist/assets/form-js-base.css +244 -16
  2. package/dist/assets/form-js.css +676 -670
  3. package/dist/index.cjs +2100 -722
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.es.js +2083 -717
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/types/Form.d.ts +15 -4
  8. package/dist/types/core/FieldFactory.d.ts +3 -1
  9. package/dist/types/core/FormFieldRegistry.d.ts +2 -1
  10. package/dist/types/core/FormLayouter.d.ts +2 -2
  11. package/dist/types/core/Importer.d.ts +1 -1
  12. package/dist/types/core/PathRegistry.d.ts +8 -4
  13. package/dist/types/core/Validator.d.ts +1 -1
  14. package/dist/types/core/index.d.ts +8 -8
  15. package/dist/types/features/{expression-language → expressionLanguage}/ConditionChecker.d.ts +9 -5
  16. package/dist/types/features/{expression-language → expressionLanguage}/FeelExpressionLanguage.d.ts +1 -1
  17. package/dist/types/features/{expression-language → expressionLanguage}/FeelersTemplating.d.ts +1 -1
  18. package/dist/types/features/{expression-language → expressionLanguage}/index.d.ts +4 -4
  19. package/dist/types/features/index.d.ts +4 -2
  20. package/dist/types/features/markdown/MarkdownRenderer.d.ts +1 -1
  21. package/dist/types/features/markdown/index.d.ts +2 -2
  22. package/dist/types/features/repeatRender/RepeatRenderManager.d.ts +21 -0
  23. package/dist/types/features/repeatRender/index.d.ts +7 -0
  24. package/dist/types/features/viewerCommands/ViewerCommands.d.ts +2 -2
  25. package/dist/types/features/viewerCommands/cmd/UpdateFieldValidationHandler.d.ts +1 -1
  26. package/dist/types/features/viewerCommands/index.d.ts +3 -3
  27. package/dist/types/index.d.ts +1 -1
  28. package/dist/types/render/Renderer.d.ts +1 -1
  29. package/dist/types/render/components/Label.d.ts +21 -1
  30. package/dist/types/render/components/Sanitizer.d.ts +8 -0
  31. package/dist/types/render/components/Util.d.ts +1 -1
  32. package/dist/types/render/components/form-fields/Button.d.ts +3 -3
  33. package/dist/types/render/components/form-fields/Checkbox.d.ts +4 -4
  34. package/dist/types/render/components/form-fields/Checklist.d.ts +5 -5
  35. package/dist/types/render/components/form-fields/Datetime.d.ts +4 -4
  36. package/dist/types/render/components/form-fields/Default.d.ts +4 -4
  37. package/dist/types/render/components/form-fields/DynamicList.d.ts +18 -0
  38. package/dist/types/render/components/form-fields/Group.d.ts +4 -4
  39. package/dist/types/render/components/form-fields/IFrame.d.ts +12 -0
  40. package/dist/types/render/components/form-fields/Image.d.ts +3 -3
  41. package/dist/types/render/components/form-fields/Number.d.ts +4 -4
  42. package/dist/types/render/components/form-fields/Radio.d.ts +5 -5
  43. package/dist/types/render/components/form-fields/Select.d.ts +5 -5
  44. package/dist/types/render/components/form-fields/Separator.d.ts +3 -3
  45. package/dist/types/render/components/form-fields/Spacer.d.ts +3 -3
  46. package/dist/types/render/components/form-fields/Table.d.ts +71 -0
  47. package/dist/types/render/components/form-fields/Taglist.d.ts +5 -5
  48. package/dist/types/render/components/form-fields/Text.d.ts +3 -3
  49. package/dist/types/render/components/form-fields/Textarea.d.ts +4 -4
  50. package/dist/types/render/components/form-fields/Textfield.d.ts +4 -4
  51. package/dist/types/render/components/form-fields/parts/ChildrenRenderer.d.ts +1 -0
  52. package/dist/types/render/components/index.d.ts +5 -2
  53. package/dist/types/render/components/util/optionsUtil.d.ts +8 -0
  54. package/dist/types/render/context/FormRenderContext.d.ts +4 -3
  55. package/dist/types/render/context/LocalExpressionContext.d.ts +7 -0
  56. package/dist/types/render/context/index.d.ts +1 -0
  57. package/dist/types/render/hooks/index.d.ts +1 -0
  58. package/dist/types/render/hooks/useCleanupMultiSelectValues.d.ts +1 -0
  59. package/dist/types/render/hooks/useCleanupSingleSelectValue.d.ts +1 -0
  60. package/dist/types/render/hooks/useExpressionEvaluation.d.ts +3 -3
  61. package/dist/types/render/hooks/useFilteredFormData.d.ts +1 -0
  62. package/dist/types/render/hooks/useOptionsAsync.d.ts +28 -0
  63. package/dist/types/render/hooks/useScrollIntoView.d.ts +18 -0
  64. package/dist/types/render/hooks/useTemplateEvaluation.d.ts +1 -1
  65. package/dist/types/render/index.d.ts +4 -3
  66. package/dist/types/util/constants/DatetimeConstants.d.ts +6 -6
  67. package/dist/types/util/constants/OptionsSourceConstants.d.ts +19 -0
  68. package/dist/types/util/constants/index.d.ts +1 -1
  69. package/dist/types/util/getSchemaVariables.d.ts +39 -0
  70. package/dist/types/util/index.d.ts +3 -52
  71. package/dist/types/util/simple.d.ts +20 -0
  72. package/dist/types/util/structure.d.ts +1 -0
  73. package/package.json +5 -5
  74. package/dist/types/render/components/form-fields/parts/Grid.d.ts +0 -1
  75. package/dist/types/render/components/util/valuesUtil.d.ts +0 -8
  76. package/dist/types/render/hooks/useValuesAsync.d.ts +0 -28
  77. package/dist/types/util/constants/ValuesSourceConstants.d.ts +0 -19
  78. /package/dist/types/features/{expression-language → expressionLanguage}/variableExtractionHelpers.d.ts +0 -0
package/dist/index.cjs CHANGED
@@ -3,16 +3,16 @@
3
3
  var Ids = require('ids');
4
4
  var minDash = require('min-dash');
5
5
  var Big = require('big.js');
6
- var feelin = require('feelin');
7
- var feelers = require('feelers');
8
6
  var classNames = require('classnames');
9
7
  var jsxRuntime = require('preact/jsx-runtime');
10
8
  var hooks = require('preact/hooks');
11
9
  var preact = require('preact');
12
- var React = require('preact/compat');
13
10
  var flatpickr = require('flatpickr');
11
+ var React = require('preact/compat');
14
12
  var Markup = require('preact-markup');
15
13
  var didi = require('didi');
14
+ var feelin = require('feelin');
15
+ var feelers = require('feelers');
16
16
  var showdown = require('showdown');
17
17
 
18
18
  function _interopNamespaceDefault(e) {
@@ -413,6 +413,92 @@ class FeelersTemplating {
413
413
  }
414
414
  FeelersTemplating.$inject = [];
415
415
 
416
+ // config ///////////////////
417
+
418
+ const MINUTES_IN_DAY = 60 * 24;
419
+ const DATETIME_SUBTYPES = {
420
+ DATE: 'date',
421
+ TIME: 'time',
422
+ DATETIME: 'datetime'
423
+ };
424
+ const TIME_SERIALISING_FORMATS = {
425
+ UTC_OFFSET: 'utc_offset',
426
+ UTC_NORMALIZED: 'utc_normalized',
427
+ NO_TIMEZONE: 'no_timezone'
428
+ };
429
+ const DATETIME_SUBTYPES_LABELS = {
430
+ [DATETIME_SUBTYPES.DATE]: 'Date',
431
+ [DATETIME_SUBTYPES.TIME]: 'Time',
432
+ [DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
433
+ };
434
+ const TIME_SERIALISINGFORMAT_LABELS = {
435
+ [TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
436
+ [TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
437
+ [TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
438
+ };
439
+ const DATETIME_SUBTYPE_PATH = ['subtype'];
440
+ const DATE_LABEL_PATH = ['dateLabel'];
441
+ const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
442
+ const TIME_LABEL_PATH = ['timeLabel'];
443
+ const TIME_USE24H_PATH = ['use24h'];
444
+ const TIME_INTERVAL_PATH = ['timeInterval'];
445
+ const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
446
+
447
+ // config ///////////////////
448
+
449
+ const OPTIONS_SOURCES = {
450
+ STATIC: 'static',
451
+ INPUT: 'input',
452
+ EXPRESSION: 'expression'
453
+ };
454
+ const OPTIONS_SOURCE_DEFAULT = OPTIONS_SOURCES.STATIC;
455
+ const OPTIONS_SOURCES_LABELS = {
456
+ [OPTIONS_SOURCES.STATIC]: 'Static',
457
+ [OPTIONS_SOURCES.INPUT]: 'Input data',
458
+ [OPTIONS_SOURCES.EXPRESSION]: 'Expression'
459
+ };
460
+ const OPTIONS_SOURCES_PATHS = {
461
+ [OPTIONS_SOURCES.STATIC]: ['values'],
462
+ [OPTIONS_SOURCES.INPUT]: ['valuesKey'],
463
+ [OPTIONS_SOURCES.EXPRESSION]: ['valuesExpression']
464
+ };
465
+ const OPTIONS_SOURCES_DEFAULTS = {
466
+ [OPTIONS_SOURCES.STATIC]: [{
467
+ label: 'Value',
468
+ value: 'value'
469
+ }],
470
+ [OPTIONS_SOURCES.INPUT]: '',
471
+ [OPTIONS_SOURCES.EXPRESSION]: '='
472
+ };
473
+
474
+ // helpers ///////////////////
475
+
476
+ function getOptionsSource(field) {
477
+ for (const source of Object.values(OPTIONS_SOURCES)) {
478
+ if (minDash.get(field, OPTIONS_SOURCES_PATHS[source]) !== undefined) {
479
+ return source;
480
+ }
481
+ }
482
+ return OPTIONS_SOURCE_DEFAULT;
483
+ }
484
+
485
+ function createInjector(bootstrapModules) {
486
+ const injector = new didi.Injector(bootstrapModules);
487
+ injector.init();
488
+ return injector;
489
+ }
490
+
491
+ /**
492
+ * @param {string?} prefix
493
+ *
494
+ * @returns Element
495
+ */
496
+ function createFormContainer(prefix = 'fjs') {
497
+ const container = document.createElement('div');
498
+ container.classList.add(`${prefix}-container`);
499
+ return container;
500
+ }
501
+
416
502
  function formFieldClasses(type, {
417
503
  errors = [],
418
504
  disabled = false,
@@ -438,14 +524,19 @@ function gridColumnClasses(formField) {
438
524
  // always fall back to top-down on smallest screens
439
525
  'cds--col-sm-16', 'cds--col-md-16');
440
526
  }
441
- function prefixId(id, formId) {
527
+ function prefixId(id, formId, indexes) {
528
+ let result = 'fjs-form';
442
529
  if (formId) {
443
- return `fjs-form-${formId}-${id}`;
530
+ result += `-${formId}`;
444
531
  }
445
- return `fjs-form-${id}`;
532
+ result += `-${id}`;
533
+ Object.values(indexes || {}).forEach(index => {
534
+ result += `_${index}`;
535
+ });
536
+ return result;
446
537
  }
447
538
 
448
- const type$d = 'button';
539
+ const type$f = 'button';
449
540
  function Button(props) {
450
541
  const {
451
542
  disabled,
@@ -457,7 +548,7 @@ function Button(props) {
457
548
  action = 'submit'
458
549
  } = field;
459
550
  return jsxRuntime.jsx("div", {
460
- class: formFieldClasses(type$d),
551
+ class: formFieldClasses(type$f),
461
552
  children: jsxRuntime.jsx("button", {
462
553
  class: "fjs-button",
463
554
  type: action,
@@ -469,7 +560,7 @@ function Button(props) {
469
560
  });
470
561
  }
471
562
  Button.config = {
472
- type: type$d,
563
+ type: type$f,
473
564
  keyed: false,
474
565
  label: 'Button',
475
566
  group: 'action',
@@ -480,27 +571,30 @@ Button.config = {
480
571
  };
481
572
 
482
573
  const FormRenderContext = preact.createContext({
483
- EmptyRoot: props => {
574
+ Empty: props => {
484
575
  return null;
485
576
  },
486
- Empty: props => {
577
+ Hidden: props => {
487
578
  return null;
488
579
  },
489
580
  Children: props => {
490
581
  return jsxRuntime.jsx("div", {
491
582
  class: props.class,
583
+ style: props.style,
492
584
  children: props.children
493
585
  });
494
586
  },
495
587
  Element: props => {
496
588
  return jsxRuntime.jsx("div", {
497
589
  class: props.class,
590
+ style: props.style,
498
591
  children: props.children
499
592
  });
500
593
  },
501
594
  Row: props => {
502
595
  return jsxRuntime.jsx("div", {
503
596
  class: props.class,
597
+ style: props.style,
504
598
  children: props.children
505
599
  });
506
600
  },
@@ -510,16 +604,24 @@ const FormRenderContext = preact.createContext({
510
604
  }
511
605
  return jsxRuntime.jsx("div", {
512
606
  class: props.class,
607
+ style: props.style,
513
608
  children: props.children
514
609
  });
515
610
  },
516
- hoveredId: [],
517
- setHoveredId: newValue => {
518
- console.log(`setHoveredId not defined, called with '${newValue}'`);
611
+ hoverInfo: {
612
+ cleanup: () => {}
519
613
  }
520
614
  });
521
615
  var FormRenderContext$1 = FormRenderContext;
522
616
 
617
+ const LocalExpressionContext = preact.createContext({
618
+ data: null,
619
+ this: null,
620
+ parent: null,
621
+ i: null
622
+ });
623
+ var LocalExpressionContext$1 = LocalExpressionContext;
624
+
523
625
  /**
524
626
  * @param {string} type
525
627
  * @param {boolean} [strict]
@@ -540,24 +642,77 @@ function useService(type, strict) {
540
642
  return getService(type, strict);
541
643
  }
542
644
 
645
+ function isRequired(field) {
646
+ return field.required;
647
+ }
648
+ function pathParse(path) {
649
+ if (!path) {
650
+ return [];
651
+ }
652
+ return path.split('.').map(key => {
653
+ return isNaN(parseInt(key)) ? key : parseInt(key);
654
+ });
655
+ }
656
+ function pathsEqual(a, b) {
657
+ return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
658
+ }
659
+ const indices = {};
660
+ function generateIndexForType(type) {
661
+ if (type in indices) {
662
+ indices[type]++;
663
+ } else {
664
+ indices[type] = 1;
665
+ }
666
+ return indices[type];
667
+ }
668
+ function generateIdForType(type) {
669
+ return `${type}${generateIndexForType(type)}`;
670
+ }
671
+
543
672
  /**
544
- * Returns the conditionally filtered data of a form reactively.
545
- * Memoised to minimize re-renders
673
+ * @template T
674
+ * @param {T} data
675
+ * @param {(this: any, key: string, value: any) => any} [replacer]
676
+ * @return {T}
677
+ */
678
+ function clone(data, replacer) {
679
+ return JSON.parse(JSON.stringify(data, replacer));
680
+ }
681
+
682
+ /**
683
+ * Transform a LocalExpressionContext object into a usable FEEL context.
546
684
  *
685
+ * @param {Object} context - The LocalExpressionContext object.
686
+ * @returns {Object} The usable FEEL context.
547
687
  */
548
- function useFilteredFormData() {
688
+
689
+ function buildExpressionContext(context) {
549
690
  const {
550
- initialData,
551
- data
552
- } = useService('form')._getState();
553
- const conditionChecker = useService('conditionChecker', false);
554
- return hooks.useMemo(() => {
555
- const newData = conditionChecker ? conditionChecker.applyConditions(data, data) : data;
556
- return {
557
- ...initialData,
558
- ...newData
559
- };
560
- }, [conditionChecker, data, initialData]);
691
+ data,
692
+ ...specialContextKeys
693
+ } = context;
694
+ return {
695
+ ...specialContextKeys,
696
+ ...data,
697
+ ..._wrapObjectKeysWithUnderscores(specialContextKeys)
698
+ };
699
+ }
700
+ function runRecursively(formField, fn) {
701
+ const components = formField.components || [];
702
+ components.forEach((component, index) => {
703
+ runRecursively(component, fn);
704
+ });
705
+ fn(formField);
706
+ }
707
+
708
+ // helpers //////////////////////
709
+
710
+ function _wrapObjectKeysWithUnderscores(obj) {
711
+ const newObj = {};
712
+ for (const [key, value] of Object.entries(obj)) {
713
+ newObj[`_${key}_`] = value;
714
+ }
715
+ return newObj;
561
716
  }
562
717
 
563
718
  /**
@@ -569,29 +724,125 @@ function useFilteredFormData() {
569
724
  */
570
725
  function useCondition(condition) {
571
726
  const conditionChecker = useService('conditionChecker', false);
572
- const filteredData = useFilteredFormData();
727
+ const expressionContextInfo = hooks.useContext(LocalExpressionContext$1);
573
728
  return hooks.useMemo(() => {
574
- return conditionChecker ? conditionChecker.check(condition, filteredData) : null;
575
- }, [conditionChecker, condition, filteredData]);
729
+ return conditionChecker ? conditionChecker.check(condition, buildExpressionContext(expressionContextInfo)) : null;
730
+ }, [conditionChecker, condition, expressionContextInfo]);
731
+ }
732
+
733
+ /**
734
+ * Custom hook to scroll an element into view only when it is not visible within the viewport.
735
+ *
736
+ * @param {Object} targetRef - A ref pointing to the DOM element to scroll into view.
737
+ * @param {Array} deps - An array of dependencies that trigger the effect.
738
+ * @param {Array} flagRefs - An array of refs that are used as flags to control when to scroll.
739
+ * @param {Object} [scrollOptions={}] - Options defining the behavior of the scrolling.
740
+ * @param {String} [scrollOptions.align='center'] - The alignment of the element within the viewport.
741
+ * @param {String} [scrollOptions.behavior='auto'] - The scrolling behavior.
742
+ * @param {Number} [scrollOptions.offset=0] - An offset that is added to the scroll position.
743
+ * @param {Boolean} [scrollOptions.scrollIfVisible=false] - Whether to scroll even if the element is visible.
744
+ */
745
+ function useScrollIntoView(targetRef, deps, scrollOptions = null, flagRefs = []) {
746
+ hooks.useEffect(() => {
747
+ // return early if flags are not raised, or component is not mounted
748
+ if (minDash.some(flagRefs, ref => !ref.current) || !targetRef.current) {
749
+ return;
750
+ }
751
+ for (let i = 0; i < flagRefs.length; i++) {
752
+ flagRefs[i].current = false;
753
+ }
754
+ const itemToBeScrolled = targetRef.current;
755
+ const scrollContainer = _getNearestScrollableAncestor(itemToBeScrolled);
756
+ if (!scrollContainer) {
757
+ return;
758
+ }
759
+ const itemRect = itemToBeScrolled.getBoundingClientRect();
760
+ const containerRect = scrollContainer.getBoundingClientRect();
761
+
762
+ // should scroll if visible or scrollIfVisible option is set
763
+ const shouldScroll = scrollOptions.scrollIfVisible || !(itemRect.top >= containerRect.top && itemRect.bottom <= containerRect.bottom);
764
+ if (!shouldScroll) {
765
+ return;
766
+ }
767
+ const {
768
+ align = 'center',
769
+ offset = 0,
770
+ behavior = 'auto'
771
+ } = scrollOptions;
772
+ const topOffset = _getTopOffset(itemToBeScrolled, scrollContainer, {
773
+ align,
774
+ offset
775
+ });
776
+ scrollContainer.scroll({
777
+ top: topOffset,
778
+ behavior
779
+ });
780
+
781
+ // eslint-disable-next-line react-hooks/exhaustive-deps
782
+ }, deps);
783
+ }
784
+
785
+ // helper //////////////////////
786
+
787
+ function _getNearestScrollableAncestor(el) {
788
+ while (el) {
789
+ if (el.scrollHeight > el.clientHeight) {
790
+ return el;
791
+ }
792
+ el = el.parentElement;
793
+ }
794
+ }
795
+ function _getTopOffset(item, scrollContainer, options) {
796
+ const itemRect = item.getBoundingClientRect();
797
+ const containerRect = scrollContainer.getBoundingClientRect();
798
+ if (options.align === 'top') {
799
+ return itemRect.top - containerRect.top + scrollContainer.scrollTop - options.offset;
800
+ } else if (options.align === 'bottom') {
801
+ return itemRect.bottom - containerRect.top - scrollContainer.clientHeight + scrollContainer.scrollTop + options.offset;
802
+ } else if (options.align === 'center') {
803
+ return itemRect.top - containerRect.top - scrollContainer.clientHeight / 2 + scrollContainer.scrollTop + itemRect.height / 2 + options.offset;
804
+ }
805
+ return 0;
576
806
  }
577
807
 
578
808
  /**
579
809
  * Evaluate a string reactively based on the expressionLanguage and form data.
580
810
  * If the string is not an expression, it is returned as is.
581
- * Memoised to minimize re-renders.
582
- *
583
- * @param {string} value
811
+ * The function is memoized to minimize re-renders.
584
812
  *
813
+ * @param {string} value - The string to evaluate.
814
+ * @returns {any} - Evaluated value or the original value if not an expression.
585
815
  */
586
816
  function useExpressionEvaluation(value) {
587
- const formData = useFilteredFormData();
588
817
  const expressionLanguage = useService('expressionLanguage');
818
+ const expressionContextInfo = hooks.useContext(LocalExpressionContext$1);
589
819
  return hooks.useMemo(() => {
590
820
  if (expressionLanguage && expressionLanguage.isExpression(value)) {
591
- return expressionLanguage.evaluate(value, formData);
821
+ return expressionLanguage.evaluate(value, buildExpressionContext(expressionContextInfo));
592
822
  }
593
823
  return value;
594
- }, [expressionLanguage, formData, value]);
824
+ }, [expressionLanguage, expressionContextInfo, value]);
825
+ }
826
+
827
+ /**
828
+ * Returns the conditionally filtered data of a form reactively.
829
+ * Memoised to minimize re-renders
830
+ *
831
+ * Warning: costly operation, use with care
832
+ */
833
+ function useFilteredFormData() {
834
+ const {
835
+ initialData,
836
+ data
837
+ } = useService('form')._getState();
838
+ const conditionChecker = useService('conditionChecker', false);
839
+ return hooks.useMemo(() => {
840
+ const newData = conditionChecker ? conditionChecker.applyConditions(data, data) : data;
841
+ return {
842
+ ...initialData,
843
+ ...newData
844
+ };
845
+ }, [conditionChecker, data, initialData]);
595
846
  }
596
847
 
597
848
  function useKeyDownAction(targetKey, action, listenerElement = window) {
@@ -624,7 +875,7 @@ function useKeyDownAction(targetKey, action, listenerElement = window) {
624
875
  function useReadonly(formField, properties = {}) {
625
876
  const expressionLanguage = useService('expressionLanguage');
626
877
  const conditionChecker = useService('conditionChecker', false);
627
- const filteredData = useFilteredFormData();
878
+ const expressionContextInfo = hooks.useContext(LocalExpressionContext$1);
628
879
  const {
629
880
  readonly
630
881
  } = formField;
@@ -632,7 +883,7 @@ function useReadonly(formField, properties = {}) {
632
883
  return true;
633
884
  }
634
885
  if (expressionLanguage && expressionLanguage.isExpression(readonly)) {
635
- return conditionChecker ? conditionChecker.check(readonly, filteredData) : false;
886
+ return conditionChecker ? conditionChecker.check(readonly, buildExpressionContext(expressionContextInfo)) : false;
636
887
  }
637
888
  return readonly || false;
638
889
  }
@@ -679,15 +930,15 @@ function compare(a, b) {
679
930
  * @param {Function} [options.buildDebugString]
680
931
  *
681
932
  */
682
- function useTemplateEvaluation(value, options) {
683
- const filteredData = useFilteredFormData();
933
+ function useTemplateEvaluation(value, options = {}) {
684
934
  const templating = useService('templating');
935
+ const expressionContextInfo = hooks.useContext(LocalExpressionContext$1);
685
936
  return hooks.useMemo(() => {
686
937
  if (templating && templating.isTemplate(value)) {
687
- return templating.evaluate(value, filteredData, options);
938
+ return templating.evaluate(value, buildExpressionContext(expressionContextInfo), options);
688
939
  }
689
940
  return value;
690
- }, [filteredData, templating, value, options]);
941
+ }, [templating, value, expressionContextInfo, options]);
691
942
  }
692
943
 
693
944
  /**
@@ -767,11 +1018,13 @@ function Label(props) {
767
1018
  });
768
1019
  }
769
1020
 
770
- const type$c = 'checkbox';
1021
+ const type$e = 'checkbox';
771
1022
  function Checkbox(props) {
772
1023
  const {
773
1024
  disabled,
774
1025
  errors = [],
1026
+ errorMessageId,
1027
+ domId,
775
1028
  onBlur,
776
1029
  onFocus,
777
1030
  field,
@@ -780,7 +1033,6 @@ function Checkbox(props) {
780
1033
  } = props;
781
1034
  const {
782
1035
  description,
783
- id,
784
1036
  label,
785
1037
  validate = {}
786
1038
  } = field;
@@ -795,12 +1047,8 @@ function Checkbox(props) {
795
1047
  value: target.checked
796
1048
  });
797
1049
  };
798
- const {
799
- formId
800
- } = hooks.useContext(FormContext$1);
801
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
802
1050
  return jsxRuntime.jsxs("div", {
803
- class: classNames(formFieldClasses(type$c, {
1051
+ class: classNames(formFieldClasses(type$e, {
804
1052
  errors,
805
1053
  disabled,
806
1054
  readonly
@@ -808,7 +1056,7 @@ function Checkbox(props) {
808
1056
  'fjs-checked': value
809
1057
  }),
810
1058
  children: [jsxRuntime.jsx(Label, {
811
- id: prefixId(id, formId),
1059
+ id: domId,
812
1060
  label: label,
813
1061
  required: required,
814
1062
  children: jsxRuntime.jsx("input", {
@@ -816,7 +1064,7 @@ function Checkbox(props) {
816
1064
  class: "fjs-input",
817
1065
  disabled: disabled,
818
1066
  readOnly: readonly,
819
- id: prefixId(id, formId),
1067
+ id: domId,
820
1068
  type: "checkbox",
821
1069
  onChange: onChange,
822
1070
  onBlur: () => onBlur && onBlur(),
@@ -832,7 +1080,7 @@ function Checkbox(props) {
832
1080
  });
833
1081
  }
834
1082
  Checkbox.config = {
835
- type: type$c,
1083
+ type: type$e,
836
1084
  keyed: true,
837
1085
  label: 'Checkbox',
838
1086
  group: 'selection',
@@ -846,54 +1094,54 @@ Checkbox.config = {
846
1094
  };
847
1095
 
848
1096
  // parses the options data from the provided form field and form data
849
- function getValuesData(formField, formData) {
1097
+ function getOptionsData(formField, formData) {
850
1098
  const {
851
- valuesKey,
852
- values
1099
+ valuesKey: optionsKey,
1100
+ values: staticOptions
853
1101
  } = formField;
854
- return valuesKey ? minDash.get(formData, [valuesKey]) : values;
1102
+ return optionsKey ? minDash.get(formData, [optionsKey]) : staticOptions;
855
1103
  }
856
1104
 
857
1105
  // transforms the provided options into a normalized format, trimming invalid options
858
- function normalizeValuesData(valuesData) {
859
- return valuesData.filter(_isValueSomething).map(v => _normalizeValueData(v)).filter(v => v);
1106
+ function normalizeOptionsData(optionsData) {
1107
+ return optionsData.filter(_isOptionSomething).map(v => _normalizeOptionsData(v)).filter(v => v);
860
1108
  }
861
- function _normalizeValueData(valueData) {
862
- if (_isAllowedValue(valueData)) {
1109
+ function _normalizeOptionsData(optionData) {
1110
+ if (_isAllowedOption(optionData)) {
863
1111
  // if a primitive is provided, use it as label and value
864
1112
  return {
865
- value: valueData,
866
- label: `${valueData}`
1113
+ value: optionData,
1114
+ label: `${optionData}`
867
1115
  };
868
1116
  }
869
- if (typeof valueData === 'object') {
870
- if (!valueData.label && _isAllowedValue(valueData.value)) {
1117
+ if (typeof optionData === 'object') {
1118
+ if (!optionData.label && _isAllowedOption(optionData.value)) {
871
1119
  // if no label is provided, use the value as label
872
1120
  return {
873
- value: valueData.value,
874
- label: `${valueData.value}`
1121
+ value: optionData.value,
1122
+ label: `${optionData.value}`
875
1123
  };
876
1124
  }
877
- if (_isValueSomething(valueData.value) && _isAllowedValue(valueData.label)) {
1125
+ if (_isOptionSomething(optionData.value) && _isAllowedOption(optionData.label)) {
878
1126
  // if both value and label are provided, use them as is, in this scenario, the value may also be an object
879
- return valueData;
1127
+ return optionData;
880
1128
  }
881
1129
  }
882
1130
  return null;
883
1131
  }
884
- function _isAllowedValue(value) {
885
- return _isReadableType(value) && _isValueSomething(value);
1132
+ function _isAllowedOption(option) {
1133
+ return _isReadableType(option) && _isOptionSomething(option);
886
1134
  }
887
- function _isReadableType(value) {
888
- return ['number', 'string', 'boolean'].includes(typeof value);
1135
+ function _isReadableType(option) {
1136
+ return ['number', 'string', 'boolean'].includes(typeof option);
889
1137
  }
890
- function _isValueSomething(value) {
891
- return value || value === 0 || value === false;
1138
+ function _isOptionSomething(option) {
1139
+ return option || option === 0 || option === false;
892
1140
  }
893
1141
  function createEmptyOptions(options = {}) {
894
1142
  const defaults = {};
895
1143
 
896
- // provide default values if valuesKey and valuesExpression are not set
1144
+ // provide default options if valuesKey and valuesExpression are not set
897
1145
  if (!options.valuesKey && !options.valuesExpression) {
898
1146
  defaults.values = [{
899
1147
  label: 'Value',
@@ -916,102 +1164,95 @@ const LOAD_STATES = {
916
1164
  };
917
1165
 
918
1166
  /**
919
- * @typedef {Object} ValuesGetter
920
- * @property {Object[]} values - The values data
921
- * @property {(LOAD_STATES)} state - The values data's loading state, to use for conditional rendering
1167
+ * @typedef {Object} OptionsGetter
1168
+ * @property {Object[]} options - The options data
1169
+ * @property {(LOAD_STATES)} loadState - The options data's loading state, to use for conditional rendering
922
1170
  */
923
1171
 
924
1172
  /**
925
- * A hook to load values for single and multiselect components.
1173
+ * A hook to load options for single and multiselect components.
926
1174
  *
927
- * @param {Object} field - The form field to handle values for
928
- * @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
1175
+ * @param {Object} field - The form field to handle options for
1176
+ * @return {OptionsGetter} optionsGetter - A options getter object providing loading state and options
929
1177
  */
930
- function useValuesAsync (field) {
1178
+ function useOptionsAsync (field) {
931
1179
  const {
932
- valuesExpression,
933
- valuesKey,
934
- values: staticValues
1180
+ valuesExpression: optionsExpression,
1181
+ valuesKey: optionsKey,
1182
+ values: staticOptions
935
1183
  } = field;
936
- const [valuesGetter, setValuesGetter] = hooks.useState({
937
- values: [],
1184
+ const [optionsGetter, setOptionsGetter] = hooks.useState({
1185
+ options: [],
938
1186
  error: undefined,
939
- state: LOAD_STATES.LOADING
1187
+ loadState: LOAD_STATES.LOADING
940
1188
  });
941
1189
  const initialData = useService('form')._getState().initialData;
942
- const expressionEvaluation = useExpressionEvaluation(valuesExpression);
943
- const evaluatedValues = useDeepCompareState(expressionEvaluation || [], []);
1190
+ const expressionEvaluation = useExpressionEvaluation(optionsExpression);
1191
+ const evaluatedOptions = useDeepCompareState(expressionEvaluation || [], []);
944
1192
  hooks.useEffect(() => {
945
- let values = [];
1193
+ let options = [];
946
1194
 
947
- // dynamic values
948
- if (valuesKey !== undefined) {
949
- const keyedValues = (initialData || {})[valuesKey];
950
- if (keyedValues && Array.isArray(keyedValues)) {
951
- values = keyedValues;
1195
+ // dynamic options
1196
+ if (optionsKey !== undefined) {
1197
+ const keyedOptions = (initialData || {})[optionsKey];
1198
+ if (keyedOptions && Array.isArray(keyedOptions)) {
1199
+ options = keyedOptions;
952
1200
  }
953
1201
 
954
- // static values
955
- } else if (staticValues !== undefined) {
956
- values = Array.isArray(staticValues) ? staticValues : [];
1202
+ // static options
1203
+ } else if (staticOptions !== undefined) {
1204
+ options = Array.isArray(staticOptions) ? staticOptions : [];
957
1205
 
958
1206
  // expression
959
- } else if (valuesExpression) {
960
- if (evaluatedValues && Array.isArray(evaluatedValues)) {
961
- values = evaluatedValues;
1207
+ } else if (optionsExpression) {
1208
+ if (evaluatedOptions && Array.isArray(evaluatedOptions)) {
1209
+ options = evaluatedOptions;
962
1210
  }
963
1211
  } else {
964
- setValuesGetter(buildErrorState('No values source defined in the form definition'));
1212
+ setOptionsGetter(buildErrorState('No options source defined in the form definition'));
965
1213
  return;
966
1214
  }
967
1215
 
968
1216
  // normalize data to support primitives and partially defined objects
969
- values = normalizeValuesData(values);
970
- setValuesGetter(buildLoadedState(values));
971
- }, [valuesKey, staticValues, initialData, valuesExpression, evaluatedValues]);
972
- return valuesGetter;
1217
+ options = normalizeOptionsData(options);
1218
+ setOptionsGetter(buildLoadedState(options));
1219
+ }, [optionsKey, staticOptions, initialData, optionsExpression, evaluatedOptions]);
1220
+ return optionsGetter;
973
1221
  }
974
1222
  const buildErrorState = error => ({
975
- values: [],
1223
+ options: [],
976
1224
  error,
977
- state: LOAD_STATES.ERROR
1225
+ loadState: LOAD_STATES.ERROR
978
1226
  });
979
- const buildLoadedState = values => ({
980
- values,
1227
+ const buildLoadedState = options => ({
1228
+ options,
981
1229
  error: undefined,
982
- state: LOAD_STATES.LOADED
1230
+ loadState: LOAD_STATES.LOADED
983
1231
  });
984
1232
 
985
- // config ///////////////////
1233
+ function useCleanupMultiSelectValues (props) {
1234
+ const {
1235
+ field,
1236
+ options,
1237
+ loadState,
1238
+ onChange,
1239
+ values
1240
+ } = props;
986
1241
 
987
- const MINUTES_IN_DAY = 60 * 24;
988
- const DATETIME_SUBTYPES = {
989
- DATE: 'date',
990
- TIME: 'time',
991
- DATETIME: 'datetime'
992
- };
993
- const TIME_SERIALISING_FORMATS = {
994
- UTC_OFFSET: 'utc_offset',
995
- UTC_NORMALIZED: 'utc_normalized',
996
- NO_TIMEZONE: 'no_timezone'
997
- };
998
- const DATETIME_SUBTYPES_LABELS = {
999
- [DATETIME_SUBTYPES.DATE]: 'Date',
1000
- [DATETIME_SUBTYPES.TIME]: 'Time',
1001
- [DATETIME_SUBTYPES.DATETIME]: 'Date & Time'
1002
- };
1003
- const TIME_SERIALISINGFORMAT_LABELS = {
1004
- [TIME_SERIALISING_FORMATS.UTC_OFFSET]: 'UTC offset',
1005
- [TIME_SERIALISING_FORMATS.UTC_NORMALIZED]: 'UTC normalized',
1006
- [TIME_SERIALISING_FORMATS.NO_TIMEZONE]: 'No timezone'
1007
- };
1008
- const DATETIME_SUBTYPE_PATH = ['subtype'];
1009
- const DATE_LABEL_PATH = ['dateLabel'];
1010
- const DATE_DISALLOW_PAST_PATH = ['disallowPassedDates'];
1011
- const TIME_LABEL_PATH = ['timeLabel'];
1012
- const TIME_USE24H_PATH = ['use24h'];
1013
- const TIME_INTERVAL_PATH = ['timeInterval'];
1014
- const TIME_SERIALISING_FORMAT_PATH = ['timeSerializingFormat'];
1242
+ // Ensures that the values are always a subset of the possible options
1243
+ hooks.useEffect(() => {
1244
+ if (loadState !== LOAD_STATES.LOADED) {
1245
+ return;
1246
+ }
1247
+ const hasValuesNotInOptions = values.some(v => !options.map(o => o.value).includes(v));
1248
+ if (hasValuesNotInOptions) {
1249
+ onChange({
1250
+ field,
1251
+ value: values.filter(v => options.map(o => o.value).includes(v))
1252
+ });
1253
+ }
1254
+ }, [field, options, onChange, JSON.stringify(values), loadState]);
1255
+ }
1015
1256
 
1016
1257
  const ENTER_KEYDOWN_EVENT = new KeyboardEvent('keydown', {
1017
1258
  code: 'Enter',
@@ -1195,7 +1436,7 @@ function sanitizeSingleSelectValue(options) {
1195
1436
  value
1196
1437
  } = options;
1197
1438
  try {
1198
- const validValues = normalizeValuesData(getValuesData(formField, data)).map(v => v.value);
1439
+ const validValues = normalizeOptionsData(getOptionsData(formField, data)).map(v => v.value);
1199
1440
  return validValues.includes(value) ? value : null;
1200
1441
  } catch (error) {
1201
1442
  // use default value in case of formatting error
@@ -1210,7 +1451,7 @@ function sanitizeMultiSelectValue(options) {
1210
1451
  value
1211
1452
  } = options;
1212
1453
  try {
1213
- const validValues = normalizeValuesData(getValuesData(formField, data)).map(v => v.value);
1454
+ const validValues = normalizeOptionsData(getOptionsData(formField, data)).map(v => v.value);
1214
1455
  return value.filter(v => validValues.includes(v));
1215
1456
  } catch (error) {
1216
1457
  // use default value in case of formatting error
@@ -1219,20 +1460,21 @@ function sanitizeMultiSelectValue(options) {
1219
1460
  }
1220
1461
  }
1221
1462
 
1222
- const type$b = 'checklist';
1463
+ const type$d = 'checklist';
1223
1464
  function Checklist(props) {
1224
1465
  const {
1225
1466
  disabled,
1226
1467
  errors = [],
1468
+ errorMessageId,
1469
+ domId,
1227
1470
  onBlur,
1228
1471
  onFocus,
1229
1472
  field,
1230
1473
  readonly,
1231
- value = []
1474
+ value: values = []
1232
1475
  } = props;
1233
1476
  const {
1234
1477
  description,
1235
- id,
1236
1478
  label,
1237
1479
  validate = {}
1238
1480
  } = field;
@@ -1241,7 +1483,7 @@ function Checklist(props) {
1241
1483
  required
1242
1484
  } = validate;
1243
1485
  const toggleCheckbox = v => {
1244
- let newValue = [...value];
1486
+ let newValue = [...values];
1245
1487
  if (!newValue.includes(v)) {
1246
1488
  newValue.push(v);
1247
1489
  } else {
@@ -1265,15 +1507,18 @@ function Checklist(props) {
1265
1507
  onFocus && onFocus();
1266
1508
  };
1267
1509
  const {
1268
- state: loadState,
1269
- values: options
1270
- } = useValuesAsync(field);
1271
- const {
1272
- formId
1273
- } = hooks.useContext(FormContext$1);
1274
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
1510
+ loadState,
1511
+ options
1512
+ } = useOptionsAsync(field);
1513
+ useCleanupMultiSelectValues({
1514
+ field,
1515
+ loadState,
1516
+ options,
1517
+ values,
1518
+ onChange: props.onChange
1519
+ });
1275
1520
  return jsxRuntime.jsxs("div", {
1276
- class: classNames(formFieldClasses(type$b, {
1521
+ class: classNames(formFieldClasses(type$d, {
1277
1522
  errors,
1278
1523
  disabled,
1279
1524
  readonly
@@ -1282,27 +1527,28 @@ function Checklist(props) {
1282
1527
  children: [jsxRuntime.jsx(Label, {
1283
1528
  label: label,
1284
1529
  required: required
1285
- }), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
1530
+ }), loadState == LOAD_STATES.LOADED && options.map((o, index) => {
1531
+ const itemDomId = `${domId}-${index}`;
1286
1532
  return jsxRuntime.jsx(Label, {
1287
- id: prefixId(`${id}-${index}`, formId),
1288
- label: v.label,
1533
+ id: itemDomId,
1534
+ label: o.label,
1289
1535
  class: classNames({
1290
- 'fjs-checked': value.includes(v.value)
1536
+ 'fjs-checked': values.includes(o.value)
1291
1537
  }),
1292
1538
  required: false,
1293
1539
  children: jsxRuntime.jsx("input", {
1294
- checked: value.includes(v.value),
1540
+ checked: values.includes(o.value),
1295
1541
  class: "fjs-input",
1296
1542
  disabled: disabled,
1297
1543
  readOnly: readonly,
1298
- id: prefixId(`${id}-${index}`, formId),
1544
+ id: itemDomId,
1299
1545
  type: "checkbox",
1300
- onClick: () => toggleCheckbox(v.value),
1546
+ onClick: () => toggleCheckbox(o.value),
1301
1547
  onBlur: onCheckboxBlur,
1302
1548
  onFocus: onCheckboxFocus,
1303
1549
  "aria-describedby": errorMessageId
1304
1550
  })
1305
- }, `${id}-${index}`);
1551
+ });
1306
1552
  }), jsxRuntime.jsx(Description, {
1307
1553
  description: description
1308
1554
  }), jsxRuntime.jsx(Errors, {
@@ -1312,9 +1558,9 @@ function Checklist(props) {
1312
1558
  });
1313
1559
  }
1314
1560
  Checklist.config = {
1315
- type: type$b,
1561
+ type: type$d,
1316
1562
  keyed: true,
1317
- label: 'Checklist',
1563
+ label: 'Checkbox group',
1318
1564
  group: 'selection',
1319
1565
  emptyValue: [],
1320
1566
  sanitizeValue: sanitizeMultiSelectValue,
@@ -1325,6 +1571,7 @@ const noop$1 = () => false;
1325
1571
  function FormField(props) {
1326
1572
  const {
1327
1573
  field,
1574
+ indexes,
1328
1575
  onChange
1329
1576
  } = props;
1330
1577
  const formFields = useService('formFields'),
@@ -1340,14 +1587,19 @@ function FormField(props) {
1340
1587
  } = form._getState();
1341
1588
  const {
1342
1589
  Element,
1343
- Empty,
1590
+ Hidden,
1344
1591
  Column
1345
1592
  } = hooks.useContext(FormRenderContext$1);
1593
+ const {
1594
+ formId
1595
+ } = hooks.useContext(FormContext$1);
1346
1596
  const FormFieldComponent = formFields.get(field.type);
1347
1597
  if (!FormFieldComponent) {
1348
1598
  throw new Error(`cannot render field <${field.type}>`);
1349
1599
  }
1350
- const valuePath = hooks.useMemo(() => pathRegistry.getValuePath(field), [field, pathRegistry]);
1600
+ const valuePath = hooks.useMemo(() => pathRegistry.getValuePath(field, {
1601
+ indexes
1602
+ }), [field, indexes, pathRegistry]);
1351
1603
  const initialValue = hooks.useMemo(() => minDash.get(initialData, valuePath), [initialData, valuePath]);
1352
1604
  const readonly = useReadonly(field, properties);
1353
1605
  const value = minDash.get(data, valuePath);
@@ -1356,12 +1608,12 @@ function FormField(props) {
1356
1608
  const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
1357
1609
  const onBlur = hooks.useCallback(() => {
1358
1610
  if (viewerCommands) {
1359
- viewerCommands.updateFieldValidation(field, value);
1611
+ viewerCommands.updateFieldValidation(field, value, indexes);
1360
1612
  }
1361
1613
  eventBus.fire('formField.blur', {
1362
1614
  formField: field
1363
1615
  });
1364
- }, [eventBus, viewerCommands, field, value]);
1616
+ }, [eventBus, viewerCommands, field, value, indexes]);
1365
1617
  const onFocus = hooks.useCallback(() => {
1366
1618
  eventBus.fire('formField.focus', {
1367
1619
  formField: field
@@ -1369,13 +1621,25 @@ function FormField(props) {
1369
1621
  }, [eventBus, field]);
1370
1622
  hooks.useEffect(() => {
1371
1623
  if (viewerCommands && initialValue) {
1372
- viewerCommands.updateFieldValidation(field, initialValue);
1624
+ viewerCommands.updateFieldValidation(field, initialValue, indexes);
1373
1625
  }
1374
- }, [viewerCommands, field, initialValue]);
1626
+ }, [viewerCommands, field, initialValue, JSON.stringify(indexes)]);
1375
1627
  const hidden = useCondition(field.conditional && field.conditional.hide || null);
1628
+ const onChangeIndexed = hooks.useCallback(update => {
1629
+ // add indexes of the keyed field to the update, if any
1630
+ onChange(FormFieldComponent.config.keyed ? {
1631
+ ...update,
1632
+ indexes
1633
+ } : update);
1634
+ }, [onChange, FormFieldComponent.config.keyed, indexes]);
1376
1635
  if (hidden) {
1377
- return jsxRuntime.jsx(Empty, {});
1636
+ return jsxRuntime.jsx(Hidden, {
1637
+ field: field
1638
+ });
1378
1639
  }
1640
+ const domId = `${prefixId(field.id, formId, indexes)}`;
1641
+ const fieldErrors = minDash.get(errors, [field.id, ...Object.values(indexes || {})]) || [];
1642
+ const errorMessageId = errors.length === 0 ? undefined : `${domId}-error-message`;
1379
1643
  return jsxRuntime.jsx(Column, {
1380
1644
  field: field,
1381
1645
  class: gridColumnClasses(field),
@@ -1385,8 +1649,10 @@ function FormField(props) {
1385
1649
  children: jsxRuntime.jsx(FormFieldComponent, {
1386
1650
  ...props,
1387
1651
  disabled: disabled,
1388
- errors: errors[field.id],
1389
- onChange: disabled || readonly ? noop$1 : onChange,
1652
+ errors: fieldErrors,
1653
+ errorMessageId: errorMessageId,
1654
+ domId: domId,
1655
+ onChange: disabled || readonly ? noop$1 : onChangeIndexed,
1390
1656
  onBlur: disabled || readonly ? noop$1 : onBlur,
1391
1657
  onFocus: disabled || readonly ? noop$1 : onFocus,
1392
1658
  readonly: readonly,
@@ -1396,26 +1662,109 @@ function FormField(props) {
1396
1662
  });
1397
1663
  }
1398
1664
 
1399
- function Grid(props) {
1665
+ function ChildrenRenderer(props) {
1400
1666
  const {
1401
- Children,
1402
- Row
1667
+ Children
1403
1668
  } = hooks.useContext(FormRenderContext$1);
1404
1669
  const {
1405
1670
  field,
1406
1671
  Empty
1407
1672
  } = props;
1408
1673
  const {
1409
- id,
1674
+ id
1675
+ } = field;
1676
+ const repeatRenderManager = useService('repeatRenderManager', false);
1677
+ const isRepeating = repeatRenderManager && repeatRenderManager.isFieldRepeating(id);
1678
+ const Repeater = repeatRenderManager.Repeater;
1679
+ const RepeatFooter = repeatRenderManager.RepeatFooter;
1680
+ return isRepeating ? jsxRuntime.jsx(RepeatChildrenRenderer, {
1681
+ ...props,
1682
+ ChildrenRoot: Children,
1683
+ Empty,
1684
+ Repeater,
1685
+ RepeatFooter,
1686
+ repeatRenderManager
1687
+ }) : jsxRuntime.jsx(SimpleChildrenRenderer, {
1688
+ ...props,
1689
+ ChildrenRoot: Children,
1690
+ Empty
1691
+ });
1692
+ }
1693
+ function SimpleChildrenRenderer(props) {
1694
+ const {
1695
+ ChildrenRoot,
1696
+ Empty,
1697
+ field
1698
+ } = props;
1699
+ const {
1410
1700
  components = []
1411
1701
  } = field;
1412
- const formLayouter = useService('formLayouter');
1413
- const formFieldRegistry = useService('formFieldRegistry');
1414
- const rows = formLayouter.getRows(id);
1415
- return jsxRuntime.jsxs(Children, {
1702
+ const isEmpty = !components.length;
1703
+ return jsxRuntime.jsxs(ChildrenRoot, {
1416
1704
  class: "fjs-vertical-layout fjs-children cds--grid cds--grid--condensed",
1417
1705
  field: field,
1418
- children: [rows.map(row => {
1706
+ children: [jsxRuntime.jsx(RowsRenderer, {
1707
+ ...props
1708
+ }), isEmpty ? jsxRuntime.jsx(Empty, {
1709
+ field: field
1710
+ }) : null]
1711
+ });
1712
+ }
1713
+ function RepeatChildrenRenderer(props) {
1714
+ const {
1715
+ ChildrenRoot,
1716
+ repeatRenderManager,
1717
+ Empty,
1718
+ field,
1719
+ ...restProps
1720
+ } = props;
1721
+ const {
1722
+ components = []
1723
+ } = field;
1724
+ const useSharedState = hooks.useState({
1725
+ isCollapsed: true
1726
+ });
1727
+ const Repeater = repeatRenderManager.Repeater;
1728
+ const RepeatFooter = repeatRenderManager.RepeatFooter;
1729
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
1730
+ children: [jsxRuntime.jsxs(ChildrenRoot, {
1731
+ class: "fjs-vertical-layout fjs-children cds--grid cds--grid--condensed",
1732
+ field: field,
1733
+ children: [Repeater ? jsxRuntime.jsx(Repeater, {
1734
+ ...restProps,
1735
+ useSharedState,
1736
+ field,
1737
+ RowsRenderer
1738
+ }) : jsxRuntime.jsx(RowsRenderer, {
1739
+ ...restProps,
1740
+ field
1741
+ }), !components.length ? jsxRuntime.jsx(Empty, {
1742
+ field: field
1743
+ }) : null]
1744
+ }), RepeatFooter ? jsxRuntime.jsx(RepeatFooter, {
1745
+ ...restProps,
1746
+ useSharedState,
1747
+ field
1748
+ }) : null]
1749
+ });
1750
+ }
1751
+ function RowsRenderer(props) {
1752
+ const {
1753
+ field,
1754
+ indexes
1755
+ } = props;
1756
+ const {
1757
+ id: parentId,
1758
+ verticalAlignment = 'start'
1759
+ } = field;
1760
+ const formLayouter = useService('formLayouter');
1761
+ const formFieldRegistry = useService('formFieldRegistry');
1762
+ const rows = formLayouter.getRows(parentId);
1763
+ const {
1764
+ Row
1765
+ } = hooks.useContext(FormRenderContext$1);
1766
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, {
1767
+ children: [" ", rows.map(row => {
1419
1768
  const {
1420
1769
  components = []
1421
1770
  } = row;
@@ -1425,31 +1774,35 @@ function Grid(props) {
1425
1774
  return jsxRuntime.jsx(Row, {
1426
1775
  row: row,
1427
1776
  class: "fjs-layout-row cds--row",
1428
- children: components.map(id => {
1429
- const childField = formFieldRegistry.get(id);
1777
+ style: {
1778
+ alignItems: verticalAlignment
1779
+ },
1780
+ children: components.map(childId => {
1781
+ const childField = formFieldRegistry.get(childId);
1430
1782
  if (!childField) {
1431
1783
  return null;
1432
1784
  }
1433
1785
  return preact.createElement(FormField, {
1434
1786
  ...props,
1435
- key: childField.id,
1436
- field: childField
1787
+ key: childId,
1788
+ field: childField,
1789
+ indexes: indexes
1437
1790
  });
1438
1791
  })
1439
1792
  });
1440
- }), components.length ? null : jsxRuntime.jsx(Empty, {})]
1793
+ }), " "]
1441
1794
  });
1442
1795
  }
1443
1796
 
1444
1797
  function FormComponent$1(props) {
1445
1798
  const {
1446
- EmptyRoot
1799
+ Empty
1447
1800
  } = hooks.useContext(FormRenderContext$1);
1448
1801
  const fullProps = {
1449
1802
  ...props,
1450
- Empty: EmptyRoot
1803
+ Empty
1451
1804
  };
1452
- return jsxRuntime.jsx(Grid, {
1805
+ return jsxRuntime.jsx(ChildrenRenderer, {
1453
1806
  ...fullProps
1454
1807
  });
1455
1808
  }
@@ -1464,24 +1817,6 @@ FormComponent$1.config = {
1464
1817
  })
1465
1818
  };
1466
1819
 
1467
- var _path$i;
1468
- function _extends$l() { _extends$l = 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$l.apply(this, arguments); }
1469
- var SvgCalendar = function SvgCalendar(props) {
1470
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$l({
1471
- xmlns: "http://www.w3.org/2000/svg",
1472
- width: 14,
1473
- height: 15,
1474
- fill: "none",
1475
- viewBox: "0 0 28 30"
1476
- }, props), _path$i || (_path$i = /*#__PURE__*/React__namespace.createElement("path", {
1477
- fill: "currentColor",
1478
- fillRule: "evenodd",
1479
- 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",
1480
- clipRule: "evenodd"
1481
- })));
1482
- };
1483
- var CalendarIcon = SvgCalendar;
1484
-
1485
1820
  /**
1486
1821
  * Returns date format for the provided locale.
1487
1822
  * If the locale is not provided, uses the browser's locale.
@@ -1550,6 +1885,24 @@ function flatpickerizeDateFormat(dateFormat) {
1550
1885
  return dateFormat;
1551
1886
  }
1552
1887
 
1888
+ var _path$u;
1889
+ function _extends$w() { _extends$w = 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$w.apply(this, arguments); }
1890
+ var SvgCalendar = function SvgCalendar(props) {
1891
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$w({
1892
+ xmlns: "http://www.w3.org/2000/svg",
1893
+ width: 14,
1894
+ height: 15,
1895
+ fill: "none",
1896
+ viewBox: "0 0 28 30"
1897
+ }, props), _path$u || (_path$u = /*#__PURE__*/React__namespace.createElement("path", {
1898
+ fill: "currentColor",
1899
+ fillRule: "evenodd",
1900
+ 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",
1901
+ clipRule: "evenodd"
1902
+ })));
1903
+ };
1904
+ var CalendarIcon = SvgCalendar;
1905
+
1553
1906
  function InputAdorner(props) {
1554
1907
  const {
1555
1908
  pre,
@@ -1590,12 +1943,11 @@ function InputAdorner(props) {
1590
1943
 
1591
1944
  function Datepicker(props) {
1592
1945
  const {
1593
- id,
1594
1946
  label,
1947
+ domId,
1595
1948
  collapseLabelOnEmpty,
1596
1949
  onDateTimeBlur,
1597
1950
  onDateTimeFocus,
1598
- formId,
1599
1951
  required,
1600
1952
  disabled,
1601
1953
  disallowPassedDates,
@@ -1695,11 +2047,10 @@ function Datepicker(props) {
1695
2047
  }
1696
2048
  onDateTimeBlur(e);
1697
2049
  }, [isInputDirty, onDateTimeBlur]);
1698
- const fullId = `${prefixId(id, formId)}--date`;
1699
2050
  return jsxRuntime.jsxs("div", {
1700
2051
  class: "fjs-datetime-subsection",
1701
2052
  children: [jsxRuntime.jsx(Label, {
1702
- id: fullId,
2053
+ id: domId,
1703
2054
  label: label,
1704
2055
  collapseOnEmpty: collapseLabelOnEmpty,
1705
2056
  required: required
@@ -1717,7 +2068,7 @@ function Datepicker(props) {
1717
2068
  children: jsxRuntime.jsx("input", {
1718
2069
  ref: dateInputRef,
1719
2070
  type: "text",
1720
- id: fullId,
2071
+ id: domId,
1721
2072
  class: "fjs-input",
1722
2073
  disabled: disabled,
1723
2074
  readOnly: readonly,
@@ -1736,19 +2087,19 @@ function Datepicker(props) {
1736
2087
  });
1737
2088
  }
1738
2089
 
1739
- var _path$h, _path2$3;
1740
- 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); }
2090
+ var _path$t, _path2$5;
2091
+ function _extends$v() { _extends$v = 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$v.apply(this, arguments); }
1741
2092
  var SvgClock = function SvgClock(props) {
1742
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$k({
2093
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$v({
1743
2094
  xmlns: "http://www.w3.org/2000/svg",
1744
2095
  width: 16,
1745
2096
  height: 16,
1746
2097
  fill: "none",
1747
2098
  viewBox: "0 0 28 29"
1748
- }, props), _path$h || (_path$h = /*#__PURE__*/React__namespace.createElement("path", {
2099
+ }, props), _path$t || (_path$t = /*#__PURE__*/React__namespace.createElement("path", {
1749
2100
  fill: "currentColor",
1750
2101
  d: "M13 14.41 18.59 20 20 18.59l-5-5.01V5h-2v9.41Z"
1751
- })), _path2$3 || (_path2$3 = /*#__PURE__*/React__namespace.createElement("path", {
2102
+ })), _path2$5 || (_path2$5 = /*#__PURE__*/React__namespace.createElement("path", {
1752
2103
  fill: "currentColor",
1753
2104
  fillRule: "evenodd",
1754
2105
  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",
@@ -1855,12 +2206,11 @@ function DropdownList(props) {
1855
2206
 
1856
2207
  function Timepicker(props) {
1857
2208
  const {
1858
- id,
1859
2209
  label,
1860
2210
  collapseLabelOnEmpty,
1861
2211
  onDateTimeBlur,
1862
2212
  onDateTimeFocus,
1863
- formId,
2213
+ domId,
1864
2214
  required,
1865
2215
  disabled,
1866
2216
  readonly,
@@ -1969,11 +2319,10 @@ function Timepicker(props) {
1969
2319
  setDropdownIsOpen(false);
1970
2320
  propagateRawToMinute(value);
1971
2321
  };
1972
- const fullId = `${prefixId(id, formId)}--time`;
1973
2322
  return jsxRuntime.jsxs("div", {
1974
2323
  class: "fjs-datetime-subsection",
1975
2324
  children: [jsxRuntime.jsx(Label, {
1976
- id: fullId,
2325
+ id: domId,
1977
2326
  label: label,
1978
2327
  collapseOnEmpty: collapseLabelOnEmpty,
1979
2328
  required: required
@@ -1987,7 +2336,7 @@ function Timepicker(props) {
1987
2336
  children: [jsxRuntime.jsx("input", {
1988
2337
  ref: timeInputRef,
1989
2338
  type: "text",
1990
- id: fullId,
2339
+ id: domId,
1991
2340
  class: "fjs-input",
1992
2341
  value: rawValue,
1993
2342
  disabled: disabled,
@@ -2019,11 +2368,12 @@ function Timepicker(props) {
2019
2368
  });
2020
2369
  }
2021
2370
 
2022
- const type$a = 'datetime';
2371
+ const type$c = 'datetime';
2023
2372
  function Datetime(props) {
2024
2373
  const {
2025
2374
  disabled,
2026
2375
  errors = [],
2376
+ domId,
2027
2377
  onBlur,
2028
2378
  onFocus,
2029
2379
  field,
@@ -2160,12 +2510,11 @@ function Datetime(props) {
2160
2510
  }, []);
2161
2511
  const errorMessageId = allErrors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
2162
2512
  const datePickerProps = {
2163
- id,
2164
2513
  label: dateLabel,
2165
2514
  collapseLabelOnEmpty: !timeLabel,
2166
2515
  onDateTimeBlur,
2167
2516
  onDateTimeFocus,
2168
- formId,
2517
+ domId: `${domId}-date`,
2169
2518
  required,
2170
2519
  disabled,
2171
2520
  disallowPassedDates,
@@ -2175,12 +2524,11 @@ function Datetime(props) {
2175
2524
  'aria-describedby': errorMessageId
2176
2525
  };
2177
2526
  const timePickerProps = {
2178
- id,
2179
2527
  label: timeLabel,
2180
2528
  collapseLabelOnEmpty: !dateLabel,
2181
2529
  onDateTimeBlur,
2182
2530
  onDateTimeFocus,
2183
- formId,
2531
+ domId: `${domId}-time`,
2184
2532
  required,
2185
2533
  disabled,
2186
2534
  readonly,
@@ -2191,7 +2539,7 @@ function Datetime(props) {
2191
2539
  'aria-describedby': errorMessageId
2192
2540
  };
2193
2541
  return jsxRuntime.jsxs("div", {
2194
- class: formFieldClasses(type$a, {
2542
+ class: formFieldClasses(type$c, {
2195
2543
  errors: allErrors,
2196
2544
  disabled,
2197
2545
  readonly
@@ -2215,7 +2563,7 @@ function Datetime(props) {
2215
2563
  });
2216
2564
  }
2217
2565
  Datetime.config = {
2218
- type: type$a,
2566
+ type: type$c,
2219
2567
  keyed: true,
2220
2568
  label: 'Date time',
2221
2569
  group: 'basic-input',
@@ -2344,32 +2692,39 @@ function FormComponent(props) {
2344
2692
  event.preventDefault();
2345
2693
  onReset();
2346
2694
  };
2695
+ const filteredFormData = useFilteredFormData();
2696
+ const localExpressionContext = hooks.useMemo(() => ({
2697
+ data: filteredFormData,
2698
+ parent: null,
2699
+ this: filteredFormData,
2700
+ i: []
2701
+ }), [filteredFormData]);
2347
2702
  return jsxRuntime.jsxs("form", {
2348
2703
  class: "fjs-form",
2349
2704
  onSubmit: handleSubmit,
2350
2705
  onReset: handleReset,
2351
2706
  "aria-label": ariaLabel,
2352
2707
  noValidate: true,
2353
- children: [jsxRuntime.jsx(FormField, {
2354
- field: schema,
2355
- onChange: onChange
2708
+ children: [jsxRuntime.jsx(LocalExpressionContext$1.Provider, {
2709
+ value: localExpressionContext,
2710
+ children: jsxRuntime.jsx(FormField, {
2711
+ field: schema,
2712
+ onChange: onChange
2713
+ })
2356
2714
  }), jsxRuntime.jsx(PoweredBy, {})]
2357
2715
  });
2358
2716
  }
2359
2717
 
2360
2718
  function Group(props) {
2361
2719
  const {
2362
- field
2720
+ field,
2721
+ domId
2363
2722
  } = props;
2364
2723
  const {
2365
2724
  label,
2366
- id,
2367
2725
  type,
2368
2726
  showOutline
2369
2727
  } = field;
2370
- const {
2371
- formId
2372
- } = hooks.useContext(FormContext$1);
2373
2728
  const {
2374
2729
  Empty
2375
2730
  } = hooks.useContext(FormRenderContext$1);
@@ -2378,15 +2733,15 @@ function Group(props) {
2378
2733
  Empty
2379
2734
  };
2380
2735
  return jsxRuntime.jsxs("div", {
2381
- className: classNames(formFieldClasses(type), {
2736
+ className: classNames(formFieldClasses(type), 'fjs-form-field-grouplike', {
2382
2737
  'fjs-outlined': showOutline
2383
2738
  }),
2384
2739
  role: "group",
2385
- "aria-labelledby": prefixId(id, formId),
2740
+ "aria-labelledby": domId,
2386
2741
  children: [jsxRuntime.jsx(Label, {
2387
- id: prefixId(id, formId),
2742
+ id: domId,
2388
2743
  label: label
2389
- }), jsxRuntime.jsx(Grid, {
2744
+ }), jsxRuntime.jsx(ChildrenRenderer, {
2390
2745
  ...fullProps
2391
2746
  })]
2392
2747
  });
@@ -2395,7 +2750,7 @@ Group.config = {
2395
2750
  type: 'group',
2396
2751
  pathed: true,
2397
2752
  label: 'Group',
2398
- group: 'presentation',
2753
+ group: 'container',
2399
2754
  create: (options = {}) => ({
2400
2755
  components: [],
2401
2756
  showOutline: true,
@@ -2409,6 +2764,7 @@ const ALLOWED_NODES = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'em', 'a', 'p
2409
2764
  const ALLOWED_ATTRIBUTES = ['align', 'alt', 'class', 'href', 'id', 'name', 'rel', 'target', 'src'];
2410
2765
  const ALLOWED_URI_PATTERN = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i; // eslint-disable-line no-useless-escape
2411
2766
  const ALLOWED_IMAGE_SRC_PATTERN = /^(https?|data):.*/i; // eslint-disable-line no-useless-escape
2767
+ const ALLOWED_IFRAME_SRC_PATTERN = /^(https):\/\/*/i; // eslint-disable-line no-useless-escape
2412
2768
  const ATTR_WHITESPACE_PATTERN = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g; // eslint-disable-line no-control-regex
2413
2769
 
2414
2770
  const FORM_ELEMENT = document.createElement('form');
@@ -2449,6 +2805,18 @@ function sanitizeImageSource(src) {
2449
2805
  return valid ? src : '';
2450
2806
  }
2451
2807
 
2808
+ /**
2809
+ * Sanitizes an iframe source to ensure we only allow for links
2810
+ * that start with http(s).
2811
+ *
2812
+ * @param {string} src
2813
+ * @returns {string}
2814
+ */
2815
+ function sanitizeIFrameSource(src) {
2816
+ const valid = ALLOWED_IFRAME_SRC_PATTERN.test(src);
2817
+ return valid ? src : '';
2818
+ }
2819
+
2452
2820
  /**
2453
2821
  * Recursively sanitize a HTML node, potentially
2454
2822
  * removing it, its children or attributes.
@@ -2530,9 +2898,77 @@ function isValidAttribute(lcTag, lcName, value) {
2530
2898
  return true;
2531
2899
  }
2532
2900
 
2533
- 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); }
2901
+ const type$b = 'iframe';
2902
+ const DEFAULT_HEIGHT = 300;
2903
+ function IFrame(props) {
2904
+ const {
2905
+ field,
2906
+ disabled,
2907
+ readonly
2908
+ } = props;
2909
+ const {
2910
+ height = DEFAULT_HEIGHT,
2911
+ id,
2912
+ label,
2913
+ url
2914
+ } = field;
2915
+ const evaluatedUrl = useSingleLineTemplateEvaluation(url, {
2916
+ debug: true
2917
+ });
2918
+ const safeUrl = hooks.useMemo(() => sanitizeIFrameSource(evaluatedUrl), [evaluatedUrl]);
2919
+ const evaluatedLabel = useSingleLineTemplateEvaluation(label, {
2920
+ debug: true
2921
+ });
2922
+ const {
2923
+ formId
2924
+ } = hooks.useContext(FormContext$1);
2925
+ return jsxRuntime.jsxs("div", {
2926
+ class: formFieldClasses(type$b, {
2927
+ disabled,
2928
+ readonly
2929
+ }),
2930
+ children: [jsxRuntime.jsx(Label, {
2931
+ id: prefixId(id, formId),
2932
+ label: evaluatedLabel
2933
+ }), !evaluatedUrl && jsxRuntime.jsx(IFramePlaceholder, {
2934
+ text: "No content to show."
2935
+ }), evaluatedUrl && safeUrl && jsxRuntime.jsx("iframe", {
2936
+ src: safeUrl,
2937
+ title: evaluatedLabel,
2938
+ height: height,
2939
+ class: "fjs-iframe",
2940
+ id: prefixId(id, formId),
2941
+ sandbox: ""
2942
+ }), evaluatedUrl && !safeUrl && jsxRuntime.jsx(IFramePlaceholder, {
2943
+ text: "External content couldn't be loaded."
2944
+ })]
2945
+ });
2946
+ }
2947
+ function IFramePlaceholder(props) {
2948
+ const {
2949
+ text = 'iFrame'
2950
+ } = props;
2951
+ return jsxRuntime.jsx("div", {
2952
+ class: "fjs-iframe-placeholder",
2953
+ children: jsxRuntime.jsx("p", {
2954
+ class: "fjs-iframe-placeholder-text",
2955
+ children: text
2956
+ })
2957
+ });
2958
+ }
2959
+ IFrame.config = {
2960
+ type: type$b,
2961
+ keyed: false,
2962
+ label: 'iFrame',
2963
+ group: 'container',
2964
+ create: (options = {}) => ({
2965
+ ...options
2966
+ })
2967
+ };
2968
+
2969
+ function _extends$u() { _extends$u = 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$u.apply(this, arguments); }
2534
2970
  var SvgImagePlaceholder = function SvgImagePlaceholder(props) {
2535
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$j({
2971
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$u({
2536
2972
  xmlns: "http://www.w3.org/2000/svg",
2537
2973
  xmlSpace: "preserve",
2538
2974
  width: 64,
@@ -2571,7 +3007,7 @@ var SvgImagePlaceholder = function SvgImagePlaceholder(props) {
2571
3007
  };
2572
3008
  var ImagePlaceholder = SvgImagePlaceholder;
2573
3009
 
2574
- const type$9 = 'image';
3010
+ const type$a = 'image';
2575
3011
  function Image(props) {
2576
3012
  const {
2577
3013
  field
@@ -2592,7 +3028,7 @@ function Image(props) {
2592
3028
  formId
2593
3029
  } = hooks.useContext(FormContext$1);
2594
3030
  return jsxRuntime.jsx("div", {
2595
- class: formFieldClasses(type$9),
3031
+ class: formFieldClasses(type$a),
2596
3032
  children: jsxRuntime.jsxs("div", {
2597
3033
  class: "fjs-image-container",
2598
3034
  children: [safeSource && jsxRuntime.jsx("img", {
@@ -2610,7 +3046,7 @@ function Image(props) {
2610
3046
  });
2611
3047
  }
2612
3048
  Image.config = {
2613
- type: type$9,
3049
+ type: type$a,
2614
3050
  keyed: false,
2615
3051
  label: 'Image view',
2616
3052
  group: 'presentation',
@@ -2637,14 +3073,14 @@ function TemplatedInputAdorner(props) {
2637
3073
  });
2638
3074
  }
2639
3075
 
2640
- var _path$g;
2641
- 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); }
3076
+ var _path$s;
3077
+ function _extends$t() { _extends$t = 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$t.apply(this, arguments); }
2642
3078
  var SvgAngelDown = function SvgAngelDown(props) {
2643
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$i({
3079
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$t({
2644
3080
  xmlns: "http://www.w3.org/2000/svg",
2645
3081
  width: 8,
2646
3082
  height: 8
2647
- }, props), _path$g || (_path$g = /*#__PURE__*/React__namespace.createElement("path", {
3083
+ }, props), _path$s || (_path$s = /*#__PURE__*/React__namespace.createElement("path", {
2648
3084
  fill: "currentColor",
2649
3085
  fillRule: "evenodd",
2650
3086
  stroke: "currentColor",
@@ -2655,14 +3091,14 @@ var SvgAngelDown = function SvgAngelDown(props) {
2655
3091
  };
2656
3092
  var AngelDownIcon = SvgAngelDown;
2657
3093
 
2658
- var _path$f;
2659
- 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); }
3094
+ var _path$r;
3095
+ function _extends$s() { _extends$s = 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$s.apply(this, arguments); }
2660
3096
  var SvgAngelUp = function SvgAngelUp(props) {
2661
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$h({
3097
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$s({
2662
3098
  xmlns: "http://www.w3.org/2000/svg",
2663
3099
  width: 8,
2664
3100
  height: 8
2665
- }, props), _path$f || (_path$f = /*#__PURE__*/React__namespace.createElement("path", {
3101
+ }, props), _path$r || (_path$r = /*#__PURE__*/React__namespace.createElement("path", {
2666
3102
  fill: "currentColor",
2667
3103
  fillRule: "evenodd",
2668
3104
  stroke: "currentColor",
@@ -2698,11 +3134,13 @@ function isNullEquivalentValue(value) {
2698
3134
  return value === undefined || value === null || value === '';
2699
3135
  }
2700
3136
 
2701
- const type$8 = 'number';
3137
+ const type$9 = 'number';
2702
3138
  function Numberfield(props) {
2703
3139
  const {
2704
3140
  disabled,
2705
3141
  errors = [],
3142
+ errorMessageId,
3143
+ domId,
2706
3144
  onBlur,
2707
3145
  onFocus,
2708
3146
  field,
@@ -2712,7 +3150,6 @@ function Numberfield(props) {
2712
3150
  } = props;
2713
3151
  const {
2714
3152
  description,
2715
- id,
2716
3153
  label,
2717
3154
  appearance = {},
2718
3155
  validate = {},
@@ -2832,18 +3269,14 @@ function Numberfield(props) {
2832
3269
  e.preventDefault();
2833
3270
  }
2834
3271
  };
2835
- const {
2836
- formId
2837
- } = hooks.useContext(FormContext$1);
2838
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
2839
3272
  return jsxRuntime.jsxs("div", {
2840
- class: formFieldClasses(type$8, {
3273
+ class: formFieldClasses(type$9, {
2841
3274
  errors,
2842
3275
  disabled,
2843
3276
  readonly
2844
3277
  }),
2845
3278
  children: [jsxRuntime.jsx(Label, {
2846
- id: prefixId(id, formId),
3279
+ id: domId,
2847
3280
  label: label,
2848
3281
  required: required
2849
3282
  }), jsxRuntime.jsx(TemplatedInputAdorner, {
@@ -2863,7 +3296,7 @@ function Numberfield(props) {
2863
3296
  class: "fjs-input",
2864
3297
  disabled: disabled,
2865
3298
  readOnly: readonly,
2866
- id: prefixId(id, formId),
3299
+ id: domId,
2867
3300
  onKeyDown: onKeyDown,
2868
3301
  onKeyPress: onKeyPress,
2869
3302
  onBlur: () => onBlur && onBlur(),
@@ -2910,7 +3343,7 @@ function Numberfield(props) {
2910
3343
  });
2911
3344
  }
2912
3345
  Numberfield.config = {
2913
- type: type$8,
3346
+ type: type$9,
2914
3347
  keyed: true,
2915
3348
  label: 'Number',
2916
3349
  group: 'basic-input',
@@ -2919,13 +3352,10 @@ Numberfield.config = {
2919
3352
  value,
2920
3353
  formField
2921
3354
  }) => {
2922
- // null state is allowed
2923
- if (isNullEquivalentValue(value)) return null;
2924
-
2925
- // if data cannot be parsed as a valid number, go into invalid NaN state
2926
- if (!isValidNumber(value)) return 'NaN';
3355
+ // invalid value types are sanitized to null
3356
+ if (isNullEquivalentValue(value) || !isValidNumber(value)) return null;
2927
3357
 
2928
- // otherwise parse to formatting type
3358
+ // otherwise, we return a string or a number depending on the form field configuration
2929
3359
  return formField.serializeToString ? value.toString() : Number(value);
2930
3360
  },
2931
3361
  create: (options = {}) => ({
@@ -2933,11 +3363,37 @@ Numberfield.config = {
2933
3363
  })
2934
3364
  };
2935
3365
 
2936
- const type$7 = 'radio';
3366
+ function useCleanupSingleSelectValue (props) {
3367
+ const {
3368
+ field,
3369
+ options,
3370
+ loadState,
3371
+ onChange,
3372
+ value
3373
+ } = props;
3374
+
3375
+ // Ensures that the value is always one of the possible options
3376
+ hooks.useEffect(() => {
3377
+ if (loadState !== LOAD_STATES.LOADED) {
3378
+ return;
3379
+ }
3380
+ const hasValueNotInOptions = value && !options.map(o => o.value).includes(value);
3381
+ if (hasValueNotInOptions) {
3382
+ onChange({
3383
+ field,
3384
+ value: null
3385
+ });
3386
+ }
3387
+ }, [field, options, onChange, value, loadState]);
3388
+ }
3389
+
3390
+ const type$8 = 'radio';
2937
3391
  function Radio(props) {
2938
3392
  const {
2939
3393
  disabled,
2940
3394
  errors = [],
3395
+ errorMessageId,
3396
+ domId,
2941
3397
  onBlur,
2942
3398
  onFocus,
2943
3399
  field,
@@ -2946,7 +3402,6 @@ function Radio(props) {
2946
3402
  } = props;
2947
3403
  const {
2948
3404
  description,
2949
- id,
2950
3405
  label,
2951
3406
  validate = {}
2952
3407
  } = field;
@@ -2973,15 +3428,18 @@ function Radio(props) {
2973
3428
  onFocus && onFocus();
2974
3429
  };
2975
3430
  const {
2976
- state: loadState,
2977
- values: options
2978
- } = useValuesAsync(field);
2979
- const {
2980
- formId
2981
- } = hooks.useContext(FormContext$1);
2982
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3431
+ loadState,
3432
+ options
3433
+ } = useOptionsAsync(field);
3434
+ useCleanupSingleSelectValue({
3435
+ field,
3436
+ loadState,
3437
+ options,
3438
+ value,
3439
+ onChange: props.onChange
3440
+ });
2983
3441
  return jsxRuntime.jsxs("div", {
2984
- class: formFieldClasses(type$7, {
3442
+ class: formFieldClasses(type$8, {
2985
3443
  errors,
2986
3444
  disabled,
2987
3445
  readonly
@@ -2991,8 +3449,9 @@ function Radio(props) {
2991
3449
  label: label,
2992
3450
  required: required
2993
3451
  }), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
3452
+ const itemDomId = `${domId}-${index}`;
2994
3453
  return jsxRuntime.jsx(Label, {
2995
- id: prefixId(`${id}-${index}`, formId),
3454
+ id: itemDomId,
2996
3455
  label: option.label,
2997
3456
  class: classNames({
2998
3457
  'fjs-checked': option.value === value
@@ -3003,14 +3462,14 @@ function Radio(props) {
3003
3462
  class: "fjs-input",
3004
3463
  disabled: disabled,
3005
3464
  readOnly: readonly,
3006
- id: prefixId(`${id}-${index}`, formId),
3465
+ id: itemDomId,
3007
3466
  type: "radio",
3008
3467
  onClick: () => onChange(option.value),
3009
3468
  onBlur: onRadioBlur,
3010
3469
  onFocus: onRadioFocus,
3011
3470
  "aria-describedby": errorMessageId
3012
3471
  })
3013
- }, `${id}-${index}`);
3472
+ }, index);
3014
3473
  }), jsxRuntime.jsx(Description, {
3015
3474
  description: description
3016
3475
  }), jsxRuntime.jsx(Errors, {
@@ -3020,23 +3479,23 @@ function Radio(props) {
3020
3479
  });
3021
3480
  }
3022
3481
  Radio.config = {
3023
- type: type$7,
3482
+ type: type$8,
3024
3483
  keyed: true,
3025
- label: 'Radio',
3484
+ label: 'Radio group',
3026
3485
  group: 'selection',
3027
3486
  emptyValue: null,
3028
3487
  sanitizeValue: sanitizeSingleSelectValue,
3029
3488
  create: createEmptyOptions
3030
3489
  };
3031
3490
 
3032
- var _path$e;
3033
- 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); }
3491
+ var _path$q;
3492
+ function _extends$r() { _extends$r = 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$r.apply(this, arguments); }
3034
3493
  var SvgXMark = function SvgXMark(props) {
3035
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$g({
3494
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$r({
3036
3495
  xmlns: "http://www.w3.org/2000/svg",
3037
3496
  width: 8,
3038
3497
  height: 8
3039
- }, props), _path$e || (_path$e = /*#__PURE__*/React__namespace.createElement("path", {
3498
+ }, props), _path$q || (_path$q = /*#__PURE__*/React__namespace.createElement("path", {
3040
3499
  fill: "currentColor",
3041
3500
  fillRule: "evenodd",
3042
3501
  stroke: "currentColor",
@@ -3049,7 +3508,7 @@ var XMarkIcon = SvgXMark;
3049
3508
 
3050
3509
  function SearchableSelect(props) {
3051
3510
  const {
3052
- id,
3511
+ domId,
3053
3512
  disabled,
3054
3513
  errors,
3055
3514
  onBlur,
@@ -3058,9 +3517,6 @@ function SearchableSelect(props) {
3058
3517
  readonly,
3059
3518
  value
3060
3519
  } = props;
3061
- const {
3062
- formId
3063
- } = hooks.useContext(FormContext$1);
3064
3520
  const [filter, setFilter] = hooks.useState('');
3065
3521
  const [isDropdownExpanded, setIsDropdownExpanded] = hooks.useState(false);
3066
3522
  const [shouldApplyFilter, setShouldApplyFilter] = hooks.useState(true);
@@ -3068,9 +3524,16 @@ function SearchableSelect(props) {
3068
3524
  const searchbarRef = hooks.useRef();
3069
3525
  const eventBus = useService('eventBus');
3070
3526
  const {
3071
- state: loadState,
3072
- values: options
3073
- } = useValuesAsync(field);
3527
+ loadState,
3528
+ options
3529
+ } = useOptionsAsync(field);
3530
+ useCleanupSingleSelectValue({
3531
+ field,
3532
+ loadState,
3533
+ options,
3534
+ value,
3535
+ onChange: props.onChange
3536
+ });
3074
3537
 
3075
3538
  // We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
3076
3539
  const valueToOptionMap = hooks.useMemo(() => Object.assign({}, ...options.map((o, x) => ({
@@ -3162,7 +3625,6 @@ function SearchableSelect(props) {
3162
3625
  }, [onBlur, valueLabel]);
3163
3626
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
3164
3627
  children: [jsxRuntime.jsxs("div", {
3165
- id: prefixId(`${id}`, formId),
3166
3628
  class: classNames('fjs-input-group', {
3167
3629
  'disabled': disabled,
3168
3630
  'readonly': readonly
@@ -3174,7 +3636,7 @@ function SearchableSelect(props) {
3174
3636
  readOnly: readonly,
3175
3637
  class: "fjs-input",
3176
3638
  ref: searchbarRef,
3177
- id: prefixId(`${id}-search`, formId),
3639
+ id: domId,
3178
3640
  onChange: onInputChange,
3179
3641
  type: "text",
3180
3642
  value: filter,
@@ -3214,7 +3676,7 @@ function SearchableSelect(props) {
3214
3676
 
3215
3677
  function SimpleSelect(props) {
3216
3678
  const {
3217
- id,
3679
+ domId,
3218
3680
  disabled,
3219
3681
  errors,
3220
3682
  onBlur,
@@ -3223,16 +3685,20 @@ function SimpleSelect(props) {
3223
3685
  readonly,
3224
3686
  value
3225
3687
  } = props;
3226
- const {
3227
- formId
3228
- } = hooks.useContext(FormContext$1);
3229
3688
  const [isDropdownExpanded, setIsDropdownExpanded] = hooks.useState(false);
3230
3689
  const selectRef = hooks.useRef();
3231
3690
  const inputRef = hooks.useRef();
3232
3691
  const {
3233
- state: loadState,
3234
- values: options
3235
- } = useValuesAsync(field);
3692
+ loadState,
3693
+ options
3694
+ } = useOptionsAsync(field);
3695
+ useCleanupSingleSelectValue({
3696
+ field,
3697
+ loadState,
3698
+ options,
3699
+ value,
3700
+ onChange: props.onChange
3701
+ });
3236
3702
 
3237
3703
  // We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
3238
3704
  const valueToOptionMap = hooks.useMemo(() => Object.assign({}, ...options.map((o, x) => ({
@@ -3278,7 +3744,6 @@ function SimpleSelect(props) {
3278
3744
  return jsxRuntime.jsxs(jsxRuntime.Fragment, {
3279
3745
  children: [jsxRuntime.jsxs("div", {
3280
3746
  ref: selectRef,
3281
- id: prefixId(`${id}`, formId),
3282
3747
  class: classNames('fjs-input-group', {
3283
3748
  disabled,
3284
3749
  readonly
@@ -3292,11 +3757,11 @@ function SimpleSelect(props) {
3292
3757
  class: classNames('fjs-select-display', {
3293
3758
  'fjs-select-placeholder': !value
3294
3759
  }),
3295
- id: prefixId(`${id}-display`, formId),
3760
+ id: `${domId}-display`,
3296
3761
  children: valueLabel || 'Select'
3297
3762
  }), !disabled && jsxRuntime.jsx("input", {
3298
3763
  ref: inputRef,
3299
- id: prefixId(`${id}-search`, formId),
3764
+ id: domId,
3300
3765
  class: "fjs-select-hidden-input",
3301
3766
  value: valueLabel,
3302
3767
  onFocus: onInputFocus,
@@ -3329,11 +3794,13 @@ function SimpleSelect(props) {
3329
3794
  });
3330
3795
  }
3331
3796
 
3332
- const type$6 = 'select';
3797
+ const type$7 = 'select';
3333
3798
  function Select(props) {
3334
3799
  const {
3335
3800
  disabled,
3336
3801
  errors = [],
3802
+ errorMessageId,
3803
+ domId,
3337
3804
  onBlur,
3338
3805
  onFocus,
3339
3806
  field,
@@ -3343,7 +3810,6 @@ function Select(props) {
3343
3810
  } = props;
3344
3811
  const {
3345
3812
  description,
3346
- id,
3347
3813
  label,
3348
3814
  searchable = false,
3349
3815
  validate = {}
@@ -3351,12 +3817,8 @@ function Select(props) {
3351
3817
  const {
3352
3818
  required
3353
3819
  } = validate;
3354
- const {
3355
- formId
3356
- } = hooks.useContext(FormContext$1);
3357
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3358
- const selectProps = hooks.useMemo(() => ({
3359
- id,
3820
+ const selectProps = {
3821
+ domId,
3360
3822
  disabled,
3361
3823
  errors,
3362
3824
  onBlur,
@@ -3366,9 +3828,9 @@ function Select(props) {
3366
3828
  onChange,
3367
3829
  readonly,
3368
3830
  'aria-describedby': errorMessageId
3369
- }), [disabled, errors, field, id, value, onChange, onBlur, onFocus, readonly, errorMessageId]);
3831
+ };
3370
3832
  return jsxRuntime.jsxs("div", {
3371
- class: formFieldClasses(type$6, {
3833
+ class: formFieldClasses(type$7, {
3372
3834
  errors,
3373
3835
  disabled,
3374
3836
  readonly
@@ -3380,7 +3842,7 @@ function Select(props) {
3380
3842
  }
3381
3843
  },
3382
3844
  children: [jsxRuntime.jsx(Label, {
3383
- id: prefixId(`${id}-search`, formId),
3845
+ id: domId,
3384
3846
  label: label,
3385
3847
  required: required
3386
3848
  }), searchable ? jsxRuntime.jsx(SearchableSelect, {
@@ -3396,7 +3858,7 @@ function Select(props) {
3396
3858
  });
3397
3859
  }
3398
3860
  Select.config = {
3399
- type: type$6,
3861
+ type: type$7,
3400
3862
  keyed: true,
3401
3863
  label: 'Select',
3402
3864
  group: 'selection',
@@ -3405,15 +3867,15 @@ Select.config = {
3405
3867
  create: createEmptyOptions
3406
3868
  };
3407
3869
 
3408
- const type$5 = 'separator';
3870
+ const type$6 = 'separator';
3409
3871
  function Separator() {
3410
3872
  return jsxRuntime.jsx("div", {
3411
- class: formFieldClasses(type$5),
3873
+ class: formFieldClasses(type$6),
3412
3874
  children: jsxRuntime.jsx("hr", {})
3413
3875
  });
3414
3876
  }
3415
3877
  Separator.config = {
3416
- type: type$5,
3878
+ type: type$6,
3417
3879
  keyed: false,
3418
3880
  label: 'Separator',
3419
3881
  group: 'presentation',
@@ -3422,7 +3884,7 @@ Separator.config = {
3422
3884
  })
3423
3885
  };
3424
3886
 
3425
- const type$4 = 'spacer';
3887
+ const type$5 = 'spacer';
3426
3888
  function Spacer(props) {
3427
3889
  const {
3428
3890
  field
@@ -3431,14 +3893,14 @@ function Spacer(props) {
3431
3893
  height = 60
3432
3894
  } = field;
3433
3895
  return jsxRuntime.jsx("div", {
3434
- class: formFieldClasses(type$4),
3896
+ class: formFieldClasses(type$5),
3435
3897
  style: {
3436
3898
  height: height
3437
3899
  }
3438
3900
  });
3439
3901
  }
3440
3902
  Spacer.config = {
3441
- type: type$4,
3903
+ type: type$5,
3442
3904
  keyed: false,
3443
3905
  label: 'Spacer',
3444
3906
  group: 'presentation',
@@ -3448,80 +3910,129 @@ Spacer.config = {
3448
3910
  })
3449
3911
  };
3450
3912
 
3451
- function SkipLink(props) {
3913
+ function DynamicList(props) {
3452
3914
  const {
3453
- className,
3454
- label,
3455
- onSkip
3915
+ field,
3916
+ domId,
3917
+ readonly
3456
3918
  } = props;
3457
- const onKeyDown = hooks.useCallback(event => {
3458
- if (event.key === 'Enter') {
3459
- event.preventDefault();
3460
- event.stopPropagation();
3461
- onSkip();
3462
- }
3463
- }, [onSkip]);
3464
- return jsxRuntime.jsx("a", {
3465
- href: "#",
3466
- class: classNames('fjs-skip-link', className),
3467
- onKeyDown: onKeyDown,
3468
- children: label
3469
- });
3470
- }
3471
-
3472
- const type$3 = 'taglist';
3473
- function Taglist(props) {
3474
3919
  const {
3475
- disabled,
3476
- errors = [],
3477
- onFocus,
3478
- onBlur,
3479
- field,
3480
- readonly,
3920
+ label,
3921
+ type,
3922
+ showOutline
3923
+ } = field;
3924
+ const {
3925
+ Empty
3926
+ } = hooks.useContext(FormRenderContext$1);
3927
+ const fullProps = {
3928
+ ...props,
3929
+ Empty
3930
+ };
3931
+ return jsxRuntime.jsxs("div", {
3932
+ className: classNames(formFieldClasses(type, {
3933
+ readonly
3934
+ }), 'fjs-form-field-grouplike', {
3935
+ 'fjs-outlined': showOutline
3936
+ }),
3937
+ role: "group",
3938
+ "aria-labelledby": domId,
3939
+ children: [jsxRuntime.jsx(Label, {
3940
+ id: domId,
3941
+ label: label
3942
+ }), jsxRuntime.jsx(ChildrenRenderer, {
3943
+ ...fullProps
3944
+ })]
3945
+ });
3946
+ }
3947
+ DynamicList.config = {
3948
+ type: 'dynamiclist',
3949
+ pathed: true,
3950
+ repeatable: true,
3951
+ label: 'Dynamic list',
3952
+ group: 'container',
3953
+ create: (options = {}) => ({
3954
+ components: [],
3955
+ showOutline: true,
3956
+ isRepeating: true,
3957
+ allowAddRemove: true,
3958
+ defaultRepetitions: 1,
3959
+ ...options
3960
+ })
3961
+ };
3962
+
3963
+ function SkipLink(props) {
3964
+ const {
3965
+ className,
3966
+ label,
3967
+ onSkip
3968
+ } = props;
3969
+ const onKeyDown = hooks.useCallback(event => {
3970
+ if (event.key === 'Enter') {
3971
+ event.preventDefault();
3972
+ event.stopPropagation();
3973
+ onSkip();
3974
+ }
3975
+ }, [onSkip]);
3976
+ return jsxRuntime.jsx("a", {
3977
+ href: "#",
3978
+ class: classNames('fjs-skip-link', className),
3979
+ onKeyDown: onKeyDown,
3980
+ children: label
3981
+ });
3982
+ }
3983
+
3984
+ const type$4 = 'taglist';
3985
+ function Taglist(props) {
3986
+ const {
3987
+ disabled,
3988
+ errors = [],
3989
+ errorMessageId,
3990
+ onFocus,
3991
+ domId,
3992
+ onBlur,
3993
+ field,
3994
+ readonly,
3481
3995
  value: values = []
3482
3996
  } = props;
3483
3997
  const {
3484
3998
  description,
3485
- id,
3486
3999
  label,
3487
4000
  validate = {}
3488
4001
  } = field;
3489
4002
  const {
3490
4003
  required
3491
4004
  } = validate;
3492
- const {
3493
- formId
3494
- } = hooks.useContext(FormContext$1);
3495
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3496
4005
  const [filter, setFilter] = hooks.useState('');
3497
- const [filteredOptions, setFilteredOptions] = hooks.useState([]);
3498
4006
  const [isDropdownExpanded, setIsDropdownExpanded] = hooks.useState(false);
3499
- const [hasOptionsLeft, setHasOptionsLeft] = hooks.useState(true);
3500
4007
  const [isEscapeClosed, setIsEscapeClose] = hooks.useState(false);
3501
4008
  const focusScopeRef = hooks.useRef();
3502
4009
  const inputRef = hooks.useRef();
3503
4010
  const eventBus = useService('eventBus');
3504
4011
  const {
3505
- state: loadState,
3506
- values: options
3507
- } = useValuesAsync(field);
4012
+ loadState,
4013
+ options
4014
+ } = useOptionsAsync(field);
4015
+ useCleanupMultiSelectValues({
4016
+ field,
4017
+ loadState,
4018
+ options,
4019
+ values,
4020
+ onChange: props.onChange
4021
+ });
3508
4022
 
3509
4023
  // We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
3510
4024
  const valueToOptionMap = hooks.useMemo(() => Object.assign({}, ...options.map((o, x) => ({
3511
4025
  [o.value]: options[x]
3512
4026
  }))), [options]);
4027
+ const hasOptionsLeft = hooks.useMemo(() => options.length > values.length, [options.length, values.length]);
3513
4028
 
3514
4029
  // Usage of stringify is necessary here because we want this effect to only trigger when there is a value change to the array
3515
- hooks.useEffect(() => {
3516
- if (loadState === LOAD_STATES.LOADED) {
3517
- setFilteredOptions(options.filter(o => o.label && o.value && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value)));
3518
- } else {
3519
- setFilteredOptions([]);
4030
+ const filteredOptions = hooks.useMemo(() => {
4031
+ if (loadState !== LOAD_STATES.LOADED) {
4032
+ return [];
3520
4033
  }
3521
- }, [filter, JSON.stringify(values), options, loadState]);
3522
- hooks.useEffect(() => {
3523
- setHasOptionsLeft(options.length > values.length);
3524
- }, [options.length, values.length]);
4034
+ return options.filter(o => o.label && o.value && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value));
4035
+ }, [filter, options, JSON.stringify(values), loadState]);
3525
4036
  const selectValue = value => {
3526
4037
  if (filter) {
3527
4038
  setFilter('');
@@ -3613,7 +4124,7 @@ function Taglist(props) {
3613
4124
  const shouldDisplayDropdown = hooks.useMemo(() => !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed, [disabled, isDropdownExpanded, isEscapeClosed, loadState]);
3614
4125
  return jsxRuntime.jsxs("div", {
3615
4126
  ref: focusScopeRef,
3616
- class: formFieldClasses(type$3, {
4127
+ class: formFieldClasses(type$4, {
3617
4128
  errors,
3618
4129
  disabled,
3619
4130
  readonly
@@ -3627,7 +4138,7 @@ function Taglist(props) {
3627
4138
  children: [jsxRuntime.jsx(Label, {
3628
4139
  label: label,
3629
4140
  required: required,
3630
- id: prefixId(`${id}-search`, formId)
4141
+ id: domId
3631
4142
  }), !disabled && !readonly && !!values.length && jsxRuntime.jsx(SkipLink, {
3632
4143
  className: "fjs-taglist-skip-link",
3633
4144
  label: "Skip to search",
@@ -3648,7 +4159,7 @@ function Taglist(props) {
3648
4159
  onMouseDown: e => e.preventDefault(),
3649
4160
  children: [jsxRuntime.jsx("span", {
3650
4161
  class: "fjs-taglist-tag-label",
3651
- children: valueToOptionMap[v] ? valueToOptionMap[v].label : `unexpected value{${v}}`
4162
+ children: valueToOptionMap[v] ? valueToOptionMap[v].label : undefined
3652
4163
  }), !disabled && !readonly && jsxRuntime.jsx("button", {
3653
4164
  type: "button",
3654
4165
  title: "Remove tag",
@@ -3665,7 +4176,7 @@ function Taglist(props) {
3665
4176
  readOnly: readonly,
3666
4177
  class: "fjs-taglist-input",
3667
4178
  ref: inputRef,
3668
- id: prefixId(`${id}-search`, formId),
4179
+ id: domId,
3669
4180
  onChange: onInputChange,
3670
4181
  type: "text",
3671
4182
  value: filter,
@@ -3695,7 +4206,7 @@ function Taglist(props) {
3695
4206
  });
3696
4207
  }
3697
4208
  Taglist.config = {
3698
- type: type$3,
4209
+ type: type$4,
3699
4210
  keyed: true,
3700
4211
  label: 'Tag list',
3701
4212
  group: 'selection',
@@ -3704,7 +4215,7 @@ Taglist.config = {
3704
4215
  create: createEmptyOptions
3705
4216
  };
3706
4217
 
3707
- const type$2 = 'text';
4218
+ const type$3 = 'text';
3708
4219
  function Text(props) {
3709
4220
  const form = useService('form');
3710
4221
  const {
@@ -3731,7 +4242,7 @@ function Text(props) {
3731
4242
  const html = markdownRenderer.render(markdown);
3732
4243
  return sanitizeHTML(html);
3733
4244
  }, [markdownRenderer, markdown]);
3734
- const OverridenTargetLink = hooks.useMemo(() => BuildOverridenTargetLink(textLinkTarget), [textLinkTarget]);
4245
+ const OverriddenTargetLink = hooks.useMemo(() => BuildOverriddenTargetLink(textLinkTarget), [textLinkTarget]);
3735
4246
  const componentOverrides = hooks.useMemo(() => {
3736
4247
  if (disableLinks) {
3737
4248
  return {
@@ -3740,13 +4251,13 @@ function Text(props) {
3740
4251
  }
3741
4252
  if (textLinkTarget) {
3742
4253
  return {
3743
- 'a': OverridenTargetLink
4254
+ 'a': OverriddenTargetLink
3744
4255
  };
3745
4256
  }
3746
4257
  return {};
3747
- }, [disableLinks, OverridenTargetLink, textLinkTarget]);
4258
+ }, [disableLinks, OverriddenTargetLink, textLinkTarget]);
3748
4259
  return jsxRuntime.jsx("div", {
3749
- class: formFieldClasses(type$2),
4260
+ class: formFieldClasses(type$3),
3750
4261
  children: jsxRuntime.jsx(Markup, {
3751
4262
  markup: safeHtml,
3752
4263
  components: componentOverrides,
@@ -3755,7 +4266,7 @@ function Text(props) {
3755
4266
  });
3756
4267
  }
3757
4268
  Text.config = {
3758
- type: type$2,
4269
+ type: type$3,
3759
4270
  keyed: false,
3760
4271
  label: 'Text view',
3761
4272
  group: 'presentation',
@@ -3764,7 +4275,7 @@ Text.config = {
3764
4275
  ...options
3765
4276
  })
3766
4277
  };
3767
- function BuildOverridenTargetLink(target) {
4278
+ function BuildOverriddenTargetLink(target) {
3768
4279
  return function ({
3769
4280
  children,
3770
4281
  ...rest
@@ -3788,11 +4299,13 @@ function DisabledLink({
3788
4299
  });
3789
4300
  }
3790
4301
 
3791
- const type$1 = 'textfield';
4302
+ const type$2 = 'textfield';
3792
4303
  function Textfield(props) {
3793
4304
  const {
3794
4305
  disabled,
3795
4306
  errors = [],
4307
+ errorMessageId,
4308
+ domId,
3796
4309
  onBlur,
3797
4310
  onFocus,
3798
4311
  field,
@@ -3801,7 +4314,6 @@ function Textfield(props) {
3801
4314
  } = props;
3802
4315
  const {
3803
4316
  description,
3804
- id,
3805
4317
  label,
3806
4318
  appearance = {},
3807
4319
  validate = {}
@@ -3821,18 +4333,14 @@ function Textfield(props) {
3821
4333
  value: target.value
3822
4334
  });
3823
4335
  };
3824
- const {
3825
- formId
3826
- } = hooks.useContext(FormContext$1);
3827
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3828
4336
  return jsxRuntime.jsxs("div", {
3829
- class: formFieldClasses(type$1, {
4337
+ class: formFieldClasses(type$2, {
3830
4338
  errors,
3831
4339
  disabled,
3832
4340
  readonly
3833
4341
  }),
3834
4342
  children: [jsxRuntime.jsx(Label, {
3835
- id: prefixId(id, formId),
4343
+ id: domId,
3836
4344
  label: label,
3837
4345
  required: required
3838
4346
  }), jsxRuntime.jsx(TemplatedInputAdorner, {
@@ -3844,7 +4352,7 @@ function Textfield(props) {
3844
4352
  class: "fjs-input",
3845
4353
  disabled: disabled,
3846
4354
  readOnly: readonly,
3847
- id: prefixId(id, formId),
4355
+ id: domId,
3848
4356
  onInput: onChange,
3849
4357
  onBlur: () => onBlur && onBlur(),
3850
4358
  onFocus: () => onFocus && onFocus(),
@@ -3861,7 +4369,7 @@ function Textfield(props) {
3861
4369
  });
3862
4370
  }
3863
4371
  Textfield.config = {
3864
- type: type$1,
4372
+ type: type$2,
3865
4373
  keyed: true,
3866
4374
  label: 'Text field',
3867
4375
  group: 'basic-input',
@@ -3869,7 +4377,7 @@ Textfield.config = {
3869
4377
  sanitizeValue: ({
3870
4378
  value
3871
4379
  }) => {
3872
- if (minDash.isArray(value) || minDash.isObject(value)) {
4380
+ if (minDash.isArray(value) || minDash.isObject(value) || minDash.isNil(value)) {
3873
4381
  return '';
3874
4382
  }
3875
4383
 
@@ -3884,11 +4392,13 @@ Textfield.config = {
3884
4392
  })
3885
4393
  };
3886
4394
 
3887
- const type = 'textarea';
4395
+ const type$1 = 'textarea';
3888
4396
  function Textarea(props) {
3889
4397
  const {
3890
4398
  disabled,
3891
4399
  errors = [],
4400
+ errorMessageId,
4401
+ domId,
3892
4402
  onBlur,
3893
4403
  onFocus,
3894
4404
  field,
@@ -3897,7 +4407,6 @@ function Textarea(props) {
3897
4407
  } = props;
3898
4408
  const {
3899
4409
  description,
3900
- id,
3901
4410
  label,
3902
4411
  validate = {}
3903
4412
  } = field;
@@ -3919,25 +4428,21 @@ function Textarea(props) {
3919
4428
  hooks.useEffect(() => {
3920
4429
  autoSizeTextarea(textareaRef.current);
3921
4430
  }, []);
3922
- const {
3923
- formId
3924
- } = hooks.useContext(FormContext$1);
3925
- const errorMessageId = errors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
3926
4431
  return jsxRuntime.jsxs("div", {
3927
- class: formFieldClasses(type, {
4432
+ class: formFieldClasses(type$1, {
3928
4433
  errors,
3929
4434
  disabled,
3930
4435
  readonly
3931
4436
  }),
3932
4437
  children: [jsxRuntime.jsx(Label, {
3933
- id: prefixId(id, formId),
4438
+ id: domId,
3934
4439
  label: label,
3935
4440
  required: required
3936
4441
  }), jsxRuntime.jsx("textarea", {
3937
4442
  class: "fjs-textarea",
3938
4443
  disabled: disabled,
3939
4444
  readonly: readonly,
3940
- id: prefixId(id, formId),
4445
+ id: domId,
3941
4446
  onInput: onInput,
3942
4447
  onBlur: () => onBlur && onBlur(),
3943
4448
  onFocus: () => onFocus && onFocus(),
@@ -3953,14 +4458,14 @@ function Textarea(props) {
3953
4458
  });
3954
4459
  }
3955
4460
  Textarea.config = {
3956
- type,
4461
+ type: type$1,
3957
4462
  keyed: true,
3958
4463
  label: 'Text area',
3959
4464
  group: 'basic-input',
3960
4465
  emptyValue: '',
3961
4466
  sanitizeValue: ({
3962
4467
  value
3963
- }) => minDash.isArray(value) || minDash.isObject(value) ? '' : String(value),
4468
+ }) => minDash.isArray(value) || minDash.isObject(value) || minDash.isNil(value) ? '' : String(value),
3964
4469
  create: (options = {}) => ({
3965
4470
  ...options
3966
4471
  })
@@ -3984,84 +4489,419 @@ const autoSizeTextarea = textarea => {
3984
4489
  textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
3985
4490
  };
3986
4491
 
3987
- var _path$d;
3988
- 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); }
4492
+ var _path$p;
4493
+ function _extends$q() { _extends$q = 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$q.apply(this, arguments); }
4494
+ var SvgArrowDown = function SvgArrowDown(props) {
4495
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$q({
4496
+ xmlns: "http://www.w3.org/2000/svg",
4497
+ viewBox: "0 0 32 32"
4498
+ }, props), _path$p || (_path$p = /*#__PURE__*/React__namespace.createElement("path", {
4499
+ fill: "currentcolor",
4500
+ d: "M24.59 16.59 17 24.17V4h-2v20.17l-7.59-7.58L6 18l10 10 10-10-1.41-1.41z"
4501
+ })));
4502
+ };
4503
+ var ArrowDownIcon = SvgArrowDown;
4504
+
4505
+ var _path$o;
4506
+ function _extends$p() { _extends$p = 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$p.apply(this, arguments); }
4507
+ var SvgArrowUp = function SvgArrowUp(props) {
4508
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$p({
4509
+ xmlns: "http://www.w3.org/2000/svg",
4510
+ viewBox: "0 0 32 32"
4511
+ }, props), _path$o || (_path$o = /*#__PURE__*/React__namespace.createElement("path", {
4512
+ fill: "currentcolor",
4513
+ d: "M16 4 6 14l1.41 1.41L15 7.83V28h2V7.83l7.59 7.58L26 14 16 4z"
4514
+ })));
4515
+ };
4516
+ var ArrowUpIcon = SvgArrowUp;
4517
+
4518
+ var _path$n;
4519
+ function _extends$o() { _extends$o = 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$o.apply(this, arguments); }
4520
+ var SvgCaretLeft = function SvgCaretLeft(props) {
4521
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$o({
4522
+ xmlns: "http://www.w3.org/2000/svg",
4523
+ xmlSpace: "preserve",
4524
+ viewBox: "0 0 32 32"
4525
+ }, props), _path$n || (_path$n = /*#__PURE__*/React__namespace.createElement("path", {
4526
+ fill: "currentcolor",
4527
+ d: "m20 24-10-8 10-8z"
4528
+ })));
4529
+ };
4530
+ var CaretLeftIcon = SvgCaretLeft;
4531
+
4532
+ var _path$m;
4533
+ function _extends$n() { _extends$n = 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$n.apply(this, arguments); }
4534
+ var SvgCaretRight = function SvgCaretRight(props) {
4535
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$n({
4536
+ xmlns: "http://www.w3.org/2000/svg",
4537
+ xmlSpace: "preserve",
4538
+ viewBox: "0 0 32 32"
4539
+ }, props), _path$m || (_path$m = /*#__PURE__*/React__namespace.createElement("path", {
4540
+ fill: "currentcolor",
4541
+ d: "m12 8 10 8-10 8z"
4542
+ })));
4543
+ };
4544
+ var CaretRightIcon = SvgCaretRight;
4545
+
4546
+ const type = 'table';
4547
+
4548
+ /**
4549
+ * @typedef {('asc'|'desc')} Direction
4550
+ *
4551
+ * @typedef Sorting
4552
+ * @property {string} key
4553
+ * @property {Direction} direction
4554
+ *
4555
+ * @typedef Column
4556
+ * @property {string} label
4557
+ * @property {string} key
4558
+ *
4559
+ * @typedef Props
4560
+ * @property {Object} field
4561
+ * @property {string} field.id
4562
+ * @property {Array<Column>} [field.columns]
4563
+ * @property {string} [field.columnsExpression]
4564
+ * @property {string} [field.label]
4565
+ * @property {number} [field.rowCount]
4566
+ * @property {string} [field.dataSource]
4567
+ *
4568
+ * @param {Props} props
4569
+ * @returns {import("preact").JSX.Element}
4570
+ */
4571
+ function Table(props) {
4572
+ const {
4573
+ field
4574
+ } = props;
4575
+ const {
4576
+ columns = [],
4577
+ columnsExpression,
4578
+ dataSource = '',
4579
+ rowCount,
4580
+ id,
4581
+ label
4582
+ } = field;
4583
+
4584
+ /** @type {[(null|Sorting), import("preact/hooks").StateUpdater<null|Sorting>]} */
4585
+ const [sortBy, setSortBy] = hooks.useState(null);
4586
+ const evaluatedColumns = useEvaluatedColumns(columnsExpression || '', columns);
4587
+ const columnKeys = evaluatedColumns.map(({
4588
+ key
4589
+ }) => key);
4590
+ const evaluatedDataSource = useExpressionEvaluation(dataSource);
4591
+ const data = Array.isArray(evaluatedDataSource) ? evaluatedDataSource : [];
4592
+ const sortedData = sortBy === null ? data : sortByColumn(data, sortBy.key, sortBy.direction);
4593
+
4594
+ /** @type {unknown[][]} */
4595
+ const chunkedData = minDash.isNumber(rowCount) ? chunk(sortedData, rowCount) : [sortedData];
4596
+ const [currentPage, setCurrentPage] = hooks.useState(0);
4597
+ const currentChunk = chunkedData[currentPage] || [];
4598
+ hooks.useEffect(() => {
4599
+ setCurrentPage(0);
4600
+ }, [rowCount, sortBy]);
4601
+
4602
+ /** @param {string} key */
4603
+ function toggleSortBy(key) {
4604
+ setSortBy(current => {
4605
+ if (current === null || current.key !== key) {
4606
+ return {
4607
+ key,
4608
+ direction: 'asc'
4609
+ };
4610
+ }
4611
+ if (current.direction === 'desc') {
4612
+ return null;
4613
+ }
4614
+ return {
4615
+ key,
4616
+ direction: 'desc'
4617
+ };
4618
+ });
4619
+ }
4620
+ return jsxRuntime.jsxs("div", {
4621
+ class: formFieldClasses(type),
4622
+ children: [jsxRuntime.jsx(Label, {
4623
+ id: prefixId(id),
4624
+ label: label
4625
+ }), jsxRuntime.jsxs("div", {
4626
+ class: classNames('fjs-table-middle-container', {
4627
+ 'fjs-table-empty': evaluatedColumns.length === 0
4628
+ }),
4629
+ children: [evaluatedColumns.length === 0 ? 'Nothing to show.' : jsxRuntime.jsx("div", {
4630
+ class: "fjs-table-inner-container",
4631
+ children: jsxRuntime.jsxs("table", {
4632
+ class: "fjs-table",
4633
+ id: prefixId(id),
4634
+ children: [jsxRuntime.jsx("thead", {
4635
+ class: "fjs-table-head",
4636
+ children: jsxRuntime.jsx("tr", {
4637
+ class: "fjs-table-tr",
4638
+ children: evaluatedColumns.map(({
4639
+ key,
4640
+ label
4641
+ }) => {
4642
+ const displayLabel = label || key;
4643
+ return jsxRuntime.jsx("th", {
4644
+ tabIndex: 0,
4645
+ class: "fjs-table-th",
4646
+ onClick: () => {
4647
+ toggleSortBy(key);
4648
+ },
4649
+ onKeyDown: event => {
4650
+ if (['Enter', 'Space'].includes(event.code)) {
4651
+ toggleSortBy(key);
4652
+ }
4653
+ },
4654
+ "aria-label": getHeaderAriaLabel(sortBy, key, displayLabel),
4655
+ children: jsxRuntime.jsxs("span", {
4656
+ class: "fjs-table-th-label",
4657
+ children: [displayLabel, sortBy !== null && sortBy.key === key ? jsxRuntime.jsx(jsxRuntime.Fragment, {
4658
+ children: sortBy.direction === 'asc' ? jsxRuntime.jsx(ArrowUpIcon, {
4659
+ class: "fjs-table-sort-icon-asc"
4660
+ }) : jsxRuntime.jsx(ArrowDownIcon, {
4661
+ class: "fjs-table-sort-icon-desc"
4662
+ })
4663
+ }) : null]
4664
+ })
4665
+ }, key);
4666
+ })
4667
+ })
4668
+ }), currentChunk.length === 0 ? jsxRuntime.jsx("tbody", {
4669
+ class: "fjs-table-body",
4670
+ children: jsxRuntime.jsx("tr", {
4671
+ class: "fjs-table-tr",
4672
+ children: jsxRuntime.jsx("td", {
4673
+ class: "fjs-table-td",
4674
+ colSpan: evaluatedColumns.length,
4675
+ children: "Nothing to show."
4676
+ })
4677
+ })
4678
+ }) : jsxRuntime.jsx("tbody", {
4679
+ class: "fjs-table-body",
4680
+ children: currentChunk.map((row, index) => jsxRuntime.jsx("tr", {
4681
+ class: "fjs-table-tr",
4682
+ children: columnKeys.map(key => jsxRuntime.jsx("td", {
4683
+ class: "fjs-table-td",
4684
+ children: row[key]
4685
+ }, key))
4686
+ }, index))
4687
+ })]
4688
+ })
4689
+ }), minDash.isNumber(rowCount) && chunkedData.length > 1 && evaluatedColumns.length > 0 ? jsxRuntime.jsxs("nav", {
4690
+ class: "fjs-table-nav",
4691
+ children: [jsxRuntime.jsxs("span", {
4692
+ class: "fjs-table-nav-label",
4693
+ children: [currentPage + 1, " of ", chunkedData.length]
4694
+ }), jsxRuntime.jsx("button", {
4695
+ type: "button",
4696
+ class: "fjs-table-nav-button",
4697
+ onClick: () => {
4698
+ setCurrentPage(page => Math.max(page - 1, 0));
4699
+ },
4700
+ disabled: currentPage === 0,
4701
+ "aria-label": "Previous page",
4702
+ children: jsxRuntime.jsx(CaretLeftIcon, {})
4703
+ }), jsxRuntime.jsx("button", {
4704
+ type: "button",
4705
+ class: "fjs-table-nav-button",
4706
+ onClick: () => {
4707
+ setCurrentPage(page => Math.min(page + 1, chunkedData.length - 1));
4708
+ },
4709
+ disabled: currentPage >= chunkedData.length - 1,
4710
+ "aria-label": "Next page",
4711
+ children: jsxRuntime.jsx(CaretRightIcon, {})
4712
+ })]
4713
+ }) : null]
4714
+ })]
4715
+ });
4716
+ }
4717
+ Table.config = {
4718
+ type,
4719
+ keyed: false,
4720
+ label: 'Table',
4721
+ group: 'presentation',
4722
+ create: (options = {}) => {
4723
+ const {
4724
+ id,
4725
+ columnsExpression,
4726
+ columns,
4727
+ rowCount,
4728
+ ...remainingOptions
4729
+ } = options;
4730
+ if (minDash.isDefined(id) && minDash.isNumber(rowCount)) {
4731
+ remainingOptions['rowCount'] = rowCount;
4732
+ }
4733
+ if (minDash.isString(columnsExpression)) {
4734
+ return {
4735
+ ...remainingOptions,
4736
+ id,
4737
+ columnsExpression
4738
+ };
4739
+ }
4740
+ if (Array.isArray(columns) && columns.every(isColumn)) {
4741
+ return {
4742
+ ...remainingOptions,
4743
+ id,
4744
+ columns
4745
+ };
4746
+ }
4747
+ return {
4748
+ ...remainingOptions,
4749
+ rowCount: 10,
4750
+ columns: [{
4751
+ label: 'ID',
4752
+ key: 'id'
4753
+ }, {
4754
+ label: 'Name',
4755
+ key: 'name'
4756
+ }, {
4757
+ label: 'Date',
4758
+ key: 'date'
4759
+ }]
4760
+ };
4761
+ },
4762
+ initialDemoData: [{
4763
+ id: 1,
4764
+ name: 'John Doe',
4765
+ date: '31.01.2023'
4766
+ }, {
4767
+ id: 2,
4768
+ name: 'Erika Muller',
4769
+ date: '20.02.2023'
4770
+ }, {
4771
+ id: 3,
4772
+ name: 'Dominic Leaf',
4773
+ date: '11.03.2023'
4774
+ }]
4775
+ };
4776
+
4777
+ // helpers /////////////////////////////
4778
+
4779
+ /**
4780
+ * @param {string|void} columnsExpression
4781
+ * @param {Column[]} fallbackColumns
4782
+ * @returns {Column[]}
4783
+ */
4784
+ function useEvaluatedColumns(columnsExpression, fallbackColumns) {
4785
+ /** @type {Column[]|null} */
4786
+ const evaluation = useExpressionEvaluation(columnsExpression || '');
4787
+ return Array.isArray(evaluation) && evaluation.every(isColumn) ? evaluation : fallbackColumns;
4788
+ }
4789
+
4790
+ /**
4791
+ * @param {any} column
4792
+ * @returns {column is Column}
4793
+ */
4794
+ function isColumn(column) {
4795
+ return minDash.isObject(column) && minDash.isString(column['label']) && minDash.isString(column['key']);
4796
+ }
4797
+
4798
+ /**
4799
+ * @param {Array} array
4800
+ * @param {number} size
4801
+ * @returns {Array}
4802
+ */
4803
+ function chunk(array, size) {
4804
+ return array.reduce((chunks, item, index) => {
4805
+ if (index % size === 0) {
4806
+ chunks.push([item]);
4807
+ } else {
4808
+ chunks[chunks.length - 1].push(item);
4809
+ }
4810
+ return chunks;
4811
+ }, []);
4812
+ }
4813
+
4814
+ /**
4815
+ * @param {unknown[]} array
4816
+ * @param {string} key
4817
+ * @param {Direction} direction
4818
+ * @returns {unknown[]}
4819
+ */
4820
+ function sortByColumn(array, key, direction) {
4821
+ return [...array].sort((a, b) => {
4822
+ if (!minDash.isObject(a) || !minDash.isObject(b)) {
4823
+ return 0;
4824
+ }
4825
+ if (direction === 'asc') {
4826
+ return a[key] > b[key] ? 1 : -1;
4827
+ }
4828
+ return a[key] < b[key] ? 1 : -1;
4829
+ });
4830
+ }
4831
+
4832
+ /**
4833
+ * @param {null|Sorting} sortBy
4834
+ * @param {string} key
4835
+ * @param {string} label
4836
+ */
4837
+ function getHeaderAriaLabel(sortBy, key, label) {
4838
+ if (sortBy === null || sortBy.key !== key) {
4839
+ return `Click to sort by ${label} descending`;
4840
+ }
4841
+ if (sortBy.direction === 'asc') {
4842
+ return 'Click to remove sorting';
4843
+ }
4844
+ return `Click to sort by ${label} ascending`;
4845
+ }
4846
+
4847
+ var _path$l;
4848
+ function _extends$m() { _extends$m = 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$m.apply(this, arguments); }
3989
4849
  var SvgButton = function SvgButton(props) {
3990
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$f({
4850
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$m({
3991
4851
  xmlns: "http://www.w3.org/2000/svg",
3992
4852
  width: 54,
3993
4853
  height: 54,
3994
4854
  fill: "currentcolor"
3995
- }, props), _path$d || (_path$d = /*#__PURE__*/React__namespace.createElement("path", {
4855
+ }, props), _path$l || (_path$l = /*#__PURE__*/React__namespace.createElement("path", {
3996
4856
  fillRule: "evenodd",
3997
4857
  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"
3998
4858
  })));
3999
4859
  };
4000
4860
  var ButtonIcon = SvgButton;
4001
4861
 
4002
- var _path$c;
4003
- 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); }
4862
+ var _path$k;
4863
+ function _extends$l() { _extends$l = 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$l.apply(this, arguments); }
4004
4864
  var SvgCheckbox = function SvgCheckbox(props) {
4005
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$e({
4865
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$l({
4006
4866
  xmlns: "http://www.w3.org/2000/svg",
4007
4867
  width: 54,
4008
4868
  height: 54,
4009
4869
  fill: "currentcolor"
4010
- }, props), _path$c || (_path$c = /*#__PURE__*/React__namespace.createElement("path", {
4870
+ }, props), _path$k || (_path$k = /*#__PURE__*/React__namespace.createElement("path", {
4011
4871
  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"
4012
4872
  })));
4013
4873
  };
4014
4874
  var CheckboxIcon = SvgCheckbox;
4015
4875
 
4016
- var _g, _use, _use2, _use3, _defs;
4017
- 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); }
4876
+ var _path$j;
4877
+ 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); }
4018
4878
  var SvgChecklist = function SvgChecklist(props) {
4019
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$d({
4879
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$k({
4020
4880
  xmlns: "http://www.w3.org/2000/svg",
4021
- xmlnsXlink: "http://www.w3.org/1999/xlink",
4022
4881
  width: 54,
4023
4882
  height: 54,
4024
- fill: "currentcolor"
4025
- }, props), _g || (_g = /*#__PURE__*/React__namespace.createElement("g", {
4026
- fillRule: "evenodd"
4027
- }, /*#__PURE__*/React__namespace.createElement("use", {
4028
- xlinkHref: "#Checklist_svg__a"
4029
- }), /*#__PURE__*/React__namespace.createElement("use", {
4030
- xlinkHref: "#Checklist_svg__a",
4031
- y: 24
4032
- }), /*#__PURE__*/React__namespace.createElement("use", {
4033
- xlinkHref: "#Checklist_svg__a",
4034
- y: 12
4035
- }))), _use || (_use = /*#__PURE__*/React__namespace.createElement("use", {
4036
- xlinkHref: "#Checklist_svg__b"
4037
- })), _use2 || (_use2 = /*#__PURE__*/React__namespace.createElement("use", {
4038
- xlinkHref: "#Checklist_svg__b",
4039
- y: 12
4040
- })), _use3 || (_use3 = /*#__PURE__*/React__namespace.createElement("use", {
4041
- xlinkHref: "#Checklist_svg__b",
4042
- y: 24
4043
- })), _defs || (_defs = /*#__PURE__*/React__namespace.createElement("defs", null, /*#__PURE__*/React__namespace.createElement("path", {
4044
- id: "Checklist_svg__a",
4045
- d: "M18 12h-6v6h6v-6zm-6-2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2h-6z"
4046
- }), /*#__PURE__*/React__namespace.createElement("path", {
4047
- id: "Checklist_svg__b",
4048
- d: "M23 14.5a1 1 0 0 1 1-1h19a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H24a1 1 0 0 1-1-1v-1z"
4049
- }))));
4883
+ fill: "none"
4884
+ }, props), _path$j || (_path$j = /*#__PURE__*/React__namespace.createElement("path", {
4885
+ fill: "currentColor",
4886
+ fillRule: "evenodd",
4887
+ d: "M14.35 24.75H19v4.65h-4.65v-4.65Zm-1.414-1.414a2 2 0 0 1 1.414-.586H19a2 2 0 0 1 2 2v4.65a2 2 0 0 1-2 2h-4.65a2 2 0 0 1-2-2v-4.65a2 2 0 0 1 .586-1.414ZM14.35 37.05H19v4.65h-4.65v-4.65Zm-1.414-1.414a2 2 0 0 1 1.414-.586H19a2 2 0 0 1 2 2v4.65a2 2 0 0 1-2 2h-4.65a2 2 0 0 1-2-2v-4.65a2 2 0 0 1 .586-1.414ZM14.35 12.45H19v4.65h-4.65v-4.65Zm-1.414-1.414a2 2 0 0 1 1.414-.586H19a2 2 0 0 1 2 2v4.65a2 2 0 0 1-2 2h-4.65a2 2 0 0 1-2-2v-4.65a2 2 0 0 1 .586-1.414Zm12.007 14.977a1 1 0 0 0-.293.707v.65a1 1 0 0 0 1 1h15a1 1 0 0 0 1-1v-.65a1 1 0 0 0-1-1h-15a1 1 0 0 0-.707.293Zm0 12.3a1 1 0 0 0-.293.707v.65a1 1 0 0 0 1 1h15a1 1 0 0 0 1-1v-.65a1 1 0 0 0-1-1h-15a1 1 0 0 0-.707.293Zm0-24.6a1 1 0 0 0-.293.707v.65a1 1 0 0 0 1 1h15a1 1 0 0 0 1-1v-.65a1 1 0 0 0-1-1h-15a1 1 0 0 0-.707.293Z",
4888
+ clipRule: "evenodd"
4889
+ })));
4050
4890
  };
4051
4891
  var ChecklistIcon = SvgChecklist;
4052
4892
 
4053
- var _path$b, _path2$2, _path3;
4054
- 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); }
4893
+ var _path$i, _path2$4, _path3;
4894
+ 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); }
4055
4895
  var SvgDatetime = function SvgDatetime(props) {
4056
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$c({
4896
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$j({
4057
4897
  xmlns: "http://www.w3.org/2000/svg",
4058
4898
  width: 54,
4059
4899
  height: 54,
4060
4900
  fill: "currentcolor"
4061
- }, props), _path$b || (_path$b = /*#__PURE__*/React__namespace.createElement("path", {
4901
+ }, props), _path$i || (_path$i = /*#__PURE__*/React__namespace.createElement("path", {
4062
4902
  fillRule: "evenodd",
4063
4903
  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"
4064
- })), _path2$2 || (_path2$2 = /*#__PURE__*/React__namespace.createElement("path", {
4904
+ })), _path2$4 || (_path2$4 = /*#__PURE__*/React__namespace.createElement("path", {
4065
4905
  d: "m35.13 37.603 1.237-1.237-3.468-3.475v-5.926h-1.754v6.654l3.984 3.984Z"
4066
4906
  })), _path3 || (_path3 = /*#__PURE__*/React__namespace.createElement("path", {
4067
4907
  fillRule: "evenodd",
@@ -4070,27 +4910,27 @@ var SvgDatetime = function SvgDatetime(props) {
4070
4910
  };
4071
4911
  var DatetimeIcon = SvgDatetime;
4072
4912
 
4073
- var _path$a, _path2$1;
4074
- 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); }
4913
+ var _path$h, _path2$3;
4914
+ 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); }
4075
4915
  var SvgTaglist = function SvgTaglist(props) {
4076
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$b({
4916
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$i({
4077
4917
  xmlns: "http://www.w3.org/2000/svg",
4078
4918
  width: 54,
4079
4919
  height: 54,
4080
4920
  fill: "currentcolor"
4081
- }, props), _path$a || (_path$a = /*#__PURE__*/React__namespace.createElement("path", {
4921
+ }, props), _path$h || (_path$h = /*#__PURE__*/React__namespace.createElement("path", {
4082
4922
  fillRule: "evenodd",
4083
4923
  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"
4084
- })), _path2$1 || (_path2$1 = /*#__PURE__*/React__namespace.createElement("path", {
4924
+ })), _path2$3 || (_path2$3 = /*#__PURE__*/React__namespace.createElement("path", {
4085
4925
  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"
4086
4926
  })));
4087
4927
  };
4088
4928
  var TaglistIcon = SvgTaglist;
4089
4929
 
4090
4930
  var _rect, _rect2, _rect3;
4091
- 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); }
4931
+ 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); }
4092
4932
  var SvgForm = function SvgForm(props) {
4093
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$a({
4933
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$h({
4094
4934
  xmlns: "http://www.w3.org/2000/svg",
4095
4935
  width: 54,
4096
4936
  height: 54
@@ -4116,152 +4956,189 @@ var SvgForm = function SvgForm(props) {
4116
4956
  };
4117
4957
  var FormIcon = SvgForm;
4118
4958
 
4119
- var _path$9;
4120
- 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); }
4959
+ var _path$g;
4960
+ 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); }
4121
4961
  var SvgGroup = function SvgGroup(props) {
4122
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$9({
4962
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$g({
4123
4963
  xmlns: "http://www.w3.org/2000/svg",
4124
4964
  width: 54,
4125
4965
  height: 54,
4126
4966
  fill: "currentcolor"
4127
- }, props), _path$9 || (_path$9 = /*#__PURE__*/React__namespace.createElement("path", {
4967
+ }, props), _path$g || (_path$g = /*#__PURE__*/React__namespace.createElement("path", {
4128
4968
  fillRule: "evenodd",
4129
4969
  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"
4130
4970
  })));
4131
4971
  };
4132
4972
  var GroupIcon = SvgGroup;
4133
4973
 
4134
- var _path$8;
4135
- 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); }
4974
+ var _path$f;
4975
+ 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); }
4136
4976
  var SvgNumber = function SvgNumber(props) {
4137
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$8({
4977
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$f({
4138
4978
  xmlns: "http://www.w3.org/2000/svg",
4139
4979
  width: 54,
4140
4980
  height: 54,
4141
4981
  fill: "currentcolor"
4142
- }, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", {
4982
+ }, props), _path$f || (_path$f = /*#__PURE__*/React__namespace.createElement("path", {
4143
4983
  fillRule: "evenodd",
4144
4984
  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"
4145
4985
  })));
4146
4986
  };
4147
4987
  var NumberIcon = SvgNumber;
4148
4988
 
4149
- var _path$7;
4150
- 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); }
4989
+ var _path$e;
4990
+ 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); }
4151
4991
  var SvgRadio = function SvgRadio(props) {
4152
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$7({
4992
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$e({
4153
4993
  xmlns: "http://www.w3.org/2000/svg",
4154
4994
  width: 54,
4155
4995
  height: 54,
4156
4996
  fill: "currentcolor"
4157
- }, props), _path$7 || (_path$7 = /*#__PURE__*/React__namespace.createElement("path", {
4997
+ }, props), _path$e || (_path$e = /*#__PURE__*/React__namespace.createElement("path", {
4158
4998
  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"
4159
4999
  })));
4160
5000
  };
4161
5001
  var RadioIcon = SvgRadio;
4162
5002
 
4163
- var _path$6;
4164
- 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); }
5003
+ var _path$d;
5004
+ 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); }
4165
5005
  var SvgSelect = function SvgSelect(props) {
4166
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$6({
5006
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$d({
4167
5007
  xmlns: "http://www.w3.org/2000/svg",
4168
5008
  width: 54,
4169
5009
  height: 54,
4170
5010
  fill: "currentcolor"
4171
- }, props), _path$6 || (_path$6 = /*#__PURE__*/React__namespace.createElement("path", {
5011
+ }, props), _path$d || (_path$d = /*#__PURE__*/React__namespace.createElement("path", {
4172
5012
  fillRule: "evenodd",
4173
5013
  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"
4174
5014
  })));
4175
5015
  };
4176
5016
  var SelectIcon = SvgSelect;
4177
5017
 
4178
- var _path$5;
4179
- 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); }
5018
+ var _path$c;
5019
+ 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); }
4180
5020
  var SvgSeparator = function SvgSeparator(props) {
4181
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$5({
5021
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$c({
4182
5022
  xmlns: "http://www.w3.org/2000/svg",
4183
5023
  width: 54,
4184
5024
  height: 54,
4185
5025
  fill: "none"
4186
- }, props), _path$5 || (_path$5 = /*#__PURE__*/React__namespace.createElement("path", {
5026
+ }, props), _path$c || (_path$c = /*#__PURE__*/React__namespace.createElement("path", {
4187
5027
  fill: "currentColor",
4188
5028
  d: "M26.293 16.293a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1-1.414 1.414L27 18.414l-3.293 3.293a1 1 0 0 1-1.414-1.414l4-4ZM9 26h36v2H9v-2Zm13.293 7.707 4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0-1.414-1.414L27 35.586l-3.293-3.293a1 1 0 0 0-1.414 1.414Z"
4189
5029
  })));
4190
5030
  };
4191
5031
  var SeparatorIcon = SvgSeparator;
4192
5032
 
4193
- var _path$4;
4194
- 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); }
5033
+ var _path$b;
5034
+ 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); }
4195
5035
  var SvgSpacer = function SvgSpacer(props) {
4196
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$4({
5036
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$b({
4197
5037
  xmlns: "http://www.w3.org/2000/svg",
4198
5038
  width: 54,
4199
5039
  height: 54,
4200
5040
  fill: "none"
4201
- }, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", {
5041
+ }, props), _path$b || (_path$b = /*#__PURE__*/React__namespace.createElement("path", {
4202
5042
  fill: "currentColor",
4203
5043
  d: "M9 15v2h36v-2H9Zm0 22v2h36v-2H9Zm17.293-17.707a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1-1.414 1.414L27 21.414l-3.293 3.293a1 1 0 0 1-1.414-1.414l4-4Zm-4 11.414 4 4a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0-1.414-1.414L27 32.586l-3.293-3.293a1 1 0 0 0-1.414 1.414Z"
4204
5044
  })));
4205
5045
  };
4206
5046
  var SpacerIcon = SvgSpacer;
4207
5047
 
4208
- var _path$3;
4209
- 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); }
5048
+ var _path$a;
5049
+ 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); }
5050
+ var SvgDynamicList = function SvgDynamicList(props) {
5051
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$a({
5052
+ xmlns: "http://www.w3.org/2000/svg",
5053
+ width: 54,
5054
+ height: 54,
5055
+ fill: "none"
5056
+ }, props), _path$a || (_path$a = /*#__PURE__*/React__namespace.createElement("path", {
5057
+ fill: "currentColor",
5058
+ fillRule: "evenodd",
5059
+ d: "M2.7 43.296v1.254c0 .746.604 1.35 1.35 1.35h1.275v-1.795c.049.14.075.29.075.445v-1.254h-.075V43.2H4.05c.177 0 .347.034.502.096H2.7Zm2.7-2.507v-2.507H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.015V23.24H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.014V13.21H2.7v2.507h2.7Zm-2.7-5.014h1.852a1.346 1.346 0 0 1-.502.096h1.275v-.096H5.4V9.45c0 .156-.026.306-.075.445V8.1H4.05A1.35 1.35 0 0 0 2.7 9.45v1.254Zm5.175.096h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1-2.7v1.795a1.348 1.348 0 0 1-.075-.445v1.254h.075v.096h1.275c-.177 0-.347-.034-.502-.096H51.3V9.45a1.35 1.35 0 0 0-1.35-1.35h-1.275Zm-.075 5.11v2.508h2.7V13.21h-2.7Zm0 5.015v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7V23.24h-2.7Zm0 5.015v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7v-2.507h-2.7Zm2.7 5.014h-1.852c.155-.062.325-.096.502-.096h-1.275v.096H48.6v1.254c0-.156.026-.305.075-.445V45.9h1.275a1.35 1.35 0 0 0 1.35-1.35v-1.254Zm-5.175-.096h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7ZM16.2 17.55a4.05 4.05 0 0 1 4.05 4.05v1.35A4.05 4.05 0 0 1 16.2 27h-1.35a4.05 4.05 0 0 1-4.05-4.05V21.6a4.05 4.05 0 0 1 4.05-4.05h1.35Zm0 2.7h-1.35a1.35 1.35 0 0 0-1.35 1.35v1.35c0 .746.604 1.35 1.35 1.35h1.35a1.35 1.35 0 0 0 1.35-1.35V21.6a1.35 1.35 0 0 0-1.35-1.35Zm27 1.35a4.05 4.05 0 0 0-4.05-4.05H29.7a4.05 4.05 0 0 0-4.05 4.05v1.35A4.05 4.05 0 0 0 29.7 27h9.45a4.05 4.05 0 0 0 4.05-4.05V21.6Zm-13.5-1.35h9.45c.746 0 1.35.604 1.35 1.35v1.35a1.35 1.35 0 0 1-1.35 1.35H29.7a1.35 1.35 0 0 1-1.35-1.35V21.6c0-.746.604-1.35 1.35-1.35ZM43.2 37.8a4.05 4.05 0 0 0-4.05-4.05H29.7a4.05 4.05 0 0 0-4.05 4.05v1.35h2.7V37.8c0-.746.604-1.35 1.35-1.35h9.45c.746 0 1.35.604 1.35 1.35v1.35h2.7V37.8Zm-27-4.05a4.05 4.05 0 0 1 4.05 4.05v1.35h-2.7V37.8a1.35 1.35 0 0 0-1.35-1.35h-1.35a1.35 1.35 0 0 0-1.35 1.35v1.35h-2.7V37.8a4.05 4.05 0 0 1 4.05-4.05h1.35Z",
5060
+ clipRule: "evenodd"
5061
+ })));
5062
+ };
5063
+ var DynamicListIcon = SvgDynamicList;
5064
+
5065
+ var _path$9;
5066
+ 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); }
4210
5067
  var SvgText = function SvgText(props) {
4211
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$3({
5068
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$9({
4212
5069
  xmlns: "http://www.w3.org/2000/svg",
4213
5070
  width: 54,
4214
5071
  height: 54,
4215
5072
  fill: "currentcolor"
4216
- }, props), _path$3 || (_path$3 = /*#__PURE__*/React__namespace.createElement("path", {
5073
+ }, props), _path$9 || (_path$9 = /*#__PURE__*/React__namespace.createElement("path", {
4217
5074
  d: "M20.58 33.77h-3l-1.18-3.08H11l-1.1 3.08H7l5.27-13.54h2.89zm-5-5.36-1.86-5-1.83 5zM22 20.23h5.41a15.47 15.47 0 0 1 2.4.14 3.42 3.42 0 0 1 1.41.55 3.47 3.47 0 0 1 1 1.14 3 3 0 0 1 .42 1.58 3.26 3.26 0 0 1-1.91 2.94 3.63 3.63 0 0 1 1.91 1.22 3.28 3.28 0 0 1 .66 2 4 4 0 0 1-.43 1.8 3.63 3.63 0 0 1-1.09 1.4 3.89 3.89 0 0 1-1.83.65q-.69.07-3.3.09H22zm2.73 2.25v3.13h3.8a1.79 1.79 0 0 0 1.1-.49 1.41 1.41 0 0 0 .41-1 1.49 1.49 0 0 0-.35-1 1.54 1.54 0 0 0-1-.48c-.27 0-1.05-.05-2.34-.05zm0 5.39v3.62h2.57a11.52 11.52 0 0 0 1.88-.09 1.65 1.65 0 0 0 1-.54 1.6 1.6 0 0 0 .38-1.14 1.75 1.75 0 0 0-.29-1 1.69 1.69 0 0 0-.86-.62 9.28 9.28 0 0 0-2.41-.23zm19.62.92 2.65.84a5.94 5.94 0 0 1-2 3.29A5.74 5.74 0 0 1 41.38 34a5.87 5.87 0 0 1-4.44-1.84 7.09 7.09 0 0 1-1.73-5A7.43 7.43 0 0 1 37 21.87 6 6 0 0 1 41.54 20a5.64 5.64 0 0 1 4 1.47A5.33 5.33 0 0 1 47 24l-2.7.65a2.8 2.8 0 0 0-2.86-2.27A3.09 3.09 0 0 0 39 23.42a5.31 5.31 0 0 0-.93 3.5 5.62 5.62 0 0 0 .93 3.65 3 3 0 0 0 2.4 1.09 2.72 2.72 0 0 0 1.82-.66 4 4 0 0 0 1.13-2.21z"
4218
5075
  })));
4219
5076
  };
4220
5077
  var TextIcon = SvgText;
4221
5078
 
4222
- var _path$2;
4223
- function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$2.apply(this, arguments); }
5079
+ var _path$8;
5080
+ 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); }
4224
5081
  var SvgTextfield = function SvgTextfield(props) {
4225
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$2({
5082
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$8({
4226
5083
  xmlns: "http://www.w3.org/2000/svg",
4227
5084
  width: 54,
4228
5085
  height: 54,
4229
5086
  fill: "currentcolor"
4230
- }, props), _path$2 || (_path$2 = /*#__PURE__*/React__namespace.createElement("path", {
5087
+ }, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", {
4231
5088
  fillRule: "evenodd",
4232
5089
  d: "M45 16a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V19a3 3 0 0 1 3-3h36zm0 2H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V19a1 1 0 0 0-1-1zm-32 4v10h-2V22h2z"
4233
5090
  })));
4234
5091
  };
4235
5092
  var TextfieldIcon = SvgTextfield;
4236
5093
 
4237
- var _path$1;
4238
- function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); }
5094
+ var _path$7;
5095
+ 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); }
4239
5096
  var SvgTextarea = function SvgTextarea(props) {
4240
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$1({
5097
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$7({
4241
5098
  xmlns: "http://www.w3.org/2000/svg",
4242
5099
  width: 54,
4243
5100
  height: 54,
4244
5101
  fill: "currentcolor"
4245
- }, props), _path$1 || (_path$1 = /*#__PURE__*/React__namespace.createElement("path", {
5102
+ }, props), _path$7 || (_path$7 = /*#__PURE__*/React__namespace.createElement("path", {
4246
5103
  fillRule: "evenodd",
4247
5104
  d: "M45 13a3 3 0 0 1 3 3v22a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V16a3 3 0 0 1 3-3h36zm0 2H9a1 1 0 0 0-1 1v22a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V16a1 1 0 0 0-1-1zm-1.136 15.5.849.849-6.364 6.364-.849-.849 6.364-6.364zm.264 3.5.849.849-2.828 2.828-.849-.849L44.128 34zM13 19v10h-2V19h2z"
4248
5105
  })));
4249
5106
  };
4250
5107
  var TextareaIcon = SvgTextarea;
4251
5108
 
4252
- var _path, _path2;
4253
- function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
5109
+ var _path$6, _path2$2;
5110
+ 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); }
5111
+ var SvgIFrame = function SvgIFrame(props) {
5112
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$6({
5113
+ xmlns: "http://www.w3.org/2000/svg",
5114
+ width: 54,
5115
+ height: 54,
5116
+ fill: "none"
5117
+ }, props), _path$6 || (_path$6 = /*#__PURE__*/React__namespace.createElement("path", {
5118
+ fill: "currentcolor",
5119
+ d: "M34.467 37.3 41 31l-6.533-6.3-1.32 1.273L38.36 31l-5.213 5.027 1.32 1.273ZM19.533 24.7 13 31l6.533 6.3 1.32-1.273L15.64 31l5.214-5.027-1.32-1.273Zm4.127 14.832 1.805.468 4.875-17.532L28.535 22 23.66 39.532Z"
5120
+ })), _path2$2 || (_path2$2 = /*#__PURE__*/React__namespace.createElement("path", {
5121
+ fill: "currentcolor",
5122
+ fillRule: "evenodd",
5123
+ d: "M46 9a3 3 0 0 1 3 3v30a3 3 0 0 1-3 3H8a3 3 0 0 1-3-3V12a3 3 0 0 1 3-3h38Zm0 2H8a1 1 0 0 0-1 1v4h40v-4a1 1 0 0 0-1-1ZM7 42V18h40v24a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1Z",
5124
+ clipRule: "evenodd"
5125
+ })));
5126
+ };
5127
+ var IFrameIcon = SvgIFrame;
5128
+
5129
+ var _path$5, _path2$1;
5130
+ 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); }
4254
5131
  var SvgImage = function SvgImage(props) {
4255
- return /*#__PURE__*/React__namespace.createElement("svg", _extends({
5132
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$5({
4256
5133
  xmlns: "http://www.w3.org/2000/svg",
4257
5134
  width: 54,
4258
5135
  height: 54,
4259
5136
  fill: "currentcolor"
4260
- }, props), _path || (_path = /*#__PURE__*/React__namespace.createElement("path", {
5137
+ }, props), _path$5 || (_path$5 = /*#__PURE__*/React__namespace.createElement("path", {
4261
5138
  fillRule: "evenodd",
4262
5139
  d: "M34.636 21.91A3.818 3.818 0 1 1 27 21.908a3.818 3.818 0 0 1 7.636 0Zm-2 0A1.818 1.818 0 1 1 29 21.908a1.818 1.818 0 0 1 3.636 0Z",
4263
5140
  clipRule: "evenodd"
4264
- })), _path2 || (_path2 = /*#__PURE__*/React__namespace.createElement("path", {
5141
+ })), _path2$1 || (_path2$1 = /*#__PURE__*/React__namespace.createElement("path", {
4265
5142
  fillRule: "evenodd",
4266
5143
  d: "M15 13a2 2 0 0 0-2 2v24a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V15a2 2 0 0 0-2-2H15Zm24 2H15v12.45l4.71-4.709a1.91 1.91 0 0 1 2.702 0l6.695 6.695 2.656-1.77a1.91 1.91 0 0 1 2.411.239L39 32.73V15ZM15 39v-8.754a.975.975 0 0 0 .168-.135l5.893-5.893 6.684 6.685a1.911 1.911 0 0 0 2.41.238l2.657-1.77 6.02 6.02c.052.051.108.097.168.135V39H15Z",
4267
5144
  clipRule: "evenodd"
@@ -4269,6 +5146,22 @@ var SvgImage = function SvgImage(props) {
4269
5146
  };
4270
5147
  var ImageIcon = SvgImage;
4271
5148
 
5149
+ var _path$4;
5150
+ 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); }
5151
+ var SvgTable = function SvgTable(props) {
5152
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$4({
5153
+ xmlns: "http://www.w3.org/2000/svg",
5154
+ fill: "none",
5155
+ viewBox: "0 0 54 54"
5156
+ }, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", {
5157
+ fill: "currentcolor",
5158
+ fillRule: "evenodd",
5159
+ d: "M42.545 12.273A2.455 2.455 0 0 1 45 14.727v24.546a2.455 2.455 0 0 1-2.455 2.454h-31.09A2.455 2.455 0 0 1 9 39.273V14.727a2.455 2.455 0 0 1 2.455-2.454zM27.818 40.09h14.727a.818.818 0 0 0 .819-.818v-4.91H27.818Zm-1.636-5.727v5.727H11.455a.818.818 0 0 1-.819-.818v-4.91zm1.636-1.637h15.546V27H27.818ZM26.182 27v5.727H10.636V27zm1.636-1.636h15.546v-5.728H27.818Zm-1.636-5.728v5.728H10.636v-5.728z",
5160
+ clipRule: "evenodd"
5161
+ })));
5162
+ };
5163
+ var TableIcon = SvgTable;
5164
+
4272
5165
  const iconsByType = type => {
4273
5166
  return {
4274
5167
  button: ButtonIcon,
@@ -4277,130 +5170,42 @@ const iconsByType = type => {
4277
5170
  columns: GroupIcon,
4278
5171
  datetime: DatetimeIcon,
4279
5172
  group: GroupIcon,
5173
+ iframe: IFrameIcon,
4280
5174
  image: ImageIcon,
4281
5175
  number: NumberIcon,
4282
5176
  radio: RadioIcon,
4283
5177
  select: SelectIcon,
4284
5178
  separator: SeparatorIcon,
4285
5179
  spacer: SpacerIcon,
5180
+ dynamiclist: DynamicListIcon,
4286
5181
  taglist: TaglistIcon,
4287
5182
  text: TextIcon,
4288
5183
  textfield: TextfieldIcon,
4289
5184
  textarea: TextareaIcon,
5185
+ table: TableIcon,
4290
5186
  default: FormIcon
4291
5187
  }[type];
4292
5188
  };
4293
5189
 
4294
- const formFields = [Button, Checkbox, Checklist, FormComponent$1, Group, Image, Numberfield, Datetime, Radio, Select, Spacer, Separator, Taglist, Text, Textfield, Textarea];
5190
+ const formFields = [Button, Checkbox, Checklist, FormComponent$1, Group, IFrame, DynamicList, Image, Numberfield, Datetime, Radio, Select, Spacer, Separator, DynamicList, Taglist, Text, Textfield, Textarea, Table];
4295
5191
 
4296
5192
  class FormFields {
4297
5193
  constructor() {
4298
5194
  this._formFields = {};
4299
- formFields.forEach(formField => {
4300
- this.register(formField.config.type, formField);
4301
- });
4302
- }
4303
- register(type, formField) {
4304
- this._formFields[type] = formField;
4305
- }
4306
- get(type) {
4307
- return this._formFields[type];
4308
- }
4309
- }
4310
-
4311
- // config ///////////////////
4312
-
4313
- const VALUES_SOURCES = {
4314
- STATIC: 'static',
4315
- INPUT: 'input',
4316
- EXPRESSION: 'expression'
4317
- };
4318
- const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
4319
- const VALUES_SOURCES_LABELS = {
4320
- [VALUES_SOURCES.STATIC]: 'Static',
4321
- [VALUES_SOURCES.INPUT]: 'Input data',
4322
- [VALUES_SOURCES.EXPRESSION]: 'Expression'
4323
- };
4324
- const VALUES_SOURCES_PATHS = {
4325
- [VALUES_SOURCES.STATIC]: ['values'],
4326
- [VALUES_SOURCES.INPUT]: ['valuesKey'],
4327
- [VALUES_SOURCES.EXPRESSION]: ['valuesExpression']
4328
- };
4329
- const VALUES_SOURCES_DEFAULTS = {
4330
- [VALUES_SOURCES.STATIC]: [{
4331
- label: 'Value',
4332
- value: 'value'
4333
- }],
4334
- [VALUES_SOURCES.INPUT]: '',
4335
- [VALUES_SOURCES.EXPRESSION]: '='
4336
- };
4337
-
4338
- // helpers ///////////////////
4339
-
4340
- function getValuesSource(field) {
4341
- for (const source of Object.values(VALUES_SOURCES)) {
4342
- if (minDash.get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
4343
- return source;
4344
- }
4345
- }
4346
- return VALUES_SOURCE_DEFAULT;
4347
- }
4348
-
4349
- function createInjector(bootstrapModules) {
4350
- const injector = new didi.Injector(bootstrapModules);
4351
- injector.init();
4352
- return injector;
4353
- }
4354
-
4355
- /**
4356
- * @param {string?} prefix
4357
- *
4358
- * @returns Element
4359
- */
4360
- function createFormContainer(prefix = 'fjs') {
4361
- const container = document.createElement('div');
4362
- container.classList.add(`${prefix}-container`);
4363
- return container;
4364
- }
4365
-
4366
- const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression'];
4367
- const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text'];
4368
- function isRequired(field) {
4369
- return field.required;
4370
- }
4371
- function pathParse(path) {
4372
- if (!path) {
4373
- return [];
4374
- }
4375
- return path.split('.').map(key => {
4376
- return isNaN(parseInt(key)) ? key : parseInt(key);
4377
- });
4378
- }
4379
- function pathsEqual(a, b) {
4380
- return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
4381
- }
4382
- const indices = {};
4383
- function generateIndexForType(type) {
4384
- if (type in indices) {
4385
- indices[type]++;
4386
- } else {
4387
- indices[type] = 1;
5195
+ formFields.forEach(formField => {
5196
+ this.register(formField.config.type, formField);
5197
+ });
5198
+ }
5199
+ register(type, formField) {
5200
+ this._formFields[type] = formField;
5201
+ }
5202
+ get(type) {
5203
+ return this._formFields[type];
4388
5204
  }
4389
- return indices[type];
4390
- }
4391
- function generateIdForType(type) {
4392
- return `${type}${generateIndexForType(type)}`;
4393
5205
  }
4394
5206
 
4395
- /**
4396
- * @template T
4397
- * @param {T} data
4398
- * @param {(this: any, key: string, value: any) => any} [replacer]
4399
- * @return {T}
4400
- */
4401
- function clone(data, replacer) {
4402
- return JSON.parse(JSON.stringify(data, replacer));
4403
- }
5207
+ const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression', 'url', 'dataSource', 'columnsExpression'];
5208
+ const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text', 'url'];
4404
5209
 
4405
5210
  /**
4406
5211
  * @typedef { import('../types').Schema } Schema
@@ -4507,13 +5312,24 @@ function getSchemaVariables(schema, options = {}) {
4507
5312
  // remove duplicates
4508
5313
  return Array.from(new Set(variables));
4509
5314
  }
4510
- function runRecursively(formField, fn) {
4511
- const components = formField.components || [];
4512
- components.forEach((component, index) => {
4513
- runRecursively(component, fn);
4514
- });
4515
- fn(formField);
4516
- }
5315
+
5316
+ /**
5317
+ * Get the ancestry list of a form field.
5318
+ *
5319
+ * @param {string} formFieldId
5320
+ * @param {import('../core/FormFieldRegistry').default} formFieldRegistry
5321
+ *
5322
+ * @return {Array<string>} ancestry list
5323
+ */
5324
+ const getAncestryList = (formFieldId, formFieldRegistry) => {
5325
+ const ids = [];
5326
+ let currentFormField = formFieldRegistry.get(formFieldId);
5327
+ while (currentFormField) {
5328
+ ids.push(currentFormField.id);
5329
+ currentFormField = formFieldRegistry.get(currentFormField._parent);
5330
+ }
5331
+ return ids;
5332
+ };
4517
5333
 
4518
5334
  /**
4519
5335
  * @typedef {object} Condition
@@ -4530,36 +5346,102 @@ class ConditionChecker {
4530
5346
  /**
4531
5347
  * For given data, remove properties based on condition.
4532
5348
  *
4533
- * @param {Object<string, any>} properties
4534
5349
  * @param {Object<string, any>} data
5350
+ * @param {Object<string, any>} contextData
4535
5351
  * @param {Object} [options]
4536
5352
  * @param {Function} [options.getFilterPath]
5353
+ * @param {boolean} [options.leafNodeDeletionOnly]
4537
5354
  */
4538
- applyConditions(properties, data = {}, options = {}) {
4539
- const newProperties = clone(properties);
5355
+ applyConditions(data, contextData = {}, options = {}) {
5356
+ const workingData = clone(data);
4540
5357
  const {
4541
- getFilterPath = field => this._pathRegistry.getValuePath(field)
5358
+ getFilterPath = (field, indexes) => this._pathRegistry.getValuePath(field, {
5359
+ indexes
5360
+ }),
5361
+ leafNodeDeletionOnly = false
4542
5362
  } = options;
4543
- const form = this._formFieldRegistry.getAll().find(field => field.type === 'default');
5363
+ const _applyConditionsWithinScope = (rootField, scopeContext, startHidden = false) => {
5364
+ const {
5365
+ indexes = {},
5366
+ expressionIndexes = [],
5367
+ scopeData = contextData,
5368
+ parentScopeData = null
5369
+ } = scopeContext;
5370
+ this._pathRegistry.executeRecursivelyOnFields(rootField, ({
5371
+ field,
5372
+ isClosed,
5373
+ isRepeatable,
5374
+ context
5375
+ }) => {
5376
+ const {
5377
+ conditional,
5378
+ components,
5379
+ id
5380
+ } = field;
5381
+
5382
+ // build the expression context in the right format
5383
+ const localExpressionContext = buildExpressionContext({
5384
+ this: scopeData,
5385
+ data: contextData,
5386
+ i: expressionIndexes,
5387
+ parent: parentScopeData
5388
+ });
5389
+ context.isHidden = startHidden || context.isHidden || conditional && this._checkHideCondition(conditional, localExpressionContext);
5390
+
5391
+ // if a field is repeatable and visible, we need to implement custom recursion on its children
5392
+ if (isRepeatable && (!context.isHidden || leafNodeDeletionOnly)) {
5393
+ // prevent the regular recursion behavior of executeRecursivelyOnFields
5394
+ context.preventRecursion = true;
5395
+ const repeaterValuePath = this._pathRegistry.getValuePath(field, {
5396
+ indexes
5397
+ });
5398
+ const repeaterValue = minDash.get(contextData, repeaterValuePath);
5399
+
5400
+ // quit early if there are no children or data associated with the repeater
5401
+ if (!Array.isArray(repeaterValue) || !repeaterValue.length || !Array.isArray(components) || !components.length) {
5402
+ return;
5403
+ }
5404
+ for (let i = 0; i < repeaterValue.length; i++) {
5405
+ // create a new scope context for each index
5406
+ const newScopeContext = {
5407
+ indexes: {
5408
+ ...indexes,
5409
+ [id]: i
5410
+ },
5411
+ expressionIndexes: [...expressionIndexes, i + 1],
5412
+ scopeData: repeaterValue[i],
5413
+ parentScopeData: scopeData
5414
+ };
5415
+
5416
+ // for each child component, apply conditions within the new repetition scope
5417
+ components.forEach(component => {
5418
+ _applyConditionsWithinScope(component, newScopeContext, context.isHidden);
5419
+ });
5420
+ }
5421
+ }
5422
+
5423
+ // if we have a hidden repeatable field, and the data structure allows, we clear it directly at the root and stop recursion
5424
+ if (context.isHidden && !leafNodeDeletionOnly && isRepeatable) {
5425
+ context.preventRecursion = true;
5426
+ this._cleanlyClearDataAtPath(getFilterPath(field, indexes), workingData);
5427
+ }
5428
+
5429
+ // for simple leaf fields, we always clear
5430
+ if (context.isHidden && isClosed) {
5431
+ this._cleanlyClearDataAtPath(getFilterPath(field, indexes), workingData);
5432
+ }
5433
+ });
5434
+ };
5435
+
5436
+ // apply conditions starting with the root of the form
5437
+ const form = this._formFieldRegistry.getForm();
4544
5438
  if (!form) {
4545
5439
  throw new Error('form field registry has no form');
4546
5440
  }
4547
- this._pathRegistry.executeRecursivelyOnFields(form, ({
4548
- field,
4549
- isClosed,
4550
- context
4551
- }) => {
4552
- const {
4553
- conditional: condition
4554
- } = field;
4555
- context.isHidden = context.isHidden || condition && this._checkHideCondition(condition, data);
4556
-
4557
- // only clear the leaf nodes, as groups may both point to the same path
4558
- if (context.isHidden && isClosed) {
4559
- this._clearObjectValueRecursively(getFilterPath(field), newProperties);
4560
- }
5441
+ _applyConditionsWithinScope(form, {
5442
+ scopeData: contextData
4561
5443
  });
4562
- return newProperties;
5444
+ return workingData;
4563
5445
  }
4564
5446
 
4565
5447
  /**
@@ -4603,16 +5485,22 @@ class ConditionChecker {
4603
5485
  const result = this.check(condition.hide, data);
4604
5486
  return result === true;
4605
5487
  }
4606
- _clearObjectValueRecursively(valuePath, obj) {
5488
+ _cleanlyClearDataAtPath(valuePath, obj) {
4607
5489
  const workingValuePath = [...valuePath];
4608
5490
  let recurse = false;
4609
5491
  do {
4610
5492
  minDash.set(obj, workingValuePath, undefined);
4611
5493
  workingValuePath.pop();
4612
5494
  const parentObject = minDash.get(obj, workingValuePath);
4613
- recurse = minDash.isObject(parentObject) && !minDash.values(parentObject).length && !!workingValuePath.length;
5495
+ recurse = !!workingValuePath.length && (this._isEmptyObject(parentObject) || this._isEmptyArray(parentObject));
4614
5496
  } while (recurse);
4615
5497
  }
5498
+ _isEmptyObject(parentObject) {
5499
+ return minDash.isObject(parentObject) && !minDash.values(parentObject).length;
5500
+ }
5501
+ _isEmptyArray(parentObject) {
5502
+ return Array.isArray(parentObject) && (!parentObject.length || parentObject.every(item => item === undefined));
5503
+ }
4616
5504
  }
4617
5505
  ConditionChecker.$inject = ['formFieldRegistry', 'pathRegistry', 'eventBus'];
4618
5506
 
@@ -5127,14 +6015,15 @@ class UpdateFieldValidationHandler {
5127
6015
  execute(context) {
5128
6016
  const {
5129
6017
  field,
5130
- value
6018
+ value,
6019
+ indexes
5131
6020
  } = context;
5132
6021
  const {
5133
6022
  errors
5134
6023
  } = this._form._getState();
5135
6024
  context.oldErrors = clone(errors);
5136
6025
  const fieldErrors = this._validator.validateField(field, value);
5137
- const updatedErrors = minDash.set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined);
6026
+ const updatedErrors = minDash.set(errors, [field.id, ...Object.values(indexes || {})], fieldErrors.length ? fieldErrors : undefined);
5138
6027
  this._form._setState({
5139
6028
  errors: updatedErrors
5140
6029
  });
@@ -5164,10 +6053,11 @@ class ViewerCommands {
5164
6053
  'formField.validation.update': UpdateFieldValidationHandler
5165
6054
  };
5166
6055
  }
5167
- updateFieldValidation(field, value) {
6056
+ updateFieldValidation(field, value, indexes) {
5168
6057
  const context = {
5169
6058
  field,
5170
- value
6059
+ value,
6060
+ indexes
5171
6061
  };
5172
6062
  this._commandStack.execute('formField.validation.update', context);
5173
6063
  }
@@ -5180,6 +6070,266 @@ var ViewerCommandsModule = {
5180
6070
  viewerCommands: ['type', ViewerCommands]
5181
6071
  };
5182
6072
 
6073
+ var _path$3;
6074
+ 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); }
6075
+ var SvgExpand = function SvgExpand(props) {
6076
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$3({
6077
+ xmlns: "http://www.w3.org/2000/svg",
6078
+ width: 16,
6079
+ height: 16,
6080
+ fill: "none"
6081
+ }, props), _path$3 || (_path$3 = /*#__PURE__*/React__namespace.createElement("path", {
6082
+ fill: "currentColor",
6083
+ d: "M2 9h5.5v3.086l-1.293-1.293-.707.707L8 14l2.5-2.5-.707-.707L8.5 12.086V9H14V8H2v1Zm11-7H3a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1Zm0 3H3V3h10v2Z"
6084
+ })));
6085
+ };
6086
+ var ExpandSvg = SvgExpand;
6087
+
6088
+ var _path$2;
6089
+ function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$2.apply(this, arguments); }
6090
+ var SvgCollapse = function SvgCollapse(props) {
6091
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$2({
6092
+ xmlns: "http://www.w3.org/2000/svg",
6093
+ width: 16,
6094
+ height: 16,
6095
+ fill: "none"
6096
+ }, props), _path$2 || (_path$2 = /*#__PURE__*/React__namespace.createElement("path", {
6097
+ fill: "currentColor",
6098
+ d: "M13 10H3a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1Zm0 3H3v-2h10v2ZM8.5 3.914l1.293 1.293.707-.707L8 2 5.5 4.5l.707.707L7.5 3.914V7H2v1h12V7H8.5V3.914Z"
6099
+ })));
6100
+ };
6101
+ var CollapseSvg = SvgCollapse;
6102
+
6103
+ var _path$1, _path2;
6104
+ function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); }
6105
+ var SvgAdd = function SvgAdd(props) {
6106
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$1({
6107
+ xmlns: "http://www.w3.org/2000/svg",
6108
+ width: 16,
6109
+ height: 16,
6110
+ fill: "none"
6111
+ }, props), _path$1 || (_path$1 = /*#__PURE__*/React__namespace.createElement("path", {
6112
+ fill: "currentColor",
6113
+ d: "M8 2c3.3 0 6 2.7 6 6s-2.7 6-6 6-6-2.7-6-6 2.7-6 6-6Zm0-1C4.15 1 1 4.15 1 8s3.15 7 7 7 7-3.15 7-7-3.15-7-7-7Z"
6114
+ })), _path2 || (_path2 = /*#__PURE__*/React__namespace.createElement("path", {
6115
+ fill: "currentColor",
6116
+ d: "M12 7.5H8.5V4h-1v3.5H4v1h3.5V12h1V8.5H12v-1Z"
6117
+ })));
6118
+ };
6119
+ var AddSvg = SvgAdd;
6120
+
6121
+ var _path;
6122
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
6123
+ var SvgDelete = function SvgDelete(props) {
6124
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends({
6125
+ xmlns: "http://www.w3.org/2000/svg",
6126
+ width: 16,
6127
+ height: 16,
6128
+ fill: "none"
6129
+ }, props), _path || (_path = /*#__PURE__*/React__namespace.createElement("path", {
6130
+ fill: "currentColor",
6131
+ d: "m12 4.7-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7Z"
6132
+ })));
6133
+ };
6134
+ var DeleteSvg = SvgDelete;
6135
+
6136
+ // disable react hook rules as the linter is confusing the functional components within a class as class components
6137
+ class RepeatRenderManager {
6138
+ constructor(form, formFields, formFieldRegistry, pathRegistry) {
6139
+ this._form = form;
6140
+ this._formFields = formFields;
6141
+ this._formFieldRegistry = formFieldRegistry;
6142
+ this._pathRegistry = pathRegistry;
6143
+ this.Repeater = this.Repeater.bind(this);
6144
+ this.RepeatFooter = this.RepeatFooter.bind(this);
6145
+ }
6146
+
6147
+ /**
6148
+ * Checks whether a field is currently repeating its children.
6149
+ *
6150
+ * @param {string} id - The id of the field to check
6151
+ * @returns {boolean} - True if repeatable, false otherwise
6152
+ */
6153
+ isFieldRepeating(id) {
6154
+ if (!id) {
6155
+ return false;
6156
+ }
6157
+ const formField = this._formFieldRegistry.get(id);
6158
+ const formFieldDefinition = this._formFields.get(formField.type);
6159
+ return formFieldDefinition.config.repeatable && formField.isRepeating;
6160
+ }
6161
+ Repeater(props) {
6162
+ const {
6163
+ RowsRenderer,
6164
+ indexes,
6165
+ useSharedState,
6166
+ ...restProps
6167
+ } = props;
6168
+ const [sharedRepeatState] = useSharedState;
6169
+ const {
6170
+ data
6171
+ } = this._form._getState();
6172
+ const repeaterField = props.field;
6173
+ const dataPath = this._pathRegistry.getValuePath(repeaterField, {
6174
+ indexes
6175
+ });
6176
+ const values = minDash.get(data, dataPath) || [];
6177
+ const nonCollapsedItems = this._getNonCollapsedItems(repeaterField);
6178
+ const collapseEnabled = !repeaterField.disableCollapse && values.length > nonCollapsedItems;
6179
+ const isCollapsed = collapseEnabled && sharedRepeatState.isCollapsed;
6180
+ const hasChildren = repeaterField.components && repeaterField.components.length > 0;
6181
+ const showRemove = repeaterField.allowAddRemove && hasChildren;
6182
+ const displayValues = isCollapsed ? values.slice(0, nonCollapsedItems) : values;
6183
+ const onDeleteItem = index => {
6184
+ const updatedValues = values.slice();
6185
+ updatedValues.splice(index, 1);
6186
+ props.onChange({
6187
+ field: repeaterField,
6188
+ value: updatedValues,
6189
+ indexes
6190
+ });
6191
+ };
6192
+ const parentExpressionContextInfo = hooks.useContext(LocalExpressionContext$1);
6193
+ return jsxRuntime.jsx(jsxRuntime.Fragment, {
6194
+ children: displayValues.map((value, index) => {
6195
+ const elementProps = {
6196
+ ...restProps,
6197
+ indexes: {
6198
+ ...(indexes || {}),
6199
+ [repeaterField.id]: index
6200
+ }
6201
+ };
6202
+ const localExpressionContextInfo = hooks.useMemo(() => ({
6203
+ data: parentExpressionContextInfo.data,
6204
+ this: value,
6205
+ parent: buildExpressionContext(parentExpressionContextInfo),
6206
+ i: [...parentExpressionContextInfo.i, index + 1]
6207
+ }), [index, value]);
6208
+ return !showRemove ? jsxRuntime.jsx(LocalExpressionContext$1.Provider, {
6209
+ value: localExpressionContextInfo,
6210
+ children: jsxRuntime.jsx(RowsRenderer, {
6211
+ ...elementProps
6212
+ })
6213
+ }) : jsxRuntime.jsxs("div", {
6214
+ class: "fjs-repeat-row-container",
6215
+ children: [jsxRuntime.jsx("div", {
6216
+ class: "fjs-repeat-row-rows",
6217
+ children: jsxRuntime.jsx(LocalExpressionContext$1.Provider, {
6218
+ value: localExpressionContextInfo,
6219
+ children: jsxRuntime.jsx(RowsRenderer, {
6220
+ ...elementProps
6221
+ })
6222
+ })
6223
+ }), jsxRuntime.jsx("button", {
6224
+ class: "fjs-repeat-row-remove",
6225
+ type: "button",
6226
+ "aria-label": `Remove list item ${index + 1}`,
6227
+ onClick: () => onDeleteItem(index),
6228
+ children: jsxRuntime.jsx("div", {
6229
+ class: "fjs-repeat-row-remove-icon-container",
6230
+ children: jsxRuntime.jsx(DeleteSvg, {})
6231
+ })
6232
+ })]
6233
+ });
6234
+ })
6235
+ });
6236
+ }
6237
+ RepeatFooter(props) {
6238
+ const addButtonRef = hooks.useRef(null);
6239
+ const {
6240
+ useSharedState,
6241
+ indexes,
6242
+ field: repeaterField,
6243
+ readonly,
6244
+ disabled
6245
+ } = props;
6246
+ const [sharedRepeatState, setSharedRepeatState] = useSharedState;
6247
+ const {
6248
+ data
6249
+ } = this._form._getState();
6250
+ const dataPath = this._pathRegistry.getValuePath(repeaterField, {
6251
+ indexes
6252
+ });
6253
+ const values = minDash.get(data, dataPath) || [];
6254
+ const nonCollapsedItems = this._getNonCollapsedItems(repeaterField);
6255
+ const collapseEnabled = !repeaterField.disableCollapse && values.length > nonCollapsedItems;
6256
+ const isCollapsed = collapseEnabled && sharedRepeatState.isCollapsed;
6257
+ const hasChildren = repeaterField.components && repeaterField.components.length > 0;
6258
+ const showAdd = repeaterField.allowAddRemove && hasChildren;
6259
+ const toggle = () => {
6260
+ setSharedRepeatState(state => ({
6261
+ ...state,
6262
+ isCollapsed: !isCollapsed
6263
+ }));
6264
+ };
6265
+ const shouldScroll = hooks.useRef(false);
6266
+ const onAddItem = () => {
6267
+ const updatedValues = values.slice();
6268
+ const newItem = this._form._getInitializedFieldData(this._form._getState().data, {
6269
+ container: repeaterField,
6270
+ indexes: {
6271
+ ...indexes,
6272
+ [repeaterField.id]: updatedValues.length
6273
+ }
6274
+ });
6275
+ updatedValues.push(newItem);
6276
+ shouldScroll.current = true;
6277
+ props.onChange({
6278
+ field: repeaterField,
6279
+ value: updatedValues,
6280
+ indexes
6281
+ });
6282
+ setSharedRepeatState(state => ({
6283
+ ...state,
6284
+ isCollapsed: false
6285
+ }));
6286
+ };
6287
+ useScrollIntoView(addButtonRef, [values.length], {
6288
+ align: 'bottom',
6289
+ behavior: 'auto',
6290
+ offset: 20
6291
+ }, [shouldScroll]);
6292
+ return jsxRuntime.jsxs("div", {
6293
+ className: classNames('fjs-repeat-render-footer', {
6294
+ 'fjs-remove-allowed': repeaterField.allowAddRemove
6295
+ }),
6296
+ children: [showAdd ? jsxRuntime.jsx("button", {
6297
+ readOnly: readonly,
6298
+ disabled: disabled || readonly,
6299
+ class: "fjs-repeat-render-add",
6300
+ type: "button",
6301
+ ref: addButtonRef,
6302
+ onClick: onAddItem,
6303
+ children: jsxRuntime.jsxs(jsxRuntime.Fragment, {
6304
+ children: [jsxRuntime.jsx(AddSvg, {}), " ", 'Add new']
6305
+ })
6306
+ }) : null, collapseEnabled ? jsxRuntime.jsx("button", {
6307
+ class: "fjs-repeat-render-collapse",
6308
+ type: "button",
6309
+ onClick: toggle,
6310
+ children: isCollapsed ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
6311
+ children: [jsxRuntime.jsx(ExpandSvg, {}), " ", `Expand all (${values.length})`]
6312
+ }) : jsxRuntime.jsxs(jsxRuntime.Fragment, {
6313
+ children: [jsxRuntime.jsx(CollapseSvg, {}), " ", 'Collapse']
6314
+ })
6315
+ }) : null]
6316
+ });
6317
+ }
6318
+ _getNonCollapsedItems(field) {
6319
+ const DEFAULT_NON_COLLAPSED_ITEMS = 5;
6320
+ const {
6321
+ nonCollapsedItems
6322
+ } = field;
6323
+ return nonCollapsedItems ? nonCollapsedItems : DEFAULT_NON_COLLAPSED_ITEMS;
6324
+ }
6325
+ }
6326
+ RepeatRenderManager.$inject = ['form', 'formFields', 'formFieldRegistry', 'pathRegistry'];
6327
+
6328
+ var RepeatRenderModule = {
6329
+ __init__: ['repeatRenderManager'],
6330
+ repeatRenderManager: ['type', RepeatRenderManager]
6331
+ };
6332
+
5183
6333
  var FN_REF = '__fn';
5184
6334
  var DEFAULT_PRIORITY = 1000;
5185
6335
  var slice = Array.prototype.slice;
@@ -5580,7 +6730,7 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
5580
6730
  * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
5581
6731
  *
5582
6732
  * @param {string} event
5583
- * @param {EventBusListener} listener
6733
+ * @param {EventBusListener} newListener
5584
6734
  */
5585
6735
  EventBus.prototype._addListener = function (event, newListener) {
5586
6736
  var listener = this._getListeners(event),
@@ -5928,10 +7078,17 @@ class FieldFactory {
5928
7078
 
5929
7079
  const parent = _parent && this._formFieldRegistry.get(_parent);
5930
7080
  const parentPath = parent && this._pathRegistry.getValuePath(parent) || [];
5931
- if (config.keyed && key && !this._pathRegistry.canClaimPath([...parentPath, ...key.split('.')], true)) {
7081
+ const knownAncestorIds = getAncestryList(_parent, this._formFieldRegistry);
7082
+ if (config.keyed && key && !this._pathRegistry.canClaimPath([...parentPath, ...key.split('.')], {
7083
+ isClosed: true,
7084
+ knownAncestorIds
7085
+ })) {
5932
7086
  throw new Error(`binding path '${[...parentPath, key].join('.')}' is already claimed`);
5933
7087
  }
5934
- if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], false)) {
7088
+ if (config.pathed && path && !this._pathRegistry.canClaimPath([...parentPath, ...path.split('.')], {
7089
+ isRepeatable: config.repeatable,
7090
+ knownAncestorIds
7091
+ })) {
5935
7092
  throw new Error(`binding path '${[...parentPath, ...path.split('.')].join('.')}' is already claimed`);
5936
7093
  }
5937
7094
  const labelAttrs = applyDefaults && config.label ? {
@@ -5944,9 +7101,23 @@ class FieldFactory {
5944
7101
  this._ensureId(field);
5945
7102
  if (config.keyed) {
5946
7103
  this._ensureKey(field);
7104
+ this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), {
7105
+ isClosed: true,
7106
+ claimerId: field.id,
7107
+ knownAncestorIds: getAncestryList(_parent, this._formFieldRegistry)
7108
+ });
5947
7109
  }
5948
- if (config.pathed && path) {
5949
- this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), false);
7110
+ if (config.pathed) {
7111
+ if (config.repeatable) {
7112
+ this._enforceDefaultPath(field);
7113
+ }
7114
+ if (field.path) {
7115
+ this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), {
7116
+ isRepeatable: config.repeatable,
7117
+ claimerId: field.id,
7118
+ knownAncestorIds: getAncestryList(_parent, this._formFieldRegistry)
7119
+ });
7120
+ }
5950
7121
  }
5951
7122
  return field;
5952
7123
  }
@@ -5963,16 +7134,23 @@ class FieldFactory {
5963
7134
  }
5964
7135
  _ensureKey(field) {
5965
7136
  if (!field.key) {
5966
- let random;
5967
- const parent = this._formFieldRegistry.get(field._parent);
5968
-
5969
- // ensure key uniqueness at level
5970
- do {
5971
- random = Math.random().toString(36).substring(7);
5972
- } while (parent && parent.components.some(child => child.key === random));
5973
- field.key = `${field.type}_${random}`;
7137
+ field.key = this._getUniqueKeyPath(field);
7138
+ }
7139
+ }
7140
+ _enforceDefaultPath(field) {
7141
+ if (!field.path) {
7142
+ field.path = this._getUniqueKeyPath(field);
5974
7143
  }
5975
- this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), true);
7144
+ }
7145
+ _getUniqueKeyPath(field) {
7146
+ let random;
7147
+ const parent = this._formFieldRegistry.get(field._parent);
7148
+
7149
+ // ensure key uniqueness at level
7150
+ do {
7151
+ random = Math.random().toString(36).substring(7);
7152
+ } while (parent && parent.components.some(child => child.key === random));
7153
+ return `${field.type}_${random}`;
5976
7154
  }
5977
7155
  }
5978
7156
  FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields'];
@@ -6009,34 +7187,61 @@ FieldFactory.$inject = ['formFieldRegistry', 'pathRegistry', 'formFields'];
6009
7187
  * ]
6010
7188
  */
6011
7189
  class PathRegistry {
6012
- constructor(formFieldRegistry, formFields) {
7190
+ constructor(formFieldRegistry, formFields, injector) {
6013
7191
  this._formFieldRegistry = formFieldRegistry;
6014
7192
  this._formFields = formFields;
7193
+ this._injector = injector;
6015
7194
  this._dataPaths = [];
6016
7195
  }
6017
- canClaimPath(path, closed = false) {
7196
+ canClaimPath(path, options = {}) {
7197
+ const {
7198
+ isClosed = false,
7199
+ isRepeatable = false,
7200
+ skipAncestryCheck = false,
7201
+ claimerId = null,
7202
+ knownAncestorIds = []
7203
+ } = options;
6018
7204
  let node = {
6019
7205
  children: this._dataPaths
6020
7206
  };
7207
+
7208
+ // (1) if we reach a leaf node, we cannot claim it, if we reach an open node, we can
7209
+ // if we reach a repeatable node, we need to ensure that the claimer is (or will be) an ancestor of the repeater
6021
7210
  for (const segment of path) {
6022
7211
  node = _getNextSegment(node, segment);
6023
-
6024
- // if no node at that path, we can claim it no matter what
6025
7212
  if (!node) {
6026
7213
  return true;
6027
7214
  }
6028
-
6029
- // if we reach a leaf node, definitely not claimable
7215
+ if (node.isRepeatable && !skipAncestryCheck) {
7216
+ if (!(claimerId || knownAncestorIds.length)) {
7217
+ throw new Error('cannot claim a path that contains a repeater without specifying a claimerId or knownAncestorIds');
7218
+ }
7219
+ const isValidRepeatClaim = knownAncestorIds.includes(node.repeaterId) || claimerId && getAncestryList(claimerId, this._formFieldRegistry).includes(node.repeaterId);
7220
+ if (!isValidRepeatClaim) {
7221
+ return false;
7222
+ }
7223
+ }
6030
7224
  if (node.children === null) {
6031
7225
  return false;
6032
7226
  }
6033
7227
  }
6034
7228
 
6035
- // if after all segments we reach a node with children, we can claim it only openly
6036
- return !closed;
7229
+ // (2) if the path lands in the middle of the tree, we can only claim an open, non-repeatable path
7230
+ return !(isClosed || isRepeatable);
6037
7231
  }
6038
- claimPath(path, closed = false) {
6039
- if (!this.canClaimPath(path, closed)) {
7232
+ claimPath(path, options = {}) {
7233
+ const {
7234
+ isClosed = false,
7235
+ isRepeatable = false,
7236
+ claimerId = null,
7237
+ knownAncestorIds = []
7238
+ } = options;
7239
+ if (!this.canClaimPath(path, {
7240
+ isClosed,
7241
+ isRepeatable,
7242
+ claimerId,
7243
+ knownAncestorIds
7244
+ })) {
6040
7245
  throw new Error(`cannot claim path '${path.join('.')}'`);
6041
7246
  }
6042
7247
  let node = {
@@ -6056,9 +7261,15 @@ class PathRegistry {
6056
7261
  }
6057
7262
  node = child;
6058
7263
  }
6059
- if (closed) {
7264
+ if (isClosed) {
6060
7265
  node.children = null;
6061
7266
  }
7267
+
7268
+ // add some additional info when we make a repeatable path claim
7269
+ if (isRepeatable) {
7270
+ node.isRepeatable = true;
7271
+ node.repeaterId = claimerId;
7272
+ }
6062
7273
  }
6063
7274
  unclaimPath(path) {
6064
7275
  // verification Pass
@@ -6107,6 +7318,7 @@ class PathRegistry {
6107
7318
  const callResult = fn({
6108
7319
  field,
6109
7320
  isClosed: true,
7321
+ isRepeatable: false,
6110
7322
  context
6111
7323
  });
6112
7324
  return result && callResult;
@@ -6114,16 +7326,22 @@ class PathRegistry {
6114
7326
  const callResult = fn({
6115
7327
  field,
6116
7328
  isClosed: false,
7329
+ isRepeatable: formFieldConfig.repeatable,
6117
7330
  context
6118
7331
  });
6119
7332
  result = result && callResult;
6120
7333
  }
6121
- if (field.components) {
7334
+
7335
+ // stop executing if false is specifically returned or if preventing recursion
7336
+ if (result === false || context.preventRecursion) {
7337
+ return result;
7338
+ }
7339
+ if (Array.isArray(field.components)) {
6122
7340
  for (const child of field.components) {
6123
7341
  const callResult = this.executeRecursivelyOnFields(child, fn, clone(context));
6124
7342
  result = result && callResult;
6125
7343
 
6126
- // only stop executing if false is specifically returned, not if undefined
7344
+ // stop executing if false is specifically returned
6127
7345
  if (result === false) {
6128
7346
  return result;
6129
7347
  }
@@ -6138,6 +7356,7 @@ class PathRegistry {
6138
7356
  * @param {Object} field - The field object with properties: `key`, `path`, `id`, and optionally `_parent`.
6139
7357
  * @param {Object} [options={}] - Configuration options.
6140
7358
  * @param {Object} [options.replacements={}] - A map of field IDs to alternative path arrays.
7359
+ * @param {Object} [options.indexes=null] - A map of parent IDs to the index of the field within said parent, leave null to get an unindexed path.
6141
7360
  * @param {Object} [options.cutoffNode] - The ID of the parent field at which to stop generating the path.
6142
7361
  *
6143
7362
  * @returns {(Array<string>|undefined)} An array of strings representing the binding path, or undefined if not determinable.
@@ -6145,11 +7364,14 @@ class PathRegistry {
6145
7364
  getValuePath(field, options = {}) {
6146
7365
  const {
6147
7366
  replacements = {},
7367
+ indexes = null,
6148
7368
  cutoffNode = null
6149
7369
  } = options;
6150
7370
  let localValuePath = [];
6151
7371
  const hasReplacement = Object.prototype.hasOwnProperty.call(replacements, field.id);
6152
7372
  const formFieldConfig = this._formFields.get(field.type).config;
7373
+
7374
+ // uses path overrides instead of true path to calculate a potential value path
6153
7375
  if (hasReplacement) {
6154
7376
  const replacement = replacements[field.id];
6155
7377
  if (replacement === null || replacement === undefined || replacement === '') {
@@ -6166,6 +7388,13 @@ class PathRegistry {
6166
7388
  } else if (formFieldConfig.pathed && field.path) {
6167
7389
  localValuePath = field.path.split('.');
6168
7390
  }
7391
+
7392
+ // add potential indexes of repeated fields
7393
+ if (indexes) {
7394
+ localValuePath = this._addIndexes(localValuePath, field, indexes);
7395
+ }
7396
+
7397
+ // if parent exists and isn't cutoff node, add parent's value path
6169
7398
  if (field._parent && field._parent !== cutoffNode) {
6170
7399
  const parent = this._formFieldRegistry.get(field._parent);
6171
7400
  return [...(this.getValuePath(parent, options) || []), ...localValuePath];
@@ -6175,6 +7404,13 @@ class PathRegistry {
6175
7404
  clear() {
6176
7405
  this._dataPaths = [];
6177
7406
  }
7407
+ _addIndexes(localValuePath, field, indexes) {
7408
+ const repeatRenderManager = this._injector.get('repeatRenderManager', false);
7409
+ if (repeatRenderManager && repeatRenderManager.isFieldRepeating(field._parent)) {
7410
+ return [indexes[field._parent], ...localValuePath];
7411
+ }
7412
+ return localValuePath;
7413
+ }
6178
7414
  }
6179
7415
  const _getNextSegment = (node, segment) => {
6180
7416
  if (minDash.isArray(node.children)) {
@@ -6182,7 +7418,7 @@ const _getNextSegment = (node, segment) => {
6182
7418
  }
6183
7419
  return null;
6184
7420
  };
6185
- PathRegistry.$inject = ['formFieldRegistry', 'formFields'];
7421
+ PathRegistry.$inject = ['formFieldRegistry', 'formFields', 'injector'];
6186
7422
 
6187
7423
  /**
6188
7424
  * @typedef { { id: String, components: Array<String> } } FormRow
@@ -6274,7 +7510,7 @@ class FormLayouter {
6274
7510
  type,
6275
7511
  components
6276
7512
  } = formField;
6277
- if (type !== 'default' && type !== 'group' || !components) {
7513
+ if (!['default', 'group', 'dynamiclist'].includes(type) || !components) {
6278
7514
  return;
6279
7515
  }
6280
7516
 
@@ -6366,6 +7602,9 @@ class FormFieldRegistry {
6366
7602
  getAll() {
6367
7603
  return Object.values(this._formFields);
6368
7604
  }
7605
+ getForm() {
7606
+ return this.getAll().find(formField => formField.type === 'default');
7607
+ }
6369
7608
  forEach(callback) {
6370
7609
  this.getAll().forEach(formField => callback(formField));
6371
7610
  }
@@ -6557,7 +7796,7 @@ class Form {
6557
7796
  schema: importedSchema,
6558
7797
  warnings
6559
7798
  } = this.get('importer').importSchema(schema);
6560
- const initializedData = this._initializeFieldData(clone(data));
7799
+ const initializedData = this._getInitializedFieldData(clone(data));
6561
7800
  this._setState({
6562
7801
  data: initializedData,
6563
7802
  errors: {},
@@ -6613,26 +7852,68 @@ class Form {
6613
7852
  * @returns {Errors}
6614
7853
  */
6615
7854
  validate() {
6616
- const formFieldRegistry = this.get('formFieldRegistry'),
7855
+ const formFields = this.get('formFields'),
7856
+ formFieldRegistry = this.get('formFieldRegistry'),
6617
7857
  pathRegistry = this.get('pathRegistry'),
6618
7858
  validator = this.get('validator');
6619
7859
  const {
6620
7860
  data
6621
7861
  } = this._getState();
6622
- const getErrorPath = field => [field.id];
6623
- const errors = formFieldRegistry.getAll().reduce((errors, field) => {
7862
+ const getErrorPath = (field, indexes) => [field.id, ...Object.values(indexes || {})];
7863
+ function validateFieldRecursively(errors, field, indexes) {
6624
7864
  const {
6625
- disabled
7865
+ disabled,
7866
+ type,
7867
+ isRepeating
6626
7868
  } = field;
7869
+ const {
7870
+ config: fieldConfig
7871
+ } = formFields.get(type);
7872
+
7873
+ // (1) Skip disabled fields
6627
7874
  if (disabled) {
6628
- return errors;
7875
+ return;
7876
+ }
7877
+
7878
+ // (2) Validate the field
7879
+ const valuePath = pathRegistry.getValuePath(field, {
7880
+ indexes
7881
+ });
7882
+ const valueData = minDash.get(data, valuePath);
7883
+ const fieldErrors = validator.validateField(field, valueData);
7884
+ if (fieldErrors.length) {
7885
+ minDash.set(errors, getErrorPath(field, indexes), fieldErrors);
7886
+ }
7887
+
7888
+ // (3) Process parents
7889
+ if (!Array.isArray(field.components)) {
7890
+ return;
7891
+ }
7892
+
7893
+ // (4a) Recurse repeatable parents both across the indexes of repetition and the children
7894
+ if (fieldConfig.repeatable && isRepeating) {
7895
+ if (!Array.isArray(valueData)) {
7896
+ return;
7897
+ }
7898
+ valueData.forEach((_, index) => {
7899
+ field.components.forEach(component => {
7900
+ validateFieldRecursively(errors, component, {
7901
+ ...indexes,
7902
+ [field.id]: index
7903
+ });
7904
+ });
7905
+ });
7906
+ return;
6629
7907
  }
6630
- const value = minDash.get(data, pathRegistry.getValuePath(field));
6631
- const fieldErrors = validator.validateField(field, value);
6632
- return minDash.set(errors, getErrorPath(field), fieldErrors.length ? fieldErrors : undefined);
6633
- }, /** @type {Errors} */{});
6634
- const filteredErrors = this._applyConditions(errors, data, {
6635
- getFilterPath: getErrorPath
7908
+
7909
+ // (4b) Recurse non-repeatable parents only across the children
7910
+ field.components.forEach(component => validateFieldRecursively(errors, component, indexes));
7911
+ }
7912
+ const workingErrors = {};
7913
+ validateFieldRecursively(workingErrors, formFieldRegistry.getForm());
7914
+ const filteredErrors = this._applyConditions(workingErrors, data, {
7915
+ getFilterPath: getErrorPath,
7916
+ leafNodeDeletionOnly: true
6636
7917
  });
6637
7918
  this._setState({
6638
7919
  errors: filteredErrors
@@ -6730,11 +8011,12 @@ class Form {
6730
8011
  /**
6731
8012
  * @internal
6732
8013
  *
6733
- * @param { { add?: boolean, field: any, remove?: number, value?: any } } update
8014
+ * @param { { add?: boolean, field: any, indexes: object, remove?: number, value?: any } } update
6734
8015
  */
6735
8016
  _update(update) {
6736
8017
  const {
6737
8018
  field,
8019
+ indexes,
6738
8020
  value
6739
8021
  } = update;
6740
8022
  const {
@@ -6744,8 +8026,11 @@ class Form {
6744
8026
  const validator = this.get('validator'),
6745
8027
  pathRegistry = this.get('pathRegistry');
6746
8028
  const fieldErrors = validator.validateField(field, value);
6747
- minDash.set(data, pathRegistry.getValuePath(field), value);
6748
- minDash.set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined);
8029
+ const valuePath = pathRegistry.getValuePath(field, {
8030
+ indexes
8031
+ });
8032
+ minDash.set(data, valuePath, value);
8033
+ minDash.set(errors, [field.id, ...Object.values(indexes || {})], fieldErrors.length ? fieldErrors : undefined);
6749
8034
  this._setState({
6750
8035
  data: clone(data),
6751
8036
  errors: clone(errors)
@@ -6774,7 +8059,7 @@ class Form {
6774
8059
  * @internal
6775
8060
  */
6776
8061
  _getModules() {
6777
- return [ExpressionLanguageModule, MarkdownModule, ViewerCommandsModule];
8062
+ return [ExpressionLanguageModule, MarkdownModule, ViewerCommandsModule, RepeatRenderModule];
6778
8063
  }
6779
8064
 
6780
8065
  /**
@@ -6788,29 +8073,58 @@ class Form {
6788
8073
  * @internal
6789
8074
  */
6790
8075
  _getSubmitData() {
6791
- const formFieldRegistry = this.get('formFieldRegistry'),
6792
- pathRegistry = this.get('pathRegistry'),
6793
- formFields = this.get('formFields');
8076
+ const formFieldRegistry = this.get('formFieldRegistry');
8077
+ const formFields = this.get('formFields');
8078
+ const pathRegistry = this.get('pathRegistry');
6794
8079
  const formData = this._getState().data;
6795
- const submitData = formFieldRegistry.getAll().reduce((previous, field) => {
8080
+ function collectSubmitDataRecursively(submitData, formField, indexes) {
6796
8081
  const {
6797
8082
  disabled,
6798
8083
  type
6799
- } = field;
8084
+ } = formField;
6800
8085
  const {
6801
8086
  config: fieldConfig
6802
8087
  } = formFields.get(type);
6803
8088
 
6804
- // do not submit disabled form fields or routing fields
6805
- if (disabled || !fieldConfig.keyed) {
6806
- return previous;
8089
+ // (1) Process keyed fields
8090
+ if (!disabled && fieldConfig.keyed) {
8091
+ const valuePath = pathRegistry.getValuePath(formField, {
8092
+ indexes
8093
+ });
8094
+ const value = minDash.get(formData, valuePath);
8095
+ minDash.set(submitData, valuePath, value);
8096
+ }
8097
+
8098
+ // (2) Process parents
8099
+ if (!Array.isArray(formField.components)) {
8100
+ return;
8101
+ }
8102
+
8103
+ // (3a) Recurse repeatable parents both across the indexes of repetition and the children
8104
+ if (fieldConfig.repeatable && formField.isRepeating) {
8105
+ const valueData = minDash.get(formData, pathRegistry.getValuePath(formField, {
8106
+ indexes
8107
+ }));
8108
+ if (!Array.isArray(valueData)) {
8109
+ return;
8110
+ }
8111
+ valueData.forEach((_, index) => {
8112
+ formField.components.forEach(component => {
8113
+ collectSubmitDataRecursively(submitData, component, {
8114
+ ...indexes,
8115
+ [formField.id]: index
8116
+ });
8117
+ });
8118
+ });
8119
+ return;
6807
8120
  }
6808
- const valuePath = pathRegistry.getValuePath(field);
6809
- const value = minDash.get(formData, valuePath);
6810
- return minDash.set(previous, valuePath, value);
6811
- }, {});
6812
- const filteredSubmitData = this._applyConditions(submitData, formData);
6813
- return filteredSubmitData;
8121
+
8122
+ // (3b) Recurse non-repeatable parents only across the children
8123
+ formField.components.forEach(component => collectSubmitDataRecursively(submitData, component, indexes));
8124
+ }
8125
+ const workingSubmitData = {};
8126
+ collectSubmitDataRecursively(workingSubmitData, formFieldRegistry.getForm(), {});
8127
+ return this._applyConditions(workingSubmitData, formData);
6814
8128
  }
6815
8129
 
6816
8130
  /**
@@ -6824,26 +8138,27 @@ class Form {
6824
8138
  /**
6825
8139
  * @internal
6826
8140
  */
6827
- _initializeFieldData(data) {
6828
- const formFieldRegistry = this.get('formFieldRegistry'),
6829
- formFields = this.get('formFields'),
6830
- pathRegistry = this.get('pathRegistry');
6831
- return formFieldRegistry.getAll().reduce((initializedData, formField) => {
8141
+ _getInitializedFieldData(data, options = {}) {
8142
+ const formFieldRegistry = this.get('formFieldRegistry');
8143
+ const formFields = this.get('formFields');
8144
+ const pathRegistry = this.get('pathRegistry');
8145
+ function initializeFieldDataRecursively(initializedData, formField, indexes) {
6832
8146
  const {
6833
8147
  defaultValue,
6834
- type
8148
+ type,
8149
+ isRepeating
6835
8150
  } = formField;
8151
+ const {
8152
+ config: fieldConfig
8153
+ } = formFields.get(type);
8154
+ const valuePath = pathRegistry.getValuePath(formField, {
8155
+ indexes
8156
+ });
8157
+ let valueData = minDash.get(data, valuePath);
6836
8158
 
6837
- // try to get value from data
6838
- // if unavailable - try to get default value from form field
6839
- // if unavailable - get empty value from form field
6840
-
6841
- const valuePath = pathRegistry.getValuePath(formField);
6842
- if (valuePath) {
6843
- const {
6844
- config: fieldConfig
6845
- } = formFields.get(type);
6846
- let valueData = minDash.get(data, valuePath);
8159
+ // (1) Process keyed fields
8160
+ if (fieldConfig.keyed) {
8161
+ // (a) Retrieve and sanitize data from input
6847
8162
  if (!minDash.isUndefined(valueData) && fieldConfig.sanitizeValue) {
6848
8163
  valueData = fieldConfig.sanitizeValue({
6849
8164
  formField,
@@ -6851,15 +8166,66 @@ class Form {
6851
8166
  value: valueData
6852
8167
  });
6853
8168
  }
8169
+
8170
+ // (b) Initialize field value in output data
6854
8171
  const initializedFieldValue = !minDash.isUndefined(valueData) ? valueData : !minDash.isUndefined(defaultValue) ? defaultValue : fieldConfig.emptyValue;
6855
- return minDash.set(initializedData, valuePath, initializedFieldValue);
8172
+ minDash.set(initializedData, valuePath, initializedFieldValue);
8173
+ }
8174
+
8175
+ // (2) Process parents
8176
+ if (!Array.isArray(formField.components)) {
8177
+ return;
8178
+ }
8179
+ if (fieldConfig.repeatable && isRepeating) {
8180
+ // (a) Sanitize repeatable parents data if it is not an array
8181
+ if (!valueData || !Array.isArray(valueData)) {
8182
+ valueData = new Array(minDash.isUndefined(formField.defaultRepetitions) ? 1 : formField.defaultRepetitions).fill().map(_ => ({})) || [];
8183
+ }
8184
+
8185
+ // (b) Ensure all elements of the array are objects
8186
+ valueData = valueData.map(val => minDash.isObject(val) ? val : {});
8187
+
8188
+ // (c) Initialize field value in output data
8189
+ minDash.set(initializedData, valuePath, valueData);
8190
+
8191
+ // (d) If indexed ahead of time, recurse repeatable simply across the children
8192
+ if (!minDash.isUndefined(indexes[formField.id])) {
8193
+ formField.components.forEach(component => initializeFieldDataRecursively(initializedData, component, {
8194
+ ...indexes
8195
+ }));
8196
+ return;
8197
+ }
8198
+
8199
+ // (e1) Recurse repeatable parents both across the indexes of repetition and the children
8200
+ valueData.forEach((_, index) => {
8201
+ formField.components.forEach(component => initializeFieldDataRecursively(initializedData, component, {
8202
+ ...indexes,
8203
+ [formField.id]: index
8204
+ }));
8205
+ });
8206
+ return;
6856
8207
  }
6857
- return initializedData;
6858
- }, data);
8208
+
8209
+ // (e2) Recurse non-repeatable parents only across the children
8210
+ formField.components.forEach(component => initializeFieldDataRecursively(initializedData, component, indexes));
8211
+ }
8212
+
8213
+ // allows definition of a specific subfield to generate the data for
8214
+ const container = options.container || formFieldRegistry.getForm();
8215
+ const indexes = options.indexes || {};
8216
+ const basePath = pathRegistry.getValuePath(container, {
8217
+ indexes
8218
+ }) || [];
8219
+
8220
+ // if indexing ahead of time, we must add this index to the data path at the end
8221
+ const path = !minDash.isUndefined(indexes[container.id]) ? [...basePath, indexes[container.id]] : basePath;
8222
+ const workingData = clone(data);
8223
+ initializeFieldDataRecursively(workingData, container, indexes);
8224
+ return minDash.get(workingData, path, {});
6859
8225
  }
6860
8226
  }
6861
8227
 
6862
- const schemaVersion = 12;
8228
+ const schemaVersion = 14;
6863
8229
 
6864
8230
  /**
6865
8231
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
@@ -6896,6 +8262,7 @@ exports.DATE_LABEL_PATH = DATE_LABEL_PATH;
6896
8262
  exports.Datetime = Datetime;
6897
8263
  exports.Default = FormComponent$1;
6898
8264
  exports.Description = Description;
8265
+ exports.DynamicList = DynamicList;
6899
8266
  exports.Errors = Errors;
6900
8267
  exports.ExpressionLanguageModule = ExpressionLanguageModule;
6901
8268
  exports.FeelExpressionLanguage = FeelExpressionLanguage;
@@ -6910,15 +8277,24 @@ exports.FormFields = FormFields;
6910
8277
  exports.FormLayouter = FormLayouter;
6911
8278
  exports.FormRenderContext = FormRenderContext$1;
6912
8279
  exports.Group = Group;
8280
+ exports.IFrame = IFrame;
6913
8281
  exports.Image = Image;
6914
8282
  exports.Importer = Importer;
6915
8283
  exports.Label = Label;
8284
+ exports.LocalExpressionContext = LocalExpressionContext$1;
6916
8285
  exports.MINUTES_IN_DAY = MINUTES_IN_DAY;
6917
8286
  exports.MarkdownModule = MarkdownModule;
6918
8287
  exports.MarkdownRenderer = MarkdownRenderer;
6919
8288
  exports.Numberfield = Numberfield;
8289
+ exports.OPTIONS_SOURCES = OPTIONS_SOURCES;
8290
+ exports.OPTIONS_SOURCES_DEFAULTS = OPTIONS_SOURCES_DEFAULTS;
8291
+ exports.OPTIONS_SOURCES_LABELS = OPTIONS_SOURCES_LABELS;
8292
+ exports.OPTIONS_SOURCES_PATHS = OPTIONS_SOURCES_PATHS;
8293
+ exports.OPTIONS_SOURCE_DEFAULT = OPTIONS_SOURCE_DEFAULT;
6920
8294
  exports.PathRegistry = PathRegistry;
6921
8295
  exports.Radio = Radio;
8296
+ exports.RepeatRenderManager = RepeatRenderManager;
8297
+ exports.RepeatRenderModule = RepeatRenderModule;
6922
8298
  exports.Select = Select;
6923
8299
  exports.Separator = Separator;
6924
8300
  exports.Spacer = Spacer;
@@ -6928,17 +8304,14 @@ exports.TIME_SERIALISINGFORMAT_LABELS = TIME_SERIALISINGFORMAT_LABELS;
6928
8304
  exports.TIME_SERIALISING_FORMATS = TIME_SERIALISING_FORMATS;
6929
8305
  exports.TIME_SERIALISING_FORMAT_PATH = TIME_SERIALISING_FORMAT_PATH;
6930
8306
  exports.TIME_USE24H_PATH = TIME_USE24H_PATH;
8307
+ exports.Table = Table;
6931
8308
  exports.Taglist = Taglist;
6932
8309
  exports.Text = Text;
6933
8310
  exports.Textarea = Textarea;
6934
8311
  exports.Textfield = Textfield;
6935
- exports.VALUES_SOURCES = VALUES_SOURCES;
6936
- exports.VALUES_SOURCES_DEFAULTS = VALUES_SOURCES_DEFAULTS;
6937
- exports.VALUES_SOURCES_LABELS = VALUES_SOURCES_LABELS;
6938
- exports.VALUES_SOURCES_PATHS = VALUES_SOURCES_PATHS;
6939
- exports.VALUES_SOURCE_DEFAULT = VALUES_SOURCE_DEFAULT;
6940
8312
  exports.ViewerCommands = ViewerCommands;
6941
8313
  exports.ViewerCommandsModule = ViewerCommandsModule;
8314
+ exports.buildExpressionContext = buildExpressionContext;
6942
8315
  exports.clone = clone;
6943
8316
  exports.createForm = createForm;
6944
8317
  exports.createFormContainer = createFormContainer;
@@ -6946,14 +8319,19 @@ exports.createInjector = createInjector;
6946
8319
  exports.formFields = formFields;
6947
8320
  exports.generateIdForType = generateIdForType;
6948
8321
  exports.generateIndexForType = generateIndexForType;
8322
+ exports.getAncestryList = getAncestryList;
8323
+ exports.getOptionsSource = getOptionsSource;
6949
8324
  exports.getSchemaVariables = getSchemaVariables;
6950
- exports.getValuesSource = getValuesSource;
6951
8325
  exports.iconsByType = iconsByType;
6952
8326
  exports.isRequired = isRequired;
6953
8327
  exports.pathParse = pathParse;
6954
8328
  exports.pathsEqual = pathsEqual;
6955
8329
  exports.runRecursively = runRecursively;
6956
8330
  exports.sanitizeHTML = sanitizeHTML;
8331
+ exports.sanitizeIFrameSource = sanitizeIFrameSource;
6957
8332
  exports.sanitizeImageSource = sanitizeImageSource;
6958
8333
  exports.schemaVersion = schemaVersion;
8334
+ exports.useExpressionEvaluation = useExpressionEvaluation;
8335
+ exports.useSingleLineTemplateEvaluation = useSingleLineTemplateEvaluation;
8336
+ exports.useTemplateEvaluation = useTemplateEvaluation;
6959
8337
  //# sourceMappingURL=index.cjs.map