@nuxt/ui 3.0.2 → 3.1.0

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 (220) hide show
  1. package/.nuxt/ui/accordion.ts +25 -4
  2. package/.nuxt/ui/alert.ts +52 -31
  3. package/.nuxt/ui/avatar-group.ts +24 -3
  4. package/.nuxt/ui/avatar.ts +26 -5
  5. package/.nuxt/ui/badge.ts +56 -35
  6. package/.nuxt/ui/breadcrumb.ts +28 -7
  7. package/.nuxt/ui/button-group.ts +23 -2
  8. package/.nuxt/ui/button.ts +66 -45
  9. package/.nuxt/ui/calendar.ts +39 -18
  10. package/.nuxt/ui/card.ts +28 -7
  11. package/.nuxt/ui/carousel.ts +29 -8
  12. package/.nuxt/ui/checkbox-group.ts +82 -0
  13. package/.nuxt/ui/checkbox.ts +163 -29
  14. package/.nuxt/ui/chip.ts +31 -10
  15. package/.nuxt/ui/collapsible.ts +23 -2
  16. package/.nuxt/ui/color-picker.ts +26 -5
  17. package/.nuxt/ui/command-palette.ts +37 -16
  18. package/.nuxt/ui/container.ts +23 -2
  19. package/.nuxt/ui/context-menu.ts +56 -35
  20. package/.nuxt/ui/drawer.ts +33 -12
  21. package/.nuxt/ui/dropdown-menu.ts +57 -36
  22. package/.nuxt/ui/form-field.ts +29 -8
  23. package/.nuxt/ui/form.ts +23 -2
  24. package/.nuxt/ui/index.ts +1 -0
  25. package/.nuxt/ui/input-menu.ts +65 -44
  26. package/.nuxt/ui/input-number.ts +43 -22
  27. package/.nuxt/ui/input.ts +46 -25
  28. package/.nuxt/ui/kbd.ts +27 -6
  29. package/.nuxt/ui/link.ts +26 -5
  30. package/.nuxt/ui/modal.ts +28 -7
  31. package/.nuxt/ui/navigation-menu.ts +102 -83
  32. package/.nuxt/ui/pagination.ts +23 -2
  33. package/.nuxt/ui/pin-input.ts +43 -22
  34. package/.nuxt/ui/popover.ts +25 -4
  35. package/.nuxt/ui/progress.ts +40 -19
  36. package/.nuxt/ui/radio-group.ts +273 -37
  37. package/.nuxt/ui/select-menu.ts +59 -35
  38. package/.nuxt/ui/select.ts +55 -34
  39. package/.nuxt/ui/separator.ts +31 -10
  40. package/.nuxt/ui/skeleton.ts +24 -3
  41. package/.nuxt/ui/slideover.ts +27 -6
  42. package/.nuxt/ui/slider.ts +39 -18
  43. package/.nuxt/ui/stepper.ts +41 -20
  44. package/.nuxt/ui/switch.ts +43 -22
  45. package/.nuxt/ui/table.ts +38 -17
  46. package/.nuxt/ui/tabs.ts +55 -34
  47. package/.nuxt/ui/textarea.ts +63 -37
  48. package/.nuxt/ui/toast.ts +47 -26
  49. package/.nuxt/ui/toaster.ts +23 -2
  50. package/.nuxt/ui/tooltip.ts +25 -4
  51. package/.nuxt/ui/tree.ts +41 -20
  52. package/.nuxt/ui.css +56 -12
  53. package/README.md +11 -0
  54. package/cli/templates.mjs +18 -17
  55. package/dist/module.json +5 -5
  56. package/dist/module.mjs +11 -7
  57. package/dist/runtime/components/Accordion.vue +36 -93
  58. package/dist/runtime/components/Accordion.vue.d.ts +91 -0
  59. package/dist/runtime/components/Alert.vue +37 -100
  60. package/dist/runtime/components/Alert.vue.d.ts +96 -0
  61. package/dist/runtime/components/App.vue +28 -34
  62. package/dist/runtime/components/App.vue.d.ts +24 -0
  63. package/dist/runtime/components/Avatar.vue +42 -75
  64. package/dist/runtime/components/Avatar.vue.d.ts +60 -0
  65. package/dist/runtime/components/AvatarGroup.vue +40 -77
  66. package/dist/runtime/components/AvatarGroup.vue.d.ts +40 -0
  67. package/dist/runtime/components/Badge.vue +33 -62
  68. package/dist/runtime/components/Badge.vue.d.ts +62 -0
  69. package/dist/runtime/components/Breadcrumb.vue +37 -90
  70. package/dist/runtime/components/Breadcrumb.vue.d.ts +82 -0
  71. package/dist/runtime/components/Button.vue +95 -104
  72. package/dist/runtime/components/Button.vue.d.ts +73 -0
  73. package/dist/runtime/components/ButtonGroup.vue +20 -46
  74. package/dist/runtime/components/ButtonGroup.vue.d.ts +55 -0
  75. package/dist/runtime/components/Calendar.vue +67 -150
  76. package/dist/runtime/components/Calendar.vue.d.ts +107 -0
  77. package/dist/runtime/components/Card.vue +18 -40
  78. package/dist/runtime/components/Card.vue.d.ts +38 -0
  79. package/dist/runtime/components/Carousel.vue +112 -234
  80. package/dist/runtime/components/Carousel.vue.d.ts +120 -0
  81. package/dist/runtime/components/Checkbox.vue +52 -93
  82. package/dist/runtime/components/Checkbox.vue.d.ts +76 -0
  83. package/dist/runtime/components/CheckboxGroup.vue +121 -0
  84. package/dist/runtime/components/CheckboxGroup.vue.d.ts +75 -0
  85. package/dist/runtime/components/Chip.vue +26 -69
  86. package/dist/runtime/components/Chip.vue.d.ts +71 -0
  87. package/dist/runtime/components/Collapsible.vue +22 -41
  88. package/dist/runtime/components/Collapsible.vue.d.ts +50 -0
  89. package/dist/runtime/components/ColorPicker.vue +111 -197
  90. package/dist/runtime/components/ColorPicker.vue.d.ts +63 -0
  91. package/dist/runtime/components/CommandPalette.vue +96 -237
  92. package/dist/runtime/components/CommandPalette.vue.d.ts +173 -0
  93. package/dist/runtime/components/Container.vue +15 -28
  94. package/dist/runtime/components/Container.vue.d.ts +27 -0
  95. package/dist/runtime/components/ContextMenu.vue +34 -133
  96. package/dist/runtime/components/ContextMenu.vue.d.ts +127 -0
  97. package/dist/runtime/components/ContextMenuContent.vue +73 -81
  98. package/dist/runtime/components/ContextMenuContent.vue.d.ts +105 -0
  99. package/dist/runtime/components/Drawer.vue +49 -83
  100. package/dist/runtime/components/Drawer.vue.d.ts +88 -0
  101. package/dist/runtime/components/DropdownMenu.vue +39 -142
  102. package/dist/runtime/components/DropdownMenu.vue.d.ts +141 -0
  103. package/dist/runtime/components/DropdownMenuContent.vue +78 -88
  104. package/dist/runtime/components/DropdownMenuContent.vue.d.ts +55 -0
  105. package/dist/runtime/components/Form.vue +135 -220
  106. package/dist/runtime/components/Form.vue.d.ts +66 -0
  107. package/dist/runtime/components/FormField.vue +35 -77
  108. package/dist/runtime/components/FormField.vue.d.ts +70 -0
  109. package/dist/runtime/components/Icon.vue +12 -19
  110. package/dist/runtime/components/Icon.vue.d.ts +17 -0
  111. package/dist/runtime/components/Input.vue +82 -140
  112. package/dist/runtime/components/Input.vue.d.ts +91 -0
  113. package/dist/runtime/components/InputMenu.vue +185 -332
  114. package/dist/runtime/components/InputMenu.vue.d.ts +312 -0
  115. package/dist/runtime/components/InputNumber.vue +71 -133
  116. package/dist/runtime/components/InputNumber.vue.d.ts +193 -0
  117. package/dist/runtime/components/Kbd.vue +20 -46
  118. package/dist/runtime/components/Kbd.vue.d.ts +55 -0
  119. package/dist/runtime/components/Link.vue +98 -176
  120. package/dist/runtime/components/Link.vue.d.ts +124 -0
  121. package/dist/runtime/components/LinkBase.vue +33 -42
  122. package/dist/runtime/components/LinkBase.vue.d.ts +48 -0
  123. package/dist/runtime/components/Modal.vue +53 -116
  124. package/dist/runtime/components/Modal.vue.d.ts +109 -0
  125. package/dist/runtime/components/NavigationMenu.vue +77 -209
  126. package/dist/runtime/components/NavigationMenu.vue.d.ts +159 -0
  127. package/dist/runtime/components/OverlayProvider.vue +14 -18
  128. package/dist/runtime/components/OverlayProvider.vue.d.ts +2 -0
  129. package/dist/runtime/components/Pagination.vue +46 -140
  130. package/dist/runtime/components/Pagination.vue.d.ts +143 -0
  131. package/dist/runtime/components/PinInput.vue +61 -78
  132. package/dist/runtime/components/PinInput.vue.d.ts +68 -0
  133. package/dist/runtime/components/Popover.vue +47 -84
  134. package/dist/runtime/components/Popover.vue.d.ts +80 -0
  135. package/dist/runtime/components/Progress.vue +70 -131
  136. package/dist/runtime/components/Progress.vue.d.ts +97 -0
  137. package/dist/runtime/components/RadioGroup.vue +70 -132
  138. package/dist/runtime/components/RadioGroup.vue.d.ts +88 -0
  139. package/dist/runtime/components/Select.vue +110 -224
  140. package/dist/runtime/components/Select.vue.d.ts +139 -0
  141. package/dist/runtime/components/SelectMenu.vue +161 -310
  142. package/dist/runtime/components/SelectMenu.vue.d.ts +184 -0
  143. package/dist/runtime/components/Separator.vue +29 -71
  144. package/dist/runtime/components/Separator.vue.d.ts +75 -0
  145. package/dist/runtime/components/Skeleton.vue +21 -23
  146. package/dist/runtime/components/Skeleton.vue.d.ts +26 -0
  147. package/dist/runtime/components/Slideover.vue +53 -120
  148. package/dist/runtime/components/Slideover.vue.d.ts +111 -0
  149. package/dist/runtime/components/Slider.vue +46 -84
  150. package/dist/runtime/components/Slider.vue.d.ts +71 -0
  151. package/dist/runtime/components/Stepper.vue +45 -115
  152. package/dist/runtime/components/Stepper.vue.d.ts +89 -0
  153. package/dist/runtime/components/Switch.vue +45 -93
  154. package/dist/runtime/components/Switch.vue.d.ts +73 -0
  155. package/dist/runtime/components/Table.vue +163 -267
  156. package/dist/runtime/components/Table.vue.d.ts +183 -0
  157. package/dist/runtime/components/Tabs.vue +41 -107
  158. package/dist/runtime/components/Tabs.vue.d.ts +104 -0
  159. package/dist/runtime/components/Textarea.vue +113 -158
  160. package/dist/runtime/components/Textarea.vue.d.ts +95 -0
  161. package/dist/runtime/components/Toast.vue +49 -110
  162. package/dist/runtime/components/Toast.vue.d.ts +95 -0
  163. package/dist/runtime/components/Toaster.vue +70 -107
  164. package/dist/runtime/components/Toaster.vue.d.ts +63 -0
  165. package/dist/runtime/components/Tooltip.vue +38 -65
  166. package/dist/runtime/components/Tooltip.vue.d.ts +65 -0
  167. package/dist/runtime/components/Tree.vue +59 -166
  168. package/dist/runtime/components/Tree.vue.d.ts +128 -0
  169. package/dist/runtime/composables/defineShortcuts.d.ts +1 -1
  170. package/dist/runtime/composables/useAvatarGroup.d.ts +1 -1
  171. package/dist/runtime/composables/useButtonGroup.d.ts +2 -2
  172. package/dist/runtime/composables/useFormField.d.ts +2 -2
  173. package/dist/runtime/composables/useOverlay.d.ts +14 -7
  174. package/dist/runtime/composables/useOverlay.js +14 -6
  175. package/dist/runtime/composables/usePortal.d.ts +6 -0
  176. package/dist/runtime/composables/usePortal.js +17 -0
  177. package/dist/runtime/index.css +1 -1
  178. package/dist/runtime/inertia/components/Link.vue +146 -0
  179. package/dist/runtime/inertia/components/Link.vue.d.ts +92 -0
  180. package/dist/runtime/inertia/stubs.d.ts +43 -0
  181. package/dist/runtime/inertia/stubs.js +82 -0
  182. package/dist/runtime/locale/bg.d.ts +3 -0
  183. package/dist/runtime/locale/bg.js +54 -0
  184. package/dist/runtime/locale/index.d.ts +5 -1
  185. package/dist/runtime/locale/index.js +5 -1
  186. package/dist/runtime/locale/kk.d.ts +3 -0
  187. package/dist/runtime/locale/kk.js +54 -0
  188. package/dist/runtime/locale/tj.d.ts +3 -0
  189. package/dist/runtime/locale/tj.js +54 -0
  190. package/dist/runtime/locale/ug_cn.d.ts +3 -0
  191. package/dist/runtime/locale/ug_cn.js +55 -0
  192. package/dist/runtime/types/form.d.ts +4 -1
  193. package/dist/runtime/types/index.d.ts +1 -0
  194. package/dist/runtime/types/index.js +1 -0
  195. package/dist/runtime/types/utils.d.ts +47 -7
  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 +14 -0
  201. package/dist/runtime/vue/components/Link.vue +118 -202
  202. package/dist/runtime/vue/components/Link.vue.d.ts +124 -0
  203. package/dist/runtime/vue/stubs.d.ts +2 -2
  204. package/dist/shared/{ui.BkNUP964.mjs → ui.D7lOOabO.mjs} +621 -362
  205. package/dist/types.d.mts +3 -5
  206. package/dist/unplugin.d.mts +4 -0
  207. package/dist/unplugin.mjs +25 -4
  208. package/dist/vite.mjs +1 -1
  209. package/package.json +94 -53
  210. package/dist/module.cjs +0 -62
  211. package/dist/module.d.cts +0 -45
  212. package/dist/module.d.ts +0 -45
  213. package/dist/shared/ui.BL-XB3u1.cjs +0 -3555
  214. package/dist/types.d.ts +0 -7
  215. package/dist/unplugin.cjs +0 -232
  216. package/dist/unplugin.d.cts +0 -62
  217. package/dist/unplugin.d.ts +0 -62
  218. package/dist/vite.cjs +0 -23
  219. package/dist/vite.d.cts +0 -15
  220. package/dist/vite.d.ts +0 -15
