@nuxt/ui 3.0.2 → 3.1.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 (221) hide show
  1. package/.nuxt/ui/accordion.ts +2 -2
  2. package/.nuxt/ui/alert.ts +29 -29
  3. package/.nuxt/ui/avatar-group.ts +1 -1
  4. package/.nuxt/ui/avatar.ts +3 -3
  5. package/.nuxt/ui/badge.ts +33 -33
  6. package/.nuxt/ui/breadcrumb.ts +5 -5
  7. package/.nuxt/ui/button.ts +43 -43
  8. package/.nuxt/ui/calendar.ts +17 -17
  9. package/.nuxt/ui/card.ts +5 -5
  10. package/.nuxt/ui/carousel.ts +6 -6
  11. package/.nuxt/ui/checkbox-group.ts +61 -0
  12. package/.nuxt/ui/checkbox.ts +140 -27
  13. package/.nuxt/ui/chip.ts +8 -8
  14. package/.nuxt/ui/color-picker.ts +3 -3
  15. package/.nuxt/ui/command-palette.ts +14 -14
  16. package/.nuxt/ui/context-menu.ts +33 -33
  17. package/.nuxt/ui/drawer.ts +10 -10
  18. package/.nuxt/ui/dropdown-menu.ts +34 -34
  19. package/.nuxt/ui/form-field.ts +6 -6
  20. package/.nuxt/ui/index.ts +1 -0
  21. package/.nuxt/ui/input-menu.ts +42 -42
  22. package/.nuxt/ui/input-number.ts +20 -20
  23. package/.nuxt/ui/input.ts +23 -23
  24. package/.nuxt/ui/kbd.ts +4 -4
  25. package/.nuxt/ui/link.ts +3 -3
  26. package/.nuxt/ui/modal.ts +5 -5
  27. package/.nuxt/ui/navigation-menu.ts +78 -80
  28. package/.nuxt/ui/pin-input.ts +20 -20
  29. package/.nuxt/ui/popover.ts +2 -2
  30. package/.nuxt/ui/progress.ts +17 -17
  31. package/.nuxt/ui/radio-group.ts +250 -35
  32. package/.nuxt/ui/select-menu.ts +36 -33
  33. package/.nuxt/ui/select.ts +32 -32
  34. package/.nuxt/ui/separator.ts +8 -8
  35. package/.nuxt/ui/skeleton.ts +1 -1
  36. package/.nuxt/ui/slideover.ts +4 -4
  37. package/.nuxt/ui/slider.ts +16 -16
  38. package/.nuxt/ui/stepper.ts +18 -18
  39. package/.nuxt/ui/switch.ts +20 -20
  40. package/.nuxt/ui/table.ts +15 -15
  41. package/.nuxt/ui/tabs.ts +32 -32
  42. package/.nuxt/ui/textarea.ts +40 -35
  43. package/.nuxt/ui/toast.ts +24 -24
  44. package/.nuxt/ui/tooltip.ts +2 -2
  45. package/.nuxt/ui/tree.ts +18 -18
  46. package/.nuxt/ui.css +63 -12
  47. package/README.md +15 -0
  48. package/cli/templates.mjs +18 -17
  49. package/dist/module.json +5 -5
  50. package/dist/module.mjs +12 -7
  51. package/dist/runtime/components/Accordion.vue +36 -93
  52. package/dist/runtime/components/Accordion.vue.d.ts +75 -0
  53. package/dist/runtime/components/Alert.vue +37 -100
  54. package/dist/runtime/components/Alert.vue.d.ts +81 -0
  55. package/dist/runtime/components/App.vue +28 -34
  56. package/dist/runtime/components/App.vue.d.ts +24 -0
  57. package/dist/runtime/components/Avatar.vue +42 -75
  58. package/dist/runtime/components/Avatar.vue.d.ts +39 -0
  59. package/dist/runtime/components/AvatarGroup.vue +40 -77
  60. package/dist/runtime/components/AvatarGroup.vue.d.ts +31 -0
  61. package/dist/runtime/components/Badge.vue +33 -62
  62. package/dist/runtime/components/Badge.vue.d.ts +41 -0
  63. package/dist/runtime/components/Breadcrumb.vue +37 -90
  64. package/dist/runtime/components/Breadcrumb.vue.d.ts +64 -0
  65. package/dist/runtime/components/Button.vue +95 -104
  66. package/dist/runtime/components/Button.vue.d.ts +48 -0
  67. package/dist/runtime/components/ButtonGroup.vue +20 -46
  68. package/dist/runtime/components/ButtonGroup.vue.d.ts +34 -0
  69. package/dist/runtime/components/Calendar.vue +67 -150
  70. package/dist/runtime/components/Calendar.vue.d.ts +111 -0
  71. package/dist/runtime/components/Card.vue +18 -40
  72. package/dist/runtime/components/Card.vue.d.ts +29 -0
  73. package/dist/runtime/components/Carousel.vue +112 -234
  74. package/dist/runtime/components/Carousel.vue.d.ts +122 -0
  75. package/dist/runtime/components/Checkbox.vue +52 -93
  76. package/dist/runtime/components/Checkbox.vue.d.ts +73 -0
  77. package/dist/runtime/components/CheckboxGroup.vue +121 -0
  78. package/dist/runtime/components/CheckboxGroup.vue.d.ts +78 -0
  79. package/dist/runtime/components/Chip.vue +26 -69
  80. package/dist/runtime/components/Chip.vue.d.ts +57 -0
  81. package/dist/runtime/components/Collapsible.vue +22 -41
  82. package/dist/runtime/components/Collapsible.vue.d.ts +35 -0
  83. package/dist/runtime/components/ColorPicker.vue +111 -197
  84. package/dist/runtime/components/ColorPicker.vue.d.ts +48 -0
  85. package/dist/runtime/components/CommandPalette.vue +96 -237
  86. package/dist/runtime/components/CommandPalette.vue.d.ts +161 -0
  87. package/dist/runtime/components/Container.vue +15 -28
  88. package/dist/runtime/components/Container.vue.d.ts +18 -0
  89. package/dist/runtime/components/ContextMenu.vue +34 -133
  90. package/dist/runtime/components/ContextMenu.vue.d.ts +107 -0
  91. package/dist/runtime/components/ContextMenuContent.vue +73 -81
  92. package/dist/runtime/components/ContextMenuContent.vue.d.ts +65 -0
  93. package/dist/runtime/components/Drawer.vue +49 -83
  94. package/dist/runtime/components/Drawer.vue.d.ts +78 -0
  95. package/dist/runtime/components/DropdownMenu.vue +39 -142
  96. package/dist/runtime/components/DropdownMenu.vue.d.ts +117 -0
  97. package/dist/runtime/components/DropdownMenuContent.vue +78 -88
  98. package/dist/runtime/components/DropdownMenuContent.vue.d.ts +68 -0
  99. package/dist/runtime/components/Form.vue +135 -220
  100. package/dist/runtime/components/Form.vue.d.ts +69 -0
  101. package/dist/runtime/components/FormField.vue +35 -77
  102. package/dist/runtime/components/FormField.vue.d.ts +61 -0
  103. package/dist/runtime/components/Icon.vue +12 -19
  104. package/dist/runtime/components/Icon.vue.d.ts +8 -0
  105. package/dist/runtime/components/Input.vue +82 -140
  106. package/dist/runtime/components/Input.vue.d.ts +76 -0
  107. package/dist/runtime/components/InputMenu.vue +185 -332
  108. package/dist/runtime/components/InputMenu.vue.d.ts +324 -0
  109. package/dist/runtime/components/InputNumber.vue +71 -133
  110. package/dist/runtime/components/InputNumber.vue.d.ts +182 -0
  111. package/dist/runtime/components/Kbd.vue +20 -46
  112. package/dist/runtime/components/Kbd.vue.d.ts +34 -0
  113. package/dist/runtime/components/Link.vue +98 -176
  114. package/dist/runtime/components/Link.vue.d.ts +93 -0
  115. package/dist/runtime/components/LinkBase.vue +33 -42
  116. package/dist/runtime/components/LinkBase.vue.d.ts +25 -0
  117. package/dist/runtime/components/Modal.vue +53 -116
  118. package/dist/runtime/components/Modal.vue.d.ts +93 -0
  119. package/dist/runtime/components/NavigationMenu.vue +77 -209
  120. package/dist/runtime/components/NavigationMenu.vue.d.ts +139 -0
  121. package/dist/runtime/components/OverlayProvider.vue +14 -18
  122. package/dist/runtime/components/OverlayProvider.vue.d.ts +2 -0
  123. package/dist/runtime/components/Pagination.vue +46 -140
  124. package/dist/runtime/components/Pagination.vue.d.ts +119 -0
  125. package/dist/runtime/components/PinInput.vue +61 -78
  126. package/dist/runtime/components/PinInput.vue.d.ts +57 -0
  127. package/dist/runtime/components/Popover.vue +47 -84
  128. package/dist/runtime/components/Popover.vue.d.ts +63 -0
  129. package/dist/runtime/components/Progress.vue +70 -131
  130. package/dist/runtime/components/Progress.vue.d.ts +66 -0
  131. package/dist/runtime/components/RadioGroup.vue +70 -132
  132. package/dist/runtime/components/RadioGroup.vue.d.ts +91 -0
  133. package/dist/runtime/components/Select.vue +110 -224
  134. package/dist/runtime/components/Select.vue.d.ts +145 -0
  135. package/dist/runtime/components/SelectMenu.vue +161 -310
  136. package/dist/runtime/components/SelectMenu.vue.d.ts +196 -0
  137. package/dist/runtime/components/Separator.vue +29 -71
  138. package/dist/runtime/components/Separator.vue.d.ts +54 -0
  139. package/dist/runtime/components/Skeleton.vue +21 -23
  140. package/dist/runtime/components/Skeleton.vue.d.ts +17 -0
  141. package/dist/runtime/components/Slideover.vue +53 -120
  142. package/dist/runtime/components/Slideover.vue.d.ts +94 -0
  143. package/dist/runtime/components/Slider.vue +46 -84
  144. package/dist/runtime/components/Slider.vue.d.ts +52 -0
  145. package/dist/runtime/components/Stepper.vue +45 -115
  146. package/dist/runtime/components/Stepper.vue.d.ts +83 -0
  147. package/dist/runtime/components/Switch.vue +45 -93
  148. package/dist/runtime/components/Switch.vue.d.ts +70 -0
  149. package/dist/runtime/components/Table.vue +163 -267
  150. package/dist/runtime/components/Table.vue.d.ts +183 -0
  151. package/dist/runtime/components/Tabs.vue +41 -107
  152. package/dist/runtime/components/Tabs.vue.d.ts +88 -0
  153. package/dist/runtime/components/Textarea.vue +113 -158
  154. package/dist/runtime/components/Textarea.vue.d.ts +78 -0
  155. package/dist/runtime/components/Toast.vue +49 -110
  156. package/dist/runtime/components/Toast.vue.d.ts +157 -0
  157. package/dist/runtime/components/Toaster.vue +70 -107
  158. package/dist/runtime/components/Toaster.vue.d.ts +38 -0
  159. package/dist/runtime/components/Tooltip.vue +38 -65
  160. package/dist/runtime/components/Tooltip.vue.d.ts +50 -0
  161. package/dist/runtime/components/Tree.vue +59 -166
  162. package/dist/runtime/components/Tree.vue.d.ts +111 -0
  163. package/dist/runtime/composables/defineShortcuts.d.ts +1 -1
  164. package/dist/runtime/composables/defineShortcuts.js +6 -0
  165. package/dist/runtime/composables/useAvatarGroup.d.ts +1 -1
  166. package/dist/runtime/composables/useButtonGroup.d.ts +2 -2
  167. package/dist/runtime/composables/useFormField.d.ts +2 -2
  168. package/dist/runtime/composables/useKbd.d.ts +1 -0
  169. package/dist/runtime/composables/useKbd.js +4 -3
  170. package/dist/runtime/composables/useOverlay.d.ts +14 -8
  171. package/dist/runtime/composables/useOverlay.js +20 -7
  172. package/dist/runtime/composables/usePortal.d.ts +6 -0
  173. package/dist/runtime/composables/usePortal.js +17 -0
  174. package/dist/runtime/index.css +1 -1
  175. package/dist/runtime/inertia/components/Link.vue +146 -0
  176. package/dist/runtime/inertia/components/Link.vue.d.ts +63 -0
  177. package/dist/runtime/inertia/stubs.d.ts +43 -0
  178. package/dist/runtime/inertia/stubs.js +82 -0
  179. package/dist/runtime/locale/bg.d.ts +3 -0
  180. package/dist/runtime/locale/bg.js +54 -0
  181. package/dist/runtime/locale/index.d.ts +5 -1
  182. package/dist/runtime/locale/index.js +5 -1
  183. package/dist/runtime/locale/kk.d.ts +3 -0
  184. package/dist/runtime/locale/kk.js +54 -0
  185. package/dist/runtime/locale/tj.d.ts +3 -0
  186. package/dist/runtime/locale/tj.js +54 -0
  187. package/dist/runtime/locale/ug_cn.d.ts +3 -0
  188. package/dist/runtime/locale/ug_cn.js +55 -0
  189. package/dist/runtime/types/form.d.ts +4 -1
  190. package/dist/runtime/types/index.d.ts +1 -0
  191. package/dist/runtime/types/index.js +1 -0
  192. package/dist/runtime/types/tv.d.ts +53 -0
  193. package/dist/runtime/types/tv.js +0 -0
  194. package/dist/runtime/types/utils.d.ts +7 -17
  195. package/dist/runtime/types/utils.js +1 -0
  196. package/dist/runtime/utils/link.d.ts +3 -3
  197. package/dist/runtime/utils/link.js +1 -0
  198. package/dist/runtime/utils/tv.js +2 -2
  199. package/dist/runtime/vue/components/Icon.vue +7 -8
  200. package/dist/runtime/vue/components/Icon.vue.d.ts +5 -0
  201. package/dist/runtime/vue/components/Link.vue +118 -202
  202. package/dist/runtime/vue/components/Link.vue.d.ts +93 -0
  203. package/dist/runtime/vue/stubs.d.ts +2 -2
  204. package/dist/shared/{ui.BkNUP964.mjs → ui.CbtTMMzt.mjs} +631 -366
  205. package/dist/types.d.mts +3 -5
  206. package/dist/unplugin.d.mts +6 -2
  207. package/dist/unplugin.mjs +25 -4
  208. package/dist/vite.d.mts +1 -1
  209. package/dist/vite.mjs +2 -2
  210. package/package.json +96 -54
  211. package/dist/module.cjs +0 -62
  212. package/dist/module.d.cts +0 -45
  213. package/dist/module.d.ts +0 -45
  214. package/dist/shared/ui.BL-XB3u1.cjs +0 -3555
  215. package/dist/types.d.ts +0 -7
  216. package/dist/unplugin.cjs +0 -232
  217. package/dist/unplugin.d.cts +0 -62
  218. package/dist/unplugin.d.ts +0 -62
  219. package/dist/vite.cjs +0 -23
  220. package/dist/vite.d.cts +0 -15
  221. package/dist/vite.d.ts +0 -15
