@avakhula/ui 0.1.20 → 0.1.21

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 (86) hide show
  1. package/dist/index.css +1 -0
  2. package/dist/index.js +13675 -12688
  3. package/dist/index.umd.cjs +92 -84
  4. package/package.json +6 -5
  5. package/src/assets/scss/mixins/dropdown-list-item.scss +3 -3
  6. package/src/assets/scss/mixins/tooltip-position.scss +7 -0
  7. package/src/assets/scss/mixins.scss +2 -2
  8. package/src/assets/scss/style.scss +4 -4
  9. package/src/components/Accordion/Accordion.scss +3 -3
  10. package/src/components/Accordion/Accordion.vue +2 -2
  11. package/src/components/Alert/Alert.vue +1 -1
  12. package/src/components/Alert/alert.scss +2 -2
  13. package/src/components/Avatar/Avatar.vue +2 -2
  14. package/src/components/Badge/Badge.vue +2 -2
  15. package/src/components/Breadcrumbs/Breadcrumbs.vue +7 -2
  16. package/src/components/Breadcrumbs/breadcrumbs.scss +5 -5
  17. package/src/components/Button/Button.vue +2 -2
  18. package/src/components/Button/button.scss +3 -3
  19. package/src/components/Chips/Chips.vue +3 -3
  20. package/src/components/Dropdown/Dropdown.spec.js +0 -0
  21. package/src/components/Dropdown/Dropdown.vue +104 -27
  22. package/src/components/Dropdown/DropdownDivider.vue +1 -1
  23. package/src/components/Dropdown/DropdownItem.vue +1 -1
  24. package/src/components/Dropdown/DropdownList.vue +11 -1
  25. package/src/components/Form/CharactersCount.vue +2 -2
  26. package/src/components/Form/Checkbox/Checkbox.scss +4 -4
  27. package/src/components/Form/Checkbox/Checkbox.vue +1 -1
  28. package/src/components/Form/DatePicker/DatePicker.scss +4 -4
  29. package/src/components/Form/DatePicker/DatePicker.vue +1 -1
  30. package/src/components/Form/FormGroup/FormGroup.vue +2 -2
  31. package/src/components/Form/FormGroup/FormGroupSet.vue +1 -1
  32. package/src/components/Form/Input/Input.vue +7 -4
  33. package/src/components/Form/Input/input.scss +3 -3
  34. package/src/components/Form/Label/Label.vue +2 -2
  35. package/src/components/Form/PhoneInput/PhoneInput.vue +56 -21
  36. package/src/components/Form/PhoneInput/phoneInput.scss +4 -4
  37. package/src/components/Form/Radio/Radio.vue +1 -1
  38. package/src/components/Form/Radio/radio.scss +3 -3
  39. package/src/components/Form/TextEditor/TextEditor.vue +27 -168
  40. package/src/components/Form/TextEditor/Toolbar.vue +723 -0
  41. package/src/components/Form/TextEditor/icons/toolbarIcons.js +8 -0
  42. package/src/components/Form/TextEditor/plugins/imageBlot.js +23 -0
  43. package/src/components/Form/TextEditor/setupTextEditor.js +71 -0
  44. package/src/components/Form/TextEditor/textEditor.scss +9 -357
  45. package/src/components/Form/Textarea/Textarea.spec.js +0 -0
  46. package/src/components/Form/Textarea/Textarea.vue +2 -1
  47. package/src/components/Form/Textarea/textarea.scss +3 -3
  48. package/src/components/Form/Toggle/Toggle.vue +1 -1
  49. package/src/components/Form/Toggle/toggle.scss +3 -3
  50. package/src/components/IconButton/IconButton.scss +2 -2
  51. package/src/components/IconButton/IconButton.vue +6 -4
  52. package/src/components/List.vue +1 -1
  53. package/src/components/Modal/Modal.vue +85 -49
  54. package/src/components/Pagination/Pagination.vue +28 -3
  55. package/src/components/Pagination/pagination.scss +20 -4
  56. package/src/components/Panel/Panel.vue +4 -4
  57. package/src/components/Popover/Popover.vue +7 -2
  58. package/src/components/Popover/popover.scss +3 -3
  59. package/src/components/ProgressBar/ProgressBar.vue +1 -1
  60. package/src/components/ProgressBar/progressBar.scss +1 -1
  61. package/src/components/Sorting/Sorting.vue +1 -1
  62. package/src/components/Sorting/sorting.scss +5 -5
  63. package/src/components/SplitButton/SplitButton.vue +1 -1
  64. package/src/components/SplitButton/SplitButtonItem.vue +1 -1
  65. package/src/components/SplitButton/splitButton.scss +3 -3
  66. package/src/components/StatusIndicator/StatusIndicator.vue +2 -2
  67. package/src/components/Table/Cells/Cell.vue +2 -2
  68. package/src/components/Table/Cells/CheckboxCell.vue +0 -0
  69. package/src/components/Table/Row.vue +1 -1
  70. package/src/components/Table/Table.stories.js +0 -0
  71. package/src/components/Table/Table.vue +0 -0
  72. package/src/components/Tabs/TabDropdown.vue +1 -1
  73. package/src/components/Tabs/Tabs.vue +9 -5
  74. package/src/components/Tabs/tabs.scss +4 -4
  75. package/src/components/TagPill/TagPill.vue +2 -2
  76. package/src/components/ToggleTip/ToggleTip.vue +1 -1
  77. package/src/components/ToggleTip/toggleTip.scss +5 -5
  78. package/src/components/Tooltip/Tooltip.vue +3 -3
  79. package/src/components/TreeSelect/Option.vue +16 -14
  80. package/src/components/TreeSelect/Select.vue +199 -132
  81. package/src/components/TreeSelect/scss/option.scss +6 -6
  82. package/src/components/TreeSelect/scss/select.scss +53 -4
  83. package/src/directives/tooltip/tooltip.js +46 -0
  84. package/src/index.js +6 -1
  85. package/vite.config.js +0 -0
  86. package/dist/style.css +0 -1
