@formio/js 5.3.0 → 5.4.0-api98.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/formio.builder.css +16 -5
  2. package/dist/formio.builder.min.css +1 -1
  3. package/dist/formio.embed.css +1 -1
  4. package/dist/formio.embed.js +1 -1
  5. package/dist/formio.embed.min.css +1 -1
  6. package/dist/formio.embed.min.js +1 -1
  7. package/dist/formio.embed.min.js.LICENSE.txt +1 -1
  8. package/dist/formio.form.css +16 -5
  9. package/dist/formio.form.js +3234 -3226
  10. package/dist/formio.form.min.css +1 -1
  11. package/dist/formio.form.min.js +1 -1
  12. package/dist/formio.form.min.js.LICENSE.txt +1 -3
  13. package/dist/formio.full.css +16 -5
  14. package/dist/formio.full.js +3961 -3933
  15. package/dist/formio.full.min.css +1 -1
  16. package/dist/formio.full.min.js +1 -1
  17. package/dist/formio.full.min.js.LICENSE.txt +1 -3
  18. package/dist/formio.js +1485 -1487
  19. package/dist/formio.min.js +1 -1
  20. package/dist/formio.min.js.LICENSE.txt +1 -1
  21. package/dist/formio.utils.js +1402 -1415
  22. package/dist/formio.utils.min.js +1 -1
  23. package/dist/formio.utils.min.js.LICENSE.txt +1 -3
  24. package/lib/cjs/Embed.js +35 -1
  25. package/lib/cjs/Form.d.ts +3 -1
  26. package/lib/cjs/Form.js +2 -2
  27. package/lib/cjs/FormBuilder.d.ts +2 -2
  28. package/lib/cjs/FormBuilder.js +1 -1
  29. package/lib/cjs/Formio.js +1 -1
  30. package/lib/cjs/PDF.js +11 -1
  31. package/lib/cjs/Webform.d.ts +2 -1
  32. package/lib/cjs/Webform.js +77 -2
  33. package/lib/cjs/WebformBuilder.js +15 -0
  34. package/lib/cjs/Wizard.d.ts +1 -0
  35. package/lib/cjs/Wizard.js +11 -0
  36. package/lib/cjs/components/_classes/component/Component.d.ts +14 -3
  37. package/lib/cjs/components/_classes/component/Component.js +91 -24
  38. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.d.ts +7 -0
  39. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +1 -0
  40. package/lib/cjs/components/_classes/input/Input.js +17 -2
  41. package/lib/cjs/components/_classes/nested/NestedComponent.js +5 -0
  42. package/lib/cjs/components/address/Address.js +18 -1
  43. package/lib/cjs/components/datagrid/DataGrid.js +14 -3
  44. package/lib/cjs/components/datamap/DataMap.d.ts +4 -0
  45. package/lib/cjs/components/datamap/DataMap.js +6 -5
  46. package/lib/cjs/components/fieldset/Fieldset.d.ts +1 -0
  47. package/lib/cjs/components/fieldset/Fieldset.js +8 -0
  48. package/lib/cjs/components/file/File.d.ts +3 -1
  49. package/lib/cjs/components/file/File.js +62 -17
  50. package/lib/cjs/components/form/Form.js +2 -1
  51. package/lib/cjs/components/select/Select.js +14 -9
  52. package/lib/cjs/components/table/editForm/Table.edit.display.d.ts +27 -0
  53. package/lib/cjs/components/table/editForm/Table.edit.display.js +10 -0
  54. package/lib/cjs/components/tags/Tags.js +2 -1
  55. package/lib/cjs/package.json +1 -1
  56. package/lib/cjs/templates/index.d.ts +3 -0
  57. package/lib/cjs/translations/en.d.ts +2 -0
  58. package/lib/cjs/translations/en.js +2 -0
  59. package/lib/cjs/utils/conditionOperators/IsEqualTo.d.ts +1 -3
  60. package/lib/cjs/utils/conditionOperators/IsEqualTo.js +6 -12
  61. package/lib/cjs/utils/conditionOperators/index.d.ts +2 -1
  62. package/lib/cjs/utils/i18n.d.ts +1 -0
  63. package/lib/cjs/utils/i18n.js +2 -0
  64. package/lib/cjs/utils/index.d.ts +2 -1
  65. package/lib/cjs/utils/utils.d.ts +9 -0
  66. package/lib/cjs/utils/utils.js +132 -2
  67. package/lib/cjs/widgets/CalendarWidget.js +2 -1
  68. package/lib/mjs/Embed.js +35 -1
  69. package/lib/mjs/Form.d.ts +3 -1
  70. package/lib/mjs/Form.js +2 -2
  71. package/lib/mjs/FormBuilder.d.ts +2 -2
  72. package/lib/mjs/FormBuilder.js +1 -1
  73. package/lib/mjs/Formio.js +1 -1
  74. package/lib/mjs/PDF.js +11 -1
  75. package/lib/mjs/Webform.d.ts +2 -1
  76. package/lib/mjs/Webform.js +76 -2
  77. package/lib/mjs/WebformBuilder.js +15 -0
  78. package/lib/mjs/Wizard.d.ts +1 -0
  79. package/lib/mjs/Wizard.js +12 -1
  80. package/lib/mjs/components/_classes/component/Component.d.ts +14 -3
  81. package/lib/mjs/components/_classes/component/Component.js +87 -24
  82. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.d.ts +7 -0
  83. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +1 -0
  84. package/lib/mjs/components/_classes/input/Input.js +16 -3
  85. package/lib/mjs/components/_classes/nested/NestedComponent.js +5 -0
  86. package/lib/mjs/components/address/Address.js +16 -1
  87. package/lib/mjs/components/datagrid/DataGrid.js +12 -2
  88. package/lib/mjs/components/datamap/DataMap.d.ts +4 -0
  89. package/lib/mjs/components/datamap/DataMap.js +6 -5
  90. package/lib/mjs/components/fieldset/Fieldset.d.ts +1 -0
  91. package/lib/mjs/components/fieldset/Fieldset.js +8 -0
  92. package/lib/mjs/components/file/File.d.ts +3 -1
  93. package/lib/mjs/components/file/File.js +60 -15
  94. package/lib/mjs/components/form/Form.js +2 -1
  95. package/lib/mjs/components/select/Select.js +12 -9
  96. package/lib/mjs/components/table/editForm/Table.edit.display.d.ts +27 -0
  97. package/lib/mjs/components/table/editForm/Table.edit.display.js +10 -0
  98. package/lib/mjs/components/tags/Tags.js +1 -1
  99. package/lib/mjs/package.json +1 -1
  100. package/lib/mjs/templates/index.d.ts +3 -0
  101. package/lib/mjs/translations/en.d.ts +2 -0
  102. package/lib/mjs/translations/en.js +2 -0
  103. package/lib/mjs/utils/conditionOperators/IsEqualTo.d.ts +1 -3
  104. package/lib/mjs/utils/conditionOperators/IsEqualTo.js +6 -11
  105. package/lib/mjs/utils/conditionOperators/index.d.ts +2 -1
  106. package/lib/mjs/utils/i18n.d.ts +1 -0
  107. package/lib/mjs/utils/i18n.js +2 -0
  108. package/lib/mjs/utils/index.d.ts +2 -1
  109. package/lib/mjs/utils/utils.d.ts +9 -0
  110. package/lib/mjs/utils/utils.js +130 -1
  111. package/lib/mjs/widgets/CalendarWidget.js +1 -1
  112. package/package.json +5 -4