@@ -1,219 +1,82 @@
1
- <script lang="ts">
2
- import type { VariantProps } from 'tailwind-variants'
3
- import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxContentEmits, ComboboxArrowProps } from 'reka-ui'
4
- import type { AppConfig } from '@nuxt/schema'
5
- import _appConfig from '#build/app.config'
6
- import theme from '#build/ui/select-menu'
7
- import type { UseComponentIconsProps } from '../composables/useComponentIcons'
8
- import { tv } from '../utils/tv'
9
- import type { AvatarProps, ChipProps, InputProps } from '../types'
10
- import type {
11
- AcceptableValue,
12
- ArrayOrNested,
13
- GetItemKeys,
14
- GetItemValue,
15
- GetModelValue,
16
- GetModelValueEmits,
17
- NestedItem,
18
- PartialString,
19
- EmitsToProps
20
- } from '../types/utils'
21
-
22
- const appConfigSelectMenu = _appConfig as AppConfig & { ui: { selectMenu: Partial<typeof theme> } }
23
-
24
- const selectMenu = tv({ extend: tv(theme), ...(appConfigSelectMenu.ui?.selectMenu || {}) })
25
-
26
- interface _SelectMenuItem {
27
- label?: string
28
- /**
29
- * @IconifyIcon
30
- */
31
- icon?: string
32
- avatar?: AvatarProps
33
- chip?: ChipProps
34
- /**
35
- * The item type.
36
- * @defaultValue 'item'
37
- */
38
- type?: 'label' | 'separator' | 'item'
39
- value?: string | number
40
- disabled?: boolean
41
- onSelect?(e?: Event): void
42
- [key: string]: any
43
- }
44
- export type SelectMenuItem = _SelectMenuItem | AcceptableValue | boolean
45
-
46
- type SelectMenuVariants = VariantProps<typeof selectMenu>
47
-
48
- export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = ArrayOrNested<SelectMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'highlightOnHover'>, UseComponentIconsProps {
49
- id?: string
50
- /** The placeholder text when the select is empty. */
51
- placeholder?: string
52
- /**
53
- * Whether to display the search input or not.
54
- * Can be an object to pass additional props to the input.
55
- * `{ placeholder: 'Search...', variant: 'none' }`{lang="ts-type"}
56
- * @defaultValue true
57
- */
58
- searchInput?: boolean | InputProps
59
- /**
60
- * @defaultValue 'primary'
61
- */
62
- color?: SelectMenuVariants['color']
63
- /**
64
- * @defaultValue 'outline'
65
- */
66
- variant?: SelectMenuVariants['variant']
67
- /**
68
- * @defaultValue 'md'
69
- */
70
- size?: SelectMenuVariants['size']
71
- required?: boolean
72
- /**
73
- * The icon displayed to open the menu.
74
- * @defaultValue appConfig.ui.icons.chevronDown
75
- * @IconifyIcon
76
- */
77
- trailingIcon?: string
78
- /**
79
- * The icon displayed when an item is selected.
80
- * @defaultValue appConfig.ui.icons.check
81
- * @IconifyIcon
82
- */
83
- selectedIcon?: string
84
- /**
85
- * The content of the menu.
86
- * @defaultValue { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
87
- */
88
- content?: Omit<ComboboxContentProps, 'as' | 'asChild' | 'forceMount'> & Partial<EmitsToProps<ComboboxContentEmits>>
89
- /**
90
- * Display an arrow alongside the menu.
91
- * @defaultValue false
92
- * @IconifyIcon
93
- */
94
- arrow?: boolean | Omit<ComboboxArrowProps, 'as' | 'asChild'>
95
- /**
96
- * Render the menu in a portal.
97
- * @defaultValue true
98
- */
99
- portal?: boolean
100
- /**
101
- * When `items` is an array of objects, select the field to use as the value instead of the object itself.
102
- * @defaultValue undefined
103
- */
104
- valueKey?: VK
105
- /**
106
- * When `items` is an array of objects, select the field to use as the label.
107
- * @defaultValue 'label'
108
- */
109
- labelKey?: keyof NestedItem<T>
110
- items?: T
111
- /** The value of the SelectMenu when initially rendered. Use when you do not need to control the state of the SelectMenu. */
112
- defaultValue?: GetModelValue<T, VK, M>
113
- /** The controlled value of the SelectMenu. Can be binded-with with `v-model`. */
114
- modelValue?: GetModelValue<T, VK, M>
115
- /** Whether multiple options can be selected or not. */
116
- multiple?: M & boolean
117
- /** Highlight the ring color like a focus state. */
118
- highlight?: boolean
119
- /**
120
- * Determines if custom user input that does not exist in options can be added.
121
- * @defaultValue false
122
- */
123
- createItem?: boolean | 'always' | { position?: 'top' | 'bottom', when?: 'empty' | 'always' }
124
- /**
125
- * Fields to filter items by.
126
- * @defaultValue [labelKey]
127
- */
128
- filterFields?: string[]
129
- /**
130
- * When `true`, disable the default filters, useful for custom filtering (useAsyncData, useFetch, etc.).
131
- * @defaultValue false
132
- */
133
- ignoreFilter?: boolean
134
- class?: any
135
- ui?: PartialString<typeof selectMenu.slots>
136
- }
137
-
138
- export type SelectMenuEmits<A extends ArrayOrNested<SelectMenuItem>, VK extends GetItemKeys<A> | undefined, M extends boolean> = Pick<ComboboxRootEmits, 'update:open'> & {
139
- change: [payload: Event]
140
- blur: [payload: FocusEvent]
141
- focus: [payload: FocusEvent]
142
- create: [item: string]
143
- /** Event handler when highlighted element changes. */
144
- highlight: [payload: {
145
- ref: HTMLElement
146
- value: GetModelValue<A, VK, M>
147
- } | undefined]
148
- } & GetModelValueEmits<A, VK, M>
149
-
150
- type SlotProps<T extends SelectMenuItem> = (props: { item: T, index: number }) => any
151
-
152
- export interface SelectMenuSlots<
153
- A extends ArrayOrNested<SelectMenuItem> = ArrayOrNested<SelectMenuItem>,
154
- VK extends GetItemKeys<A> | undefined = undefined,
155
- M extends boolean = false,
156
- T extends NestedItem<A> = NestedItem<A>
157
- > {
158
- 'leading'(props: { modelValue?: GetModelValue<A, VK, M>, open: boolean, ui: ReturnType<typeof selectMenu> }): any
159
- 'default'(props: { modelValue?: GetModelValue<A, VK, M>, open: boolean }): any
160
- 'trailing'(props: { modelValue?: GetModelValue<A, VK, M>, open: boolean, ui: ReturnType<typeof selectMenu> }): any
161
- 'empty'(props: { searchTerm?: string }): any
162
- 'item': SlotProps<T>
163
- 'item-leading': SlotProps<T>
164
- 'item-label': SlotProps<T>
165
- 'item-trailing': SlotProps<T>
166
- 'create-item-label'(props: { item: string }): any
167
- }
1
+ <script>
2
+ import theme from "#build/ui/select-menu";
168
3
  </script>