@@ -9,7 +9,8 @@
9
9
  :aria-label="option.title"
10
10
  :id="'option-' + id"
11
11
  :class="{
12
- 'tree-select-option-checked': isChecked(option),
12
+ 'tree-select-option-checked': option.checked,
13
+ 'tree-select-option-indeterminate': isChecked(option) === null,
13
14
  'tree-select-option-margin': hasVisibleChildren,
14
15
  active: option.isChildrenVisible,
15
16
  'is-multiple': isMultiple,
@@ -25,7 +26,7 @@
25
26
  :disabled-focus="true"
26
27
  kind="ghost"
27
28
  class="toggle-children"
28
- @click="toggleChildrenVisibility"
29
+ @click.prevent="toggleChildrenVisibility"
29
30
  v-show="hasVisibleChildren"
30
31
  >
31
32
  <ib-icon :name="iconName"></ib-icon>
@@ -279,12 +280,11 @@ export default {
279
280
  allChildrenSelected =
280
281
  childrenSelectedCount >= this.option.children.length;
281
282
 
282
- if (
283
- (!this.option.checked && allChildrenSelected && this.parentAutoCheck) ||
284
- (this.option.checked && !allChildrenSelected)
285
- ) {
286
- this.toggle(!this.option.checked, false);
287
- }
283
+ if (!this.option.checked && allChildrenSelected || this.option.checked && !allChildrenSelected) {
284
+ if (this.parentAutoCheck) {
285
+ this.toggle(!this.option.checked, false);
286
+ }
287
+ }
288
288
  },
