@formio/js 5.0.0 → 5.1.0-rc.2

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 (84) hide show
  1. package/dist/formio.embed.js +1 -1
  2. package/dist/formio.embed.min.js +1 -1
  3. package/dist/formio.embed.min.js.LICENSE.txt +1 -1
  4. package/dist/formio.form.js +127 -116
  5. package/dist/formio.form.min.js +1 -1
  6. package/dist/formio.form.min.js.LICENSE.txt +3 -3
  7. package/dist/formio.full.js +128 -117
  8. package/dist/formio.full.min.js +1 -1
  9. package/dist/formio.full.min.js.LICENSE.txt +3 -3
  10. package/dist/formio.js +3013 -283
  11. package/dist/formio.min.js +1 -1
  12. package/dist/formio.min.js.LICENSE.txt +14 -2
  13. package/dist/formio.utils.js +60 -49
  14. package/dist/formio.utils.min.js +1 -1
  15. package/dist/formio.utils.min.js.LICENSE.txt +3 -3
  16. package/lib/cjs/Webform.d.ts +8 -1
  17. package/lib/cjs/Webform.js +40 -32
  18. package/lib/cjs/WebformBuilder.js +4 -12
  19. package/lib/cjs/Wizard.js +4 -11
  20. package/lib/cjs/components/Components.d.ts +0 -7
  21. package/lib/cjs/components/Components.js +1 -33
  22. package/lib/cjs/components/_classes/component/Component.d.ts +52 -7
  23. package/lib/cjs/components/_classes/component/Component.js +120 -42
  24. package/lib/cjs/components/_classes/component/editForm/Component.edit.data.js +2 -2
  25. package/lib/cjs/components/_classes/componentModal/ComponentModal.d.ts +1 -0
  26. package/lib/cjs/components/_classes/componentModal/ComponentModal.js +1 -0
  27. package/lib/cjs/components/_classes/nested/NestedComponent.d.ts +4 -19
  28. package/lib/cjs/components/_classes/nested/NestedComponent.js +54 -60
  29. package/lib/cjs/components/_classes/nestedarray/NestedArrayComponent.d.ts +2 -1
  30. package/lib/cjs/components/_classes/nestedarray/NestedArrayComponent.js +7 -44
  31. package/lib/cjs/components/datagrid/DataGrid.d.ts +0 -1
  32. package/lib/cjs/components/datagrid/DataGrid.js +1 -45
  33. package/lib/cjs/components/datamap/DataMap.js +2 -3
  34. package/lib/cjs/components/editgrid/EditGrid.js +8 -11
  35. package/lib/cjs/components/form/Form.d.ts +8 -3
  36. package/lib/cjs/components/form/Form.js +31 -29
  37. package/lib/cjs/components/html/HTML.js +15 -3
  38. package/lib/cjs/components/selectboxes/SelectBoxes.js +0 -1
  39. package/lib/cjs/components/signature/Signature.d.ts +0 -1
  40. package/lib/cjs/components/signature/Signature.js +1 -1
  41. package/lib/cjs/utils/conditionOperators/DateGreaterThan.js +2 -2
  42. package/lib/cjs/utils/conditionOperators/IsEmptyValue.d.ts +2 -2
  43. package/lib/cjs/utils/conditionOperators/IsEmptyValue.js +2 -2
  44. package/lib/cjs/utils/conditionOperators/IsEqualTo.d.ts +2 -2
  45. package/lib/cjs/utils/conditionOperators/IsEqualTo.js +2 -2
  46. package/lib/cjs/utils/formUtils.d.ts +25 -14
  47. package/lib/cjs/utils/formUtils.js +11 -16
  48. package/lib/cjs/utils/utils.d.ts +1 -3
  49. package/lib/cjs/utils/utils.js +19 -35
  50. package/lib/mjs/Webform.d.ts +8 -1
  51. package/lib/mjs/Webform.js +37 -31
  52. package/lib/mjs/WebformBuilder.js +4 -12
  53. package/lib/mjs/Wizard.js +2 -8
  54. package/lib/mjs/components/Components.d.ts +0 -7
  55. package/lib/mjs/components/Components.js +1 -32
  56. package/lib/mjs/components/_classes/component/Component.d.ts +52 -7
  57. package/lib/mjs/components/_classes/component/Component.js +130 -43
  58. package/lib/mjs/components/_classes/component/editForm/Component.edit.data.js +2 -2
  59. package/lib/mjs/components/_classes/componentModal/ComponentModal.d.ts +1 -0
  60. package/lib/mjs/components/_classes/componentModal/ComponentModal.js +1 -0
  61. package/lib/mjs/components/_classes/nested/NestedComponent.d.ts +4 -19
  62. package/lib/mjs/components/_classes/nested/NestedComponent.js +55 -61
  63. package/lib/mjs/components/_classes/nestedarray/NestedArrayComponent.d.ts +2 -1
  64. package/lib/mjs/components/_classes/nestedarray/NestedArrayComponent.js +8 -43
  65. package/lib/mjs/components/datagrid/DataGrid.d.ts +0 -1
  66. package/lib/mjs/components/datagrid/DataGrid.js +1 -45
  67. package/lib/mjs/components/datamap/DataMap.js +2 -3
  68. package/lib/mjs/components/editgrid/EditGrid.js +11 -11
  69. package/lib/mjs/components/form/Form.d.ts +8 -3
  70. package/lib/mjs/components/form/Form.js +32 -29
  71. package/lib/mjs/components/html/HTML.js +15 -3
  72. package/lib/mjs/components/selectboxes/SelectBoxes.js +0 -1
  73. package/lib/mjs/components/signature/Signature.d.ts +0 -1
  74. package/lib/mjs/components/signature/Signature.js +1 -1
  75. package/lib/mjs/utils/conditionOperators/DateGreaterThan.js +2 -2
  76. package/lib/mjs/utils/conditionOperators/IsEmptyValue.d.ts +2 -2
  77. package/lib/mjs/utils/conditionOperators/IsEmptyValue.js +2 -2
  78. package/lib/mjs/utils/conditionOperators/IsEqualTo.d.ts +2 -2
  79. package/lib/mjs/utils/conditionOperators/IsEqualTo.js +2 -2
  80. package/lib/mjs/utils/formUtils.d.ts +25 -14
  81. package/lib/mjs/utils/formUtils.js +2 -12
  82. package/lib/mjs/utils/utils.d.ts +1 -3
  83. package/lib/mjs/utils/utils.js +18 -33
  84. package/package.json +4 -4
