@avakhula/ui 0.0.505 → 0.0.510-alpha-spa.1

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 (187) hide show
  1. package/.babelrc.json +0 -0
  2. package/.eslintrc.cjs +0 -0
  3. package/.nvmrc +0 -0
  4. package/.storybook/main.js +0 -0
  5. package/.storybook/preview-head.html +0 -0
  6. package/.storybook/preview.js +0 -0
  7. package/dist/index.css +1 -0
  8. package/dist/index.es.js +22382 -0
  9. package/dist/index.umd.js +238 -0
  10. package/package.json +11 -10
  11. package/src/App.vue +16 -127
  12. package/src/assets/scss/mixins/dropdown-list-item.scss +9 -4
  13. package/src/assets/scss/mixins/tooltip-position.scss +7 -0
  14. package/src/assets/scss/mixins.scss +2 -2
  15. package/src/assets/scss/style.scss +4 -4
  16. package/src/assets/scss/typography.scss +3 -3
  17. package/src/assets/scss/variables/colors.json +0 -0
  18. package/src/assets/scss/variables/colors.scss +0 -0
  19. package/src/assets/scss/variables/shadows.json +0 -0
  20. package/src/assets/scss/variables/shadows.scss +0 -0
  21. package/src/components/Accordion/Accordion.scss +3 -3
  22. package/src/components/Accordion/Accordion.stories.js +0 -0
  23. package/src/components/Accordion/Accordion.vue +2 -2
  24. package/src/components/Accordion/Acordion.spec.js +0 -0
  25. package/src/components/Accordion/readme.mdx +0 -0
  26. package/src/components/Alert/Alert.spec.js +0 -0
  27. package/src/components/Alert/Alert.stories.js +0 -0
  28. package/src/components/Alert/Alert.vue +6 -1
  29. package/src/components/Alert/alert.scss +8 -3
  30. package/src/components/Alert/constants.js +0 -0
  31. package/src/components/Alert/readme.mdx +0 -0
  32. package/src/components/Avatar/Avatar.stories.js +5 -1
  33. package/src/components/Avatar/Avatar.vue +27 -4
  34. package/src/components/Avatar/constants.js +6 -0
  35. package/src/components/Badge/Badge.spec.js +0 -0
  36. package/src/components/Badge/Badge.vue +2 -2
  37. package/src/components/Badge/readme.mdx +0 -0
  38. package/src/components/Breadcrumbs/Breadcrumbs.vue +24 -9
  39. package/src/components/Breadcrumbs/breadcrumbs.scss +5 -5
  40. package/src/components/Breadcrumbs/breadcrumbs.stories.js +0 -0
  41. package/src/components/Button/Button.spec.js +0 -0
  42. package/src/components/Button/Button.vue +20 -4
  43. package/src/components/Button/button.scss +8 -3
  44. package/src/components/Button/readme.mdx +0 -0
  45. package/src/components/ButtonGroup/ButtonGroup.stories.js +0 -0
  46. package/src/components/ButtonGroup/readme.mdx +0 -0
  47. package/src/components/Chips/Chips.stories.js +30 -0
  48. package/src/components/Chips/Chips.vue +125 -0
  49. package/src/components/Dropdown/Dropdown.spec.js +0 -0
  50. package/src/components/Dropdown/Dropdown.stories.js +0 -0
  51. package/src/components/Dropdown/Dropdown.vue +3 -3
  52. package/src/components/Dropdown/DropdownDivider.vue +1 -1
  53. package/src/components/Dropdown/DropdownItem.vue +27 -5
  54. package/src/components/Dropdown/DropdownList.stories.js +0 -0
  55. package/src/components/Dropdown/DropdownList.vue +6 -2
  56. package/src/components/Dropdown/readme.mdx +0 -0
  57. package/src/components/Form/CharactersCount.vue +12 -9
  58. package/src/components/Form/Checkbox/Checkbox.scss +4 -4
  59. package/src/components/Form/Checkbox/Checkbox.stories.js +0 -0
  60. package/src/components/Form/Checkbox/Checkbox.vue +25 -12
  61. package/src/components/Form/Checkbox/readme.mdx +0 -0
  62. package/src/components/Form/CheckboxGroup/CheckboxGroup.stories.js +0 -0
  63. package/src/components/Form/CheckboxGroup/CheckboxGroup.vue +15 -0
  64. package/src/components/Form/CheckboxGroup/readme.mdx +2 -0
  65. package/src/components/Form/DatePicker/DatePicker.scss +356 -265
  66. package/src/components/Form/DatePicker/DatePicker.stories.js +0 -0
  67. package/src/components/Form/DatePicker/DatePicker.vue +73 -18
  68. package/src/components/Form/DatePicker/readme.mdx +0 -0
  69. package/src/components/Form/FormGroup/FormGroup.vue +5 -5
  70. package/src/components/Form/FormGroup/FormGroupSet.vue +1 -1
  71. package/src/components/Form/Input/Input.stories.js +0 -0
  72. package/src/components/Form/Input/Input.vue +120 -14
  73. package/src/components/Form/Input/constants.js +0 -0
  74. package/src/components/Form/Input/input.scss +64 -5
  75. package/src/components/Form/Input/readme.mdx +0 -0
  76. package/src/components/Form/Label/Label.stories.js +0 -0
  77. package/src/components/Form/Label/Label.vue +24 -12
  78. package/src/components/Form/Label/readme.mdx +0 -0
  79. package/src/components/Form/PhoneInput/PhoneInput.stories.js +0 -0
  80. package/src/components/Form/PhoneInput/PhoneInput.vue +77 -28
  81. package/src/components/Form/PhoneInput/phoneInput.scss +42 -10
  82. package/src/components/Form/PhoneInput/readme.mdx +0 -0
  83. package/src/components/Form/Radio/Radio.stories.js +0 -0
  84. package/src/components/Form/Radio/Radio.vue +17 -45
  85. package/src/components/Form/Radio/radio.scss +8 -5
  86. package/src/components/Form/Radio/readme.mdx +0 -0
  87. package/src/components/Form/TextEditor/TextEditor.stories.js +0 -0
  88. package/src/components/Form/TextEditor/TextEditor.vue +92 -138
  89. package/src/components/Form/TextEditor/Toolbar.vue +723 -0
  90. package/src/components/Form/TextEditor/icons/toolbarIcons.js +8 -0
  91. package/src/components/Form/TextEditor/plugins/imageBlot.js +23 -0
  92. package/src/components/Form/TextEditor/readme.mdx +0 -0
  93. package/src/components/Form/TextEditor/setupTextEditor.js +71 -0
  94. package/src/components/Form/TextEditor/textEditor.scss +15 -339
  95. package/src/components/Form/Textarea/Textarea.spec.js +0 -0
  96. package/src/components/Form/Textarea/Textarea.stories.js +0 -0
  97. package/src/components/Form/Textarea/Textarea.vue +28 -10
  98. package/src/components/Form/Textarea/readme.mdx +0 -0
  99. package/src/components/Form/Textarea/textarea.scss +33 -5
  100. package/src/components/Form/Toggle/Toggle.stories.js +0 -0
  101. package/src/components/Form/Toggle/Toggle.vue +1 -1
  102. package/src/components/Form/Toggle/readme.mdx +0 -0
  103. package/src/components/Form/Toggle/toggle.scss +3 -3
  104. package/src/components/IconButton/IconButton.scss +13 -2
  105. package/src/components/IconButton/IconButton.vue +11 -4
  106. package/src/components/IconButton/readme.mdx +0 -0
  107. package/src/components/List.vue +1 -1
  108. package/src/components/Modal/Modal.stories.js +0 -0
  109. package/src/components/Modal/Modal.vue +109 -40
  110. package/src/components/Modal/constants.js +0 -0
  111. package/src/components/Modal/readme.mdx +0 -0
  112. package/src/components/Pagination/LimitSelector.vue +5 -0
  113. package/src/components/Pagination/Pagination.vue +37 -5
  114. package/src/components/Pagination/pagination.scss +20 -4
  115. package/src/components/Panel/Panel.stories.js +0 -0
  116. package/src/components/Panel/Panel.vue +72 -6
  117. package/src/components/Popover/Popover.vue +27 -10
  118. package/src/components/Popover/constants.js +0 -0
  119. package/src/components/Popover/popover.scss +4 -4
  120. package/src/components/Popover/readme.mdx +0 -0
  121. package/src/components/ProgressBar/ProgressBar.vue +1 -1
  122. package/src/components/ProgressBar/constants.js +0 -0
  123. package/src/components/ProgressBar/progressBar.scss +1 -1
  124. package/src/components/ProgressBar/readme.mdx +0 -0
  125. package/src/components/Sorting/Sorting.stories.js +0 -0
  126. package/src/components/Sorting/Sorting.vue +25 -27
  127. package/src/components/Sorting/sorting.scss +5 -5
  128. package/src/components/SplitButton/SplitButton.stories.js +0 -0
  129. package/src/components/SplitButton/SplitButton.vue +52 -9
  130. package/src/components/SplitButton/SplitButtonItem.vue +14 -2
  131. package/src/components/SplitButton/readme.mdx +0 -0
  132. package/src/components/SplitButton/splitButton.scss +3 -3
  133. package/src/components/StatusIndicator/StatusIndicator.stories.js +0 -0
  134. package/src/components/StatusIndicator/StatusIndicator.vue +2 -2
  135. package/src/components/StatusIndicator/constants.js +0 -0
  136. package/src/components/StatusIndicator/icons.js +0 -0
  137. package/src/components/StatusIndicator/readme.mdx +0 -0
  138. package/src/components/Table/Cells/Cell.vue +2 -2
  139. package/src/components/Table/Cells/CheckboxCell.vue +0 -0
  140. package/src/components/Table/Row.vue +1 -1
  141. package/src/components/Table/Table.stories.js +0 -0
  142. package/src/components/Table/Table.vue +0 -0
  143. package/src/components/Tabs/Tab.vue +4 -0
  144. package/src/components/Tabs/TabDropdown.vue +1 -1
  145. package/src/components/Tabs/Tabs.stories.js +0 -0
  146. package/src/components/Tabs/Tabs.vue +21 -6
  147. package/src/components/Tabs/tabs.scss +12 -6
  148. package/src/components/TagPill/TagPill.stories.js +0 -0
  149. package/src/components/TagPill/TagPill.vue +8 -2
  150. package/src/components/TagPill/readme.mdx +0 -0
  151. package/src/components/ToggleTip/ToggleTip.vue +1 -1
  152. package/src/components/ToggleTip/constants.js +0 -0
  153. package/src/components/ToggleTip/readme.mdx +0 -0
  154. package/src/components/ToggleTip/toggleTip.scss +5 -5
  155. package/src/components/Tooltip/Tooltip.vue +4 -4
  156. package/src/components/Tooltip/readme.mdx +0 -0
  157. package/src/components/TreeSelect/Option.vue +59 -25
  158. package/src/components/TreeSelect/Select.stories.js +0 -0
  159. package/src/components/TreeSelect/Select.vue +283 -148
  160. package/src/components/TreeSelect/TreeSelect.stories.js +0 -0
  161. package/src/components/TreeSelect/mixins/InfinityLoaderMixin.js +40 -0
  162. package/src/components/TreeSelect/scss/option.scss +37 -6
  163. package/src/components/TreeSelect/scss/select.scss +97 -6
  164. package/src/constants/keyCodes.js +1 -0
  165. package/src/directives/outside/outside.stories.js +0 -0
  166. package/src/directives/outside/readme.mdx +0 -0
  167. package/src/directives/tooltip/TooltipController.js +2 -0
  168. package/src/directives/tooltip/readme.mdx +0 -0
  169. package/src/directives/tooltip/textOverflowTooltip.js +3 -1
  170. package/src/directives/tooltip/tooltip.js +61 -0
  171. package/src/directives/tooltip/tooltip.stories.js +0 -0
  172. package/src/helpers/debounce.js +23 -0
  173. package/src/helpers/removeEvents.js +0 -0
  174. package/src/helpers/stripHtml.js +4 -0
  175. package/src/index.js +7 -0
  176. package/src/main.js +0 -0
  177. package/src/mixins/expandAnimation.js +0 -0
  178. package/src/scripts/parseScssVariables.js +0 -0
  179. package/src/stories/link.readme.mdx +0 -0
  180. package/src/stories/variables/colors.stories.js +0 -0
  181. package/src/stories/variables/shadows.stories.js +0 -0
  182. package/static/docks/button.pdf +0 -0
  183. package/static/favicon.ico +0 -0
  184. package/vite.config.js +3 -9
  185. package/dist/index.js +0 -20786
  186. package/dist/index.umd.cjs +0 -227
  187. package/dist/style.css +0 -1
