11<!-- eslint-disable vue/block-tag-newline -->
22<script lang="ts">
3- import type { NavigationMenuRootProps , NavigationMenuRootEmits , NavigationMenuContentProps , NavigationMenuContentEmits , AccordionRootProps } from ' reka-ui'
3+ import type { NavigationMenuRootProps , NavigationMenuContentProps , NavigationMenuContentEmits , AccordionRootProps } from ' reka-ui'
44import type { AppConfig } from ' @nuxt/schema'
55import theme from ' #build/ui/navigation-menu'
66import type { AvatarProps , BadgeProps , IconProps , LinkProps , PopoverProps , TooltipProps } from ' ../types'
@@ -63,12 +63,49 @@ export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
6363 [key : string ]: any
6464}
6565
66- export interface NavigationMenuProps <T extends ArrayOrNested <NavigationMenuItem > = ArrayOrNested <NavigationMenuItem >> extends Pick <NavigationMenuRootProps , ' modelValue' | ' defaultValue' | ' delayDuration' | ' disableClickTrigger' | ' disableHoverTrigger' | ' skipDelayDuration' | ' disablePointerLeaveClose' | ' unmountOnHide' >, Pick <AccordionRootProps , ' disabled' | ' type' | ' collapsible' > {
66+ type SingleOrMultipleType = ' single' | ' multiple'
67+ type Orientation = NavigationMenuRootProps [' orientation' ]
68+
69+ type NavigationMenuModelValue <
70+ K extends SingleOrMultipleType = SingleOrMultipleType ,
71+ O extends Orientation = Orientation
72+ > = O extends ' horizontal' ? string : K extends ' single' ? string : K extends ' multiple' ? string [] : string | string []
73+
74+ export interface NavigationMenuProps <
75+ T extends ArrayOrNested <NavigationMenuItem > = ArrayOrNested <NavigationMenuItem >,
76+ K extends SingleOrMultipleType = SingleOrMultipleType ,
77+ O extends Orientation = Orientation
78+ > extends Pick <NavigationMenuRootProps , ' delayDuration' | ' disableClickTrigger' | ' disableHoverTrigger' | ' skipDelayDuration' | ' disablePointerLeaveClose' | ' unmountOnHide' >, Pick <AccordionRootProps , ' disabled' | ' collapsible' > {
6779 /**
6880 * The element or component this component should render as.
6981 * @defaultValue 'div'
7082 */
7183 as? : any
84+ /**
85+ * Determines whether a "single" or "multiple" items can be selected at a time.
86+ *
87+ * Only works when `orientation` is `vertical`.
88+ * @defaultValue 'multiple'
89+ */
90+ type? : K
91+ /**
92+ * The controlled value of the active item(s).
93+ * - In horizontal orientation: always `string`
94+ * - In vertical orientation with `type="single"`: `string`
95+ * - In vertical orientation with `type="multiple"`: `string[]`
96+ *
97+ * Use this when you need to control the state of the items. Can be binded with `v-model`
98+ */
99+ modelValue? : NavigationMenuModelValue <K , O >
100+ /**
101+ * The default active value of the item(s).
102+ * - In horizontal orientation: always `string`
103+ * - In vertical orientation with `type="single"`: `string`
104+ * - In vertical orientation with `type="multiple"`: `string[]`
105+ *
106+ * Use when you do not need to control the state of the item(s).
107+ */
108+ defaultValue? : NavigationMenuModelValue <K , O >
72109 /**
73110 * The icon displayed to open the menu.
74111 * @defaultValue appConfig.ui.icons.chevronDown
@@ -95,7 +132,7 @@ export interface NavigationMenuProps<T extends ArrayOrNested<NavigationMenuItem>
95132 * The orientation of the menu.
96133 * @defaultValue 'horizontal'
97134 */
98- orientation? : NavigationMenuRootProps [ ' orientation ' ]
135+ orientation? : O
99136 /**
100137 * Collapse the navigation menu to only show icons.
101138 * Only works when `orientation` is `vertical`.
@@ -142,7 +179,18 @@ export interface NavigationMenuProps<T extends ArrayOrNested<NavigationMenuItem>
142179 ui? : NavigationMenu [' slots' ]
143180}
144181
145- export interface NavigationMenuEmits extends NavigationMenuRootEmits {}
182+ export type NavigationMenuEmits <
183+ K extends SingleOrMultipleType = SingleOrMultipleType ,
184+ O extends Orientation = Orientation
185+ > = {
186+ /**
187+ * Event handler called when the value changes.
188+ * - In horizontal orientation: emits `string`
189+ * - In vertical orientation with `type="single"`: emits `string | undefined`
190+ * - In vertical orientation with `type="multiple"`: emits `string[] | undefined`
191+ */
192+ ' update:modelValue' : [value : NavigationMenuModelValue <K , O > | undefined ]
193+ }
146194
147195type SlotProps <T extends NavigationMenuItem > = (props : { item: T , index: number , active? : boolean , ui: NavigationMenu [' ui' ] }) => any
148196
@@ -163,7 +211,7 @@ export type NavigationMenuSlots<
163211
164212 </script >
165213
166- <script setup lang="ts" generic =" T extends ArrayOrNested <NavigationMenuItem >" >
214+ <script setup lang="ts" generic =" T extends ArrayOrNested <NavigationMenuItem >, K extends SingleOrMultipleType = SingleOrMultipleType , O extends Orientation = Orientation " >
167215import { computed , toRef } from ' vue'
168216import { NavigationMenuRoot , NavigationMenuList , NavigationMenuItem , NavigationMenuTrigger , NavigationMenuContent , NavigationMenuLink , NavigationMenuIndicator , NavigationMenuViewport , AccordionRoot , AccordionItem , AccordionTrigger , AccordionContent , useForwardPropsEmits } from ' reka-ui'
169217import { defu } from ' defu'
@@ -182,25 +230,23 @@ import UTooltip from './Tooltip.vue'
182230
183231defineOptions ({ inheritAttrs: false })
184232
185- const props = withDefaults (defineProps <NavigationMenuProps <T >>(), {
186- orientation: ' horizontal' ,
233+ const props = withDefaults (defineProps <NavigationMenuProps <T , K , O >>(), {
234+ orientation: ' horizontal' as never ,
187235 contentOrientation: ' horizontal' ,
188236 externalIcon: true ,
189237 delayDuration: 0 ,
190- type: ' multiple' ,
238+ type: ' multiple' as never ,
191239 collapsible: true ,
192240 unmountOnHide: true ,
193241 labelKey: ' label'
194242})
195- const emits = defineEmits <NavigationMenuEmits >()
243+ const emits = defineEmits <NavigationMenuEmits < K , O > >()
196244const slots = defineSlots <NavigationMenuSlots <T >>()
197245
198246const appConfig = useAppConfig () as NavigationMenu [' AppConfig' ]
199247
200248const rootProps = useForwardPropsEmits (computed (() => ({
201249 as: props .as ,
202- modelValue: props .modelValue ,
203- defaultValue: props .defaultValue ,
204250 delayDuration: props .delayDuration ,
205251 skipDelayDuration: props .skipDelayDuration ,
206252 orientation: props .orientation ,
@@ -415,14 +461,27 @@ function getAccordionDefaultValue(list: NavigationMenuItem[], level = 0) {
415461 </component >
416462 </DefineItemTemplate >
417463
418- <NavigationMenuRoot v-bind =" { ...rootProps, ...$attrs }" :data-collapsed =" collapsed" data-slot =" root" :class =" ui.root({ class: [props.ui?.root, props.class] })" >
464+ <NavigationMenuRoot
465+ v-bind =" {
466+ ...rootProps,
467+ ...(orientation === 'horizontal' ? {
468+ modelValue: modelValue as string,
469+ defaultValue: defaultValue as string
470+ } : {}),
471+ ...$attrs
472+ }"
473+ :data-collapsed =" collapsed"
474+ data-slot =" root"
475+ :class =" ui.root({ class: [props.ui?.root, props.class] })"
476+ >
419477 <slot name =" list-leading" />
420478
421479 <template v-for =" (list , listIndex ) in lists " :key =" ` list-${listIndex } ` " >
422480 <component
423481 v-bind =" orientation === 'vertical' && !collapsed ? {
424482 ...accordionProps,
425- defaultValue: getAccordionDefaultValue(list)
483+ modelValue,
484+ defaultValue: defaultValue ?? getAccordionDefaultValue(list)
426485 } : {}"
427486 :is =" orientation === 'vertical' && !collapsed ? AccordionRoot : NavigationMenuList"
428487 as =" ul"
0 commit comments