@nuxt/ui 3.0.0-alpha.10 → 3.0.0-alpha.12
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.
- package/.nuxt/ui/alert.ts +76 -59
- package/.nuxt/ui/avatar-group.ts +13 -1
- package/.nuxt/ui/avatar.ts +14 -2
- package/.nuxt/ui/badge.ts +102 -65
- package/.nuxt/ui/button-group.ts +13 -0
- package/.nuxt/ui/button.ts +124 -93
- package/.nuxt/ui/calendar.ts +20 -2
- package/.nuxt/ui/carousel.ts +5 -3
- package/.nuxt/ui/checkbox.ts +27 -9
- package/.nuxt/ui/chip.ts +36 -7
- package/.nuxt/ui/color-picker.ts +9 -1
- package/.nuxt/ui/context-menu.ts +31 -13
- package/.nuxt/ui/drawer.ts +11 -4
- package/.nuxt/ui/dropdown-menu.ts +31 -13
- package/.nuxt/ui/form-field.ts +9 -1
- package/.nuxt/ui/input-menu.ts +110 -75
- package/.nuxt/ui/input-number.ts +82 -51
- package/.nuxt/ui/input.ts +88 -53
- package/.nuxt/ui/kbd.ts +14 -2
- package/.nuxt/ui/navigation-menu.ts +193 -79
- package/.nuxt/ui/pin-input.ts +57 -31
- package/.nuxt/ui/popover.ts +1 -1
- package/.nuxt/ui/progress.ts +93 -54
- package/.nuxt/ui/radio-group.ts +25 -2
- package/.nuxt/ui/select-menu.ts +89 -54
- package/.nuxt/ui/select.ts +89 -54
- package/.nuxt/ui/separator.ts +52 -23
- package/.nuxt/ui/slideover.ts +11 -4
- package/.nuxt/ui/slider.ts +45 -22
- package/.nuxt/ui/stepper.ts +45 -23
- package/.nuxt/ui/switch.ts +20 -2
- package/.nuxt/ui/table.ts +30 -13
- package/.nuxt/ui/tabs.ts +67 -39
- package/.nuxt/ui/textarea.ts +88 -53
- package/.nuxt/ui/toast.ts +11 -1
- package/.nuxt/ui/toaster.ts +27 -11
- package/.nuxt/ui/tooltip.ts +1 -1
- package/README.md +8 -1
- package/cli/commands/make/component.mjs +12 -0
- package/cli/package.json +2 -2
- package/cli/templates.mjs +21 -16
- package/dist/chunks/component-meta.cjs +2590 -2511
- package/dist/chunks/component-meta.mjs +2590 -2511
- package/dist/client/devtools/200.html +1 -1
- package/dist/client/devtools/404.html +1 -1
- package/dist/client/devtools/_nuxt/CgoQwOTV.js +57 -0
- package/dist/client/devtools/_nuxt/DLmPhbaq.js +1 -0
- package/dist/client/devtools/_nuxt/DYuJNiSW.js +1 -0
- package/dist/client/devtools/_nuxt/builds/latest.json +1 -1
- package/dist/client/devtools/_nuxt/builds/meta/3184ffe2-7577-4441-af98-fe6e81c30e3a.json +1 -0
- package/dist/client/devtools/_nuxt/entry.ChJczkiN.css +1 -0
- package/dist/client/devtools/_nuxt/error-404.DyY3rYaL.css +1 -0
- package/dist/client/devtools/_nuxt/error-500.D_1PCaJh.css +1 -0
- package/dist/client/devtools/index.html +1 -1
- package/dist/module.cjs +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/components/Accordion.vue +4 -3
- package/dist/runtime/components/Alert.vue +5 -4
- package/dist/runtime/components/Avatar.vue +35 -13
- package/dist/runtime/components/AvatarGroup.vue +4 -3
- package/dist/runtime/components/Badge.vue +4 -3
- package/dist/runtime/components/Breadcrumb.vue +3 -3
- package/dist/runtime/components/Button.vue +4 -3
- package/dist/runtime/components/ButtonGroup.vue +4 -3
- package/dist/runtime/components/Calendar.vue +6 -3
- package/dist/runtime/components/Card.vue +3 -3
- package/dist/runtime/components/Carousel.vue +4 -3
- package/dist/runtime/components/Checkbox.vue +6 -5
- package/dist/runtime/components/Chip.vue +5 -4
- package/dist/runtime/components/Collapsible.vue +6 -4
- package/dist/runtime/components/ColorPicker.vue +48 -16
- package/dist/runtime/components/CommandPalette.vue +14 -7
- package/dist/runtime/components/Container.vue +3 -3
- package/dist/runtime/components/ContextMenu.vue +4 -3
- package/dist/runtime/components/ContextMenuContent.vue +4 -4
- package/dist/runtime/components/Drawer.vue +9 -4
- package/dist/runtime/components/DropdownMenu.vue +4 -3
- package/dist/runtime/components/DropdownMenuContent.vue +4 -4
- package/dist/runtime/components/Form.vue +59 -29
- package/dist/runtime/components/FormField.vue +14 -7
- package/dist/runtime/components/Input.vue +7 -5
- package/dist/runtime/components/InputMenu.vue +19 -7
- package/dist/runtime/components/InputNumber.vue +9 -5
- package/dist/runtime/components/Kbd.vue +4 -3
- package/dist/runtime/components/Link.vue +3 -3
- package/dist/runtime/components/Modal.vue +10 -15
- package/dist/runtime/components/NavigationMenu.vue +97 -69
- package/dist/runtime/components/Pagination.vue +3 -3
- package/dist/runtime/components/PinInput.vue +9 -7
- package/dist/runtime/components/Popover.vue +9 -8
- package/dist/runtime/components/Progress.vue +6 -5
- package/dist/runtime/components/RadioGroup.vue +6 -5
- package/dist/runtime/components/Select.vue +12 -9
- package/dist/runtime/components/SelectMenu.vue +25 -8
- package/dist/runtime/components/Separator.vue +4 -3
- package/dist/runtime/components/Skeleton.vue +3 -3
- package/dist/runtime/components/Slideover.vue +10 -14
- package/dist/runtime/components/Slider.vue +6 -5
- package/dist/runtime/components/Stepper.vue +8 -6
- package/dist/runtime/components/Switch.vue +6 -5
- package/dist/runtime/components/Table.vue +4 -3
- package/dist/runtime/components/Tabs.vue +5 -3
- package/dist/runtime/components/Textarea.vue +7 -5
- package/dist/runtime/components/Toast.vue +4 -3
- package/dist/runtime/components/Toaster.vue +4 -3
- package/dist/runtime/components/Tooltip.vue +3 -3
- package/dist/runtime/composables/defineShortcuts.js +1 -1
- package/dist/runtime/composables/useFormField.d.ts +7 -3
- package/dist/runtime/composables/useFormField.js +18 -8
- package/dist/runtime/composables/useToast.d.ts +1 -1
- package/dist/runtime/composables/useToast.js +21 -7
- package/dist/runtime/index.css +1 -1
- package/dist/runtime/locale/ar.js +3 -1
- package/dist/runtime/locale/cs.js +3 -1
- package/dist/runtime/locale/da.js +54 -0
- package/dist/runtime/locale/de.js +3 -1
- package/dist/runtime/locale/el.js +54 -0
- package/dist/runtime/locale/en.js +3 -1
- package/dist/runtime/locale/es.js +5 -3
- package/dist/runtime/locale/et.d.ts +2 -0
- package/dist/runtime/locale/et.js +54 -0
- package/dist/runtime/locale/fa_ir.js +3 -1
- package/dist/runtime/locale/fi.d.ts +2 -0
- package/dist/runtime/locale/fi.js +54 -0
- package/dist/runtime/locale/fr.js +3 -1
- package/dist/runtime/locale/he.d.ts +2 -0
- package/dist/runtime/locale/he.js +53 -0
- package/dist/runtime/locale/hi.d.ts +2 -0
- package/dist/runtime/locale/hi.js +54 -0
- package/dist/runtime/locale/hu.d.ts +2 -0
- package/dist/runtime/locale/hu.js +54 -0
- package/dist/runtime/locale/id.d.ts +2 -0
- package/dist/runtime/locale/id.js +54 -0
- package/dist/runtime/locale/index.d.ts +14 -2
- package/dist/runtime/locale/index.js +14 -2
- package/dist/runtime/locale/it.js +3 -1
- package/dist/runtime/locale/ja.js +3 -1
- package/dist/runtime/locale/km.d.ts +2 -0
- package/dist/runtime/locale/km.js +54 -0
- package/dist/runtime/locale/ko.js +3 -1
- package/dist/runtime/locale/nb_no.d.ts +2 -0
- package/dist/runtime/locale/nb_no.js +54 -0
- package/dist/runtime/locale/nl.js +3 -1
- package/dist/runtime/locale/pl.js +3 -1
- package/dist/runtime/locale/pt.js +3 -1
- package/dist/runtime/locale/pt_br.js +3 -1
- package/dist/runtime/locale/ru.js +3 -1
- package/dist/runtime/locale/sk.js +3 -1
- package/dist/runtime/locale/sv.d.ts +2 -0
- package/dist/runtime/locale/sv.js +54 -0
- package/dist/runtime/locale/th.d.ts +2 -0
- package/dist/runtime/locale/th.js +54 -0
- package/dist/runtime/locale/tr.js +3 -1
- package/dist/runtime/locale/uk.d.ts +2 -0
- package/dist/runtime/locale/uk.js +54 -0
- package/dist/runtime/locale/vi.d.ts +2 -0
- package/dist/runtime/locale/vi.js +54 -0
- package/dist/runtime/locale/zh_cn.d.ts +2 -0
- package/dist/runtime/locale/{zh_hans.js → zh_cn.js} +4 -2
- package/dist/runtime/locale/zh_tw.d.ts +2 -0
- package/dist/runtime/locale/{zh_hant.js → zh_tw.js} +12 -10
- package/dist/runtime/plugins/colors.js +7 -4
- package/dist/runtime/types/form.d.ts +23 -14
- package/dist/runtime/types/form.js +2 -2
- package/dist/runtime/types/locale.d.ts +2 -0
- package/dist/runtime/utils/form.d.ts +2 -2
- package/dist/runtime/utils/form.js +5 -7
- package/dist/runtime/utils/tv.d.ts +1 -0
- package/dist/runtime/utils/tv.js +4 -0
- package/dist/runtime/vue/components/Icon.vue +2 -2
- package/dist/runtime/vue/components/Link.vue +2 -2
- package/dist/runtime/vue/plugins/head.d.ts +1 -1
- package/dist/runtime/vue/plugins/head.js +3 -3
- package/dist/shared/{ui.D_93iuwH.mjs → ui.CENZ17mM.mjs} +131 -48
- package/dist/shared/{ui.CwmIkD_Y.cjs → ui.ClMXjgLK.cjs} +131 -48
- package/dist/unplugin.cjs +5 -5
- package/dist/unplugin.mjs +5 -5
- package/dist/vite.cjs +1 -1
- package/dist/vite.mjs +1 -1
- package/package.json +55 -51
- package/dist/client/devtools/_nuxt/B1fTd_Rf.js +0 -1
- package/dist/client/devtools/_nuxt/CSUxkedg.js +0 -1
- package/dist/client/devtools/_nuxt/CbRTGpb7.js +0 -1
- package/dist/client/devtools/_nuxt/YQTlxbcT.js +0 -53
- package/dist/client/devtools/_nuxt/builds/meta/b3465abc-0a92-4ee7-ba6b-e5174891fcc0.json +0 -1
- package/dist/client/devtools/_nuxt/entry.DXXceQev.css +0 -1
- package/dist/client/devtools/_nuxt/error-404.BJpkZFyY.css +0 -1
- package/dist/client/devtools/_nuxt/error-500.D3i9VDlt.css +0 -1
- /package/dist/runtime/locale/{zh_hans.d.ts → da.d.ts} +0 -0
- /package/dist/runtime/locale/{zh_hant.d.ts → el.d.ts} +0 -0
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
3
|
import type { NavigationMenuRootProps, NavigationMenuRootEmits, NavigationMenuContentProps, CollapsibleRootProps } from 'reka-ui'
|
|
4
4
|
import type { AppConfig } from '@nuxt/schema'
|
|
5
5
|
import _appConfig from '#build/app.config'
|
|
6
6
|
import theme from '#build/ui/navigation-menu'
|
|
7
7
|
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
|
8
|
+
import { tv } from '../utils/tv'
|
|
8
9
|
import type { AvatarProps, BadgeProps, LinkProps } from '../types'
|
|
9
10
|
import type { DynamicSlots, MaybeArrayOfArray, MaybeArrayOfArrayItem, PartialString } from '../types/utils'
|
|
10
11
|
|
|
11
|
-
const
|
|
12
|
+
const appConfigNavigationMenu = _appConfig as AppConfig & { ui: { navigationMenu: Partial<typeof theme> } }
|
|
12
13
|
|
|
13
|
-
const navigationMenu = tv({ extend: tv(theme), ...(
|
|
14
|
+
const navigationMenu = tv({ extend: tv(theme), ...(appConfigNavigationMenu.ui?.navigationMenu || {}) })
|
|
14
15
|
|
|
15
|
-
export interface NavigationMenuChildItem extends Omit<NavigationMenuItem, 'children'> {
|
|
16
|
+
export interface NavigationMenuChildItem extends Omit<NavigationMenuItem, 'children' | 'type'> {
|
|
16
17
|
/** Description is only used when `orientation` is `horizontal`. */
|
|
17
18
|
description?: string
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
export interface NavigationMenuItem extends Omit<LinkProps, 'raw' | 'custom'>, Pick<CollapsibleRootProps, 'defaultOpen' | 'open'> {
|
|
21
|
+
export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'custom'>, Pick<CollapsibleRootProps, 'defaultOpen' | 'open'> {
|
|
21
22
|
label?: string
|
|
22
23
|
icon?: string
|
|
23
24
|
avatar?: AvatarProps
|
|
25
|
+
/**
|
|
26
|
+
* Display a badge on the item.
|
|
27
|
+
* `{ size: 'sm', color: 'neutral', variant: 'outline' }`{lang="ts-type"}
|
|
28
|
+
*/
|
|
24
29
|
badge?: string | number | BadgeProps
|
|
25
30
|
trailingIcon?: string
|
|
31
|
+
/**
|
|
32
|
+
* The type of the item.
|
|
33
|
+
* The `label` type only works on `vertical` orientation.
|
|
34
|
+
* @defaultValue 'link'
|
|
35
|
+
*/
|
|
36
|
+
type?: 'label' | 'link'
|
|
26
37
|
slot?: string
|
|
27
38
|
value?: string
|
|
28
39
|
children?: NavigationMenuChildItem[]
|
|
@@ -50,11 +61,23 @@ export interface NavigationMenuProps<T> extends Pick<NavigationMenuRootProps, 'm
|
|
|
50
61
|
* @defaultValue 'horizontal'
|
|
51
62
|
*/
|
|
52
63
|
orientation?: NavigationMenuRootProps['orientation']
|
|
64
|
+
/**
|
|
65
|
+
* Collapse the navigation menu to only show icons.
|
|
66
|
+
* Only works when `orientation` is `vertical`.
|
|
67
|
+
* @defaultValue false
|
|
68
|
+
*/
|
|
69
|
+
collapsed?: boolean
|
|
53
70
|
/** Display a line next to the active item. */
|
|
54
71
|
highlight?: boolean
|
|
55
72
|
highlightColor?: NavigationMenuVariants['highlightColor']
|
|
56
73
|
/** The content of the menu. */
|
|
57
74
|
content?: Omit<NavigationMenuContentProps, 'as' | 'asChild' | 'forceMount'>
|
|
75
|
+
/**
|
|
76
|
+
* The orientation of the content.
|
|
77
|
+
* Only works when `orientation` is `horizontal`.
|
|
78
|
+
* @defaultValue 'horizontal'
|
|
79
|
+
*/
|
|
80
|
+
contentOrientation?: NavigationMenuVariants['contentOrientation']
|
|
58
81
|
/**
|
|
59
82
|
* Display an arrow alongside the menu.
|
|
60
83
|
* @defaultValue false
|
|
@@ -125,6 +148,7 @@ extendDevtoolsMeta({
|
|
|
125
148
|
import { computed, toRef } from 'vue'
|
|
126
149
|
import { NavigationMenuRoot, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink, NavigationMenuIndicator, NavigationMenuViewport, useForwardPropsEmits } from 'reka-ui'
|
|
127
150
|
import { createReusableTemplate } from '@vueuse/core'
|
|
151
|
+
import { useAppConfig } from '#imports'
|
|
128
152
|
import { get } from '../utils'
|
|
129
153
|
import { pickLinkProps } from '../utils/link'
|
|
130
154
|
import ULinkBase from './LinkBase.vue'
|
|
@@ -136,9 +160,10 @@ import UCollapsible from './Collapsible.vue'
|
|
|
136
160
|
|
|
137
161
|
const props = withDefaults(defineProps<NavigationMenuProps<I>>(), {
|
|
138
162
|
orientation: 'horizontal',
|
|
163
|
+
contentOrientation: 'horizontal',
|
|
139
164
|
delayDuration: 0,
|
|
140
|
-
|
|
141
|
-
|
|
165
|
+
unmountOnHide: true,
|
|
166
|
+
labelKey: 'label'
|
|
142
167
|
})
|
|
143
168
|
const emits = defineEmits<NavigationMenuEmits>()
|
|
144
169
|
const slots = defineSlots<NavigationMenuSlots<T>>()
|
|
@@ -158,10 +183,14 @@ const rootProps = useForwardPropsEmits(computed(() => ({
|
|
|
158
183
|
|
|
159
184
|
const contentProps = toRef(() => props.content)
|
|
160
185
|
|
|
161
|
-
const
|
|
186
|
+
const appConfig = useAppConfig()
|
|
187
|
+
const [DefineLinkTemplate, ReuseLinkTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number, active?: boolean }>()
|
|
188
|
+
const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate<{ item: NavigationMenuItem, index: number }>()
|
|
162
189
|
|
|
163
190
|
const ui = computed(() => navigationMenu({
|
|
164
191
|
orientation: props.orientation,
|
|
192
|
+
contentOrientation: props.contentOrientation,
|
|
193
|
+
collapsed: props.collapsed,
|
|
165
194
|
color: props.color,
|
|
166
195
|
variant: props.variant,
|
|
167
196
|
highlight: props.highlight,
|
|
@@ -172,14 +201,17 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
|
|
|
172
201
|
</script>
|
|
173
202
|
|
|
174
203
|
<template>
|
|
175
|
-
<
|
|
204
|
+
<DefineLinkTemplate v-slot="{ item, active, index }">
|
|
176
205
|
<slot :name="item.slot || 'item'" :item="(item as T)" :index="index">
|
|
177
206
|
<slot :name="item.slot ? `${item.slot}-leading` : 'item-leading'" :item="(item as T)" :active="active" :index="index">
|
|
178
207
|
<UAvatar v-if="item.avatar" :size="((props.ui?.linkLeadingAvatarSize || ui.linkLeadingAvatarSize()) as AvatarProps['size'])" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ class: props.ui?.linkLeadingAvatar, active, disabled: !!item.disabled })" />
|
|
179
208
|
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ class: props.ui?.linkLeadingIcon, active, disabled: !!item.disabled })" />
|
|
180
209
|
</slot>
|
|
181
210
|
|
|
182
|
-
<span
|
|
211
|
+
<span
|
|
212
|
+
v-if="(!collapsed || orientation !== 'vertical') && (get(item, props.labelKey as string) || !!slots[item.slot ? `${item.slot}-label` : 'item-label'])"
|
|
213
|
+
:class="ui.linkLabel({ class: props.ui?.linkLabel })"
|
|
214
|
+
>
|
|
183
215
|
<slot :name="item.slot ? `${item.slot}-label` : 'item-label'" :item="(item as T)" :active="active" :index="index">
|
|
184
216
|
{{ get(item, props.labelKey as string) }}
|
|
185
217
|
</slot>
|
|
@@ -187,7 +219,7 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
|
|
|
187
219
|
<UIcon v-if="item.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.linkLabelExternalIcon({ class: props.ui?.linkLabelExternalIcon, active })" />
|
|
188
220
|
</span>
|
|
189
221
|
|
|
190
|
-
<span v-if="item.badge || (orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) || (orientation === 'vertical' && item.children?.length) || item.trailingIcon || !!slots[item.slot ? `${item.slot}-trailing` : 'item-trailing']" :class="ui.linkTrailing({ class: props.ui?.linkTrailing })">
|
|
222
|
+
<span v-if="(!collapsed || orientation !== 'vertical') && (item.badge || (orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) || (orientation === 'vertical' && item.children?.length) || item.trailingIcon || !!slots[item.slot ? `${item.slot}-trailing` : 'item-trailing'])" :class="ui.linkTrailing({ class: props.ui?.linkTrailing })">
|
|
191
223
|
<slot :name="item.slot ? `${item.slot}-trailing` : 'item-trailing'" :item="(item as T)" :active="active" :index="index">
|
|
192
224
|
<UBadge
|
|
193
225
|
v-if="item.badge"
|
|
@@ -203,77 +235,73 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
|
|
|
203
235
|
</slot>
|
|
204
236
|
</span>
|
|
205
237
|
</slot>
|
|
206
|
-
</
|
|
238
|
+
</DefineLinkTemplate>
|
|
207
239
|
|
|
208
|
-
<
|
|
209
|
-
<
|
|
210
|
-
|
|
240
|
+
<DefineItemTemplate v-slot="{ item, index }">
|
|
241
|
+
<component
|
|
242
|
+
:is="(orientation === 'vertical' && item.children?.length) ? UCollapsible : NavigationMenuItem"
|
|
243
|
+
as="li"
|
|
244
|
+
:value="item.value || String(index)"
|
|
245
|
+
:default-open="item.defaultOpen"
|
|
246
|
+
:unmount-on-hide="(orientation === 'vertical' && item.children?.length) ? unmountOnHide : undefined"
|
|
247
|
+
:open="item.open"
|
|
248
|
+
>
|
|
249
|
+
<div v-if="orientation === 'vertical' && item.type === 'label'" :class="ui.label({ class: props.ui?.label })">
|
|
250
|
+
<ReuseLinkTemplate :item="(item as T)" :index="index" />
|
|
251
|
+
</div>
|
|
252
|
+
<ULink v-else-if="item.type !== 'label'" v-slot="{ active, ...slotProps }" v-bind="(orientation === 'vertical' && item.children?.length) ? {} : pickLinkProps(item as Omit<NavigationMenuItem, 'type'>)" custom>
|
|
211
253
|
<component
|
|
212
|
-
:is="(item.children?.length
|
|
213
|
-
|
|
214
|
-
:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
:default-open="item.defaultOpen"
|
|
218
|
-
:unmount-on-hide="(item.children?.length && orientation === 'vertical') ? unmountOnHide : undefined"
|
|
219
|
-
:open="item.open"
|
|
220
|
-
:class="ui.item({ class: props.ui?.item })"
|
|
254
|
+
:is="(orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) ? NavigationMenuTrigger : NavigationMenuLink"
|
|
255
|
+
as-child
|
|
256
|
+
:active="active"
|
|
257
|
+
:disabled="item.disabled"
|
|
258
|
+
@select="item.onSelect"
|
|
221
259
|
>
|
|
222
|
-
<
|
|
223
|
-
<
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
:active="active"
|
|
227
|
-
:disabled="item.disabled"
|
|
228
|
-
@select="item.onSelect"
|
|
229
|
-
>
|
|
230
|
-
<ULinkBase v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active, disabled: !!item.disabled })">
|
|
231
|
-
<ReuseItemTemplate :item="(item as T)" :active="active" :index="index" />
|
|
232
|
-
</ULinkBase>
|
|
233
|
-
</component>
|
|
234
|
-
|
|
235
|
-
<NavigationMenuContent v-if="orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])" v-bind="contentProps" :class="ui.content({ class: props.ui?.content })">
|
|
236
|
-
<slot :name="item.slot ? `${item.slot}-content` : 'item-content'" :item="(item as T)" :active="active" :index="index">
|
|
237
|
-
<ul :class="ui.childList({ class: props.ui?.childList })">
|
|
238
|
-
<li v-for="(childItem, childIndex) in item.children" :key="childIndex" :class="ui.childItem({ class: props.ui?.childItem })">
|
|
239
|
-
<ULink v-slot="{ active: childActive, ...childSlotProps }" v-bind="pickLinkProps(childItem)" custom>
|
|
240
|
-
<NavigationMenuLink as-child :active="childActive" @select="childItem.onSelect">
|
|
241
|
-
<ULinkBase v-bind="childSlotProps" :class="ui.childLink({ class: [props.ui?.childLink, childItem.class], active: childActive })">
|
|
242
|
-
<UIcon v-if="childItem.icon" :name="childItem.icon" :class="ui.childLinkIcon({ class: props.ui?.childLinkIcon, active: childActive })" />
|
|
243
|
-
|
|
244
|
-
<div :class="ui.childLinkWrapper({ class: props.ui?.childLinkWrapper })">
|
|
245
|
-
<p :class="ui.childLinkLabel({ class: props.ui?.childLinkLabel, active: childActive })">
|
|
246
|
-
{{ get(childItem, props.labelKey as string) }}
|
|
247
|
-
|
|
248
|
-
<UIcon v-if="childItem.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.childLinkLabelExternalIcon({ class: props.ui?.childLinkLabelExternalIcon, active: childActive })" />
|
|
249
|
-
</p>
|
|
250
|
-
<p v-if="childItem.description" :class="ui.childLinkDescription({ class: props.ui?.childLinkDescription, active: childActive })">
|
|
251
|
-
{{ childItem.description }}
|
|
252
|
-
</p>
|
|
253
|
-
</div>
|
|
254
|
-
</ULinkBase>
|
|
255
|
-
</NavigationMenuLink>
|
|
256
|
-
</ULink>
|
|
257
|
-
</li>
|
|
258
|
-
</ul>
|
|
259
|
-
</slot>
|
|
260
|
-
</NavigationMenuContent>
|
|
261
|
-
</ULink>
|
|
260
|
+
<ULinkBase v-bind="slotProps" :class="ui.link({ class: [props.ui?.link, item.class], active: active || item.active, disabled: !!item.disabled, level: !(orientation === 'vertical' && item.children?.length) })">
|
|
261
|
+
<ReuseLinkTemplate :item="(item as T)" :active="active || item.active" :index="index" />
|
|
262
|
+
</ULinkBase>
|
|
263
|
+
</component>
|
|
262
264
|
|
|
263
|
-
|
|
265
|
+
<NavigationMenuContent v-if="orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])" v-bind="contentProps" :class="ui.content({ class: props.ui?.content })">
|
|
266
|
+
<slot :name="item.slot ? `${item.slot}-content` : 'item-content'" :item="(item as T)" :active="active" :index="index">
|
|
264
267
|
<ul :class="ui.childList({ class: props.ui?.childList })">
|
|
265
268
|
<li v-for="(childItem, childIndex) in item.children" :key="childIndex" :class="ui.childItem({ class: props.ui?.childItem })">
|
|
266
269
|
<ULink v-slot="{ active: childActive, ...childSlotProps }" v-bind="pickLinkProps(childItem)" custom>
|
|
267
270
|
<NavigationMenuLink as-child :active="childActive" @select="childItem.onSelect">
|
|
268
|
-
<ULinkBase v-bind="childSlotProps" :class="ui.
|
|
269
|
-
<
|
|
271
|
+
<ULinkBase v-bind="childSlotProps" :class="ui.childLink({ class: [props.ui?.childLink, childItem.class], active: childActive })">
|
|
272
|
+
<UIcon v-if="childItem.icon" :name="childItem.icon" :class="ui.childLinkIcon({ class: props.ui?.childLinkIcon, active: childActive })" />
|
|
273
|
+
|
|
274
|
+
<div :class="ui.childLinkWrapper({ class: props.ui?.childLinkWrapper })">
|
|
275
|
+
<p :class="ui.childLinkLabel({ class: props.ui?.childLinkLabel, active: childActive })">
|
|
276
|
+
{{ get(childItem, props.labelKey as string) }}
|
|
277
|
+
|
|
278
|
+
<UIcon v-if="childItem.target === '_blank'" :name="appConfig.ui.icons.external" :class="ui.childLinkLabelExternalIcon({ class: props.ui?.childLinkLabelExternalIcon, active: childActive })" />
|
|
279
|
+
</p>
|
|
280
|
+
<p v-if="childItem.description" :class="ui.childLinkDescription({ class: props.ui?.childLinkDescription, active: childActive })">
|
|
281
|
+
{{ childItem.description }}
|
|
282
|
+
</p>
|
|
283
|
+
</div>
|
|
270
284
|
</ULinkBase>
|
|
271
285
|
</NavigationMenuLink>
|
|
272
286
|
</ULink>
|
|
273
287
|
</li>
|
|
274
288
|
</ul>
|
|
275
|
-
</
|
|
276
|
-
</
|
|
289
|
+
</slot>
|
|
290
|
+
</NavigationMenuContent>
|
|
291
|
+
</ULink>
|
|
292
|
+
|
|
293
|
+
<template v-if="orientation === 'vertical' && item.children?.length" #content>
|
|
294
|
+
<ul :class="ui.childList({ class: props.ui?.childList })">
|
|
295
|
+
<ReuseItemTemplate v-for="(childItem, childIndex) in item.children" :key="childIndex" :item="childItem" :index="childIndex" :class="ui.childItem({ class: props.ui?.childItem })" />
|
|
296
|
+
</ul>
|
|
297
|
+
</template>
|
|
298
|
+
</component>
|
|
299
|
+
</DefineItemTemplate>
|
|
300
|
+
|
|
301
|
+
<NavigationMenuRoot v-bind="rootProps" :data-collapsed="collapsed" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
|
302
|
+
<template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
|
|
303
|
+
<NavigationMenuList :class="ui.list({ class: props.ui?.list })">
|
|
304
|
+
<ReuseItemTemplate v-for="(item, index) in list" :key="`list-${listIndex}-${index}`" :item="item" :index="index" :class="ui.item({ class: props.ui?.item })" />
|
|
277
305
|
</NavigationMenuList>
|
|
278
306
|
|
|
279
307
|
<div v-if="orientation === 'vertical' && listIndex < lists.length - 1" :class="ui.separator({ class: props.ui?.separator })" />
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { tv } from 'tailwind-variants'
|
|
3
2
|
import type { PaginationRootProps, PaginationRootEmits } from 'reka-ui'
|
|
4
3
|
import type { AppConfig } from '@nuxt/schema'
|
|
5
4
|
import type { RouteLocationRaw } from '#vue-router'
|
|
6
5
|
import _appConfig from '#build/app.config'
|
|
7
6
|
import theme from '#build/ui/pagination'
|
|
8
7
|
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
|
8
|
+
import { tv } from '../utils/tv'
|
|
9
9
|
import type { ButtonProps } from '../types'
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const appConfigPagination = _appConfig as AppConfig & { ui: { pagination: Partial<typeof theme> } }
|
|
12
12
|
|
|
13
|
-
const pagination = tv({ extend: tv(theme), ...(
|
|
13
|
+
const pagination = tv({ extend: tv(theme), ...(appConfigPagination.ui?.pagination || {}) })
|
|
14
14
|
|
|
15
15
|
export interface PaginationProps extends Partial<Pick<PaginationRootProps, 'defaultPage' | 'disabled' | 'itemsPerPage' | 'page' | 'showEdges' | 'siblingCount' | 'total'>> {
|
|
16
16
|
/**
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
|
+
import type { PinInputRootEmits, PinInputRootProps } from 'reka-ui'
|
|
4
|
+
import type { AppConfig } from '@nuxt/schema'
|
|
2
5
|
import _appConfig from '#build/app.config'
|
|
3
6
|
import theme from '#build/ui/pin-input'
|
|
4
|
-
import
|
|
5
|
-
import type { PinInputRootEmits, PinInputRootProps } from 'reka-ui'
|
|
6
|
-
import { tv, type VariantProps } from 'tailwind-variants'
|
|
7
|
+
import { tv } from '../utils/tv'
|
|
7
8
|
import type { PartialString } from '../types/utils'
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const appConfigPinInput = _appConfig as AppConfig & { ui: { pinInput: Partial<typeof theme> } }
|
|
10
11
|
|
|
11
|
-
const pinInput = tv({ extend: tv(theme), ...(
|
|
12
|
+
const pinInput = tv({ extend: tv(theme), ...(appConfigPinInput.ui?.pinInput || {}) })
|
|
12
13
|
|
|
13
14
|
type PinInputVariants = VariantProps<typeof pinInput>
|
|
14
15
|
|
|
@@ -49,7 +50,7 @@ const props = withDefaults(defineProps<PinInputProps>(), {
|
|
|
49
50
|
const emits = defineEmits<PinInputEmits>()
|
|
50
51
|
|
|
51
52
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'defaultValue', 'disabled', 'id', 'mask', 'modelValue', 'name', 'otp', 'placeholder', 'required', 'type'), emits)
|
|
52
|
-
const { emitFormInput, emitFormChange, emitFormBlur, size, color, id, name, highlight, disabled } = useFormField<PinInputProps>(props)
|
|
53
|
+
const { emitFormInput, emitFormFocus, emitFormChange, emitFormBlur, size, color, id, name, highlight, disabled, ariaAttrs } = useFormField<PinInputProps>(props)
|
|
53
54
|
|
|
54
55
|
const ui = computed(() => pinInput({
|
|
55
56
|
color: color.value,
|
|
@@ -76,7 +77,7 @@ function onBlur(event: FocusEvent) {
|
|
|
76
77
|
|
|
77
78
|
<template>
|
|
78
79
|
<PinInputRoot
|
|
79
|
-
v-bind="rootProps"
|
|
80
|
+
v-bind="{ ...rootProps, ...ariaAttrs }"
|
|
80
81
|
:id="id"
|
|
81
82
|
:name="name"
|
|
82
83
|
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
|
@@ -91,6 +92,7 @@ function onBlur(event: FocusEvent) {
|
|
|
91
92
|
v-bind="$attrs"
|
|
92
93
|
:disabled="disabled"
|
|
93
94
|
@blur="onBlur"
|
|
95
|
+
@focus="emitFormFocus"
|
|
94
96
|
/>
|
|
95
97
|
</PinInputRoot>
|
|
96
98
|
</template>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { tv } from 'tailwind-variants'
|
|
3
2
|
import type { PopoverRootProps, HoverCardRootProps, PopoverRootEmits, PopoverContentProps, PopoverArrowProps } from 'reka-ui'
|
|
4
3
|
import type { AppConfig } from '@nuxt/schema'
|
|
5
4
|
import _appConfig from '#build/app.config'
|
|
6
5
|
import theme from '#build/ui/popover'
|
|
6
|
+
import { tv } from '../utils/tv'
|
|
7
7
|
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const appConfigPopover = _appConfig as AppConfig & { ui: { popover: Partial<typeof theme> } }
|
|
10
10
|
|
|
11
|
-
const popover = tv({ extend: tv(theme), ...(
|
|
11
|
+
const popover = tv({ extend: tv(theme), ...(appConfigPopover.ui?.popover || {}) })
|
|
12
12
|
|
|
13
13
|
export interface PopoverProps extends PopoverRootProps, Pick<HoverCardRootProps, 'openDelay' | 'closeDelay'> {
|
|
14
14
|
/**
|
|
@@ -32,10 +32,10 @@ export interface PopoverProps extends PopoverRootProps, Pick<HoverCardRootProps,
|
|
|
32
32
|
*/
|
|
33
33
|
portal?: boolean
|
|
34
34
|
/**
|
|
35
|
-
* When `
|
|
36
|
-
* @defaultValue
|
|
35
|
+
* When `false`, the popover will not close when clicking outside or pressing escape.
|
|
36
|
+
* @defaultValue true
|
|
37
37
|
*/
|
|
38
|
-
|
|
38
|
+
dismissible?: boolean
|
|
39
39
|
class?: any
|
|
40
40
|
ui?: Partial<typeof popover.slots>
|
|
41
41
|
}
|
|
@@ -61,7 +61,8 @@ const props = withDefaults(defineProps<PopoverProps>(), {
|
|
|
61
61
|
portal: true,
|
|
62
62
|
mode: 'click',
|
|
63
63
|
openDelay: 0,
|
|
64
|
-
closeDelay: 0
|
|
64
|
+
closeDelay: 0,
|
|
65
|
+
dismissible: true
|
|
65
66
|
})
|
|
66
67
|
const emits = defineEmits<PopoverEmits>()
|
|
67
68
|
const slots = defineSlots<PopoverSlots>()
|
|
@@ -70,7 +71,7 @@ const pick = props.mode === 'hover' ? reactivePick(props, 'defaultOpen', 'open',
|
|
|
70
71
|
const rootProps = useForwardPropsEmits(pick, emits)
|
|
71
72
|
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8 }) as PopoverContentProps)
|
|
72
73
|
const contentEvents = computed(() => {
|
|
73
|
-
if (props.
|
|
74
|
+
if (!props.dismissible) {
|
|
74
75
|
return {
|
|
75
76
|
pointerDownOutside: (e: Event) => e.preventDefault(),
|
|
76
77
|
interactOutside: (e: Event) => e.preventDefault(),
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<!-- eslint-disable vue/block-tag-newline -->
|
|
2
2
|
<script lang="ts">
|
|
3
|
-
import {
|
|
3
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
4
4
|
import type { ProgressRootProps, ProgressRootEmits } from 'reka-ui'
|
|
5
5
|
import type { AppConfig } from '@nuxt/schema'
|
|
6
6
|
import _appConfig from '#build/app.config'
|
|
7
7
|
import theme from '#build/ui/progress'
|
|
8
|
+
import { tv } from '../utils/tv'
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const appConfigProgress = _appConfig as AppConfig & { ui: { progress: Partial<typeof theme> } }
|
|
10
11
|
|
|
11
|
-
const progress = tv({ extend: tv(theme), ...(
|
|
12
|
+
const progress = tv({ extend: tv(theme), ...(appConfigProgress.ui?.progress || {}) })
|
|
12
13
|
|
|
13
14
|
type ProgressVariants = VariantProps<typeof progress>
|
|
14
15
|
|
|
@@ -58,7 +59,7 @@ const props = withDefaults(defineProps<ProgressProps>(), {
|
|
|
58
59
|
orientation: 'horizontal'
|
|
59
60
|
})
|
|
60
61
|
const emits = defineEmits<ProgressEmits>()
|
|
61
|
-
defineSlots<ProgressSlots>()
|
|
62
|
+
const slots = defineSlots<ProgressSlots>()
|
|
62
63
|
|
|
63
64
|
const { dir } = useLocale()
|
|
64
65
|
|
|
@@ -160,7 +161,7 @@ const ui = computed(() => progress({
|
|
|
160
161
|
|
|
161
162
|
<template>
|
|
162
163
|
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
|
163
|
-
<div v-if="!isIndeterminate && (status ||
|
|
164
|
+
<div v-if="!isIndeterminate && (status || !!slots.status)" :class="ui.status({ class: props.ui?.status })" :style="statusStyle">
|
|
164
165
|
<slot name="status" :percent="percent">
|
|
165
166
|
{{ percent }}%
|
|
166
167
|
</slot>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
3
|
import type { RadioGroupRootProps, RadioGroupRootEmits, AcceptableValue } from 'reka-ui'
|
|
4
4
|
import type { AppConfig } from '@nuxt/schema'
|
|
5
5
|
import _appConfig from '#build/app.config'
|
|
6
6
|
import theme from '#build/ui/radio-group'
|
|
7
7
|
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
|
8
|
+
import { tv } from '../utils/tv'
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const appConfigRadioGroup = _appConfig as AppConfig & { ui: { radioGroup: Partial<typeof theme> } }
|
|
10
11
|
|
|
11
|
-
const radioGroup = tv({ extend: tv(theme), ...(
|
|
12
|
+
const radioGroup = tv({ extend: tv(theme), ...(appConfigRadioGroup.ui?.radioGroup || {}) })
|
|
12
13
|
|
|
13
14
|
type RadioGroupVariants = VariantProps<typeof radioGroup>
|
|
14
15
|
|
|
@@ -86,7 +87,7 @@ const slots = defineSlots<RadioGroupSlots<T>>()
|
|
|
86
87
|
|
|
87
88
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'orientation', 'loop', 'required'), emits)
|
|
88
89
|
|
|
89
|
-
const { emitFormChange, emitFormInput, color, name, size, id: _id, disabled } = useFormField<RadioGroupProps<T>>(props, { bind: false })
|
|
90
|
+
const { emitFormChange, emitFormInput, color, name, size, id: _id, disabled, ariaAttrs } = useFormField<RadioGroupProps<T>>(props, { bind: false })
|
|
90
91
|
const id = _id.value ?? useId()
|
|
91
92
|
|
|
92
93
|
const ui = computed(() => radioGroup({
|
|
@@ -146,7 +147,7 @@ function onUpdate(value: any) {
|
|
|
146
147
|
:class="ui.root({ class: [props.class, props.ui?.root] })"
|
|
147
148
|
@update:model-value="onUpdate"
|
|
148
149
|
>
|
|
149
|
-
<fieldset :class="ui.fieldset({ class: props.ui?.fieldset })">
|
|
150
|
+
<fieldset :class="ui.fieldset({ class: props.ui?.fieldset })" v-bind="ariaAttrs">
|
|
150
151
|
<legend v-if="legend || !!slots.legend" :class="ui.legend({ class: props.ui?.legend })">
|
|
151
152
|
<slot name="legend">
|
|
152
153
|
{{ legend }}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
3
|
import type { SelectRootProps, SelectRootEmits, SelectContentProps, SelectArrowProps, AcceptableValue } from 'reka-ui'
|
|
4
4
|
import type { AppConfig } from '@nuxt/schema'
|
|
5
5
|
import _appConfig from '#build/app.config'
|
|
6
6
|
import theme from '#build/ui/select'
|
|
7
7
|
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
|
8
8
|
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
|
9
|
+
import { tv } from '../utils/tv'
|
|
9
10
|
import type { AvatarProps, ChipProps, InputProps } from '../types'
|
|
10
11
|
import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
+
const appConfigSelect = _appConfig as AppConfig & { ui: { select: Partial<typeof theme> } }
|
|
13
14
|
|
|
14
|
-
const select = tv({ extend: tv(theme), ...(
|
|
15
|
+
const select = tv({ extend: tv(theme), ...(appConfigSelect.ui?.select || {}) })
|
|
15
16
|
|
|
16
17
|
export interface SelectItem {
|
|
17
18
|
label?: string
|
|
@@ -128,11 +129,11 @@ const emits = defineEmits<SelectEmits<T, V, M>>()
|
|
|
128
129
|
const slots = defineSlots<SelectSlots<T, M>>()
|
|
129
130
|
|
|
130
131
|
const appConfig = useAppConfig()
|
|
131
|
-
const rootProps = useForwardPropsEmits(reactivePick(props, '
|
|
132
|
+
const rootProps = useForwardPropsEmits(reactivePick(props, 'open', 'defaultOpen', 'disabled', 'autocomplete', 'required', 'multiple'), emits)
|
|
132
133
|
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as SelectContentProps)
|
|
133
134
|
const arrowProps = toRef(() => props.arrow as SelectArrowProps)
|
|
134
135
|
|
|
135
|
-
const { emitFormChange, emitFormInput, emitFormBlur, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
|
136
|
+
const { emitFormChange, emitFormInput, emitFormBlur, emitFormFocus, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
|
|
136
137
|
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
|
137
138
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
|
|
138
139
|
|
|
@@ -158,7 +159,7 @@ function displayValue(value?: AcceptableValue | AcceptableValue[]): string | und
|
|
|
158
159
|
return value.map(v => displayValue(v)).filter(Boolean).join(', ')
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
const item = items.value.find(item => compare(typeof item === 'object' ? get(item, props.valueKey as string) : item, value))
|
|
162
|
+
const item = items.value.find(item => compare(typeof item === 'object' ? get(item as Record<string, any>, props.valueKey as string) : item, value))
|
|
162
163
|
return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
|
|
163
164
|
}
|
|
164
165
|
|
|
@@ -178,6 +179,7 @@ function onUpdateOpen(value: boolean) {
|
|
|
178
179
|
} else {
|
|
179
180
|
const event = new FocusEvent('focus')
|
|
180
181
|
emits('focus', event)
|
|
182
|
+
emitFormFocus()
|
|
181
183
|
}
|
|
182
184
|
}
|
|
183
185
|
</script>
|
|
@@ -185,16 +187,17 @@ function onUpdateOpen(value: boolean) {
|
|
|
185
187
|
<!-- eslint-disable vue/no-template-shadow -->
|
|
186
188
|
<template>
|
|
187
189
|
<SelectRoot
|
|
188
|
-
:id="id"
|
|
189
190
|
v-slot="{ modelValue, open }"
|
|
190
|
-
v-bind="rootProps"
|
|
191
191
|
:name="name"
|
|
192
|
+
v-bind="rootProps"
|
|
192
193
|
:autocomplete="autocomplete"
|
|
193
194
|
:disabled="disabled"
|
|
195
|
+
:default-value="(defaultValue as (AcceptableValue | AcceptableValue[] | undefined))"
|
|
196
|
+
:model-value="(modelValue as (AcceptableValue | AcceptableValue[] | undefined))"
|
|
194
197
|
@update:model-value="onUpdate"
|
|
195
198
|
@update:open="onUpdateOpen"
|
|
196
199
|
>
|
|
197
|
-
<SelectTrigger :class="ui.base({ class: [props.class, props.ui?.base] })">
|
|
200
|
+
<SelectTrigger :id="id" :class="ui.base({ class: [props.class, props.ui?.base] })" v-bind="ariaAttrs">
|
|
198
201
|
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
|
199
202
|
<slot name="leading" :model-value="(modelValue as M extends true ? AcceptableValue[] : AcceptableValue)" :open="open" :ui="ui">
|
|
200
203
|
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { VariantProps } from 'tailwind-variants'
|
|
3
3
|
import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, ComboboxArrowProps, AcceptableValue } from 'reka-ui'
|
|
4
4
|
import type { AppConfig } from '@nuxt/schema'
|
|
5
5
|
import _appConfig from '#build/app.config'
|
|
6
6
|
import theme from '#build/ui/select-menu'
|
|
7
7
|
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
|
|
8
8
|
import { extendDevtoolsMeta } from '../composables/extendDevtoolsMeta'
|
|
9
|
+
import { tv } from '../utils/tv'
|
|
9
10
|
import type { AvatarProps, ChipProps, InputProps } from '../types'
|
|
10
11
|
import type { PartialString, MaybeArrayOfArray, MaybeArrayOfArrayItem, SelectModelValue, SelectModelValueEmits, SelectItemKey } from '../types/utils'
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
+
const appConfigSelectMenu = _appConfig as AppConfig & { ui: { selectMenu: Partial<typeof theme> } }
|
|
13
14
|
|
|
14
|
-
const selectMenu = tv({ extend: tv(theme), ...(
|
|
15
|
+
const selectMenu = tv({ extend: tv(theme), ...(appConfigSelectMenu.ui?.selectMenu || {}) })
|
|
15
16
|
|
|
16
17
|
export interface SelectMenuItem {
|
|
17
18
|
label?: string
|
|
@@ -150,7 +151,8 @@ import UInput from './Input.vue'
|
|
|
150
151
|
const props = withDefaults(defineProps<SelectMenuProps<T, I, V, M>>(), {
|
|
151
152
|
portal: true,
|
|
152
153
|
searchInput: true,
|
|
153
|
-
labelKey: 'label' as never
|
|
154
|
+
labelKey: 'label' as never,
|
|
155
|
+
resetSearchTermOnBlur: true
|
|
154
156
|
})
|
|
155
157
|
const emits = defineEmits<SelectMenuEmits<T, V, M>>()
|
|
156
158
|
const slots = defineSlots<SelectMenuSlots<T, M>>()
|
|
@@ -164,9 +166,9 @@ const { contains } = useFilter({ sensitivity: 'base' })
|
|
|
164
166
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover'), emits)
|
|
165
167
|
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
|
|
166
168
|
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
|
167
|
-
const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: '
|
|
169
|
+
const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t('selectMenu.search'), variant: 'none' }) as InputProps)
|
|
168
170
|
|
|
169
|
-
const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
|
171
|
+
const { emitFormBlur, emitFormFocus, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled, ariaAttrs } = useFormField<InputProps>(props)
|
|
170
172
|
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
|
171
173
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(toRef(() => defu(props, { trailingIcon: appConfig.ui.icons.chevronDown })))
|
|
172
174
|
|
|
@@ -194,7 +196,7 @@ function displayValue(value: T | T[]): string {
|
|
|
194
196
|
return value && (typeof value === 'object' ? get(value, props.labelKey as string) : value)
|
|
195
197
|
}
|
|
196
198
|
|
|
197
|
-
const item = items.value.find(item => compare(typeof item === 'object' ? get(item, props.valueKey as string) : item, value))
|
|
199
|
+
const item = items.value.find(item => compare(typeof item === 'object' ? get(item as Record<string, any>, props.valueKey as string) : item, value))
|
|
198
200
|
return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
|
|
199
201
|
}
|
|
200
202
|
|
|
@@ -250,13 +252,28 @@ function onUpdate(value: any) {
|
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
function onUpdateOpen(value: boolean) {
|
|
255
|
+
let timeoutId
|
|
256
|
+
|
|
253
257
|
if (!value) {
|
|
254
258
|
const event = new FocusEvent('blur')
|
|
259
|
+
|
|
255
260
|
emits('blur', event)
|
|
256
261
|
emitFormBlur()
|
|
262
|
+
|
|
263
|
+
// Since we use `displayValue` prop inside ComboboxInput we should reset searchTerm manually
|
|
264
|
+
// https://reka-ui.com/docs/components/combobox#api-reference
|
|
265
|
+
if (props.resetSearchTermOnBlur) {
|
|
266
|
+
const STATE_ANIMATION_DELAY_MS = 100
|
|
267
|
+
|
|
268
|
+
timeoutId = setTimeout(() => {
|
|
269
|
+
searchTerm.value = ''
|
|
270
|
+
}, STATE_ANIMATION_DELAY_MS)
|
|
271
|
+
}
|
|
257
272
|
} else {
|
|
258
273
|
const event = new FocusEvent('focus')
|
|
259
274
|
emits('focus', event)
|
|
275
|
+
emitFormFocus()
|
|
276
|
+
clearTimeout(timeoutId)
|
|
260
277
|
}
|
|
261
278
|
}
|
|
262
279
|
</script>
|
|
@@ -282,7 +299,7 @@ function onUpdateOpen(value: boolean) {
|
|
|
282
299
|
<ComboboxRoot
|
|
283
300
|
:id="id"
|
|
284
301
|
v-slot="{ modelValue, open }"
|
|
285
|
-
v-bind="rootProps"
|
|
302
|
+
v-bind="{ ...rootProps, ...ariaAttrs }"
|
|
286
303
|
ignore-filter
|
|
287
304
|
as-child
|
|
288
305
|
:name="name"
|