@@ -4,21 +4,25 @@
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
13
- :disabled="isLoading"
14
+ :disabled="isLoading || disable"
14
15
  :is-resizable="isResizable"
15
16
  :vertical="verticalVal"
17
+ :class="{
18
+ disable: disable
19
+ }"
16
20
  ref="dropdown"
17
21
  @close="onClose"
18
22
  @open="onOpen"
19
23
  >
20
24
  <template v-if="hasTrigger" v-slot:trigger>
21
- <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>
22
26
  </template>
23
27
 
24
28
  <template v-else v-slot:trigger="{ isOpened }">
@@ -27,6 +31,7 @@
27
31
  tabindex="0"
28
32
  class="tree-choice"
29
33
  ref="combobox"
34
+ :aria-expanded="isOpened"
30
35
  @click.prevent
31
36
  @blur="onBlur"
32
37
  @keyup.down="comboboxKeyupDown"
@@ -41,7 +46,7 @@
41
46
  >
42
47
 
43
48
  <template v-if="hasTriggerContent">
44
- <slot v-bind:selected-count="selectedKeys.length" name="triggerContent"></slot>
49
+ <slot v-bind:selected-count="selectedKeys.length" v-bind:is-open="isOpened" name="triggerContent"></slot>
45
50
  </template>