@@ -1,226 +1,85 @@
1
- <script lang="ts">
2
- import type { InputHTMLAttributes } from 'vue'
3
- import type { VariantProps } from 'tailwind-variants'
4
- import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxContentEmits, ComboboxArrowProps } from 'reka-ui'
5
- import type { AppConfig } from '@nuxt/schema'
6
- import _appConfig from '#build/app.config'
7
- import theme from '#build/ui/input-menu'
8
- import type { UseComponentIconsProps } from '../composables/useComponentIcons'
9
- import { tv } from '../utils/tv'
10
- import type { AvatarProps, ChipProps, InputProps } from '../types'
11
- import type {
12
- AcceptableValue,
13
- ArrayOrNested,
14
- GetItemKeys,
15
- GetModelValue,
16
- GetModelValueEmits,
17
- NestedItem,
18
- PartialString,
19
- EmitsToProps
20
- } from '../types/utils'
21
-
22
- const appConfigInputMenu = _appConfig as AppConfig & { ui: { inputMenu: Partial<typeof theme> } }
23
-
24
- const inputMenu = tv({ extend: tv(theme), ...(appConfigInputMenu.ui?.inputMenu || {}) })
25
-
26
- interface _InputMenuItem {
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 InputMenuItem = _InputMenuItem | AcceptableValue | boolean
45
-
46
- type InputMenuVariants = VariantProps<typeof inputMenu>
47
-
48
- export interface InputMenuProps<T extends ArrayOrNested<InputMenuItem> = ArrayOrNested<InputMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'highlightOnHover'>, UseComponentIconsProps {
49
- /**
50
- * The element or component this component should render as.
51
- * @defaultValue 'div'
52
- */
53
- as?: any
54
- id?: string
55
- type?: InputHTMLAttributes['type']
56
- /** The placeholder text when the input is empty. */
57
- placeholder?: string
58
- /**
59
- * @defaultValue 'primary'
60
- */
61
- color?: InputMenuVariants['color']
62
- /**
63
- * @defaultValue 'outline'
64
- */
65
- variant?: InputMenuVariants['variant']
66
- /**
67
- * @defaultValue 'md'
68
- */
69
- size?: InputMenuVariants['size']
70
- required?: boolean
71
- autofocus?: boolean
72
- autofocusDelay?: number
73
- /**
74
- * The icon displayed to open the menu.
75
- * @defaultValue appConfig.ui.icons.chevronDown
76
- * @IconifyIcon
77
- */
78
- trailingIcon?: string
79
- /**
80
- * The icon displayed when an item is selected.
81
- * @defaultValue appConfig.ui.icons.check
82
- * @IconifyIcon
83
- */
84
- selectedIcon?: string
85
- /**
86
- * The icon displayed to delete a tag.
87
- * Works only when `multiple` is `true`.
88
- * @defaultValue appConfig.ui.icons.close
89
- * @IconifyIcon
90
- */
91
- deleteIcon?: string
92
- /**
93
- * The content of the menu.
94
- * @defaultValue { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
95
- */
96
- content?: Omit<ComboboxContentProps, 'as' | 'asChild' | 'forceMount'> & Partial<EmitsToProps<ComboboxContentEmits>>
97
- /**
98
- * Display an arrow alongside the menu.
99
- * @defaultValue false
100
- */
101
- arrow?: boolean | Omit<ComboboxArrowProps, 'as' | 'asChild'>
102
- /**
103
- * Render the menu in a portal.
104
- * @defaultValue true
105
- */
106
- portal?: boolean
107
- /**
108
- * When `items` is an array of objects, select the field to use as the value instead of the object itself.
109
- * @defaultValue undefined
110
- */
111
- valueKey?: VK
112
- /**
113
- * When `items` is an array of objects, select the field to use as the label.
114
- * @defaultValue 'label'
115
- */
116
- labelKey?: keyof NestedItem<T>
117
- items?: T
118
- /** The value of the InputMenu when initially rendered. Use when you do not need to control the state of the InputMenu. */
119
- defaultValue?: GetModelValue<T, VK, M>
120
- /** The controlled value of the InputMenu. Can be binded-with with `v-model`. */
121
- modelValue?: GetModelValue<T, VK, M>
122
- /** Whether multiple options can be selected or not. */
123
- multiple?: M & boolean
124
- /** Highlight the ring color like a focus state. */
125
- highlight?: boolean
126
- /**
127
- * Determines if custom user input that does not exist in options can be added.
128
- * @defaultValue false
129
- */
130
- createItem?: boolean | 'always' | { position?: 'top' | 'bottom', when?: 'empty' | 'always' }
131
- /**
132
- * Fields to filter items by.
133
- * @defaultValue [labelKey]
134
- */
135
- filterFields?: string[]
136
- /**
137
- * When `true`, disable the default filters, useful for custom filtering (useAsyncData, useFetch, etc.).
138
- * @defaultValue false
139
- */
140
- ignoreFilter?: boolean
141
- class?: any
142
- ui?: PartialString<typeof inputMenu.slots>
143
- }
144
-
145
- export type InputMenuEmits<A extends ArrayOrNested<InputMenuItem>, VK extends GetItemKeys<A> | undefined, M extends boolean> = Pick<ComboboxRootEmits, 'update:open'> & {
146
- change: [payload: Event]
147
- blur: [payload: FocusEvent]
148
- focus: [payload: FocusEvent]
149
- create: [item: string]
150
- /** Event handler when highlighted element changes. */
151
- highlight: [payload: {
152
- ref: HTMLElement
153
- value: GetModelValue<A, VK, M>
154
- } | undefined]
155
- } & GetModelValueEmits<A, VK, M>
156
-
157
- type SlotProps<T extends InputMenuItem> = (props: { item: T, index: number }) => any
158
-
159
- export interface InputMenuSlots<
160
- A extends ArrayOrNested<InputMenuItem> = ArrayOrNested<InputMenuItem>,
161
- VK extends GetItemKeys<A> | undefined = undefined,
162
- M extends boolean = false,
163
- T extends NestedItem<A> = NestedItem<A>
164
- > {
165
- 'leading'(props: { modelValue?: GetModelValue<A, VK, M>, open: boolean, ui: ReturnType<typeof inputMenu> }): any
166
- 'trailing'(props: { modelValue?: GetModelValue<A, VK, M>, open: boolean, ui: ReturnType<typeof inputMenu> }): any
167
- 'empty'(props: { searchTerm?: string }): any
168
- 'item': SlotProps<T>
169
- 'item-leading': SlotProps<T>
170
- 'item-label': SlotProps<T>
171
- 'item-trailing': SlotProps<T>
172
- 'tags-item-text': SlotProps<T>
173
- 'tags-item-delete': SlotProps<T>
174
- 'create-item-label'(props: { item: string }): any
175
- }
1
+ <script>
2
+ import theme from "#build/ui/input-menu";
176
3
  </script>
177
4
 
178
- <script setup lang="ts" generic="T extends ArrayOrNested<InputMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false">
179
- import { computed, ref, toRef, onMounted, toRaw, nextTick } from 'vue'
180
- import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits, useFilter } from 'reka-ui'
181
- import { defu } from 'defu'
182
- import { isEqual } from 'ohash/utils'
183
- import { reactivePick, createReusableTemplate } from '@vueuse/core'
184
- import { useAppConfig } from '#imports'
185
- import { useButtonGroup } from '../composables/useButtonGroup'
186
- import { useComponentIcons } from '../composables/useComponentIcons'
187
- import { useFormField } from '../composables/useFormField'
188
- import { useLocale } from '../composables/useLocale'
189
- import { compare, get, isArrayOfArray } from '../utils'
190
- import UIcon from './Icon.vue'
191
- import UAvatar from './Avatar.vue'
192
- import UChip from './Chip.vue'
193
-
194
- defineOptions({ inheritAttrs: false })
195
-
196
- const props = withDefaults(defineProps<InputMenuProps<T, VK, M>>(), {
197
- type: 'text',
198
- autofocusDelay: 0,
199
- portal: true,
200
- labelKey: 'label' as never
201
- })
202
- const emits = defineEmits<InputMenuEmits<T, VK, M>>()
203
- const slots = defineSlots<InputMenuSlots<T, VK, M>>()
204
-
205
- const searchTerm = defineModel<string>('searchTerm', { default: '' })
206
-
207
- const { t } = useLocale()
208
- const appConfig = useAppConfig()
209
- const { contains } = useFilter({ sensitivity: 'base' })
210
-
211
- const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'required', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover', 'ignoreFilter'), emits)
212
- const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
213
- const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
214
-
215
- const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
216
- const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
217
- const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
218
-
219
- const inputSize = computed(() => buttonGroupSize.value || formGroupSize.value)
220
-
221
- const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate()
222
-
223
- const ui = computed(() => inputMenu({
5
+ <script setup>
6
+ import { computed, ref, toRef, onMounted, toRaw } from "vue";
7
+ import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits, useFilter } from "reka-ui";
8
+ import { defu } from "defu";
9
+ import { isEqual } from "ohash/utils";
10
+ import { reactivePick, createReusableTemplate } from "@vueuse/core";
11
+ import { useAppConfig } from "#imports";
12
+ import { useButtonGroup } from "../composables/useButtonGroup";
13
+ import { useComponentIcons } from "../composables/useComponentIcons";
14
+ import { useFormField } from "../composables/useFormField";
15
+ import { useLocale } from "../composables/useLocale";
16
+ import { usePortal } from "../composables/usePortal";
17
+ import { compare, get, isArrayOfArray } from "../utils";
18
+ import { tv } from "../utils/tv";
19
+ import UIcon from "./Icon.vue";
20
+ import UAvatar from "./Avatar.vue";
21
+ import UChip from "./Chip.vue";
22
+ defineOptions({ inheritAttrs: false });
23
+ const props = defineProps({
24
+ as: { type: null, required: false },
25
+ id: { type: String, required: false },
26
+ type: { type: null, required: false, default: "text" },
27
+ placeholder: { type: String, required: false },
28
+ color: { type: null, required: false },
29
+ variant: { type: null, required: false },
30
+ size: { type: null, required: false },
31
+ required: { type: Boolean, required: false },
32
+ autofocus: { type: Boolean, required: false },
33
+ autofocusDelay: { type: Number, required: false, default: 0 },
34
+ trailingIcon: { type: String, required: false },
35
+ selectedIcon: { type: String, required: false },
36
+ deleteIcon: { type: String, required: false },
37
+ content: { type: Object, required: false },
38
+ arrow: { type: [Boolean, Object], required: false },
39
+ portal: { type: [Boolean, String], required: false, skipCheck: true, default: true },
40
+ valueKey: { type: null, required: false },
41
+ labelKey: { type: null, required: false, default: "label" },
42
+ items: { type: null, required: false },
43
+ defaultValue: { type: null, required: false },
44
+ modelValue: { type: null, required: false },
45
+ multiple: { type: Boolean, required: false },
46
+ highlight: { type: Boolean, required: false },
47
+ createItem: { type: [Boolean, String, Object], required: false },
48
+ filterFields: { type: Array, required: false },
49
+ ignoreFilter: { type: Boolean, required: false },
50
+ class: { type: null, required: false },
51
+ ui: { type: null, required: false },
52
+ open: { type: Boolean, required: false },
53
+ defaultOpen: { type: Boolean, required: false },
54
+ disabled: { type: Boolean, required: false },
55
+ name: { type: String, required: false },
56
+ resetSearchTermOnBlur: { type: Boolean, required: false, default: true },
57
+ resetSearchTermOnSelect: { type: Boolean, required: false, default: true },
58
+ highlightOnHover: { type: Boolean, required: false },
59
+ icon: { type: String, required: false },
60
+ avatar: { type: Object, required: false },
61
+ leading: { type: Boolean, required: false },
62
+ leadingIcon: { type: String, required: false },
63
+ trailing: { type: Boolean, required: false },
64
+ loading: { type: Boolean, required: false },
65
+ loadingIcon: { type: String, required: false }
66
+ });
67
+ const emits = defineEmits(["update:open", "change", "blur", "focus", "create", "highlight", "update:modelValue"]);
68
+ const slots = defineSlots();
69
+ const searchTerm = defineModel("searchTerm", { type: String, ...{ default: "" } });
70
+ const { t } = useLocale();
71
+ const appConfig = useAppConfig();
72
+ const { contains } = useFilter({ sensitivity: "base" });
73
+ const rootProps = useForwardPropsEmits(reactivePick(props, "as", "modelValue", "defaultValue", "open", "defaultOpen", "required", "multiple", "resetSearchTermOnBlur", "resetSearchTermOnSelect", "highlightOnHover", "ignoreFilter"), emits);
74
+ const portalProps = usePortal(toRef(() => props.portal));
75
+ const contentProps = toRef(() => defu(props.content, { side: "bottom", sideOffset: 8, collisionPadding: 8, position: "popper" }));
76
+ const arrowProps = toRef(() => props.arrow);
77
+ const { emitFormBlur, emitFormFocus, emitFormChange, emitFormInput, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField(props);
78
+ const { orientation, size: buttonGroupSize } = useButtonGroup(props);
79
+ const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })));
80
+ const inputSize = computed(() => buttonGroupSize.value || formGroupSize.value);
81
+ const [DefineCreateItemTemplate, ReuseCreateItemTemplate] = createReusableTemplate();
82
+ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.inputMenu || {} })({
224
83
  color: color.value,
225
84
  variant: props.variant,
226
85
  size: inputSize?.value,
@@ -230,133 +89,123 @@ const ui = computed(() => inputMenu({
230
89
  trailing: isTrailing.value || !!slots.trailing,
231
90
  multiple: props.multiple,
232
91
  buttonGroup: orientation.value
233
- }))
234
-
235
- function displayValue(value: T): string {
92
+ }));
93
+ function displayValue(value) {
236
94
  if (!props.valueKey) {
237
- return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
95
+ return value && (typeof value === "object" ? get(value, props.labelKey) : value);
238
96
  }
239
-
240
- const item = items.value.find(item => compare(typeof item === 'object' ? get(item as Record<string, any>, props.valueKey as string) : item, value))
241
- return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
97
+ const item = items.value.find((item2) => compare(typeof item2 === "object" ? get(item2, props.valueKey) : item2, value));
98
+ return item && (typeof item === "object" ? get(item, props.labelKey) : item);
242
99
  }
