@volverjs/ui-vue 0.0.10-beta.4 → 0.0.10-beta.41

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 (481) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +146 -49
  3. package/auto-imports.d.ts +7 -2
  4. package/bin/icons.cjs +1 -1
  5. package/bin/icons.js +27 -20
  6. package/dist/Volver.d.ts +11 -11
  7. package/dist/components/VvAccordion/VvAccordion.es.js +190 -101
  8. package/dist/components/VvAccordion/VvAccordion.umd.js +1 -1
  9. package/dist/components/VvAccordion/VvAccordion.vue.d.ts +30 -8
  10. package/dist/components/VvAccordion/index.d.ts +8 -9
  11. package/dist/components/VvAccordionGroup/VvAccordionGroup.es.js +450 -170
  12. package/dist/components/VvAccordionGroup/VvAccordionGroup.umd.js +1 -1
  13. package/dist/components/VvAccordionGroup/VvAccordionGroup.vue.d.ts +58 -13
  14. package/dist/components/VvAccordionGroup/index.d.ts +14 -6
  15. package/dist/components/VvAction/VvAction.es.js +84 -33
  16. package/dist/components/VvAction/VvAction.umd.js +1 -1
  17. package/dist/components/VvAction/VvAction.vue.d.ts +57 -22
  18. package/dist/components/VvAction/index.d.ts +25 -9
  19. package/dist/components/VvAlert/VvAlert.es.js +228 -193
  20. package/dist/components/VvAlert/VvAlert.umd.js +1 -1
  21. package/dist/components/VvAlert/VvAlert.vue.d.ts +24 -14
  22. package/dist/components/VvAlert/index.d.ts +17 -9
  23. package/dist/components/VvAlertGroup/VvAlertGroup.es.js +549 -485
  24. package/dist/components/VvAlertGroup/VvAlertGroup.umd.js +1 -1
  25. package/dist/components/VvAlertGroup/VvAlertGroup.vue.d.ts +16 -9
  26. package/dist/components/VvAlertGroup/index.d.ts +7 -15
  27. package/dist/components/VvAvatar/VvAvatar.es.js +65 -22
  28. package/dist/components/VvAvatar/VvAvatar.umd.js +1 -1
  29. package/dist/components/VvAvatar/VvAvatar.vue.d.ts +12 -4
  30. package/dist/components/VvAvatar/index.d.ts +4 -1
  31. package/dist/components/VvAvatarGroup/VvAvatarGroup.es.js +128 -49
  32. package/dist/components/VvAvatarGroup/VvAvatarGroup.umd.js +1 -1
  33. package/dist/components/VvAvatarGroup/VvAvatarGroup.vue.d.ts +10 -3
  34. package/dist/components/VvAvatarGroup/index.d.ts +4 -1
  35. package/dist/components/VvBadge/VvBadge.es.js +77 -28
  36. package/dist/components/VvBadge/VvBadge.umd.js +1 -1
  37. package/dist/components/VvBadge/VvBadge.vue.d.ts +12 -4
  38. package/dist/components/VvBadge/index.d.ts +4 -1
  39. package/dist/components/VvBreadcrumb/VvBreadcrumb.es.js +276 -60
  40. package/dist/components/VvBreadcrumb/VvBreadcrumb.umd.js +1 -1
  41. package/dist/components/VvBreadcrumb/VvBreadcrumb.vue.d.ts +27 -7
  42. package/dist/components/VvBreadcrumb/index.d.ts +6 -10
  43. package/dist/components/VvButton/VvButton.es.js +307 -262
  44. package/dist/components/VvButton/VvButton.umd.js +1 -1
  45. package/dist/components/VvButton/VvButton.vue.d.ts +94 -40
  46. package/dist/components/VvButton/index.d.ts +51 -29
  47. package/dist/components/VvButtonGroup/VvButtonGroup.es.js +95 -40
  48. package/dist/components/VvButtonGroup/VvButtonGroup.umd.js +1 -1
  49. package/dist/components/VvButtonGroup/VvButtonGroup.vue.d.ts +31 -11
  50. package/dist/components/VvButtonGroup/index.d.ts +11 -2
  51. package/dist/components/VvCard/VvCard.es.js +86 -36
  52. package/dist/components/VvCard/VvCard.umd.js +1 -1
  53. package/dist/components/VvCard/VvCard.vue.d.ts +12 -4
  54. package/dist/components/VvCard/index.d.ts +4 -1
  55. package/dist/components/VvCheckbox/VvCheckbox.es.js +315 -251
  56. package/dist/components/VvCheckbox/VvCheckbox.umd.js +1 -1
  57. package/dist/components/VvCheckbox/VvCheckbox.vue.d.ts +106 -34
  58. package/dist/components/VvCheckbox/index.d.ts +47 -14
  59. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.es.js +238 -129
  60. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.umd.js +1 -1
  61. package/dist/components/VvCheckboxGroup/VvCheckboxGroup.vue.d.ts +101 -30
  62. package/dist/components/VvCheckboxGroup/index.d.ts +45 -12
  63. package/dist/components/VvCombobox/VvCombobox.es.js +1377 -1059
  64. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  65. package/dist/components/VvCombobox/VvCombobox.vue.d.ts +606 -680
  66. package/dist/components/VvCombobox/index.d.ts +488 -26
  67. package/dist/components/VvDialog/VvDialog.es.js +180 -176
  68. package/dist/components/VvDialog/VvDialog.umd.js +1 -1
  69. package/dist/components/VvDialog/VvDialog.vue.d.ts +13 -4
  70. package/dist/components/VvDialog/index.d.ts +5 -0
  71. package/dist/components/VvDropdown/VvDropdown.es.js +165 -94
  72. package/dist/components/VvDropdown/VvDropdown.umd.js +1 -1
  73. package/dist/components/VvDropdown/VvDropdown.vue.d.ts +111 -81
  74. package/dist/components/VvDropdown/VvDropdownAction.vue.d.ts +66 -25
  75. package/dist/components/VvDropdown/VvDropdownItem.vue.d.ts +13 -1
  76. package/dist/components/VvDropdown/VvDropdownOptgroup.vue.d.ts +12 -4
  77. package/dist/components/VvDropdown/VvDropdownOption.vue.d.ts +35 -7
  78. package/dist/components/VvDropdown/index.d.ts +52 -10
  79. package/dist/components/VvDropdownAction/VvDropdownAction.es.js +163 -53
  80. package/dist/components/VvDropdownAction/VvDropdownAction.umd.js +1 -1
  81. package/dist/components/VvDropdownItem/VvDropdownItem.es.js +335 -8
  82. package/dist/components/VvDropdownItem/VvDropdownItem.umd.js +1 -1
  83. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.es.js +63 -20
  84. package/dist/components/VvDropdownOptgroup/VvDropdownOptgroup.umd.js +1 -1
  85. package/dist/components/VvDropdownOption/VvDropdownOption.es.js +188 -80
  86. package/dist/components/VvDropdownOption/VvDropdownOption.umd.js +1 -1
  87. package/dist/components/VvIcon/VvIcon.es.js +24 -97
  88. package/dist/components/VvIcon/VvIcon.umd.js +1 -1
  89. package/dist/components/VvIcon/VvIcon.vue.d.ts +23 -66
  90. package/dist/components/VvIcon/index.d.ts +33 -48
  91. package/dist/components/VvInputFile/VvInputFile.es.js +1789 -0
  92. package/dist/components/VvInputFile/VvInputFile.umd.js +1 -0
  93. package/dist/components/VvInputFile/VvInputFile.vue.d.ts +391 -0
  94. package/dist/components/VvInputFile/index.d.ts +210 -0
  95. package/dist/components/VvInputText/VvInputClearAction.d.ts +7 -5
  96. package/dist/components/VvInputText/VvInputPasswordAction.d.ts +10 -8
  97. package/dist/components/VvInputText/VvInputStepAction.d.ts +2 -2
  98. package/dist/components/VvInputText/VvInputText.es.js +1489 -563
  99. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  100. package/dist/components/VvInputText/VvInputText.vue.d.ts +207 -57
  101. package/dist/components/VvInputText/index.d.ts +105 -30
  102. package/dist/components/VvNav/VvNav.es.js +160 -75
  103. package/dist/components/VvNav/VvNav.umd.js +1 -1
  104. package/dist/components/VvNav/VvNav.vue.d.ts +32 -9
  105. package/dist/components/VvNav/VvNavItem.vue.d.ts +1 -1
  106. package/dist/components/VvNav/VvNavSeparator.vue.d.ts +1 -1
  107. package/dist/components/VvNav/index.d.ts +5 -2
  108. package/dist/components/VvNavItem/VvNavItem.es.js +100 -39
  109. package/dist/components/VvNavItem/VvNavItem.umd.js +1 -1
  110. package/dist/components/VvProgress/VvProgress.es.js +73 -27
  111. package/dist/components/VvProgress/VvProgress.umd.js +1 -1
  112. package/dist/components/VvProgress/VvProgress.vue.d.ts +10 -3
  113. package/dist/components/VvProgress/index.d.ts +4 -1
  114. package/dist/components/VvRadio/VvRadio.es.js +313 -250
  115. package/dist/components/VvRadio/VvRadio.umd.js +1 -1
  116. package/dist/components/VvRadio/VvRadio.vue.d.ts +103 -31
  117. package/dist/components/VvRadio/index.d.ts +50 -17
  118. package/dist/components/VvRadioGroup/VvRadioGroup.es.js +236 -128
  119. package/dist/components/VvRadioGroup/VvRadioGroup.umd.js +1 -1
  120. package/dist/components/VvRadioGroup/VvRadioGroup.vue.d.ts +101 -30
  121. package/dist/components/VvRadioGroup/index.d.ts +45 -12
  122. package/dist/components/VvSelect/VvSelect.es.js +367 -300
  123. package/dist/components/VvSelect/VvSelect.umd.js +1 -1
  124. package/dist/components/VvSelect/VvSelect.vue.d.ts +232 -203
  125. package/dist/components/VvSelect/index.d.ts +195 -15
  126. package/dist/components/VvTab/VvTab.es.js +222 -97
  127. package/dist/components/VvTab/VvTab.umd.js +1 -1
  128. package/dist/components/VvTab/VvTab.vue.d.ts +31 -7
  129. package/dist/components/VvTab/index.d.ts +4 -1
  130. package/dist/components/VvTextarea/VvTextarea.es.js +258 -248
  131. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  132. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +156 -49
  133. package/dist/components/VvTextarea/index.d.ts +68 -19
  134. package/dist/components/VvTooltip/VvTooltip.es.js +83 -30
  135. package/dist/components/VvTooltip/VvTooltip.umd.js +1 -1
  136. package/dist/components/VvTooltip/VvTooltip.vue.d.ts +13 -6
  137. package/dist/components/VvTooltip/index.d.ts +5 -2
  138. package/dist/components/common/HintSlot.d.ts +4 -5
  139. package/dist/components/index.d.ts +10 -0
  140. package/dist/components/index.es.js +4575 -2534
  141. package/dist/components/index.umd.js +1 -1
  142. package/dist/composables/alert/useAlert.d.ts +101 -6
  143. package/dist/composables/alert/useInjectAlert.d.ts +1 -6
  144. package/dist/composables/dropdown/useInjectDropdown.d.ts +3 -23
  145. package/dist/composables/dropdown/useProvideDropdown.d.ts +3 -4
  146. package/dist/composables/group/useInjectedGroupState.d.ts +4 -5
  147. package/dist/composables/group/useProvideGroupState.d.ts +3 -3
  148. package/dist/composables/index.d.ts +1 -0
  149. package/dist/composables/index.es.js +94 -5
  150. package/dist/composables/index.umd.js +1 -1
  151. package/dist/composables/useBlurhash.d.ts +7 -0
  152. package/dist/composables/useComponentFocus.d.ts +1 -1
  153. package/dist/composables/useComponentIcon.d.ts +9 -8
  154. package/dist/composables/useOptions.d.ts +4 -4
  155. package/dist/composables/usePersistence.d.ts +3 -0
  156. package/dist/composables/useUniqueId.d.ts +1 -1
  157. package/dist/composables/useVolver.d.ts +1 -1
  158. package/dist/constants.d.ts +34 -32
  159. package/dist/directives/index.d.ts +3 -5
  160. package/dist/directives/index.es.js +104 -45
  161. package/dist/directives/index.umd.js +1 -1
  162. package/dist/directives/v-contextmenu.es.js +1 -1
  163. package/dist/directives/v-contextmenu.umd.js +1 -1
  164. package/dist/directives/v-tooltip.es.js +101 -39
  165. package/dist/directives/v-tooltip.umd.js +1 -1
  166. package/dist/icons.es.js +267 -267
  167. package/dist/icons.umd.js +1 -1
  168. package/dist/index.d.ts +3 -1
  169. package/dist/index.es.js +92 -18
  170. package/dist/index.umd.js +1 -1
  171. package/dist/props/index.d.ts +272 -81
  172. package/dist/resolvers/unplugin.d.ts +6 -1
  173. package/dist/resolvers/unplugin.es.js +87 -10
  174. package/dist/resolvers/unplugin.umd.js +1 -1
  175. package/dist/stories/Accordion/Accordion.settings.d.ts +2 -57
  176. package/dist/stories/AccordionGroup/AccordionGroup.settings.d.ts +2 -66
  177. package/dist/stories/AccordionGroup/AccordionGroup.stories.d.ts +2 -127
  178. package/dist/stories/AccordionGroup/AccordionGroupSlots.stories.d.ts +1437 -495
  179. package/dist/stories/Alert/Alert.settings.d.ts +2 -109
  180. package/dist/stories/Alert/AlertModifiers.stories.d.ts +1 -1
  181. package/dist/stories/Alert/AlertSlots.stories.d.ts +1 -1
  182. package/dist/stories/AlertGroup/AlertGroup.settings.d.ts +2 -85
  183. package/dist/stories/AlertGroup/AlertGroupPosition.stories.d.ts +1 -1
  184. package/dist/stories/AlertGroup/AlertGroupSlots.stories.d.ts +1 -1
  185. package/dist/stories/AlertGroup/AlertGroupWithComposable.stories.d.ts +2 -2
  186. package/dist/stories/AvatarGroup/AvatarGroup.settings.d.ts +2 -38
  187. package/dist/stories/Badge/Badge.settings.d.ts +2 -26
  188. package/dist/stories/Badge/Badge.test.d.ts +1 -1
  189. package/dist/stories/Blurhash/BlurhashComposable.stories.d.ts +4 -0
  190. package/dist/stories/Breadcrumb/Breadcrumb.settings.d.ts +2 -18
  191. package/dist/stories/Breadcrumb/Breadcrumb.test.d.ts +1 -1
  192. package/dist/stories/Button/Button.settings.d.ts +2 -194
  193. package/dist/stories/ButtonGroup/ButtonGroup.settings.d.ts +2 -40
  194. package/dist/stories/Card/Card.settings.d.ts +2 -63
  195. package/dist/stories/Checkbox/Checkbox.settings.d.ts +2 -132
  196. package/dist/stories/CheckboxGroup/CheckboxGroup.settings.d.ts +1 -141
  197. package/dist/stories/Combobox/Combobox.settings.d.ts +2 -609
  198. package/dist/stories/Combobox/Combobox.stories.d.ts +1 -0
  199. package/dist/stories/Combobox/ComboboxMultiple.stories.d.ts +1 -0
  200. package/dist/stories/Dialog/Dialog.settings.d.ts +2 -47
  201. package/dist/stories/Dialog/DialogModifiers.stories.d.ts +8 -0
  202. package/dist/stories/Dropdown/Dropdown.settings.d.ts +2 -205
  203. package/dist/stories/Icon/Icon.settings.d.ts +3 -68
  204. package/dist/stories/InputFile/InputFile.settings.d.ts +6 -0
  205. package/dist/stories/InputFile/InputFile.stories.d.ts +12 -0
  206. package/dist/stories/InputFile/InputFileDropArea.stories.d.ts +9 -0
  207. package/dist/stories/InputFile/InputFileIconPosition.stories.d.ts +8 -0
  208. package/dist/stories/InputFile/InputFileSlots.stories.d.ts +7 -0
  209. package/dist/stories/InputText/InputText.settings.d.ts +2 -438
  210. package/dist/stories/Nav/Nav.settings.d.ts +2 -10
  211. package/dist/stories/Progress/Progress.settings.d.ts +2 -27
  212. package/dist/stories/Radio/Radio.settings.d.ts +1 -110
  213. package/dist/stories/RadioGroup/RadioGroup.settings.d.ts +1 -141
  214. package/dist/stories/Select/Select.settings.d.ts +2 -246
  215. package/dist/stories/Select/Select.stories.d.ts +1 -0
  216. package/dist/stories/Tab/Tab.settings.d.ts +2 -15
  217. package/dist/stories/Textarea/Textarea.settings.d.ts +2 -287
  218. package/dist/stories/argTypes.d.ts +27 -866
  219. package/dist/test/expect.d.ts +1 -1
  220. package/dist/test/options.d.ts +1 -1
  221. package/dist/test/sleep.d.ts +1 -1
  222. package/dist/types/alert.d.ts +9 -7
  223. package/dist/types/blurhash.d.ts +12 -0
  224. package/dist/types/generic.d.ts +1 -2
  225. package/dist/types/group.d.ts +37 -15
  226. package/dist/types/index.d.ts +7 -0
  227. package/dist/types/input-file.d.ts +16 -0
  228. package/dist/types/nav.d.ts +2 -2
  229. package/dist/utils/ObjectUtilities.d.ts +7 -8
  230. package/dist/workers/blurhash.d.ts +1 -0
  231. package/package.json +239 -246
  232. package/src/Volver.ts +245 -234
  233. package/src/assets/icons/detailed.json +1 -1
  234. package/src/assets/icons/normal.json +1 -1
  235. package/src/assets/icons/simple.json +1 -1
  236. package/src/components/VvAccordion/VvAccordion.vue +163 -100
  237. package/src/components/VvAccordion/index.ts +64 -79
  238. package/src/components/VvAccordionGroup/VvAccordionGroup.vue +223 -105
  239. package/src/components/VvAccordionGroup/index.ts +42 -42
  240. package/src/components/VvAction/VvAction.vue +144 -130
  241. package/src/components/VvAlert/VvAlert.vue +72 -70
  242. package/src/components/VvAlert/index.ts +149 -147
  243. package/src/components/VvAlertGroup/VvAlertGroup.vue +57 -56
  244. package/src/components/VvAlertGroup/index.ts +101 -117
  245. package/src/components/VvAvatar/VvAvatar.vue +20 -14
  246. package/src/components/VvAvatar/index.ts +5 -5
  247. package/src/components/VvAvatarGroup/VvAvatarGroup.vue +58 -53
  248. package/src/components/VvAvatarGroup/index.ts +21 -21
  249. package/src/components/VvBadge/VvBadge.vue +15 -14
  250. package/src/components/VvBadge/index.ts +2 -2
  251. package/src/components/VvBreadcrumb/VvBreadcrumb.vue +50 -48
  252. package/src/components/VvBreadcrumb/index.ts +3 -9
  253. package/src/components/VvButton/VvButton.vue +163 -152
  254. package/src/components/VvButton/index.ts +103 -110
  255. package/src/components/VvButtonGroup/VvButtonGroup.vue +72 -64
  256. package/src/components/VvButtonGroup/index.ts +22 -21
  257. package/src/components/VvCard/VvCard.vue +30 -30
  258. package/src/components/VvCard/index.ts +2 -2
  259. package/src/components/VvCheckbox/VvCheckbox.vue +185 -183
  260. package/src/components/VvCheckbox/index.ts +44 -44
  261. package/src/components/VvCheckboxGroup/VvCheckboxGroup.vue +88 -87
  262. package/src/components/VvCombobox/VvCombobox.vue +639 -619
  263. package/src/components/VvCombobox/index.ts +206 -164
  264. package/src/components/VvDialog/VvDialog.vue +141 -129
  265. package/src/components/VvDialog/index.ts +38 -36
  266. package/src/components/VvDropdown/VvDropdown.vue +466 -445
  267. package/src/components/VvDropdown/VvDropdownAction.vue +37 -39
  268. package/src/components/VvDropdown/VvDropdownItem.vue +30 -26
  269. package/src/components/VvDropdown/VvDropdownOptgroup.vue +13 -12
  270. package/src/components/VvDropdown/VvDropdownOption.vue +47 -64
  271. package/src/components/VvDropdown/index.ts +61 -27
  272. package/src/components/VvIcon/README.md +1 -1
  273. package/src/components/VvIcon/VvIcon.vue +133 -133
  274. package/src/components/VvIcon/index.ts +84 -97
  275. package/src/components/VvInputFile/VvInputFile.vue +402 -0
  276. package/src/components/VvInputFile/index.ts +141 -0
  277. package/src/components/VvInputText/VvInputClearAction.ts +51 -47
  278. package/src/components/VvInputText/VvInputPasswordAction.ts +66 -62
  279. package/src/components/VvInputText/VvInputStepAction.ts +43 -43
  280. package/src/components/VvInputText/VvInputText.vue +638 -516
  281. package/src/components/VvInputText/VvInputTextActions.ts +86 -86
  282. package/src/components/VvInputText/index.ts +200 -185
  283. package/src/components/VvNav/VvNav.vue +40 -36
  284. package/src/components/VvNav/VvNavItem.vue +12 -12
  285. package/src/components/VvNav/VvNavSeparator.vue +6 -6
  286. package/src/components/VvNav/index.ts +2 -2
  287. package/src/components/VvProgress/VvProgress.vue +27 -27
  288. package/src/components/VvProgress/index.ts +28 -28
  289. package/src/components/VvRadio/VvRadio.vue +115 -112
  290. package/src/components/VvRadio/index.ts +28 -28
  291. package/src/components/VvRadioGroup/VvRadioGroup.vue +91 -90
  292. package/src/components/VvSelect/VvSelect.vue +262 -241
  293. package/src/components/VvSelect/index.ts +88 -63
  294. package/src/components/VvTab/VvTab.vue +79 -69
  295. package/src/components/VvTab/index.ts +12 -12
  296. package/src/components/VvTextarea/VvTextarea.vue +218 -219
  297. package/src/components/VvTextarea/index.ts +35 -35
  298. package/src/components/VvTooltip/VvTooltip.vue +22 -16
  299. package/src/components/VvTooltip/index.ts +12 -12
  300. package/src/components/common/HintSlot.ts +149 -150
  301. package/src/components/index.ts +10 -0
  302. package/src/composables/alert/useAlert.ts +76 -73
  303. package/src/composables/alert/useInjectAlert.ts +1 -1
  304. package/src/composables/alert/useProvideAlert.ts +10 -10
  305. package/src/composables/dropdown/useInjectDropdown.ts +6 -6
  306. package/src/composables/dropdown/useProvideDropdown.ts +63 -63
  307. package/src/composables/group/useInjectedGroupState.ts +46 -42
  308. package/src/composables/group/useProvideGroupState.ts +9 -15
  309. package/src/composables/index.ts +1 -0
  310. package/src/composables/useBlurhash.ts +68 -0
  311. package/src/composables/useComponentFocus.ts +9 -9
  312. package/src/composables/useComponentIcon.ts +36 -35
  313. package/src/composables/useDebouncedInput.ts +25 -25
  314. package/src/composables/useDefaults.ts +77 -76
  315. package/src/composables/useModifiers.ts +29 -29
  316. package/src/composables/useOptions.ts +52 -43
  317. package/src/composables/usePersistence.ts +74 -0
  318. package/src/composables/useTextCount.ts +44 -44
  319. package/src/composables/useUniqueId.ts +3 -2
  320. package/src/composables/useVolver.ts +1 -1
  321. package/src/constants.ts +97 -82
  322. package/src/directives/index.ts +3 -6
  323. package/src/directives/v-contextmenu.ts +34 -34
  324. package/src/directives/v-tooltip.ts +18 -9
  325. package/src/index.ts +6 -4
  326. package/src/props/index.ts +457 -380
  327. package/src/resolvers/unplugin.ts +146 -136
  328. package/src/shims.d.ts +4 -5
  329. package/src/stories/Accordion/Accordion.settings.ts +51 -50
  330. package/src/stories/Accordion/Accordion.stories.ts +21 -21
  331. package/src/stories/Accordion/Accordion.test.ts +56 -54
  332. package/src/stories/Accordion/AccordionSlots.stories.ts +13 -13
  333. package/src/stories/AccordionGroup/AccordionGroup.settings.ts +70 -67
  334. package/src/stories/AccordionGroup/AccordionGroup.stories.ts +41 -39
  335. package/src/stories/AccordionGroup/AccordionGroup.test.ts +49 -45
  336. package/src/stories/AccordionGroup/AccordionGroupSlots.stories.ts +35 -35
  337. package/src/stories/Alert/Alert.settings.ts +117 -116
  338. package/src/stories/Alert/Alert.stories.ts +30 -30
  339. package/src/stories/Alert/Alert.test.ts +78 -80
  340. package/src/stories/Alert/AlertModifiers.stories.ts +45 -45
  341. package/src/stories/Alert/AlertSlots.stories.ts +35 -35
  342. package/src/stories/AlertGroup/AlertGroup.settings.ts +107 -105
  343. package/src/stories/AlertGroup/AlertGroup.stories.ts +25 -25
  344. package/src/stories/AlertGroup/AlertGroup.test.ts +67 -69
  345. package/src/stories/AlertGroup/AlertGroupPosition.stories.ts +68 -68
  346. package/src/stories/AlertGroup/AlertGroupSlots.stories.ts +23 -23
  347. package/src/stories/AlertGroup/AlertGroupWithComposable.stories.ts +58 -58
  348. package/src/stories/Avatar/Avatar.settings.ts +29 -29
  349. package/src/stories/Avatar/Avatar.stories.ts +23 -23
  350. package/src/stories/Avatar/Avatar.test.ts +22 -24
  351. package/src/stories/Avatar/AvatarBadge.stories.ts +15 -15
  352. package/src/stories/Avatar/AvatarModifiers.stories.ts +61 -61
  353. package/src/stories/Avatar/AvatarSlots.stories.ts +18 -18
  354. package/src/stories/AvatarGroup/AvatarGroup.settings.ts +54 -53
  355. package/src/stories/AvatarGroup/AvatarGroup.stories.ts +17 -17
  356. package/src/stories/AvatarGroup/AvatarGroup.test.ts +24 -26
  357. package/src/stories/AvatarGroup/AvatarGroupModifiers.stories.ts +15 -15
  358. package/src/stories/AvatarGroup/AvatarGroupSlotDefault.stories.ts +17 -17
  359. package/src/stories/Badge/Badge.settings.ts +21 -20
  360. package/src/stories/Badge/Badge.stories.ts +24 -24
  361. package/src/stories/Badge/Badge.test.ts +8 -8
  362. package/src/stories/Badge/BadgeSlots.stories.ts +10 -10
  363. package/src/stories/Blurhash/BlurhashComposable.stories.ts +196 -0
  364. package/src/stories/Breadcrumb/Breadcrumb.settings.ts +35 -34
  365. package/src/stories/Breadcrumb/Breadcrumb.stories.ts +23 -23
  366. package/src/stories/Breadcrumb/Breadcrumb.test.ts +44 -43
  367. package/src/stories/Breadcrumb/BreadcrumbSlots.stories.ts +17 -17
  368. package/src/stories/Button/Button.settings.ts +146 -150
  369. package/src/stories/Button/Button.stories.ts +19 -19
  370. package/src/stories/Button/Button.test.ts +41 -42
  371. package/src/stories/Button/ButtonIcon.stories.ts +42 -42
  372. package/src/stories/Button/ButtonLink.stories.ts +24 -24
  373. package/src/stories/Button/ButtonLoading.stories.ts +22 -22
  374. package/src/stories/Button/ButtonModifiers.stories.ts +91 -91
  375. package/src/stories/Button/ButtonSlots.stories.ts +47 -47
  376. package/src/stories/Button/ButtonState.stories.ts +23 -23
  377. package/src/stories/Button/ButtonToggle.stories.ts +30 -30
  378. package/src/stories/ButtonGroup/ButtonGroup.settings.ts +33 -24
  379. package/src/stories/ButtonGroup/ButtonGroup.stories.ts +20 -20
  380. package/src/stories/ButtonGroup/ButtonGroup.test.ts +23 -26
  381. package/src/stories/ButtonGroup/ButtonGroupModifiers.stories.ts +20 -20
  382. package/src/stories/ButtonGroup/ButtonGroupSlots.stories.ts +18 -18
  383. package/src/stories/ButtonGroup/ButtonGroupToggle.stories.ts +22 -22
  384. package/src/stories/Card/Card.settings.ts +49 -48
  385. package/src/stories/Card/Card.stories.ts +22 -22
  386. package/src/stories/Card/Card.test.ts +14 -16
  387. package/src/stories/Card/CardSlots.stories.ts +42 -42
  388. package/src/stories/Checkbox/Checkbox.settings.ts +36 -35
  389. package/src/stories/Checkbox/Checkbox.stories.ts +57 -57
  390. package/src/stories/Checkbox/Checkbox.test.ts +63 -66
  391. package/src/stories/Checkbox/CheckboxBinary.stories.ts +18 -18
  392. package/src/stories/Checkbox/CheckboxSlots.stories.ts +15 -15
  393. package/src/stories/CheckboxGroup/CheckboxGroup.settings.ts +9 -9
  394. package/src/stories/CheckboxGroup/CheckboxGroup.stories.ts +50 -50
  395. package/src/stories/CheckboxGroup/CheckboxGroup.test.ts +63 -67
  396. package/src/stories/CheckboxGroup/CheckboxGroupOptions.stories.ts +34 -34
  397. package/src/stories/CheckboxGroup/CheckboxGroupSlots.stories.ts +23 -23
  398. package/src/stories/Combobox/Combobox.settings.ts +407 -384
  399. package/src/stories/Combobox/Combobox.stories.ts +116 -107
  400. package/src/stories/Combobox/Combobox.test.ts +91 -91
  401. package/src/stories/Combobox/ComboboxIconPosition.stories.ts +25 -24
  402. package/src/stories/Combobox/ComboboxMultiple.stories.ts +32 -22
  403. package/src/stories/Combobox/ComboboxOptions.stories.ts +81 -84
  404. package/src/stories/Combobox/ComboboxSlots.stories.ts +56 -55
  405. package/src/stories/Dialog/Dialog.settings.ts +49 -40
  406. package/src/stories/Dialog/Dialog.stories.ts +28 -28
  407. package/src/stories/Dialog/Dialog.test.ts +49 -54
  408. package/src/stories/Dialog/DialogModifiers.stories.ts +42 -0
  409. package/src/stories/Dialog/DialogSlots.stories.ts +20 -20
  410. package/src/stories/Dropdown/Dropdown.settings.ts +63 -62
  411. package/src/stories/Dropdown/Dropdown.stories.ts +59 -59
  412. package/src/stories/Dropdown/Dropdown.test.ts +9 -13
  413. package/src/stories/Dropdown/DropdownContextmenuDirective.stories.ts +16 -16
  414. package/src/stories/Dropdown/DropdownMultilevel.stories.ts +18 -18
  415. package/src/stories/Dropdown/DropdownSlots.stories.ts +50 -50
  416. package/src/stories/Icon/Icon.settings.ts +66 -65
  417. package/src/stories/Icon/Icon.stories.ts +28 -29
  418. package/src/stories/Icon/IconsCollection.stories.ts +22 -22
  419. package/src/stories/InputFile/InputFile.settings.ts +37 -0
  420. package/src/stories/InputFile/InputFile.stories.ts +89 -0
  421. package/src/stories/InputFile/InputFileDropArea.stories.ts +56 -0
  422. package/src/stories/InputFile/InputFileIconPosition.stories.ts +43 -0
  423. package/src/stories/InputFile/InputFileSlots.stories.ts +33 -0
  424. package/src/stories/InputText/InputText.settings.ts +246 -244
  425. package/src/stories/InputText/InputText.stories.ts +67 -67
  426. package/src/stories/InputText/InputText.test.ts +118 -121
  427. package/src/stories/InputText/InputTextIconPosition.stories.ts +24 -24
  428. package/src/stories/InputText/InputTextLength.stories.ts +33 -33
  429. package/src/stories/InputText/InputTextMask.stories.ts +91 -91
  430. package/src/stories/InputText/InputTextMinMax.stories.ts +30 -30
  431. package/src/stories/InputText/InputTextSlots.stories.ts +20 -20
  432. package/src/stories/InputText/InputTextType.stories.ts +70 -70
  433. package/src/stories/Nav/Nav.settings.ts +27 -27
  434. package/src/stories/Nav/Nav.stories.ts +18 -18
  435. package/src/stories/Nav/Nav.test.ts +10 -12
  436. package/src/stories/Nav/NavModifiers.stories.ts +25 -25
  437. package/src/stories/Progress/Progress.settings.ts +24 -23
  438. package/src/stories/Progress/Progress.stories.ts +23 -23
  439. package/src/stories/Progress/Progress.test.ts +4 -4
  440. package/src/stories/Radio/Radio.settings.ts +9 -9
  441. package/src/stories/Radio/Radio.stories.ts +47 -47
  442. package/src/stories/Radio/Radio.test.ts +54 -57
  443. package/src/stories/Radio/RadioSlots.stories.ts +15 -15
  444. package/src/stories/RadioGroup/RadioGroup.settings.ts +9 -9
  445. package/src/stories/RadioGroup/RadioGroup.stories.ts +51 -52
  446. package/src/stories/RadioGroup/RadioGroup.test.ts +63 -67
  447. package/src/stories/RadioGroup/RadioGroupOptions.stories.ts +35 -35
  448. package/src/stories/RadioGroup/RadioGroupSlots.stories.ts +23 -23
  449. package/src/stories/Select/Select.settings.ts +71 -70
  450. package/src/stories/Select/Select.stories.ts +75 -66
  451. package/src/stories/Select/Select.test.ts +67 -70
  452. package/src/stories/Select/SelectIconPosition.stories.ts +27 -26
  453. package/src/stories/Select/SelectOptions.stories.ts +55 -55
  454. package/src/stories/Select/SelectSlots.stories.ts +21 -20
  455. package/src/stories/Tab/Tab.settings.ts +34 -34
  456. package/src/stories/Tab/Tab.stories.ts +17 -17
  457. package/src/stories/Tab/Tab.test.ts +17 -19
  458. package/src/stories/Textarea/Textarea.settings.ts +79 -77
  459. package/src/stories/Textarea/Textarea.stories.ts +63 -63
  460. package/src/stories/Textarea/Textarea.test.ts +70 -73
  461. package/src/stories/Textarea/TextareaLength.stories.ts +33 -33
  462. package/src/stories/Textarea/TextareaSlots.stories.ts +20 -20
  463. package/src/stories/Textarea/TextareatIconPosition.stories.ts +24 -24
  464. package/src/stories/Tooltip/Tooltip.settings.ts +16 -17
  465. package/src/stories/Tooltip/Tooltip.stories.ts +18 -18
  466. package/src/stories/Tooltip/Tooltip.test.ts +53 -54
  467. package/src/stories/Tooltip/TooltipDirective.stories.ts +37 -37
  468. package/src/stories/argTypes.ts +506 -505
  469. package/src/test/expect.ts +72 -77
  470. package/src/test/options.ts +17 -16
  471. package/src/test/sleep.ts +3 -2
  472. package/src/test/types.d.ts +11 -11
  473. package/src/types/alert.ts +21 -17
  474. package/src/types/blurhash.ts +21 -0
  475. package/src/types/generic.ts +2 -3
  476. package/src/types/group.ts +34 -26
  477. package/src/types/index.ts +7 -0
  478. package/src/types/input-file.ts +18 -0
  479. package/src/types/nav.ts +13 -14
  480. package/src/utils/ObjectUtilities.ts +192 -188
  481. package/src/workers/blurhash.ts +9 -0