169
4
 
170
- <script setup lang="ts" generic="T extends ArrayOrNested<SelectMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false">
171
- import { computed, toRef, toRaw } from 'vue'
172
- import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, FocusScope, useForwardPropsEmits, useFilter } from 'reka-ui'
173
- import { defu } from 'defu'
174
- import { reactivePick, createReusableTemplate } from '@vueuse/core'
175
- import { useAppConfig } from '#imports'
176
- import { useButtonGroup } from '../composables/useButtonGroup'
177
- import { useComponentIcons } from '../composables/useComponentIcons'
178
- import { useFormField } from '../composables/useFormField'
179
- import { useLocale } from '../composables/useLocale'
180
- import { compare, get, isArrayOfArray } from '../utils'
181
- import UIcon from './Icon.vue'
182
- import UAvatar from './Avatar.vue'
183
- import UChip from './Chip.vue'
184
- import UInput from './Input.vue'
185
-
186
- defineOptions({ inheritAttrs: false })
187
-
188
- const props = withDefaults(defineProps<SelectMenuProps<T, VK, M>>(), {
189
- portal: true,
190
- searchInput: true,
191
- labelKey: 'label' as never,
192
- resetSearchTermOnBlur: true
193
- })
194
- const emits = defineEmits<SelectMenuEmits<T, VK, M>>()
195
- const slots = defineSlots<SelectMenuSlots<T, VK, M>>()
196
-
197
- const searchTerm = defineModel<string>('searchTerm', { default: '' })
198
-
199
- const { t } = useLocale()
200
- const appConfig = useAppConfig()
201
- const { contains } = useFilter({ sensitivity: 'base' })
202
-
203
- const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'required', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover'), emits)
204
- const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
205
- const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
206
- const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t('selectMenu.search'), variant: 'none' }) as InputProps)
207
-
208
- const { emitFormBlur, emitFormFocus, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
209
- const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
210
- const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
211
-
212
- const selectSize = computed(() => buttonGroupSize.value || formGroupSize.value)
213
-
214
- const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate()
215
-
216
- const ui = computed(() => selectMenu({
5
+ <script setup>
6
+ import { computed, toRef, toRaw } from "vue";
7
+ import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, FocusScope, useForwardPropsEmits, useFilter } from "reka-ui";
8
+ import { defu } from "defu";
9
+ import { reactivePick, createReusableTemplate } from "@vueuse/core";
10
+ import { useAppConfig } from "#imports";
11
+ import { useButtonGroup } from "../composables/useButtonGroup";
12
+ import { useComponentIcons } from "../composables/useComponentIcons";
13
+ import { useFormField } from "../composables/useFormField";
14
+ import { useLocale } from "../composables/useLocale";
15
+ import { usePortal } from "../composables/usePortal";
16
+ import { compare, get, isArrayOfArray } from "../utils";
17
+ import { tv } from "../utils/tv";
18
+ import UIcon from "./Icon.vue";
19
+ import UAvatar from "./Avatar.vue";
20
+ import UChip from "./Chip.vue";
21
+ import UInput from "./Input.vue";
22
+ defineOptions({ inheritAttrs: false });
23
+ const props = defineProps({
24
+ id: { type: String, required: false },
25
+ placeholder: { type: String, required: false },
26
+ searchInput: { type: [Boolean, Object], required: false, default: true },
27
+ color: { type: null, required: false },
28
+ variant: { type: null, required: false },
29
+ size: { type: null, required: false },
30
+ required: { type: Boolean, required: false },
31
+ trailingIcon: { type: String, required: false },
32
+ selectedIcon: { type: String, required: false },
33
+ content: { type: Object, required: false },
34
+ arrow: { type: [Boolean, Object], required: false },
35
+ portal: { type: [Boolean, String], required: false, skipCheck: true, default: true },
36
+ valueKey: { type: null, required: false },
37
+ labelKey: { type: null, required: false, default: "label" },
38
+ items: { type: null, required: false },
39
+ defaultValue: { type: null, required: false },
40
+ modelValue: { type: null, required: false },
41
+ multiple: { type: Boolean, required: false },
42
+ highlight: { type: Boolean, required: false },
43
+ createItem: { type: [Boolean, String, Object], required: false },
44
+ filterFields: { type: Array, required: false },
45
+ ignoreFilter: { type: Boolean, required: false },
46
+ class: { type: null, required: false },
47
+ ui: { type: null, required: false },
48
+ open: { type: Boolean, required: false },
49
+ defaultOpen: { type: Boolean, required: false },
50
+ disabled: { type: Boolean, required: false },
51
+ name: { type: String, required: false },
52
+ resetSearchTermOnBlur: { type: Boolean, required: false, default: true },
53
+ resetSearchTermOnSelect: { type: Boolean, required: false, default: true },
54
+ highlightOnHover: { type: Boolean, required: false },
55
+ icon: { type: String, required: false },
56
+ avatar: { type: Object, required: false },
57
+ leading: { type: Boolean, required: false },
58
+ leadingIcon: { type: String, required: false },
59
+ trailing: { type: Boolean, required: false },
60
+ loading: { type: Boolean, required: false },
61
+ loadingIcon: { type: String, required: false }
62
+ });
63
+ const emits = defineEmits(["update:open", "change", "blur", "focus", "create", "highlight", "update:modelValue"]);
64
+ const slots = defineSlots();
65
+ const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" } });
66
+ const { t } = useLocale();
67
+ const appConfig = useAppConfig();
68
+ const { contains } = useFilter({ sensitivity: "base" });
69
+ const rootProps = useForwardPropsEmits(reactivePick(props, "modelValue", "defaultValue", "open", "defaultOpen", "required", "multiple", "resetSearchTermOnBlur", "resetSearchTermOnSelect", "highlightOnHover"), emits);
70
+ const portalProps = usePortal(toRef(() => props.portal));
71
+ const contentProps = toRef(() => defu(props.content, { side: "bottom", sideOffset: 8, collisionPadding: 8, position: "popper" }));
72
+ const arrowProps = toRef(() => props.arrow);
73
+ const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t("selectMenu.search"), variant: "none" }));
74
+ const { emitFormBlur, emitFormFocus, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField(props);
75
+ const { orientation, size: buttonGroupSize } = useButtonGroup(props);
76
+ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })));
77
+ const selectSize = computed(() => buttonGroupSize.value || formGroupSize.value);
78
+ const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate();
79
+ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.selectMenu || {} })({
217
80
  color: color.value,
218
81
  variant: props.variant,
219
82
  size: selectSize?.value,
@@ -222,112 +85,96 @@ const ui = computed(() => selectMenu({
222
85
  leading: isLeading.value || !!props.avatar || !!slots.leading,
223
86
  trailing: isTrailing.value || !!slots.trailing,
224
87
  buttonGroup: orientation.value
225
- }))
226
-
227
- function displayValue(value: GetItemValue<T, VK> | GetItemValue<T, VK>[]): string {
88
+ }));
89
+ function displayValue(value) {
228
90
  if (props.multiple && Array.isArray(value)) {
229
- return value.map(v => displayValue(v)).filter(Boolean).join(', ')
91
+ return value.map((v) => displayValue(v)).filter(Boolean).join(", ");
230
92
  }
231
-
232
93
  if (!props.valueKey) {
233
- return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
94
+ return value && (typeof value === "object" ? get(value, props.labelKey) : value);
234
95
  }
235
-
236
- const item = items.value.find(item => compare(typeof item === 'object' ? get(item as Record<string, any>, props.valueKey as string) : item, value))
237
- return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
96
+ const item = items.value.find((item2) => compare(typeof item2 === "object" ? get(item2, props.valueKey) : item2, value));
97
+ return item && (typeof item === "object" ? get(item, props.labelKey) : item);
238
98
  }
