@volverjs/ui-vue 0.0.10-beta.5 → 0.0.10-beta.50

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