@formio/js 5.4.0-api98.1 → 5.4.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 (132) hide show
  1. package/dist/formio.builder.css +26 -5
  2. package/dist/formio.builder.min.css +1 -1
  3. package/dist/formio.embed.js +1 -1
  4. package/dist/formio.embed.min.js +1 -1
  5. package/dist/formio.embed.min.js.LICENSE.txt +1 -1
  6. package/dist/formio.form.css +26 -5
  7. package/dist/formio.form.js +3462 -3448
  8. package/dist/formio.form.min.css +1 -1
  9. package/dist/formio.form.min.js +1 -1
  10. package/dist/formio.form.min.js.LICENSE.txt +2 -2
  11. package/dist/formio.full.css +26 -5
  12. package/dist/formio.full.js +4277 -4263
  13. package/dist/formio.full.min.css +1 -1
  14. package/dist/formio.full.min.js +1 -1
  15. package/dist/formio.full.min.js.LICENSE.txt +2 -2
  16. package/dist/formio.js +1738 -1724
  17. package/dist/formio.min.js +1 -1
  18. package/dist/formio.min.js.LICENSE.txt +2 -2
  19. package/dist/formio.utils.js +1631 -1617
  20. package/dist/formio.utils.min.js +1 -1
  21. package/dist/formio.utils.min.js.LICENSE.txt +2 -2
  22. package/lib/cjs/Element.d.ts +11 -0
  23. package/lib/cjs/Element.js +24 -0
  24. package/lib/cjs/Embed.js +23 -2
  25. package/lib/cjs/Form.d.ts +1 -1
  26. package/lib/cjs/Formio.js +1 -1
  27. package/lib/cjs/PDFBuilder.js +6 -1
  28. package/lib/cjs/Webform.d.ts +1 -1
  29. package/lib/cjs/Webform.js +9 -6
  30. package/lib/cjs/WebformBuilder.js +14 -1
  31. package/lib/cjs/Wizard.js +15 -11
  32. package/lib/cjs/components/Components.d.ts +3 -0
  33. package/lib/cjs/components/Components.js +3 -1
  34. package/lib/cjs/components/_classes/component/Component.d.ts +13 -0
  35. package/lib/cjs/components/_classes/component/Component.js +137 -44
  36. package/lib/cjs/components/_classes/component/editForm/Component.edit.conditional.js +1 -1
  37. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +1 -1
  38. package/lib/cjs/components/_classes/component/editForm/utils.d.ts +1 -0
  39. package/lib/cjs/components/_classes/component/editForm/utils.js +3 -0
  40. package/lib/cjs/components/_classes/nested/NestedComponent.js +5 -7
  41. package/lib/cjs/components/address/Address.js +2 -0
  42. package/lib/cjs/components/button/Button.d.ts +1 -0
  43. package/lib/cjs/components/button/Button.js +22 -1
  44. package/lib/cjs/components/datagrid/DataGrid.js +35 -10
  45. package/lib/cjs/components/datamap/DataMap.d.ts +1 -4
  46. package/lib/cjs/components/datamap/DataMap.js +42 -10
  47. package/lib/cjs/components/datetime/DateTime.js +11 -1
  48. package/lib/cjs/components/datetime/editForm/DateTime.edit.date.d.ts +18 -1
  49. package/lib/cjs/components/datetime/editForm/DateTime.edit.date.js +3 -0
  50. package/lib/cjs/components/datetime/editForm/DateTime.edit.time.d.ts +13 -2
  51. package/lib/cjs/components/datetime/editForm/DateTime.edit.time.js +3 -0
  52. package/lib/cjs/components/day/Day.d.ts +0 -15
  53. package/lib/cjs/components/day/Day.js +8 -17
  54. package/lib/cjs/components/editgrid/EditGrid.js +13 -3
  55. package/lib/cjs/components/file/File.js +7 -6
  56. package/lib/cjs/components/form/Form.d.ts +1 -0
  57. package/lib/cjs/components/form/Form.js +20 -8
  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 +6 -3
  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/textfield/editForm/TextField.edit.display.d.ts +0 -10
  65. package/lib/cjs/components/textfield/editForm/TextField.edit.display.js +9 -23
  66. package/lib/cjs/formio.form.js +2 -5
  67. package/lib/cjs/package.json +1 -1
  68. package/lib/cjs/providers/address/GoogleAddressProvider.js +1 -1
  69. package/lib/cjs/providers/storage/azure.js +9 -3
  70. package/lib/cjs/translations/en.d.ts +1 -0
  71. package/lib/cjs/translations/en.js +3 -1
  72. package/lib/cjs/utils/formUtils.d.ts +2 -2
  73. package/lib/cjs/utils/index.d.ts +3 -3
  74. package/lib/cjs/utils/utils.d.ts +1 -1
  75. package/lib/cjs/utils/utils.js +28 -11
  76. package/lib/cjs/widgets/CalendarWidget.js +1 -1
  77. package/lib/mjs/Element.d.ts +11 -0
  78. package/lib/mjs/Element.js +23 -0
  79. package/lib/mjs/Embed.js +21 -2
  80. package/lib/mjs/Form.d.ts +1 -1
  81. package/lib/mjs/Formio.js +1 -1
  82. package/lib/mjs/PDFBuilder.js +6 -1
  83. package/lib/mjs/Webform.d.ts +1 -1
  84. package/lib/mjs/Webform.js +6 -3
  85. package/lib/mjs/WebformBuilder.js +13 -1
  86. package/lib/mjs/Wizard.js +9 -10
  87. package/lib/mjs/components/Components.d.ts +3 -0
  88. package/lib/mjs/components/Components.js +3 -1
  89. package/lib/mjs/components/_classes/component/Component.d.ts +13 -0
  90. package/lib/mjs/components/_classes/component/Component.js +135 -43
  91. package/lib/mjs/components/_classes/component/editForm/Component.edit.conditional.js +1 -1
  92. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +1 -1
  93. package/lib/mjs/components/_classes/component/editForm/utils.d.ts +1 -0
  94. package/lib/mjs/components/_classes/component/editForm/utils.js +3 -0
  95. package/lib/mjs/components/_classes/nested/NestedComponent.js +5 -6
  96. package/lib/mjs/components/address/Address.js +2 -0
  97. package/lib/mjs/components/button/Button.d.ts +1 -0
  98. package/lib/mjs/components/button/Button.js +21 -1
  99. package/lib/mjs/components/datagrid/DataGrid.js +39 -11
  100. package/lib/mjs/components/datamap/DataMap.d.ts +1 -4
  101. package/lib/mjs/components/datamap/DataMap.js +41 -10
  102. package/lib/mjs/components/datetime/DateTime.js +11 -1
  103. package/lib/mjs/components/datetime/editForm/DateTime.edit.date.d.ts +18 -1
  104. package/lib/mjs/components/datetime/editForm/DateTime.edit.date.js +3 -0
  105. package/lib/mjs/components/datetime/editForm/DateTime.edit.time.d.ts +13 -2
  106. package/lib/mjs/components/datetime/editForm/DateTime.edit.time.js +3 -0
  107. package/lib/mjs/components/day/Day.d.ts +0 -15
  108. package/lib/mjs/components/day/Day.js +8 -17
  109. package/lib/mjs/components/editgrid/EditGrid.js +12 -2
  110. package/lib/mjs/components/file/File.js +7 -6
  111. package/lib/mjs/components/form/Form.d.ts +1 -0
  112. package/lib/mjs/components/form/Form.js +18 -6
  113. package/lib/mjs/components/number/Number.d.ts +1 -0
  114. package/lib/mjs/components/number/Number.js +17 -0
  115. package/lib/mjs/components/select/Select.js +6 -3
  116. package/lib/mjs/components/signature/Signature.js +1 -1
  117. package/lib/mjs/components/signature/editForm/Signature.edit.display.d.ts +0 -6
  118. package/lib/mjs/components/signature/editForm/Signature.edit.display.js +0 -1
  119. package/lib/mjs/components/textfield/editForm/TextField.edit.display.d.ts +0 -10
  120. package/lib/mjs/components/textfield/editForm/TextField.edit.display.js +9 -23
  121. package/lib/mjs/formio.form.js +4 -7
  122. package/lib/mjs/package.json +1 -1
  123. package/lib/mjs/providers/address/GoogleAddressProvider.js +1 -1
  124. package/lib/mjs/providers/storage/azure.js +9 -3
  125. package/lib/mjs/translations/en.d.ts +1 -0
  126. package/lib/mjs/translations/en.js +3 -1
  127. package/lib/mjs/utils/formUtils.d.ts +2 -2
  128. package/lib/mjs/utils/index.d.ts +3 -3
  129. package/lib/mjs/utils/utils.d.ts +1 -1
  130. package/lib/mjs/utils/utils.js +27 -11
  131. package/lib/mjs/widgets/CalendarWidget.js +2 -2
  132. package/package.json +8 -7
