@nuxt/ui 3.0.0-alpha.8 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/.nuxt/ui/accordion.ts +2 -2
  2. package/.nuxt/ui/alert.ts +122 -95
  3. package/.nuxt/ui/avatar-group.ts +14 -2
  4. package/.nuxt/ui/avatar.ts +16 -4
  5. package/.nuxt/ui/badge.ts +139 -93
  6. package/.nuxt/ui/breadcrumb.ts +5 -5
  7. package/.nuxt/ui/button-group.ts +13 -0
  8. package/.nuxt/ui/button.ts +167 -136
  9. package/.nuxt/ui/calendar.ts +103 -0
  10. package/.nuxt/ui/card.ts +27 -1
  11. package/.nuxt/ui/carousel.ts +9 -7
  12. package/.nuxt/ui/checkbox.ts +45 -27
  13. package/.nuxt/ui/chip.ts +44 -15
  14. package/.nuxt/ui/color-picker.ts +47 -0
  15. package/.nuxt/ui/command-palette.ts +28 -18
  16. package/.nuxt/ui/container.ts +1 -1
  17. package/.nuxt/ui/context-menu.ts +64 -46
  18. package/.nuxt/ui/drawer.ts +83 -15
  19. package/.nuxt/ui/dropdown-menu.ts +65 -47
  20. package/.nuxt/ui/form-field.ts +15 -7
  21. package/.nuxt/ui/index.ts +7 -1
  22. package/.nuxt/ui/input-menu.ts +150 -116
  23. package/.nuxt/ui/input-number.ts +235 -0
  24. package/.nuxt/ui/input.ts +111 -76
  25. package/.nuxt/ui/kbd.ts +18 -6
  26. package/.nuxt/ui/link.ts +3 -3
  27. package/.nuxt/ui/modal.ts +8 -7
  28. package/.nuxt/ui/navigation-menu.ts +244 -131
  29. package/.nuxt/ui/pin-input.ts +171 -0
  30. package/.nuxt/ui/popover.ts +2 -2
  31. package/.nuxt/ui/progress.ts +111 -72
  32. package/.nuxt/ui/radio-group.ts +45 -22
  33. package/.nuxt/ui/select-menu.ts +127 -96
  34. package/.nuxt/ui/select.ts +120 -84
  35. package/.nuxt/ui/separator.ts +60 -31
  36. package/.nuxt/ui/skeleton.ts +1 -1
  37. package/.nuxt/ui/slideover.ts +17 -9
  38. package/.nuxt/ui/slider.ts +61 -38
  39. package/.nuxt/ui/stepper.ts +202 -0
  40. package/.nuxt/ui/switch.ts +40 -22
  41. package/.nuxt/ui/table.ts +49 -31
  42. package/.nuxt/ui/tabs.ts +101 -73
  43. package/.nuxt/ui/textarea.ts +111 -76
  44. package/.nuxt/ui/toast.ts +53 -33
  45. package/.nuxt/ui/toaster.ts +31 -15
  46. package/.nuxt/ui/tooltip.ts +2 -2
  47. package/.nuxt/ui/tree.ts +154 -0
  48. package/.nuxt/ui.css +92 -0
  49. package/README.md +69 -18
  50. package/cli/commands/{init.mjs → make/component.mjs} +16 -4
  51. package/cli/commands/make/index.mjs +14 -0
  52. package/cli/commands/make/locale.mjs +64 -0
  53. package/cli/index.mjs +2 -2
  54. package/cli/package.json +2 -2
  55. package/cli/templates.mjs +62 -12
  56. package/cli/utils.mjs +14 -0
  57. package/dist/module.cjs +9 -170
  58. package/dist/module.d.cts +5 -15
  59. package/dist/module.d.mts +5 -15
  60. package/dist/module.d.ts +5 -15
  61. package/dist/module.json +2 -2
  62. package/dist/module.mjs +12 -167
  63. package/dist/runtime/components/Accordion.vue +8 -39
  64. package/dist/runtime/components/Alert.vue +25 -21
  65. package/dist/runtime/components/App.vue +15 -15
  66. package/dist/runtime/components/Avatar.vue +33 -21
  67. package/dist/runtime/components/AvatarGroup.vue +5 -7
  68. package/dist/runtime/components/Badge.vue +10 -8
  69. package/dist/runtime/components/Breadcrumb.vue +13 -34
  70. package/dist/runtime/components/Button.vue +5 -8
  71. package/dist/runtime/components/ButtonGroup.vue +5 -7
  72. package/dist/runtime/components/Calendar.vue +194 -0
  73. package/dist/runtime/components/Card.vue +10 -9
  74. package/dist/runtime/components/Carousel.vue +26 -17
  75. package/dist/runtime/components/Checkbox.vue +32 -38
  76. package/dist/runtime/components/Chip.vue +6 -8
  77. package/dist/runtime/components/Collapsible.vue +10 -11
  78. package/dist/runtime/components/ColorPicker.vue +297 -0
  79. package/dist/runtime/components/CommandPalette.vue +114 -98
  80. package/dist/runtime/components/Container.vue +4 -7
  81. package/dist/runtime/components/ContextMenu.vue +16 -69
  82. package/dist/runtime/components/ContextMenuContent.vue +14 -10
  83. package/dist/runtime/components/Drawer.vue +23 -12
  84. package/dist/runtime/components/DropdownMenu.vue +18 -59
  85. package/dist/runtime/components/DropdownMenuContent.vue +14 -10
  86. package/dist/runtime/components/Form.vue +78 -49
  87. package/dist/runtime/components/FormField.vue +28 -15
  88. package/dist/runtime/components/Icon.vue +1 -1
  89. package/dist/runtime/components/Input.vue +15 -7
  90. package/dist/runtime/components/InputMenu.vue +133 -66
  91. package/dist/runtime/components/InputNumber.vue +197 -0
  92. package/dist/runtime/components/Kbd.vue +5 -6
  93. package/dist/runtime/components/Link.vue +24 -13
  94. package/dist/runtime/components/LinkBase.vue +1 -1
  95. package/dist/runtime/components/Modal.vue +56 -34
  96. package/dist/runtime/components/NavigationMenu.vue +129 -112
  97. package/dist/runtime/components/OverlayProvider.vue +28 -0
  98. package/dist/runtime/components/Pagination.vue +18 -14
  99. package/dist/runtime/components/PinInput.vue +95 -0
  100. package/dist/runtime/components/Popover.vue +28 -14
  101. package/dist/runtime/components/Progress.vue +28 -12
  102. package/dist/runtime/components/RadioGroup.vue +9 -12
  103. package/dist/runtime/components/Select.vue +61 -35
  104. package/dist/runtime/components/SelectMenu.vue +201 -130
  105. package/dist/runtime/components/Separator.vue +6 -5
  106. package/dist/runtime/components/Skeleton.vue +4 -7
  107. package/dist/runtime/components/Slideover.vue +56 -33
  108. package/dist/runtime/components/Slider.vue +8 -7
  109. package/dist/runtime/components/Stepper.vue +170 -0
  110. package/dist/runtime/components/Switch.vue +19 -23
  111. package/dist/runtime/components/Table.vue +157 -32
  112. package/dist/runtime/components/Tabs.vue +12 -31
  113. package/dist/runtime/components/Textarea.vue +18 -9
  114. package/dist/runtime/components/Toast.vue +39 -25
  115. package/dist/runtime/components/Toaster.vue +31 -24
  116. package/dist/runtime/components/Tooltip.vue +9 -12
  117. package/dist/runtime/components/Tree.vue +196 -0
  118. package/dist/runtime/composables/defineLocale.d.ts +9 -0
  119. package/dist/runtime/composables/defineLocale.js +4 -0
  120. package/dist/runtime/composables/defineShortcuts.d.ts +1 -1
  121. package/dist/runtime/composables/defineShortcuts.js +2 -2
  122. package/dist/runtime/composables/useFormField.d.ts +11 -4
  123. package/dist/runtime/composables/useFormField.js +19 -9
  124. package/dist/runtime/composables/useLocale.d.ts +4 -0
  125. package/dist/runtime/composables/useLocale.js +10 -0
  126. package/dist/runtime/composables/useOverlay.d.ts +30 -0
  127. package/dist/runtime/composables/useOverlay.js +70 -0
  128. package/dist/runtime/composables/useToast.d.ts +4 -3
  129. package/dist/runtime/composables/useToast.js +20 -6
  130. package/dist/runtime/index.css +1 -1
  131. package/dist/runtime/keyframes.css +1 -1
  132. package/dist/runtime/locale/ar.d.ts +2 -0
  133. package/dist/runtime/locale/ar.js +55 -0
  134. package/dist/runtime/locale/az.d.ts +2 -0
  135. package/dist/runtime/locale/az.js +54 -0
  136. package/dist/runtime/locale/bn.d.ts +2 -0
  137. package/dist/runtime/locale/bn.js +54 -0
  138. package/dist/runtime/locale/cs.d.ts +2 -0
  139. package/dist/runtime/locale/cs.js +54 -0
  140. package/dist/runtime/locale/da.d.ts +2 -0
  141. package/dist/runtime/locale/da.js +54 -0
  142. package/dist/runtime/locale/de.d.ts +2 -0
  143. package/dist/runtime/locale/de.js +54 -0
  144. package/dist/runtime/locale/el.d.ts +2 -0
  145. package/dist/runtime/locale/el.js +54 -0
  146. package/dist/runtime/locale/en.d.ts +2 -0
  147. package/dist/runtime/locale/en.js +54 -0
  148. package/dist/runtime/locale/es.d.ts +2 -0
  149. package/dist/runtime/locale/es.js +54 -0
  150. package/dist/runtime/locale/et.d.ts +2 -0
  151. package/dist/runtime/locale/et.js +54 -0
  152. package/dist/runtime/locale/fa_ir.d.ts +2 -0
  153. package/dist/runtime/locale/fa_ir.js +55 -0
  154. package/dist/runtime/locale/fi.d.ts +2 -0
  155. package/dist/runtime/locale/fi.js +54 -0
  156. package/dist/runtime/locale/fr.d.ts +2 -0
  157. package/dist/runtime/locale/fr.js +54 -0
  158. package/dist/runtime/locale/he.d.ts +2 -0
  159. package/dist/runtime/locale/he.js +53 -0
  160. package/dist/runtime/locale/hi.d.ts +2 -0
  161. package/dist/runtime/locale/hi.js +54 -0
  162. package/dist/runtime/locale/hu.d.ts +2 -0
  163. package/dist/runtime/locale/hu.js +54 -0
  164. package/dist/runtime/locale/id.d.ts +2 -0
  165. package/dist/runtime/locale/id.js +54 -0
  166. package/dist/runtime/locale/index.d.ts +34 -0
  167. package/dist/runtime/locale/index.js +34 -0
  168. package/dist/runtime/locale/it.d.ts +2 -0
  169. package/dist/runtime/locale/it.js +54 -0
  170. package/dist/runtime/locale/ja.d.ts +2 -0
  171. package/dist/runtime/locale/ja.js +54 -0
  172. package/dist/runtime/locale/km.d.ts +2 -0
  173. package/dist/runtime/locale/km.js +54 -0
  174. package/dist/runtime/locale/ko.d.ts +2 -0
  175. package/dist/runtime/locale/ko.js +54 -0
  176. package/dist/runtime/locale/nb_no.d.ts +2 -0
  177. package/dist/runtime/locale/nb_no.js +54 -0
  178. package/dist/runtime/locale/nl.d.ts +2 -0
  179. package/dist/runtime/locale/nl.js +54 -0
  180. package/dist/runtime/locale/pl.d.ts +2 -0
  181. package/dist/runtime/locale/pl.js +54 -0
  182. package/dist/runtime/locale/pt.d.ts +2 -0
  183. package/dist/runtime/locale/pt.js +54 -0
  184. package/dist/runtime/locale/pt_br.d.ts +2 -0
  185. package/dist/runtime/locale/pt_br.js +54 -0
  186. package/dist/runtime/locale/ru.d.ts +2 -0
  187. package/dist/runtime/locale/ru.js +54 -0
  188. package/dist/runtime/locale/sk.d.ts +2 -0
  189. package/dist/runtime/locale/sk.js +54 -0
  190. package/dist/runtime/locale/sv.d.ts +2 -0
  191. package/dist/runtime/locale/sv.js +54 -0
  192. package/dist/runtime/locale/th.d.ts +2 -0
  193. package/dist/runtime/locale/th.js +54 -0
  194. package/dist/runtime/locale/tr.d.ts +2 -0
  195. package/dist/runtime/locale/tr.js +54 -0
  196. package/dist/runtime/locale/uk.d.ts +2 -0
  197. package/dist/runtime/locale/uk.js +54 -0
  198. package/dist/runtime/locale/vi.d.ts +2 -0
  199. package/dist/runtime/locale/vi.js +54 -0
  200. package/dist/runtime/locale/zh_cn.d.ts +2 -0
  201. package/dist/runtime/locale/zh_cn.js +54 -0
  202. package/dist/runtime/locale/zh_tw.d.ts +2 -0
  203. package/dist/runtime/locale/zh_tw.js +54 -0
  204. package/dist/runtime/plugins/colors.js +8 -5
  205. package/dist/runtime/types/form.d.ts +29 -15
  206. package/dist/runtime/types/form.js +2 -2
  207. package/dist/runtime/types/index.d.ts +8 -0
  208. package/dist/runtime/types/index.js +8 -0
  209. package/dist/runtime/types/locale.d.ts +56 -0
  210. package/dist/runtime/types/locale.js +0 -0
  211. package/dist/runtime/types/utils.d.ts +7 -3
  212. package/dist/runtime/utils/form.d.ts +5 -9
  213. package/dist/runtime/utils/form.js +113 -50
  214. package/dist/runtime/utils/index.d.ts +1 -1
  215. package/dist/runtime/utils/index.js +15 -2
  216. package/dist/runtime/utils/link.d.ts +1 -1
  217. package/dist/runtime/utils/locale.d.ts +15 -0
  218. package/dist/runtime/utils/locale.js +25 -0
  219. package/dist/runtime/utils/tv.d.ts +1 -0
  220. package/dist/runtime/utils/tv.js +4 -0
  221. package/dist/runtime/vue/components/Icon.vue +2 -2
  222. package/dist/runtime/vue/components/Link.vue +87 -23
  223. package/dist/runtime/vue/composables/useAppConfig.d.ts +1 -0
  224. package/dist/runtime/vue/composables/useAppConfig.js +2 -0
  225. package/dist/runtime/vue/plugins/head.d.ts +1 -1
  226. package/dist/runtime/vue/plugins/head.js +3 -3
  227. package/dist/runtime/vue/stubs.d.ts +19 -0
  228. package/dist/runtime/vue/stubs.js +37 -0
  229. package/dist/shared/{ui.BufKhDiD.mjs → ui.DSPu6Y8j.mjs} +1071 -409
  230. package/dist/shared/{ui.BU7wzH0D.cjs → ui.DfK2RX6G.cjs} +1074 -409
  231. package/dist/unplugin.cjs +62 -26
  232. package/dist/unplugin.d.cts +17 -3
  233. package/dist/unplugin.d.mts +17 -3
  234. package/dist/unplugin.d.ts +17 -3
  235. package/dist/unplugin.mjs +61 -25
  236. package/dist/vite.cjs +3 -2
  237. package/dist/vite.d.cts +2 -0
  238. package/dist/vite.d.mts +2 -0
  239. package/dist/vite.d.ts +2 -0
  240. package/dist/vite.mjs +3 -2
  241. package/package.json +110 -67
  242. package/dist/chunks/component-meta.cjs +0 -73264
  243. package/dist/chunks/component-meta.mjs +0 -73262
  244. package/dist/client/devtools/200.html +0 -1
  245. package/dist/client/devtools/404.html +0 -1
  246. package/dist/client/devtools/_fonts/rP2Wp2ywxg089UriCZaSExd86J3t9jz86MvyyKK58UfivUw4aw-SK92LTmKP0.woff2 +0 -0
  247. package/dist/client/devtools/_fonts/rP2Wp2ywxg089UriCZaSExd86J3t9jz86MvyyKy58UfivUw-9uYm8d48E4.woff2 +0 -0
  248. package/dist/client/devtools/_fonts/rP2Yp2ywxg089UriI5-g4vlH9VoD8Cmcqbu0-K6z9mXg-VNw7NHvqnp.woff2 +0 -0
  249. package/dist/client/devtools/_fonts/rP2Yp2ywxg089UriI5-g4vlH9VoD8Cmcqbu6-K6z9mXgjU0-EkYdMs3MAX.woff2 +0 -0
  250. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-7DW3w-R7n06NbhGy.woff +0 -0
  251. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-JDG3w-leGNfkTmsj.woff +0 -0
  252. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-JDW3w-ciElMF03ku.woff +0 -0
  253. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8JCm3w-sB722Uoa0f.woff +0 -0
  254. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8JDW3w-PBDI1JDjwV.woff +0 -0
  255. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8gCm3w-0q1hqVn09O.woff +0 -0
  256. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat9XCm3w-ByvzuLy2fa.woff +0 -0
  257. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat9uCm3w-5TKCIs6EEw.woff +0 -0
  258. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat_XDW3w-r2swRDGfn2.woff +0 -0
  259. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAC5thTQ-ldB60l5U8r.woff +0 -0
  260. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAIpthTQ-wbFKGFDrgo.woff +0 -0
  261. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAIpxhTQ-LLUBv5jskj.woff +0 -0
  262. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwARZthTQ-F71RdTRbNg.woff +0 -0
  263. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwA_JxhTQ-6nh65gZkc0.woff +0 -0
  264. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAfJthTQ-aMoWEJLmTt.woff +0 -0
  265. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAkJxhTQ-WMBvmLOgKm.woff +0 -0
  266. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAop1hTQ-utGC2hnWq2.woff +0 -0
  267. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAopxhTQ-YpyTieVa5B.woff +0 -0
  268. package/dist/client/devtools/_nuxt/Bj9hdafK.js +0 -1
  269. package/dist/client/devtools/_nuxt/DM3_wAgz.js +0 -62
  270. package/dist/client/devtools/_nuxt/builds/latest.json +0 -1
  271. package/dist/client/devtools/_nuxt/builds/meta/e6b425f7-b919-4014-915b-0ea07c316790.json +0 -1
  272. package/dist/client/devtools/_nuxt/entry.DaJP-ZMB.css +0 -24
  273. package/dist/client/devtools/_nuxt/error-404.B0Nmv3fV.css +0 -1
  274. package/dist/client/devtools/_nuxt/error-500.C8fgTxVz.css +0 -1
  275. package/dist/client/devtools/_nuxt/hKiujHsR.js +0 -1
  276. package/dist/client/devtools/favicon.svg +0 -1
  277. package/dist/client/devtools/index.html +0 -1
  278. package/dist/devtools/runtime/DevtoolsRenderer.vue +0 -53
  279. package/dist/devtools/runtime/examples/AvatarGroupExample.vue +0 -7
  280. package/dist/devtools/runtime/examples/ButtonGroupExample.vue +0 -8
  281. package/dist/devtools/runtime/examples/CardExample.vue +0 -13
  282. package/dist/devtools/runtime/examples/CarouselExample.vue +0 -13
  283. package/dist/devtools/runtime/examples/ChipExample.vue +0 -5
  284. package/dist/devtools/runtime/examples/CollapsibleExample.vue +0 -8
  285. package/dist/devtools/runtime/examples/CommandPaletteExample.vue +0 -29
  286. package/dist/devtools/runtime/examples/ContainerExample.vue +0 -5
  287. package/dist/devtools/runtime/examples/ContextMenuExample.vue +0 -5
  288. package/dist/devtools/runtime/examples/DrawerExample.vue +0 -8
  289. package/dist/devtools/runtime/examples/DropdownMenuExample.vue +0 -5
  290. package/dist/devtools/runtime/examples/FormExample.vue +0 -30
  291. package/dist/devtools/runtime/examples/FormFieldExample.vue +0 -5
  292. package/dist/devtools/runtime/examples/LinkExample.vue +0 -5
  293. package/dist/devtools/runtime/examples/ModalExample.vue +0 -8
  294. package/dist/devtools/runtime/examples/PopoverExample.vue +0 -8
  295. package/dist/devtools/runtime/examples/SkeletonExample.vue +0 -3
  296. package/dist/devtools/runtime/examples/SlideoverExample.vue +0 -8
  297. package/dist/devtools/runtime/examples/ToasterExample.vue +0 -11
  298. package/dist/devtools/runtime/examples/TooltipExample.vue +0 -5
  299. package/dist/runtime/components/ModalProvider.vue +0 -12
  300. package/dist/runtime/components/SlideoverProvider.vue +0 -12
  301. package/dist/runtime/composables/extendDevtoolsMeta.d.ts +0 -7
  302. package/dist/runtime/composables/extendDevtoolsMeta.js +0 -2
  303. package/dist/runtime/composables/useModal.d.ts +0 -17
  304. package/dist/runtime/composables/useModal.js +0 -46
  305. package/dist/runtime/composables/useSlideover.d.ts +0 -17
  306. package/dist/runtime/composables/useSlideover.js +0 -46
  307. package/dist/runtime/plugins/modal.d.ts +0 -2
  308. package/dist/runtime/plugins/modal.js +0 -10
  309. package/dist/runtime/plugins/slideover.d.ts +0 -2
  310. package/dist/runtime/plugins/slideover.js +0 -10
