@nuxt/ui 3.0.0-alpha.7 → 3.0.0-alpha.9

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 (296) hide show
  1. package/.nuxt/ui/accordion.ts +20 -0
  2. package/.nuxt/ui/alert.ts +242 -0
  3. package/.nuxt/ui/avatar-group.ts +40 -0
  4. package/.nuxt/ui/avatar.ts +42 -0
  5. package/.nuxt/ui/badge.ts +194 -0
  6. package/.nuxt/ui/breadcrumb.ts +45 -0
  7. package/.nuxt/ui/button-group.ts +16 -0
  8. package/.nuxt/ui/button.ts +344 -0
  9. package/.nuxt/ui/card.ts +8 -0
  10. package/.nuxt/ui/carousel.ts +41 -0
  11. package/.nuxt/ui/checkbox.ts +105 -0
  12. package/.nuxt/ui/chip.ts +67 -0
  13. package/.nuxt/ui/collapsible.ts +6 -0
  14. package/.nuxt/ui/command-palette.ts +40 -0
  15. package/.nuxt/ui/container.ts +3 -0
  16. package/.nuxt/ui/context-menu.ts +198 -0
  17. package/.nuxt/ui/drawer.ts +55 -0
  18. package/.nuxt/ui/dropdown-menu.ts +199 -0
  19. package/.nuxt/ui/form-field.ts +40 -0
  20. package/.nuxt/ui/form.ts +3 -0
  21. package/.nuxt/ui/index.ts +45 -0
  22. package/.nuxt/ui/input-menu.ts +411 -0
  23. package/.nuxt/ui/input-number.ts +204 -0
  24. package/.nuxt/ui/input.ts +263 -0
  25. package/.nuxt/ui/kbd.ts +19 -0
  26. package/.nuxt/ui/link.ts +15 -0
  27. package/.nuxt/ui/modal.ts +28 -0
  28. package/.nuxt/ui/navigation-menu.ts +390 -0
  29. package/.nuxt/ui/pagination.ts +8 -0
  30. package/.nuxt/ui/pin-input.ts +145 -0
  31. package/.nuxt/ui/popover.ts +6 -0
  32. package/.nuxt/ui/progress.ts +258 -0
  33. package/.nuxt/ui/radio-group.ts +112 -0
  34. package/.nuxt/ui/select-menu.ts +316 -0
  35. package/.nuxt/ui/select.ts +314 -0
  36. package/.nuxt/ui/separator.ts +143 -0
  37. package/.nuxt/ui/skeleton.ts +3 -0
  38. package/.nuxt/ui/slideover.ts +63 -0
  39. package/.nuxt/ui/slider.ts +148 -0
  40. package/.nuxt/ui/switch.ts +113 -0
  41. package/.nuxt/ui/table.ts +129 -0
  42. package/.nuxt/ui/tabs.ts +227 -0
  43. package/.nuxt/ui/textarea.ts +263 -0
  44. package/.nuxt/ui/toast.ts +66 -0
  45. package/.nuxt/ui/toaster.ts +75 -0
  46. package/.nuxt/ui/tooltip.ts +9 -0
  47. package/README.md +52 -12
  48. package/cli/commands/{init.mjs → make/component.mjs} +4 -4
  49. package/cli/commands/make/index.mjs +14 -0
  50. package/cli/commands/make/locale.mjs +64 -0
  51. package/cli/index.mjs +2 -2
  52. package/cli/templates.mjs +47 -2
  53. package/cli/utils.mjs +14 -0
  54. package/dist/chunks/component-meta.cjs +77249 -0
  55. package/dist/chunks/component-meta.mjs +77247 -0
  56. package/dist/client/devtools/200.html +1 -0
  57. package/dist/client/devtools/404.html +1 -0
  58. package/dist/client/devtools/_fonts/rP2Wp2ywxg089UriCZaSExd86J3t9jz86MvyyKK58UfivUw4aw-SK92LTmKP0.woff2 +0 -0
  59. package/dist/client/devtools/_fonts/rP2Wp2ywxg089UriCZaSExd86J3t9jz86MvyyKy58UfivUw-9uYm8d48E4.woff2 +0 -0
  60. package/dist/client/devtools/_fonts/rP2Yp2ywxg089UriI5-g4vlH9VoD8Cmcqbu0-K6z9mXg-VNw7NHvqnp.woff2 +0 -0
  61. package/dist/client/devtools/_fonts/rP2Yp2ywxg089UriI5-g4vlH9VoD8Cmcqbu6-K6z9mXgjU0-EkYdMs3MAX.woff2 +0 -0
  62. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-7DW3w-R7n06NbhGy.woff +0 -0
  63. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-JDG3w-leGNfkTmsj.woff +0 -0
  64. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat-JDW3w-ciElMF03ku.woff +0 -0
  65. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8JCm3w-sB722Uoa0f.woff +0 -0
  66. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8JDW3w-PBDI1JDjwV.woff +0 -0
  67. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat8gCm3w-0q1hqVn09O.woff +0 -0
  68. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat9XCm3w-ByvzuLy2fa.woff +0 -0
  69. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat9uCm3w-5TKCIs6EEw.woff +0 -0
  70. package/dist/client/devtools/_fonts/rP2rp2ywxg089UriCZaSExd86J3t9jz86Mvy4qCRAL19DksVat_XDW3w-r2swRDGfn2.woff +0 -0
  71. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAC5thTQ-ldB60l5U8r.woff +0 -0
  72. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAIpthTQ-wbFKGFDrgo.woff +0 -0
  73. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAIpxhTQ-LLUBv5jskj.woff +0 -0
  74. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwARZthTQ-F71RdTRbNg.woff +0 -0
  75. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwA_JxhTQ-6nh65gZkc0.woff +0 -0
  76. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAfJthTQ-aMoWEJLmTt.woff +0 -0
  77. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAkJxhTQ-WMBvmLOgKm.woff +0 -0
  78. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAop1hTQ-utGC2hnWq2.woff +0 -0
  79. package/dist/client/devtools/_fonts/rP2tp2ywxg089UriI5-g4vlH9VoD8CmcqZG40F9JadbnoEwAopxhTQ-YpyTieVa5B.woff +0 -0
  80. package/dist/client/devtools/_nuxt/BDC8ywlR.js +1 -0
  81. package/dist/client/devtools/_nuxt/BT004Uxp.js +53 -0
  82. package/dist/client/devtools/_nuxt/C1H2Soz3.js +1 -0
  83. package/dist/client/devtools/_nuxt/builds/latest.json +1 -0
  84. package/dist/client/devtools/_nuxt/builds/meta/f98c13ea-d751-4b37-8ce3-94e99708745f.json +1 -0
  85. package/dist/client/devtools/_nuxt/entry.Bx6WJjrx.css +1 -0
  86. package/dist/client/devtools/_nuxt/error-404.Cq4qshcf.css +1 -0
  87. package/dist/client/devtools/_nuxt/error-500.ax1aM34m.css +1 -0
  88. package/dist/client/devtools/favicon.svg +1 -0
  89. package/dist/client/devtools/index.html +1 -0
  90. package/dist/devtools/runtime/DevtoolsRenderer.vue +53 -0
  91. package/dist/devtools/runtime/examples/AvatarGroupExample.vue +7 -0
  92. package/dist/devtools/runtime/examples/ButtonGroupExample.vue +8 -0
  93. package/dist/devtools/runtime/examples/CardExample.vue +13 -0
  94. package/dist/devtools/runtime/examples/CarouselExample.vue +13 -0
  95. package/dist/devtools/runtime/examples/ChipExample.vue +5 -0
  96. package/dist/devtools/runtime/examples/CollapsibleExample.vue +8 -0
  97. package/dist/devtools/runtime/examples/CommandPaletteExample.vue +29 -0
  98. package/dist/devtools/runtime/examples/ContainerExample.vue +5 -0
  99. package/dist/devtools/runtime/examples/ContextMenuExample.vue +5 -0
  100. package/dist/devtools/runtime/examples/DrawerExample.vue +8 -0
  101. package/dist/devtools/runtime/examples/DropdownMenuExample.vue +5 -0
  102. package/dist/devtools/runtime/examples/FormExample.vue +30 -0
  103. package/dist/devtools/runtime/examples/FormFieldExample.vue +5 -0
  104. package/dist/devtools/runtime/examples/LinkExample.vue +5 -0
  105. package/dist/devtools/runtime/examples/ModalExample.vue +8 -0
  106. package/dist/devtools/runtime/examples/PopoverExample.vue +8 -0
  107. package/dist/devtools/runtime/examples/SkeletonExample.vue +3 -0
  108. package/dist/devtools/runtime/examples/SlideoverExample.vue +8 -0
  109. package/dist/devtools/runtime/examples/ToasterExample.vue +11 -0
  110. package/dist/devtools/runtime/examples/TooltipExample.vue +5 -0
  111. package/dist/module.cjs +223 -4
  112. package/dist/module.d.cts +54 -0
  113. package/dist/module.d.mts +10 -0
  114. package/dist/module.d.ts +10 -0
  115. package/dist/module.json +1 -1
  116. package/dist/module.mjs +158 -2763
  117. package/dist/runtime/components/Accordion.vue +32 -1
  118. package/dist/runtime/components/Alert.vue +8 -1
  119. package/dist/runtime/components/App.vue +19 -5
  120. package/dist/runtime/components/Avatar.vue +23 -5
  121. package/dist/runtime/components/AvatarGroup.vue +3 -0
  122. package/dist/runtime/components/Badge.vue +33 -3
  123. package/dist/runtime/components/Breadcrumb.vue +33 -4
  124. package/dist/runtime/components/Button.vue +6 -1
  125. package/dist/runtime/components/ButtonGroup.vue +4 -1
  126. package/dist/runtime/components/Card.vue +3 -0
  127. package/dist/runtime/components/Carousel.vue +17 -8
  128. package/dist/runtime/components/Checkbox.vue +4 -0
  129. package/dist/runtime/components/Chip.vue +9 -2
  130. package/dist/runtime/components/Collapsible.vue +3 -0
  131. package/dist/runtime/components/CommandPalette.vue +8 -4
  132. package/dist/runtime/components/Container.vue +3 -0
  133. package/dist/runtime/components/ContextMenu.vue +64 -3
  134. package/dist/runtime/components/ContextMenuContent.vue +10 -8
  135. package/dist/runtime/components/Drawer.vue +3 -0
  136. package/dist/runtime/components/DropdownMenu.vue +52 -3
  137. package/dist/runtime/components/DropdownMenuContent.vue +10 -8
  138. package/dist/runtime/components/Form.vue +21 -20
  139. package/dist/runtime/components/FormField.vue +10 -3
  140. package/dist/runtime/components/Input.vue +1 -0
  141. package/dist/runtime/components/InputMenu.vue +118 -31
  142. package/dist/runtime/components/InputNumber.vue +192 -0
  143. package/dist/runtime/components/Kbd.vue +2 -0
  144. package/dist/runtime/components/Link.vue +69 -6
  145. package/dist/runtime/components/Modal.vue +15 -3
  146. package/dist/runtime/components/NavigationMenu.vue +95 -46
  147. package/dist/runtime/components/Pagination.vue +17 -6
  148. package/dist/runtime/components/PinInput.vue +96 -0
  149. package/dist/runtime/components/Popover.vue +20 -1
  150. package/dist/runtime/components/Progress.vue +1 -1
  151. package/dist/runtime/components/RadioGroup.vue +4 -1
  152. package/dist/runtime/components/Select.vue +24 -13
  153. package/dist/runtime/components/SelectMenu.vue +130 -42
  154. package/dist/runtime/components/Separator.vue +1 -1
  155. package/dist/runtime/components/Skeleton.vue +3 -0
  156. package/dist/runtime/components/Slideover.vue +15 -3
  157. package/dist/runtime/components/Slider.vue +1 -1
  158. package/dist/runtime/components/Switch.vue +5 -1
  159. package/dist/runtime/components/Table.vue +27 -8
  160. package/dist/runtime/components/Tabs.vue +20 -1
  161. package/dist/runtime/components/Textarea.vue +1 -1
  162. package/dist/runtime/components/Toast.vue +8 -1
  163. package/dist/runtime/components/Toaster.vue +29 -14
  164. package/dist/runtime/components/Tooltip.vue +3 -0
  165. package/dist/runtime/composables/defineLocale.d.ts +9 -0
  166. package/dist/runtime/composables/defineLocale.js +4 -0
  167. package/dist/runtime/composables/defineShortcuts.js +0 -6
  168. package/dist/runtime/composables/extendDevtoolsMeta.d.ts +7 -0
  169. package/dist/runtime/composables/extendDevtoolsMeta.js +2 -0
  170. package/dist/runtime/composables/useFormField.d.ts +4 -1
  171. package/dist/runtime/composables/useFormField.js +1 -1
  172. package/dist/runtime/composables/useKbd.d.ts +10 -3
  173. package/dist/runtime/composables/useKbd.js +14 -8
  174. package/dist/runtime/composables/useLocale.d.ts +4 -0
  175. package/dist/runtime/composables/useLocale.js +10 -0
  176. package/dist/runtime/index.css +1 -1
  177. package/dist/runtime/locale/ar.d.ts +2 -0
  178. package/dist/runtime/locale/ar.js +47 -0
  179. package/dist/runtime/locale/cs.d.ts +2 -0
  180. package/dist/runtime/locale/cs.js +46 -0
  181. package/dist/runtime/locale/de.d.ts +2 -0
  182. package/dist/runtime/locale/de.js +46 -0
  183. package/dist/runtime/locale/en.d.ts +2 -0
  184. package/dist/runtime/locale/en.js +46 -0
  185. package/dist/runtime/locale/es.d.ts +2 -0
  186. package/dist/runtime/locale/es.js +46 -0
  187. package/dist/runtime/locale/fa_ir.d.ts +2 -0
  188. package/dist/runtime/locale/fa_ir.js +47 -0
  189. package/dist/runtime/locale/fr.d.ts +2 -0
  190. package/dist/runtime/locale/fr.js +46 -0
  191. package/dist/runtime/locale/index.d.ts +12 -0
  192. package/dist/runtime/locale/index.js +12 -0
  193. package/dist/runtime/locale/it.d.ts +2 -0
  194. package/dist/runtime/locale/it.js +46 -0
  195. package/dist/runtime/locale/pl.d.ts +2 -0
  196. package/dist/runtime/locale/pl.js +46 -0
  197. package/dist/runtime/locale/ru.d.ts +2 -0
  198. package/dist/runtime/locale/ru.js +46 -0
  199. package/dist/runtime/locale/zh_hans.d.ts +2 -0
  200. package/dist/runtime/locale/zh_hans.js +46 -0
  201. package/dist/runtime/locale/zh_hant.d.ts +2 -0
  202. package/dist/runtime/locale/zh_hant.js +46 -0
  203. package/dist/runtime/types/form.d.ts +7 -2
  204. package/dist/runtime/types/index.d.ts +3 -0
  205. package/dist/runtime/types/index.js +3 -0
  206. package/dist/runtime/types/locale.d.ts +48 -0
  207. package/dist/runtime/types/locale.js +0 -0
  208. package/dist/runtime/types/utils.d.ts +7 -0
  209. package/dist/runtime/utils/form.d.ts +5 -9
  210. package/dist/runtime/utils/form.js +115 -50
  211. package/dist/runtime/utils/index.js +1 -1
  212. package/dist/runtime/utils/link.d.ts +2 -2
  213. package/dist/runtime/utils/locale.d.ts +15 -0
  214. package/dist/runtime/utils/locale.js +25 -0
  215. package/dist/runtime/vue/components/Icon.vue +15 -0
  216. package/dist/runtime/vue/components/Link.vue +195 -0
  217. package/dist/runtime/vue/plugins/color-mode.d.ts +4 -0
  218. package/dist/runtime/vue/plugins/color-mode.js +6 -0
  219. package/dist/runtime/vue/plugins/head.d.ts +4 -0
  220. package/dist/runtime/vue/plugins/head.js +6 -0
  221. package/dist/runtime/vue/stubs.d.ts +15 -0
  222. package/dist/runtime/vue/stubs.js +27 -0
  223. package/dist/shared/ui.BPnAe4QS.cjs +3030 -0
  224. package/dist/shared/ui.d52SSCwA.mjs +3023 -0
  225. package/dist/unplugin.cjs +192 -0
  226. package/dist/unplugin.d.cts +49 -0
  227. package/dist/unplugin.d.mts +49 -0
  228. package/dist/unplugin.d.ts +49 -0
  229. package/dist/unplugin.mjs +181 -0
  230. package/dist/vite.cjs +22 -0
  231. package/dist/vite.d.cts +13 -0
  232. package/dist/vite.d.mts +13 -0
  233. package/dist/vite.d.ts +13 -0
  234. package/dist/vite.mjs +20 -0
  235. package/package.json +78 -33
  236. package/vue-plugin.d.ts +5 -0
  237. package/cli/node_modules/.ignored/citty/LICENSE +0 -36
  238. package/cli/node_modules/.ignored/citty/README.md +0 -134
  239. package/cli/node_modules/.ignored/citty/dist/index.cjs +0 -475
  240. package/cli/node_modules/.ignored/citty/dist/index.d.cts +0 -80
  241. package/cli/node_modules/.ignored/citty/dist/index.d.mts +0 -80
  242. package/cli/node_modules/.ignored/citty/dist/index.d.ts +0 -80
  243. package/cli/node_modules/.ignored/citty/dist/index.mjs +0 -463
  244. package/cli/node_modules/.ignored/citty/package.json +0 -49
  245. package/cli/node_modules/.ignored/consola/LICENSE +0 -47
  246. package/cli/node_modules/.ignored/consola/README.md +0 -318
  247. package/cli/node_modules/.ignored/consola/core.d.ts +0 -1
  248. package/cli/node_modules/.ignored/consola/dist/basic.cjs +0 -32
  249. package/cli/node_modules/.ignored/consola/dist/basic.d.ts +0 -9
  250. package/cli/node_modules/.ignored/consola/dist/basic.mjs +0 -24
  251. package/cli/node_modules/.ignored/consola/dist/browser.cjs +0 -80
  252. package/cli/node_modules/.ignored/consola/dist/browser.d.ts +0 -7
  253. package/cli/node_modules/.ignored/consola/dist/browser.mjs +0 -72
  254. package/cli/node_modules/.ignored/consola/dist/chunks/prompt.cjs +0 -436
  255. package/cli/node_modules/.ignored/consola/dist/chunks/prompt.mjs +0 -429
  256. package/cli/node_modules/.ignored/consola/dist/core.cjs +0 -415
  257. package/cli/node_modules/.ignored/consola/dist/core.d.ts +0 -124
  258. package/cli/node_modules/.ignored/consola/dist/core.mjs +0 -410
  259. package/cli/node_modules/.ignored/consola/dist/index.cjs +0 -21
  260. package/cli/node_modules/.ignored/consola/dist/index.d.ts +0 -9
  261. package/cli/node_modules/.ignored/consola/dist/index.mjs +0 -8
  262. package/cli/node_modules/.ignored/consola/dist/shared/consola.06ad8a64.mjs +0 -62
  263. package/cli/node_modules/.ignored/consola/dist/shared/consola.36c0034f.mjs +0 -636
  264. package/cli/node_modules/.ignored/consola/dist/shared/consola.4bbae468.cjs +0 -645
  265. package/cli/node_modules/.ignored/consola/dist/shared/consola.deac7d5a.cjs +0 -65
  266. package/cli/node_modules/.ignored/consola/dist/utils.cjs +0 -308
  267. package/cli/node_modules/.ignored/consola/dist/utils.d.ts +0 -169
  268. package/cli/node_modules/.ignored/consola/dist/utils.mjs +0 -284
  269. package/cli/node_modules/.ignored/consola/lib/index.cjs +0 -9
  270. package/cli/node_modules/.ignored/consola/package.json +0 -101
  271. package/cli/node_modules/.ignored/consola/utils.d.ts +0 -1
  272. package/cli/node_modules/.ignored/pathe/LICENSE +0 -44
  273. package/cli/node_modules/.ignored/pathe/README.md +0 -69
  274. package/cli/node_modules/.ignored/pathe/dist/index.cjs +0 -23
  275. package/cli/node_modules/.ignored/pathe/dist/index.d.cts +0 -36
  276. package/cli/node_modules/.ignored/pathe/dist/index.d.mts +0 -36
  277. package/cli/node_modules/.ignored/pathe/dist/index.d.ts +0 -36
  278. package/cli/node_modules/.ignored/pathe/dist/index.mjs +0 -1
  279. package/cli/node_modules/.ignored/pathe/dist/shared/pathe.1f0a373c.cjs +0 -238
  280. package/cli/node_modules/.ignored/pathe/dist/shared/pathe.ff20891b.mjs +0 -221
  281. package/cli/node_modules/.ignored/pathe/dist/utils.cjs +0 -58
  282. package/cli/node_modules/.ignored/pathe/dist/utils.d.cts +0 -5
  283. package/cli/node_modules/.ignored/pathe/dist/utils.d.mts +0 -5
  284. package/cli/node_modules/.ignored/pathe/dist/utils.d.ts +0 -5
  285. package/cli/node_modules/.ignored/pathe/dist/utils.mjs +0 -54
  286. package/cli/node_modules/.ignored/pathe/package.json +0 -48
  287. package/cli/node_modules/.ignored/pathe/utils.d.ts +0 -1
  288. package/cli/node_modules/.ignored/scule/LICENSE +0 -21
  289. package/cli/node_modules/.ignored/scule/README.md +0 -149
  290. package/cli/node_modules/.ignored/scule/dist/index.cjs +0 -92
  291. package/cli/node_modules/.ignored/scule/dist/index.d.cts +0 -57
  292. package/cli/node_modules/.ignored/scule/dist/index.d.mts +0 -57
  293. package/cli/node_modules/.ignored/scule/dist/index.d.ts +0 -57
  294. package/cli/node_modules/.ignored/scule/dist/index.mjs +0 -80
  295. package/cli/node_modules/.ignored/scule/package.json +0 -43
  296. package/cli/node_modules/.package-lock.json +0 -33
@@ -5,8 +5,9 @@ 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
9
  import type { AvatarProps, ChipProps, InputProps } from '../types'
9
- import type { AcceptableValue, ArrayOrWrapped, PartialString } from '../types/utils'
10
+ import type { AcceptableValue, ArrayOrWrapped, PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
10
11
 
11
12
  const appConfig = _appConfig as AppConfig & { ui: { selectMenu: Partial<typeof theme> } }
12
13
 
@@ -28,16 +29,17 @@ export interface SelectMenuItem {
28
29
 
29
30
  type SelectMenuVariants = VariantProps<typeof selectMenu>
30
31
 
31
- export interface SelectMenuProps<T> extends Pick<ComboboxRootProps<T>, 'modelValue' | 'defaultValue' | 'selectedValue' | 'open' | 'defaultOpen' | 'searchTerm' | 'multiple' | 'disabled' | 'name' | 'resetSearchTermOnBlur'>, UseComponentIconsProps {
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
33
  id?: string
33
34
  /** The placeholder text when the select is empty. */
34
35
  placeholder?: string
35
36
  /**
36
- * Wether to display the search input or not.
37
+ * Whether to display the search input or not.
37
38
  * Can be an object to pass additional props to the input.
38
- * @defaultValue { placeholder: 'Search...' }
39
+ * `{ placeholder: 'Search...', variant: 'none' }`{lang="ts-type"}
40
+ * @defaultValue true
39
41
  */
40
- searchInput?: boolean | { placeholder?: string }
42
+ searchInput?: boolean | InputProps
41
43
  color?: SelectMenuVariants['color']
42
44
  variant?: SelectMenuVariants['variant']
43
45
  size?: SelectMenuVariants['size']
@@ -68,33 +70,44 @@ export interface SelectMenuProps<T> extends Pick<ComboboxRootProps<T>, 'modelVal
68
70
  */
69
71
  portal?: boolean
70
72
  /**
71
- * Whether to filter items or not, can be an array of fields to filter.
73
+ * Whether to filter items or not, can be an array of fields to filter. Defaults to `[labelKey]`.
72
74
  * When `false`, items will not be filtered which is useful for custom filtering (useAsyncData, useFetch, etc.).
73
- * @defaultValue ['label']
75
+ * `['label']`{lang="ts-type"}
76
+ * @defaultValue true
74
77
  */
75
78
  filter?: boolean | string[]
76
79
  /**
77
80
  * When `items` is an array of objects, select the field to use as the value instead of the object itself.
78
81
  * @defaultValue undefined
79
82
  */
80
- valueKey?: keyof T
83
+ valueKey?: V
81
84
  /**
82
85
  * When `items` is an array of objects, select the field to use as the label.
83
86
  * @defaultValue 'label'
84
87
  */
85
- labelKey?: keyof T
86
- items?: T[] | T[][]
88
+ labelKey?: V
89
+ items?: I
87
90
  /** Highlight the ring color like a focus state. */
88
91
  highlight?: boolean
92
+ /**
93
+ * Determines if custom user input that does not exist in options can be added.
94
+ * @defaultValue false
95
+ */
96
+ createItem?: boolean | 'always' | { placement?: 'top' | 'bottom', when?: 'empty' | 'always' }
89
97
  class?: any
90
98
  ui?: PartialString<typeof selectMenu.slots>
99
+ /** The controlled value of the Combobox. Can be binded-with with `v-model`. */
100
+ modelValue?: SelectModelValue<T, V, M>
101
+ /** Whether multiple options can be selected or not. */
102
+ multiple?: M
91
103
  }
92
104
 
93
- export type SelectMenuEmits<T> = ComboboxRootEmits<T> & {
105
+ export type SelectMenuEmits<T, V, M extends boolean> = Omit<ComboboxRootEmits<T>, 'update:modelValue'> & {
94
106
  change: [payload: Event]
95
107
  blur: [payload: FocusEvent]
96
108
  focus: [payload: FocusEvent]
97
- }
109
+ create: [payload: Event, item: T]
110
+ } & SelectModelValueEmits<T, V, M>
98
111
 
99
112
  type SlotProps<T> = (props: { item: T, index: number }) => any
100
113
 
@@ -107,40 +120,55 @@ export interface SelectMenuSlots<T> {
107
120
  'item-leading': SlotProps<T>
108
121
  'item-label': SlotProps<T>
109
122
  'item-trailing': SlotProps<T>
123
+ 'create-item-label'(props: { item: T }): any
110
124
  }
125
+
126
+ extendDevtoolsMeta({ defaultProps: { items: ['Option 1', 'Option 2', 'Option 3'] } })
111
127
  </script>
112
128
 
113
- <script setup lang="ts" generic="T extends SelectMenuItem | AcceptableValue">
114
- import { computed, toRef } from 'vue'
115
- import { ComboboxRoot, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, useForwardPropsEmits } from 'radix-vue'
129
+ <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">
130
+ import { computed, toRef, toRaw } from 'vue'
131
+ import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, useForwardPropsEmits } from 'radix-vue'
116
132
  import { defu } from 'defu'
117
- import isEqual from 'fast-deep-equal'
118
- import { reactivePick } from '@vueuse/core'
133
+ import { isEqual } from 'ohash'
134
+ import { reactivePick, createReusableTemplate } from '@vueuse/core'
119
135
  import { useAppConfig } from '#imports'
120
136
  import { useButtonGroup } from '../composables/useButtonGroup'
121
137
  import { useComponentIcons } from '../composables/useComponentIcons'
122
138
  import { useFormField } from '../composables/useFormField'
139
+ import { useLocale } from '../composables/useLocale'
123
140
  import { get, escapeRegExp } from '../utils'
124
141
  import UIcon from './Icon.vue'
125
142
  import UAvatar from './Avatar.vue'
126
143
  import UChip from './Chip.vue'
144
+ import UInput from './Input.vue'
127
145
 
128
- const props = withDefaults(defineProps<SelectMenuProps<T>>(), {
146
+ const props = withDefaults(defineProps<SelectMenuProps<T, I, V, M>>(), {
129
147
  search: true,
130
148
  portal: true,
131
149
  autofocusDelay: 0,
132
- searchInput: () => ({ placeholder: 'Search...' }),
133
- filter: () => ['label'],
134
- labelKey: 'label' as keyof T
150
+ searchInput: true,
151
+ filter: true,
152
+ labelKey: 'label' as never
135
153
  })
136
- const emits = defineEmits<SelectMenuEmits<T>>()
154
+
155
+ const emits = defineEmits<SelectMenuEmits<T, V, M>>()
137
156
  const slots = defineSlots<SelectMenuSlots<T>>()
138
157
 
139
158
  const searchTerm = defineModel<string>('searchTerm', { default: '' })
140
159
 
141
160
  const appConfig = useAppConfig()
142
- const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur'), emits)
161
+
162
+ const { t } = useLocale()
163
+ const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'selectedValue', 'open', 'defaultOpen', 'resetSearchTermOnBlur'), emits)
143
164
  const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, position: 'popper' }) as ComboboxContentProps)
165
+ const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
166
+ const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: 'Search...', variant: 'none' }) as InputProps)
167
+ // This is a hack due to generic boolean casting (see https://github.com/nuxt/ui/issues/2541)
168
+ const multiple = toRef(() => typeof props.multiple === 'string' ? true : props.multiple)
169
+
170
+ const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate()
171
+
144
172
  const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
145
173
  const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
146
174
  const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
@@ -158,33 +186,41 @@ const ui = computed(() => selectMenu({
158
186
  buttonGroup: orientation.value
159
187
  }))
160
188
 
161
- function displayValue(value: T): string {
162
- if (props.multiple && Array.isArray(value)) {
163
- return value.map(v => displayValue(v)).join(', ')
189
+ function displayValue(value: T | T[]): string {
190
+ if (multiple.value && Array.isArray(value)) {
191
+ return value.map(v => displayValue(v)).filter(Boolean).join(', ')
192
+ }
193
+
194
+ if (!props.valueKey) {
195
+ return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
164
196
  }
165
197
 
166
- const item = items.value.find(item => props.valueKey ? isEqual(get(item as Record<string, any>, props.valueKey as string), value) : isEqual(item, value))
198
+ const item = items.value.find(item => isEqual(get(item as Record<string, any>, props.valueKey as string), value)) ?? (props.createItem && value)
167
199
 
168
200
  return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
169
201
  }
170
202
 
171
- function filterFunction(items: ArrayOrWrapped<AcceptableValue>, searchTerm: string): ArrayOrWrapped<AcceptableValue> {
203
+ function filterFunction(
204
+ inputItems: ArrayOrWrapped<T> = items.value as ArrayOrWrapped<T>,
205
+ filterSearchTerm: string = searchTerm.value,
206
+ comparator = (item: any, term: string) => String(item).search(new RegExp(term, 'i')) !== -1
207
+ ): ArrayOrWrapped<T> {
172
208
  if (props.filter === false) {
173
- return items
209
+ return inputItems
174
210
  }
175
211
 
176
212
  const fields = Array.isArray(props.filter) ? props.filter : [props.labelKey]
177
- const escapedSearchTerm = escapeRegExp(searchTerm)
213
+ const escapedSearchTerm = escapeRegExp(filterSearchTerm)
178
214
 
179
- return items.filter((item) => {
215
+ return inputItems.filter((item: T) => {
180
216
  if (typeof item !== 'object') {
181
- return String(item).search(new RegExp(escapedSearchTerm, 'i')) !== -1
217
+ return comparator(item, escapedSearchTerm)
182
218
  }
183
219
 
184
220
  return fields.some((field) => {
185
221
  const child = get(item, field as string)
186
222
 
187
- return child !== null && child !== undefined && String(child).search(new RegExp(escapedSearchTerm, 'i')) !== -1
223
+ return child !== null && child !== undefined && comparator(child, escapedSearchTerm)
188
224
  })
189
225
  }) as ArrayOrWrapped<T>
190
226
  }
@@ -193,7 +229,40 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
193
229
  // eslint-disable-next-line vue/no-dupe-keys
194
230
  const items = computed(() => groups.value.flatMap(group => group) as T[])
195
231
 
232
+ const creatable = computed(() => {
233
+ if (!props.createItem) {
234
+ return false
235
+ }
236
+
237
+ const isModelValueCustom = props.modelValue && filterFunction((props.multiple && Array.isArray(props.modelValue) ? props.modelValue : [props.modelValue]) as ArrayOrWrapped<T>, searchTerm.value, (item, term) => String(item) === term).length === 1
238
+
239
+ if (isModelValueCustom) {
240
+ return false
241
+ }
242
+
243
+ const filteredItems = filterFunction()
244
+ const newItem = searchTerm.value && {
245
+ item: props.valueKey ? { [props.valueKey]: searchTerm.value, [props.labelKey ?? 'label']: searchTerm.value } : searchTerm.value,
246
+ position: ((typeof props.createItem === 'object' && props.createItem.placement) || 'bottom') as 'top' | 'bottom'
247
+ }
248
+
249
+ if ((typeof props.createItem === 'object' && props.createItem.when === 'always') || props.createItem === 'always') {
250
+ return (filteredItems.length === 1 && filterFunction(filteredItems, searchTerm.value, (item, term) => String(item) === term).length === 1) ? false : newItem
251
+ }
252
+
253
+ return filteredItems.length > 0 ? false : newItem
254
+ })
255
+
256
+ const rootItems = computed(() => [
257
+ ...(creatable.value && creatable.value.position === 'top' ? [creatable.value.item] : []),
258
+ ...filterFunction(),
259
+ ...(creatable.value && creatable.value.position === 'bottom' ? [creatable.value.item] : [])
260
+ ] as ArrayOrWrapped<T>)
261
+
196
262
  function onUpdate(value: any) {
263
+ if (toRaw(props.modelValue) === value) {
264
+ return
265
+ }
197
266
  // @ts-expect-error - 'target' does not exist in type 'EventInit'
198
267
  const event = new Event('change', { target: { value } })
199
268
  emits('change', event)
@@ -214,6 +283,22 @@ function onUpdateOpen(value: boolean) {
214
283
  </script>
215
284
 
216
285
  <template>
286
+ <DefineCreateItemTemplate>
287
+ <ComboboxGroup v-if="creatable" :class="ui.group({ class: props.ui?.group })">
288
+ <ComboboxItem
289
+ :class="ui.item({ class: props.ui?.item })"
290
+ :value="valueKey && typeof creatable.item === 'object' ? get(creatable.item, props.valueKey as string) : creatable.item"
291
+ @select="e => emits('create', e, (creatable as any).item as T)"
292
+ >
293
+ <span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
294
+ <slot name="create-item-label" :item="(creatable.item as T)">
295
+ {{ t('selectMenu.create', { label: typeof creatable.item === 'object' ? get(creatable.item, props.labelKey as string) : creatable.item }) }}
296
+ </slot>
297
+ </span>
298
+ </ComboboxItem>
299
+ </ComboboxGroup>
300
+ </DefineCreateItemTemplate>
301
+
217
302
  <ComboboxRoot
218
303
  :id="id"
219
304
  v-slot="{ modelValue, open }"
@@ -222,8 +307,9 @@ function onUpdateOpen(value: boolean) {
222
307
  as-child
223
308
  :name="name"
224
309
  :disabled="disabled"
310
+ :multiple="multiple"
225
311
  :display-value="() => searchTerm"
226
- :filter-function="filterFunction"
312
+ :filter-function="() => rootItems"
227
313
  @update:model-value="onUpdate"
228
314
  @update:open="onUpdateOpen"
229
315
  >
@@ -257,21 +343,19 @@ function onUpdateOpen(value: boolean) {
257
343
 
258
344
  <ComboboxPortal :disabled="!portal">
259
345
  <ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
260
- <ComboboxInput
261
- v-if="!!searchInput"
262
- autofocus
263
- autocomplete="off"
264
- v-bind="typeof searchInput === 'object' ? searchInput : {}"
265
- :class="ui.input({ class: props.ui?.input })"
266
- />
346
+ <ComboboxInput v-if="!!searchInput" as-child>
347
+ <UInput autofocus autocomplete="off" v-bind="searchInputProps" :class="ui.input({ class: props.ui?.input })" />
348
+ </ComboboxInput>
267
349
 
268
350
  <ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
269
351
  <slot name="empty" :search-term="searchTerm">
270
- {{ searchTerm ? `No results for ${searchTerm}` : 'No results' }}
352
+ {{ searchTerm ? t('selectMenu.noMatch', { searchTerm }) : t('selectMenu.noData') }}
271
353
  </slot>
272
354
  </ComboboxEmpty>
273
355
 
274
356
  <ComboboxViewport :class="ui.viewport({ class: props.ui?.viewport })">
357
+ <ReuseCreateItemTemplate v-if="creatable && creatable.position === 'top'" />
358
+
275
359
  <ComboboxGroup v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
276
360
  <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
277
361
  <ComboboxLabel v-if="item?.type === 'label'" :class="ui.label({ class: props.ui?.label })">
@@ -318,7 +402,11 @@ function onUpdateOpen(value: boolean) {
318
402
  </ComboboxItem>
319
403
  </template>
320
404
  </ComboboxGroup>
405
+
406
+ <ReuseCreateItemTemplate v-if="creatable && creatable.position === 'bottom'" />
321
407
  </ComboboxViewport>
408
+
409
+ <ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
322
410
  </ComboboxContent>
323
411
  </ComboboxPortal>
324
412
  </ComboboxRoot>
@@ -15,7 +15,7 @@ type SeparatorVariants = VariantProps<typeof separator>
15
15
  export interface SeparatorProps extends Pick<_SeparatorProps, 'decorative'> {
16
16
  /**
17
17
  * The element or component this component should render as.
18
- * @defaultValue `div`
18
+ * @defaultValue 'div'
19
19
  */
20
20
  as?: any
21
21
  /** Display a label in the middle. */
@@ -3,6 +3,7 @@ import { tv } from 'tailwind-variants'
3
3
  import type { AppConfig } from '@nuxt/schema'
4
4
  import _appConfig from '#build/app.config'
5
5
  import theme from '#build/ui/skeleton'
6
+ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
6
7
 
7
8
  const appConfig = _appConfig as AppConfig & { ui: { skeleton: Partial<typeof theme> } }
8
9
 
@@ -16,6 +17,8 @@ export interface SkeletonProps {
16
17
  as?: any
17
18
  class?: any
18
19
  }
20
+
21
+ extendDevtoolsMeta({ example: 'SkeletonExample' })
19
22
  </script>
20
23
 
21
24
  <script setup lang="ts">
@@ -4,6 +4,7 @@ import type { DialogRootProps, DialogRootEmits, DialogContentProps } from 'radix
4
4
  import type { AppConfig } from '@nuxt/schema'
5
5
  import _appConfig from '#build/app.config'
6
6
  import theme from '#build/ui/slideover'
7
+ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
7
8
  import type { ButtonProps } from '../types'
8
9
 
9
10
  const appConfig = _appConfig as AppConfig & { ui: { slideover: Partial<typeof theme> } }
@@ -65,6 +66,8 @@ export interface SlideoverSlots {
65
66
  body(props?: {}): any
66
67
  footer(props?: {}): any
67
68
  }
69
+
70
+ extendDevtoolsMeta({ example: 'SlideoverExample' })
68
71
  </script>
69
72
 
70
73
  <script setup lang="ts">
@@ -72,6 +75,7 @@ import { computed, toRef } from 'vue'
72
75
  import { DialogRoot, DialogTrigger, DialogPortal, DialogOverlay, DialogContent, DialogTitle, DialogDescription, DialogClose, useForwardPropsEmits } from 'radix-vue'
73
76
  import { reactivePick } from '@vueuse/core'
74
77
  import { useAppConfig } from '#imports'
78
+ import { useLocale } from '../composables/useLocale'
75
79
  import UButton from './Button.vue'
76
80
 
77
81
  const props = withDefaults(defineProps<SlideoverProps>(), {
@@ -91,14 +95,22 @@ const contentEvents = computed(() => {
91
95
  if (props.preventClose) {
92
96
  return {
93
97
  pointerDownOutside: (e: Event) => e.preventDefault(),
94
- interactOutside: (e: Event) => e.preventDefault()
98
+ interactOutside: (e: Event) => e.preventDefault(),
99
+ escapeKeyDown: (e: Event) => e.preventDefault()
95
100
  }
96
101
  }
97
102
 
98
- return {}
103
+ return {
104
+ interactOutside: (e: Event) => {
105
+ if (e.target instanceof Element && e.target.closest('[data-sonner-toaster]')) {
106
+ return e.preventDefault()
107
+ }
108
+ }
109
+ }
99
110
  })
100
111
 
101
112
  const appConfig = useAppConfig()
113
+ const { t } = useLocale()
102
114
 
103
115
  const ui = computed(() => slideover({
104
116
  transition: props.transition,
@@ -139,7 +151,7 @@ const ui = computed(() => slideover({
139
151
  size="md"
140
152
  color="neutral"
141
153
  variant="ghost"
142
- aria-label="Close"
154
+ :aria-label="t('slideover.close')"
143
155
  v-bind="typeof close === 'object' ? close : undefined"
144
156
  :class="ui.close({ class: props.ui?.close })"
145
157
  />
@@ -14,7 +14,7 @@ type SliderVariants = VariantProps<typeof slider>
14
14
  export interface SliderProps extends Pick<SliderRootProps, 'name' | 'disabled' | 'inverted' | 'min' | 'max' | 'step' | 'minStepsBetweenThumbs'> {
15
15
  /**
16
16
  * The element or component this component should render as.
17
- * @defaultValue `div`
17
+ * @defaultValue 'div'
18
18
  */
19
19
  as?: any
20
20
  size?: SliderVariants['size']
@@ -4,6 +4,7 @@ import type { SwitchRootProps } from 'radix-vue'
4
4
  import type { AppConfig } from '@nuxt/schema'
5
5
  import _appConfig from '#build/app.config'
6
6
  import theme from '#build/ui/switch'
7
+ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
7
8
  import type { PartialString } from '../types/utils'
8
9
 
9
10
  const appConfig = _appConfig as AppConfig & { ui: { switch: Partial<typeof theme> } }
@@ -15,7 +16,7 @@ type SwitchVariants = VariantProps<typeof switchTv>
15
16
  export interface SwitchProps extends Pick<SwitchRootProps, 'disabled' | 'id' | 'name' | 'required' | 'value'> {
16
17
  /**
17
18
  * The element or component this component should render as.
18
- * @defaultValue `div`
19
+ * @defaultValue 'div'
19
20
  */
20
21
  as?: any
21
22
  color?: SwitchVariants['color']
@@ -48,6 +49,8 @@ export interface SwitchSlots {
48
49
  label(props: { label?: string }): any
49
50
  description(props: { description?: string }): any
50
51
  }
52
+
53
+ extendDevtoolsMeta({ defaultProps: { label: 'Switch me!' } })
51
54
  </script>
52
55
 
53
56
  <script setup lang="ts">
@@ -56,6 +59,7 @@ import { SwitchRoot, SwitchThumb, useForwardProps, Label } from 'radix-vue'
56
59
  import { reactivePick } from '@vueuse/core'
57
60
  import { useAppConfig } from '#imports'
58
61
  import { useFormField } from '../composables/useFormField'
62
+ import UIcon from './Icon.vue'
59
63
 
60
64
  const props = defineProps<SwitchProps>()
61
65
  const slots = defineSlots<SwitchSlots>()
@@ -19,7 +19,9 @@ import type {
19
19
  ExpandedOptions,
20
20
  SortingOptions,
21
21
  RowSelectionOptions,
22
- Updater
22
+ Updater,
23
+ CellContext,
24
+ HeaderContext
23
25
  } from '@tanstack/vue-table'
24
26
  import _appConfig from '#build/app.config'
25
27
  import theme from '#build/ui/table'
@@ -39,6 +41,7 @@ export interface TableData {
39
41
  export interface TableProps<T> {
40
42
  data?: T[]
41
43
  columns?: TableColumn<T>[]
44
+ caption?: string
42
45
  /**
43
46
  * Whether the table should have a sticky header.
44
47
  * @defaultValue false
@@ -87,10 +90,14 @@ export interface TableProps<T> {
87
90
  ui?: Partial<typeof table.slots>
88
91
  }
89
92
 
90
- export interface TableSlots<T> {
91
- expanded(props: { row: Row<T> }): any
92
- empty(props?: {}): any
93
- }
93
+ type DynamicHeaderSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-header`, (props: HeaderContext<T, unknown>) => any>
94
+ type DynamicCellSlots<T, K = keyof T> = Record<string, (props: CellContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-cell`, (props: CellContext<T, unknown>) => any>
95
+
96
+ export type TableSlots<T> = {
97
+ expanded: (props: { row: Row<T> }) => any
98
+ empty: (props?: {}) => any
99
+ caption: (props?: {}) => any
100
+ } & DynamicHeaderSlots<T> & DynamicCellSlots<T>
94
101
 
95
102
  </script>
96
103
 
@@ -105,10 +112,12 @@ import {
105
112
  useVueTable
106
113
  } from '@tanstack/vue-table'
107
114
  import { upperFirst } from 'scule'
115
+ import { useLocale } from '../composables/useLocale'
108
116
 
109
117
  const props = defineProps<TableProps<T>>()
110
118
  defineSlots<TableSlots<T>>()
111
119
 
120
+ const { t } = useLocale()
112
121
  const data = computed(() => props.data ?? [])
113
122
  const columns = computed<TableColumn<T>[]>(() => props.columns ?? Object.keys(data.value[0] ?? {}).map((accessorKey: string) => ({ accessorKey, header: upperFirst(accessorKey) })))
114
123
 
@@ -185,6 +194,12 @@ defineExpose({
185
194
  <template>
186
195
  <div :class="ui.root({ class: [props.class, props.ui?.root] })">
187
196
  <table :class="ui.base({ class: [props.ui?.base] })">
197
+ <caption v-if="caption" :class="ui.caption({ class: [props.ui?.caption] })">
198
+ <slot name="caption">
199
+ {{ caption }}
200
+ </slot>
201
+ </caption>
202
+
188
203
  <thead :class="ui.thead({ class: [props.ui?.thead] })">
189
204
  <tr v-for="headerGroup in tableApi.getHeaderGroups()" :key="headerGroup.id" :class="ui.tr({ class: [props.ui?.tr] })">
190
205
  <th
@@ -193,7 +208,9 @@ defineExpose({
193
208
  :data-pinned="header.column.getIsPinned()"
194
209
  :class="ui.th({ class: [props.ui?.th], pinned: !!header.column.getIsPinned() })"
195
210
  >
196
- <FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
211
+ <slot :name="`${header.id}-header`" v-bind="header.getContext()">
212
+ <FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
213
+ </slot>
197
214
  </th>
198
215
  </tr>
199
216
  </thead>
@@ -208,7 +225,9 @@ defineExpose({
208
225
  :data-pinned="cell.column.getIsPinned()"
209
226
  :class="ui.td({ class: [props.ui?.td], pinned: !!cell.column.getIsPinned() })"
210
227
  >
211
- <FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
228
+ <slot :name="`${cell.column.id}-cell`" v-bind="cell.getContext()">
229
+ <FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
230
+ </slot>
212
231
  </td>
213
232
  </tr>
214
233
  <tr v-if="row.getIsExpanded()" :class="ui.tr({ class: [props.ui?.tr] })">
@@ -222,7 +241,7 @@ defineExpose({
222
241
  <tr v-else :class="ui.tr({ class: [props.ui?.tr] })">
223
242
  <td :colspan="columns?.length" :class="ui.empty({ class: props.ui?.empty })">
224
243
  <slot name="empty">
225
- No results
244
+ {{ t('table.noData') }}
226
245
  </slot>
227
246
  </td>
228
247
  </tr>
@@ -1,10 +1,10 @@
1
- <!-- eslint-disable vue/block-tag-newline -->
2
1
  <script lang="ts">
3
2
  import { tv, type VariantProps } from 'tailwind-variants'
4
3
  import type { TabsRootProps, TabsRootEmits, TabsContentProps } from 'radix-vue'
5
4
  import type { AppConfig } from '@nuxt/schema'
6
5
  import _appConfig from '#build/app.config'
7
6
  import theme from '#build/ui/tabs'
7
+ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
8
8
  import type { AvatarProps } from '../types'
9
9
  import type { DynamicSlots, PartialString } from '../types/utils'
10
10
 
@@ -65,6 +65,23 @@ export type TabsSlots<T extends { slot?: string }> = {
65
65
  content: SlotProps<T>
66
66
  } & DynamicSlots<T, SlotProps<T>>
67
67
 
68
+ extendDevtoolsMeta({
69
+ defaultProps: {
70
+ items: [{
71
+ label: 'Tab1',
72
+ avatar: { src: 'https://avatars.githubusercontent.com/u/739984?v=4' },
73
+ content: 'This is the content shown for Tab1'
74
+ }, {
75
+ label: 'Tab2',
76
+ icon: 'i-lucide-user',
77
+ content: 'And, this is the content for Tab2'
78
+ }, {
79
+ label: 'Tab3',
80
+ icon: 'i-lucide-bell',
81
+ content: 'Finally, this is the content for Tab3'
82
+ }]
83
+ }
84
+ })
68
85
  </script>
69
86
 
70
87
  <script setup lang="ts" generic="T extends TabsItem">
@@ -73,6 +90,8 @@ import { defu } from 'defu'
73
90
  import { TabsRoot, TabsList, TabsIndicator, TabsTrigger, TabsContent, useForwardPropsEmits } from 'radix-vue'
74
91
  import { reactivePick } from '@vueuse/core'
75
92
  import { get } from '../utils'
93
+ import UIcon from './Icon.vue'
94
+ import UAvatar from './Avatar.vue'
76
95
 
77
96
  const props = withDefaults(defineProps<TabsProps<T>>(), {
78
97
  content: true,
@@ -151,7 +151,7 @@ function autoResize() {
151
151
  }
152
152
  }
153
153
 
154
- watch(() => modelValue, () => {
154
+ watch(modelValue, () => {
155
155
  nextTick(autoResize)
156
156
  })
157
157
 
@@ -4,6 +4,7 @@ import type { ToastRootProps, ToastRootEmits } from 'radix-vue'
4
4
  import type { AppConfig } from '@nuxt/schema'
5
5
  import _appConfig from '#build/app.config'
6
6
  import theme from '#build/ui/toast'
7
+ import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
7
8
  import type { AvatarProps, ButtonProps } from '../types'
8
9
 
9
10
  const appConfig = _appConfig as AppConfig & { ui: { toast: Partial<typeof theme> } }
@@ -27,6 +28,7 @@ export interface ToastProps extends Pick<ToastRootProps, 'defaultOpen' | 'open'
27
28
  * Display a list of actions:
28
29
  * - under the title and description if multiline
29
30
  * - next to the close button if not multiline
31
+ * `{ size: 'xs' }`{lang="ts-type"}
30
32
  */
31
33
  actions?: ButtonProps[]
32
34
  /**
@@ -53,6 +55,8 @@ export interface ToastSlots {
53
55
  actions(props?: {}): any
54
56
  close(props: { ui: any }): any
55
57
  }
58
+
59
+ extendDevtoolsMeta<ToastProps>({ ignore: true })
56
60
  </script>
57
61
 
58
62
  <script setup lang="ts">
@@ -60,8 +64,10 @@ import { ref, computed, onMounted } from 'vue'
60
64
  import { ToastRoot, ToastTitle, ToastDescription, ToastAction, ToastClose, useForwardPropsEmits } from 'radix-vue'
61
65
  import { reactivePick } from '@vueuse/core'
62
66
  import { useAppConfig } from '#imports'
67
+ import { useLocale } from '../composables/useLocale'
63
68
  import UIcon from './Icon.vue'
64
69
  import UAvatar from './Avatar.vue'
70
+ import UButton from './Button.vue'
65
71
 
66
72
  const props = withDefaults(defineProps<ToastProps>(), {
67
73
  close: true
@@ -70,6 +76,7 @@ const emits = defineEmits<ToastEmits>()
70
76
  const slots = defineSlots<ToastSlots>()
71
77
 
72
78
  const appConfig = useAppConfig()
79
+ const { t } = useLocale()
73
80
  const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'defaultOpen', 'open', 'duration', 'type'), emits)
74
81
 
75
82
  const multiline = computed(() => !!props.title && !!props.description)
@@ -147,7 +154,7 @@ defineExpose({
147
154
  size="md"
148
155
  color="neutral"
149
156
  variant="link"
150
- aria-label="Close"
157
+ :aria-label="t('toast.close')"
151
158
  v-bind="typeof close === 'object' ? close : undefined"
152
159
  :class="ui.close({ class: props.ui?.close })"
153
160
  @click.stop