289
289
  calculateChildren(option, filter, checkNested = false) {
290
290
  let count = 0;
@@ -304,12 +304,14 @@ export default {
304
304
  },
305
305
  isChecked(option) {
306
306
  if(this.hasChildren) {
307
- if (this.childrenSelectedCount === this.countOfAllChildren) {
308
- return true;
309
- }
310
307
 
311
- if (this.childrenSelectedCount > 0 && this.countOfAllChildren > this.childrenSelectedCount) {
312
- return null; //null will trigger indeterminate stage
308
+ const childrenSelectedCount = this.childrenSelectedCount;
309
+
310
+ if (childrenSelectedCount > 0 && this.countOfAllChildren > childrenSelectedCount
311
+ || (!childrenSelectedCount && this.option.checked && !this.parentAutoCheck)
312
+ || (this.countOfAllChildren == childrenSelectedCount && !this.option.checked && !this.parentAutoCheck)
313
+ ) {
314
+ return null;
313
315
  }
314
316
  }
315
317
 
@@ -368,5 +370,5 @@ export default {
368
370
  };
369
371
  </script>
370
372
  <style lang="scss">
371
- @import "./scss/option.scss";
373
+ @use "./scss/option.scss" as *;
372
374
  </style>
@@ -7,7 +7,7 @@
7
7
  v-bind="Object.fromEntries(Object.entries($attrs).filter(([key]) => key.startsWith('data-')))"
8
8
  class="tree-select"
9
9
  :class="{
10
- ...classList, 'tree-select-custom-trigger-content': hasTriggerContent
10
+ ...classList, 'tree-select-custom-trigger-content': hasTriggerContent, 'disabled-parent-autocheck': parentAutoCheck === false
11
11
  }"
12
12
  >
13
13
  <ib-dropdown
@@ -22,7 +22,7 @@
22
22
  @open="onOpen"
23
23
  >
24
24
  <template v-if="hasTrigger" v-slot:trigger>
25
- <slot v-bind:selected-count="selectedKeys.length" name="trigger"></slot>
25
+ <slot v-bind:selected-count="selectedKeys.length" v-bind:is-open="isOpen" name="trigger"></slot>
26
26
  </template>
27
27
 
28
28
  <template v-else v-slot:trigger="{ isOpened }">
@@ -82,8 +82,15 @@
82
82
  :name="isOpened ? 'chevron-up-outline' : 'chevron-down-outline'"
83
83
  :classes="'tree-select-caret'"
84
84
  />
85
- </div>
86
85
 
86
+ <input
87
+ v-for="id in selectedKeys"
88
+ type="hidden"
89
+ :key="'hidden-'+id"
90
+ :name="actualName"
91
+ :value="id"
92
+ />
93
+ </div>
87
94
  </template>
88
95
 
89
96
  <template v-slot:body>
@@ -109,14 +116,15 @@
109
116
  class="tree-search"
110
117
  v-if="showSearch"
111
118
  ref="search"
112
- autocomplete="off"
119
+ autocomplete="new-password"
113
120
  :show-icon="true"
114
121
  :value="filterString"
115
122
  :debounce="searchDebounce"
116
123
  :aria-label="
117
124
  searchPlaceholderText
118
125
  ? searchPlaceholderText
119
- : actualStrings.searchPlaceholder"
126
+ : actualStrings.searchPlaceholder
127
+ "
120
128
  :placeholder="
121
129
  searchPlaceholderText
122
130
  ? searchPlaceholderText
@@ -145,6 +153,7 @@
145
153
  >
146
154
  <slot name="emptyMessage"></slot>
147
155
  </div>
156
+
148
157
  <div
149
158
  v-else-if="!requiredDependencyNotFilled && !visibleOptionsCount"
150
159
  class="tree-select-default-empty tree-select-empty"
@@ -165,7 +174,7 @@
165
174
  checked: isEmpty,
166
175
  }"
167
176
  :name="actualName"
168
- :parent-auto-check="parentAutoCheck"
177
+ :parent-auto-check="parentAutoCheckVal"
169
178
  :is-multiple="isMultiple"
170
179
  role="option"
171
180
  @check="registerCheck"
@@ -176,7 +185,7 @@
176
185
  ></select-option>
177
186
  </template>
178
187
 
179
- <template v-if="Object.keys(actualBookmarkedOptions).length > 0">
188
+ <template v-if="Object.keys(actualBookmarkedOptions).length > 0">
180
189
  <select-option
181
190
  :key="'bookmark' + option.id"
182
191
  v-for="option in actualBookmarkedOptions"
@@ -197,6 +206,7 @@
197
206
  </template>
198
207
 
199
208
  <template v-if="!requiredDependencyNotFilled">
209
+ <div class="scrollable-container">
200
210
  <template
201
211
  v-if="
202
212
  allOptions &&
@@ -209,7 +219,6 @@
209
219
  <select-option
210
220
  :option="{
211
221
  title: actualStrings.selectAllOptions,
212
- id: '!all!',
213
222
  initiallyVisible: true,
214
223
  visible: true,
215
224
  isDisabled: visibleOptionsCount < optionsCount,
@@ -219,7 +228,6 @@
219
228
  : false,
220
229
  }"