@@ -1,17 +1,17 @@
1
1
  <script lang="ts">
2
- import { tv, type VariantProps } from 'tailwind-variants'
3
- import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxArrowProps } from 'radix-vue'
2
+ import type { VariantProps } from 'tailwind-variants'
3
+ import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxArrowProps, AcceptableValue } from 'reka-ui'
4
4
  import type { AppConfig } from '@nuxt/schema'
5
5
  import _appConfig from '#build/app.config'
6
6
  import theme from '#build/ui/select-menu'
7
7
  import type { UseComponentIconsProps } from '../composables/useComponentIcons'
8
- import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
+ import { tv } from '../utils/tv'
9
9
  import type { AvatarProps, ChipProps, InputProps } from '../types'
10
- import type { AcceptableValue, ArrayOrWrapped, PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
10
+ import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
11
11
 
12
- const appConfig = _appConfig as AppConfig & { ui: { selectMenu: Partial<typeof theme> } }
12
+ const appConfigSelectMenu = _appConfig as AppConfig & { ui: { selectMenu: Partial<typeof theme> } }
13
13
 
14
- const selectMenu = tv({ extend: tv(theme), ...(appConfig.ui?.selectMenu || {}) })
14
+ const selectMenu = tv({ extend: tv(theme), ...(appConfigSelectMenu.ui?.selectMenu || {}) })
15
15
 
16
16
  export interface SelectMenuItem {
17
17
  label?: string
@@ -29,16 +29,17 @@ export interface SelectMenuItem {
29
29
 
30
30
  type SelectMenuVariants = VariantProps<typeof selectMenu>
31
31
 
32
- export interface SelectMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<SelectMenuItem | AcceptableValue> = MaybeArrayOfArray<SelectMenuItem | AcceptableValue>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'defaultValue' | 'selectedValue' | 'open' | 'defaultOpen' | 'searchTerm' | 'disabled' | 'name' | 'resetSearchTermOnBlur'>, UseComponentIconsProps {
32
+ export interface SelectMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<SelectMenuItem | AcceptableValue | boolean> = MaybeArrayOfArray<SelectMenuItem | AcceptableValue | boolean>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'highlightOnHover'>, UseComponentIconsProps {
33
33
  id?: string
34
34
  /** The placeholder text when the select is empty. */
35
35
  placeholder?: string
36
36
  /**
37
- * Wether to display the search input or not.
37
+ * Whether to display the search input or not.
38
38
  * Can be an object to pass additional props to the input.
39
- * @defaultValue { placeholder: 'Search...' }
39
+ * `{ placeholder: 'Search...', variant: 'none' }`{lang="ts-type"}
40
+ * @defaultValue true
40
41
  */
41
- searchInput?: boolean | { placeholder?: string }
42
+ searchInput?: boolean | InputProps
42
43
  color?: SelectMenuVariants['color']
43
44
  variant?: SelectMenuVariants['variant']
44
45
  size?: SelectMenuVariants['size']
@@ -55,7 +56,7 @@ export interface SelectMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends M
55
56
  selectedIcon?: string
56
57
  /**
57
58
  * The content of the menu.
58
- * @defaultValue { side: 'bottom', sideOffset: 8, position: 'popper' }
59
+ * @defaultValue { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
59
60
  */
60
61
  content?: Omit<ComboboxContentProps, 'as' | 'asChild' | 'forceMount'>
61
62
  /**
@@ -68,12 +69,6 @@ export interface SelectMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends M
68
69
  * @defaultValue true
69
70
  */
70
71
  portal?: boolean
71
- /**
72
- * Whether to filter items or not, can be an array of fields to filter.
73
- * When `false`, items will not be filtered which is useful for custom filtering (useAsyncData, useFetch, etc.).
74
- * @defaultValue ['label']
75
- */
76
- filter?: boolean | string[]
77
72
  /**
78
73
  * When `items` is an array of objects, select the field to use as the value instead of the object itself.
79
74
  * @defaultValue undefined
@@ -83,80 +78,103 @@ export interface SelectMenuProps<T extends MaybeArrayOfArrayItem<I>, I extends M
83
78
  * When `items` is an array of objects, select the field to use as the label.
84
79
  * @defaultValue 'label'
85
80
  */
86
- labelKey?: SelectItemKey<T>
81
+ labelKey?: V
87
82
  items?: I
83
+ /** The value of the SelectMenu when initially rendered. Use when you do not need to control the state of the SelectMenu. */
84
+ defaultValue?: SelectModelValue<T, V, M>
85
+ /** The controlled value of the SelectMenu. Can be binded-with with `v-model`. */
86
+ modelValue?: SelectModelValue<T, V, M>
87
+ /** Whether multiple options can be selected or not. */
88
+ multiple?: M & boolean
88
89
  /** Highlight the ring color like a focus state. */
89
90
  highlight?: boolean
91
+ /**
92
+ * Determines if custom user input that does not exist in options can be added.
93
+ * @defaultValue false
94
+ */
95
+ createItem?: boolean | 'always' | { position?: 'top' | 'bottom', when?: 'empty' | 'always' }
96
+ /**
97
+ * Fields to filter items by.
98
+ * @defaultValue [labelKey]
99
+ */
100
+ filterFields?: string[]
101
+ /**
102
+ * When `true`, disable the default filters, useful for custom filtering (useAsyncData, useFetch, etc.).
103
+ * @defaultValue false
104
+ */
105
+ ignoreFilter?: boolean
90
106
  class?: any
91
107
  ui?: PartialString<typeof selectMenu.slots>
92
- /** The controlled value of the Combobox. Can be binded-with with `v-model`. */
93
- modelValue?: SelectModelValue<T, V, M>
94
- /** Whether multiple options can be selected or not. */
95
- multiple?: M
96
108
  }
97
109
 
98
110
  export type SelectMenuEmits<T, V, M extends boolean> = Omit<ComboboxRootEmits<T>, 'update:modelValue'> & {
99
111
  change: [payload: Event]
100
112
  blur: [payload: FocusEvent]
101
113
  focus: [payload: FocusEvent]
114
+ create: [item: string]
102
115
  } & SelectModelValueEmits<T, V, M>
103
116
 
104
117
  type SlotProps<T> = (props: { item: T, index: number }) => any
105
118
 
106
- export interface SelectMenuSlots<T> {
107
- 'leading'(props: { modelValue: T, open: boolean, ui: any }): any
108
- 'default'(props: { modelValue: T, open: boolean }): any
109
- 'trailing'(props: { modelValue: T, open: boolean, ui: any }): any
119
+ export interface SelectMenuSlots<T, M extends boolean> {
120
+ 'leading'(props: { modelValue?: M extends true ? T[] : T, open: boolean, ui: any }): any
121
+ 'default'(props: { modelValue?: M extends true ? T[] : T, open: boolean }): any
122
+ 'trailing'(props: { modelValue?: M extends true ? T[] : T, open: boolean, ui: any }): any
110
123
  'empty'(props: { searchTerm?: string }): any
111
124
  'item': SlotProps<T>
112
125
  'item-leading': SlotProps<T>
113
126
  'item-label': SlotProps<T>
114
127
  'item-trailing': SlotProps<T>
128
+ 'create-item-label'(props: { item: string }): any
115
129
  }
116
-
117
- extendDevtoolsMeta({ defaultProps: { items: ['Option 1', 'Option 2', 'Option 3'] } })
118
130
  </script>
119
131
 
120
- <script setup lang="ts" generic="T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<SelectMenuItem | AcceptableValue> = MaybeArrayOfArray<SelectMenuItem | AcceptableValue>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false">
121
- import { computed, toRef } from 'vue'
122
- import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, useForwardPropsEmits } from 'radix-vue'
132
+ <script setup lang="ts" generic="T extends MaybeArrayOfArrayItem<I>, I extends MaybeArrayOfArray<SelectMenuItem | AcceptableValue | boolean> = MaybeArrayOfArray<SelectMenuItem | AcceptableValue | boolean>, V extends SelectItemKey<T> | undefined = undefined, M extends boolean = false">
133
+ import { computed, toRef, toRaw } from 'vue'
134
+ import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, FocusScope, useForwardPropsEmits, useFilter } from 'reka-ui'
123
135
  import { defu } from 'defu'
124
- import * as isEqual from 'fast-deep-equal'
125
- import { reactivePick } from '@vueuse/core'
136
+ import { reactivePick, createReusableTemplate } from '@vueuse/core'
126
137
  import { useAppConfig } from '#imports'
127
138
  import { useButtonGroup } from '../composables/useButtonGroup'
128
139
  import { useComponentIcons } from '../composables/useComponentIcons'
129
140
  import { useFormField } from '../composables/useFormField'
130
- import { get, escapeRegExp } from '../utils'
141
+ import { useLocale } from '../composables/useLocale'
142
+ import { get, compare } from '../utils'
131
143
  import UIcon from './Icon.vue'
132
144
  import UAvatar from './Avatar.vue'
133
145
  import UChip from './Chip.vue'
146
+ import UInput from './Input.vue'
147
+
148
+ defineOptions({ inheritAttrs: false })
134
149
 
135
150
  const props = withDefaults(defineProps<SelectMenuProps<T, I, V, M>>(), {
136
- search: true,
137
151
  portal: true,
138
- autofocusDelay: 0,
139
- searchInput: () => ({ placeholder: 'Search...' }),
140
- filter: () => ['label'],
141
- labelKey: 'label' as never
152
+ searchInput: true,
153
+ labelKey: 'label' as never,
154
+ resetSearchTermOnBlur: true
142
155
  })
143
-
144
156
  const emits = defineEmits<SelectMenuEmits<T, V, M>>()
145
- const slots = defineSlots<SelectMenuSlots<T>>()
157
+ const slots = defineSlots<SelectMenuSlots<T, M>>()
146
158
 
147
159
  const searchTerm = defineModel<string>('searchTerm', { default: '' })
148
160
 
161
+ const { t } = useLocale()
149
162
  const appConfig = useAppConfig()
150
- const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur'), emits)
151
- const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, position: 'popper' }) as ComboboxContentProps)
163
+ const { contains } = useFilter({ sensitivity: 'base' })
164
+
165
+ const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover'), emits)
166
+ const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
152
167
  const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