239
-
240
- const groups = computed<SelectMenuItem[][]>(() =>
241
- props.items?.length
242
- ? isArrayOfArray(props.items)
243
- ? props.items
244
- : [props.items]
245
- : []
246
- )
247
- // eslint-disable-next-line vue/no-dupe-keys
248
- const items = computed(() => groups.value.flatMap(group => group) as T[])
249
-
99
+ const groups = computed(
100
+ () => props.items?.length ? isArrayOfArray(props.items) ? props.items : [props.items] : []
101
+ );
102
+ const items = computed(() => groups.value.flatMap((group) => group));
250
103
  const filteredGroups = computed(() => {
251
104
  if (props.ignoreFilter || !searchTerm.value) {
252
- return groups.value
105
+ return groups.value;
253
106
  }
254
-
255
- const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey] as string[]
256
-
257
- return groups.value.map(items => items.filter((item) => {
258
- if (typeof item !== 'object' || item === null) {
259
- return contains(String(item), searchTerm.value)
107
+ const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey];
108
+ return groups.value.map((items2) => items2.filter((item) => {
109
+ if (typeof item !== "object" || item === null) {
110
+ return contains(String(item), searchTerm.value);
260
111
  }
261
-
262
- if (item.type && ['label', 'separator'].includes(item.type)) {
263
- return true
112
+ if (item.type && ["label", "separator"].includes(item.type)) {
113
+ return true;
264
114
  }
265
-
266
- return fields.some(field => contains(get(item, field), searchTerm.value))
267
- })).filter(group => group.filter(item =>
268
- !isSelectItem(item) || (!item.type || !['label', 'separator'].includes(item.type))
269
- ).length > 0)
270
- })
271
- const filteredItems = computed(() => filteredGroups.value.flatMap(group => group))
272
-
115
+ return fields.some((field) => contains(get(item, field), searchTerm.value));
116
+ })).filter((group) => group.filter(
117
+ (item) => !isSelectItem(item) || (!item.type || !["label", "separator"].includes(item.type))
118
+ ).length > 0);
119
+ });
120
+ const filteredItems = computed(() => filteredGroups.value.flatMap((group) => group));
273
121
  const createItem = computed(() => {
274
122
  if (!props.createItem || !searchTerm.value) {
275
- return false
123
+ return false;
276
124
  }
277
-
278
- const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } as NestedItem<T> : searchTerm.value
279
-
280
- if ((typeof props.createItem === 'object' && props.createItem.when === 'always') || props.createItem === 'always') {
281
- return !filteredItems.value.find(item => compare(item, newItem, String(props.valueKey)))
125
+ const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } : searchTerm.value;
126
+ if (typeof props.createItem === "object" && props.createItem.when === "always" || props.createItem === "always") {
127
+ return !filteredItems.value.find((item) => compare(item, newItem, props.valueKey));
282
128
  }
283
-
284
- return !filteredItems.value.length
285
- })
286
- const createItemPosition = computed(() => typeof props.createItem === 'object' ? props.createItem.position : 'bottom')
287
-
288
- function onUpdate(value: any) {
129
+ return !filteredItems.value.length;
130
+ });
131
+ const createItemPosition = computed(() => typeof props.createItem === "object" ? props.createItem.position : "bottom");
132
+ function onUpdate(value) {
289
133
  if (toRaw(props.modelValue) === value) {
290
- return
134
+ return;
135
+ }
136
+ const event = new Event("change", { target: { value } });
137
+ emits("change", event);
138
+ emitFormChange();
139
+ emitFormInput();
140
+ if (props.resetSearchTermOnSelect) {
141
+ searchTerm.value = "";
291
142
  }
292
- // @ts-expect-error - 'target' does not exist in type 'EventInit'
293
- const event = new Event('change', { target: { value } })
294
- emits('change', event)
295
- emitFormChange()
296
- emitFormInput()
297
143
  }
