@formio/js 5.2.0 → 5.2.1-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 (76) hide show
  1. package/dist/formio.builder.css +15 -17
  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 +15 -17
  7. package/dist/formio.form.js +32 -32
  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 +3 -3
  11. package/dist/formio.full.css +15 -17
  12. package/dist/formio.full.js +33 -33
  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 +3 -3
  16. package/dist/formio.js +7 -7
  17. package/dist/formio.min.js +1 -1
  18. package/dist/formio.min.js.LICENSE.txt +1 -1
  19. package/dist/formio.utils.js +6 -6
  20. package/dist/formio.utils.min.js +1 -1
  21. package/dist/formio.utils.min.js.LICENSE.txt +1 -1
  22. package/lib/cjs/Embed.js +1 -1
  23. package/lib/cjs/Formio.js +1 -1
  24. package/lib/cjs/Webform.js +3 -2
  25. package/lib/cjs/WebformBuilder.js +18 -11
  26. package/lib/cjs/Wizard.d.ts +1 -2
  27. package/lib/cjs/Wizard.js +17 -23
  28. package/lib/cjs/components/Components.js +1 -1
  29. package/lib/cjs/components/_classes/component/Component.d.ts +23 -2
  30. package/lib/cjs/components/_classes/component/Component.js +61 -35
  31. package/lib/cjs/components/_classes/nested/NestedComponent.js +2 -2
  32. package/lib/cjs/components/file/File.d.ts +1 -1
  33. package/lib/cjs/components/file/File.js +6 -1
  34. package/lib/cjs/components/form/Form.d.ts +0 -2
  35. package/lib/cjs/components/form/Form.js +12 -20
  36. package/lib/cjs/components/select/Select.d.ts +1 -1
  37. package/lib/cjs/components/select/Select.js +16 -24
  38. package/lib/cjs/components/tags/Tags.d.ts +1 -1
  39. package/lib/cjs/components/tags/Tags.js +2 -2
  40. package/lib/cjs/formio.form.js +1 -0
  41. package/lib/cjs/utils/ChoicesWrapper.d.ts +4 -25
  42. package/lib/cjs/utils/ChoicesWrapper.js +47 -124
  43. package/lib/cjs/utils/formUtils.d.ts +2 -2
  44. package/lib/cjs/utils/index.d.ts +4 -4
  45. package/lib/cjs/utils/utils.d.ts +4 -4
  46. package/lib/cjs/utils/utils.js +2 -2
  47. package/lib/cjs/widgets/CalendarWidget.d.ts +1 -1
  48. package/lib/cjs/widgets/CalendarWidget.js +1 -1
  49. package/lib/mjs/Embed.js +1 -1
  50. package/lib/mjs/Formio.js +1 -1
  51. package/lib/mjs/Webform.js +2 -2
  52. package/lib/mjs/WebformBuilder.js +19 -12
  53. package/lib/mjs/Wizard.d.ts +1 -2
  54. package/lib/mjs/Wizard.js +16 -22
  55. package/lib/mjs/components/Components.js +1 -1
  56. package/lib/mjs/components/_classes/component/Component.d.ts +23 -2
  57. package/lib/mjs/components/_classes/component/Component.js +61 -35
  58. package/lib/mjs/components/_classes/nested/NestedComponent.js +2 -2
  59. package/lib/mjs/components/file/File.d.ts +1 -1
  60. package/lib/mjs/components/file/File.js +6 -1
  61. package/lib/mjs/components/form/Form.d.ts +0 -2
  62. package/lib/mjs/components/form/Form.js +12 -20
  63. package/lib/mjs/components/select/Select.d.ts +1 -1
  64. package/lib/mjs/components/select/Select.js +16 -23
  65. package/lib/mjs/components/tags/Tags.d.ts +1 -1
  66. package/lib/mjs/components/tags/Tags.js +2 -2
  67. package/lib/mjs/formio.form.js +1 -0
  68. package/lib/mjs/utils/ChoicesWrapper.d.ts +4 -25
  69. package/lib/mjs/utils/ChoicesWrapper.js +26 -119
  70. package/lib/mjs/utils/formUtils.d.ts +2 -2
  71. package/lib/mjs/utils/index.d.ts +4 -4
  72. package/lib/mjs/utils/utils.d.ts +4 -4
  73. package/lib/mjs/utils/utils.js +2 -2
  74. package/lib/mjs/widgets/CalendarWidget.d.ts +1 -1
  75. package/lib/mjs/widgets/CalendarWidget.js +1 -1
  76. package/package.json +5 -5