168
+ const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t('selectMenu.search'), variant: 'none' }) as InputProps)
153
169
 
154
- const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
170
+ const { emitFormBlur, emitFormFocus, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
155
171
  const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
156
172
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
157
173
 
158
174
  const selectSize = computed(() => buttonGroupSize.value || formGroupSize.value)
159
175
 
176
+ const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate()
177
+
160
178
  const ui = computed(() => selectMenu({
161
179
  color: color.value,
162
180
  variant: props.variant,
@@ -170,40 +188,61 @@ const ui = computed(() => selectMenu({
170
188
 
171
189
  function displayValue(value: T | T[]): string {
172
190
  if (props.multiple && Array.isArray(value)) {
173
- return value.map(v => displayValue(v)).join(', ')
191
+ return value.map(v => displayValue(v)).filter(Boolean).join(', ')
174
192
  }
175
193
 
176
- const item = items.value.find(item => props.valueKey ? isEqual.default(get(item as Record<string, any>, props.valueKey as string), value) : isEqual.default(item, value))
194
+ if (!props.valueKey) {
195
+ return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
196
+ }
177
197
 
198
+ const item = items.value.find(item => compare(typeof item === 'object' ? get(item as Record<string, any>, props.valueKey as string) : item, value))
178
199
  return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
179
200
  }
180
201
 
181
- function filterFunction(items: ArrayOrWrapped<T>, searchTerm: string): ArrayOrWrapped<T> {
182
- if (props.filter === false) {
183
- return items
202
+ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0]) ? props.items : [props.items]) as SelectMenuItem[][] : [])
203
+ // eslint-disable-next-line vue/no-dupe-keys
204
+ const items = computed(() => groups.value.flatMap(group => group) as T[])
205
+
206
+ const filteredGroups = computed(() => {
207
+ if (props.ignoreFilter || !searchTerm.value) {
208
+ return groups.value
184
209
  }
185
210
 
186
- const fields = Array.isArray(props.filter) ? props.filter : [props.labelKey]
187
- const escapedSearchTerm = escapeRegExp(searchTerm)
211
+ const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey] as string[]
188
212
 
189
- return items.filter((item: T) => {
213
+ return groups.value.map(items => items.filter((item) => {
190
214
  if (typeof item !== 'object') {
191
- return String(item).search(new RegExp(escapedSearchTerm, 'i')) !== -1
215
+ return contains(item, searchTerm.value)
216
+ }
217
+
218
+ if (item.type && ['label', 'separator'].includes(item.type)) {
219
+ return true
192
220
  }
193
221
 
194
- return fields.some((field) => {
195
- const child = get(item, field as string)
222
+ return fields.some(field => contains(get(item, field), searchTerm.value))
223
+ })).filter(group => group.filter(item => !item.type || !['label', 'separator'].includes(item.type)).length > 0)
224
+ })
225
+ const filteredItems = computed(() => filteredGroups.value.flatMap(group => group) as T[])
196
226
 
197
- return child !== null && child !== undefined && String(child).search(new RegExp(escapedSearchTerm, 'i')) !== -1
198
- })
199
- }) as ArrayOrWrapped<T>
200
- }
227
+ const createItem = computed(() => {
228
+ if (!props.createItem || !searchTerm.value) {
229
+ return false
230
+ }
201
231
 
202
- const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0]) ? props.items : [props.items]) as SelectMenuItem[][] : [])
203
- // eslint-disable-next-line vue/no-dupe-keys
204
- const items = computed(() => groups.value.flatMap(group => group) as T[])
232
+ const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } as T : searchTerm.value
233
+
234
+ if ((typeof props.createItem === 'object' && props.createItem.when === 'always') || props.createItem === 'always') {
235
+ return !filteredItems.value.find(item => compare(item, newItem, props.valueKey))
236
+ }
237
+
238
+ return !filteredItems.value.length
239
+ })
240
+ const createItemPosition = computed(() => typeof props.createItem === 'object' ? props.createItem.position : 'bottom')
205
241
 
