@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
@@ -166,25 +166,19 @@ export default class DayComponent extends Field {
166
166
  };
167
167
  }
168
168
  get days() {
169
- if (this._days) {
170
- return this._days;
171
- }
172
- this._days = [
169
+ const days = [
173
170
  { value: '', label: _.get(this.component, 'fields.day.placeholder', '') },
174
171
  ];
175
172
  for (let x = 1; x <= 31; x++) {
176
- this._days.push({
173
+ days.push({
177
174
  value: x,
178
175
  label: x.toString(),
179
176
  });
180
177
  }
181
- return this._days;
178
+ return days;
182
179
  }
183
180
  get months() {
184
- if (this._months) {
185
- return this._months;
186
- }
187
- this._months = [
181
+ const months = [
188
182
  {
189
183
  value: '',
190
184
  label: _.get(this.component, 'fields.month.placeholder') ||
@@ -203,24 +197,21 @@ export default class DayComponent extends Field {
203
197
  { value: 11, label: 'November' },
204
198
  { value: 12, label: 'December' },
205
199
  ];
206
- return this._months;
200
+ return months;
207
201
  }
208
202
  get years() {
209
- if (this._years) {
210
- return this._years;
211
- }
212
- this._years = [
203
+ const years = [
213
204
  { value: '', label: _.get(this.component, 'fields.year.placeholder', '') },
214
205
  ];
215
206
  const minYears = _.get(this.component, 'fields.year.minYear', 1900) || 1900;
216
207
  const maxYears = _.get(this.component, 'fields.year.maxYear', 2030) || 2030;
217
208
  for (let x = minYears; x <= maxYears; x++) {
218
- this._years.push({
209
+ years.push({
219
210
  value: x,
220
211
  label: x.toString(),
221
212
  });
222
213
  }
223
- return this._years;
214
+ return years;
224
215
  }
225
216
  setErrorClasses(elements, dirty, hasError) {
226
217
  super.setErrorClasses(elements, dirty, hasError);
@@ -538,7 +538,7 @@ export default class EditGridComponent extends NestedArrayComponent {
538
538
  isVisibleInRow: (component) => this.isComponentVisibleInRow(component, flattenedComponents),
539
539
  getView: (component, data) => {
540
540
  const instance = flattenedComponents[component.key];
541
- const view = instance ? instance.getView(data || instance.dataValue) : '';
541
+ const view = instance ? instance.getView(instance.dataValue) : '';
542
542
  // If there is an html tag in view, don't allow it to be injected in template
543
543
  const htmlTagRegExp = new RegExp('<(.*?)>');
544
544
  return typeof view === 'string' &&
@@ -948,9 +948,19 @@ export default class EditGridComponent extends NestedArrayComponent {
948
948
  }
949
949
  const column = _.clone(col);
950
950
  const options = _.clone(this.options);
951
+ const rootSubmissionTz = _.get(this.root, 'options.submissionTimezone');
952
+ if (rootSubmissionTz && !options.submissionTimezone) {
953
+ options.submissionTimezone = rootSubmissionTz;
954
+ }
951
955
  options.name += `[${rowIndex}]`;
952
956
  options.row = `${rowIndex}-${colIndex}`;
953
957
  options.rowIndex = rowIndex;
958
+ if (this.submissionTimezone) {
959
+ options.submissionTimezone = this.submissionTimezone;
960
+ if (column.type === 'datetime') {
961
+ column.widget = { ...column.widget, submissionTimezone: this.submissionTimezone };
962
+ }
963
+ }
954
964
  options.onChange = (flags = {}, changed, modified) => {
955
965
  if (changed.instance.root?.id && this.root?.id !== changed.instance.root.id) {
956
966
  changed.instance.root?.triggerChange?.(flags, changed, modified);
@@ -7,6 +7,7 @@ export default class FieldsetComponent extends NestedComponent {
7
7
  type: 'fieldset',
8
8
  legend: '',
9
9
  components: [],
10
+ clearOnHide: false,
10
11
  input: false,
11
12
  persistent: false,
12
13
  }, ...extend);
@@ -30,6 +30,8 @@ export default class FileComponent extends Field {
30
30
  } | undefined;
31
31
  isSyncing: boolean | undefined;
32
32
  abortUploads: any[] | undefined;
33
+ pendingfiles: any;
34
+ resolvedFiles: any[] | undefined;
33
35
  get dataReady(): Promise<any>;
34
36
  loadImage(fileInfo: any): any;
35
37
  get emptyValue(): never[];
@@ -147,7 +149,7 @@ export default class FileComponent extends Field {
147
149
  getMultipartOptions(fileToSync: any): any;
148
150
  uploadFile(fileToSync: any): Promise<any>;
149
151
  upload(): Promise<void | {
150
- fileToSync: never;
152
+ fileToSync: any;
151
153
  fileInfo: any;
152
154
  }[]>;
153
155
  syncFiles(): Promise<void>;
@@ -96,6 +96,8 @@ export default class FileComponent extends Field {
96
96
  };
97
97
  this.isSyncing = false;
98
98
  this.abortUploads = [];
99
+ this.pendingfiles = [];
100
+ this.resolvedFiles = [];
99
101
  }
100
102
  get dataReady() {
101
103
  return this.filesReady || Promise.resolve();
@@ -695,22 +697,42 @@ export default class FileComponent extends Field {
695
697
  };
696
698
  }
697
699
  // Check file minimum size
698
- if (this.component.fileMinSize && !this.validateMinSize(file, this.component.fileMinSize)) {
699
- return {
700
- status: 'error',
701
- message: this.t('File is too small; it must be at least {{ size }}', {
702
- size: this.component.fileMinSize,
703
- }),
704
- };
700
+ if (this.component.fileMinSize) {
701
+ const interpolatedMinSize = this.interpolate(this.component.fileMinSize, this.evalContext());
702
+ // This case is when the user entered fileMinSize expression, but did not enter or made a typo when
703
+ // setting the fileMinSize variable in the config of the project
704
+ if (!interpolatedMinSize) {
705
+ return {
706
+ status: 'error',
707
+ message: 'Please, check the entered parameters',
708
+ };
709
+ }
710
+ if (!this.validateMinSize(file, interpolatedMinSize)) {
711
+ return {
712
+ status: 'error',
713
+ message: this.t('fileTooSmall', {
714
+ size: interpolatedMinSize,
715
+ }),
716
+ };
717
+ }
705
718
  }
706
719
  // Check file maximum size
707
- if (this.component.fileMaxSize && !this.validateMaxSize(file, this.component.fileMaxSize)) {
708
- return {
709
- status: 'error',
710
- message: this.t('File is too big; it must be at most {{ size }}', {
711
- size: this.component.fileMaxSize,
712
- }),
713
- };
720
+ if (this.component.fileMaxSize) {
721
+ const interpolatedMaxSize = this.interpolate(this.component.fileMaxSize, this.evalContext());
722
+ if (!interpolatedMaxSize) {
723
+ return {
724
+ status: 'error',
725
+ message: 'Please, check the entered parameters',
726
+ };
727
+ }
728
+ if (!this.validateMaxSize(file, interpolatedMaxSize)) {
729
+ return {
730
+ status: 'error',
731
+ message: this.t('fileTooBig', {
732
+ size: interpolatedMaxSize,
733
+ }),
734
+ };
735
+ }
714
736
  }
715
737
  return {};
716
738
  }
@@ -966,7 +988,23 @@ export default class FileComponent extends Field {
966
988
  fileInfo,
967
989
  };
968
990
  }
969
- fileInfo = await this.uploadFile(fileToSync);
991
+ if (fileToSync.status === "success") {
992
+ const uploadedFile = this.resolvedFiles.find(x => x.fileToSync.originalName === fileToSync.originalName);
993
+ return {
994
+ fileToSync: uploadedFile.fileToSync,
995
+ fileInfo: uploadedFile.fileInfo,
996
+ };
997
+ }
998
+ const pendingFile = this.pendingfiles.find(x => x.name === fileToSync.name);
999
+ if (pendingFile) {
1000
+ fileInfo = await pendingFile.fileInfoProm;
1001
+ }
1002
+ else {
1003
+ const promInfo = this.uploadFile(fileToSync);
1004
+ this.pendingfiles.push({ name: fileToSync.name, fileInfoProm: promInfo });
1005
+ fileInfo = await promInfo;
1006
+ }
1007
+ this.pendingfiles = this.pendingfiles.filter(x => x.name !== fileToSync.name);
970
1008
  fileToSync.status = 'success';
971
1009
  fileToSync.message = this.t('Succefully uploaded');
972
1010
  fileInfo.originalName = fileToSync.originalName;
@@ -991,6 +1029,10 @@ export default class FileComponent extends Field {
991
1029
  finally {
992
1030
  delete fileToSync.progress;
993
1031
  this.redraw();
1032
+ const fileExists = this.resolvedFiles.find(x => x.fileInfo.originalName === fileToSync.originalName);
1033
+ if (!fileExists && fileToSync.status !== 'error') {
1034
+ this.resolvedFiles.push({ fileToSync, fileInfo });
1035
+ }
994
1036
  }
995
1037
  return {
996
1038
  fileToSync,
@@ -1007,6 +1049,9 @@ export default class FileComponent extends Field {
1007
1049
  this.delete(),
1008
1050
  this.upload(),
1009
1051
  ]);
1052
+ if (filesToUpload.length !== this.filesToSync?.filesToUpload?.length) {
1053
+ return;
1054
+ }
1010
1055
  this.filesToSync.filesToDelete = filesToDelete
1011
1056
  .filter((file) => file.fileToSync?.status === 'error')
1012
1057
  .map((file) => file.fileToSync);
@@ -561,9 +561,11 @@ export default class FormComponent extends Component {
561
561
  * @returns {*|boolean} - TRUE if the subform should be submitted, FALSE if it should not.
562
562
  */
563
563
  get shouldSubmit() {
564
+ const hiddenByJsonOnly = !this.hasCondition() && this.component.hidden;
564
565
  return (this.subFormReady &&
565
566
  (!this.component.hasOwnProperty('reference') || this.component.reference) &&
566
- !this.shouldConditionallyClear());
567
+ !this.shouldConditionallyClear() &&
568
+ !(hiddenByJsonOnly && this.component.clearOnHide));
567
569
  }
568
570
  /**
569
571
  * Returns the data for the subform.
@@ -34,6 +34,7 @@ export default class NumberComponent extends Input {
34
34
  * @returns {number} a parsed number
35
35
  */
36
36
  parseNumber(value: string): number;
37
+ normalizeValue(value: any, flags?: {}, emptyValue?: null): any;
37
38
  setInputMask(input: any): void;
38
39
  getValueAt(index: any): number | null;
39
40
  setValueAt(index: any, value: any, flags?: {}): void;
@@ -141,6 +141,23 @@ export default class NumberComponent extends Input {
141
141
  return parseFloat(value);
142
142
  }
143
143
  }
144
+ normalizeValue(value, flags = {}, emptyValue = this.emptyValue) {
145
+ if (typeof value === 'string') {
146
+ const result = this.parseNumber(value);
147
+ value = _.isNaN(result) ? this.emptyValue : result;
148
+ }
149
+ if (this.component?.multiple && Array.isArray(value)) {
150
+ const normilizedValues = value.map((val) => {
151
+ if (typeof val === 'string') {
152
+ const result = this.parseNumber(val);
153
+ return _.isNaN(result) ? this.emptyValue : result;
154
+ }
155
+ return val;
156
+ });
157
+ value = normilizedValues;
158
+ }
159
+ return super.normalizeValue(value, flags, emptyValue);
160
+ }
144
161
  setInputMask(input) {
145
162
  let numberPattern = '[0-9';
146
163
  numberPattern += this.decimalSeparator || '';
@@ -522,7 +522,7 @@ export default class SelectComponent extends ListComponent {
522
522
  noUpdateEvent: true,
523
523
  });
524
524
  }
525
- else if (this.shouldAddDefaultValue && !this.options.readOnly) {
525
+ else if (this.shouldAddDefaultValue && !this.options.readOnly && this.root && !this.root.submissionSet) {
526
526
  // If a default value is provided then select it.
527
527
  const defaultValue = this.defaultValue;
528
528
  if (!this.isEmpty(defaultValue)) {
@@ -1366,6 +1366,10 @@ export default class SelectComponent extends ListComponent {
1366
1366
  }
1367
1367
  _.set(submission.metadata.selectData, this.path, templateData);
1368
1368
  }
1369
+ else if (!this.templateData[templateValue] &&
1370
+ this.isEmpty(value)) {
1371
+ _.unset(this.root.submission, `metadata.selectData.${this.path}`);
1372
+ }
1369
1373
  if (flags.resetValue && this.root?.submission && !this.options.readOnly) {
1370
1374
  const submission = this.root.submission;
1371
1375
  if (!submission.metadata) {
@@ -57,7 +57,7 @@ export default class SignatureComponent extends Input {
57
57
  this.component.height = '200px';
58
58
  }
59
59
  if (this.component.keepOverlayRatio &&
60
- this.options?.display === 'pdf' &&
60
+ this.options.pdf &&
61
61
  this.component.overlay?.width &&
62
62
  this.component.overlay?.height) {
63
63
  this.ratio = this.component.overlay?.width / this.component.overlay?.height;
@@ -7,7 +7,6 @@ declare const _default: ({
7
7
  placeholder: string;
8
8
  weight: number;
9
9
  conditional?: undefined;
10
- customConditional?: undefined;
11
10
  ignore?: undefined;
12
11
  } | {
13
12
  type: string;
@@ -24,7 +23,6 @@ declare const _default: ({
24
23
  };
25
24
  };
26
25
  weight: number;
27
- customConditional?: undefined;
28
26
  ignore?: undefined;
29
27
  } | {
30
28
  weight: number;
@@ -32,9 +30,6 @@ declare const _default: ({
32
30
  label: string;
33
31
  tooltip: string;
34
32
  key: string;
35
- customConditional: ({ options }: {
36
- options: any;
37
- }) => boolean;
38
33
  input: boolean;
39
34
  placeholder?: undefined;
40
35
  conditional?: undefined;
@@ -49,6 +44,5 @@ declare const _default: ({
49
44
  placeholder?: undefined;
50
45
  weight?: undefined;
51
46
  conditional?: undefined;
52
- customConditional?: undefined;
53
47
  })[];
54
48
  export default _default;
@@ -46,7 +46,6 @@ export default [
46
46
  label: 'Keep Overlay Aspect Ratio',
47
47
  tooltip: 'If checked, the field will have the same aspect ratio as its preview.',
48
48
  key: 'keepOverlayRatio',
49
- customConditional: ({ options }) => options?.editForm?.display === 'pdf',
50
49
  input: true,
51
50
  },
52
51
  {
@@ -10,6 +10,8 @@ declare const _default: ({
10
10
  validate?: undefined;
11
11
  autofocus?: undefined;
12
12
  overrideEditForm?: undefined;
13
+ multiple?: undefined;
14
+ customConditional?: undefined;
13
15
  dataSrc?: undefined;
14
16
  data?: undefined;
15
17
  defaultValue?: undefined;
@@ -27,6 +29,8 @@ declare const _default: ({
27
29
  autofocus: boolean;
28
30
  overrideEditForm: boolean;
29
31
  ignore?: undefined;
32
+ multiple?: undefined;
33
+ customConditional?: undefined;
30
34
  dataSrc?: undefined;
31
35
  data?: undefined;
32
36
  defaultValue?: undefined;
@@ -42,6 +46,25 @@ declare const _default: ({
42
46
  validate?: undefined;
43
47
  autofocus?: undefined;
44
48
  overrideEditForm?: undefined;
49
+ multiple?: undefined;
50
+ customConditional?: undefined;
51
+ dataSrc?: undefined;
52
+ data?: undefined;
53
+ defaultValue?: undefined;
54
+ } | {
55
+ label: string;
56
+ multiple: boolean;
57
+ key: string;
58
+ type: string;
59
+ input: boolean;
60
+ tooltip: string;
61
+ customConditional: string;
62
+ weight: number;
63
+ ignore?: undefined;
64
+ placeholder?: undefined;
65
+ validate?: undefined;
66
+ autofocus?: undefined;
67
+ overrideEditForm?: undefined;
45
68
  dataSrc?: undefined;
46
69
  data?: undefined;
47
70
  defaultValue?: undefined;
@@ -57,6 +80,8 @@ declare const _default: ({
57
80
  validate?: undefined;
58
81
  autofocus?: undefined;
59
82
  overrideEditForm?: undefined;
83
+ multiple?: undefined;
84
+ customConditional?: undefined;
60
85
  dataSrc?: undefined;
61
86
  data?: undefined;
62
87
  defaultValue?: undefined;
@@ -80,5 +105,7 @@ declare const _default: ({
80
105
  validate?: undefined;
81
106
  autofocus?: undefined;
82
107
  overrideEditForm?: undefined;
108
+ multiple?: undefined;
109
+ customConditional?: undefined;
83
110
  })[];
84
111
  export default _default;
@@ -67,6 +67,16 @@ export default [
67
67
  placeholder: 'Number of Columns',
68
68
  tooltip: 'Enter the number or columns that should be displayed by this table.',
69
69
  },
70
+ {
71
+ label: "Column Headers",
72
+ multiple: true,
73
+ key: "header",
74
+ type: "textfield",
75
+ input: true,
76
+ tooltip: 'Enter header names for the columns',
77
+ customConditional: "if(instance && instance.dataValue && Array.isArray(instance.dataValue)) {\r\n const isAllowToAddHeader = instance.dataValue.length < data.numCols;\r\n const addBtn = _.get(instance, 'refs.addButton[0]', null);\r\n if(addBtn) {\r\n isAllowToAddHeader? addBtn.removeAttribute('disabled'): addBtn.setAttribute('disabled', 'disabled');\r\n }\r\n} ",
78
+ weight: 3,
79
+ },
70
80
  {
71
81
  type: 'checkbox',
72
82
  label: 'Clone Row Components',
@@ -7,7 +7,7 @@ import Templates from './templates/Templates';
7
7
  import Providers from './providers';
8
8
  import Widgets from './widgets';
9
9
  import Form, { FormOptions } from './Form';
10
- import Utils, { Evaluator, registerEvaluator, DefaultEvaluator } from './utils';
10
+ import Utils, { DefaultEvaluator, Evaluator, registerEvaluator } from './utils';
11
11
  import Licenses from './licenses';
12
12
  import EventEmitter from './EventEmitter';
13
13
  import Webform from './Webform';
@@ -90,12 +90,9 @@ export function registerModule(mod, defaultFn = null, options = {}) {
90
90
  break;
91
91
  default:
92
92
  if (defaultFn) {
93
- if (!defaultFn(key, mod)) {
94
- console.warn('Unknown module option', key);
95
- }
93
+ defaultFn(key, mod);
96
94
  break;
97
95
  }
98
- console.log('Unknown module option', key);
99
96
  }
100
97
  }
101
98
  }
@@ -108,7 +105,7 @@ export function useModule(defaultFn = null) {
108
105
  plugins = _.isArray(plugins)
109
106
  ? plugins
110
107
  : [
111
- plugins,
108
+ plugins
112
109
  ];
113
110
  plugins.forEach((plugin) => {
114
111
  if (Array.isArray(plugin)) {
@@ -129,4 +126,4 @@ export function useModule(defaultFn = null) {
129
126
  Formio.use = useModule();
130
127
  export { Formio as FormioCore } from './Formio';
131
128
  // Export the components.
132
- export { Components, Displays, Providers, Widgets, Templates, Utils, Form, Formio, Licenses, EventEmitter, Webform, DefaultEvaluator, FormOptions, };
129
+ export { Components, Displays, Providers, Widgets, Templates, Utils, Form, Formio, Licenses, EventEmitter, Webform, DefaultEvaluator, FormOptions };
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "type": "module",
3
- "version": "5.3.6"
3
+ "version": "5.4.0"
4
4
 
5
5
  }
@@ -30,9 +30,15 @@ function azure(formio) {
30
30
  downloadFile(file) {
31
31
  return formio.makeRequest('file', `${formio.formUrl}/storage/azure?name=${XHR.trim(file.name)}`, 'GET');
32
32
  },
33
- deleteFile: function deleteFile(fileInfo) {
34
- var url = `${formio.formUrl}/storage/azure?name=${XHR.trim(fileInfo.name)}&key=${XHR.trim(fileInfo.key)}`;
35
- return formio.makeRequest('', url, 'delete');
33
+ deleteFile(fileInfo, options) {
34
+ const name = XHR.trim(fileInfo.name);
35
+ const key = XHR.trim(fileInfo.key);
36
+ return formio.makeRequest('', `${formio.formUrl}/storage/azure?name=${encodeURIComponent(name)}&key=${encodeURIComponent(key)}`, 'delete').then((response) => {
37
+ return {
38
+ success: true,
39
+ key: response?.key || key,
40
+ };
41
+ });
36
42
  },
37
43
  };
38
44
  }
@@ -20,6 +20,9 @@ declare namespace _default {
20
20
  wizardHeaderVertical: {
21
21
  form: string;
22
22
  };
23
+ wizardHeaderStepIndicator: {
24
+ form: string;
25
+ };
23
26
  wizardNav: {
24
27
  form: string;
25
28
  };
@@ -76,5 +76,7 @@ declare namespace _default {
76
76
  let requiredDayEmpty: string;
77
77
  let requiredMonthField: string;
78
78
  let requiredYearField: string;
79
+ let fileTooSmall: string;
80
+ let fileTooBig: string;
79
81
  }
80
82
  export default _default;
@@ -76,4 +76,6 @@ export default {
76
76
  requiredDayEmpty: '{{ field }} is required',
77
77
  requiredMonthField: '{{ field }} is required',
78
78
  requiredYearField: '{{ field }} is required',
79
+ fileTooSmall: 'File is too small; it must be at least {{ size }}',
80
+ fileTooBig: 'File is too big; it must be at most {{ size }}'
79
81
  };
@@ -7,6 +7,7 @@ export class I18n {
7
7
  constructor(languages?: {});
8
8
  languages: {};
9
9
  language: string;
10
+ originalLanguage: string;
10
11
  currentLanguage: any;
11
12
  setLanguages(languages: any): void;
12
13
  dir(lang?: string): "rtl" | "ltr";
@@ -12,6 +12,7 @@ for (const lang in i18n.resources) {
12
12
  export class I18n {
13
13
  languages = i18Defaults;
14
14
  language = 'en';
15
+ originalLanguage = 'en';
15
16
  currentLanguage = i18Defaults.en;
16
17
  constructor(languages = {}) {
17
18
  this.setLanguages(languages);
@@ -66,6 +67,7 @@ export class I18n {
66
67
  return new I18n();
67
68
  }
68
69
  changeLanguage(language, ready = null) {
70
+ this.originalLanguage = language;
69
71
  if (!this.languages[language]) {
70
72
  language = 'en';
71
73
  }
@@ -94,7 +94,7 @@ declare const FormioUtils: {
94
94
  offsetDate(date: Date, timezone: string): Date;
95
95
  zonesLoaded(): boolean;
96
96
  shouldLoadZones(timezone: string): boolean;
97
- loadZones(url: string, timezone: string): any;
97
+ loadZones(url: string, _timezone: any): any;
98
98
  momentDate(value: string | Date, format: string, timezone: string, options: object): Date;
99
99
  formatDate(timezonesUrl: string, value: string | Date, format: string, timezone: string, flatPickrInputFormat: string): string;
100
100
  formatOffset(timezonesUrl: string, formatFn: Function, date: string | Date, format: string, timezone: string): string;
@@ -202,7 +202,7 @@ export function shouldLoadZones(timezone: string): boolean;
202
202
  * @param {string} timezone - The timezone to load.
203
203
  * @returns {Promise<any> | *} - Resolves when the zones for this timezone are loaded.
204
204
  */
205
- export function loadZones(url: string, timezone: string): Promise<any> | any;
205
+ export function loadZones(url: string, _timezone: any): Promise<any> | any;
206
206
  /**
207
207
  * Get the moment date object for translating dates with timezones.
208
208
  * @param {string|Date} value - The value to convert into a moment date.
@@ -217,6 +217,16 @@ export function checkSimpleConditional(component, condition, row, data, instance
217
217
  }
218
218
  else {
219
219
  const value = getComponentActualValue(conditionComponentPath, data, row);
220
+ // When inside a DataGrid/EditGrid, construct a row-indexed path so that
221
+ // operators like isEmpty can look up the correct row's component instance.
222
+ let operatorPath = conditionComponentPath;
223
+ const dataParent = getDataParentComponent(instance);
224
+ if (dataParent && !_.isNil(instance?.rowIndex)) {
225
+ const parentPath = dataParent.paths?.localPath;
226
+ if (parentPath && conditionComponentPath.startsWith(`${parentPath}.`)) {
227
+ operatorPath = conditionComponentPath.replace(`${parentPath}.`, `${parentPath}[${instance.rowIndex}].`);
228
+ }
229
+ }
220
230
  const СonditionOperator = ConditionOperators[operator];
221
231
  return СonditionOperator
222
232
  ? new СonditionOperator().getResult({
@@ -224,7 +234,7 @@ export function checkSimpleConditional(component, condition, row, data, instance
224
234
  comparedValue,
225
235
  instance,
226
236
  component,
227
- path: conditionComponentPath,
237
+ path: operatorPath,
228
238
  })
229
239
  : true;
230
240
  }
@@ -275,7 +285,11 @@ export function getComponentActualValue(compPath, data, row) {
275
285
  */
276
286
  export function checkCustomConditional(component, custom, row, data, form, variable, onError, instance) {
277
287
  if (typeof custom === 'string') {
278
- custom = `var ${variable} = true; ${custom}; return ${variable};`;
288
+ custom = `
289
+ var ${variable} = true;
290
+ ${custom};
291
+ return ${variable};
292
+ `;
279
293
  }
280
294
  const value = instance && instance.evaluate
281
295
  ? instance.evaluate(custom, { row, data, form })
@@ -606,14 +620,16 @@ export function shouldLoadZones(timezone) {
606
620
  * @param {string} timezone - The timezone to load.
607
621
  * @returns {Promise<any> | *} - Resolves when the zones for this timezone are loaded.
608
622
  */
609
- export function loadZones(url, timezone) {
610
- if (timezone && !shouldLoadZones(timezone)) {
611
- // Return non-resolving promise.
612
- return new Promise(_.noop);
623
+ export function loadZones(url, _timezone) {
624
+ if (moment.zonesLoaded) {
625
+ return Promise.resolve();
613
626
  }
614
627
  if (moment.zonesPromise) {
615
628
  return moment.zonesPromise;
616
629
  }
630
+ // Always load the full packed dataset once. The previous optimization skipped fetch when the
631
+ // display timezone matched the runtime zone, but moment-timezone still needs `tz.load()` for
632
+ // `.tz(ianaName)` and `z` formatting to work; otherwise conversions silently match server local time.
617
633
  return (moment.zonesPromise = fetch(url).then((resp) => resp.json().then((zones) => {
618
634
  moment.tz.load(zones);
619
635
  moment.zonesLoaded = true;
@@ -1,6 +1,6 @@
1
1
  import { Formio } from '../Formio';
2
2
  import InputWidget from './InputWidget';
3
- import { convertFormatToFlatpickr, convertFormatToMask, convertFormatToMoment, formatDate, formatOffset, getBrowserInfo, getDateSetting, getLocaleDateFormatInfo, momentDate, zonesLoaded, shouldLoadZones, loadZones, hasEncodedTimezone, } from '../utils';
3
+ import { convertFormatToFlatpickr, convertFormatToMask, convertFormatToMoment, formatDate, formatOffset, getBrowserInfo, getDateSetting, getLocaleDateFormatInfo, momentDate, zonesLoaded, loadZones, hasEncodedTimezone, } from '../utils';
4
4
  import moment from 'moment';
5
5
  import _ from 'lodash';
6
6
  const DEFAULT_FORMAT = 'yyyy-MM-dd hh:mm a';
@@ -56,7 +56,7 @@ export default class CalendarWidget extends InputWidget {
56
56
  if (this.zoneLoading) {
57
57
  return true;
58
58
  }
59
- if (!zonesLoaded() && shouldLoadZones(timezone)) {
59
+ if (!zonesLoaded()) {
60
60
  this.zoneLoading = true;
61
61
  loadZones(this.timezonesUrl, timezone).then(() => {
62
62
  this.zoneLoading = false;