@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
@@ -20,9 +20,7 @@
20
20
 
21
21
  /*! @license DOMPurify 3.2.4 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.4/LICENSE */
22
22
 
23
- /*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */
24
-
25
- /*! formiojs v5.3.0 | https://unpkg.com/formiojs@5.3.0/LICENSE.txt */
23
+ /*! formiojs v5.4.0-api98.1 | https://unpkg.com/formiojs@5.4.0-api98.1/LICENSE.txt */
26
24
 
27
25
  /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
28
26
 
package/lib/cjs/Embed.js CHANGED
@@ -154,6 +154,34 @@ class Formio {
154
154
  if (successMessage && successMessage.toLowerCase() !== 'false' && instance.element) {
155
155
  instance.element.innerHTML = `<div class="alert-success" role="alert">${successMessage}</div>`;
156
156
  }
157
+ const announcementMessage = successMessage && successMessage.toLowerCase() !== 'false'
158
+ ? successMessage
159
+ : 'Form submission complete';
160
+ let liveRegion = document.getElementById('formio-announcements');
161
+ if (!liveRegion) {
162
+ liveRegion = _a.createElement('div', {
163
+ id: 'formio-announcements',
164
+ 'role': 'status',
165
+ 'aria-live': 'polite',
166
+ 'aria-atomic': 'true',
167
+ style: 'position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0);'
168
+ });
169
+ document.body.appendChild(liveRegion);
170
+ }
171
+ // Announce the submission completion using VPAT clear-and-reset technique
172
+ liveRegion.textContent = '';
173
+ liveRegion.setAttribute('aria-live', 'off');
174
+ requestAnimationFrame(() => {
175
+ setTimeout(() => {
176
+ liveRegion.setAttribute('aria-live', 'polite');
177
+ liveRegion.textContent = announcementMessage;
178
+ setTimeout(() => {
179
+ if (liveRegion) {
180
+ liveRegion.textContent = '';
181
+ }
182
+ }, 1000);
183
+ }, 100);
184
+ });
157
185
  let returnUrl = _a.config.redirect;
158
186
  // Allow form based configuration for return url.
159
187
  if (!returnUrl &&
@@ -338,6 +366,12 @@ class Formio {
338
366
  mode: 'open',
339
367
  });
340
368
  options.shadowRoot = wrapper;
369
+ // Due to an issue with quill not loading styles in the shadowdom, we need to add quill styles and js to the shadowdom
370
+ const quill = {
371
+ js: `${_a.cdn.quill}/quill.min.js`,
372
+ css: `${_a.cdn.quill}/quill.snow.css`
373
+ };
374
+ yield _a.addLibrary(wrapper, quill, 'quill');
341
375
  }
342
376
  element.parentNode.removeChild(element);
343
377
  wrapper.appendChild(element);
@@ -453,7 +487,7 @@ Formio.formioReady = new Promise((ready, reject) => {
453
487
  _a._formioReady = ready;
454
488
  _a._formioReadyReject = reject;
455
489
  });
456
- Formio.version = '5.3.0';
490
+ Formio.version = '5.4.0-api98.1';
457
491
  // Create a report.