46
51
 
47
52
  <template v-else>
@@ -62,6 +67,7 @@
62
67
  v-if="showClearButton"
63
68
  kind="ghost"
64
69
  class="button-clear"
70
+ aria-label="Clear selection"
65
71
  @click.prevent="clearValue"
66
72
  @keypress.enter.stop.prevent
67
73
  @keydown.enter.stop.prevent
@@ -76,8 +82,15 @@
76
82
  :name="isOpened ? 'chevron-up-outline' : 'chevron-down-outline'"
77
83
  :classes="'tree-select-caret'"
78
84
  />
79
- </div>
80
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>
81
94
  </template>
82
95
 
83
96
  <template v-slot:body>
@@ -85,6 +98,7 @@
85
98
  class="tree-drop"
86
99
  :class="{ 'not-tree-child': !hasTreeChildren }"
87
100
  :style="treeDropPos"
101
+ role="listbox"
88
102
  >
89
103
  <div
90
104
  v-if="isResizable"
@@ -95,38 +109,22 @@
95
109
  v-if="isResizable"
96
110
  class="ib-dropdown-resizer ib-dropdown-resizer-right"
97
111
  @mousedown="startResizing('right')"
112
+ v-tooltip.rightCenter="lang('resize_list', 'select')"
98
113
  ></div>