206
242
  function onUpdate(value: any) {
243
+ if (toRaw(props.modelValue) === value) {
244
+ return
245
+ }
207
246
  // @ts-expect-error - 'target' does not exist in type 'EventInit'
208
247
  const event = new Event('change', { target: { value } })
209
248
  emits('change', event)
@@ -212,42 +251,72 @@ function onUpdate(value: any) {
212
251
  }
213
252
 
214
253
  function onUpdateOpen(value: boolean) {
254
+ let timeoutId
255
+
215
256
  if (!value) {
216
257
  const event = new FocusEvent('blur')
258
+
217
259
  emits('blur', event)
218
260
  emitFormBlur()
261
+
262
+ // Since we use `displayValue` prop inside ComboboxInput we should reset searchTerm manually
263
+ // https://reka-ui.com/docs/components/combobox#api-reference
264
+ if (props.resetSearchTermOnBlur) {
265
+ const STATE_ANIMATION_DELAY_MS = 100
266
+
267
+ timeoutId = setTimeout(() => {
268
+ searchTerm.value = ''
269
+ }, STATE_ANIMATION_DELAY_MS)
270
+ }
219
271
  } else {
220
272
  const event = new FocusEvent('focus')
221
273
  emits('focus', event)
274
+ emitFormFocus()
275
+ clearTimeout(timeoutId)
222
276
  }
223
277
  }
224
278
  </script>
225
279
 
280
+ <!-- eslint-disable vue/no-template-shadow -->
226
281
  <template>
282
+ <DefineCreateItemTemplate>
283
+ <ComboboxGroup :class="ui.group({ class: props.ui?.group })">
284
+ <ComboboxItem
285
+ :class="ui.item({ class: props.ui?.item })"
286
+ :value="searchTerm"
287
+ @select.prevent="emits('create', searchTerm)"
288
+ >
289
+ <span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
290
+ <slot name="create-item-label" :item="searchTerm">
291
+ {{ t('selectMenu.create', { label: searchTerm }) }}
292
+ </slot>
293
+ </span>
294
+ </ComboboxItem>
295
+ </ComboboxGroup>
296
+ </DefineCreateItemTemplate>
297
+
227
298
  <ComboboxRoot
228
299
  :id="id"
229
300
  v-slot="{ modelValue, open }"
230
- v-bind="rootProps"
231
- v-model:search-term="searchTerm"
301
+ v-bind="{ ...rootProps, ...$attrs, ...ariaAttrs }"
302
+ ignore-filter
232
303
  as-child
233
304
  :name="name"
234
305
  :disabled="disabled"
235
- :display-value="() => searchTerm"
236
- :filter-function="filterFunction"
237
306
  @update:model-value="onUpdate"
238
307
  @update:open="onUpdateOpen"
239
308
  >
240
309
  <ComboboxAnchor as-child>
241
310
  <ComboboxTrigger :class="ui.base({ class: [props.class, props.ui?.base] })" tabindex="0">
242
311
  <span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
243
- <slot name="leading" :model-value="(modelValue as T)" :open="open" :ui="ui">
312
+ <slot name="leading" :model-value="(modelValue as M extends true ? T[] : T)" :open="open" :ui="ui">
244
313
  <UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
245
314
  <UAvatar v-else-if="!!avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
246
315
  </slot>
247
316
  </span>
248
317
 
249
- <slot :model-value="(modelValue as T)" :open="open">
250
- <template v-for="displayedModelValue in [displayValue(modelValue)]" :key="displayedModelValue">
318
+ <slot :model-value="(modelValue as M extends true ? T[] : T)" :open="open">
319
+ <template v-for="displayedModelValue in [displayValue(modelValue as M extends true ? T[] : T)]" :key="displayedModelValue">
251
320
  <span v-if="displayedModelValue" :class="ui.value({ class: props.ui?.value })">
252
321
  {{ displayedModelValue }}
253
322
  </span>
@@ -258,7 +327,7 @@ function onUpdateOpen(value: boolean) {
258
327
  </slot>
259
328
 
260
329
  <span v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
261
- <slot name="trailing" :model-value="(modelValue as T)" :open="open" :ui="ui">
330
+ <slot name="trailing" :model-value="(modelValue as M extends true ? T[] : T)" :open="open" :ui="ui">
262
331
  <UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
263
332
  </slot>
264
333
  </span>
@@ -267,68 +336,70 @@ function onUpdateOpen(value: boolean) {
267
336
 
268
337
  <ComboboxPortal :disabled="!portal">
269
338
  <ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
270
- <ComboboxInput
271
- v-if="!!searchInput"
272
- autofocus
273
- autocomplete="off"
274
- v-bind="typeof searchInput === 'object' ? searchInput : {}"
275
- :class="ui.input({ class: props.ui?.input })"
276
- />
277
-
278
- <ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
279
- <slot name="empty" :search-term="searchTerm">
280
- {{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
281
- </slot>
282
- </ComboboxEmpty>
283
-
284
- <ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
285
- <ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
286
- <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
287
- <ComboboxLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
288
- {{ get(item, props.labelKey as string) }}
289
- </ComboboxLabel>
290
-
291
- <ComboboxSeparator v-else-if="item?.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
292
-
293
- <ComboboxItem
294
- v-else
295
- :class="ui.item({ class: props.ui?.item })"
296
- :disabled="item.disabled"
297
- :value="valueKey && typeof item === 'object' ? get(item, props.valueKey as string) : item"
298
- @select="item.onSelect"
299
- >
300
- <slot name="item" :item="(item as T)" :index="index">
301
- <slot name="item-leading" :item="(item as T)" :index="index">
302
- <UIcon v-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
303
- <UAvatar v-else-if="item.avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
304
- <UChip
305
- v-else-if="item.chip"
306
- :size="((props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()) as ChipProps['size'])"
307
- inset
308
- standalone
309
- v-bind="item.chip"
310
- :class="ui.itemLeadingChip({ class: props.ui?.itemLeadingChip })"
311
- />
339
+ <FocusScope trapped :class="ui.focusScope({ class: props.ui?.focusScope })">
340
+ <ComboboxInput v-if="!!searchInput" v-model="searchTerm" :display-value="() => searchTerm" as-child>
341
+ <UInput autofocus autocomplete="off" v-bind="searchInputProps" :class="ui.input({ class: props.ui?.input })" />
342
+ </ComboboxInput>
343
+
344
+ <ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
345
+ <slot name="empty" :search-term="searchTerm">
346
+ {{ searchTerm ? t('selectMenu.noMatch', { searchTerm }) : t('selectMenu.noData') }}
347
+ </slot>
348
+ </ComboboxEmpty>
349
+
350
+ <ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
351
+ <ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'top'" />
352
+
353
+ <ComboboxGroup v-for="(group, groupIndex) in filteredGroups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
354
+ <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
355
+ <ComboboxLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
356
+ {{ get(item, props.labelKey as string) }}
357
+ </ComboboxLabel>
358
+
359
+ <ComboboxSeparator v-else-if="item?.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
360
+
361
+ <ComboboxItem
362
+ v-else
363
+ :class="ui.item({ class: props.ui?.item })"
364
+ :disabled="item.disabled"
365
+ :value="valueKey && typeof item === 'object' ? get(item, props.valueKey as string) : item"
366
+ @select="item.onSelect"
367
+ >
368
+ <slot name="item" :item="(item as T)" :index="index">
369
+ <slot name="item-leading" :item="(item as T)" :index="index">
370
+ <UIcon v-if="item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
371
+ <UAvatar v-else-if="item.avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
372
+ <UChip
373
+ v-else-if="item.chip"
374
+ :size="((props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()) as ChipProps['size'])"
375
+ inset
376
+ standalone
377
+ v-bind="item.chip"
378
+ :class="ui.itemLeadingChip({ class: props.ui?.itemLeadingChip })"
379
+ />
380
+ </slot>
381
+
382
+ <span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
383
+ <slot name="item-label" :item="(item as T)" :index="index">
384
+ {{ typeof item === 'object' ? get(item, props.labelKey as string) : item }}
385
+ </slot>
386
+ </span>
387
+
388
+ <span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
389
+ <slot name="item-trailing" :item="(item as T)" :index="index" />
390
+
391
+ <ComboboxItemIndicator as-child>
392
+ <UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
393
+ </ComboboxItemIndicator>
394
+ </span>
312
395
  </slot>
396
+ </ComboboxItem>
397
+ </template>
398
+ </ComboboxGroup>
313
399
 
314
- <span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
315
- <slot name="item-label" :item="(item as T)" :index="index">
316
- {{ typeof item === 'object' ? get(item, props.labelKey as string) : item }}
317
- </slot>
318
- </span>
319
-
320
- <span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
321
- <slot name="item-trailing" :item="(item as T)" :index="index" />
322
-
323
- <ComboboxItemIndicator as-child>
324
- <UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
325
- </ComboboxItemIndicator>
326
- </span>
327
- </slot>
328
- </ComboboxItem>
329
- </template>
330
- </ComboboxGroup>
331
- </ComboboxViewport>
400
+ <ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'bottom'" />
401
+ </ComboboxViewport>
402
+ </FocusScope>
332
403
 
333
404
  <ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
334
405
  </ComboboxContent>
@@ -1,14 +1,15 @@
1
1
  <script lang="ts">
2
- import { tv, type VariantProps } from 'tailwind-variants'
3
- import type { SeparatorProps as _SeparatorProps } from 'radix-vue'
2
+ import type { VariantProps } from 'tailwind-variants'
3
+ import type { SeparatorProps as _SeparatorProps } from 'reka-ui'
4
4
  import type { AppConfig } from '@nuxt/schema'
5
5
  import _appConfig from '#build/app.config'
6
6
  import theme from '#build/ui/separator'
7
+ import { tv } from '../utils/tv'
7
8
  import type { AvatarProps } from '../types'
8
9
 
9
- const appConfig = _appConfig as AppConfig & { ui: { separator: Partial<typeof theme> } }
10
+ const appConfigSeparator = _appConfig as AppConfig & { ui: { separator: Partial<typeof theme> } }
10
11
 
11
- const separator = tv({ extend: tv(theme), ...(appConfig.ui?.separator || {}) })
12
+ const separator = tv({ extend: tv(theme), ...(appConfigSeparator.ui?.separator || {}) })
12
13
 
13
14
  type SeparatorVariants = VariantProps<typeof separator>
14
15
 
@@ -43,7 +44,7 @@ export interface SeparatorSlots {
43
44
 
44
45
  <script setup lang="ts">
45
46
  import { computed } from 'vue'
46
- import { Separator, useForwardProps } from 'radix-vue'
47
+ import { Separator, useForwardProps } from 'reka-ui'
47
48
  import { reactivePick } from '@vueuse/core'
48
49
  import UIcon from './Icon.vue'
49
50
  import UAvatar from './Avatar.vue'
@@ -1,13 +1,12 @@
1
1
  <script lang="ts">
2
- import { tv } from 'tailwind-variants'
3
2
  import type { AppConfig } from '@nuxt/schema'
4
3
  import _appConfig from '#build/app.config'
5
4
  import theme from '#build/ui/skeleton'
6
- import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
5
+ import { tv } from '../utils/tv'
7
6
 
8
- const appConfig = _appConfig as AppConfig & { ui: { skeleton: Partial<typeof theme> } }
7
+ const appConfigSkeleton = _appConfig as AppConfig & { ui: { skeleton: Partial<typeof theme> } }
9
8
 
10
- const skeleton = tv({ extend: tv(theme), ...(appConfig.ui?.skeleton || {}) })
9
+ const skeleton = tv({ extend: tv(theme), ...(appConfigSkeleton.ui?.skeleton || {}) })
11
10
 
12
11
  export interface SkeletonProps {
13
12
  /**
@@ -17,12 +16,10 @@ export interface SkeletonProps {
17
16
  as?: any
18
17
  class?: any
19
18
  }
20
-
21
- extendDevtoolsMeta({ example: 'SkeletonExample' })
22
19
  </script>
23
20
 
24
21
  <script setup lang="ts">
25
- import { Primitive } from 'radix-vue'
22
+ import { Primitive } from 'reka-ui'
26
23
 
27
24
  const props = defineProps<SkeletonProps>()
28
25
  </script>