Skip to content

Commit

Permalink
feat(NavigationMenu): handle label type in items
Browse files Browse the repository at this point in the history
Resolves #2993
  • Loading branch information
benjamincanac committed Jan 16, 2025
1 parent 1e88512 commit 27fdc8e
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 104 deletions.
7 changes: 6 additions & 1 deletion docs/content/3.components/navigation-menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Use the `items` prop as an array of objects with the following properties:
- `avatar?: AvatarProps`{lang="ts-type"}
- `badge?: string | number | BadgeProps`{lang="ts-type"}
- `trailingIcon?: string`{lang="ts-type"}
- `type?: 'label' | 'link'`{lang="ts-type"}
- `value?: string`{lang="ts-type"}
- `disabled?: boolean`{lang="ts-type"}
- `class?: any`{lang="ts-type"}
Expand Down Expand Up @@ -138,7 +139,9 @@ Each item can take a `children` array of objects with the following properties t

Use the `orientation` prop to change the orientation of the NavigationMenu.

::note
When orientation is `vertical`, a [Collapsible](/components/collapsible) component is used to display children. You can control the open state of each item using the `open` and `defaultOpen` properties.
::

::component-code
---
Expand All @@ -151,7 +154,9 @@ external:
props:
orientation: 'vertical'
items:
- - label: Guide
- - label: Links
type: 'label'
- label: Guide
icon: i-lucide-book-open
children:
- label: Introduction
Expand Down
15 changes: 12 additions & 3 deletions src/runtime/components/NavigationMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ const appConfig = _appConfig as AppConfig & { ui: { navigationMenu: Partial<type
const navigationMenu = tv({ extend: tv(theme), ...(appConfig.ui?.navigationMenu || {}) })
export interface NavigationMenuChildItem extends Omit<NavigationMenuItem, 'children'> {
export interface NavigationMenuChildItem extends Omit<NavigationMenuItem, 'children' | 'type'> {
/** Description is only used when `orientation` is `horizontal`. */
description?: string
}
export interface NavigationMenuItem extends Omit<LinkProps, 'raw' | 'custom'>, Pick<CollapsibleRootProps, 'defaultOpen' | 'open'> {
export interface NavigationMenuItem extends Omit<LinkProps, 'type' | 'raw' | 'custom'>, Pick<CollapsibleRootProps, 'defaultOpen' | 'open'> {
label?: string
icon?: string
avatar?: AvatarProps
Expand All @@ -28,6 +28,12 @@ export interface NavigationMenuItem extends Omit<LinkProps, 'raw' | 'custom'>, P
*/
badge?: string | number | BadgeProps
trailingIcon?: string
/**
* The type of the item.
* The `label` type only works on `vertical` orientation.
* @defaultValue 'link'
*/
type?: 'label' | 'link'
slot?: string
value?: string
children?: NavigationMenuChildItem[]
Expand Down Expand Up @@ -224,7 +230,10 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
:open="item.open"
:class="ui.item({ class: props.ui?.item })"
>
<ULink v-slot="{ active, ...slotProps }" v-bind="(orientation === 'vertical' && item.children?.length) ? {} : pickLinkProps(item)" custom>
<div v-if="orientation === 'vertical' && item.type === 'label'" :class="ui.label({ class: props.ui?.label })">
<ReuseItemTemplate :item="(item as T)" :index="index" />
</div>
<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>
<component
:is="(orientation === 'horizontal' && (item.children?.length || !!slots[item.slot ? `${item.slot}-content` : 'item-content'])) ? NavigationMenuTrigger : NavigationMenuLink"
as-child
Expand Down
1 change: 1 addition & 0 deletions src/theme/navigation-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default (options: Required<ModuleOptions>) => ({
slots: {
root: 'relative flex gap-1.5 [&>div]:min-w-0',
list: 'isolate min-w-0',
label: 'w-full flex items-center gap-1.5 font-semibold text-xs/5 text-[var(--ui-text-highlighted)] px-2.5 py-1.5',
item: 'min-w-0',
link: 'group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-[calc(var(--ui-radius)*1.5)] focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2',
linkLeadingIcon: 'shrink-0 size-5',
Expand Down
3 changes: 3 additions & 0 deletions test/components/NavigationMenu.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ describe('NavigationMenu', () => {

const items = [
[{
label: 'Links',
type: 'label'
}, {
label: 'Documentation',
icon: 'i-lucide-book-open',
badge: 10,
Expand Down
Loading

0 comments on commit 27fdc8e

Please sign in to comment.