@@ -590,6 +590,7 @@ export default class Webform extends NestedDataComponent {
590
590
  try {
591
591
  // Do not set the form again if it has been already set
592
592
  if (isFormAlreadySet && JSON.stringify(this._form) === JSON.stringify(form)) {
593
+ this.formReadyResolve();
593
594
  return Promise.resolve();
594
595
  }
595
596
  // Create the form.
@@ -597,13 +598,11 @@ export default class Webform extends NestedDataComponent {
597
598
  if (this.onSetForm) {
598
599
  this.onSetForm(_.cloneDeep(this._form), form);
599
600
  }
600
- if (this.parent?.component?.modalEdit) {
601
- return Promise.resolve();
602
- }
603
601
  }
604
602
  catch (err) {
605
603
  console.warn(err);
606
604
  // If provided form is not a valid JSON object, do not set it too
605
+ this.formReadyReject(err);
607
606
  return Promise.resolve();
608
607
  }
609
608
  // Allow the form to provide component overrides.
@@ -702,6 +701,18 @@ export default class Webform extends NestedDataComponent {
702
701
  set submission(submission) {
703
702
  this.setSubmission(submission);
704
703
  }
704
+ /**
705
+ * Sets the submission value
706
+ * @param {object|null|undefined} submission - The submission to set.
707
+ * @param {object|null|undefined} flags - Any flags to apply when setting the submission.
708
+ * @return {void}
709
+ */
710
+ onSetSubmission(submission, flags = {}) {
711
+ this.submissionSet = true;
712
+ this.triggerChange(flags);
713
+ this.emit('beforeSetSubmission', submission);
714
+ this.setValue(submission, flags);
715
+ }
705
716
  /**
706
717
  * Sets a submission and returns the promise when it is ready.
707
718
  * @param {any} submission - The submission to set.
@@ -721,10 +732,7 @@ export default class Webform extends NestedDataComponent {
721
732
  ...resolveFlags,
722
733
  };
723
734
  }
724
- this.submissionSet = true;
725
- this.triggerChange(flags);
726
- this.emit("beforeSetSubmission", submission);
727
- this.setValue(submission, flags);
735
+ this.onSetSubmission(submission, flags);
728
736
  return this.submissionReadyResolve(submission);
729
737
  }, (err) => this.submissionReadyReject(err))
730
738
  .catch((err) => this.submissionReadyReject(err)));
@@ -843,6 +851,9 @@ export default class Webform extends NestedDataComponent {
843
851
  return changed;
844
852
  }
845
853
  getValue() {
854
+ if (!this._submission) {
855
+ this._submission = {};
856
+ }
846
857
  if (!this._submission.data) {
847
858
  this._submission.data = {};
848
859
  }
@@ -1102,29 +1113,23 @@ export default class Webform extends NestedDataComponent {
1102
1113
  return;
1103
1114
  }
1104
1115
  // Mark any components as invalid if in a custom message.
1116
+ const componentErrors = {};
1105
1117
  errors.forEach((err) => {
1106
- const { components = [] } = err;
1107
- if (err.component) {
1108
- components.push(err.component);
1109
- }
1110
- if (err.path) {
1111
- components.push(err.path);
1118
+ const path = err.path || err.context?.path || err.component?.key;
1119
+ if (!componentErrors[path]) {
1120
+ componentErrors[path] = [];
1112
1121
  }
1113
- components.forEach((path) => {
1114
- const originalPath = getStringFromComponentPath(path);
1115
- const component = this.getComponent(path, _.identity, originalPath);
1116
- if (err.fromServer) {
1117
- if (component.serverErrors) {
1118
- component.serverErrors.push(err);
1119
- }
1120
- else {
1121
- component.serverErrors = [err];
1122
- }
1123
- }
1124
- const components = _.compact(Array.isArray(component) ? component : [component]);
1125
- components.forEach((component) => component.setCustomValidity(err.message, true));
1126
- });
1122
+ componentErrors[path].push(err);
1127
1123
  });
1124
+ // Iterate through all of our component errors and apply them to the components.
1125
+ for (let path in componentErrors) {
1126
+ const component = this.getComponent(path);
1127
+ const errors = componentErrors[path];
1128
+ if (component) {
1129
+ component.serverErrors = errors.filter((err) => err.fromServer);
1130
+ component.setCustomValidity(errors, true);
1131
+ }
1132
+ }
1128
1133
  const displayedErrors = [];
1129
1134
  if (errors.length) {
1130
1135
  errors = _.uniqBy(errors, (error) => [error.message, error.component?.id, error.context?.path].join());
@@ -1317,7 +1322,7 @@ export default class Webform extends NestedDataComponent {
1317
1322
  onLine: navigator.onLine,
1318
1323
  });
1319
1324
  }
1320
- submitForm(options = {}) {
1325
+ submitForm(options = {}, local = false) {
1321
1326
  this.clearServerErrors();
1322
1327
  return new Promise((resolve, reject) => {
1323
1328
  // Read-only forms should never submit.
@@ -1342,6 +1347,7 @@ export default class Webform extends NestedDataComponent {
1342
1347
  return reject("Invalid Submission");
1343
1348
  }
1344
1349
  const errors = this.validate(submission.data, {
1350
+ local,
1345
1351
  dirty: true,
1346
1352
  silentCheck: false,
1347
1353
  process: "submit",
@@ -1357,11 +1363,11 @@ export default class Webform extends NestedDataComponent {
1357
1363
  }
1358
1364
  this.everyComponent((comp) => {
1359
1365
  if (submission._vnote && comp.type === "form" && comp.component.reference) {
1360
- _.get(submission.data, comp.path, {})._vnote = submission._vnote;
1366
+ _.get(submission.data, local ? comp.paths?.localDataPath : comp.path, {})._vnote = submission._vnote;
1361
1367
  }
1362
1368
  const { persistent } = comp.component;
1363
1369
  if (persistent === "client-only") {
1364
- _.unset(submission.data, comp.path);
1370
+ _.unset(submission.data, local ? comp.paths?.localDataPath : comp.path);
1365
1371
  }
1366
1372
  });
1367
1373
  this.hook("customValidation", { ...submission, component: options.component }, (err) => {
@@ -1527,7 +1533,7 @@ export default class Webform extends NestedDataComponent {
1527
1533
  return;
1528
1534
  }
1529
1535
  const captchaComponent = [];
1530
- eachComponent(this.components, (component) => {
1536
+ this.eachComponent((component) => {
1531
1537
  if (/^(re)?captcha$/.test(component.type) && component.component.eventType === 'formLoad') {
1532
1538
  captchaComponent.push(component);
1533
1539
  }
@@ -1108,20 +1108,12 @@ export default class WebformBuilder extends Component {
1108
1108
  findRepeatablePaths() {
1109
1109
  const repeatablePaths = [];
1110
1110
  const keys = new Map();
1111
- eachComponent(this.form.components, (comp, path) => {
1112
- if (!comp.key) {
1113
- return;
1114
- }
1115
- if (keys.has(comp.key)) {
1116
- if (keys.get(comp.key).includes(path)) {
1117
- repeatablePaths.push(path);
1118
- }
1119
- else {
1120
- keys.set(comp.key, [...keys.get(comp.key), path]);
1121
- }
1111
+ eachComponent(this.form.components, (comp, path, components, parent, paths) => {
1112
+ if (keys.has(paths.dataPath)) {
1113
+ repeatablePaths.push(paths.dataPath);
1122
1114
  }
1123
1115
  else {
1124
- keys.set(comp.key, [path]);
1116
+ keys.set(paths.dataPath, true);
1125
1117
  }
1126
1118
  }, true);
1127
1119
  return repeatablePaths;
package/lib/mjs/Wizard.js CHANGED
@@ -369,7 +369,7 @@ export default class Wizard extends Webform {
369
369
  }
370
370
  attachHeader() {
371
371
  const isAllowPrevious = this.isAllowPrevious();
372
- this.attachTooltips(this.refs[`${this.wizardKey}-tooltip`], this.currentPanel.tooltip);
372
+ this.attachTooltips(this.refs[`${this.wizardKey}-tooltip`], this.currentPanel?.tooltip);
373
373
  if (this.isBreadcrumbClickable() || isAllowPrevious) {
374
374
  this.refs[`${this.wizardKey}-link`]?.forEach((link, index) => {
375
375
  if (!isAllowPrevious || index <= this.enabledIndex) {
@@ -717,7 +717,7 @@ export default class Wizard extends Webform {
717
717
  validateCurrentPage(flags = {}) {
718
718
  const components = this.currentPage?.components.map((component) => component.component);
719
719
  // Accessing the parent ensures the right instance (whether it's the parent Wizard or a nested Wizard) performs its validation
720
- return this.currentPage?.parent.validateComponents(components, this.currentPage.parent.data, flags);
720
+ return this.currentPage?.parent.validateComponents(components, this.root.data, flags);
721
721
  }
722
722
  emitPrevPage() {
723
723
  this.emit('prevPage', { page: this.page, submission: this.submission });
@@ -891,12 +891,6 @@ export default class Wizard extends Webform {
891
891
  this.redraw();
892
892
  }
893
893
  }
894
- redraw() {
895
- if (this.parent?.component?.modalEdit) {
896
- return this.parent.redraw();
897
- }
898
- return super.redraw();
899
- }
900
894
  rebuild() {
901
895
  const currentPage = this.page;
902
896
  const setCurrentPage = () => this.setPage(currentPage);
@@ -256,13 +256,6 @@ export default class Components {
256
256
  static setComponents(comps: any): void;
257
257
  static addComponent(name: any, comp: any): void;
258
258
  static setComponent(name: any, comp: any): void;
259
- /**
260
- * Return a path of component's value.
261
- * @param {Component} component - The component instance.
262
- * @returns {string} - The component's value path.
263
- */
264
- static getComponentPath(component: Component): string;
265
259
  static create(component: any, options: any, data: any): any;
266
260
  }
267
261
  import BaseEditForm from './_classes/component/Component.form';
268
- import Component from './_classes/component/Component';
@@ -1,7 +1,6 @@
1
1
  import Component from './_classes/component/Component';
2
2
  import EditFormUtils from './_classes/component/editForm/utils';
3
3
  import BaseEditForm from './_classes/component/Component.form';
4
- import { getComponentKey, getModelType } from '../utils/utils';
5
4
  import _ from 'lodash';
6
5
  export default class Components {
7
6
  static _editFormUtils = EditFormUtils;
@@ -46,34 +45,6 @@ export default class Components {
46
45
  static setComponent(name, comp) {
47
46
  Components.components[name] = comp;
48
47
  }
49
- /**
50
- * Return a path of component's value.
51
- * @param {Component} component - The component instance.
52
- * @returns {string} - The component's value path.
53
- */
54
- static getComponentPath(component) {
55
- let path = '';
56
- const componentKey = getComponentKey(component.component);
57
- if (componentKey) {
58
- let thisPath = component.options?.parent || component;
59
- while (thisPath && !thisPath.allowData && thisPath.parent) {
60
- thisPath = thisPath.parent;
61
- }
62
- // TODO: any component that is nested in e.g. a Data Grid or an Edit Grid is going to receive a row prop; the problem
63
- // is that options.row is passed to each further nested component, which results in erroneous paths like
64
- // `editGrid[0].container[0].textField` rather than `editGrid[0].container.textField`. This should be adapted for other
65
- // components with a tree-like data model
66
- const rowIndex = component.row;
67
- const rowIndexPath = rowIndex && !['container'].includes(thisPath.component.type) ? `[${Number.parseInt(rowIndex)}]` : '';
68
- path = `${thisPath.path}${rowIndexPath}.`;
69
- if (rowIndexPath && getModelType(thisPath) === 'nestedDataArray') {
70
- path = `${path}data.`;
71
- }
72
- path += componentKey;
73
- return _.trim(path, '.');
74
- }
75
- return path;
76
- }
77
48
  static create(component, options, data) {
78
49
  let comp = null;
79
50
  if (component.type && Components.components.hasOwnProperty(component.type)) {
@@ -98,9 +69,7 @@ export default class Components {
98
69
  else {
99
70
  comp = new Component(component, options, data);
100
71
  }
101
- const path = Components.getComponentPath(comp);
102
- if (path) {
103
- comp.path = path;
72
+ if (comp.path) {
104
73
  comp.componentsMap[comp.path] = comp;
105
74
  }
106
75
  return comp;
@@ -42,14 +42,13 @@ declare class Component extends Element {
42
42
  */
43
43
  private _hasCondition;
44
44
  /**
45
- * References to dom elements
45
+ * The row index for this component.
46
46
  */
47
- refs: {};
47
+ _rowIndex: number | undefined;
48
48
  /**
49
- * The data path to this specific component instance.
50
- * @type {string}
49
+ * References to dom elements
51
50
  */
52
- path: string;
51
+ refs: {};
53
52
  /**
54
53
  * An array of all the children components errors.
55
54
  */
@@ -114,7 +113,19 @@ declare class Component extends Element {
114
113
  * @type {Component}
115
114
  */
116
115
  parent: Component;
116
+ /**
117
+ * The component paths for this component.
118
+ * @type {import('@formio/core').ComponentPaths} - The component paths.
119
+ */
120
+ paths: import('@formio/core').ComponentPaths;
117
121
  _path: string;
122
+ /**
123
+ * Determines if this component is conditionally hidden. Should generally not be set outside of conditional logic pipeline.
124
+ * This is necessary because of clearOnHide behavior that only clears when conditionally hidden - we need to track
125
+ * conditionallyHidden separately from "regular" visibility.
126
+ */
127
+ _parentConditionallyHidden: any;
128
+ _conditionallyHidden: any;
118
129
  /**
119
130
  * Determines if this component is visible, or not.
120
131
  */
@@ -158,7 +169,7 @@ declare class Component extends Element {
158
169
  * @type {*}
159
170
  */
160
171
  info: any;
161
- get componentsMap(): any;
172
+ get componentsMap(): object;
162
173
  set data(value: any);
163
174
  get data(): any;
164
175
  mergeSchema(component?: {}): any;
@@ -182,6 +193,17 @@ declare class Component extends Element {
182
193
  * @returns {boolean} - TRUE if the component is disabled.
183
194
  */
184
195
  get disabled(): boolean;
196
+ /**
197
+ * Set Row Index to row and update each component.
198
+ * @param {number} value - The row index.
199
+ * @returns {void}
200
+ */
201
+ set rowIndex(value: number);
202
+ /**
203
+ * Get Row Index.
204
+ * @returns {number} - The row index.
205
+ */
206
+ get rowIndex(): number;
185
207
  afterComponentAssign(): void;
186
208
  createAddon(addonConfiguration: any): any;
187
209
  get shouldDisabled(): any;
@@ -190,6 +212,8 @@ declare class Component extends Element {
190
212
  get hasInput(): any;
191
213
  get defaultSchema(): any;
192
214
  get key(): any;
215
+ set path(path: string | undefined);
216
+ get path(): string | undefined;
193
217
  set parentVisible(value: any);
194
218
  get parentVisible(): any;
195
219
  set parentDisabled(value: boolean);
@@ -207,12 +231,20 @@ declare class Component extends Element {
207
231
  * @returns {boolean} - Whether the component is visible or not.
208
232
  */
209
233
  get visible(): boolean;
234
+ get conditionallyHidden(): any;
235
+ /**
236
+ * Evaluates whether the component is conditionally hidden (as opposed to intentionally hidden, e.g. via the `hidden` component schema property).
237
+ * @param {object} data - The data object to evaluate the condition against.
238
+ * @param {object} row - The row object to evaluate the condition against.
239
+ * @returns {boolean} - Whether the component is conditionally hidden.
240
+ */
241
+ checkConditionallyHidden(data?: object, row?: object): boolean;
210
242
  set currentForm(instance: any);
211
243
  get currentForm(): any;
212
244
  _currentForm: any;
213
245
  get fullMode(): boolean;
214
246
  get builderMode(): boolean;
215
- get calculatedPath(): string;
247
+ get calculatedPath(): string | undefined;
216
248
  get labelPosition(): any;
217
249
  get labelWidth(): any;
218
250
  get labelMargin(): any;
@@ -343,6 +375,12 @@ declare class Component extends Element {
343
375
  * @param {string} template - The template to use for the modal dialog.
344
376
  */
345
377
  setOpenModalElement(template?: string): void;
378
+ /**
379
+ * Renders a modal preview template and returns the markup as a string
380
+ * @param {object|null|undefined} ctx - The rendering context
381
+ * @return {string} - The modal preview markup
382
+ */
383
+ renderModalPreview(ctx: object | null | undefined): string;
346
384
  /**
347
385
  * Returns the modal preview template.
348
386
  * @returns {string} - The modal preview template.
@@ -362,6 +400,13 @@ declare class Component extends Element {
362
400
  * @returns {string} - The rendered HTML string of a component.
363
401
  */
364
402
  render(children?: string, topLevel?: boolean): string;
403
+ /**
404
+ * Creates the tooltip instance using tippy.js and returns it
405
+ * @param {HTMLElement} tooltipEl - HTML element to attach the tooltip
406
+ * @param {object|null|undefined} settings - tippy.js options
407
+ * @return {import('tippy.js').Tippy} - tippy.js instance
408
+ */
409
+ createTooltip(tooltipEl: HTMLElement, settings?: object | null | undefined): import('tippy.js').Tippy;
365
410
  /**
366
411
  * Attaches all the tooltips provided the refs object.
367
412
  * @param {object} toolTipsRefs - The refs for the tooltips within your template.