99
- <list
100
- :class="{ 'has-hierarchy': hasHierarchy }"
101
- v-if="Object.keys(actualBookmarkedOptions).length > 0"
102
- >
103
- <select-option
104
- :key="'bookmark' + option.id"
105
- v-for="option in actualBookmarkedOptions"
106
- :option="option"
107
- :parent-auto-check="false"
108
- :is-multiple="isMultiple"
109
- :is-bookmarkable="true"
110
- :is-bookmarked="true"
111
- @check="registerCheck"
112
- @toggle-bookmark="toggleBookmark"
113
- :uid="uid"
114
- :only-end-nodes="onlyEndNodes"
115
- :html-title="htmlOptionTitle"
116
- :show-input="showInputs"
117
- ></select-option>
118
- </list>
119
114
 
120
115
  <ib-input
121
116
  class="tree-search"
122
117
  v-if="showSearch"
123
118
  ref="search"
119
+ autocomplete="new-password"
124
120
  :show-icon="true"
125
121
  :value="filterString"
122
+ :debounce="searchDebounce"
126
123
  :aria-label="
127
124
  searchPlaceholderText
128
125
  ? searchPlaceholderText
129
- : actualStrings.searchPlaceholder"
126
+ : actualStrings.searchPlaceholder
127
+ "
130
128
  :placeholder="
131
129
  searchPlaceholderText
132
130
  ? searchPlaceholderText
@@ -139,7 +137,11 @@
139
137
  <list
140
138
  ref="list"
141
139
  role="listbox"
142
- :class="{ 'tree-select-list': true, 'has-hierarchy': hasHierarchy }"
140
+ :class="{
141
+ 'tree-select-list': true,
142
+ 'has-hierarchy': hasHierarchy,
143
+ 'alphabetic-list': alphabeticStyle,
144
+ }"
143
145
  >
144
146
  <div
145
147
  v-if="
@@ -151,6 +153,7 @@
151
153
  >
152
154
  <slot name="emptyMessage"></slot>
153
155
  </div>
156
+
154
157
  <div
155
158
  v-else-if="!requiredDependencyNotFilled && !visibleOptionsCount"
156
159
  class="tree-select-default-empty tree-select-empty"
@@ -171,20 +174,43 @@
171
174
  checked: isEmpty,
172
175
  }"
173
176
  :name="actualName"
174
- :parent-auto-check="parentAutoCheck"
177
+ :parent-auto-check="parentAutoCheckVal"
178
+ :is-multiple="isMultiple"
179
+ role="option"
180
+ @check="registerCheck"
181
+ @toggle-bookmark="toggleBookmark"
182
+ :uid="uid"
183
+ :only-end-nodes="onlyEndNodes"
184
+ :show-input="showInputs"
185
+ ></select-option>
186
+ </template>
187
+
188
+ <template v-if="Object.keys(actualBookmarkedOptions).length > 0">
189
+ <select-option
190
+ :key="'bookmark' + option.id"
191
+ v-for="option in actualBookmarkedOptions"
192
+ class="bookmarked-option"
193
+ :option="option"
194
+ :parent-auto-check="false"
175
195
  :is-multiple="isMultiple"
196
+ :is-bookmarkable="true"
197
+ :is-bookmarked="true"
198
+ role="option"
176
199
  @check="registerCheck"
177
200
  @toggle-bookmark="toggleBookmark"
178
201
  :uid="uid"
179
202
  :only-end-nodes="onlyEndNodes"
203
+ :html-title="htmlOptionTitle"
180
204
  :show-input="showInputs"
181
205
  ></select-option>
182
206
  </template>
183
207
 
184
208
  <template v-if="!requiredDependencyNotFilled">
209
+ <div class="scrollable-container">
185
210
  <template
186
211
  v-if="
187
212
  allOptions &&
213
+ !alphabeticStyle &&
188
214
  isMultiple &&
189
215
  visibleOptionsCount &&
190
216
  !requiredDependencyNotFilled
@@ -193,7 +219,6 @@
193
219
  <select-option
194
220
  :option="{
195
221
  title: actualStrings.selectAllOptions,
196
- id: '!all!',
197
222
  initiallyVisible: true,
198
223
  visible: true,
199
224
  isDisabled: visibleOptionsCount < optionsCount,
@@ -203,51 +228,66 @@
203
228
  : false,
204
229
  }"
205
230
  :is-toggle="isToggle"
206
- :name="actualName"
207
231
  :parent-auto-check="false"
208
232
  :is-multiple="isMultiple"