package/lib/mjs/Wizard.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import _ from 'lodash';
2
2
  import Webform from './Webform';
3
3
  import { Formio } from './Formio';
4
- import { fastCloneDeep, checkCondition, firstNonNil, uniqueKey, eachComponent } from './utils';
4
+ import { fastCloneDeep, checkCondition, firstNonNil, uniqueKey, eachComponent, screenReaderSpeech } from './utils';
5
5
  export default class Wizard extends Webform {
6
6
  /**
7
7
  * Constructor for wizard-based forms.
@@ -701,6 +701,7 @@ export default class Wizard extends Webform {
701
701
  }
702
702
  emitNextPage() {
703
703
  this.emit('nextPage', { page: this.page, submission: this.submission });
704
+ this.announceCurrentPage();
704
705
  }
705
706
  nextPage() {
706
707
  // Read-only forms should not worry about validation before going to next page, nor should they submit.
@@ -745,6 +746,16 @@ export default class Wizard extends Webform {
745
746
  }
746
747
  emitPrevPage() {
747
748
  this.emit('prevPage', { page: this.page, submission: this.submission });
749
+ this.announceCurrentPage();
750
+ }
751
+ announceCurrentPage() {
752
+ if (_.get(this.form, 'settings.wizardHeaderType', '') === 'StepIndicator') {
753
+ screenReaderSpeech(`Now on step ${this.page + 1} of ${this.pages.length}: ${_.get(this.currentPage, 'component.title')}`);
754
+ const currentLink = _.get(this.refs, `${this.wizardKey}-link.[${this.page}]`);
755
+ if (currentLink) {
756
+ currentLink.focus();
757
+ }
758
+ }
748
759
  }
749
760
  prevPage() {
750
761
  return this.beforePage().then(() => {
@@ -169,6 +169,7 @@ declare class Component extends Element {
169
169
  * @returns {boolean} - If the parent should conditionally clear.
170
170
  */
171
171
  parentShouldConditionallyClear(): boolean;
172
+ hasCondionallyHiddenLayoutParent(): boolean;
172
173
  parentConditionallyHidden(): boolean;
173
174
  /**
174
175
  * Returns true if any of the parents default their component "hidden" property to true.
@@ -187,6 +188,7 @@ declare class Component extends Element {
187
188
  tooltipClass: string;
188
189
  for: any;
189
190
  };
191
+ getFieldsetLegendIds(): string;
190
192
  init(): void;
191
193
  /**
192
194
  * Disable this component.
@@ -584,6 +586,15 @@ declare class Component extends Element {
584
586
  * @returns {string} - The custom style
585
587
  */
586
588
  get customStyle(): string;
589
+ /**
590
+ * Build custom styles from the styles form option or global config.
591
+ * @param {string[]} templateNames - The possible template names.
592
+ * @returns {{ [refName: string]: string[] }} - The custom styles object for the named template.
593
+ * @todo - Rename this to a better method name that doesn't clash
594
+ */
595
+ getCustomStyles(templateNames: string[]): {
596
+ [refName: string]: string[];
597
+ };
587
598
  /**
588
599
  * Returns if the application is on a mobile device.
589
600
  * @returns {boolean} - TRUE if the application is on a mobile device.
@@ -918,9 +929,9 @@ declare class Component extends Element {
918
929
  */
919
930
  get hasDefaultValue(): boolean;
920
931
  /**
921
- * Determine if we should add a default value for this component.
922
- * @returns {boolean} - TRUE if a default value should be set
923
- */
932
+ * Determine if we should add a default value for this component.
933
+ * @returns {boolean} - TRUE if a default value should be set
934
+ */
924
935
  get shouldAddDefaultValue(): boolean;
925
936
  /**
926
937
  * Get the default value of this component.
@@ -442,6 +442,16 @@ export default class Component extends Element {
442
442
  }
443
443
  return false;
444
444
  }
445
+ hasCondionallyHiddenLayoutParent() {
446
+ let currentParent = this.parent;
447
+ while (currentParent) {
448
+ if (currentParent._conditionallyHidden && FormioUtils.isLayoutComponent(currentParent) && currentParent.component.clearOnHide === true) {
449
+ return true;
450
+ }
451
+ currentParent = currentParent.parent;
452
+ }
453
+ return false;
454
+ }
445
455
  parentConditionallyHidden() {
446
456
  let currentParent = this.parent;
447
457
  while (currentParent) {
@@ -503,6 +513,17 @@ export default class Component extends Element {
503
513
  }
504
514
  return label;
505
515
  }
516
+ getFieldsetLegendIds() {
517
+ const legendIds = [];
518
+ let currentParent = this.parent;
519
+ while (currentParent) {
520
+ if (currentParent.component?.type === 'fieldset' && currentParent.component?.legend) {
521
+ legendIds.push(`l-${currentParent.id}-legend`);
522
+ }
523
+ currentParent = currentParent.parent;
524
+ }
525
+ return legendIds.reverse().join(' ');
526
+ }
506
527
  init() {
507
528
  this.disabled = this.shouldDisabled;
508
529
  this._visible = this.hasCondition() ? !this.conditionallyHidden() : !this.component.hidden;
@@ -706,7 +727,7 @@ export default class Component extends Element {
706
727
  this._conditionallyClear = true;
707
728
  return this._conditionallyClear;
708
729
  }
709
- this._conditionallyClear = this.hasSetValue ? false : this.parentShouldConditionallyClear();
730
+ this._conditionallyClear = this.hasSetValue ? this.hasCondionallyHiddenLayoutParent() : this.parentShouldConditionallyClear();
710
731
  return this._conditionallyClear;
711
732
  }
712
733
  /**
@@ -961,8 +982,20 @@ export default class Component extends Element {
961
982
  return this.options.renderMode === 'html';
962
983
  }
963
984
  renderTemplate(name, data = {}, modeOption = '') {
964
- // Need to make this fall back to form if renderMode is not found similar to how we search templates.
985
+ // Allow more specific template names
986
+ const names = [
987
+ `${name}-${this.component.type}-${this.key}`,
988
+ `${name}-${this.component.type}`,
989
+ `${name}-${this.key}`,
990
+ `${name}`,
991
+ ];
992
+ // Allow template alters.
965
993
  const mode = modeOption || this.options.renderMode || 'form';
994
+ const { referenceAttributeName, template } = this.getTemplate(names, mode);
995
+ if (referenceAttributeName) {
996
+ this._referenceAttributeName = referenceAttributeName;
997
+ }
998
+ // Need to make this fall back to form if renderMode is not found similar to how we search templates.
966
999
  data.component = this.component;
967
1000
  data.self = this;
968
1001
  data.options = this.options;
@@ -984,18 +1017,7 @@ export default class Component extends Element {
984
1017
  };
985
1018
  data.label = data.labelInfo || this.labelInfo;
986
1019
  data.tooltip = this.getFormattedTooltip(this.component.tooltip);
987
- // Allow more specific template names
988
- const names = [
989
- `${name}-${this.component.type}-${this.key}`,
990
- `${name}-${this.component.type}`,
991
- `${name}-${this.key}`,
992
- `${name}`,
993
- ];
994
- // Allow template alters.
995
- const { referenceAttributeName, template } = this.getTemplate(names, mode);
996
- if (referenceAttributeName) {
997
- this._referenceAttributeName = referenceAttributeName;
998
- }
1020
+ data.customStyles = this.getCustomStyles(names);
999
1021
  return this.hook(`render${name.charAt(0).toUpperCase() + name.substring(1, name.length)}`, this.interpolate(template, data), data, mode);
1000
1022
  }
1001
1023
  /**
@@ -1638,14 +1660,27 @@ export default class Component extends Element {
1638
1660
  dialogContents: 'single',
1639
1661
  dialogClose: 'single',
1640
1662
  });
1663
+ // Check if an element is inside shadow dom
1664
+ const isInShadowDOM = typeof ShadowRoot !== 'undefined' && this.element?.getRootNode() instanceof ShadowRoot;
1665
+ // if we render shadow dom inside <iframe>'s we need to get the body from the current iframe,
1666
+ // not the general body. This is necessary to hide and show the scroll bar correctly.
1667
+ const body = isInShadowDOM ? this.element.getRootNode().host.ownerDocument.body : document.body;
1668
+ const rootEl = isInShadowDOM ? this.element.closest('.formio-form-wrapper') : document.body;
1669
+ const checkModal = (method) => {
1670
+ if (isInShadowDOM) {
1671
+ body.style.overflow = method === 'add' ? 'hidden' : '';
1672
+ return;
1673
+ }
1674
+ body.classList[method]('modal-open');
1675
+ };
1641
1676
  dialog.refs.dialogContents.appendChild(element);
1642
- document.body.appendChild(dialog);
1643
- document.body.classList.add('modal-open');
1677
+ rootEl.appendChild(dialog);
1678
+ checkModal('add');
1644
1679
  dialog.close = () => {
1645
- document.body.classList.remove('modal-open');
1680
+ checkModal('remove');
1646
1681
  dialog.dispatchEvent(new CustomEvent('close'));
1647
1682
  };
1648
- this.addEventListener(dialog, 'close', () => this.removeChildFrom(dialog, document.body));
1683
+ this.addEventListener(dialog, 'close', () => this.removeChildFrom(dialog, rootEl));
1649
1684
  const close = (event) => {
1650
1685
  event.preventDefault();
1651
1686
  dialog.close();
@@ -1716,6 +1751,20 @@ export default class Component extends Element {
1716
1751
  });
1717
1752
  return customCSS;
1718
1753
  }
1754
+ /**
1755
+ * Build custom styles from the styles form option or global config.
1756
+ * @param {string[]} templateNames - The possible template names.
1757
+ * @returns {{ [refName: string]: string[] }} - The custom styles object for the named template.
1758
+ * @todo - Rename this to a better method name that doesn't clash
1759
+ */
1760
+ getCustomStyles(templateNames) {
1761
+ for (const name of templateNames) {
1762
+ if (this.options.styles?.[name]) {
1763
+ return this.options.styles[name];
1764
+ }
1765
+ }
1766
+ return {};
1767
+ }
1719
1768
  /**
1720
1769
  * Returns the component condition operator settings if available.
1721
1770
  * @returns {object} - The component condition operator settings.
@@ -2497,6 +2546,20 @@ export default class Component extends Element {
2497
2546
  return Promise.resolve(editor);
2498
2547
  }
2499
2548
  else {
2549
+ // Due to an issue with ckeditor not loading styles in the shadowdom (https://github.com/ckeditor/ckeditor5/issues/15824), we need to copy cke-styles to the shadowdom
2550
+ let current = element;
2551
+ while (current) {
2552
+ if (current instanceof ShadowRoot) {
2553
+ const ckeStyles = document.querySelector('style[data-cke="true"]');
2554
+ const clone = document.createElement('style');
2555
+ clone.setAttribute('data-cke', 'true');
2556
+ clone.textContent = ckeStyles.textContent;
2557
+ current.prepend(clone);
2558
+ break;
2559
+ }
2560
+ ;
2561
+ current = current.parentNode || current.host;
2562
+ }
2500
2563
  return ClassicEditor.create(element, settings).then((editor) => {
2501
2564
  editor.model.document.on('change', () => onChange(editor.data.get()));
2502
2565
  return editor;
@@ -2556,7 +2619,7 @@ export default class Component extends Element {
2556
2619
  });
2557
2620
  }
2558
2621
  get shouldSanitizeValue() {
2559
- // Sanitize value if sanitizing for thw whole content is turned off
2622
+ // Sanitize value if sanitizing for the whole content is turned off
2560
2623
  return this.options?.sanitize !== false;
2561
2624
  }
2562
2625
  addAce(element, settings, onChange) {
@@ -2574,6 +2637,7 @@ export default class Component extends Element {
2574
2637
  editor.setOptions(settings);
2575
2638
  editor.getSession().setMode(settings.mode);
2576
2639
  editor.on('change', () => onChange(editor.getValue()));
2640
+ editor.renderer.attachToShadowRoot();
2577
2641
  if (settings.isUseWorkerDisabled) {
2578
2642
  editor.session.setUseWorker(false);
2579
2643
  }
@@ -2634,7 +2698,6 @@ export default class Component extends Element {
2634
2698
  return;
2635
2699
  }
2636
2700
  _.set(this._data, this.key, value);
2637
- return;
2638
2701
  }
2639
2702
  /**
2640
2703
  * Splice a value from the dataValue.
@@ -2681,9 +2744,9 @@ export default class Component extends Element {
2681
2744
  this.component.defaultValue !== undefined));
2682
2745
  }
2683
2746
  /**
2684
- * Determine if we should add a default value for this component.
2685
- * @returns {boolean} - TRUE if a default value should be set
2686
- */
2747
+ * Determine if we should add a default value for this component.
2748
+ * @returns {boolean} - TRUE if a default value should be set
2749
+ */
2687
2750
  get shouldAddDefaultValue() {
2688
2751
  return this.pristine && this.allowData && (this.hasDefaultValue || !this.options.noDefaults);
2689
2752
  }
@@ -3672,7 +3735,7 @@ export default class Component extends Element {
3672
3735
  class: 'form-control',
3673
3736
  lang: this.options.language,
3674
3737
  };
3675
- if (this.component.placeholder) {
3738
+ if (this.component.placeholder && !this.options?.readOnly) {
3676
3739
  attributes.placeholder = this.t(this.component.placeholder, { _userInput: true });
3677
3740
  }
3678
3741
  if (this.component.tabindex) {
@@ -82,6 +82,7 @@ declare const _default: ({
82
82
  inline?: undefined;
83
83
  defaultValue?: undefined;
84
84
  values?: undefined;
85
+ customConditional?: undefined;
85
86
  logic?: undefined;
86
87
  dataSrc?: undefined;
87
88
  valueProperty?: undefined;
@@ -101,6 +102,7 @@ declare const _default: ({
101
102
  inline?: undefined;
102
103
  defaultValue?: undefined;
103
104
  values?: undefined;
105
+ customConditional?: undefined;
104
106
  logic?: undefined;
105
107
  dataSrc?: undefined;
106
108
  valueProperty?: undefined;
@@ -126,6 +128,7 @@ declare const _default: ({
126
128
  value: string;
127
129
  })[];
128
130
  placeholder?: undefined;
131
+ customConditional?: undefined;
129
132
  logic?: undefined;
130
133
  dataSrc?: undefined;
131
134
  valueProperty?: undefined;
@@ -141,6 +144,7 @@ declare const _default: ({
141
144
  tooltip: string;
142
145
  key: string;
143
146
  input: boolean;
147
+ customConditional: string;
144
148
  logic: ({
145
149
  name: string;
146
150
  trigger: {
@@ -211,6 +215,7 @@ declare const _default: ({
211
215
  inline?: undefined;
212
216
  defaultValue?: undefined;
213
217
  values?: undefined;
218
+ customConditional?: undefined;
214
219
  logic?: undefined;
215
220
  as?: undefined;
216
221
  editor?: undefined;
@@ -226,6 +231,7 @@ declare const _default: ({
226
231
  placeholder?: undefined;
227
232
  inline?: undefined;
228
233
  values?: undefined;
234
+ customConditional?: undefined;
229
235
  logic?: undefined;
230
236
  dataSrc?: undefined;
231
237
  valueProperty?: undefined;
@@ -248,6 +254,7 @@ declare const _default: ({
248
254
  placeholder?: undefined;
249
255
  inline?: undefined;
250
256
  values?: undefined;
257
+ customConditional?: undefined;
251
258
  logic?: undefined;
252
259
  dataSrc?: undefined;
253
260
  valueProperty?: undefined;
@@ -55,6 +55,7 @@ export default [
55
55
  tooltip: 'Encrypt this field on the server. This is two way encryption which is not suitable for passwords.',
56
56
  key: 'encrypted',
57
57
  input: true,
58
+ customConditional: 'show = data.encrypted;',
58
59
  logic: [
59
60
  {
60
61
  name: 'disabled',
@@ -1,5 +1,5 @@
1
1
  import Multivalue from '../multivalue/Multivalue';
2
- import { convertStringToHTMLElement } from '../../../utils/index';
2
+ import { announceScreenReaderMessage, convertStringToHTMLElement } from '../../../utils/index';
3
3
  import Widgets from '../../../widgets/index';
4
4
  import _ from 'lodash';
5
5
  export default class Input extends Multivalue {
@@ -29,7 +29,7 @@ export default class Input extends Multivalue {
29
29
  if (this.component.inputMode) {
30
30
  attr.inputmode = this.component.inputMode;
31
31
  }
32
- if (this.component.placeholder) {
32
+ if (this.component.placeholder && !this.options?.readOnly) {
33
33
  attr.placeholder = this.getFormattedAttribute(this.component.placeholder);
34
34
  }
35
35
  if (this.component.tabindex) {
@@ -161,6 +161,9 @@ export default class Input extends Multivalue {
161
161
  }
162
162
  }
163
163
  updateValueAt(value, flags, index) {
164
+ if (flags.modified) {
165
+ announceScreenReaderMessage(this, value, index);
166
+ }
164
167
  flags = flags || {};
165
168
  if (_.get(this.component, 'showWordCount', false)) {
166
169
  if (this.refs.wordcount && this.refs.wordcount[index]) {
@@ -185,7 +188,7 @@ export default class Input extends Multivalue {
185
188
  updateValue(value, flags, index) {
186
189
  flags = flags || {};
187
190
  const changed = super.updateValue(value, flags);
188
- this.triggerUpdateValueAt(this.dataValue, flags, index);
191
+ this.triggerUpdateValueAt(this.dataValue, { ...flags }, index);
189
192
  return changed;
190
193
  }
191
194
  parseValue(value) {
@@ -196,6 +199,7 @@ export default class Input extends Multivalue {
196
199
  }
197
200
  attach(element) {
198
201
  this.loadRefs(element, {
202
+ announceMessage: 'multiple',
199
203
  charcount: 'multiple',
200
204
  wordcount: 'multiple',
201
205
  prefix: 'multiple',
@@ -239,6 +243,15 @@ export default class Input extends Multivalue {
239
243
  }
240
244
  });
241
245
  }
246
+ this.on('focus', (comp) => {
247
+ announceScreenReaderMessage(comp, comp.dataValue, 0, true);
248
+ });
249
+ this.on('blur', (comp) => {
250
+ const el = comp.refs?.["announceMessage"]?.[0];
251
+ if (el) {
252
+ el.textContent = "";
253
+ }
254
+ });
242
255
  return promise;
243
256
  }
244
257
  /**
@@ -829,6 +829,11 @@ export default class NestedComponent extends Field {
829
829
  else if (value && component.hasValue(value)) {
830
830
  return component.setValue(_.get(value, component.key), flags);
831
831
  }
832
+ // if no value is provided and noDefault flag, set empty value
833
+ else if (flags.noDefault && component.allowData) {
834
+ flags.resetValue = true;
835
+ return component.setValue(component.emptyValue, flags);
836
+ }
832
837
  else if ((!this.rootPristine || component.visible) &&
833
838
  (flags.resetValue || component.shouldAddDefaultValue)) {
834
839
  flags.noValidate = !flags.dirty;
@@ -317,7 +317,7 @@ export default class AddressComponent extends ContainerComponent {
317
317
  lang: this.options.language,
318
318
  tabindex: this.component.tabindex || 0,
319
319
  };
320
- if (this.component.placeholder) {
320
+ if (this.component.placeholder && !this.options?.readOnly) {
321
321
  ((attr.placeholder = this.t(this.component.placeholder)), { _userInput: true });
322
322
  }
323
323
  if (this.disabled) {
@@ -416,6 +416,20 @@ export default class AddressComponent extends ContainerComponent {
416
416
  [AddressComponent.removeValueIconRef]: 'multiple',
417
417
  [AddressComponent.searchInputRef]: 'multiple',
418
418
  });
419
+ // We define a container for rendering autocomplete.
420
+ // If isInShadowDOM=true then we render it in shadow dom otherwise in the document body.
421
+ const isInShadowDOM = typeof ShadowRoot !== 'undefined' && this.element?.getRootNode() instanceof ShadowRoot;
422
+ let container;
423
+ if (isInShadowDOM) {
424
+ const shadowRoot = this.element.getRootNode();
425
+ container = document.createElement('div');
426
+ const target = shadowRoot.querySelector('.formio-form-wrapper');
427
+ target.appendChild(container);
428
+ }
429
+ else {
430
+ container = document.createElement('div');
431
+ document.body.appendChild(container);
432
+ }
419
433
  this.searchInput.forEach((element, index) => {
420
434
  if (!this.builderMode && element && this.provider) {
421
435
  if (this.component.provider === 'google') {
@@ -424,6 +438,7 @@ export default class AddressComponent extends ContainerComponent {
424
438
  else {
425
439
  autocompleter({
426
440
  input: element,
441
+ container,
427
442
  debounceWaitMs: 300,
428
443
  fetch: (text, update) => {
429
444
  const query = text;
@@ -108,6 +108,16 @@ export default class DataGridComponent extends NestedArrayComponent {
108
108
  for (let dIndex = defaultValue.length; dIndex < this.minLength; dIndex++) {
109
109
  defaultValue.push({});
110
110
  }
111
+ if (this.component.customDefaultValue) {
112
+ return defaultValue;
113
+ }
114
+ if (defaultValue.length === 1 && this.columns) {
115
+ eachComponent(this.components, (comp, path) => {
116
+ if (comp.component?.input && comp.defaultValue) {
117
+ _.set(defaultValue[0], path, comp.defaultValue);
118
+ }
119
+ });
120
+ }
111
121
  return defaultValue;
112
122
  }
113
123
  set disabled(disabled) {
@@ -433,7 +443,7 @@ export default class DataGridComponent extends NestedArrayComponent {
433
443
  });
434
444
  screenReaderSpeech('Row has been added');
435
445
  this.checkConditions();
436
- this.triggerChange?.({ modified: true });
446
+ this.triggerChange?.({ modified: true, noPristineChangeOnModified: true });
437
447
  this.redraw().then(() => {
438
448
  this.focusOnNewRowElement(this.rows[index]);
439
449
  });
@@ -529,7 +539,7 @@ export default class DataGridComponent extends NestedArrayComponent {
529
539
  changed.instance.root.triggerChange?.(flags, changed, modified);
530
540
  }
531
541
  else {
532
- this.triggerChange?.({ modified });
542
+ this.triggerRootChange(flags, changed, modified);
533
543
  }
534
544
  };
535
545
  let columnComponent;
@@ -15,6 +15,10 @@ export default class DataMapComponent extends DataGridComponent {
15
15
  disableBuilderActions: boolean;
16
16
  };
17
17
  get valueKey(): any;
18
+ get iteratableRows(): {
19
+ components: any;
20
+ data: any;
21
+ }[][];
18
22
  hasHeader(): boolean;
19
23
  getRowKey(rowIndex: any): string;
20
24
  get defaultRowKey(): string;
@@ -118,14 +118,15 @@ export default class DataMapComponent extends DataGridComponent {
118
118
  }
119
119
  get iteratableRows() {
120
120
  return this.rows.map((row) => {
121
- return {
122
- components: row,
123
- data: _.mapValues(row, (comp) => comp.dataValue)
124
- };
121
+ return Object.keys(row).map((key) => ({
122
+ components: row[key],
123
+ data: row[key].dataValue,
124
+ }));
125
125
  });
126
126
  }
127
127
  componentContext(component) {
128
- return this.iteratableRows[component.row].data[component.key];
128
+ return this.iteratableRows[component.row].find((comp) => comp.components.key === component.key)
129
+ .data;
129
130
  }
130
131
  hasHeader() {
131
132
  return true;
@@ -10,6 +10,7 @@ export default class FieldsetComponent extends NestedComponent {
10
10
  };
11
11
  static savedValueTypes(): never[];
12
12
  constructor(...args: any[]);
13
+ attach(element: any): Promise<void>;
13
14
  noField: boolean;
14
15
  }
15
16
  import NestedComponent from '../_classes/nested/NestedComponent';
@@ -7,6 +7,7 @@ export default class FieldsetComponent extends NestedComponent {
7
7
  type: 'fieldset',
8
8
  legend: '',
9
9
  components: [],
10
+ clearOnHide: false,
10
11
  input: false,
11
12
  persistent: false,
12
13
  }, ...extend);
@@ -34,6 +35,13 @@ export default class FieldsetComponent extends NestedComponent {
34
35
  get templateName() {
35
36
  return 'fieldset';
36
37
  }
38
+ attach(element) {
39
+ return super.attach(element).then(() => {
40
+ if (this.component.legend && this.refs.header) {
41
+ this.refs.header.setAttribute('id', `l-${this.id}-legend`);
42
+ }
43
+ });
44
+ }
37
45
  constructor(...args) {
38
46
  super(...args);
39
47
  this.noField = true;
@@ -30,6 +30,8 @@ export default class FileComponent extends Field {
30
30
  } | undefined;
31
31
  isSyncing: boolean | undefined;
32
32
  abortUploads: any[] | undefined;
33
+ pendingfiles: any;
34
+ resolvedFiles: any[] | undefined;
33
35
  get dataReady(): Promise<any>;
34
36
  loadImage(fileInfo: any): any;
35
37
  get emptyValue(): never[];
@@ -147,7 +149,7 @@ export default class FileComponent extends Field {
147
149
  getMultipartOptions(fileToSync: any): any;
148
150
  uploadFile(fileToSync: any): Promise<any>;
149
151
  upload(): Promise<void | {
150
- fileToSync: never;
152
+ fileToSync: any;
151
153
  fileInfo: any;
152
154
  }[]>;
153
155
  syncFiles(): Promise<void>;