243
-
244
- const groups = computed<InputMenuItem[][]>(() =>
245
- props.items?.length
246
- ? isArrayOfArray(props.items)
247
- ? props.items
248
- : [props.items]
249
- : []
250
- )
251
- // eslint-disable-next-line vue/no-dupe-keys
252
- const items = computed(() => groups.value.flatMap(group => group))
253
-
100
+ const groups = computed(
101
+ () => props.items?.length ? isArrayOfArray(props.items) ? props.items : [props.items] : []
102
+ );
103
+ const items = computed(() => groups.value.flatMap((group) => group));
254
104
  const filteredGroups = computed(() => {
255
105
  if (props.ignoreFilter || !searchTerm.value) {
256
- return groups.value
106
+ return groups.value;
257
107
  }
258
-
259
- const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey] as string[]
260
-
261
- return groups.value.map(group => group.filter((item) => {
262
- if (typeof item !== 'object' || item === null) {
263
- return contains(String(item), searchTerm.value)
108
+ const fields = Array.isArray(props.filterFields) ? props.filterFields : [props.labelKey];
109
+ return groups.value.map((group) => group.filter((item) => {
110
+ if (typeof item !== "object" || item === null) {
111
+ return contains(String(item), searchTerm.value);
264
112
  }
265
-
266
- if (item.type && ['label', 'separator'].includes(item.type)) {
267
- return true
113
+ if (item.type && ["label", "separator"].includes(item.type)) {
114
+ return true;
268
115
  }
269
-
270
- return fields.some(field => contains(get(item, field), searchTerm.value))
271
- })).filter(group => group.filter(item =>
272
- !isInputItem(item) || (!item.type || !['label', 'separator'].includes(item.type))
273
- ).length > 0)
274
- })
275
- const filteredItems = computed(() => filteredGroups.value.flatMap(group => group))
276
-
116
+ return fields.some((field) => contains(get(item, field), searchTerm.value));
117
+ })).filter((group) => group.filter(
118
+ (item) => !isInputItem(item) || (!item.type || !["label", "separator"].includes(item.type))
119
+ ).length > 0);
120
+ });
121
+ const filteredItems = computed(() => filteredGroups.value.flatMap((group) => group));
277
122
  const createItem = computed(() => {
278
123
  if (!props.createItem || !searchTerm.value) {
279
- return false
124
+ return false;
280
125
  }
281
-
282
- const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } as NestedItem<T> : searchTerm.value
283
-
284
- if ((typeof props.createItem === 'object' && props.createItem.when === 'always') || props.createItem === 'always') {
285
- return !filteredItems.value.find(item => compare(item, newItem, String(props.valueKey)))
126
+ const newItem = props.valueKey ? { [props.valueKey]: searchTerm.value } : searchTerm.value;
127
+ if (typeof props.createItem === "object" && props.createItem.when === "always" || props.createItem === "always") {
128
+ return !filteredItems.value.find((item) => compare(item, newItem, props.valueKey));
286
129
  }
287
-
288
- return !filteredItems.value.length
289
- })
290
- const createItemPosition = computed(() => typeof props.createItem === 'object' ? props.createItem.position : 'bottom')
291
-
292
- const inputRef = ref<InstanceType<typeof ComboboxInput> | null>(null)
293
-
130
+ return !filteredItems.value.length;
131
+ });
132
+ const createItemPosition = computed(() => typeof props.createItem === "object" ? props.createItem.position : "bottom");
133
+ const inputRef = ref(null);
294
134
  function autoFocus() {
295
135
  if (props.autofocus) {
296
- inputRef.value?.$el?.focus()
136
+ inputRef.value?.$el?.focus();
297
137
  }
298
138
  }