209
233
  :is-bookmarkable="false"
210
234
  :uid="uid"
211
235
  :only-end-nodes="onlyEndNodes"
212
236
  :show-input="showInputs"
237
+ :alphabetic-style="alphabeticStyle"
238
+ role="option"
213
239
  @check="manageAll"
214
- @on-focus="(id) => focusedOptionId = id"
240
+ @on-focus="(id) => (focusedOptionId = id)"
215
241
  ></select-option>
216
242
  </template>
217
243
 
218
- <template
219
- v-for="option in actualOptions"
220
- :key="name + option.value"
221
- >
222
- <slot
223
- :option="option"
224
- :name="actualName"
225
- :parent-auto-check="parentAutoCheck"
226
- :is-multiple="isMultiple"
227
- :uid="uid"
228
- :only-end-nodes="onlyEndNodes"
229
- :html-title="htmlOptionTitle"
230
- :show-input="showInputs"
244
+ <div ref="parentRef">
245
+ <div
246
+ :style="{
247
+ height: virtualizer?.getTotalSize() + 'px',
248
+ position: 'relative',
249
+ }"
231
250
  >
232
- <select-option
233
- v-show="option.visible"
234
- :option="option"
235
- :is-toggle="isToggle"
236
- :name="actualName"
237
- :parent-auto-check="parentAutoCheck"
238
- :is-multiple="isMultiple"
239
- :is-bookmarkable="isBookmarkable"
240
- :uid="uid"
241
- :only-end-nodes="onlyEndNodes"
242
- :html-title="htmlOptionTitle"
243
- :show-input="showInputs"
244
- @check="registerCheck"
245
- @toggle-bookmark="toggleBookmark"
246
- @on-focus="(id) => focusedOptionId = id"
247
- ></select-option>
248
- </slot>
249
- </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
+
250
288
  </template>
289
+
290
+ <div v-if="infiniteLoader" ref="infinityLoader"></div>
251
291
  </list>
252
292
  </div>
253
293
  </template>
@@ -256,7 +296,7 @@
256
296
  </template>
257
297
 
258
298
  <script>
259
- // <!-- TODO: use constants for vertical position -->
299
+ import { useVirtualizer } from "@tanstack/vue-virtual";
260
300
  import IbInput from "../Form/Input/Input.vue";
261
301
  import Option from "./Option.vue";
262
302
  import Mark from "mark.js/dist/mark.es6.min";
@@ -266,6 +306,9 @@ import IbIcon from "../Icon.vue";
266
306
  import IbIconButton from "../IconButton/IconButton.vue";
267
307
  import IbAlert from "../Alert/Alert.vue";
268
308
  import List from "../List.vue";
309
+ import InfinityLoaderMixin from "./mixins/InfinityLoaderMixin";
310
+ import { TooltipDirective as Tooltip } from "../../directives/tooltip/tooltip";
311
+ import debounce from "../../helpers/debounce";
269
312
 