298
-
299
- function onUpdateOpen(value: boolean) {
300
- let timeoutId
301
-
144
+ function onUpdateOpen(value) {
145
+ let timeoutId;
302
146
  if (!value) {
303
- const event = new FocusEvent('blur')
304
-
305
- emits('blur', event)
306
- emitFormBlur()
307
-
308
- // Since we use `displayValue` prop inside ComboboxInput we should reset searchTerm manually
309
- // https://reka-ui.com/docs/components/combobox#api-reference
147
+ const event = new FocusEvent("blur");
148
+ emits("blur", event);
149
+ emitFormBlur();
310
150
  if (props.resetSearchTermOnBlur) {
311
- const STATE_ANIMATION_DELAY_MS = 100
312
-
151
+ const STATE_ANIMATION_DELAY_MS = 100;
313
152
  timeoutId = setTimeout(() => {
314
- searchTerm.value = ''
315
- }, STATE_ANIMATION_DELAY_MS)
153
+ searchTerm.value = "";
154
+ }, STATE_ANIMATION_DELAY_MS);
316
155
  }
317
156
  } else {
318
- const event = new FocusEvent('focus')
319
- emits('focus', event)
320
- emitFormFocus()
321
- clearTimeout(timeoutId)
157
+ const event = new FocusEvent("focus");
158
+ emits("focus", event);
159
+ emitFormFocus();
160
+ clearTimeout(timeoutId);
322
161
  }
