@formio/js 5.3.6 → 5.4.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 (132) hide show
  1. package/dist/formio.builder.css +31 -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 +31 -5
  9. package/dist/formio.form.js +2837 -2818
  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 -1
  13. package/dist/formio.full.css +31 -5
  14. package/dist/formio.full.js +3442 -3403
  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 -1
  18. package/dist/formio.js +1152 -1154
  19. package/dist/formio.min.js +1 -1
  20. package/dist/formio.min.js.LICENSE.txt +1 -1
  21. package/dist/formio.utils.js +1084 -1086
  22. package/dist/formio.utils.min.js +1 -1
  23. package/dist/formio.utils.min.js.LICENSE.txt +1 -1
  24. package/lib/cjs/Embed.js +28 -1
  25. package/lib/cjs/Form.d.ts +4 -2
  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 +2 -0
  31. package/lib/cjs/PDFBuilder.js +6 -1
  32. package/lib/cjs/Webform.d.ts +1 -0
  33. package/lib/cjs/Webform.js +50 -1
  34. package/lib/cjs/WebformBuilder.js +29 -1
  35. package/lib/cjs/Wizard.d.ts +1 -0
  36. package/lib/cjs/Wizard.js +11 -0
  37. package/lib/cjs/components/Components.d.ts +3 -0
  38. package/lib/cjs/components/_classes/component/Component.d.ts +13 -3
  39. package/lib/cjs/components/_classes/component/Component.js +167 -47
  40. package/lib/cjs/components/_classes/component/editForm/Component.edit.conditional.js +1 -1
  41. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.d.ts +7 -0
  42. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +2 -1
  43. package/lib/cjs/components/_classes/component/editForm/utils.d.ts +1 -0
  44. package/lib/cjs/components/_classes/component/editForm/utils.js +3 -0
  45. package/lib/cjs/components/_classes/nested/NestedComponent.js +5 -0
  46. package/lib/cjs/components/address/Address.js +18 -0
  47. package/lib/cjs/components/datagrid/DataGrid.js +12 -2
  48. package/lib/cjs/components/datamap/DataMap.d.ts +1 -0
  49. package/lib/cjs/components/datamap/DataMap.js +37 -4
  50. package/lib/cjs/components/datetime/DateTime.js +11 -1
  51. package/lib/cjs/components/day/Day.d.ts +0 -15
  52. package/lib/cjs/components/day/Day.js +8 -17
  53. package/lib/cjs/components/editgrid/EditGrid.js +11 -1
  54. package/lib/cjs/components/fieldset/Fieldset.js +1 -0
  55. package/lib/cjs/components/file/File.d.ts +3 -1
  56. package/lib/cjs/components/file/File.js +62 -17
  57. package/lib/cjs/components/form/Form.js +3 -1
  58. package/lib/cjs/components/number/Number.d.ts +1 -0
  59. package/lib/cjs/components/number/Number.js +18 -0
  60. package/lib/cjs/components/select/Select.js +5 -1
  61. package/lib/cjs/components/signature/Signature.js +5 -5
  62. package/lib/cjs/components/signature/editForm/Signature.edit.display.d.ts +0 -6
  63. package/lib/cjs/components/signature/editForm/Signature.edit.display.js +0 -1
  64. package/lib/cjs/components/table/editForm/Table.edit.display.d.ts +27 -0
  65. package/lib/cjs/components/table/editForm/Table.edit.display.js +10 -0
  66. package/lib/cjs/formio.form.js +2 -5
  67. package/lib/cjs/package.json +1 -1
  68. package/lib/cjs/providers/storage/azure.js +9 -3
  69. package/lib/cjs/templates/index.d.ts +3 -0
  70. package/lib/cjs/translations/en.d.ts +2 -0
  71. package/lib/cjs/translations/en.js +2 -0
  72. package/lib/cjs/utils/i18n.d.ts +1 -0
  73. package/lib/cjs/utils/i18n.js +2 -0
  74. package/lib/cjs/utils/index.d.ts +1 -1
  75. package/lib/cjs/utils/utils.d.ts +1 -1
  76. package/lib/cjs/utils/utils.js +23 -6
  77. package/lib/cjs/widgets/CalendarWidget.js +1 -1
  78. package/lib/mjs/Embed.js +26 -1
  79. package/lib/mjs/Form.d.ts +4 -2
  80. package/lib/mjs/Form.js +2 -2
  81. package/lib/mjs/FormBuilder.d.ts +2 -2
  82. package/lib/mjs/FormBuilder.js +1 -1
  83. package/lib/mjs/Formio.js +1 -1
  84. package/lib/mjs/PDF.js +2 -0
  85. package/lib/mjs/PDFBuilder.js +6 -1
  86. package/lib/mjs/Webform.d.ts +1 -0
  87. package/lib/mjs/Webform.js +48 -1
  88. package/lib/mjs/WebformBuilder.js +28 -1
  89. package/lib/mjs/Wizard.d.ts +1 -0
  90. package/lib/mjs/Wizard.js +12 -1
  91. package/lib/mjs/components/Components.d.ts +3 -0
  92. package/lib/mjs/components/_classes/component/Component.d.ts +13 -3
  93. package/lib/mjs/components/_classes/component/Component.js +164 -46
  94. package/lib/mjs/components/_classes/component/editForm/Component.edit.conditional.js +1 -1
  95. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.d.ts +7 -0
  96. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +2 -1
  97. package/lib/mjs/components/_classes/component/editForm/utils.d.ts +1 -0
  98. package/lib/mjs/components/_classes/component/editForm/utils.js +3 -0
  99. package/lib/mjs/components/_classes/nested/NestedComponent.js +5 -0
  100. package/lib/mjs/components/address/Address.js +17 -0
  101. package/lib/mjs/components/datagrid/DataGrid.js +14 -1
  102. package/lib/mjs/components/datamap/DataMap.d.ts +1 -0
  103. package/lib/mjs/components/datamap/DataMap.js +36 -4
  104. package/lib/mjs/components/datetime/DateTime.js +11 -1
  105. package/lib/mjs/components/day/Day.d.ts +0 -15
  106. package/lib/mjs/components/day/Day.js +8 -17
  107. package/lib/mjs/components/editgrid/EditGrid.js +11 -1
  108. package/lib/mjs/components/fieldset/Fieldset.js +1 -0
  109. package/lib/mjs/components/file/File.d.ts +3 -1
  110. package/lib/mjs/components/file/File.js +60 -15
  111. package/lib/mjs/components/form/Form.js +3 -1
  112. package/lib/mjs/components/number/Number.d.ts +1 -0
  113. package/lib/mjs/components/number/Number.js +17 -0
  114. package/lib/mjs/components/select/Select.js +5 -1
  115. package/lib/mjs/components/signature/Signature.js +1 -1
  116. package/lib/mjs/components/signature/editForm/Signature.edit.display.d.ts +0 -6
  117. package/lib/mjs/components/signature/editForm/Signature.edit.display.js +0 -1
  118. package/lib/mjs/components/table/editForm/Table.edit.display.d.ts +27 -0
  119. package/lib/mjs/components/table/editForm/Table.edit.display.js +10 -0
  120. package/lib/mjs/formio.form.js +4 -7
  121. package/lib/mjs/package.json +1 -1
  122. package/lib/mjs/providers/storage/azure.js +9 -3
  123. package/lib/mjs/templates/index.d.ts +3 -0
  124. package/lib/mjs/translations/en.d.ts +2 -0
  125. package/lib/mjs/translations/en.js +2 -0
  126. package/lib/mjs/utils/i18n.d.ts +1 -0
  127. package/lib/mjs/utils/i18n.js +2 -0
  128. package/lib/mjs/utils/index.d.ts +1 -1
  129. package/lib/mjs/utils/utils.d.ts +1 -1
  130. package/lib/mjs/utils/utils.js +22 -6
  131. package/lib/mjs/widgets/CalendarWidget.js +2 -2
  132. package/package.json +8 -6