270
313
  function copy(data) {
271
314
  return JSON.parse(JSON.stringify(data));
@@ -274,8 +317,13 @@ function copy(data) {
274
317
  export default {
275
318
  name: "IbTreeSelect",
276
319
  inject: ["LANG_COMPONENTS"],
320
+ mixins: [InfinityLoaderMixin],
277
321
  props: {
278
322
  classList: [String, Array],
323
+ keywordHighlighter: {
324
+ type: Boolean,
325
+ default: true,
326
+ },
279
327
  placeholder: {
280
328
  type: String,
281
329
  default: "",
@@ -315,6 +363,7 @@ export default {
315
363
  },
316
364
  },
317
365
  options: {
366
+ type: [Array, Function],
318
367
  default() {
319
368
  return [];
320
369
  },
@@ -338,7 +387,7 @@ export default {
338
387
  },
339
388
  parentAutoCheck: {
340
389
  type: Boolean,
341
- default: true,
390
+ default: null,
342
391
  },
343
392
  strings: {
344
393
  type: Object,
@@ -420,6 +469,18 @@ export default {
420
469
  type: Boolean,
421
470
  default: false,
422
471
  },
472
+ disable: {
473
+ type: Boolean,
474
+ default: false
475
+ },
476
+ searchDebounce: {
477
+ type: Number,
478
+ default: 500,
479
+ },
480
+ alphabeticStyle: {
481
+ type: Boolean,
482
+ default: false
483
+ },
423
484
  },
424
485
  emits: [
425
486
  "close",
@@ -429,6 +490,7 @@ export default {
429
490
  "resize",
430
491
  "submit",
431
492
  "clearValue",
493
+ "toggle-bookmarked-option",
432
494
  "update:modelValue",
433
495
  ],
434
496
  watch: {
@@ -440,9 +502,15 @@ export default {
440
502
  },
441
503
  modelValue: {
442
504
  handler(value) {
443
- this.val = value;
444
- this.actualOptions = [];
445
- 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);
446
514
  },
447
515
  deep: true,
448
516
  },
@@ -462,7 +530,7 @@ export default {
462
530
  },
463
531
  options: {
464
532
  handler(newOptions) {
465
- this.initialOptions = copy(newOptions);
533
+ this.initialOptions = typeof newOptions === "function" ? newOptions : copy(newOptions);
466
534
  },
467
535
  deep: true,
468
536
  },
@@ -517,18 +585,21 @@ export default {
517
585
  document.addEventListener("mouseup", this.endResizing);
518
586
  },
519
587
  data() {
520
- this.defaultFilter = (options) => {
588
+ this.defaultFilter = debounce((options) => {
521
589
  this.marker.unmark();
522
590
  const filterString = this.filterString.toLowerCase().trim();
523
- this.filterFunc.call(this, options, filterString);
591
+ this.countVisibleChildren = this.filterFunc.call(this, options, filterString);
524
592
 
525
- if (filterString) {
593
+ if (filterString && this.keywordHighlighter) {
526
594
  this.marker.mark(filterString);
527
595
  }
528
- };
596
+
597
+ this.virtualizer?.measure();
598
+ }, 1000);
529
599
 
530
600
  return {
531
- initialOptions: copy(this.options),
601
+ virtualizer: null,
602
+ initialOptions: typeof this.options === "function" ? this.options : copy(this.options),
532
603
  val: this.modelValue ? this.modelValue : this.value,
533
604
  size: {
534
605
  left: (this.initialSize && this.initialSize.left) || 0,
@@ -536,14 +607,15 @@ export default {
536
607
  },
537
608
  resizingProp: null,
538
609
  isInitialized: false,
539
- optionsIdsWatch: [],
540
610
  isLoading: false,
611
+ isOpen: false,
612
+ optionsIdsWatch: [],
541
613
  actualName: this.isMultiple ? this.name + "[]" : this.name,
614
+ parentAutoCheckVal: this.parentAutoCheck !== null ? this.parentAutoCheck : this.isMultiple,
542
615
  filterString: "",
543
616
  actualOptions: [],
544
617
  actualBookmarkedOptions: {},
545
618
  selected: [],
546
- isOpen: false,
547
619
  verticalVal: this.vertical ?? "bottom",
548
620
  allOptionsIsChecked: true,
549
621
  hasTreeChildren: false,
@@ -589,9 +661,38 @@ export default {
589
661
  ...this.strings,
590
662
  },
591
663
  dependencyValue: null,
664
+ isInternalChange: false,
665
+ nodeIndex: new Map()
592
666
  };
593
667
  },
594
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
+ },
595
696
  onBlur() {
596
697
  setTimeout(() => {
597
698
  if (!this.isOpen) {
@@ -614,7 +715,7 @@ export default {
614
715
  this.$refs.combobox.focus();
615
716
  },
616
717
  focusOnFirstOptions() {
617
- this.$refs.list.$el.querySelector('[tabindex]:not(hidden)').focus();
718
+ this.$refs.list.$el.querySelector("[tabindex]:not(hidden)").focus();
618
719
  },
619
720
  startResizing(prop) {
620
721
  this.resizingProp = prop;
@@ -667,7 +768,7 @@ export default {
667
768
  },
668
769
  filter(filterString, options) {
669
770
  this.filterString = filterString;
670
- this.$emit("search", { search: this.filterString });
771
+ this.$emit("search", this.filterString);
671
772
  this.defaultFilter(options);
672
773
  },
673
774
  setPreparedValues(opt) {
@@ -678,37 +779,32 @@ export default {
678
779
  );
679
780
  }
680
781
 
681
- return this.prepare(options).then(([options, selected]) => {
682
- this.actualOptions = options;
683
- this.allOptionsIsChecked = this.checkIfOptionsChecked(options);
684
- this.isInitialized = true;
685
- this.selected = selected;
686
- this.setBookmarkedOptions(options);
687
- });
782
+ return this.prepare(options).then(([options, selected]) => {
783
+ this.actualOptions = options;
784
+ this.buildNodeIndex();
785
+ this.allOptionsIsChecked = this.checkIfOptionsChecked(options);
786
+ this.isInitialized = true;
787
+ this.selected = selected;
788
+ this.setBookmarkedOptions(options);
789
+ });
688
790
  },
689
791
  clear() {
690
- this.setPreparedValues();
691
- this.allOptionsIsChecked = false;
692
- this.selected = [];
693
-
694
- if (this.isMultiple) {
695
- this.$emit("update:modelValue", null);
696
- this.$emit("input", null);
697
- this.$emit("clear-value", null);
698
-
699
- } else {
700
- this.$emit("update:modelValue", []);
701
- this.$emit("input", []);
702
- this.$emit("clear-value", []);
703
- }
792
+ this.traverseTree(this.actualOptions, (opt) => (opt.checked = false));
793
+ this.selected = [];
794
+ this.allOptionsIsChecked = false;
704
795
 
705
- this.setPreparedValues();
796
+ this.isInternalChange = true;
797
+ const empty = this.isMultiple ? [] : null;
798
+ this.$emit("update:modelValue", empty);
799
+ this.$emit("input", empty);
800
+ this.$emit("clear-value", empty);
801
+ this.$nextTick(() => (this.isInternalChange = false));
706
802
  },
707
803
  clearValue() {
708
804
  this.clear();
709
805
  this.setPreparedValues();
710
806
  },
711
- prepare(options) {
807
+ prepare(options, checkInitialVisibility = true) {
712
808
  return new Promise((res) => {
713
809
  const selected = {},
714
810
  promises = [];
@@ -736,7 +832,6 @@ export default {
736
832
  typeof option.visible === "undefined" ? true : option.visible;
737
833
  option.visible = option.initiallyVisible;
738
834
  option.readonly = option.readonly ? true : false;
739
- option.isDisabled = false;
740
835
 
741
836
  option.checked = this.isMultiple
742
837
  ? this.val !== null &&
@@ -760,6 +855,13 @@ export default {
760
855
  this.prepare(option.children).then(
761
856
  ([preparedChildren, selectedChildren]) => {
762
857
  option.children = preparedChildren;
858
+
859
+ if (this.parentAutoCheckVal) {
860
+ option.checked = this.checkIfOptionsChecked(
861
+ option.children
862
+ );
863
+ }
864
+
763
865
  Object.assign(selected, selectedChildren);
764
866
  res(option);
765
867
  }
@@ -789,11 +891,16 @@ export default {
789
891
 
790
892
  if (option.children && option.children.length) {
791
893
  let visibleChildrenCount = this.filterFunc(option.children, filterString);
894
+
792
895
  visibleOptionsCount += visibleChildrenCount;
793
896
 
794
897
  if (visibleChildrenCount) {
795
- option.isChildrenVisible = !!filterString || Boolean(Object.keys(this.actualBookmarkedOptions).length);
796
- option.isDisabled = visibleChildrenCount < option.children.length && !this.isBookmarkable;
898
+ option.isChildrenVisible =
899
+ filterString.length > 0 ||
900
+ Boolean(Object.keys(this.actualBookmarkedOptions).length);
901
+ option.isDisabled =
902
+ visibleChildrenCount < option.children.length &&
903
+ !this.isBookmarkable;
797
904
  }
798
905
 
799
906
  if (!isVisible) {
@@ -821,57 +928,52 @@ export default {
821
928
  this.$emit("submit");
822
929
  },
823
930
  change() {
824
- const values = Object.keys(this.selected);
825
- if (this.isMultiple) {
826
- this.$emit("update:modelValue", values);
827
- this.$emit("input", values);
828
- } else {
829
- this.$emit("update:modelValue", values[0]);
830
- this.$emit("input", values[0]);
831
- }
832
- this.$globalEvents.$emit("select-" + this.filterId + ":update", {
833
- values,
834
- filter: this.filterId,
835
- });
836
- this.$refs.dropdown.close();
931
+ const values = Object.keys(this.selected);
932
+ this.isInternalChange = true;
933
+ if (this.isMultiple) {
934
+ this.$emit("update:modelValue", values);
935
+ this.$emit("input", values);
936
+ } else {
937
+ this.$emit("update:modelValue", values[0]);
938
+ this.$emit("input", values[0]);
939
+ }
940
+ this.$nextTick(() => (this.isInternalChange = false));
941
+ this.$globalEvents.$emit("select-" + this.filterId + ":update", { values, filter: this.filterId });
942
+ if (!this.isMultiple) this.$refs.dropdown.close();
837
943
  },
838
944
  checkIfOptionsChecked(options) {
839
945
  return options.every((option) => option.checked || option.readonly);
840
946
  },
841
947
  registerCheck(option, isChecked, isDirectChild) {
842
- if (isChecked) {
843
- option.checked = true;
844
- if (this.isMultiple) {
845
- if (
846
- !(this.onlyEndNodes && option.children && option.children.length)
847
- ) {
948
+ if (isChecked) {
949
+ option.checked = true;
950
+ if (this.isMultiple && !(this.onlyEndNodes && option.children?.length)) {
848
951
  this.selected[option.id] = option;
849
- this.$emit("update:modelValue", Object.keys(this.selected));
850
- this.$emit("input", Object.keys(this.selected));
952
+ } else if (!this.isMultiple) {
953
+ const prev = Object.keys(this.selected)[0];
954
+ if (prev) this.selected[prev].checked = false;
955
+ this.selected = { [option.id]: option };
956
+ this.change();
957
+ return;
851
958
  }
852
959
  } else {
853
- const selectedOptionKey = Object.keys(this.selected)[0];
960
+ delete this.selected[option.id];
961
+ option.checked = false;
962
+ }
854
963
 
855
- if (selectedOptionKey) {
856
- this.selected[selectedOptionKey].checked = false;
857
- }
964
+ this.toggleDuplicateOptionsFast(option.id, isChecked);
858
965
 
859
- this.selected = { [option.id]: option };
860
- this.change();
966
+ if (isDirectChild) {
967
+ this.allOptionsIsChecked = this.checkIfOptionsChecked(this.actualOptions);
861
968
  }
862
- } else {
863
- delete this.selected[option.id];
864
- option.checked = false;
865
- this.$emit("update:modelValue", Object.keys(this.selected));
866
- this.$emit("input", Object.keys(this.selected));
867
- }
868
969
 
869
- this.toggleDuplicateOptions(this.actualOptions, option.id, isChecked);
870
- if (isDirectChild) {
871
- this.allOptionsIsChecked = this.checkIfOptionsChecked(
872
- this.actualOptions
873
- );
874
- }
970
+ if (this.isMultiple) {
971
+ this.isInternalChange = true;
972
+ const values = Object.keys(this.selected);
973
+ this.$emit("update:modelValue", values);
974
+ this.$emit("input", values);
975
+ this.$nextTick(() => (this.isInternalChange = false));
976
+ }
875
977
  },
876
978
  toggleDuplicateOptions(options, optionId, checked) {
877
979
  for (let opt of options) {
@@ -933,13 +1035,15 @@ export default {
933
1035
  },
934
1036
  onClose() {
935
1037
  this.isOpen = false;
936
- this.filter("", this.actualOptions);
1038
+ this.filterString = "";
1039
+ this.filterFunc(this.actualOptions, this.filterString);
937
1040
 
938
1041
  if (this.isMultiple) {
939
1042
  this.$emit("close", Object.keys(this.selected));
940
1043
  } else {
941
1044
  this.$emit("close", Object.keys(this.selected)[0]);
942
1045
  }
1046
+ this.virtualizer = null;
943
1047
  this.$emit("blur");
944
1048
  this.verticalVal = this.vertical ?? "bottom";
945
1049
  },
@@ -947,6 +1051,17 @@ export default {
947
1051
  const screenHeight = document.documentElement.scrollHeight;
948
1052
  this.isOpen = true;
949
1053
 
1054
+
1055
+ if (!this.virtualizer) {
1056
+ this.virtualizer = useVirtualizer({
1057
+ count: this.actualOptions.length,
1058
+ getScrollElement: () => this.$refs.parentRef,
1059
+ estimateSize: () => 40,
1060
+ overscan: 8,
1061
+ });
1062
+ }
1063
+ this.virtualizer?.measure();
1064
+
950
1065
  if (this.vertical === "bottom") return;
951
1066
 
952
1067
  this.$nextTick(() => {
@@ -955,7 +1070,7 @@ export default {
955
1070
  this.verticalVal = "top";
956
1071
  }
957
1072
  })
958
- }
1073
+ },
959
1074
  },
960
1075
  computed: {
961
1076
  hasTrigger() {
@@ -995,7 +1110,7 @@ export default {
995
1110
  }
996
1111
  });
997
1112
  },
998
- selectStatus() {
1113
+ selectStatus() {
999
1114
  if (this.staticPlaceholder) {
1000
1115
  return this.placeholder;
1001
1116
  } else if (this.isLoading) {
@@ -1006,7 +1121,7 @@ export default {
1006
1121
  return this.selectedKeys
1007
1122
  .map((key) => this.selected[key].title)
1008
1123
  .join(",");
1009
- } else if (this.selectedKeys.length < this.optionsCount) {
1124
+ } else if (!this.allOptionsIsChecked) {
1010
1125
  return this.actualStrings.selectedCount
1011
1126
  .replace("{selected}", this.selectedKeys.length)
1012
1127
  .replace("{all}", this.optionsCount);
@@ -1026,7 +1141,7 @@ export default {
1026
1141
  );
1027
1142
  },
1028
1143
  showSearch() {
1029
- return this.useSearch || this.optionsCount > 10;
1144
+ return (this.useSearch || (this.optionsCount > 10 && !this.alphabeticStyle));
1030
1145
  },
1031
1146
  arrayOfOptions() {
1032
1147
  return this.getArrayOptions(this.actualOptions);
@@ -1073,12 +1188,32 @@ export default {
1073
1188
  List,
1074
1189
  "select-option": Option,
1075
1190
  },
1191
+ directives: {
1192
+ Tooltip,
1193
+ },
1076
1194
  beforeUnmount() {
1077
1195
  document.removeEventListener("mousemove", this.onResize);
1078
1196
  document.removeEventListener("mouseup", this.endResizing);
1079
1197
  },
1198
+ inheritAttrs: false,
1080
1199
  };
1081
1200
  </script>
1082
1201
  <style lang="scss">
1083
- @import "./scss/select.scss";
1202
+ @use "./scss/select.scss" as *;
1203
+ @use "../../assets/scss/variables/colors.scss" as *;
1204
+
1205
+ .scrollable-container {
1206
+ overflow: auto;
1207
+ max-height: 300px;
1208
+ }
1209
+
1210
+ .bookmarked-option {
1211
+ .tree-select-option-label {
1212
+ padding-left: 15px;
1213
+
1214
+ ion-icon {
1215
+ color: $blue-900;
1216
+ }
1217
+ }
1218
+ }
1084
1219
  </style>