299
-
300
139
  onMounted(() => {
301
140
  setTimeout(() => {
302
- autoFocus()
303
- }, props.autofocusDelay)
304
- })
305
-
306
- function onUpdate(value: any) {
141
+ autoFocus();
142
+ }, props.autofocusDelay);
143
+ });
144
+ function onUpdate(value) {
307
145
  if (toRaw(props.modelValue) === value) {
308
- return
146
+ return;
147
+ }
148
+ const event = new Event("change", { target: { value } });
149
+ emits("change", event);
150
+ emitFormChange();
151
+ emitFormInput();
152
+ if (props.resetSearchTermOnSelect) {
153
+ searchTerm.value = "";
309
154
  }
310
- // @ts-expect-error - 'target' does not exist in type 'EventInit'
311
- const event = new Event('change', { target: { value } })
312
- emits('change', event)
313
- emitFormChange()
314
- emitFormInput()
315
155
  }
316
-
317
- function onBlur(event: FocusEvent) {
318
- emits('blur', event)
319
- emitFormBlur()
156
+ function onBlur(event) {
157
+ emits("blur", event);
158
+ emitFormBlur();
320
159
  }
321
-
322
- function onFocus(event: FocusEvent) {
323
- emits('focus', event)
324
- emitFormFocus()
160
+ function onFocus(event) {
161
+ emits("focus", event);
162
+ emitFormFocus();
325
163
  }
326
-
327
- function onUpdateOpen(value: boolean) {
164
+ function onUpdateOpen(value) {
165
+ let timeoutId;
328
166
  if (!value) {
329
- const event = new FocusEvent('blur')
330
- emits('blur', event)
331
- emitFormBlur()
167
+ const event = new FocusEvent("blur");
168
+ emits("blur", event);
169
+ emitFormBlur();
170
+ if (props.resetSearchTermOnBlur) {
171
+ const STATE_ANIMATION_DELAY_MS = 100;
172
+ timeoutId = setTimeout(() => {
173
+ searchTerm.value = "";
174
+ }, STATE_ANIMATION_DELAY_MS);
175
+ }
332
176
  } else {
333
- const event = new FocusEvent('focus')
334
- emits('focus', event)
177
+ const event = new FocusEvent("focus");
178
+ emits("focus", event);
179
+ emitFormFocus();
180
+ clearTimeout(timeoutId);
335
181
  }
336
-
337
- nextTick(() => {
338
- searchTerm.value = ''
339
- })
340
182
  }
341
-
342
- function onRemoveTag(event: any) {
183
+ function onRemoveTag(event) {
343
184
  if (props.multiple) {
344
- const modelValue = props.modelValue as GetModelValue<T, VK, true>
345
- const filteredValue = modelValue.filter(value => !isEqual(value, event))
346
- emits('update:modelValue', filteredValue as GetModelValue<T, VK, M>)
185
+ const modelValue = props.modelValue;
186
+ const filteredValue = modelValue.filter((value) => !isEqual(value, event));
187
+ emits("update:modelValue", filteredValue);
188
+ onUpdate(filteredValue);
347
189
  }
348
190
  }
349
-
350
- function isInputItem(item: InputMenuItem): item is _InputMenuItem {
351
- return typeof item === 'object' && item !== null
191
+ function onSelect(e, item) {
192
+ if (!isInputItem(item)) {
193
+ return;
194
+ }
195
+ if (item.disabled) {
196
+ e.preventDefault();
197
+ return;
198
+ }
199
+ item.onSelect?.(e);
200
+ }
201
+ function isInputItem(item) {
202
+ return typeof item === "object" && item !== null;
352
203
  }
353
-
354
204
  defineExpose({
355
205
  inputRef
356
- })
206
+ });
357
207
  </script>
358
208
 
359
- <!-- eslint-disable vue/no-template-shadow -->
360
209
  <template>
361
210
  <DefineCreateItemTemplate>
362
211
  <ComboboxGroup :class="ui.group({ class: props.ui?.group })">
@@ -391,7 +240,7 @@ defineExpose({
391
240
  <TagsInputRoot
392
241
  v-if="multiple"
393
242
  v-slot="{ modelValue: tags }"
394
- :model-value="(modelValue as string[])"
243
+ :model-value="modelValue"
395
244
  :disabled="disabled"
396
245
  :required="required"
397
246
  delimiter=""
@@ -402,19 +251,19 @@ defineExpose({
402
251
  >
403
252
  <TagsInputItem v-for="(item, index) in tags" :key="index" :value="item" :class="ui.tagsItem({ class: props.ui?.tagsItem })">
404
253
  <TagsInputItemText :class="ui.tagsItemText({ class: props.ui?.tagsItemText })">
405
- <slot name="tags-item-text" :item="(item as NestedItem<T>)" :index="index">
406
- {{ displayValue(item as T) }}
254
+ <slot name="tags-item-text" :item="item" :index="index">
255
+ {{ displayValue(item) }}
407
256
  </slot>
408
257
  </TagsInputItemText>
409
258
 
410
259
  <TagsInputItemDelete :class="ui.tagsItemDelete({ class: props.ui?.tagsItemDelete })" :disabled="disabled">
411
- <slot name="tags-item-delete" :item="(item as NestedItem<T>)" :index="index">
260
+ <slot name="tags-item-delete" :item="item" :index="index">
412
261
  <UIcon :name="deleteIcon || appConfig.ui.icons.close" :class="ui.tagsItemDeleteIcon({ class: props.ui?.tagsItemDeleteIcon })" />
413
262
  </slot>
414
263
  </TagsInputItemDelete>
415
264
  </TagsInputItem>
416
265
 
417
- <ComboboxInput as-child @update:model-value="searchTerm = $event">
266
+ <ComboboxInput v-model="searchTerm" as-child>
418
267
  <TagsInputInput
419
268
  ref="inputRef"
420
269
  v-bind="{ ...$attrs, ...ariaAttrs }"
@@ -439,21 +288,23 @@ defineExpose({
439
288
  />
440
289
 
441
290
  <span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
442
- <slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
291
+ <slot name="leading" :model-value="modelValue" :open="open" :ui="ui">
443
292
  <UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
444
- <UAvatar v-else-if="!!avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
293
+ <UAvatar v-else-if="!!avatar" :size="props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()" v-bind="avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
445
294
  </slot>
446
295
  </span>
447
296
 
448
297
  <ComboboxTrigger v-if="isTrailing || !!slots.trailing" :class="ui.trailing({ class: props.ui?.trailing })">
449
- <slot name="trailing" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
298
+ <slot name="trailing" :model-value="modelValue" :open="open" :ui="ui">
450
299
  <UIcon v-if="trailingIconName" :name="trailingIconName" :class="ui.trailingIcon({ class: props.ui?.trailingIcon })" />
451
300
  </slot>
452
301
  </ComboboxTrigger>
453
302
  </ComboboxAnchor>
454
303
 
455
- <ComboboxPortal :disabled="!portal">
304
+ <ComboboxPortal v-bind="portalProps">
456
305
  <ComboboxContent :class="ui.content({ class: props.ui?.content })" v-bind="contentProps">
306
+ <slot name="content-top" />
307
+
457
308
  <ComboboxEmpty :class="ui.empty({ class: props.ui?.empty })">
458
309
  <slot name="empty" :search-term="searchTerm">
459
310
  {{ searchTerm ? t('inputMenu.noMatch', { searchTerm }) : t('inputMenu.noData') }}
@@ -466,7 +317,7 @@ defineExpose({
466
317
  <ComboboxGroup v-for="(group, groupIndex) in filteredGroups" :key="`group-${groupIndex}`" :class="ui.group({ class: props.ui?.group })">
467
318
  <template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
468
319
  <ComboboxLabel v-if="isInputItem(item) && item.type === 'label'" :class="ui.label({ class: props.ui?.label })">
469
- {{ get(item, props.labelKey as string) }}
320
+ {{ get(item, props.labelKey) }}
470
321
  </ComboboxLabel>
471
322
 
472
323
  <ComboboxSeparator v-else-if="isInputItem(item) && item.type === 'separator'" :class="ui.separator({ class: props.ui?.separator })" />
@@ -475,16 +326,16 @@ defineExpose({
475
326
  v-else
476
327
  :class="ui.item({ class: props.ui?.item })"
477
328
  :disabled="isInputItem(item) && item.disabled"
478
- :value="props.valueKey && isInputItem(item) ? get(item, String(props.valueKey)) : item"
479
- @select="isInputItem(item) && item.onSelect"
329
+ :value="props.valueKey && isInputItem(item) ? get(item, props.valueKey) : item"
330
+ @select="onSelect($event, item)"
480
331
  >
481
- <slot name="item" :item="(item as NestedItem<T>)" :index="index">
482
- <slot name="item-leading" :item="(item as NestedItem<T>)" :index="index">
332
+ <slot name="item" :item="item" :index="index">
333
+ <slot name="item-leading" :item="item" :index="index">
483
334
  <UIcon v-if="isInputItem(item) && item.icon" :name="item.icon" :class="ui.itemLeadingIcon({ class: props.ui?.itemLeadingIcon })" />
484
- <UAvatar v-else-if="isInputItem(item) && item.avatar" :size="((props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
335
+ <UAvatar v-else-if="isInputItem(item) && item.avatar" :size="props.ui?.itemLeadingAvatarSize || ui.itemLeadingAvatarSize()" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ class: props.ui?.itemLeadingAvatar })" />
485
336
  <UChip
486
337
  v-else-if="isInputItem(item) && item.chip"
487
- :size="((props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()) as ChipProps['size'])"
338
+ :size="props.ui?.itemLeadingChipSize || ui.itemLeadingChipSize()"
488
339
  inset
489
340
  standalone
490
341
  v-bind="item.chip"
@@ -493,13 +344,13 @@ defineExpose({
493
344
  </slot>
494
345
 
495
346
  <span :class="ui.itemLabel({ class: props.ui?.itemLabel })">
496
- <slot name="item-label" :item="(item as NestedItem<T>)" :index="index">
497
- {{ isInputItem(item) ? get(item, props.labelKey as string) : item }}
347
+ <slot name="item-label" :item="item" :index="index">
348
+ {{ isInputItem(item) ? get(item, props.labelKey) : item }}
498
349
  </slot>
499
350
  </span>
500
351
 
501
352
  <span :class="ui.itemTrailing({ class: props.ui?.itemTrailing })">
502
- <slot name="item-trailing" :item="(item as NestedItem<T>)" :index="index" />
353
+ <slot name="item-trailing" :item="item" :index="index" />
503
354
 
504
355
  <ComboboxItemIndicator as-child>
505
356
  <UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: props.ui?.itemTrailingIcon })" />
@@ -513,6 +364,8 @@ defineExpose({
513
364
  <ReuseCreateItemTemplate v-if="createItem && createItemPosition === 'bottom'" />
514
365
  </ComboboxViewport>
515
366
 
367
+ <slot name="content-bottom" />
368
+
516
369
  <ComboboxArrow v-if="!!arrow" v-bind="arrowProps" :class="ui.arrow({ class: props.ui?.arrow })" />
517
370
  </ComboboxContent>
518
371
  </ComboboxPortal>