@@ -206,6 +206,7 @@ function checkSimpleConditional(component, condition, row, data, instance) {
206
206
  return true;
207
207
  }
208
208
  const conditionsResult = lodash_1.default.map(conditions, (cond) => {
209
+ var _a;
209
210
  const { value: comparedValue, operator, component: conditionComponentPath } = cond;
210
211
  if (!conditionComponentPath) {
211
212
  return true;
@@ -232,6 +233,16 @@ function checkSimpleConditional(component, condition, row, data, instance) {
232
233
  }
233
234
  else {
234
235
  const value = getComponentActualValue(conditionComponentPath, data, row);
236
+ // When inside a DataGrid/EditGrid, construct a row-indexed path so that
237
+ // operators like isEmpty can look up the correct row's component instance.
238
+ let operatorPath = conditionComponentPath;
239
+ const dataParent = getDataParentComponent(instance);
240
+ if (dataParent && !lodash_1.default.isNil(instance === null || instance === void 0 ? void 0 : instance.rowIndex)) {
241
+ const parentPath = (_a = dataParent.paths) === null || _a === void 0 ? void 0 : _a.localPath;
242
+ if (parentPath && conditionComponentPath.startsWith(`${parentPath}.`)) {
243
+ operatorPath = conditionComponentPath.replace(`${parentPath}.`, `${parentPath}[${instance.rowIndex}].`);
244
+ }
245
+ }
235
246
  const СonditionOperator = conditionOperators_1.default[operator];
236
247
  return СonditionOperator
237
248
  ? new СonditionOperator().getResult({
@@ -239,7 +250,7 @@ function checkSimpleConditional(component, condition, row, data, instance) {
239
250
  comparedValue,
240
251
  instance,
241
252
  component,
242
- path: conditionComponentPath,
253
+ path: operatorPath,
243
254
  })
244
255
  : true;
245
256
  }
@@ -292,7 +303,11 @@ exports.getComponentActualValue = getComponentActualValue;
292
303
  */
293
304
  function checkCustomConditional(component, custom, row, data, form, variable, onError, instance) {
294
305
  if (typeof custom === 'string') {
295
- custom = `var ${variable} = true; ${custom}; return ${variable};`;
306
+ custom = `
307
+ var ${variable} = true;
308
+ ${custom};
309
+ return ${variable};
310
+ `;
296
311
  }
297
312
  const value = instance && instance.evaluate
298
313
  ? instance.evaluate(custom, { row, data, form })
@@ -640,14 +655,16 @@ exports.shouldLoadZones = shouldLoadZones;
640
655
  * @param {string} timezone - The timezone to load.
641
656
  * @returns {Promise<any> | *} - Resolves when the zones for this timezone are loaded.
642
657
  */
643
- function loadZones(url, timezone) {
644
- if (timezone && !shouldLoadZones(timezone)) {
645
- // Return non-resolving promise.
646
- return new Promise(lodash_1.default.noop);
658
+ function loadZones(url, _timezone) {
659
+ if (moment_timezone_1.default.zonesLoaded) {
660
+ return Promise.resolve();
647
661
  }
648
662
  if (moment_timezone_1.default.zonesPromise) {
649
663
  return moment_timezone_1.default.zonesPromise;
650
664
  }
665
+ // Always load the full packed dataset once. The previous optimization skipped fetch when the
666
+ // display timezone matched the runtime zone, but moment-timezone still needs `tz.load()` for
667
+ // `.tz(ianaName)` and `z` formatting to work; otherwise conversions silently match server local time.
651
668
  return (moment_timezone_1.default.zonesPromise = fetch(url).then((resp) => resp.json().then((zones) => {
652
669
  moment_timezone_1.default.tz.load(zones);
653
670
  moment_timezone_1.default.zonesLoaded = true;
@@ -61,7 +61,7 @@ class CalendarWidget extends InputWidget_1.default {
61
61
  if (this.zoneLoading) {
62
62
  return true;
63
63
  }
64
- if (!(0, utils_1.zonesLoaded)() && (0, utils_1.shouldLoadZones)(timezone)) {
64
+ if (!(0, utils_1.zonesLoaded)()) {
65
65
  this.zoneLoading = true;
66
66
  (0, utils_1.loadZones)(this.timezonesUrl, timezone).then(() => {
67
67
  this.zoneLoading = false;
package/lib/mjs/Embed.js CHANGED
@@ -14,7 +14,7 @@ export class Formio {
14
14
  Formio._formioReady = ready;
15
15
  Formio._formioReadyReject = reject;
16
16
  });
17
- static version = '5.3.6';
17
+ static version = '5.4.0';
18
18
  static setLicense(license, norecurse = false) {
19
19
  Formio.license = license;
20
20
  if (!norecurse && Formio.FormioClass) {
@@ -340,6 +340,24 @@ export class Formio {
340
340
  };
341
341
  });
342
342
  const id = Formio.config.id || `formio-${Math.random().toString(36).substring(7)}`;
343
+ const hasQuillComponent = (components = []) => {
344
+ if (!Array.isArray(components)) {
345
+ return false;
346
+ }
347
+ return components.some((component) => {
348
+ if (!component || typeof component !== 'object') {
349
+ return false;
350
+ }
351
+ const isQuillTextarea = component.type === 'textarea' &&
352
+ component.wysiwyg === true &&
353
+ component.editor === 'quill';
354
+ return (isQuillTextarea ||
355
+ hasQuillComponent(component.components) ||
356
+ hasQuillComponent(component.columns?.flatMap((column) => column.components || [])) ||
357
+ hasQuillComponent(component.rows?.flatMap((row) => row.flatMap((cell) => cell.components || []))));
358
+ });
359
+ };
360
+ const disableShadowForQuill = hasQuillComponent(Formio.config.form?.components);
343
361
  // Create a new wrapper and add the element inside of a new wrapper.
344
362
  let wrapper = Formio.createElement('div', {
345
363
  id: `${id}-wrapper`,
@@ -348,12 +366,19 @@ export class Formio {
348
366
  // If we include the libraries, then we will attempt to run this in shadow dom.
349
367
  const useShadowDom = Formio.config.includeLibs &&
350
368
  !Formio.config.noshadow &&
369
+ !disableShadowForQuill &&
351
370
  typeof wrapper.attachShadow === 'function';
352
371
  if (useShadowDom) {
353
372
  wrapper = wrapper.attachShadow({
354
373
  mode: 'open',
355
374
  });
356
375
  options.shadowRoot = wrapper;
376
+ // Due to an issue with quill not loading styles in the shadowdom, we need to add quill styles and js to the shadowdom
377
+ const quill = {
378
+ js: `${Formio.cdn.quill}/quill.js`,
379
+ css: `${Formio.cdn.quill}/quill.snow.css`
380
+ };
381
+ await Formio.addLibrary(wrapper, quill, 'quill');
357
382
  }
358
383
  element.parentNode.removeChild(element);
359
384
  wrapper.appendChild(element);
package/lib/mjs/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.
@@ -236,7 +238,7 @@ export type FormOptions = {
236
238
  /**
237
239
  * - The render mode for this form.
238
240
  */
239
- renderMode?: "builder" | "form" | "html" | "flat" | "pdf" | undefined;
241
+ renderMode?: "form" | "builder" | "html" | "flat" | "pdf" | undefined;
240
242
  /**
241
243
  * - Highlight any errors on the form.
242
244
  */
package/lib/mjs/Form.js CHANGED
@@ -50,7 +50,7 @@ import FormioUtils from './utils';
50
50
  * @property {number} [saveDraftThrottle] - The throttle for the save draft feature.
51
51
  * @property {boolean} [readOnly] - Set this form to readOnly.
52
52
  * @property {boolean} [noAlerts] - Disable the alerts dialog.
53
- * @property {{[key: string]: string}} [i18n] - The translation file for this rendering.
53
+ * @property {{[key: string]: string} | { translationsUrl: string }} [i18n] - The translation file for this rendering.
54
54
  * @property {string} [template] - Custom logic for creation of elements.
55
55
  * @property {boolean} [noDefaults] - Exclude default values from the settings.
56
56
  * @property {any} [fileService] - The file service for this form.
@@ -354,7 +354,7 @@ export default class Form extends Element {
354
354
  return Promise.resolve(this.instance);
355
355
  }
356
356
  this.form.display = display;
357
- this.instance.destroy();
357
+ this.instance.destroy(true);
358
358
  this.instance = this.create(display);
359
359
  return this.setForm(this.form).then(() => {
360
360
  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
  */
@@ -25,7 +25,7 @@ export default class FormBuilder extends Form {
25
25
  /**
26
26
  * Creates a new form builder.
27
27
  * @param {HTMLElement} element - The HTML element to place the form builder.
28
- * @param {string | object} form - The form to pass to the builder
28
+ * @param {string | object | undefined} form - The form to pass to the builder
29
29
  * @param {FormBuilderOptions} options - The options to create this builder.
30
30
  * @returns {FormBuilder} - The form builder instance.
31
31
  */
package/lib/mjs/Formio.js CHANGED
@@ -4,7 +4,7 @@ import CDN from './CDN';
4
4
  import Providers from './providers';
5
5
  FormioCore.cdn = new CDN();
6
6
  FormioCore.Providers = Providers;
7
- FormioCore.version = '5.3.6';
7
+ FormioCore.version = '5.4.0';
8
8
  CDN.defaultCDN = FormioCore.version.includes('rc')
9
9
  ? 'https://cdn.test-form.io'
10
10
  : 'https://cdn.form.io';
package/lib/mjs/PDF.js CHANGED
@@ -12,9 +12,11 @@ export default class PDF extends Webform {
12
12
  // Handle an iframe submission.
13
13
  this.on('iframe-submission', (submission) => this.setValue(submission, {
14
14
  fromIframe: true,
15
+ noDefault: true
15
16
  }), true);
16
17
  this.on('iframe-change', (submission) => this.setValue(submission, {
17
18
  fromIframe: true,
19
+ noDefault: true
18
20
  }), true);
19
21
  this.on('iframe-getIframePositions', (query) => {
20
22
  const iframe = document.getElementById(`iframe-${query.formId}`);
@@ -227,7 +227,12 @@ export default class PDFBuilder extends WebformBuilder {
227
227
  nonFillableConversionUsed: autoConversionComponentsAssigned && result.data.formfields.nonFillableConversionUsed,
228
228
  });
229
229
  this.emit('pdfUploaded', result.data);
230
- this.redraw();
230
+ if (autoConversionComponentsAssigned) {
231
+ this.rebuild();
232
+ }
233
+ else {
234
+ this.redraw();
235
+ }
231
236
  })
232
237
  .catch((err) => this.setUploadError(err));
233
238
  }
@@ -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;
@@ -569,7 +569,9 @@ export default class Webform extends NestedDataComponent {
569
569
  }
570
570
  this.initialized = false;
571
571
  const rebuild = this.rebuild() || Promise.resolve();
572
- return rebuild.then(() => {
572
+ return this.loadTranslations()
573
+ .then(() => rebuild)
574
+ .then(() => {
573
575
  this.emit('formLoad', form);
574
576
  if (!this.options.server) {
575
577
  this.triggerCaptcha();
@@ -1115,6 +1117,7 @@ export default class Webform extends NestedDataComponent {
1115
1117
  this.setPristine(true);
1116
1118
  // We want to return the submitted submission and setValue will mutate the submission so cloneDeep it here.
1117
1119
  this.setValue(fastCloneDeep(submission), {
1120
+ noDefault: true,
1118
1121
  noValidate: true,
1119
1122
  noCheck: true,
1120
1123
  });
@@ -1288,6 +1291,7 @@ export default class Webform extends NestedDataComponent {
1288
1291
  userAgent: navigator.userAgent,
1289
1292
  pathName: window.location.pathname,
1290
1293
  onLine: navigator.onLine,
1294
+ language: this.i18next?.originalLanguage || this.options.language || this.i18next?.language,
1291
1295
  });
1292
1296
  }
1293
1297
  submitForm(options = {}, local = false) {
@@ -1517,6 +1521,49 @@ export default class Webform extends NestedDataComponent {
1517
1521
  captchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`);
1518
1522
  }
1519
1523
  }
1524
+ loadTranslations() {
1525
+ // We only need a resolve since if translations cannot load, we still want to proceed and render the for
1526
+ let translationsLoadResolve;
1527
+ const promise = new Promise((resolve) => {
1528
+ translationsLoadResolve = resolve;
1529
+ });
1530
+ const translationsUrl = typeof this.options.i18n?.translationsUrl === 'string'
1531
+ ? this.options.i18n.translationsUrl
1532
+ : null;
1533
+ if (translationsUrl) {
1534
+ const url = this.sanitize(this.interpolate(translationsUrl, {}), this.shouldSanitizeValue);
1535
+ Formio.makeStaticRequest(url, 'GET')
1536
+ .then((response) => {
1537
+ let languages = response;
1538
+ try {
1539
+ if (typeof languages == 'string') {
1540
+ languages = JSON.parse(languages);
1541
+ }
1542
+ this.i18next.setLanguages(languages);
1543
+ this.i18next.changeLanguage(this.i18next.originalLanguage, (err) => {
1544
+ if (err) {
1545
+ return;
1546
+ }
1547
+ this.emit('languageChanged');
1548
+ });
1549
+ this.redraw();
1550
+ translationsLoadResolve();
1551
+ }
1552
+ catch (err) {
1553
+ console.warn(err.message);
1554
+ translationsLoadResolve();
1555
+ }
1556
+ })
1557
+ .catch((err) => {
1558
+ console.warn(err);
1559
+ translationsLoadResolve();
1560
+ });
1561
+ }
1562
+ else {
1563
+ translationsLoadResolve();
1564
+ }
1565
+ return promise;
1566
+ }
1520
1567
  set nosubmit(value) {
1521
1568
  this._nosubmit = !!value;
1522
1569
  this.emit('nosubmit', this._nosubmit);
@@ -364,11 +364,14 @@ export default class WebformBuilder extends Component {
364
364
  this.attachTooltip(component.refs.editComponent, this.t('Edit'));
365
365
  component.addEventListener(component.refs.editComponent, 'click', () => this.editComponent(component.schema, parent, false, false, component.component, {
366
366
  inDataGrid: component.isInDataGrid,
367
+ editComponentPath: component.path,
367
368
  }));
368
369
  }
369
370
  if (component.refs.editJson) {
370
371
  this.attachTooltip(component.refs.editJson, this.t('Edit JSON'));
371
- component.addEventListener(component.refs.editJson, 'click', () => this.editComponent(component.schema, parent, false, true, component.component));
372
+ component.addEventListener(component.refs.editJson, 'click', () => this.editComponent(component.schema, parent, false, true, component.component, {
373
+ editComponentPath: component.path,
374
+ }));
372
375
  }
373
376
  if (component.refs.removeComponent) {
374
377
  this.attachTooltip(component.refs.removeComponent, this.t('Remove'));
@@ -932,7 +935,22 @@ export default class WebformBuilder extends Component {
932
935
  rebuild = Promise.resolve();
933
936
  }
934
937
  return rebuild.then(() => {
938
+ // Get the updated `toIndex` after the component has been inserted/rebuilt
939
+ const toIndex = _.findIndex(target.formioContainer, { key: info.key });
935
940
  this.emit('addComponent', info, parent, path, index, isNew && !this.options.noNewEdit && !info.noNewEdit);
941
+ // If this is not a new component — it means it was moved
942
+ if (!isNew) {
943
+ const payload = {
944
+ component: info,
945
+ parent,
946
+ path,
947
+ fromIndex: index,
948
+ toIndex,
949
+ timestamp: new Date()
950
+ };
951
+ // New event that allows explicit tracking of reordering
952
+ this.emit('moveComponent', payload);
953
+ }
936
954
  if (!isNew || this.options.noNewEdit || info.noNewEdit) {
937
955
  this.emit('change', this.form);
938
956
  }
@@ -1066,6 +1084,14 @@ export default class WebformBuilder extends Component {
1066
1084
  _.get(this.webform, 'form.globalSettings.sanitizeConfig');
1067
1085
  // Update the preview.
1068
1086
  if (this.preview) {
1087
+ if (changed?.instance?.key === 'allowMultipleMasks' && changed?.value === false) {
1088
+ const changedComp = this.preview?.getComponent(component.key);
1089
+ if (changedComp) {
1090
+ const emptyValue = changedComp.emptyValue;
1091
+ changedComp.dataValue = emptyValue;
1092
+ component.defaultValue = emptyValue;
1093
+ }
1094
+ }
1069
1095
  this.preview.form = {
1070
1096
  components: [
1071
1097
  _.omit({ ...component }, [
@@ -1381,6 +1407,7 @@ export default class WebformBuilder extends Component {
1381
1407
  // Pass along the form being edited.
1382
1408
  editFormOptions.editForm = this.form;
1383
1409
  editFormOptions.editComponent = component;
1410
+ editFormOptions.editComponentPath = flags.editComponentPath;
1384
1411
  editFormOptions.flags = flags;
1385
1412
  this.hook('editComponentParentInstance', editFormOptions, parent);
1386
1413
  this.editForm = new Webform({
@@ -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/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(() => {
@@ -2,6 +2,7 @@ export default class Components {
2
2
  static _editFormUtils: {
3
3
  sortAndFilterComponents(components: any): any;
4
4
  unifyComponents(objValue: any, srcValue: any): any;
5
+ tokenVariableDescription(): string;
5
6
  logicVariablesTable(additional: any): {
6
7
  type: string;
7
8
  tag: string;
@@ -86,6 +87,7 @@ export default class Components {
86
87
  static set EditFormUtils(value: {
87
88
  sortAndFilterComponents(components: any): any;
88
89
  unifyComponents(objValue: any, srcValue: any): any;
90
+ tokenVariableDescription(): string;
89
91
  logicVariablesTable(additional: any): {
90
92
  type: string;
91
93
  tag: string;
@@ -169,6 +171,7 @@ export default class Components {
169
171
  static get EditFormUtils(): {
170
172
  sortAndFilterComponents(components: any): any;
171
173
  unifyComponents(objValue: any, srcValue: any): any;
174
+ tokenVariableDescription(): string;
172
175
  logicVariablesTable(additional: any): {
173
176
  type: string;
174
177
  tag: string;
@@ -177,6 +177,7 @@ declare class Component extends Element {
177
177
  * @returns {boolean} - If the parent should conditionally clear.
178
178
  */
179
179
  parentShouldConditionallyClear(): boolean;
180
+ hasCondionallyHiddenLayoutParent(): boolean;
180
181
  parentConditionallyHidden(): boolean;
181
182
  /**
182
183
  * Returns true if any of the parents default their component "hidden" property to true.
@@ -593,6 +594,15 @@ declare class Component extends Element {
593
594
  * @returns {string} - The custom style
594
595
  */
595
596
  get customStyle(): string;
597
+ /**
598
+ * Build custom styles from the styles form option or global config.
599
+ * @param {string[]} templateNames - The possible template names.
600
+ * @returns {{ [refName: string]: string[] }} - The custom styles object for the named template.
601
+ * @todo - Rename this to a better method name that doesn't clash
602
+ */
603
+ getCustomStyles(templateNames: string[]): {
604
+ [refName: string]: string[];
605
+ };
596
606
  /**
597
607
  * Returns if the application is on a mobile device.
598
608
  * @returns {boolean} - TRUE if the application is on a mobile device.
@@ -927,9 +937,9 @@ declare class Component extends Element {
927
937
  */
928
938
  get hasDefaultValue(): boolean;
929
939
  /**
930
- * Determine if we should add a default value for this component.
931
- * @returns {boolean} - TRUE if a default value should be set
932
- */
940
+ * Determine if we should add a default value for this component.
941
+ * @returns {boolean} - TRUE if a default value should be set
942
+ */
933
943
  get shouldAddDefaultValue(): boolean;
934
944
  /**
935
945
  * Get the default value of this component.