323
162
  }
324
-
325
- function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
326
- return typeof item === 'object' && item !== null
163
+ function onSelect(e, item) {
164
+ if (!isSelectItem(item)) {
165
+ return;
166
+ }
167
+ if (item.disabled) {
168
+ e.preventDefault();
169
+ return;
170
+ }
171
+ item.onSelect?.(e);
172
+ }
173
+ function isSelectItem(item) {
174
+ return typeof item === "object" && item !== null;
327
175
  }
328
176
  </script>
329
177
 
330
- <!-- eslint-disable vue/no-template-shadow -->
331
178
  <template>
332
179
  <DefineCreateItemTemplate>
333
180
  <ComboboxGroup :class="ui.group({ class: props.ui?.group })">
@@ -359,34 +206,36 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
359
206
  <ComboboxAnchor as-child>
360
207
  <ComboboxTrigger :class="ui.base({ class: [props.class, props.ui?.base] })" tabindex="0">
361
208
  <span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
362
- <slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
209
+ <slot name="leading" :model-value="modelValue" :open="open" :ui="ui">
363
210
  <UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
364
- <UAvatar v-else-if="!!avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
211
+ <UAvatar v-else-if="!!avatar" :size="props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()" v-bind="avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
365
212
  </slot>
366
213
  </span>