458
492
  Formio.Report = {
459
493
  create: (element, submission, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
package/lib/cjs/Form.d.ts CHANGED
@@ -45,7 +45,7 @@
45
45
  * @property {number} [saveDraftThrottle] - The throttle for the save draft feature.
46
46
  * @property {boolean} [readOnly] - Set this form to readOnly.
47
47
  * @property {boolean} [noAlerts] - Disable the alerts dialog.
48
- * @property {{[key: string]: string}} [i18n] - The translation file for this rendering.
48
+ * @property {{[key: string]: string} | { translationsUrl: string }} [i18n] - The translation file for this rendering.
49
49
  * @property {string} [template] - Custom logic for creation of elements.
50
50
  * @property {boolean} [noDefaults] - Exclude default values from the settings.
51
51
  * @property {any} [fileService] - The file service for this form.
@@ -202,6 +202,8 @@ export type FormOptions = {
202
202
  */
203
203
  i18n?: {
204
204
  [key: string]: string;
205
+ } | {
206
+ translationsUrl: string;
205
207
  } | undefined;
206
208
  /**
207
209
  * - Custom logic for creation of elements.
package/lib/cjs/Form.js CHANGED
@@ -56,7 +56,7 @@ const utils_1 = __importDefault(require("./utils"));
56
56
  * @property {number} [saveDraftThrottle] - The throttle for the save draft feature.
57
57
  * @property {boolean} [readOnly] - Set this form to readOnly.
58
58
  * @property {boolean} [noAlerts] - Disable the alerts dialog.
59
- * @property {{[key: string]: string}} [i18n] - The translation file for this rendering.
59
+ * @property {{[key: string]: string} | { translationsUrl: string }} [i18n] - The translation file for this rendering.
60
60
  * @property {string} [template] - Custom logic for creation of elements.
61
61
  * @property {boolean} [noDefaults] - Exclude default values from the settings.
62
62
  * @property {any} [fileService] - The file service for this form.
@@ -360,7 +360,7 @@ class Form extends Element_1.default {
360
360
  return Promise.resolve(this.instance);
361
361
  }
362
362
  this.form.display = display;
363
- this.instance.destroy();
363
+ this.instance.destroy(true);
364
364
  this.instance = this.create(display);
365
365
  return this.setForm(this.form).then(() => {
366
366
  this.instance.emit('setDisplay', this.form.display);
@@ -73,11 +73,11 @@ export default class FormBuilder extends Form {
73
73
  /**
74
74
  * Creates a new form builder.
75
75
  * @param {HTMLElement} element - The HTML element to place the form builder.
76
- * @param {string | object} form - The form to pass to the builder
76
+ * @param {string | object | undefined} form - The form to pass to the builder
77
77
  * @param {FormBuilderOptions} options - The options to create this builder.
78
78
  * @returns {FormBuilder} - The form builder instance.
79
79
  */
80
- constructor(element: HTMLElement, form: string | object, options: {
80
+ constructor(element: HTMLElement, form: string | object | undefined, options: {
81
81
  /**
82
82
  * - An array of "keys" of components that should be disabled within the form builder. Example: ['firstName', 'lastName']
83
83
  */
@@ -10,7 +10,7 @@ class FormBuilder extends Form_1.default {
10
10
  /**
11
11
  * Creates a new form builder.
12
12
  * @param {HTMLElement} element - The HTML element to place the form builder.
13
- * @param {string | object} form - The form to pass to the builder
13
+ * @param {string | object | undefined} form - The form to pass to the builder
14
14
  * @param {FormBuilderOptions} options - The options to create this builder.
15
15
  * @returns {FormBuilder} - The form builder instance.
16
16
  */
package/lib/cjs/Formio.js CHANGED
@@ -11,7 +11,7 @@ const CDN_1 = __importDefault(require("./CDN"));
11
11
  const providers_1 = __importDefault(require("./providers"));
12
12
  sdk_1.Formio.cdn = new CDN_1.default();
13
13
  sdk_1.Formio.Providers = providers_1.default;
14
- sdk_1.Formio.version = '5.3.0';
14
+ sdk_1.Formio.version = '5.4.0-api98.1';
15
15
  CDN_1.default.defaultCDN = sdk_1.Formio.version.includes('rc')
16
16
  ? 'https://cdn.test-form.io'
17
17
  : 'https://cdn.form.io';
package/lib/cjs/PDF.js CHANGED
@@ -17,9 +17,11 @@ class PDF extends Webform_1.default {
17
17
  // Handle an iframe submission.
18
18
  this.on('iframe-submission', (submission) => this.setValue(submission, {
19
19
  fromIframe: true,
20
+ noDefault: true
20
21
  }), true);
21
22
  this.on('iframe-change', (submission) => this.setValue(submission, {
22
23
  fromIframe: true,
24
+ noDefault: true
23
25
  }), true);
24
26
  this.on('iframe-getIframePositions', (query) => {
25
27
  const iframe = document.getElementById(`iframe-${query.formId}`);
@@ -286,7 +288,15 @@ if (typeof window !== 'undefined') {
286
288
  eventData.name &&
287
289
  eventData.formId &&
288
290
  Formio_1.Formio.forms.hasOwnProperty(eventData.formId)) {
289
- Formio_1.Formio.forms[eventData.formId].emit(`iframe-${eventData.name}`, eventData.data);
291
+ if (eventData.compPath) {
292
+ const comp = Formio_1.Formio.forms[eventData.formId].getComponent(eventData.compPath);
293
+ if (comp) {
294
+ comp.emit(eventData.name, eventData.data);
295
+ }
296
+ }
297
+ else {
298
+ Formio_1.Formio.forms[eventData.formId].emit(`iframe-${eventData.name}`, eventData.data);
299
+ }
290
300
  }
291
301
  });
292
302
  }
@@ -259,6 +259,7 @@ declare class Webform extends NestedDataComponent {
259
259
  * @returns {Promise} - The promise that is triggered when the submission is set.
260
260
  */
261
261
  setSubmission(submission: any, flags?: any): Promise<any>;
262
+ _submission: any;
262
263
  handleDraftError(errName: any, errDetails: any, restoreDraft: any): void;
263
264
  saveDraft(): void;
264
265
  /**
@@ -269,7 +270,6 @@ declare class Webform extends NestedDataComponent {
269
270
  get schema(): any;
270
271
  mergeData(_this: any, _that: any): void;
271
272
  editing: boolean | undefined;
272
- _submission: any;
273
273
  /**
274
274
  * Build the form.
275
275
  * @returns {Promise} - The promise that is triggered when the form is built.
@@ -372,6 +372,7 @@ declare class Webform extends NestedDataComponent {
372
372
  submit(before?: boolean, options?: any): Promise<any>;
373
373
  submitUrl(URL: any, headers: any): void;
374
374
  triggerCaptcha(components?: null): void;
375
+ loadTranslations(): Promise<any>;
375
376
  _nosubmit: any;
376
377
  get conditions(): any;
377
378
  get variables(): any;
@@ -259,7 +259,7 @@ class Webform extends NestedDataComponent_1.default {
259
259
  if (err) {
260
260
  return;
261
261
  }
262
- this.rebuild();
262
+ this.redraw();
263
263
  this.emit('languageChanged');
264
264
  });
265
265
  }
@@ -575,7 +575,9 @@ class Webform extends NestedDataComponent_1.default {
575
575
  }
576
576
  this.initialized = false;
577
577
  const rebuild = this.rebuild() || Promise.resolve();
578
- return rebuild.then(() => {
578
+ return this.loadTranslations()
579
+ .then(() => rebuild)
580
+ .then(() => {
579
581
  this.emit('formLoad', form);
580
582
  if (!this.options.server) {
581
583
  this.triggerCaptcha();
@@ -657,6 +659,8 @@ class Webform extends NestedDataComponent_1.default {
657
659
  if (resolveFlags) {
658
660
  flags = Object.assign(Object.assign({}, flags), resolveFlags);
659
661
  }
662
+ this._submission = {};
663
+ this._data = {};
660
664
  this.onSetSubmission(submission, flags);
661
665
  return this.submissionReadyResolve(submission);
662
666
  }, (err) => this.submissionReadyReject(err))
@@ -1122,6 +1126,7 @@ class Webform extends NestedDataComponent_1.default {
1122
1126
  this.setPristine(true);
1123
1127
  // We want to return the submitted submission and setValue will mutate the submission so cloneDeep it here.
1124
1128
  this.setValue((0, utils_1.fastCloneDeep)(submission), {
1129
+ noDefault: true,
1125
1130
  noValidate: true,
1126
1131
  noCheck: true,
1127
1132
  });
@@ -1130,6 +1135,32 @@ class Webform extends NestedDataComponent_1.default {
1130
1135
  if (this.draftEnabled && ((_a = this.triggerSaveDraft) === null || _a === void 0 ? void 0 : _a.cancel)) {
1131
1136
  this.triggerSaveDraft.cancel();
1132
1137
  }
1138
+ if (typeof document !== 'undefined' && document.body) {
1139
+ const announcementMessage = this.t ? this.t('complete') : 'Form submission complete';
1140
+ // Get or create ARIA live region for announcements
1141
+ let liveRegion = document.getElementById('formio-announcements');
1142
+ if (!liveRegion) {
1143
+ liveRegion = document.createElement('div');
1144
+ liveRegion.id = 'formio-announcements';
1145
+ liveRegion.setAttribute('role', 'status');
1146
+ liveRegion.setAttribute('aria-live', 'polite');
1147
+ liveRegion.setAttribute('aria-atomic', 'true');
1148
+ liveRegion.style.cssText = 'position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0);';
1149
+ document.body.appendChild(liveRegion);
1150
+ }
1151
+ // Announce the submission completion using VPAT clear-and-reset technique
1152
+ liveRegion.textContent = '';
1153
+ liveRegion.setAttribute('aria-live', 'off');
1154
+ requestAnimationFrame(() => {
1155
+ setTimeout(() => {
1156
+ liveRegion.setAttribute('aria-live', 'polite');
1157
+ liveRegion.textContent = announcementMessage;
1158
+ setTimeout(() => {
1159
+ liveRegion.textContent = '';
1160
+ }, 1000);
1161
+ }, 100);
1162
+ });
1163
+ }
1133
1164
  this.emit('submit', submission, saved);
1134
1165
  if (saved) {
1135
1166
  this.emit('submitDone', submission);
@@ -1497,6 +1528,50 @@ class Webform extends NestedDataComponent_1.default {
1497
1528
  captchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`);
1498
1529
  }
1499
1530
  }
1531
+ loadTranslations() {
1532
+ var _a;
1533
+ // We only need a resolve since if translations cannot load, we still want to proceed and render the for
1534
+ let translationsLoadResolve;
1535
+ const promise = new Promise((resolve) => {
1536
+ translationsLoadResolve = resolve;
1537
+ });
1538
+ const translationsUrl = typeof ((_a = this.options.i18n) === null || _a === void 0 ? void 0 : _a.translationsUrl) === 'string'
1539
+ ? this.options.i18n.translationsUrl
1540
+ : null;
1541
+ if (translationsUrl) {
1542
+ const url = this.sanitize(this.interpolate(translationsUrl, {}), this.shouldSanitizeValue);
1543
+ Formio_1.Formio.makeStaticRequest(url, 'GET')
1544
+ .then((response) => {
1545
+ let languages = response;
1546
+ try {
1547
+ if (typeof languages == 'string') {
1548
+ languages = JSON.parse(languages);
1549
+ }
1550
+ this.i18next.setLanguages(languages);
1551
+ this.i18next.changeLanguage(this.i18next.originalLanguage, (err) => {
1552
+ if (err) {
1553
+ return;
1554
+ }
1555
+ this.emit('languageChanged');
1556
+ });
1557
+ this.redraw();
1558
+ translationsLoadResolve();
1559
+ }
1560
+ catch (err) {
1561
+ console.warn(err.message);
1562
+ translationsLoadResolve();
1563
+ }
1564
+ })
1565
+ .catch((err) => {
1566
+ console.warn(err);
1567
+ translationsLoadResolve();
1568
+ });
1569
+ }
1570
+ else {
1571
+ translationsLoadResolve();
1572
+ }
1573
+ return promise;
1574
+ }
1500
1575
  set nosubmit(value) {
1501
1576
  this._nosubmit = !!value;
1502
1577
  this.emit('nosubmit', this._nosubmit);
@@ -949,7 +949,22 @@ class WebformBuilder extends Component_1.default {
949
949
  rebuild = Promise.resolve();
950
950
  }
951
951
  return rebuild.then(() => {
952
+ // Get the updated `toIndex` after the component has been inserted/rebuilt
953
+ const toIndex = lodash_1.default.findIndex(target.formioContainer, { key: info.key });
952
954
  this.emit('addComponent', info, parent, path, index, isNew && !this.options.noNewEdit && !info.noNewEdit);
955
+ // If this is not a new component — it means it was moved
956
+ if (!isNew) {
957
+ const payload = {
958
+ component: info,
959
+ parent,
960
+ path,
961
+ fromIndex: index,
962
+ toIndex,
963
+ timestamp: new Date()
964
+ };
965
+ // New event that allows explicit tracking of reordering
966
+ this.emit('moveComponent', payload);
967
+ }
953
968
  if (!isNew || this.options.noNewEdit || info.noNewEdit) {
954
969
  this.emit('change', this.form);
955
970
  }
@@ -90,6 +90,7 @@ declare class Wizard extends Webform {
90
90
  nextPage(): Promise<void>;
91
91
  validateCurrentPage(flags?: {}): any;
92
92
  emitPrevPage(): void;
93
+ announceCurrentPage(): void;
93
94
  prevPage(): Promise<void>;
94
95
  cancel(noconfirm: any): Promise<void> | Promise<number>;
95
96
  getPageIndexByKey(key: any): number;
package/lib/cjs/Wizard.js CHANGED
@@ -711,6 +711,7 @@ class Wizard extends Webform_1.default {
711
711
  }
712
712
  emitNextPage() {
713
713
  this.emit('nextPage', { page: this.page, submission: this.submission });
714
+ this.announceCurrentPage();
714
715
  }
715
716
  nextPage() {
716
717
  // Read-only forms should not worry about validation before going to next page, nor should they submit.
@@ -756,6 +757,16 @@ class Wizard extends Webform_1.default {
756
757
  }
757
758
  emitPrevPage() {
758
759
  this.emit('prevPage', { page: this.page, submission: this.submission });
760
+ this.announceCurrentPage();
761
+ }
762
+ announceCurrentPage() {
763
+ if (lodash_1.default.get(this.form, 'settings.wizardHeaderType', '') === 'StepIndicator') {
764
+ (0, utils_1.screenReaderSpeech)(`Now on step ${this.page + 1} of ${this.pages.length}: ${lodash_1.default.get(this.currentPage, 'component.title')}`);
765
+ const currentLink = lodash_1.default.get(this.refs, `${this.wizardKey}-link.[${this.page}]`);
766
+ if (currentLink) {
767
+ currentLink.focus();
768
+ }
769
+ }
759
770
  }
760
771
  prevPage() {
761
772
  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.
@@ -446,6 +446,16 @@ class Component extends Element_1.default {
446
446
  }
447
447
  return false;
448
448
  }
449
+ hasCondionallyHiddenLayoutParent() {
450
+ let currentParent = this.parent;
451
+ while (currentParent) {
452
+ if (currentParent._conditionallyHidden && utils_1.default.isLayoutComponent(currentParent) && currentParent.component.clearOnHide === true) {
453
+ return true;
454
+ }
455
+ currentParent = currentParent.parent;
456
+ }
457
+ return false;
458
+ }
449
459
  parentConditionallyHidden() {
450
460
  let currentParent = this.parent;
451
461
  while (currentParent) {
@@ -507,6 +517,18 @@ class Component extends Element_1.default {
507
517
  }
508
518
  return label;
509
519
  }
520
+ getFieldsetLegendIds() {
521
+ var _a, _b;
522
+ const legendIds = [];
523
+ let currentParent = this.parent;
524
+ while (currentParent) {
525
+ if (((_a = currentParent.component) === null || _a === void 0 ? void 0 : _a.type) === 'fieldset' && ((_b = currentParent.component) === null || _b === void 0 ? void 0 : _b.legend)) {
526
+ legendIds.push(`l-${currentParent.id}-legend`);
527
+ }
528
+ currentParent = currentParent.parent;
529
+ }
530
+ return legendIds.reverse().join(' ');
531
+ }
510
532
  init() {
511
533
  var _a;
512
534
  this.disabled = this.shouldDisabled;
@@ -710,7 +732,7 @@ class Component extends Element_1.default {
710
732
  this._conditionallyClear = true;
711
733
  return this._conditionallyClear;
712
734
  }
713
- this._conditionallyClear = this.hasSetValue ? false : this.parentShouldConditionallyClear();
735
+ this._conditionallyClear = this.hasSetValue ? this.hasCondionallyHiddenLayoutParent() : this.parentShouldConditionallyClear();
714
736
  return this._conditionallyClear;
715
737
  }
716
738
  /**
@@ -965,8 +987,20 @@ class Component extends Element_1.default {
965
987
  return this.options.renderMode === 'html';
966
988
  }
967
989
  renderTemplate(name, data = {}, modeOption = '') {
968
- // Need to make this fall back to form if renderMode is not found similar to how we search templates.
990
+ // Allow more specific template names
991
+ const names = [
992
+ `${name}-${this.component.type}-${this.key}`,
993
+ `${name}-${this.component.type}`,
994
+ `${name}-${this.key}`,
995
+ `${name}`,
996
+ ];
997
+ // Allow template alters.
969
998
  const mode = modeOption || this.options.renderMode || 'form';
999
+ const { referenceAttributeName, template } = this.getTemplate(names, mode);
1000
+ if (referenceAttributeName) {
1001
+ this._referenceAttributeName = referenceAttributeName;
1002
+ }
1003
+ // Need to make this fall back to form if renderMode is not found similar to how we search templates.
970
1004
  data.component = this.component;
971
1005
  data.self = this;
972
1006
  data.options = this.options;
@@ -988,18 +1022,7 @@ class Component extends Element_1.default {
988
1022
  };
989
1023
  data.label = data.labelInfo || this.labelInfo;
990
1024
  data.tooltip = this.getFormattedTooltip(this.component.tooltip);
991
- // Allow more specific template names
992
- const names = [
993
- `${name}-${this.component.type}-${this.key}`,
994
- `${name}-${this.component.type}`,
995
- `${name}-${this.key}`,
996
- `${name}`,
997
- ];
998
- // Allow template alters.
999
- const { referenceAttributeName, template } = this.getTemplate(names, mode);
1000
- if (referenceAttributeName) {
1001
- this._referenceAttributeName = referenceAttributeName;
1002
- }
1025
+ data.customStyles = this.getCustomStyles(names);
1003
1026
  return this.hook(`render${name.charAt(0).toUpperCase() + name.substring(1, name.length)}`, this.interpolate(template, data), data, mode);
1004
1027
  }
1005
1028
  /**
@@ -1633,6 +1656,7 @@ class Component extends Element_1.default {
1633
1656
  * @returns {HTMLElement} - The created modal element.
1634
1657
  */
1635
1658
  createModal(element, attr, confirm) {
1659
+ var _a;
1636
1660
  const dialog = this.ce('div', attr || {});
1637
1661
  this.setContent(dialog, this.renderTemplate('dialog'));
1638
1662
  // Add refs to dialog, not "this".
@@ -1642,14 +1666,27 @@ class Component extends Element_1.default {
1642
1666
  dialogContents: 'single',
1643
1667
  dialogClose: 'single',
1644
1668
  });
1669
+ // Check if an element is inside shadow dom
1670
+ const isInShadowDOM = typeof ShadowRoot !== 'undefined' && ((_a = this.element) === null || _a === void 0 ? void 0 : _a.getRootNode()) instanceof ShadowRoot;
1671
+ // if we render shadow dom inside <iframe>'s we need to get the body from the current iframe,
1672
+ // not the general body. This is necessary to hide and show the scroll bar correctly.
1673
+ const body = isInShadowDOM ? this.element.getRootNode().host.ownerDocument.body : document.body;
1674
+ const rootEl = isInShadowDOM ? this.element.closest('.formio-form-wrapper') : document.body;
1675
+ const checkModal = (method) => {
1676
+ if (isInShadowDOM) {
1677
+ body.style.overflow = method === 'add' ? 'hidden' : '';
1678
+ return;
1679
+ }
1680
+ body.classList[method]('modal-open');
1681
+ };
1645
1682
  dialog.refs.dialogContents.appendChild(element);
1646
- document.body.appendChild(dialog);
1647
- document.body.classList.add('modal-open');
1683
+ rootEl.appendChild(dialog);
1684
+ checkModal('add');
1648
1685
  dialog.close = () => {
1649
- document.body.classList.remove('modal-open');
1686
+ checkModal('remove');
1650
1687
  dialog.dispatchEvent(new CustomEvent('close'));
1651
1688
  };
1652
- this.addEventListener(dialog, 'close', () => this.removeChildFrom(dialog, document.body));
1689
+ this.addEventListener(dialog, 'close', () => this.removeChildFrom(dialog, rootEl));
1653
1690
  const close = (event) => {
1654
1691
  event.preventDefault();
1655
1692
  dialog.close();
@@ -1720,6 +1757,21 @@ class Component extends Element_1.default {
1720
1757
  });
1721
1758
  return customCSS;
1722
1759
  }
1760
+ /**
1761
+ * Build custom styles from the styles form option or global config.
1762
+ * @param {string[]} templateNames - The possible template names.
1763
+ * @returns {{ [refName: string]: string[] }} - The custom styles object for the named template.
1764
+ * @todo - Rename this to a better method name that doesn't clash
1765
+ */
1766
+ getCustomStyles(templateNames) {
1767
+ var _a;
1768
+ for (const name of templateNames) {
1769
+ if ((_a = this.options.styles) === null || _a === void 0 ? void 0 : _a[name]) {
1770
+ return this.options.styles[name];
1771
+ }
1772
+ }
1773
+ return {};
1774
+ }
1723
1775
  /**
1724
1776
  * Returns the component condition operator settings if available.
1725
1777
  * @returns {object} - The component condition operator settings.
@@ -2502,6 +2554,20 @@ class Component extends Element_1.default {
2502
2554
  return Promise.resolve(editor);
2503
2555
  }
2504
2556
  else {
2557
+ // 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
2558
+ let current = element;
2559
+ while (current) {
2560
+ if (current instanceof ShadowRoot) {
2561
+ const ckeStyles = document.querySelector('style[data-cke="true"]');
2562
+ const clone = document.createElement('style');
2563
+ clone.setAttribute('data-cke', 'true');
2564
+ clone.textContent = ckeStyles.textContent;
2565
+ current.prepend(clone);
2566
+ break;
2567
+ }
2568
+ ;
2569
+ current = current.parentNode || current.host;
2570
+ }
2505
2571
  return ClassicEditor.create(element, settings).then((editor) => {
2506
2572
  editor.model.document.on('change', () => onChange(editor.data.get()));
2507
2573
  return editor;
@@ -2556,7 +2622,7 @@ class Component extends Element_1.default {
2556
2622
  }
2557
2623
  get shouldSanitizeValue() {
2558
2624
  var _a;
2559
- // Sanitize value if sanitizing for thw whole content is turned off
2625
+ // Sanitize value if sanitizing for the whole content is turned off
2560
2626
  return ((_a = this.options) === null || _a === void 0 ? void 0 : _a.sanitize) !== false;
2561
2627
  }
2562
2628
  addAce(element, settings, onChange) {
@@ -2574,6 +2640,7 @@ class Component extends Element_1.default {
2574
2640
  editor.setOptions(settings);
2575
2641
  editor.getSession().setMode(settings.mode);
2576
2642
  editor.on('change', () => onChange(editor.getValue()));
2643
+ editor.renderer.attachToShadowRoot();
2577
2644
  if (settings.isUseWorkerDisabled) {
2578
2645
  editor.session.setUseWorker(false);
2579
2646
  }
@@ -2634,7 +2701,6 @@ class Component extends Element_1.default {
2634
2701
  return;
2635
2702
  }
2636
2703
  lodash_1.default.set(this._data, this.key, value);
2637
- return;
2638
2704
  }
2639
2705
  /**
2640
2706
  * Splice a value from the dataValue.
@@ -2682,9 +2748,9 @@ class Component extends Element_1.default {
2682
2748
  this.component.defaultValue !== undefined));
2683
2749
  }
2684
2750
  /**
2685
- * Determine if we should add a default value for this component.
2686
- * @returns {boolean} - TRUE if a default value should be set
2687
- */
2751
+ * Determine if we should add a default value for this component.
2752
+ * @returns {boolean} - TRUE if a default value should be set
2753
+ */
2688
2754
  get shouldAddDefaultValue() {
2689
2755
  return this.pristine && this.allowData && (this.hasDefaultValue || !this.options.noDefaults);
2690
2756
  }
@@ -3677,13 +3743,14 @@ class Component extends Element_1.default {
3677
3743
  * @returns {*} - The components "input" DOM element information.
3678
3744
  */
3679
3745
  elementInfo() {
3746
+ var _a;
3680
3747
  const attributes = {
3681
3748
  name: this.options.name,
3682
3749
  type: this.component.inputType || 'text',
3683
3750
  class: 'form-control',
3684
3751
  lang: this.options.language,
3685
3752
  };
3686
- if (this.component.placeholder) {
3753
+ if (this.component.placeholder && !((_a = this.options) === null || _a === void 0 ? void 0 : _a.readOnly)) {
3687
3754
  attributes.placeholder = this.t(this.component.placeholder, { _userInput: true });
3688
3755
  }
3689
3756
  if (this.component.tabindex) {