@@ -420,12 +420,14 @@ export default class Component extends Element {
420
420
  }
421
421
  /**
422
422
  * Returns if the parent should conditionally clear.
423
+ *
423
424
  * @returns {boolean} - If the parent should conditionally clear.
424
425
  */
425
426
  parentShouldConditionallyClear() {
426
427
  let currentParent = this.parent;
427
428
  while (currentParent) {
428
- if (currentParent.shouldConditionallyClear(true)) {
429
+ if ((currentParent.allowData && currentParent._conditionallyClear) ||
430
+ (!currentParent.allowData && currentParent._conditionallyHidden)) {
429
431
  return true;
430
432
  }
431
433
  currentParent = currentParent.parent;
@@ -435,7 +437,21 @@ export default class Component extends Element {
435
437
  parentConditionallyHidden() {
436
438
  let currentParent = this.parent;
437
439
  while (currentParent) {
438
- if (currentParent.conditionallyHidden(true)) {
440
+ if (currentParent._conditionallyHidden) {
441
+ return true;
442
+ }
443
+ currentParent = currentParent.parent;
444
+ }
445
+ return false;
446
+ }
447
+ /**
448
+ * Returns true if any of the parents default their component "hidden" property to true.
449
+ * @returns {boolean} - If any parent defaults the hidden property to true.
450
+ */
451
+ anyParentDefaultsHidden() {
452
+ let currentParent = this.parent;
453
+ while (currentParent) {
454
+ if (currentParent.component.hidden) {
439
455
  return true;
440
456
  }
441
457
  currentParent = currentParent.parent;
@@ -650,48 +666,58 @@ export default class Component extends Element {
650
666
  }
651
667
  return this._logicallyHidden;
652
668
  }
653
- shouldConditionallyClear(skipParent = false) {
669
+ /**
670
+ * Determines if the component should clear its value when the root form is pristine.
671
+ * @returns {boolean} - If the component should clear its value when the root form is pristine.
672
+ */
673
+ shouldConditionallyClearOnPristine() {
674
+ // If the form is pristine, we should NOT clear the value of a conditionally hidden child component
675
+ // of a layout component that defaults to hidden using the "hidden" component property.
676
+ return !this.anyParentDefaultsHidden();
677
+ }
678
+ /**
679
+ * Returns if the component should clear its value when conditionally hidden.
680
+ * @returns {boolean} - If the component should clear its value when conditionally hidden.
681
+ */
682
+ shouldConditionallyClear() {
654
683
  // Skip if this component has clearOnHide set to false.
655
684
  if (this.component.clearOnHide === false) {
656
- return false;
685
+ this._conditionallyClear = false;
686
+ return this._conditionallyClear;
657
687
  }
658
688
  // If the component is logically hidden, then it is conditionally hidden and should clear.
659
689
  if (this.logicallyHidden) {
660
- return true;
690
+ this._conditionallyClear = true;
691
+ return this._conditionallyClear;
661
692
  }
662
693
  // If we have a condition and it is not conditionally visible, the it should conditionally clear.
663
- if (this.hasCondition() && !this.conditionallyVisible()) {
664
- return true;
665
- }
666
- if (skipParent) {
667
- // Stop recurrsion for the parent checks.
668
- return false;
669
- }
670
- // If this component has a set value, then it should ONLY clear if a parent is hidden
671
- // and has the clearOnHide set to true.
672
- if (this.hasSetValue) {
673
- return this.parentShouldConditionallyClear();
694
+ if (this.hasCondition() &&
695
+ !this.conditionallyVisible() &&
696
+ (!this.rootPristine || this.shouldConditionallyClearOnPristine())) {
697
+ this._conditionallyClear = true;
698
+ return this._conditionallyClear;
674
699
  }
675
- // Clear the value if the parent is conditionally hidden.
676
- return this.parentConditionallyHidden();
700
+ this._conditionallyClear = this.hasSetValue ? false : this.parentShouldConditionallyClear();
701
+ return this._conditionallyClear;
677
702
  }
678
- conditionallyHidden(skipParent = false) {
703
+ /**
704
+ * Returns if the component is conditionally hidden.
705
+ * @returns {boolean} - If the component is conditionally hidden.
706
+ */
707
+ conditionallyHidden() {
708
+ // If it is logically hidden, then it is conditionally hidden.
679
709
  if (this.logicallyHidden) {
680
- return true;
710
+ this._conditionallyHidden = true;
711
+ return this._conditionallyHidden;
681
712
  }
682
- if (!this.hasCondition() && !skipParent) {
683
- return this.parentConditionallyHidden();
684
- }
685
- // Return if we are not conditionally visible (conditionallyHidden)
686
- if (!this.conditionallyVisible()) {
687
- return true;
688
- }
689
- if (skipParent) {
690
- // Stop recurrsion for the parent checks.
691
- return false;
713
+ // If it has a condition, and is not conditionally visible, then it is conditionally hidden.
714
+ if (this.hasCondition() && !this.conditionallyVisible()) {
715
+ this._conditionallyHidden = true;
716
+ return this._conditionallyHidden;
692
717
  }
693
- // Check the parent.
694
- return this.parentConditionallyHidden();
718
+ // It is conditionally hidden if its parent is conditionally hidden.
719
+ this._conditionallyHidden = this.parentConditionallyHidden();
720
+ return this._conditionallyHidden;
695
721
  }
696
722
  get currentForm() {
697
723
  return this._currentForm;
@@ -3162,6 +3188,9 @@ export default class Component extends Element {
3162
3188
  data = data || this.rootValue;
3163
3189
  flags = flags || {};
3164
3190
  row = row || this.data;
3191
+ if (flags.noCheck) {
3192
+ return true;
3193
+ }
3165
3194
  // Some components (for legacy reasons) have calls to "checkData" in inappropriate places such
3166
3195
  // as setValue. Historically, this was bypassed by a series of cached states around the data model
3167
3196
  // which caused its own problems. We need to ensure that premium and custom components do not fall into
@@ -3176,9 +3205,6 @@ export default class Component extends Element {
3176
3205
  if (!flags.fromBlur) {
3177
3206
  this.checkRefreshOn(flags.changes, flags);
3178
3207
  }
3179
- if (flags.noCheck) {
3180
- return true;
3181
- }
3182
3208
  this.checkComponentConditions(data, flags, row);
3183
3209
  if (this.id !== flags.triggeredComponentId) {
3184
3210
  this.calculateComponentValue(data, flags, row);
@@ -667,7 +667,7 @@ export default class NestedComponent extends Field {
667
667
  }
668
668
  validationProcessor({ scope, data, row, instance, paths }, flags) {
669
669
  const { dirty } = flags;
670
- if (this.root.hasExtraPages && this.page !== this.root.page) {
670
+ if (this.root && this.root.hasSubWizards && this.page !== this.root.page) {
671
671
  instance = this.componentsMap?.hasOwnProperty(paths.dataPath)
672
672
  ? this.componentsMap[paths.dataPath]
673
673
  : this.getComponent(paths.dataPath);
@@ -816,7 +816,7 @@ export default class NestedComponent extends Field {
816
816
  return false;
817
817
  }
818
818
  if (component.type === 'components') {
819
- if (component.tree && component.hasValue(value)) {
819
+ if ((component.tree || component.hasInput) && component.hasValue(value)) {
820
820
  return component.setValue(_.get(value, component.key), flags);
821
821
  }
822
822
  return component.setValue(value, flags);
@@ -33,7 +33,7 @@ export default class FileComponent extends Field {
33
33
  get dataReady(): Promise<any>;
34
34
  loadImage(fileInfo: any): any;
35
35
  get emptyValue(): never[];
36
- getValueAsString(value: any): any;
36
+ getValueAsString(value: any, options: any): any;
37
37
  get defaultValue(): any[];
38
38
  get hasTypes(): any;
39
39
  _fileBrowseHidden: any;
@@ -103,7 +103,12 @@ export default class FileComponent extends Field {
103
103
  get emptyValue() {
104
104
  return [];
105
105
  }
106
- getValueAsString(value) {
106
+ getValueAsString(value, options) {
107
+ if (options?.review && !this.component.uploadOnly) {
108
+ return _.map(value, (val, index) => {
109
+ return `<a href="${val.url || '#'}" target="_blank" data-path='${this.path}' data-fileindex='${index}'>${val.originalName}</a>`;
110
+ }).join(', ');
111
+ }
107
112
  if (_.isArray(value)) {
108
113
  return _.map(value, 'originalName').join(', ');
109
114
  }
@@ -98,8 +98,6 @@ export default class FormComponent extends Component {
98
98
  * @returns {void}
99
99
  */
100
100
  onSetSubFormValue(submission: object | null | undefined, flags: object | null | undefined): void;
101
- areAllComponentsEmpty(data: any): boolean;
102
- conditionallyHidden(): boolean;
103
101
  updateSubFormVisibility(): void;
104
102
  /**
105
103
  * Determines if this form is a Nested Wizard
@@ -96,6 +96,9 @@ export default class FormComponent extends Component {
96
96
  }
97
97
  return this.createSubForm();
98
98
  }
99
+ shouldConditionallyClearOnPristine() {
100
+ return !this.hasSetValue && super.shouldConditionallyClearOnPristine();
101
+ }
99
102
  get dataReady() {
100
103
  return this.subFormReady || Promise.resolve();
101
104
  }
@@ -289,11 +292,13 @@ export default class FormComponent extends Component {
289
292
  }
290
293
  this.subForm.attach(element);
291
294
  this.valueChanged = this.hasSetValue;
292
- if (!this.valueChanged && this.dataValue.state !== 'submitted') {
293
- this.setDefaultValue();
294
- }
295
- else {
296
- this.restoreValue();
295
+ if (!this.shouldConditionallyClear()) {
296
+ if (!this.valueChanged && this.dataValue.state !== 'submitted') {
297
+ this.setDefaultValue();
298
+ }
299
+ else {
300
+ this.restoreValue();
301
+ }
297
302
  }
298
303
  }
299
304
  if (!this.builderMode && this.component.modalEdit) {
@@ -409,7 +414,7 @@ export default class FormComponent extends Component {
409
414
  this.component.components = this.subForm._form?.components;
410
415
  this.component.display = this.subForm._form?.display;
411
416
  this.subForm.on('change', () => {
412
- if (this.subForm) {
417
+ if (this.subForm && !this.shouldConditionallyClear()) {
413
418
  this.dataValue = this.subForm.getValue();
414
419
  this.triggerChange({
415
420
  noEmit: true
@@ -669,20 +674,7 @@ export default class FormComponent extends Component {
669
674
  this.subForm.setValue(submission, flags);
670
675
  }
671
676
  isEmpty(value = this.dataValue) {
672
- return value === null || _.isEqual(value, this.emptyValue) || (this.areAllComponentsEmpty(value?.data) && !value?._id);
673
- }
674
- areAllComponentsEmpty(data) {
675
- let res = true;
676
- if (this.subForm) {
677
- this.subForm.everyComponent((comp) => {
678
- const componentValue = _.get(data, comp.key);
679
- res &= comp.isEmpty(componentValue);
680
- });
681
- }
682
- else {
683
- res = false;
684
- }
685
- return res;
677
+ return value === null || _.isEqual(value, this.emptyValue);
686
678
  }
687
679
  getValue() {
688
680
  if (this.subForm) {
@@ -89,6 +89,7 @@ export default class SelectComponent extends ListComponent {
89
89
  disableInfiniteScroll(): void;
90
90
  set serverCount(value: any);
91
91
  get serverCount(): any;
92
+ shouldResetChoicesItems(items: any): boolean;
92
93
  setItems(items: any, fromSearch: any): void;
93
94
  selectItems: any;
94
95
  set downloadedResources(value: any);
@@ -126,7 +127,6 @@ export default class SelectComponent extends ListComponent {
126
127
  get isLoadingAvailable(): any;
127
128
  onScroll(): void;
128
129
  attachRefreshOnBlur(): void;
129
- addPlaceholderItem(placeholderValue: any): void;
130
130
  update(): void;
131
131
  addCurrentChoices(values: any, items: any, keyValue: any): any;
132
132
  getValueAsString(data: any, options: any): any;
@@ -360,6 +360,18 @@ export default class SelectComponent extends ListComponent {
360
360
  this.downloadedResources.serverCount = this.downloadedResources.length;
361
361
  this.serverCount = this.downloadedResources.length;
362
362
  }
363
+ shouldResetChoicesItems(items) {
364
+ if (this.choices._store.choices.length !== items.length) {
365
+ return true;
366
+ }
367
+ for (let item of items) {
368
+ const choicesItem = this.choices._store.choices.find((i) => i.label === item.label);
369
+ if (!choicesItem) {
370
+ return true;
371
+ }
372
+ }
373
+ return false;
374
+ }
363
375
  /* eslint-disable max-statements */
364
376
  setItems(items, fromSearch) {
365
377
  this.selectItems = items;
@@ -445,7 +457,7 @@ export default class SelectComponent extends ListComponent {
445
457
  this.addOption(itemValueAndLabel.value, itemValueAndLabel.label, {}, _.get(item, this.component.idPath, String(index)));
446
458
  });
447
459
  if (this.choices) {
448
- this.choices.setChoices(this.selectOptions, 'value', 'label', true);
460
+ this.choices.setChoices(this.selectOptions, 'value', 'label', true, true, !fromSearch && this.shouldResetChoicesItems(this.selectOptions));
449
461
  }
450
462
  else if (this.loading) {
451
463
  // Re-attach select input.
@@ -773,8 +785,8 @@ export default class SelectComponent extends ListComponent {
773
785
  removeItemButton: this.component.disabled ? false : _.get(this.component, 'removeItemButton', true),
774
786
  itemSelectText: '',
775
787
  classNames: {
776
- containerOuter: 'choices form-group formio-choices',
777
- containerInner: this.transform('class', 'form-control ui fluid selection dropdown')
788
+ containerOuter: ['choices', 'form-group', 'formio-choices'],
789
+ containerInner: this.transform('class', 'form-control ui fluid selection dropdown').split(' '),
778
790
  },
779
791
  addItemText: false,
780
792
  allowHTML: true,
@@ -802,6 +814,7 @@ export default class SelectComponent extends ListComponent {
802
814
  }),
803
815
  valueComparer: _.isEqual,
804
816
  resetScrollPosition: false,
817
+ duplicateItemsAllowed: false,
805
818
  ...customOptions,
806
819
  };
807
820
  }
@@ -934,12 +947,6 @@ export default class SelectComponent extends ListComponent {
934
947
  this.positionDropdown();
935
948
  });
936
949
  }
937
- if (this.choices && choicesOptions.placeholderValue && this.choices._isSelectOneElement) {
938
- this.addPlaceholderItem(choicesOptions.placeholderValue);
939
- this.addEventListener(input, 'removeItem', () => {
940
- this.addPlaceholderItem(choicesOptions.placeholderValue);
941
- });
942
- }
943
950
  // Add value options.
944
951
  this.addValueOptions();
945
952
  this.setChoicesValue(this.dataValue);
@@ -1025,20 +1032,6 @@ export default class SelectComponent extends ListComponent {
1025
1032
  });
1026
1033
  }
1027
1034
  }
1028
- addPlaceholderItem(placeholderValue) {
1029
- const items = this.choices._store.activeItems;
1030
- if (!items.length) {
1031
- this.choices._addItem({
1032
- value: '',
1033
- label: placeholderValue,
1034
- choiceId: 0,
1035
- groupId: -1,
1036
- customProperties: null,
1037
- placeholder: true,
1038
- keyCode: null
1039
- });
1040
- }
1041
- }
1042
1035
  /* eslint-enable max-statements */
1043
1036
  update() {
1044
1037
  if (this.component.dataSrc === 'custom') {
@@ -24,4 +24,4 @@ export default class TagsComponent extends Input {
24
24
  getValueAsString(value: any): any;
25
25
  }
26
26
  import Input from '../_classes/input/Input';
27
- import Choices from '@formio/choices.js';
27
+ import Choices from 'choices.js';
@@ -1,6 +1,6 @@
1
1
  import { componentValueTypes, getComponentSavedTypes } from '../../utils';
2
2
  import Input from '../_classes/input/Input';
3
- import Choices from '@formio/choices.js';
3
+ import Choices from 'choices.js';
4
4
  export default class TagsComponent extends Input {
5
5
  static schema(...extend) {
6
6
  return Input.schema({
@@ -127,7 +127,7 @@ export default class TagsComponent extends Input {
127
127
  const changed = super.setValue(value, flags);
128
128
  if (this.choices) {
129
129
  let dataValue = this.dataValue;
130
- this.choices.removeActiveItems();
130
+ this.choices.clearStore();
131
131
  if (dataValue) {
132
132
  if (typeof dataValue === 'string') {
133
133
  dataValue = dataValue.split(this.delimiter).filter(result => result);
@@ -56,6 +56,7 @@ export function registerModule(mod, defaultFn = null, options = {}) {
56
56
  case 'templates':
57
57
  for (const framework of Object.keys(mod.templates)) {
58
58
  Formio.Templates.extendTemplate(framework, mod.templates[framework]);
59
+ Formio.Templates.defaultTemplates = _.defaults(mod.templates[framework], Formio.Templates.defaultTemplates);
59
60
  }
60
61
  if (mod.templates[current]) {
61
62
  Formio.Templates.current = mod.templates[current];
@@ -1,38 +1,17 @@
1
- export namespace KEY_CODES {
2
- let BACK_KEY: number;
3
- let DELETE_KEY: number;
4
- let TAB_KEY: number;
5
- let ENTER_KEY: number;
6
- let A_KEY: number;
7
- let ESC_KEY: number;
8
- let UP_KEY: number;
9
- let DOWN_KEY: number;
10
- let PAGE_UP_KEY: number;
11
- let PAGE_DOWN_KEY: number;
12
- }
13
1
  export default ChoicesWrapper;
14
2
  declare class ChoicesWrapper extends Choices {
15
3
  constructor(...args: any[]);
16
- _onTabKey({ activeItems, hasActiveDropdown }: {
17
- activeItems: any;
18
- hasActiveDropdown: any;
19
- }): void;
4
+ _onTabKey(): void;
20
5
  isDirectionUsing: boolean;
21
6
  shouldOpenDropDown: boolean;
22
7
  _onTouchEnd(event: any): void;
23
- _handleButtonAction(activeItems: any, element: any): void;
24
- _onEnterKey(args: any): void;
8
+ _onEnterKey(...args: any[]): void;
25
9
  _onDirectionKey(...args: any[]): void;
26
10
  timeout: NodeJS.Timeout | undefined;
27
11
  _selectHighlightedChoice(): void;
28
12
  _onKeyDown(event: any): void;
29
- onSelectValue({ event, activeItems, hasActiveDropdown }: {
30
- event: any;
31
- activeItems: any;
32
- hasActiveDropdown: any;
33
- }): void;
13
+ onSelectValue(event: any, hasActiveDropdown: any): void;
34
14
  showDropdown(...args: any[]): void;
35
15
  hideDropdown(...args: any[]): void;
36
- _onBlur(...args: any[]): void;
37
16
  }
38
- import Choices from '@formio/choices.js';
17
+ import Choices from 'choices.js';
@@ -1,41 +1,7 @@
1
- import Choices from '@formio/choices.js';
2
- /**
3
- * TODO: REMOVE THIS ONCE THE PULL REQUEST HAS BEEN RESOLVED.
4
- *
5
- * https://github.com/jshjohnson/Choices/pull/788
6
- *
7
- * This is intentionally not part of the extended class, since other components use Choices and need this fix as well.
8
- * @type {Choices._generatePlaceholderValue}
9
- * @private
10
- */
11
- Choices.prototype._generatePlaceholderValue = function () {
12
- if (this._isSelectElement && this.passedElement.placeholderOption) {
13
- const { placeholderOption } = this.passedElement;
14
- return placeholderOption ? placeholderOption.text : false;
15
- }
16
- const { placeholder, placeholderValue } = this.config;
17
- const { element: { dataset }, } = this.passedElement;
18
- if (placeholder) {
19
- if (placeholderValue) {
20
- return placeholderValue;
21
- }
22
- if (dataset.placeholder) {
23
- return dataset.placeholder;
24
- }
25
- }
26
- return false;
27
- };
28
- export const KEY_CODES = {
29
- BACK_KEY: 46,
30
- DELETE_KEY: 8,
1
+ import Choices, { KeyCodeMap } from 'choices.js';
2
+ const ExtendedKeyCodeMap = {
3
+ ...KeyCodeMap,
31
4
  TAB_KEY: 9,
32
- ENTER_KEY: 13,
33
- A_KEY: 65,
34
- ESC_KEY: 27,
35
- UP_KEY: 38,
36
- DOWN_KEY: 40,
37
- PAGE_UP_KEY: 33,
38
- PAGE_DOWN_KEY: 34,
39
5
  };
40
6
  class ChoicesWrapper extends Choices {
41
7
  constructor(...args) {
@@ -63,24 +29,13 @@ class ChoicesWrapper extends Choices {
63
29
  }
64
30
  this._wasTap = true;
65
31
  }
66
- _handleButtonAction(activeItems, element) {
67
- if (!this._isSelectOneElement) {
68
- return super._handleButtonAction(activeItems, element);
69
- }
70
- if (!activeItems ||
71
- !element ||
72
- !this.config.removeItems ||
73
- !this.config.removeItemButton) {
74
- return;
75
- }
76
- super._handleButtonAction(activeItems, element);
77
- }
78
- _onEnterKey(args) {
32
+ _onEnterKey(...args) {
33
+ const [event] = args;
79
34
  // Prevent dropdown form opening when removeItemButton was pressed using 'Enter' on keyboard
80
- if (args.event.target.className === 'choices__button') {
35
+ if (event.target.className === 'choices__button') {
81
36
  this.shouldOpenDropDown = false;
82
37
  }
83
- super._onEnterKey(args);
38
+ super._onEnterKey(...args);
84
39
  }
85
40
  _onDirectionKey(...args) {
86
41
  if (!this._isSelectOneElement) {
@@ -94,17 +49,18 @@ class ChoicesWrapper extends Choices {
94
49
  this.isDirectionUsing = false;
95
50
  }, 250);
96
51
  }
97
- _onTabKey({ activeItems, hasActiveDropdown }) {
98
- if (hasActiveDropdown) {
99
- this._selectHighlightedChoice(activeItems);
52
+ _onTabKey() {
53
+ if (this.dropdown.isActive) {
54
+ this._selectHighlightedChoice();
100
55
  }
101
56
  }
102
57
  _selectHighlightedChoice() {
103
- const highlightedChoice = this.dropdown.getChild(`.${this.config.classNames.highlightedState}`);
58
+ const highlightedChoice = this.dropdown.element.querySelector(`.${this.config.classNames.highlightedState}`);
104
59
  if (highlightedChoice) {
105
60
  const id = highlightedChoice.dataset.id;
106
- const choice = id && this._store.getChoiceById(id);
61
+ const choice = id && this._store.getChoiceById(Number(id));
107
62
  this._addItem({
63
+ id: choice.id,
108
64
  value: choice.value,
109
65
  label: choice.label,
110
66
  choiceId: choice.id,
@@ -115,61 +71,16 @@ class ChoicesWrapper extends Choices {
115
71
  });
116
72
  this._triggerChange(choice.value);
117
73
  }
118
- event.preventDefault();
119
74
  }
120
75
  _onKeyDown(event) {
121
- if (!this._isSelectOneElement) {
122
- return super._onKeyDown(event);
123
- }
124
- const { target, keyCode, ctrlKey, metaKey } = event;
125
- if (target !== this.input.element &&
126
- !this.containerOuter.element.contains(target)) {
127
- return;
128
- }
129
- const activeItems = this._store.activeItems;
130
- const hasFocusedInput = this.input.isFocussed;
131
- const hasActiveDropdown = this.dropdown.isActive;
132
- const hasItems = this.itemList.hasChildren;
133
- const keyString = String.fromCharCode(keyCode);
134
- const { BACK_KEY, DELETE_KEY, TAB_KEY, ENTER_KEY, A_KEY, ESC_KEY, UP_KEY, DOWN_KEY, PAGE_UP_KEY, PAGE_DOWN_KEY, } = KEY_CODES;
135
- const hasCtrlDownKeyPressed = ctrlKey || metaKey;
136
- // If a user is typing and the dropdown is not active
137
- if (!hasActiveDropdown && !this._isTextElement && /[a-zA-Z0-9-_ ]/.test(keyString)) {
138
- const currentValue = this.input.element.value;
139
- this.input.element.value = currentValue ? `${currentValue}${keyString}` : keyString;
140
- this.showDropdown();
141
- }
142
- // Map keys to key actions
143
- const keyDownActions = {
144
- [A_KEY]: this._onAKey,
145
- [TAB_KEY]: this._onTabKey,
146
- [ENTER_KEY]: this._onEnterKey,
147
- [ESC_KEY]: this._onEscapeKey,
148
- [UP_KEY]: this._onDirectionKey,
149
- [PAGE_UP_KEY]: this._onDirectionKey,
150
- [DOWN_KEY]: this._onDirectionKey,
151
- [PAGE_DOWN_KEY]: this._onDirectionKey,
152
- [DELETE_KEY]: this._onDeleteKey,
153
- [BACK_KEY]: this._onDeleteKey,
154
- };
155
- // If keycode has a function, run it
156
- if (keyDownActions[keyCode]) {
157
- keyDownActions[keyCode]({
158
- event,
159
- target,
160
- keyCode,
161
- metaKey,
162
- activeItems,
163
- hasFocusedInput,
164
- hasActiveDropdown,
165
- hasItems,
166
- hasCtrlDownKeyPressed,
167
- });
168
- }
76
+ const keyCode = event.keyCode;
77
+ return this._isSelectOneElement && keyCode === ExtendedKeyCodeMap.TAB_KEY
78
+ ? this._onTabKey()
79
+ : super._onKeyDown(event);
169
80
  }
170
- onSelectValue({ event, activeItems, hasActiveDropdown }) {
81
+ onSelectValue(event, hasActiveDropdown) {
171
82
  if (hasActiveDropdown) {
172
- this._selectHighlightedChoice(activeItems);
83
+ this._selectHighlightedChoice();
173
84
  }
174
85
  else if (this._isSelectOneElement) {
175
86
  this.showDropdown();
@@ -177,11 +88,13 @@ class ChoicesWrapper extends Choices {
177
88
  }
178
89
  }
179
90
  showDropdown(...args) {
180
- if (!this.shouldOpenDropDown) {
181
- this.shouldOpenDropDown = true;
182
- return;
183
- }
184
- super.showDropdown(...args);
91
+ setTimeout(() => {
92
+ if (!this.shouldOpenDropDown) {
93
+ this.shouldOpenDropDown = true;
94
+ return;
95
+ }
96
+ super.showDropdown(...args);
97
+ }, 0);
185
98
  }
186
99
  hideDropdown(...args) {
187
100
  if (this.isDirectionUsing) {
@@ -189,11 +102,5 @@ class ChoicesWrapper extends Choices {
189
102
  }
190
103
  super.hideDropdown(...args);
191
104
  }
192
- _onBlur(...args) {
193
- if (this._isScrollingOnIe) {
194
- return;
195
- }
196
- super._onBlur(...args);
197
- }
198
105
  }
199
106
  export default ChoicesWrapper;
@@ -26,8 +26,8 @@ export const getBestMatch: typeof Utils.getBestMatch;
26
26
  export const getComponentFromPath: typeof Utils.getComponentFromPath;
27
27
  export const getComponentValue: typeof Utils.getComponentValue;
28
28
  export const findComponents: typeof Utils.findComponents;
29
- export const eachComponentDataAsync: (components: import("@formio/core").Component[], data: import("@formio/core").DataObject, fn: import("@formio/core").EachComponentDataAsyncCallback, includeAll?: boolean | undefined, local?: boolean | undefined, parent?: import("@formio/core").Component | undefined, parentPaths?: import("@formio/core").ComponentPaths | undefined) => Promise<void>;
30
- export const eachComponentData: (components: import("@formio/core").Component[], data: import("@formio/core").DataObject, fn: import("@formio/core").EachComponentDataCallback, includeAll?: boolean | undefined, local?: boolean | undefined, parent?: import("@formio/core").Component | undefined, parentPaths?: import("@formio/core").ComponentPaths | undefined) => void;
29
+ export const eachComponentDataAsync: (components: import("@formio/core").Component[], data: import("@formio/core").DataObject, fn: import("@formio/core").EachComponentDataAsyncCallback, includeAll?: boolean | undefined, local?: boolean | undefined, parent?: import("@formio/core").Component | undefined, parentPaths?: import("@formio/core").ComponentPaths | undefined, noScopeReset?: boolean | undefined) => Promise<void>;
30
+ export const eachComponentData: (components: import("@formio/core").Component[], data: import("@formio/core").DataObject, fn: import("@formio/core").EachComponentDataCallback, includeAll?: boolean | undefined, local?: boolean | undefined, parent?: import("@formio/core").Component | undefined, parentPaths?: import("@formio/core").ComponentPaths | undefined, noScopeReset?: boolean | undefined) => void;
31
31
  export const getComponentKey: typeof Utils.getComponentKey;
32
32
  export const getContextualRowPath: typeof Utils.getContextualRowPath;
33
33
  export const getContextualRowData: typeof Utils.getContextualRowData;