221
230
  :is-toggle="isToggle"
222
- :name="actualName"
223
231
  :parent-auto-check="false"
224
232
  :is-multiple="isMultiple"
225
233
  :is-bookmarkable="false"
@@ -229,44 +237,54 @@
229
237
  :alphabetic-style="alphabeticStyle"
230
238
  role="option"
231
239
  @check="manageAll"
232
- @on-focus="(id) => focusedOptionId = id"
240
+ @on-focus="(id) => (focusedOptionId = id)"
233
241
  ></select-option>
234
242
  </template>
235
243
 
236
- <template
237
- v-for="option in actualOptions"
238
- :key="name + option.value"
239
- >
240
- <slot
241
- :option="option"
242
- :name="actualName"
243
- :parent-auto-check="parentAutoCheck"
244
- :is-multiple="isMultiple"
245
- :uid="uid"
246
- :only-end-nodes="onlyEndNodes"
247
- :html-title="htmlOptionTitle"
248
- :show-input="showInputs"
244
+ <div ref="parentRef">
245
+ <div
246
+ :style="{
247
+ height: virtualizer?.getTotalSize() + 'px',
248
+ position: 'relative',
249
+ }"
249
250
  >
250
- <select-option
251
- v-show="option.visible"
252
- :option="option"
253
- :is-toggle="isToggle"
254
- :name="actualName"
255
- role="option"
256
- :parent-auto-check="parentAutoCheck"
257
- :is-multiple="isMultiple"
258
- :is-bookmarkable="isBookmarkable"
259
- :uid="uid"
260
- :only-end-nodes="onlyEndNodes"
261
- :html-title="htmlOptionTitle"
262
- :show-input="showInputs"
263
- :alphabetic-style="alphabeticStyle"
264
- @check="registerCheck"
265
- @toggle-bookmark="toggleBookmark"
266
- @on-focus="(id) => focusedOptionId = id"
267
- ></select-option>
268
- </slot>
269
- </template>
251
+ <div
252
+ v-for="virtualRow in virtualizer?.getVirtualItems()"
253
+ :key="virtualRow.index"
254
+ :data-index="virtualRow.index"
255
+ :ref="virtualizer.measureElement"
256
+ :style="{
257
+ position: 'absolute',
258
+ top: 0,
259
+ left: 0,
260
+ width: '100%',
261
+ transform: `translateY(${virtualRow.start}px)`,
262
+ }"
263
+ >
264
+ <select-option
265
+ v-if="actualOptions[virtualRow.index]"
266
+ v-show="actualOptions[virtualRow.index].visible && !actualOptions[virtualRow.index].hidden"
267
+ :option="actualOptions[virtualRow.index]"
268
+ :is-toggle="isToggle"
269
+ :name="actualName"
270
+ role="option"
271
+ :parent-auto-check="parentAutoCheckVal"
272
+ :is-multiple="isMultiple"
273
+ :is-bookmarkable="isBookmarkable"
274
+ :uid="uid"
275
+ :only-end-nodes="onlyEndNodes"
276
+ :html-title="htmlOptionTitle"
277
+ :show-input="showInputs"
278
+ :alphabetic-style="alphabeticStyle"
279
+ @check="registerCheck"
280
+ @toggle-bookmark="toggleBookmark"
281
+ @on-focus="(id) => focusedOptionId = id"
282
+ ></select-option>
283
+ </div>
284
+ </div>
285
+ </div>
286
+ </div>
287
+
270
288
  </template>
271
289
 
272
290
  <div v-if="infiniteLoader" ref="infinityLoader"></div>
@@ -278,7 +296,7 @@
278
296
  </template>
279
297
 
280
298
  <script>
281
- // <!-- TODO: use constants for vertical position -->
299
+ import { useVirtualizer } from "@tanstack/vue-virtual";
282
300
  import IbInput from "../Form/Input/Input.vue";
283
301
  import Option from "./Option.vue";
284
302
  import Mark from "mark.js/dist/mark.es6.min";
@@ -369,7 +387,7 @@ export default {
369
387
  },
370
388
  parentAutoCheck: {
371
389
  type: Boolean,
372
- default: true,
390
+ default: null,
373
391
  },
374
392
  strings: {
375
393
  type: Object,
@@ -484,9 +502,15 @@ export default {
484
502
  },
485
503
  modelValue: {
486
504
  handler(value) {
487
- this.val = value;
488
- this.actualOptions = [];
489
- this.setPreparedValues();
505
+ if (this.isInternalChange) return;
506
+
507
+ this.val = value;
508
+ this.val = value;
509
+ if (!Array.isArray(value) || value.join(',') !== Object.keys(this.selected).join(',')) {
510
+ this.setPreparedValues(this.actualOptions, false);
511
+ }
512
+ const selectedSet = new Set(Array.isArray(value) ? value : [value].filter(Boolean));
513
+ this.syncCheckedBySet(selectedSet);
490
514
  },
491
515
  deep: true,
492
516
  },
@@ -569,9 +593,12 @@ export default {
569
593
  if (filterString && this.keywordHighlighter) {
570
594
  this.marker.mark(filterString);
571
595
  }
596
+
597
+ this.virtualizer?.measure();
572
598
  }, 1000);
573
599
 
574
600
  return {
601
+ virtualizer: null,
575
602
  initialOptions: typeof this.options === "function" ? this.options : copy(this.options),
576
603
  val: this.modelValue ? this.modelValue : this.value,
577
604
  size: {
@@ -580,14 +607,15 @@ export default {
580
607
  },
581
608
  resizingProp: null,
582
609
  isInitialized: false,
583
- optionsIdsWatch: [],
584
610
  isLoading: false,
611
+ isOpen: false,
612
+ optionsIdsWatch: [],
585
613
  actualName: this.isMultiple ? this.name + "[]" : this.name,
614
+ parentAutoCheckVal: this.parentAutoCheck !== null ? this.parentAutoCheck : this.isMultiple,
586
615
  filterString: "",
587
616
  actualOptions: [],
588
617
  actualBookmarkedOptions: {},
589
618
  selected: [],
590
- isOpen: false,
591
619
  verticalVal: this.vertical ?? "bottom",
592
620
  allOptionsIsChecked: true,
593
621
  hasTreeChildren: false,
@@ -633,9 +661,38 @@ export default {
633
661
  ...this.strings,
634
662
  },
635
663
  dependencyValue: null,
664
+ isInternalChange: false,
665
+ nodeIndex: new Map()
636
666
  };
637
667
  },
638
668
  methods: {
669
+ toggleDuplicateOptionsFast(optionId, checked) {
670
+ const arr = this.nodeIndex.get(optionId);
671
+ if (!arr) return;
672
+ for (const node of arr) node.checked = checked;
673
+ },
674
+ buildNodeIndex() {
675
+ this.nodeIndex.clear();
676
+ this.traverseTree(this.actualOptions, (node) => {
677
+ if (!this.nodeIndex.has(node.id)) this.nodeIndex.set(node.id, []);
678
+ this.nodeIndex.get(node.id).push(node);
679
+ });
680
+ },
681
+ syncCheckedBySet(selectedSet) {
682
+ this.traverseTree(this.actualOptions, (opt) => {
683
+ const shouldBeChecked = selectedSet.has(opt.id);
684
+ if (opt.checked !== shouldBeChecked) opt.checked = shouldBeChecked;
685
+ });
686
+
687
+ this.selected = {};
688
+ this.traverseTree(this.actualOptions, (opt) => {
689
+ if (opt.checked && (!this.onlyEndNodes || !opt.children)) {
690
+ this.selected[opt.id] = opt;
691
+ }
692
+ });
693
+
694
+ this.allOptionsIsChecked = this.checkIfOptionsChecked(this.actualOptions);
695
+ },
639
696
  onBlur() {
640
697
  setTimeout(() => {
641
698
  if (!this.isOpen) {
@@ -658,7 +715,7 @@ export default {
658
715
  this.$refs.combobox.focus();
659
716
  },
660
717
  focusOnFirstOptions() {
661
- this.$refs.list.$el.querySelector('[tabindex]:not(hidden)').focus();
718
+ this.$refs.list.$el.querySelector("[tabindex]:not(hidden)").focus();
662
719
  },
663
720
  startResizing(prop) {
664
721
  this.resizingProp = prop;
@@ -681,18 +738,11 @@ export default {
681
738
  },
682
739
  registerDependency(oldDependency) {
683
740
  if (this.dependency) {
684
- this.$globalEvents.$on(
685
- "select-" + this.dependency + ":update",
686
- (dependencyValue) => {
687
- this.clear();
741
+ this.$globalEvents.$on("select-" + this.dependency + ":update", (dependencyValue) => {
742
+ this.clear();
688
743
  this.dependencyValue = dependencyValue;
689
744
 
690
- if (
691
- this.dependencyValue &&
692
- this.dependencyValue.values &&
693
- (!Array.isArray(this.dependencyValue.values) ||
694
- this.dependencyValue.values.length)
695
- ) {
745
+ if (this.dependencyValue && this.dependencyValue.values && (!Array.isArray(this.dependencyValue.values) || this.dependencyValue.values.length)) {
696
746
  this.setPreparedValues();
697
747
  }
698
748
  }
@@ -722,35 +772,33 @@ export default {
722
772
  );
723
773
  }
724
774
 
725
- return this.prepare(options).then(([options, selected]) => {
726
- this.actualOptions = options;
727
- this.allOptionsIsChecked = this.checkIfOptionsChecked(options);
728
- this.isInitialized = true;
729
- this.selected = selected;
730
- this.setBookmarkedOptions(options);
731
- });
775
+ return this.prepare(options).then(([options, selected]) => {
776
+ this.actualOptions = options;
777
+ this.buildNodeIndex();
778
+ this.allOptionsIsChecked = this.checkIfOptionsChecked(options);
779
+ this.isInitialized = true;
780
+ this.selected = selected;
781
+ this.setBookmarkedOptions(options);
782
+ });
732
783
  },
733
784
  clear() {
734
- this.setPreparedValues();
785
+ this.actualOptions = [];
735
786
  this.allOptionsIsChecked = false;
787
+ this.countVisibleChildren = 0;
736
788
  this.selected = [];
737
-
738
- if (this.isMultiple) {
739
- this.$emit("update:modelValue", null);
740
- this.$emit("input", null);
741
- this.$emit("clear-value", null);
742
-
743
- } else {
744
- this.$emit("update:modelValue", []);
745
- this.$emit("input", []);
746
- this.$emit("clear-value", []);
747
- }
748
-
749
- this.setPreparedValues();
750
789
  },
751
790
  clearValue() {
752
- this.clear();
753
- this.setPreparedValues();
791
+ this.traverseTree(this.actualOptions, (opt) => (opt.checked = false));
792
+ this.clear();
793
+
794
+ this.isInternalChange = true;
795
+ const empty = this.isMultiple ? [] : null;
796
+
797
+ this.$emit("update:modelValue", empty);
798
+ this.$emit("input", empty);
799
+ this.$emit("clear-value", empty);
800
+ this.$nextTick(() => (this.isInternalChange = false));
801
+ this.setPreparedValues();
754
802
  },
755
803
  prepare(options, checkInitialVisibility = true) {
756
804
  return new Promise((res) => {
@@ -804,8 +852,10 @@ export default {
804
852
  ([preparedChildren, selectedChildren]) => {
805
853
  option.children = preparedChildren;
806
854
 
807
- if (this.parentAutoCheck) {
808
- option.checked = this.checkIfOptionsChecked(option.children);
855
+ if (this.parentAutoCheckVal) {
856
+ option.checked = this.checkIfOptionsChecked(
857
+ option.children
858
+ );
809
859
  }
810
860
 
811
861
  Object.assign(selected, selectedChildren);
@@ -841,8 +891,12 @@ export default {
841
891
  visibleOptionsCount += visibleChildrenCount;
842
892
 
843
893
  if (visibleChildrenCount) {
844
- option.isChildrenVisible = filterString.length > 0 || Boolean(Object.keys(this.actualBookmarkedOptions).length);
845
- option.isDisabled = visibleChildrenCount < option.children.length && !this.isBookmarkable;
894
+ option.isChildrenVisible =
895
+ filterString.length > 0 ||
896
+ Boolean(Object.keys(this.actualBookmarkedOptions).length);
897
+ option.isDisabled =
898
+ visibleChildrenCount < option.children.length &&
899
+ !this.isBookmarkable;
846
900
  }
847
901
 
848
902
  if (!isVisible) {
@@ -870,57 +924,52 @@ export default {
870
924
  this.$emit("submit");
871
925
  },
872
926
  change() {
873
- const values = Object.keys(this.selected);
874
- if (this.isMultiple) {
875
- this.$emit("update:modelValue", values);
876
- this.$emit("input", values);
877
- } else {
878
- this.$emit("update:modelValue", values[0]);
879
- this.$emit("input", values[0]);
880
- }
881
- this.$globalEvents.$emit("select-" + this.filterId + ":update", {
882
- values,
883
- filter: this.filterId,
884
- });
885
- this.$refs.dropdown.close();
927
+ const values = Object.keys(this.selected);
928
+ this.isInternalChange = true;
929
+ if (this.isMultiple) {
930
+ this.$emit("update:modelValue", values);
931
+ this.$emit("input", values);
932
+ } else {
933
+ this.$emit("update:modelValue", values[0]);
934
+ this.$emit("input", values[0]);
935
+ }
936
+ this.$nextTick(() => (this.isInternalChange = false));
937
+ this.$globalEvents.$emit("select-" + this.filterId + ":update", { values, filter: this.filterId });
938
+ if (!this.isMultiple) this.$refs.dropdown.close();
886
939
  },
887
940
  checkIfOptionsChecked(options) {
888
941
  return options.every((option) => option.checked || option.readonly);
889
942
  },
890
943
  registerCheck(option, isChecked, isDirectChild) {
891
- if (isChecked) {
892
- option.checked = true;
893
- if (this.isMultiple) {
894
- if (
895
- !(this.onlyEndNodes && option.children && option.children.length)
896
- ) {
944
+ if (isChecked) {
945
+ option.checked = true;
946
+ if (this.isMultiple && !(this.onlyEndNodes && option.children?.length)) {
897
947
  this.selected[option.id] = option;
898
- this.$emit("update:modelValue", Object.keys(this.selected));
899
- this.$emit("input", Object.keys(this.selected));
948
+ } else if (!this.isMultiple) {
949
+ const prev = Object.keys(this.selected)[0];
950
+ if (prev) this.selected[prev].checked = false;
951
+ this.selected = { [option.id]: option };
952
+ this.change();
953
+ return;
900
954
  }
901
955
  } else {
902
- const selectedOptionKey = Object.keys(this.selected)[0];
956
+ delete this.selected[option.id];
957
+ option.checked = false;
958
+ }
903
959
 
904
- if (selectedOptionKey) {
905
- this.selected[selectedOptionKey].checked = false;
906
- }
960
+ this.toggleDuplicateOptionsFast(option.id, isChecked);
907
961
 
908
- this.selected = { [option.id]: option };
909
- this.change();
962
+ if (isDirectChild) {
963
+ this.allOptionsIsChecked = this.checkIfOptionsChecked(this.actualOptions);
910
964
  }
911
- } else {
912
- delete this.selected[option.id];
913
- option.checked = false;
914
- this.$emit("update:modelValue", Object.keys(this.selected));
915
- this.$emit("input", Object.keys(this.selected));
916
- }
917
965
 
918
- this.toggleDuplicateOptions(this.actualOptions, option.id, isChecked);
919
- if (isDirectChild) {
920
- this.allOptionsIsChecked = this.checkIfOptionsChecked(
921
- this.actualOptions
922
- );
923
- }
966
+ if (this.isMultiple) {
967
+ this.isInternalChange = true;
968
+ const values = Object.keys(this.selected);
969
+ this.$emit("update:modelValue", values);
970
+ this.$emit("input", values);
971
+ this.$nextTick(() => (this.isInternalChange = false));
972
+ }
924
973
  },
925
974
  toggleDuplicateOptions(options, optionId, checked) {
926
975
  for (let opt of options) {
@@ -990,6 +1039,7 @@ export default {
990
1039
  } else {
991
1040
  this.$emit("close", Object.keys(this.selected)[0]);
992
1041
  }
1042
+ this.virtualizer = null;
993
1043
  this.$emit("blur");
994
1044
  this.verticalVal = this.vertical ?? "bottom";
995
1045
  },
@@ -997,6 +1047,17 @@ export default {
997
1047
  const screenHeight = document.documentElement.scrollHeight;
998
1048
  this.isOpen = true;
999
1049
 
1050
+
1051
+ if (!this.virtualizer) {
1052
+ this.virtualizer = useVirtualizer({
1053
+ count: this.actualOptions.length,
1054
+ getScrollElement: () => this.$refs.parentRef,
1055
+ estimateSize: () => 40,
1056
+ overscan: 8,
1057
+ });
1058
+ }
1059
+ this.virtualizer?.measure();
1060
+
1000
1061
  if (this.vertical === "bottom") return;
1001
1062
 
1002
1063
  this.$nextTick(() => {
@@ -1005,7 +1066,7 @@ export default {
1005
1066
  this.verticalVal = "top";
1006
1067
  }
1007
1068
  })
1008
- }
1069
+ },
1009
1070
  },
1010
1071
  computed: {
1011
1072
  hasTrigger() {
@@ -1045,7 +1106,7 @@ export default {
1045
1106
  }
1046
1107
  });
1047
1108
  },
1048
- selectStatus() {
1109
+ selectStatus() {
1049
1110
  if (this.staticPlaceholder) {
1050
1111
  return this.placeholder;
1051
1112
  } else if (this.isLoading) {
@@ -1056,7 +1117,7 @@ export default {
1056
1117
  return this.selectedKeys
1057
1118
  .map((key) => this.selected[key].title)
1058
1119
  .join(",");
1059
- } else if (this.selectedKeys.length < this.optionsCount) {
1120
+ } else if (!this.allOptionsIsChecked) {
1060
1121
  return this.actualStrings.selectedCount
1061
1122
  .replace("{selected}", this.selectedKeys.length)
1062
1123
  .replace("{all}", this.optionsCount);
@@ -1076,7 +1137,7 @@ export default {
1076
1137
  );
1077
1138
  },
1078
1139
  showSearch() {
1079
- return this.useSearch || (this.optionsCount > 10 && !this.alphabeticStyle);
1140
+ return (this.useSearch || (this.optionsCount > 10 && !this.alphabeticStyle));
1080
1141
  },
1081
1142
  arrayOfOptions() {
1082
1143
  return this.getArrayOptions(this.actualOptions);
@@ -1134,7 +1195,13 @@ export default {
1134
1195
  };
1135
1196
  </script>
1136
1197
  <style lang="scss">
1137
- @import "./scss/select.scss";
1198
+ @use "./scss/select.scss" as *;
1199
+ @use "../../assets/scss/variables/colors.scss" as *;
1200
+
1201
+ .scrollable-container {
1202
+ overflow: auto;
1203
+ max-height: 300px;
1204
+ }
1138
1205
 
1139
1206
  .bookmarked-option {
1140
1207
  .tree-select-option-label {
@@ -1,6 +1,6 @@
1
- @import "../../../assets/scss/variables/colors.scss";
2
- @import "../../../assets/scss/typography.scss";
3
- @import "../../../assets/scss/mixins.scss";
1
+ @use "../../../assets/scss/variables/colors.scss" as *;
2
+ @use "../../../assets/scss/typography.scss" as *;
3
+ @use "../../../assets/scss/mixins.scss" as *;
4
4
 
5
5
  $option-hover-bg: $gray-100;
6
6
  $option-checked-bg: $gray-100;
@@ -41,7 +41,7 @@ $option-checked-hover-bg: $blue-50;
41
41
 
42
42
  .ib-checkbox-body {
43
43
  padding: 0;
44
- }
44
+ }
45
45
 
46
46
  .option-label {
47
47
  margin-left: 15px;
@@ -165,7 +165,7 @@ $option-checked-hover-bg: $blue-50;
165
165
  .ib-checkbox {
166
166
  transform: translateX(75px);
167
167
  }
168
-
168
+
169
169
  .option-label {
170
170
  width: calc(100% - 100px);
171
171
  }
@@ -212,7 +212,7 @@ $option-checked-hover-bg: $blue-50;
212
212
  }
213
213
  }
214
214
 
215
-
215
+
216
216
  .ib-toggle-container {
217
217
  position: absolute;
218
218
  right: 0;