@@ -145,7 +145,7 @@ class Component extends Element_1.default {
145
145
  unique: false,
146
146
  },
147
147
  /**
148
- * The simple conditional settings for a component.
148
+ * the simple conditional settings for a component.
149
149
  */
150
150
  conditional: {
151
151
  show: null,
@@ -430,6 +430,24 @@ class Component extends Element_1.default {
430
430
  var _a;
431
431
  return ((_a = this.root) === null || _a === void 0 ? void 0 : _a.childComponentsMap) || {};
432
432
  }
433
+ /**
434
+ * Walks this component's root chain, invoking `fn` with each ancestor root's
435
+ * `childComponentsMap`. Component registration is propagated up the wizard /
436
+ * nested-form chain at create time, so any code that mutates a registration
437
+ * (creation, removal, path-driven re-key) must update every map in the chain.
438
+ * @param {(map: object) => void} fn - Called once per root that exposes a `childComponentsMap`.
439
+ */
440
+ eachRootChildComponentsMap(fn) {
441
+ let currentRoot = this.root;
442
+ let prevRootId = null;
443
+ while (currentRoot && currentRoot.id !== prevRootId) {
444
+ if (currentRoot.childComponentsMap) {
445
+ fn(currentRoot.childComponentsMap);
446
+ }
447
+ prevRootId = currentRoot.id;
448
+ currentRoot = currentRoot.root;
449
+ }
450
+ }
433
451
  /**
434
452
  * Returns if the parent should conditionally clear.
435
453
  *
@@ -1134,9 +1152,12 @@ class Component extends Element_1.default {
1134
1152
  * @returns {string} - The submission timezone.
1135
1153
  */
1136
1154
  get submissionTimezone() {
1137
- this.options.submissionTimezone =
1138
- this.options.submissionTimezone || lodash_1.default.get(this.root, 'options.submissionTimezone');
1139
- return this.options.submissionTimezone;
1155
+ if (!this.options.submissionTimezone) {
1156
+ this.options.submissionTimezone = lodash_1.default.get(this.root, 'options.submissionTimezone');
1157
+ }
1158
+ return (this.options.submissionTimezone ||
1159
+ lodash_1.default.get(this.root, '_submission.metadata.timezone') ||
1160
+ lodash_1.default.get(this.component, 'widget.submissionTimezone'));
1140
1161
  }
1141
1162
  /**
1142
1163
  * Return the current timezone.
@@ -1151,6 +1172,7 @@ class Component extends Element_1.default {
1151
1172
  * @returns {string} - The current timezone.
1152
1173
  */
1153
1174
  getTimezone(settings) {
1175
+ settings = settings || {};
1154
1176
  if (settings.timezone) {
1155
1177
  return settings.timezone;
1156
1178
  }
@@ -1158,12 +1180,19 @@ class Component extends Element_1.default {
1158
1180
  return 'UTC';
1159
1181
  }
1160
1182
  const submissionTimezone = this.submissionTimezone;
1183
+ const mode = settings.displayInTimezone === '' || settings.displayInTimezone == null
1184
+ ? 'viewer'
1185
+ : settings.displayInTimezone;
1186
+ if (this.options.pdf && submissionTimezone) {
1187
+ return submissionTimezone;
1188
+ }
1189
+ const staticSnapshot = this.options.server ||
1190
+ this.options.renderMode === 'html' ||
1191
+ !!this.options.viewAsHtml;
1161
1192
  if (submissionTimezone &&
1162
- (settings.displayInTimezone === 'submission' ||
1163
- ((this.options.pdf || this.options.server) && settings.displayInTimezone === 'viewer'))) {
1193
+ (mode === 'submission' || (staticSnapshot && (mode === 'viewer' || mode === 'location')))) {
1164
1194
  return submissionTimezone;
1165
1195
  }
1166
- // Return current timezone if none are provided.
1167
1196
  return (0, utils_2.currentTimezone)();
1168
1197
  }
1169
1198
  /**
@@ -1190,6 +1219,19 @@ class Component extends Element_1.default {
1190
1219
  }
1191
1220
  }
1192
1221
  }
1222
+ /**
1223
+ * Announces a message to screen readers via the component's live region.
1224
+ * @param {string} message - The message to announce.
1225
+ */
1226
+ announce(message) {
1227
+ const liveRegion = this.refs.liveRegion;
1228
+ if (liveRegion) {
1229
+ liveRegion.textContent = '';
1230
+ setTimeout(() => {
1231
+ liveRegion.textContent = message;
1232
+ }, 50);
1233
+ }
1234
+ }
1193
1235
  /**
1194
1236
  * Opens the modal element.
1195
1237
  * @param {string} template - The template to use for the modal dialog.
@@ -1323,6 +1365,7 @@ class Component extends Element_1.default {
1323
1365
  this.loadRefs(element, {
1324
1366
  messageContainer: 'single',
1325
1367
  tooltip: 'multiple',
1368
+ liveRegion: 'single',
1326
1369
  });
1327
1370
  this.attachTooltips(this.refs.tooltip);
1328
1371
  // Attach logic.
@@ -1567,13 +1610,13 @@ class Component extends Element_1.default {
1567
1610
  value.forEach((val, index) => {
1568
1611
  const widget = this.refs.input[index] && this.refs.input[index].widget;
1569
1612
  if (widget) {
1570
- values.push(widget.getValueAsString(val, options));
1613
+ values.push(widget.getValueAsString(val));
1571
1614
  }
1572
1615
  });
1573
1616
  return values;
1574
1617
  }
1575
1618
  const widget = this.refs.input[0].widget;
1576
- return widget.getValueAsString(value, options);
1619
+ return widget.getValueAsString(value);
1577
1620
  }
1578
1621
  /**
1579
1622
  * Returns the value of the component as a string.
@@ -2312,29 +2355,24 @@ class Component extends Element_1.default {
2312
2355
  * @returns {void}
2313
2356
  */
2314
2357
  setErrorClasses(elements, dirty, hasErrors, hasMessages, element = this.element) {
2315
- this.clearErrorClasses();
2316
- elements.forEach((element) => {
2317
- this.setElementInvalid(this.performInputMapping(element), hasErrors);
2358
+ var _a;
2359
+ elements.forEach((el) => {
2360
+ this.setElementInvalid(this.performInputMapping(el), hasErrors);
2318
2361
  });
2319
2362
  this.setInputWidgetErrorClasses(elements, hasErrors);
2320
2363
  // do not set error classes for hidden components
2321
2364
  if (!this.visible) {
2365
+ this.clearErrorClasses(element);
2322
2366
  return;
2323
2367
  }
2324
- if (hasErrors) {
2325
- // Add error classes
2326
- elements.forEach((input) => {
2327
- this.setElementInvalid(this.performInputMapping(input), true);
2328
- });
2329
- if (dirty && this.options.highlightErrors) {
2330
- this.addClass(element, this.options.componentErrorClass);
2331
- }
2332
- else {
2333
- this.addClass(element, 'has-error');
2334
- }
2335
- }
2336
- if (hasMessages) {
2337
- this.addClass(element, 'has-message');
2368
+ const wantHighlight = hasErrors && !!dirty && !!this.options.highlightErrors;
2369
+ const wantHasError = hasErrors && !wantHighlight;
2370
+ this.toggleClass(element, this.options.componentErrorClass, wantHighlight);
2371
+ this.toggleClass(element, 'has-error', wantHasError);
2372
+ this.toggleClass(element, 'has-message', hasMessages);
2373
+ // Preserve previous clearErrorClasses() behavior: drop the 'alert alert-danger' pair if left over.
2374
+ if ((_a = element === null || element === void 0 ? void 0 : element.classList) === null || _a === void 0 ? void 0 : _a.contains('alert-danger')) {
2375
+ this.removeClass(element, 'alert alert-danger');
2338
2376
  }
2339
2377
  }
2340
2378
  /**
@@ -2584,12 +2622,61 @@ class Component extends Element_1.default {
2584
2622
  { type: 'styles', src: `${Formio_1.Formio.cdn.quill}/quill.${settings.theme}.css` },
2585
2623
  ], true);
2586
2624
  // Lazy load the quill library.
2587
- return Formio_1.Formio.requireLibrary('quill', 'Quill', lodash_1.default.get(this.options, 'editors.quill.src', `${Formio_1.Formio.cdn.quill}/quill.min.js`), true).then(() => {
2625
+ return Formio_1.Formio.requireLibrary('quill', 'Quill', lodash_1.default.get(this.options, 'editors.quill.src', `${Formio_1.Formio.cdn.quill}/quill.js`), true).then(() => {
2588
2626
  return Formio_1.Formio.requireLibrary('quill-table', 'Quill', `${Formio_1.Formio.cdn.baseUrl}/quill/quill-table.js`, true).then(() => {
2589
2627
  if (!element.parentNode) {
2590
2628
  return Promise.reject();
2591
2629
  }
2592
2630
  this.quill = new Quill(element, isIEBrowser ? Object.assign(Object.assign({}, settings), { modules: {} }) : settings);
2631
+ const root = element.getRootNode();
2632
+ if (root instanceof ShadowRoot && root.getSelection) {
2633
+ const sel = this.quill.selection;
2634
+ // 1. getNativeRange: read selection from shadowRoot instead of document
2635
+ sel.getNativeRange = () => {
2636
+ const shadowSelection = root.getSelection();
2637
+ if (shadowSelection == null || shadowSelection.rangeCount <= 0)
2638
+ return null;
2639
+ const nativeRange = shadowSelection.getRangeAt(0);
2640
+ if (nativeRange == null)
2641
+ return null;
2642
+ return sel.normalizeNative(nativeRange);
2643
+ };
2644
+ // 2. hasFocus: check shadowRoot.activeElement instead of document.activeElement
2645
+ sel.hasFocus = () => {
2646
+ return root.activeElement === sel.root ||
2647
+ (root.activeElement != null && sel.root.contains(root.activeElement));
2648
+ };
2649
+ // 3. setNativeRange: use shadowRoot's selection to add/remove ranges
2650
+ const origSetNativeRange = sel.setNativeRange.bind(sel);
2651
+ sel.setNativeRange = (startNode, startOffset, endNode, endOffset, force) => {
2652
+ // Delegate to original logic for the null case (blur)
2653
+ if (startNode == null) {
2654
+ origSetNativeRange(null);
2655
+ return;
2656
+ }
2657
+ if (!sel.hasFocus()) {
2658
+ sel.root.focus({ preventScroll: true });
2659
+ }
2660
+ const shadowSelection = root.getSelection();
2661
+ if (shadowSelection == null)
2662
+ return;
2663
+ const { native } = sel.getNativeRange() || {};
2664
+ endNode = endNode !== null && endNode !== void 0 ? endNode : startNode;
2665
+ endOffset = endOffset !== null && endOffset !== void 0 ? endOffset : startOffset;
2666
+ if (native == null || force ||
2667
+ startNode !== native.startContainer || startOffset !== native.startOffset ||
2668
+ endNode !== native.endContainer || endOffset !== native.endOffset) {
2669
+ const range = document.createRange();
2670
+ range.setStart(startNode, startOffset);
2671
+ range.setEnd(endNode, endOffset);
2672
+ shadowSelection.removeAllRanges();
2673
+ shadowSelection.addRange(range);
2674
+ }
2675
+ };
2676
+ document.addEventListener('selectionchange', () => {
2677
+ sel.update();
2678
+ });
2679
+ }
2593
2680
  /** This block of code adds the [source] capabilities. See https://codepen.io/anon/pen/ZyEjrQ */
2594
2681
  const txtArea = document.createElement('textarea');
2595
2682
  txtArea.setAttribute('class', 'quill-source-code');
@@ -2608,7 +2695,8 @@ class Component extends Element_1.default {
2608
2695
  // Make sure to select cursor when they click on the element.
2609
2696
  this.addEventListener(element, 'click', () => this.quill.focus());
2610
2697
  // Allows users to skip toolbar items when tabbing though form
2611
- const elm = document.querySelectorAll('.ql-formats > button');
2698
+ const queryRoot = element.getRootNode() || document;
2699
+ const elm = queryRoot.querySelectorAll('.ql-formats > button');
2612
2700
  for (let i = 0; i < elm.length; i++) {
2613
2701
  elm[i].setAttribute('tabindex', '-1');
2614
2702
  }
@@ -3243,7 +3331,7 @@ class Component extends Element_1.default {
3243
3331
  if (flags.silentCheck) {
3244
3332
  return [];
3245
3333
  }
3246
- let isDirty = flags.dirty === false ? false : this.dirty || flags.dirty;
3334
+ let isDirty = flags.dirty || this.dirty;
3247
3335
  if (this.options.alwaysDirty) {
3248
3336
  isDirty = true;
3249
3337
  }
@@ -3450,22 +3538,27 @@ class Component extends Element_1.default {
3450
3538
  }
3451
3539
  });
3452
3540
  this.addEventListener(element, 'blur', () => {
3453
- if (this.root) {
3454
- this.root.pendingBlur = utils_1.default.delay(() => {
3455
- var _a, _b;
3456
- this.emit('blur', this);
3457
- if (this.component.validateOn === 'blur') {
3458
- (_b = (_a = this.root).triggerChange) === null || _b === void 0 ? void 0 : _b.call(_a, { fromBlur: true }, {
3459
- instance: this,
3460
- component: this.component,
3461
- value: this.dataValue,
3462
- flags: { fromBlur: true },
3463
- });
3464
- }
3465
- this.root.focusedComponent = null;
3466
- this.root.pendingBlur = null;
3467
- });
3541
+ const root = this.root;
3542
+ if (!root) {
3543
+ return;
3468
3544
  }
3545
+ root.pendingBlur = utils_1.default.delay(() => {
3546
+ var _a;
3547
+ if (!root) {
3548
+ return;
3549
+ }
3550
+ this.emit('blur', this);
3551
+ if (this.component.validateOn === 'blur') {
3552
+ (_a = root.triggerChange) === null || _a === void 0 ? void 0 : _a.call(root, { fromBlur: true }, {
3553
+ instance: this,
3554
+ component: this.component,
3555
+ value: this.dataValue,
3556
+ flags: { fromBlur: true },
3557
+ });
3558
+ }
3559
+ root.focusedComponent = null;
3560
+ root.pendingBlur = null;
3561
+ });
3469
3562
  });
3470
3563
  }
3471
3564
  setCustomValidity(messages, dirty, external) {
@@ -49,5 +49,5 @@ exports.default = [
49
49
  },
50
50
  utils_1.default.javaScriptValue('Advanced Conditions', 'customConditional', 'conditional.json', 110, '<p>You must assign the <strong>show</strong> variable a boolean result.</p>' +
51
51
  '<p><strong>Note: Advanced Conditional logic will override the results of the Simple Conditional logic.</strong></p>' +
52
- '<h5>Example</h5><pre>show = !!data.showMe;</pre>', '<p><a href="https://help.form.io/userguide/form-building/logic-and-conditions" target="_blank" rel="noopener noreferrer">Click here for an example</a></p>'),
52
+ '<h5>Example</h5><pre>show = !!data.showMe;</pre>', '<p><a href="https://help.form.io/userguide/form-building/logic-and-conditions" target="_blank" rel="noopener noreferrer">Click here for an example</a></p>', utils_1.default.tokenVariableDescription()),
53
53
  ];
@@ -144,7 +144,7 @@ exports.default = [
144
144
  input: true,
145
145
  },
146
146
  utils_1.default.javaScriptValue('Custom Default Value', 'customDefaultValue', 'customDefaultValue', 1000, '<p><h4>Example:</h4><pre>value = data.firstName + " " + data.lastName;</pre></p>', '<p><h4>Example:</h4><pre>{"cat": [{"var": "data.firstName"}, " ", {"var": "data.lastName"}]}</pre>'),
147
- utils_1.default.javaScriptValue('Calculated Value', 'calculateValue', 'calculateValue', 1100, '<p><h4>Example:</h4><pre>value = data.a + data.b + data.c;</pre></p>', '<p><h4>Example:</h4><pre>{"+": [{"var": "data.a"}, {"var": "data.b"}, {"var": "data.c"}]}</pre><p><a href="https://help.form.io/userguide/form-building/logic-and-conditions#calculated-values" target="_blank" rel="noopener noreferrer">Click here for an example</a></p>', '<tr><th>token</th><td>The decoded JWT token for the authenticated user.</td></tr>'),
147
+ utils_1.default.javaScriptValue('Calculated Value', 'calculateValue', 'calculateValue', 1100, '<p><h4>Example:</h4><pre>value = data.a + data.b + data.c;</pre></p>', '<p><h4>Example:</h4><pre>{"+": [{"var": "data.a"}, {"var": "data.b"}, {"var": "data.c"}]}</pre><p><a href="https://help.form.io/userguide/form-building/logic-and-conditions#calculated-values" target="_blank" rel="noopener noreferrer">Click here for an example</a></p>', utils_1.default.tokenVariableDescription()),
148
148
  {
149
149
  type: 'checkbox',
150
150
  input: true,
@@ -2,6 +2,7 @@ export default EditFormUtils;
2
2
  declare namespace EditFormUtils {
3
3
  function sortAndFilterComponents(components: any): any;
4
4
  function unifyComponents(objValue: any, srcValue: any): any;
5
+ function tokenVariableDescription(): string;
5
6
  function logicVariablesTable(additional: any): {
6
7
  type: string;
7
8
  tag: string;
@@ -37,6 +37,9 @@ const EditFormUtils = {
37
37
  }
38
38
  return lodash_1.default.isEqual(objValue, srcValue);
39
39
  },
40
+ tokenVariableDescription() {
41
+ return '<tr><th>token</th><td>The decoded JWT token for the authenticated user.</td></tr>';
42
+ },
40
43
  logicVariablesTable(additional) {
41
44
  additional = additional || '';
42
45
  return {
@@ -557,16 +557,14 @@ class NestedComponent extends Field_1.default {
557
557
  * @param {boolean} [all] - If set to TRUE will cascade remove all components.
558
558
  */
559
559
  removeComponent(component, components, all = false) {
560
- var _a, _b;
561
560
  components = components || this.components;
562
561
  component.destroy(all);
563
562
  lodash_1.default.remove(components, { id: component.id });
564
- if (this.componentsMap[component.path]) {
565
- delete this.componentsMap[component.path];
566
- }
567
- if ((_a = this.root) === null || _a === void 0 ? void 0 : _a.componentsMap[component.path]) {
568
- (_b = this.root) === null || _b === void 0 ? true : delete _b.componentsMap[component.path];
569
- }
563
+ component.eachRootChildComponentsMap((map) => {
564
+ if (map[component.path]) {
565
+ delete map[component.path];
566
+ }
567
+ });
570
568
  }
571
569
  /**
572
570
  * Removes a component provided the API key of that component.
@@ -265,6 +265,8 @@ class AddressComponent extends Container_1.default {
265
265
  this.restoreComponentsContext();
266
266
  }
267
267
  if (changed || (!lodash_1.default.isEmpty(value) && flags.fromSubmission)) {
268
+ // Recheck conditions on child components before redraw so their visibility is updated
269
+ this.getComponents().forEach((comp) => { var _a; return comp.checkConditions((_a = this.root) === null || _a === void 0 ? void 0 : _a.data); });
268
270
  this.redraw();
269
271
  }
270
272
  return changed;
@@ -29,6 +29,7 @@ export default class ButtonComponent extends Field {
29
29
  detach(element: any): void;
30
30
  onClick(event: any): void;
31
31
  openOauth(settings: any): void;
32
+ _handleOauthSessionExpired(): void;
32
33
  get oauthComponentPath(): any;
33
34
  focus(): void;
34
35
  triggerCaptcha(): void;
@@ -371,6 +371,12 @@ class ButtonComponent extends Field_1.default {
371
371
  }
372
372
  openOauth(settings) {
373
373
  var _a;
374
+ // this is if the temp session (storing the state and code verifiers) expires in the db
375
+ // and we need to fetch new oauth state
376
+ if (settings.sessionExpireAt && Date.now() >= settings.sessionExpireAt) {
377
+ this._handleOauthSessionExpired();
378
+ return;
379
+ }
374
380
  if (!((_a = this.root) === null || _a === void 0 ? void 0 : _a.formio)) {
375
381
  console.warn('You must attach a Form API url to your form in order to use OAuth buttons.');
376
382
  return;
@@ -386,7 +392,8 @@ class ButtonComponent extends Field_1.default {
386
392
  if (settings.state) {
387
393
  params.state = settings.state;
388
394
  }
389
- else if (settings.code_challenge) {
395
+ // okta requires both a state and a code challenge for PKCE
396
+ if (settings.code_challenge) {
390
397
  params.code_challenge = settings.code_challenge;
391
398
  params.code_challenge_method = 'S256';
392
399
  }
@@ -429,6 +436,9 @@ class ButtonComponent extends Field_1.default {
429
436
  (_b = this.root) === null || _b === void 0 ? void 0 : _b.setAlert('danger', 'OAuth state does not match. Please try logging in again.');
430
437
  return;
431
438
  }
439
+ if (settings.sessionId) {
440
+ params.sessionId = settings.sessionId;
441
+ }
432
442
  // Depending on where the settings came from, submit to either the submission endpoint (old) or oauth endpoint (new).
433
443
  let requestPromise = Promise.resolve();
434
444
  if (lodash_1.default.has(this, 'root.form.config.oauth') &&
@@ -457,6 +467,11 @@ class ButtonComponent extends Field_1.default {
457
467
  })
458
468
  .catch((err) => {
459
469
  var _a;
470
+ console.log(err);
471
+ if (settings.sessionExpireAt && Date.now() >= settings.sessionExpireAt) {
472
+ this._handleOauthSessionExpired();
473
+ return;
474
+ }
460
475
  (_a = this.root) === null || _a === void 0 ? void 0 : _a.onSubmissionError(err);
461
476
  });
462
477
  }
@@ -472,6 +487,12 @@ class ButtonComponent extends Field_1.default {
472
487
  }
473
488
  }, 100);
474
489
  }
490
+ _handleOauthSessionExpired() {
491
+ var _a;
492
+ (_a = this.root) === null || _a === void 0 ? void 0 : _a.setAlert('warning', this.t('oauthSessionExpired'));
493
+ this.loading = true;
494
+ setTimeout(() => window.location.reload(), 2000);
495
+ }
475
496
  get oauthComponentPath() {
476
497
  const pathArray = (0, utils_1.getArrayFromComponentPath)(this.path);
477
498
  return lodash_1.default.chain(pathArray)
@@ -446,18 +446,26 @@ class DataGridComponent extends NestedArrayComponent_1.default {
446
446
  component: this.component,
447
447
  row,
448
448
  });
449
- (0, utils_1.screenReaderSpeech)('Row has been added');
450
449
  this.checkConditions();
451
450
  (_a = this.triggerChange) === null || _a === void 0 ? void 0 : _a.call(this, { modified: true, noPristineChangeOnModified: true });
452
451
  this.redraw().then(() => {
453
452
  this.focusOnNewRowElement(this.rows[index]);
453
+ this.announce(this.t('Row has been added'));
454
454
  });
455
455
  }
456
456
  updateComponentsRowIndex(components, rowIndex) {
457
457
  components.forEach((component, colIndex) => {
458
458
  var _a;
459
- if (this.componentsMap[component.paths.dataPath]) {
460
- delete this.componentsMap[component.paths.dataPath];
459
+ // The rowIndex setter cascades into descendants and regenerates their
460
+ // paths, but does not re-key them in componentsMap. Collect the slot
461
+ // and every descendant up front so we can re-key them after paths
462
+ // regenerate. Required for nested-form / sub-wizard scenarios where
463
+ // the outer wizard validates against its own componentsMap copy.
464
+ const entries = [{ instance: component, oldPath: component.paths.dataPath }];
465
+ if (typeof component.everyComponent === 'function') {
466
+ component.everyComponent((descendant) => {
467
+ entries.push({ instance: descendant, oldPath: descendant.paths.dataPath });
468
+ });
461
469
  }
462
470
  if ((_a = component.options) === null || _a === void 0 ? void 0 : _a.name) {
463
471
  const newName = `[${this.key}][${rowIndex}]`;
@@ -465,7 +473,14 @@ class DataGridComponent extends NestedArrayComponent_1.default {
465
473
  }
466
474
  component.rowIndex = rowIndex;
467
475
  component.row = `${rowIndex}-${colIndex}`;
468
- this.componentsMap[component.paths.dataPath] = component;
476
+ entries.forEach(({ instance, oldPath }) => {
477
+ instance.eachRootChildComponentsMap((map) => {
478
+ if (map[oldPath] === instance) {
479
+ delete map[oldPath];
480
+ }
481
+ map[instance.paths.dataPath] = instance;
482
+ });
483
+ });
469
484
  });
470
485
  }
471
486
  updateRowsComponents(rowIndex) {
@@ -478,15 +493,14 @@ class DataGridComponent extends NestedArrayComponent_1.default {
478
493
  const flags = { isReordered: !makeEmpty, resetValue: makeEmpty };
479
494
  this.splice(index, flags);
480
495
  this.emit('dataGridDeleteRow', { index });
481
- if (this.rows.length > 1) {
482
- (0, utils_1.screenReaderSpeech)('Row has been deleted');
483
- }
484
496
  const [row,] = this.rows.splice(index, 1);
485
497
  this.removeSubmissionMetadataRow(index);
486
498
  this.removeRowComponents(row);
487
499
  this.updateRowsComponents(index);
488
500
  this.setValue(this.dataValue, flags);
489
- this.redraw();
501
+ this.redraw().then(() => {
502
+ this.announce(this.t('Row has been deleted'));
503
+ });
490
504
  }
491
505
  removeRowComponents(row) {
492
506
  lodash_1.default.each(row, (component) => this.removeComponent(component));
@@ -537,8 +551,9 @@ class DataGridComponent extends NestedArrayComponent_1.default {
537
551
  options.rowIndex = rowIndex;
538
552
  options.onChange = (flags, changed, modified) => {
539
553
  var _a, _b, _c, _d;
540
- if (changed.component.type === 'form') {
541
- const formComp = (0, utils_1.getComponent)(this.component.components, changed.component.key);
554
+ const changedComponent = changed.component;
555
+ if ((changedComponent === null || changedComponent === void 0 ? void 0 : changedComponent.type) === 'form' && (changedComponent === null || changedComponent === void 0 ? void 0 : changedComponent.key)) {
556
+ const formComp = (0, utils_1.getComponent)(this.component.components, changedComponent.key);
542
557
  lodash_1.default.set(formComp, 'components', changed.component.components);
543
558
  }
544
559
  // If we're in a nested form we need to ensure our changes are triggered upstream
@@ -546,8 +561,18 @@ class DataGridComponent extends NestedArrayComponent_1.default {
546
561
  (_d = (_c = changed.instance.root).triggerChange) === null || _d === void 0 ? void 0 : _d.call(_c, flags, changed, modified);
547
562
  }
548
563
  else {
564
+ if (modified && !flags.noPristineChangeOnModified) {
565
+ this.pristine = false;
566
+ }
567
+ this.triggerRootChange(flags, {
568
+ instance: this,
569
+ component: this.component,
570
+ value: this.dataValue,
571
+ flags,
572
+ }, modified);
549
573
  this.triggerRootChange(flags, changed, modified);
550
574
  }
575
+ this.processRow('checkData', null, Object.assign(Object.assign({}, flags), { changed }), row, lodash_1.default.toArray(this.rows[rowIndex]));
551
576
  };
552
577
  let columnComponent;
553
578
  if (this.builderMode) {
@@ -15,14 +15,11 @@ 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
- }[][];
22
18
  hasHeader(): boolean;
23
19
  getRowKey(rowIndex: any): string;
24
20
  get defaultRowKey(): string;
25
21
  getValueAsString(value: any, options: any): any;
22
+ findComponentInstance(key: any): any;
26
23
  createRowComponents(row: any, rowIndex: any): {
27
24
  __key: any;
28
25
  };
@@ -123,15 +123,14 @@ class DataMapComponent extends DataGrid_1.default {
123
123
  }
124
124
  get iteratableRows() {
125
125
  return this.rows.map((row) => {
126
- return Object.keys(row).map((key) => ({
127
- components: row[key],
128
- data: row[key].dataValue,
129
- }));
126
+ return {
127
+ components: row,
128
+ data: lodash_1.default.mapValues(row, (comp) => comp.dataValue)
129
+ };
130
130
  });
131
131
  }
132
132
  componentContext(component) {
133
- return this.iteratableRows[component.row].find((comp) => comp.components.key === component.key)
134
- .data;
133
+ return this.iteratableRows[component.row].data[component.key];
135
134
  }
136
135
  hasHeader() {
137
136
  return true;
@@ -186,10 +185,14 @@ class DataMapComponent extends DataGrid_1.default {
186
185
  <tbody>
187
186
  `;
188
187
  result = Object.keys(value).reduce((result, key) => {
188
+ const componentInstance = this.findComponentInstance(key);
189
+ const viewValue = componentInstance
190
+ ? componentInstance.getView(value[key], options)
191
+ : this.getView(value[key], options);
189
192
  result += `
190
193
  <tr>
191
194
  <th style="padding: 5px 10px;">${key}</th>
192
- <td style="width:100%;padding:5px 10px;">${this.getView(value[key], options)}</td>
195
+ <td style="width:100%;padding:5px 10px;">${viewValue}</td>
193
196
  </tr>
194
197
  `;
195
198
  return result;
@@ -209,6 +212,19 @@ class DataMapComponent extends DataGrid_1.default {
209
212
  }
210
213
  return typeof value === 'object' ? '[Complex Data]' : value;
211
214
  }
215
+ findComponentInstance(key) {
216
+ var _a;
217
+ if (!this.rows || !this.rows.length) {
218
+ return null;
219
+ }
220
+ // Find component instance with matching key
221
+ const foundRow = lodash_1.default.find(this.rows, (row) => { var _a; return ((_a = row === null || row === void 0 ? void 0 : row[this.valueKey]) === null || _a === void 0 ? void 0 : _a.key) === key; });
222
+ if (foundRow === null || foundRow === void 0 ? void 0 : foundRow[this.valueKey]) {
223
+ return foundRow[this.valueKey];
224
+ }
225
+ // If not found by key, return the first row's value component as fallback
226
+ return ((_a = this.rows[0]) === null || _a === void 0 ? void 0 : _a[this.valueKey]) || null;
227
+ }
212
228
  getDataValueAsTable(value, options) {
213
229
  let result = `
214
230
  <table border="1" style="width:100%">
@@ -216,10 +232,14 @@ class DataMapComponent extends DataGrid_1.default {
216
232
  `;
217
233
  if (this.visible && lodash_1.default.isObject(value)) {
218
234
  Object.keys(value).forEach((key) => {
235
+ const componentInstance = this.findComponentInstance(key);
236
+ const viewValue = componentInstance
237
+ ? componentInstance.getView(value[key], options)
238
+ : this.getView(value[key], options);
219
239
  result += `
220
240
  <tr>
221
241
  <th style="padding: 5px 10px;">${key}</th>
222
- <td style="width:100%;padding:5px 10px;">${this.getView(value[key], options)}</td>
242
+ <td style="width:100%;padding:5px 10px;">${viewValue}</td>
223
243
  </tr>
224
244
  `;
225
245
  });
@@ -254,9 +274,21 @@ class DataMapComponent extends DataGrid_1.default {
254
274
  });
255
275
  const valueComponent = lodash_1.default.clone(this.component.valueComponent);
256
276
  valueComponent.key = key;
257
- const componentOptions = this.options;
277
+ const componentOptions = lodash_1.default.clone(this.options);
258
278
  componentOptions.row = options.row;
259
- components[this.valueKey] = this.createComponent(valueComponent, componentOptions, this.dataValue);
279
+ if (this.submissionTimezone) {
280
+ componentOptions.submissionTimezone = this.submissionTimezone;
281
+ if (valueComponent.type === 'datetime') {
282
+ valueComponent.widget = Object.assign(Object.assign({}, valueComponent.widget), { submissionTimezone: this.submissionTimezone });
283
+ }
284
+ }
285
+ const createdComponent = this.createComponent(valueComponent, componentOptions, this.dataValue);
286
+ // Ensure submissionTimezone is set on datetime component instance's widget and options
287
+ if ((createdComponent === null || createdComponent === void 0 ? void 0 : createdComponent.type) === 'datetime' && this.submissionTimezone) {
288
+ createdComponent.component.widget = Object.assign(Object.assign({}, createdComponent.component.widget), { submissionTimezone: this.submissionTimezone });
289
+ createdComponent.options.submissionTimezone = this.submissionTimezone;
290
+ }
291
+ components[this.valueKey] = createdComponent;
260
292
  return components;
261
293
  }
262
294
  get canAddColumn() {