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