367
214
 
368
- <slot :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open">
369
- <template v-for="displayedModelValue in [displayValue(modelValue as GetModelValue<T, VK, M>)]" :key="displayedModelValue">
215
+ <slot :model-value="modelValue" :open="open">
216
+ <template v-for="displayedModelValue in [displayValue(modelValue)]" :key="displayedModelValue">
370
217
  <span v-if="displayedModelValue" :class="ui.value({ class: props.ui?.value })">
371
218
  {{ displayedModelValue }}
372
219
  </span>
373
220
  <span v-else :class="ui.placeholder({ class: props.ui?.placeholder })">
374
- {{ placeholder ?? '&nbsp;' }}
221
+ {{ placeholder ?? '\xA0' }}
375
222
  </span>
376
223
  </template>
377
224
  </slot>
378
225
 
379
226
  <span v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
380
- <slot name="trailing" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
227
+ <slot name="trailing" :model-value="modelValue" :open="open" :ui="ui">
381
228
  <UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
382
229
  </slot>
383
230
  </span>
384
231
  </ComboboxTrigger>
385
232
  </ComboboxAnchor>
386
233
 
387
- <ComboboxPortal :disabled="!portal">
234
+ <ComboboxPortal v-bind="portalProps">
388
235
  <ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
389
236
  <FocusScope trapped :class="ui.focusScope({ class: props.ui?.focusScope })">