@@ -1,625 +1,645 @@
1
- <script lang="ts">
2
- export default {
3
- name: 'VvCombobox',
4
- components: {
5
- VvDropdown,
6
- VvDropdownOption,
7
- VvDropdownOptgroup,
8
- VvButton,
9
- },
10
- }
1
+ <script setup lang="ts" generic="T extends string | Option">
2
+ import type { Ref } from 'vue'
3
+ import { toRefs } from 'vue'
4
+ import VvIcon from '../VvIcon/VvIcon.vue'
5
+ import VvDropdown from '../VvDropdown/VvDropdown.vue'
6
+ import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
7
+ import VvDropdownOptgroup from '../VvDropdown/VvDropdownOptgroup.vue'
8
+ import VvSelect from '../VvSelect/VvSelect.vue'
9
+ import VvBadge from '../VvBadge/VvBadge.vue'
10
+ import VvButton from '../VvButton/VvButton.vue'
11
+ import HintSlotFactory from '../common/HintSlot'
12
+ import type { Option } from '../../types/generic'
13
+ import { DropdownRole } from '../../constants'
14
+ import { type VvComboboxEvents, useVvComboboxProps } from '.'
15
+
16
+ // props, emit and slots
17
+ // WARNING: This is a provisiaonal implementation, it may change in the future
18
+ const props = defineProps(useVvComboboxProps<T>())
19
+ const emit = defineEmits<VvComboboxEvents>()
20
+ const slots = useSlots()
21
+
22
+ // props merged with volver defaults (now only for labels)
23
+ const VvComboboxProps = useVvComboboxProps<T>()
24
+ const propsDefaults = useDefaults<typeof VvComboboxProps>(
25
+ 'VvCombobox',
26
+ VvComboboxProps,
27
+ props,
28
+ )
29
+
30
+ // template ref
31
+ const inputEl: Ref<HTMLElement | null> = ref(null)
32
+ const inputSearchEl: Ref<HTMLElement | null> = ref(null)
33
+ const wrapperEl: Ref<HTMLElement | null> = ref(null)
34
+ const dropdownEl = ref<typeof VvDropdown | null>(null)
35
+
36
+ // hint slot
37
+ const {
38
+ HintSlot,
39
+ hasHintLabelOrSlot,
40
+ hasInvalidLabelOrSlot,
41
+ hintSlotScope,
42
+ } = HintSlotFactory(propsDefaults, slots)
43
+
44
+ // focus
45
+ const { focused } = useComponentFocus(inputEl, emit)
46
+ const { focused: focusedWithin } = useFocusWithin(wrapperEl)
47
+
48
+ watch(focused, (newValue) => {
49
+ if (!props.autoOpen) {
50
+ return
51
+ }
52
+ if (newValue && !expanded.value) {
53
+ expand()
54
+ return
55
+ }
56
+ if (!newValue && expanded.value && !focusedWithin.value) {
57
+ collapse()
58
+ }
59
+ })
60
+
61
+ watch(focusedWithin, (newValue) => {
62
+ if (!focused.value && !newValue && expanded.value) {
63
+ collapse()
64
+ }
65
+ })
66
+
67
+ // search
68
+ const searchText = ref('')
69
+ const debouncedSearchText = refDebounced(
70
+ searchText,
71
+ computed(() => Number(props.debounceSearch)),
72
+ )
73
+ watch(debouncedSearchText, () => {
74
+ emit('update:search', debouncedSearchText.value)
75
+ // DEPRECATED: Must be removed in the future
76
+ // eslint-disable-next-line vue/custom-event-name-casing
77
+ emit('change:search', debouncedSearchText.value)
78
+ })
79
+
80
+ // expanded
81
+ const expanded = ref(false)
82
+ function toggleExpanded() {
83
+ if (isDisabledOrReadonly.value)
84
+ return
85
+ expanded.value = !expanded.value
86
+ }
87
+ function expand() {
88
+ if (isDisabledOrReadonly.value || expanded.value)
89
+ return
90
+ expanded.value = true
91
+ }
92
+ function collapse() {
93
+ if (isDisabledOrReadonly.value || !expanded.value)
94
+ return
95
+ expanded.value = false
96
+ }
97
+ function onAfterExpand() {
98
+ if (propsDefaults.value.searchable) {
99
+ if (inputSearchEl.value) {
100
+ inputSearchEl.value.focus({
101
+ preventScroll: true,
102
+ })
103
+ }
104
+ }
105
+ }
106
+ function onAfterCollapse() {
107
+ if (propsDefaults.value.searchable) {
108
+ searchText.value = ''
109
+ }
110
+ }
111
+
112
+ // group
113
+ function isGroup(option: T) {
114
+ if (typeof option === 'string') {
115
+ return false
116
+ }
117
+ return option.options?.length
118
+ }
119
+
120
+ // data
121
+ const {
122
+ id,
123
+ icon,
124
+ iconPosition,
125
+ modifiers,
126
+ disabled,
127
+ readonly,
128
+ loading,
129
+ valid,
130
+ invalid,
131
+ floating,
132
+ } = toRefs(props)
133
+ const hasId = useUniqueId(id)
134
+ const hasHintId = computed(() => `${hasId.value}-hint`)
135
+ const hasDropdownId = computed(() => `${hasId.value}-dropdown`)
136
+ const hasSearchId = computed(() => `${hasId.value}-search`)
137
+ const hasLabelId = computed(() => `${hasId.value}-label`)
138
+
139
+ // tabindex
140
+ const isDisabledOrReadonly = computed(() => props.disabled || props.readonly)
141
+ const hasTabindex = computed(() => {
142
+ return isDisabledOrReadonly.value ? -1 : props.tabindex
143
+ })
144
+
145
+ // modelValue
146
+ const localModelValue = computed({
147
+ get: () => {
148
+ if (Array.isArray(props.modelValue)) {
149
+ return new Set(props.modelValue)
150
+ }
151
+ return props.modelValue !== undefined && props.modelValue !== null ? new Set([props.modelValue]) : new Set()
152
+ },
153
+ set: (value: Set<unknown>) => {
154
+ emit('update:modelValue', props.multiple ? [...value] : [...value].pop())
155
+ },
156
+ })
157
+ const sizeOfModelValue = computed(() => localModelValue.value.size)
158
+ const isDirty = computed(() => sizeOfModelValue.value > 0)
159
+ const hasMaxValues = computed(() => {
160
+ if (!props.multiple) {
161
+ return 1
162
+ }
163
+ if (props.maxValues === undefined) {
164
+ return Infinity
165
+ }
166
+ return Number(props.maxValues)
167
+ })
168
+ const isUnselectable = computed(() => {
169
+ if (isDisabledOrReadonly.value) {
170
+ return false
171
+ }
172
+ // DEPRECATED: Must be removed in the future
173
+ if (!props.unselectable) {
174
+ return false
175
+ }
176
+ return sizeOfModelValue.value > Number(props.minValues)
177
+ })
178
+ const isSelectable = computed(() => {
179
+ if (isDisabledOrReadonly.value) {
180
+ return false
181
+ }
182
+ if (!props.multiple) {
183
+ return true
184
+ }
185
+ return sizeOfModelValue.value < hasMaxValues.value
186
+ })
187
+
188
+ // loading
189
+ const localLoading = ref(false)
190
+ const isLoading = computed(() => localLoading.value || loading.value)
191
+
192
+ // icons
193
+ const { hasIconBefore, hasIconAfter } = useComponentIcon(icon, iconPosition)
194
+
195
+ // styles
196
+ const bemCssClasses = useModifiers(
197
+ 'vv-select',
198
+ modifiers,
199
+ computed(() => ({
200
+ 'disabled': disabled.value,
201
+ 'loading': isLoading.value,
202
+ 'readonly': readonly.value,
203
+ 'icon-before': hasIconBefore.value !== undefined,
204
+ 'icon-after': hasIconAfter.value !== undefined,
205
+ 'valid': valid.value,
206
+ 'invalid': invalid.value,
207
+ 'dirty': isDirty.value,
208
+ 'focus': focused.value || focusedWithin.value || expanded.value,
209
+ 'floating': floating.value,
210
+ 'badges': props.badges,
211
+ })),
212
+ )
213
+
214
+ // options
215
+ const {
216
+ getOptionLabel,
217
+ getOptionValue,
218
+ getOptionGrouped,
219
+ isOptionDisabled,
220
+ } = useOptions(props)
221
+
222
+ function isOptionDisabledOrNotSelectable(option: T) {
223
+ return isOptionDisabled(option) || (!isSelectable.value && !isOptionSelected(option))
224
+ }
225
+
226
+ const filteredOptions = computedAsync(async () => {
227
+ if (propsDefaults.value.searchFunction) {
228
+ localLoading.value = true
229
+ const toReturn = await Promise.resolve(
230
+ propsDefaults.value.searchFunction(
231
+ debouncedSearchText.value,
232
+ props.options,
233
+ ),
234
+ )
235
+ localLoading.value = false
236
+ return toReturn
237
+ }
238
+ return props.options?.filter((option) => {
239
+ return getOptionLabel(option)
240
+ .toLowerCase()
241
+ .includes(debouncedSearchText.value.toLowerCase().trim())
242
+ })
243
+ })
244
+
245
+ /**
246
+ * Check if an option is selected
247
+ * @param {T} option
248
+ */
249
+ function isOptionSelected(option: T) {
250
+ return localModelValue.value.has(getOptionValue(option))
251
+ }
252
+
253
+ /**
254
+ * Compute the label to show to the user
255
+ * Check if is multiple mode, object mode or "string" mode
256
+ */
257
+ const selectedOptions = computed(() => {
258
+ const options = props.options.reduce<T[]>(
259
+ (acc, value) => {
260
+ if (isGroup(value)) {
261
+ return [...acc, ...getOptionGrouped(value)]
262
+ }
263
+ return [...acc, value]
264
+ },
265
+ [],
266
+ )
267
+ return options.filter((option) => {
268
+ return isOptionSelected(option)
269
+ })
270
+ })
271
+
272
+ const hasValue = computed(() => {
273
+ return selectedOptions.value
274
+ .map((option: T) => getOptionLabel(option))
275
+ .join(props.separator)
276
+ })
277
+
278
+ /**
279
+ * Function triggered on click on input
280
+ */
281
+ function onClickInput() {
282
+ props.autoOpen ? expand() : toggleExpanded()
283
+ }
284
+
285
+ /**
286
+ * Function triggered on option click
287
+ * @param option {T} option value
288
+ */
289
+ function onInput(option: T) {
290
+ const isSelected = isOptionSelected(option)
291
+ if (isSelected && isUnselectable.value) {
292
+ localModelValue.value.delete(getOptionValue(option))
293
+ }
294
+ else if (!isSelected && isSelectable.value) {
295
+ localModelValue.value.add(getOptionValue(option))
296
+ }
297
+ // force reactivity
298
+ localModelValue.value = new Set(localModelValue.value)
299
+ if (!props.multiple && !props.keepOpen) {
300
+ collapse()
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Auto select the first option if autoOpen is enabled
306
+ */
307
+ watch(
308
+ () => props.options,
309
+ (newValue) => {
310
+ if (newValue?.length && props.autoselectFirst && !isDirty.value) {
311
+ onInput(newValue[0])
312
+ }
313
+ },
314
+ { immediate: true },
315
+ )
316
+
317
+ const selectProps = computed(() => ({
318
+ id: hasId.value,
319
+ name: props.name,
320
+ tabindex: hasTabindex.value,
321
+ valid: valid.value,
322
+ validLabel: propsDefaults.value.validLabel,
323
+ invalid: invalid.value,
324
+ invalidLabel: propsDefaults.value.invalidLabel,
325
+ hintLabel: propsDefaults.value.hintLabel,
326
+ loading: isLoading.value,
327
+ loadingLabel: propsDefaults.value.loadingLabel,
328
+ disabled: disabled.value,
329
+ readonly: readonly.value,
330
+ modifiers: propsDefaults.value.modifiers,
331
+ options: propsDefaults.value.options,
332
+ labelKey: propsDefaults.value.labelKey,
333
+ valueKey: propsDefaults.value.valueKey,
334
+ icon: propsDefaults.value.icon,
335
+ iconPosition: propsDefaults.value.iconPosition,
336
+ floating: propsDefaults.value.floating,
337
+ unselectable: isUnselectable.value,
338
+ autoselectFirst: propsDefaults.value.autoselectFirst,
339
+ multiple: propsDefaults.value.multiple,
340
+ label: propsDefaults.value.label,
341
+ placeholder: propsDefaults.value.placeholder,
342
+ modelValue: props.modelValue,
343
+ }))
344
+
345
+ const dropdownProps = computed(() => ({
346
+ id: hasDropdownId.value,
347
+ reference: wrapperEl.value,
348
+ placement: propsDefaults.value.placement,
349
+ strategy: propsDefaults.value.strategy,
350
+ transitionName: propsDefaults.value.transitionName,
351
+ offset: propsDefaults.value.offset,
352
+ shift: propsDefaults.value.shift,
353
+ flip: propsDefaults.value.flip,
354
+ autoPlacement: propsDefaults.value.autoPlacement,
355
+ arrow: propsDefaults.value.arrow,
356
+ autofocusFirst: propsDefaults.value.searchable
357
+ ? true
358
+ : propsDefaults.value.autofocusFirst,
359
+ triggerWidth: propsDefaults.value.triggerWidth,
360
+ modifiers: propsDefaults.value.dropdownModifiers,
361
+ }))
362
+
363
+ // slots
364
+ const slotProps = computed(() => ({
365
+ valid: props.valid,
366
+ invalid: props.invalid,
367
+ modelValue: props.modelValue,
368
+ }))
369
+
370
+ // keyboard
371
+ onKeyStroke(
372
+ [' ', 'Enter'],
373
+ (e) => {
374
+ if (props.autoOpen) {
375
+ return
376
+ }
377
+ if (!expanded.value && focused.value) {
378
+ e.preventDefault()
379
+ e.stopImmediatePropagation()
380
+ toggleExpanded()
381
+ }
382
+ },
383
+ { target: inputEl },
384
+ )
11
385
  </script>
12
386
 
13
- <script setup lang="ts">
14
- import type { Ref } from 'vue'
15
- import { toRefs } from 'vue'
16
- import { VvComboboxProps, VvComboboxEvents } from '.'
17
- import VvIcon from '../VvIcon/VvIcon.vue'
18
- import VvDropdown from '../VvDropdown/VvDropdown.vue'
19
- import VvDropdownOption from '../VvDropdown/VvDropdownOption.vue'
20
- import VvDropdownOptgroup from '../VvDropdown/VvDropdownOptgroup.vue'
21
- import VvSelect from '../VvSelect/VvSelect.vue'
22
- import VvBadge from '../VvBadge/VvBadge.vue'
23
- import VvButton from '../VvButton/VvButton.vue'
24
- import HintSlotFactory from '../common/HintSlot'
25
- import type { Option } from '../../types/generic'
26
- import { DropdownRole } from '../../constants'
27
-
28
- // props, emit and slots
29
- const props = defineProps(VvComboboxProps)
30
- const emit = defineEmits(VvComboboxEvents)
31
- const slots = useSlots()
32
-
33
- // props merged with volver defaults (now only for labels)
34
- const propsDefaults = useDefaults<typeof VvComboboxProps>(
35
- 'VvCombobox',
36
- VvComboboxProps,
37
- props,
38
- )
39
-
40
- // Grouped options
41
- const isGroup = (option: string | Option) => {
42
- if (typeof option === 'string') {
43
- return false
44
- }
45
- return option.options && option.options.length > 0
46
- }
47
-
48
- // hint slot
49
- const {
50
- HintSlot,
51
- hasHintLabelOrSlot,
52
- hasInvalidLabelOrSlot,
53
- hintSlotScope,
54
- } = HintSlotFactory(propsDefaults, slots)
55
-
56
- // template ref
57
- const inputEl: Ref<HTMLElement | null> = ref(null)
58
- const inputSearchEl: Ref<HTMLElement | null> = ref(null)
59
- const wrapperEl: Ref<HTMLElement | null> = ref(null)
60
-
61
- // focus
62
- const { focused } = useComponentFocus(inputEl, emit)
63
- const { focused: focusedWithin } = useFocusWithin(wrapperEl)
64
-
65
- watch(focused, (newValue) => {
66
- if (!props.autoOpen) {
67
- return
68
- }
69
- if (newValue && !expanded.value) {
70
- expand()
71
- return
72
- }
73
- if (!newValue && expanded.value && !focusedWithin.value) {
74
- collapse()
75
- }
76
- })
77
-
78
- watch(focusedWithin, (newValue) => {
79
- if (!focused.value && !newValue && expanded.value) {
80
- collapse()
81
- }
82
- })
83
-
84
- // search
85
- const searchText = ref('')
86
- const debouncedSearchText = refDebounced(
87
- searchText,
88
- computed(() => Number(props.debounceSearch)),
89
- )
90
- watch(debouncedSearchText, () =>
91
- emit('change:search', debouncedSearchText.value),
92
- )
93
-
94
- // expanded
95
- const expanded = ref(false)
96
- const toggleExpanded = () => {
97
- if (props.disabled || props.readonly) return
98
- expanded.value = !expanded.value
99
- }
100
- const expand = () => {
101
- if (props.disabled || props.readonly || expanded.value) return
102
- expanded.value = true
103
- }
104
- const collapse = () => {
105
- if (props.disabled || props.readonly || !expanded.value) return
106
- expanded.value = false
107
- }
108
- const onAfterExpand = () => {
109
- if (propsDefaults.value.searchable) {
110
- if (inputSearchEl.value) {
111
- inputSearchEl.value.focus({
112
- preventScroll: true,
113
- })
114
- }
115
- }
116
- }
117
- const onAfterCollapse = () => {
118
- if (propsDefaults.value.searchable) {
119
- searchText.value = ''
120
- }
121
- }
122
-
123
- // data
124
- const {
125
- id,
126
- icon,
127
- iconPosition,
128
- modifiers,
129
- disabled,
130
- readonly,
131
- loading,
132
- valid,
133
- invalid,
134
- floating,
135
- } = toRefs(props)
136
- const hasId = useUniqueId(id)
137
- const hasHintId = computed(() => `${hasId.value}-hint`)
138
- const hasDropdownId = computed(() => `${hasId.value}-dropdown`)
139
- const hasSearchId = computed(() => `${hasId.value}-search`)
140
- const hasLabelId = computed(() => `${hasId.value}-label`)
141
-
142
- // loading
143
- const localLoading = ref(false)
144
- const isLoading = computed(() => localLoading.value || loading.value)
145
-
146
- // ref
147
- const dropdownEl = ref()
148
-
149
- // icons
150
- const { hasIcon, hasIconBefore, hasIconAfter } = useComponentIcon(
151
- icon,
152
- iconPosition,
153
- )
154
-
155
- // dirty
156
- const isDirty = computed(() => !isEmpty(props.modelValue))
157
-
158
- // tabindex
159
- const hasTabindex = computed(() => {
160
- return disabled.value || readonly.value ? -1 : props.tabindex
161
- })
162
-
163
- // styles
164
- const bemCssClasses = useModifiers(
165
- 'vv-select',
166
- modifiers,
167
- computed(() => ({
168
- disabled: disabled.value,
169
- loading: isLoading.value,
170
- readonly: readonly.value,
171
- 'icon-before': Boolean(hasIconBefore.value),
172
- 'icon-after': Boolean(hasIconAfter.value),
173
- valid: valid.value,
174
- invalid: invalid.value,
175
- dirty: isDirty.value,
176
- focus: focused.value,
177
- floating: floating.value,
178
- badges: props.badges,
179
- })),
180
- )
181
-
182
- const {
183
- getOptionLabel,
184
- getOptionValue,
185
- getOptionGrouped,
186
- isOptionDisabled,
187
- } = useOptions(props)
188
-
189
- // options filtered by search text
190
- const filteredOptions = computedAsync(async () => {
191
- if (propsDefaults.value.searchFunction) {
192
- localLoading.value = true
193
- const toReturn = await Promise.resolve(
194
- propsDefaults.value.searchFunction(
195
- debouncedSearchText.value,
196
- props.options,
197
- ),
198
- )
199
- localLoading.value = false
200
- return toReturn
201
- }
202
- return props.options?.filter((option) => {
203
- return getOptionLabel(option)
204
- .toLowerCase()
205
- .includes(debouncedSearchText.value.toLowerCase().trim())
206
- })
207
- })
208
-
209
- /**
210
- * Check if an option exist into modelValue array (multiple) or is equal to modelValue (single)
211
- * @param {String | Option} option
212
- */
213
- function isOptionSelected(option: string | Option) {
214
- if (Array.isArray(props.modelValue)) {
215
- // check if contain whole option or option value
216
- return (
217
- contains(option, props.modelValue) ||
218
- contains(getOptionValue(option), props.modelValue)
219
- )
220
- }
221
- // check if modelValue is equal to option or option value
222
- return (
223
- equals(option, props.modelValue) ||
224
- equals(getOptionValue(option), props.modelValue)
225
- )
226
- }
227
-
228
- /**
229
- * Compute the label to show to the user
230
- * Check if is multiple mode, object mode or "string" mode
231
- */
232
- const selectedOptions = computed(() => {
233
- const options = props.options.reduce<Array<Option | string>>(
234
- (acc, value) => {
235
- if (isGroup(value)) {
236
- return [...acc, ...getOptionGrouped(value)]
237
- }
238
- return [...acc, value]
239
- },
240
- [],
241
- )
242
- return options.filter((option) => {
243
- return isOptionSelected(option)
244
- })
245
- })
246
-
247
- const hasValue = computed(() => {
248
- return selectedOptions.value
249
- .map((option) => getOptionLabel(option))
250
- .join(props.separator)
251
- })
252
-
253
- /**
254
- * Function triggered on click on input
255
- */
256
- const onClickInput = () => {
257
- props.autoOpen ? expand() : toggleExpanded()
258
- }
259
-
260
- /**
261
- * Function triggered on input of checkbox or radio (multple or single mode)
262
- * @param event on input event (checkbox or radio input)
263
- */
264
- const onInput = (option: string | Option) => {
265
- if (props.disabled || props.readonly) {
266
- return
267
- }
268
-
269
- // get option value
270
- const value = getOptionValue(option)
271
- let toReturn: string | string[] | Option | Option[] | undefined = value
272
-
273
- // check multiple prop, override value with array and remove or add the value
274
- if (props.multiple) {
275
- // check max-values prop and block check new values
276
- if (Array.isArray(props.modelValue)) {
277
- const maxValues = Number(props.maxValues)
278
- if (
279
- props.maxValues !== undefined &&
280
- maxValues >= 0 &&
281
- props.modelValue?.length >= maxValues
282
- ) {
283
- if (!contains(value, props.modelValue)) {
284
- // maxValues reached
285
- return
286
- }
287
- }
288
- toReturn = contains(value, props.modelValue)
289
- ? removeFromList(value, props.modelValue)
290
- : [...props.modelValue, value]
291
- } else {
292
- toReturn = [value as Option]
293
- }
294
- } else {
295
- if (!props.keepOpen) {
296
- collapse()
297
- }
298
- if (Array.isArray(props.modelValue)) {
299
- if (props.unselectable && props.modelValue.includes(value)) {
300
- toReturn = []
301
- } else {
302
- toReturn = [value]
303
- }
304
- } else if (props.unselectable && value === props.modelValue) {
305
- toReturn = undefined
306
- }
307
- }
308
- emit('update:modelValue', toReturn)
309
- }
310
-
311
- const selectProps = computed(() => ({
312
- id: hasId.value,
313
- name: props.name,
314
- tabindex: hasTabindex.value,
315
- valid: valid.value,
316
- validLabel: propsDefaults.value.validLabel,
317
- invalid: invalid.value,
318
- invalidLabel: propsDefaults.value.invalidLabel,
319
- hintLabel: propsDefaults.value.hintLabel,
320
- loading: isLoading.value,
321
- loadingLabel: propsDefaults.value.loadingLabel,
322
- disabled: disabled.value,
323
- readonly: readonly.value,
324
- modifiers: propsDefaults.value.modifiers,
325
- options: propsDefaults.value.options,
326
- labelKey: propsDefaults.value.labelKey,
327
- valueKey: propsDefaults.value.valueKey,
328
- icon: propsDefaults.value.icon,
329
- iconPosition: propsDefaults.value.iconPosition,
330
- floating: propsDefaults.value.floating,
331
- unselectable: propsDefaults.value.unselectable,
332
- multiple: propsDefaults.value.multiple,
333
- label: propsDefaults.value.label,
334
- placeholder: propsDefaults.value.placeholder,
335
- modelValue: props.modelValue,
336
- }))
337
-
338
- const dropdownProps = computed(() => ({
339
- id: hasDropdownId.value,
340
- reference: wrapperEl.value,
341
- placement: propsDefaults.value.placement,
342
- strategy: propsDefaults.value.strategy,
343
- transitionName: propsDefaults.value.transitionName,
344
- offset: propsDefaults.value.offset,
345
- shift: propsDefaults.value.shift,
346
- flip: propsDefaults.value.flip,
347
- autoPlacement: propsDefaults.value.autoPlacement,
348
- arrow: propsDefaults.value.arrow,
349
- autofocusFirst: propsDefaults.value.searchable
350
- ? true
351
- : propsDefaults.value.autofocusFirst,
352
- triggerWidth: propsDefaults.value.triggerWidth,
353
- modifiers: propsDefaults.value.dropdownModifiers,
354
- }))
355
-
356
- // slots
357
- const slotProps = computed(() => ({
358
- valid: props.valid,
359
- invalid: props.invalid,
360
- modelValue: props.modelValue,
361
- }))
362
-
363
- // computed
364
- onKeyStroke(
365
- [' ', 'Enter'],
366
- (e) => {
367
- if (props.autoOpen) {
368
- return
369
- }
370
- if (!expanded.value && focused.value) {
371
- e.preventDefault()
372
- e.stopImmediatePropagation()
373
- toggleExpanded()
374
- }
375
- },
376
- { target: inputEl },
377
- )
387
+ <script lang="ts">
388
+ export default {
389
+ name: 'VvCombobox',
390
+ components: {
391
+ VvDropdown,
392
+ VvDropdownOption,
393
+ VvDropdownOptgroup,
394
+ VvButton,
395
+ },
396
+ }
378
397
  </script>
379
398
 
380
399
  <template>
381
- <div v-if="!native" :id="hasId" :class="bemCssClasses">
382
- <label
383
- v-if="label"
384
- :id="hasLabelId"
385
- :for="propsDefaults.searchable ? hasSearchId : undefined"
386
- >
387
- {{ label }}
388
- </label>
389
- <div ref="wrapperEl" class="vv-select__wrapper">
390
- <VvDropdown
391
- ref="dropdownEl"
392
- v-model="expanded"
393
- v-bind="dropdownProps"
394
- :role="DropdownRole.listbox"
395
- @after-expand="onAfterExpand"
396
- @after-collapse="onAfterCollapse"
397
- >
398
- <template
399
- v-if="
400
- propsDefaults.searchable || $slots['dropdown::before']
401
- "
402
- #before
403
- >
404
- <!-- @slot Slot before dropdown items -->
405
- <slot name="dropdown::before" />
406
- <input
407
- v-if="propsDefaults.searchable && !disabled"
408
- :id="hasSearchId"
409
- ref="inputSearchEl"
410
- v-model="searchText"
411
- aria-autocomplete="list"
412
- :aria-controls="hasDropdownId"
413
- autocomplete="off"
414
- spellcheck="false"
415
- type="search"
416
- class="vv-dropdown__search"
417
- :placeholder="propsDefaults.searchPlaceholder"
418
- />
419
- </template>
420
- <template #default="{ aria }">
421
- <div v-if="$slots.before" class="vv-select__input-before">
422
- <!-- @slot Slot before input -->
423
- <slot name="before" v-bind="slotProps" />
424
- </div>
425
- <div class="vv-select__inner">
426
- <VvIcon
427
- v-if="hasIconBefore"
428
- class="vv-select__icon"
429
- v-bind="hasIcon"
430
- />
431
- <div
432
- ref="inputEl"
433
- v-bind="aria"
434
- class="vv-select__input"
435
- role="combobox"
436
- :aria-expanded="expanded"
437
- :aria-labelledby="hasLabelId"
438
- :aria-describedby="
439
- hasHintLabelOrSlot ? hasHintId : undefined
440
- "
441
- :aria-errormessage="
442
- hasInvalidLabelOrSlot ? hasHintId : undefined
443
- "
444
- :tabindex="hasTabindex"
445
- @click.passive="onClickInput"
446
- >
447
- <!-- @slot Slot for value customization -->
448
- <slot
449
- name="value"
450
- v-bind="{ selectedOptions, onInput }"
451
- >
452
- <template v-if="hasValue">
453
- <div
454
- v-if="!badges"
455
- class="vv-select__value"
456
- >
457
- {{ hasValue }}
458
- </div>
459
- <VvBadge
460
- v-for="(
461
- option, index
462
- ) in selectedOptions"
463
- v-else
464
- :key="index"
465
- :modifiers="badgeModifiers"
466
- class="vv-select__badge"
467
- >
468
- {{ getOptionLabel(option) }}
469
- <button
470
- v-if="
471
- unselectable &&
472
- !readonly &&
473
- !disabled
474
- "
475
- :aria-label="
476
- propsDefaults.deselectActionLabel
477
- "
478
- type="button"
479
- @click.stop="onInput(option)"
480
- >
481
- <VvIcon name="close" />
482
- </button>
483
- </VvBadge>
484
- </template>
485
- <template v-else>
486
- {{ placeholder }}
487
- </template>
488
- </slot>
489
- </div>
490
- <VvIcon
491
- v-if="hasIconAfter"
492
- class="vv-select__icon vv-select__icon-after"
493
- v-bind="hasIcon"
494
- />
495
- </div>
496
- <div v-if="$slots.after" class="vv-select__input-after">
497
- <!-- @slot Slot after input -->
498
- <slot name="after" v-bind="slotProps" />
499
- </div>
500
- </template>
501
- <template #items>
502
- <template v-if="!disabled && filteredOptions?.length">
503
- <template
504
- v-for="(option, index) in filteredOptions"
505
- :key="index"
506
- >
507
- <template v-if="isGroup(option)">
508
- <VvDropdownOptgroup
509
- :label="getOptionLabel(option)"
510
- />
511
- <VvDropdownOption
512
- v-for="(item, i) in getOptionGrouped(
513
- option,
514
- )"
515
- v-bind="{
516
- selected: isOptionSelected(item),
517
- disabled: isOptionDisabled(item),
518
- unselectable,
519
- deselectHintLabel:
520
- propsDefaults.deselectHintLabel,
521
- selectHintLabel:
522
- propsDefaults.selectHintLabel,
523
- selectedHintLabel:
524
- propsDefaults.selectedHintLabel,
525
- }"
526
- :key="i"
527
- class="vv-dropdown-option"
528
- @click.passive="onInput(item)"
529
- >
530
- <!-- @slot Slot for option customization -->
531
- <slot
532
- name="option"
533
- v-bind="{
534
- option,
535
- selectedOptions,
536
- selected: isOptionSelected(item),
537
- disabled: isOptionDisabled(item),
538
- }"
539
- >
540
- {{ getOptionLabel(item) }}
541
- </slot>
542
- </VvDropdownOption>
543
- </template>
544
- <VvDropdownOption
545
- v-else
546
- v-bind="{
547
- selected: isOptionSelected(option),
548
- disabled: isOptionDisabled(option),
549
- unselectable,
550
- deselectHintLabel:
551
- propsDefaults.deselectHintLabel,
552
- selectHintLabel:
553
- propsDefaults.selectHintLabel,
554
- selectedHintLabel:
555
- propsDefaults.selectedHintLabel,
556
- }"
557
- class="vv-dropdown-option"
558
- @click.passive="onInput(option)"
559
- >
560
- <!-- @slot Slot for option customization -->
561
- <slot
562
- name="option"
563
- v-bind="{
564
- option,
565
- selectedOptions,
566
- selected: isOptionSelected(option),
567
- disabled: isOptionDisabled(option),
568
- }"
569
- >
570
- {{ getOptionLabel(option) }}
571
- </slot>
572
- </VvDropdownOption>
573
- </template>
574
- </template>
575
- <VvDropdownOption
576
- v-else-if="!options.length"
577
- modifiers="inert"
578
- >
579
- <!-- @slot Slot for no options available -->
580
- <slot name="no-options">
581
- {{ propsDefaults.noOptionsLabel }}
582
- </slot>
583
- </VvDropdownOption>
584
- <VvDropdownOption v-else-if="!disabled" modifiers="inert">
585
- <!-- @slot Slot for no results available -->
586
- <slot name="no-results">
587
- {{ propsDefaults.noResultsLabel }}
588
- </slot>
589
- </VvDropdownOption>
590
- </template>
591
- <template #after>
592
- <!-- @slot Slot after dropdown items -->
593
- <slot name="dropdown::after">
594
- <!-- Close button if dropdown custom position is enabled and floating-ui disabled -->
595
- <VvButton
596
- v-if="dropdownEl?.customPosition"
597
- :label="propsDefaults.closeLabel"
598
- modifiers="secondary"
599
- @click="dropdownEl.hide()"
600
- />
601
- </slot>
602
- </template>
603
- </VvDropdown>
604
- </div>
605
- <HintSlot :id="hasHintId" class="vv-select__hint">
606
- <template v-if="$slots.hint" #hint>
607
- <slot name="hint" v-bind="hintSlotScope" />
608
- </template>
609
- <template v-if="$slots.loading" #loading>
610
- <slot name="loading" v-bind="hintSlotScope" />
611
- </template>
612
- <template v-if="$slots.valid" #valid>
613
- <slot name="valid" v-bind="hintSlotScope" />
614
- </template>
615
- <template v-if="$slots.invalid" #invalid>
616
- <slot name="invalid" v-bind="hintSlotScope" />
617
- </template>
618
- </HintSlot>
619
- </div>
620
- <VvSelect
621
- v-else
622
- v-bind="selectProps"
623
- @update:model-value="emit('update:modelValue', $event)"
624
- />
400
+ <div v-if="!native" :id="hasId" :class="bemCssClasses">
401
+ <label
402
+ v-if="label"
403
+ :id="hasLabelId"
404
+ :for="propsDefaults.searchable ? hasSearchId : undefined"
405
+ >
406
+ {{ label }}
407
+ </label>
408
+ <div ref="wrapperEl" class="vv-select__wrapper">
409
+ <VvDropdown
410
+ ref="dropdownEl"
411
+ v-model="expanded"
412
+ v-bind="dropdownProps"
413
+ :role="DropdownRole.listbox"
414
+ @after-expand="onAfterExpand"
415
+ @after-collapse="onAfterCollapse"
416
+ >
417
+ <template
418
+ v-if="
419
+ propsDefaults.searchable || $slots['dropdown::before']
420
+ "
421
+ #before
422
+ >
423
+ <!-- @slot Slot before dropdown items -->
424
+ <slot name="dropdown::before" />
425
+ <input
426
+ v-if="propsDefaults.searchable && !disabled"
427
+ :id="hasSearchId"
428
+ ref="inputSearchEl"
429
+ v-model="searchText"
430
+ aria-autocomplete="list"
431
+ :aria-controls="hasDropdownId"
432
+ autocomplete="off"
433
+ spellcheck="false"
434
+ type="search"
435
+ class="vv-dropdown__search"
436
+ :placeholder="propsDefaults.searchPlaceholder"
437
+ >
438
+ </template>
439
+ <template #default="{ aria }">
440
+ <div v-if="$slots.before" class="vv-select__input-before">
441
+ <!-- @slot Slot before input -->
442
+ <slot name="before" v-bind="slotProps" />
443
+ </div>
444
+ <div class="vv-select__inner">
445
+ <VvIcon
446
+ v-if="hasIconBefore"
447
+ v-bind="hasIconBefore"
448
+ class="vv-select__icon"
449
+ />
450
+ <div
451
+ ref="inputEl"
452
+ v-bind="aria"
453
+ class="vv-select__input"
454
+ role="combobox"
455
+ :aria-controls="hasDropdownId"
456
+ :aria-expanded="expanded"
457
+ :aria-labelledby="hasLabelId"
458
+ :aria-describedby="
459
+ hasHintLabelOrSlot ? hasHintId : undefined
460
+ "
461
+ :aria-errormessage="
462
+ hasInvalidLabelOrSlot ? hasHintId : undefined
463
+ "
464
+ :tabindex="hasTabindex"
465
+ @click.passive="onClickInput"
466
+ >
467
+ <!-- @slot Slot for value customization -->
468
+ <slot
469
+ name="value"
470
+ v-bind="{ selectedOptions, onInput }"
471
+ >
472
+ <template v-if="hasValue">
473
+ <div
474
+ v-if="!badges"
475
+ class="vv-select__value"
476
+ >
477
+ {{ hasValue }}
478
+ </div>
479
+ <VvBadge
480
+ v-for="(
481
+ option, index
482
+ ) in selectedOptions"
483
+ v-else
484
+ :key="index"
485
+ :modifiers="badgeModifiers"
486
+ class="vv-select__badge"
487
+ >
488
+ {{ getOptionLabel(option) }}
489
+ <button
490
+ v-if="
491
+ isUnselectable
492
+ "
493
+ :aria-label="
494
+ propsDefaults.deselectActionLabel
495
+ "
496
+ type="button"
497
+ @click.stop="onInput(option)"
498
+ >
499
+ <VvIcon name="close" />
500
+ </button>
501
+ </VvBadge>
502
+ </template>
503
+ <template v-else>
504
+ {{ placeholder }}
505
+ </template>
506
+ </slot>
507
+ </div>
508
+ <VvIcon
509
+ v-if="hasIconAfter"
510
+ v-bind="hasIconAfter"
511
+ class="vv-select__icon vv-select__icon-after"
512
+ />
513
+ </div>
514
+ <div v-if="$slots.after" class="vv-select__input-after">
515
+ <!-- @slot Slot after input -->
516
+ <slot name="after" v-bind="slotProps" />
517
+ </div>
518
+ </template>
519
+ <template #items>
520
+ <template v-if="!disabled && filteredOptions?.length">
521
+ <template
522
+ v-for="(option, index) in filteredOptions"
523
+ :key="index"
524
+ >
525
+ <template v-if="isGroup(option)">
526
+ <VvDropdownOptgroup
527
+ :label="getOptionLabel(option)"
528
+ />
529
+ <VvDropdownOption
530
+ v-for="(item, i) in getOptionGrouped(
531
+ option,
532
+ )"
533
+ v-bind="{
534
+ selected: isOptionSelected(item),
535
+ disabled: isOptionDisabledOrNotSelectable(item),
536
+ unselectable: isUnselectable,
537
+ deselectHintLabel:
538
+ propsDefaults.deselectHintLabel,
539
+ selectHintLabel:
540
+ propsDefaults.selectHintLabel,
541
+ selectedHintLabel:
542
+ propsDefaults.selectedHintLabel,
543
+ }"
544
+ :key="i"
545
+ class="vv-dropdown-option"
546
+ focus-on-hover
547
+ @click.passive="onInput(item)"
548
+ >
549
+ <!-- @slot Slot for option customization -->
550
+ <slot
551
+ name="option"
552
+ v-bind="{
553
+ option,
554
+ selectedOptions,
555
+ selected: isOptionSelected(item),
556
+ disabled: isOptionDisabledOrNotSelectable(item),
557
+ }"
558
+ >
559
+ {{ getOptionLabel(item) }}
560
+ </slot>
561
+ </VvDropdownOption>
562
+ </template>
563
+ <VvDropdownOption
564
+ v-else
565
+ v-bind="{
566
+ selected: isOptionSelected(option),
567
+ disabled: isOptionDisabledOrNotSelectable(option),
568
+ unselectable: isUnselectable,
569
+ deselectHintLabel:
570
+ propsDefaults.deselectHintLabel,
571
+ selectHintLabel:
572
+ propsDefaults.selectHintLabel,
573
+ selectedHintLabel:
574
+ propsDefaults.selectedHintLabel,
575
+ }"
576
+ class="vv-dropdown-option"
577
+ focus-on-hover
578
+ @click.passive="onInput(option)"
579
+ >
580
+ <!-- @slot Slot for option customization -->
581
+ <slot
582
+ name="option"
583
+ v-bind="{
584
+ option,
585
+ selectedOptions,
586
+ selected: isOptionSelected(option),
587
+ disabled: isOptionDisabledOrNotSelectable(option),
588
+ }"
589
+ >
590
+ {{ getOptionLabel(option) }}
591
+ </slot>
592
+ </VvDropdownOption>
593
+ </template>
594
+ </template>
595
+ <VvDropdownOption
596
+ v-else-if="!options.length"
597
+ modifiers="inert"
598
+ >
599
+ <!-- @slot Slot for no options available -->
600
+ <slot name="no-options">
601
+ {{ propsDefaults.noOptionsLabel }}
602
+ </slot>
603
+ </VvDropdownOption>
604
+ <VvDropdownOption v-else-if="!disabled" modifiers="inert">
605
+ <!-- @slot Slot for no results available -->
606
+ <slot name="no-results">
607
+ {{ propsDefaults.noResultsLabel }}
608
+ </slot>
609
+ </VvDropdownOption>
610
+ </template>
611
+ <template #after>
612
+ <!-- @slot Slot after dropdown items -->
613
+ <slot name="dropdown::after">
614
+ <!-- Close button if dropdown custom position is enabled and floating-ui disabled -->
615
+ <VvButton
616
+ v-if="dropdownEl?.customPosition"
617
+ :label="propsDefaults.closeLabel"
618
+ modifiers="secondary"
619
+ @click="dropdownEl.hide()"
620
+ />
621
+ </slot>
622
+ </template>
623
+ </VvDropdown>
624
+ </div>
625
+ <HintSlot :id="hasHintId" class="vv-select__hint">
626
+ <template v-if="$slots.hint" #hint>
627
+ <slot name="hint" v-bind="hintSlotScope" />
628
+ </template>
629
+ <template v-if="$slots.loading" #loading>
630
+ <slot name="loading" v-bind="hintSlotScope" />
631
+ </template>
632
+ <template v-if="$slots.valid" #valid>
633
+ <slot name="valid" v-bind="hintSlotScope" />
634
+ </template>
635
+ <template v-if="$slots.invalid" #invalid>
636
+ <slot name="invalid" v-bind="hintSlotScope" />
637
+ </template>
638
+ </HintSlot>
639
+ </div>
640
+ <VvSelect
641
+ v-else
642
+ v-bind="selectProps"
643
+ @update:model-value="emit('update:modelValue', $event)"
644
+ />
625
645
  </template>