237
+ <slot name="content-top" />
238
+
390
239
  <ComboboxInput v-if="!!searchInput" v-model="searchTerm" :display-value="() => searchTerm" as-child>
391
240
  <UInput autofocus autocomplete="off" v-bind="searchInputProps" :class="ui.input({ class: props.ui?.input })" />
392
241
  </ComboboxInput>
@@ -403,7 +252,7 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
403
252
  <ComboboxGroup v-for="(group, groupIndex) in filteredGroups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
404
253
  <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
405
254
  <ComboboxLabel v-if="isSelectItem(item) && item.type === 'label'" :class="ui.label({ class: props.ui?.label })">
406
- {{ get(item, props.labelKey as string) }}
255
+ {{ get(item, props.labelKey) }}
407
256
  </ComboboxLabel>
408
257
 
409
258
  <ComboboxSeparator v-else-if="isSelectItem(item) && item.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
@@ -412,16 +261,16 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
412
261
  v-else
413
262
  :class="ui.item({ class: props.ui?.item })"
414
263
  :disabled="isSelectItem(item) && item.disabled"
415
- :value="props.valueKey && isSelectItem(item) ? get(item, props.valueKey as string) : item"
416
- @select="isSelectItem(item) && item.onSelect"
264
+ :value="props.valueKey && isSelectItem(item) ? get(item, props.valueKey) : item"
265
+ @select="onSelect($event, item)"
417
266
  >
418
- <slot name="item" :item="(item as NestedItem<T>)" :index="index">
419
- <slot name="item-leading" :item="(item as NestedItem<T>)" :index="index">
267
+ <slot name="item" :item="item" :index="index">
268
+ <slot name="item-leading" :item="item" :index="index">
420
269
  <UIcon v-if="isSelectItem(item) && item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
421
- <UAvatar v-else-if="isSelectItem(item) && item.avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
270
+ <UAvatar v-else-if="isSelectItem(item) && item.avatar" :size="props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
422
271
  <UChip
423
272
  v-else-if="isSelectItem(item) && item.chip"
424
- :size="((props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()) as ChipProps['size'])"
273
+ :size="props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()"
425
274
  inset
426
275
  standalone
427
276
  v-bind="item.chip"
@@ -430,13 +279,13 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
430
279
  </slot>
431
280
 
432
281
  <span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
433
- <slot name="item-label" :item="(item as NestedItem<T>)" :index="index">
434
- {{ isSelectItem(item) ? get(item, props.labelKey as string) : item }}
282
+ <slot name="item-label" :item="item" :index="index">
283
+ {{ isSelectItem(item) ? get(item, props.labelKey) : item }}
435
284
  </slot>
436
285
  </span>
437
286
 
438
287
  <span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
439
- <slot name="item-trailing" :item="(item as NestedItem<T>)" :index="index" />
288
+ <slot name="item-trailing" :item="item" :index="index" />
440
289
 
441
290
  <ComboboxItemIndicator as-child>
442
291
  <UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
@@ -449,6 +298,8 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
449
298
 
450
299
  <ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'bottom'" />
451
300
  </ComboboxViewport>
301
+
302
+ <slot name="content-bottom" />
452
303
  </FocusScope>
453
304
 
454
305
  <ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />