Skip to content

Commit c42c2ab

Browse files
committed
feat(ContentNavigation): handle collapsible false with type multiple
1 parent 3ed3fa9 commit c42c2ab

File tree

5 files changed

+74
-7
lines changed

5 files changed

+74
-7
lines changed

docs/app/layouts/docs.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const { navigationByCategory } = useNavigation(navigation!)
1616
<UPageAside>
1717
<UContentNavigation
1818
:key="route.path"
19+
:collapsible="false"
1920
:navigation="navigationByCategory"
2021
highlight
2122
:ui="{

src/runtime/components/content/ContentNavigation.vue

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ export interface ContentNavigationProps<T extends ContentNavigationLink = Conten
6767
*/
6868
highlightColor?: ContentNavigation['variants']['highlightColor']
6969
/**
70-
* When type is "single", allows closing content when clicking trigger for an open item.
71-
* When type is "multiple", this prop has no effect.
70+
* When type is "single", prevents closing the open item when clicking its trigger.
71+
* When type is "multiple", disables the collapsible behavior.
7272
* @defaultValue true
7373
*/
7474
collapsible?: boolean
@@ -118,7 +118,7 @@ const props = withDefaults(defineProps<ContentNavigationProps<T>>(), {
118118
const emits = defineEmits<ContentNavigationEmits>()
119119
const slots = defineSlots<ContentNavigationSlots<T>>()
120120
121-
const rootProps = useForwardPropsEmits(reactivePick(props, 'collapsible', 'disabled', 'type', 'unmountOnHide'), emits)
121+
const rootProps = useForwardPropsEmits(reactivePick(props, 'collapsible', 'type', 'unmountOnHide'), emits)
122122
123123
const route = useRoute()
124124
const appConfig = useAppConfig() as ContentNavigation['AppConfig']
@@ -132,6 +132,8 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.contentNavig
132132
highlightColor: props.highlightColor || props.color
133133
}))
134134
135+
const disabled = computed(() => props.disabled || (props.type === 'multiple' && props.collapsible === false))
136+
135137
const defaultValue = computed(() => {
136138
// When `defaultOpen` is `false`, return `undefined` to close all items
137139
if (props.defaultOpen === false) {
@@ -182,14 +184,14 @@ const defaultValue = computed(() => {
182184
</DefineLinkTemplate>
183185

184186
<Primitive :as="as" v-bind="$attrs" :as-child="level > 0" :class="ui.root({ class: [props.ui?.root, props.class] })">
185-
<AccordionRoot as="ul" v-bind="rootProps" :default-value="defaultValue" :class="level > 0 ? ui.listWithChildren({ class: props.ui?.listWithChildren }) : ui.list({ class: props.ui?.list })">
187+
<AccordionRoot as="ul" :disabled="disabled" v-bind="rootProps" :default-value="defaultValue" :class="level > 0 ? ui.listWithChildren({ class: props.ui?.listWithChildren }) : ui.list({ class: props.ui?.list })">
186188
<template v-for="(link, index) in navigation" :key="index">
187189
<AccordionItem v-if="link.children?.length" as="li" :class="ui.itemWithChildren({ class: [props.ui?.itemWithChildren, link.ui?.itemWithChildren], level: level > 0 })" :value="String(index)">
188190
<AccordionTrigger
189191
as="button"
190192
:class="[
191-
ui.link({ class: [props.ui?.link, link.ui?.link, link.class], active: link.active, disabled: !!link.disabled }),
192-
ui.trigger({ class: [props.ui?.trigger, link.ui?.trigger] })
193+
ui.link({ class: [props.ui?.link, link.ui?.link, link.class], active: link.active, disabled: !!link.disabled || disabled }),
194+
ui.trigger({ class: [props.ui?.trigger, link.ui?.trigger], disabled })
193195
]"
194196
>
195197
<ReuseLinkTemplate :link="link" :active="link.active" />

src/theme/content/content-navigation.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export default (options: Required<NuxtOptions['ui']>) => ({
4848
},
4949
disabled: {
5050
true: {
51-
link: 'cursor-not-allowed opacity-75'
51+
trigger: 'data-[state=open]:text-highlighted'
5252
}
5353
},
5454
highlight: {
@@ -102,6 +102,7 @@ export default (options: Required<NuxtOptions['ui']>) => ({
102102
variant: 'pill',
103103
active: true,
104104
highlight: true,
105+
disabled: false,
105106
class: {
106107
link: ['hover:before:bg-elevated/50', options.theme.transitions && 'before:transition-colors']
107108
}

test/components/content/ContentNavigation.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ describe('ContentNavigation', () => {
5353
['with navigation', { props }],
5454
['with defaultOpen', { props, defaultOpen: true }],
5555
['without defaultOpen', { props, defaultOpen: false }],
56+
['without collapsible', { props, collapsible: false }],
5657
...variants.map((variant: string) => [`with primary variant ${variant}`, { props: { ...props, variant } }]),
5758
...variants.map((variant: string) => [`with neutral variant ${variant}`, { props: { ...props, variant, color: 'neutral' } }]),
5859
...variants.map((variant: string) => [`with primary variant ${variant} highlight`, { props: { ...props, variant, highlight: true } }]),

test/components/content/__snapshots__/ContentNavigation.spec.ts.snap

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,68 @@ exports[`ContentNavigation > renders with ui correctly 1`] = `
12401240
</nav>"
12411241
`;
12421242

1243+
exports[`ContentNavigation > renders without collapsible correctly 1`] = `
1244+
"<nav>
1245+
<ul class="isolate -mx-2.5 -mt-1.5">
1246+
<li data-state="open" data-orientation="vertical" class="flex flex-col data-[state=open]:mb-1.5"><button type="button" aria-controls="" aria-expanded="true" data-state="open" id="reka-accordion-trigger-v-0-0-0" data-reka-collection-item="" data-orientation="vertical" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors font-semibold focus-visible:ring-primary">
1247+
<!--v-if--><span class="truncate">Getting Started<!--v-if--></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="font-medium inline-flex items-center text-[10px]/3 px-1.5 py-1 gap-1 rounded-sm ring ring-inset ring-accented text-default bg-default shrink-0"><!--v-if--><span class="truncate">New</span>
1248+
<!--v-if--></span><span class="iconify i-lucide:chevron-down size-5 transform transition-transform duration-200 shrink-0 group-data-[state=open]:rotate-180" aria-hidden="true"></span></span>
1249+
</button>
1250+
<div role="region" aria-labelledby="reka-accordion-trigger-v-0-0-0" data-orientation="vertical" style="--reka-accordion-content-width: var(--reka-collapsible-content-width); --reka-accordion-content-height: var(--reka-collapsible-content-height); --reka-collapsible-content-height: 0px; --reka-collapsible-content-width: 0px; transition-duration: 0s; animation-name: none;" class="data-[state=open]:animate-[accordion-down_200ms_ease-out] data-[state=closed]:animate-[accordion-up_200ms_ease-out] overflow-hidden focus:outline-none" id="reka-collapsible-content-v-0-0-1">
1251+
<!---->
1252+
<ul class="ms-5 border-s border-default">
1253+
<li class="ps-1.5 -ms-px"><a href="/getting-started" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary font-medium text-primary before:bg-elevated">
1254+
<!--v-if--><span class="truncate">Introduction<!--v-if--></span>
1255+
<!--v-if-->
1256+
</a></li>
1257+
<li class="ps-1.5 -ms-px"><a href="/getting-started/installation" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1258+
<!--v-if--><span class="truncate">Installation<!--v-if--></span>
1259+
<!--v-if-->
1260+
</a></li>
1261+
<li class="ps-1.5 -ms-px"><a href="/getting-started/theming" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1262+
<!--v-if--><span class="truncate">Theming<!--v-if--></span>
1263+
<!--v-if-->
1264+
</a></li>
1265+
<li class="ps-1.5 -ms-px"><a href="/getting-started/structure" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1266+
<!--v-if--><span class="truncate">Structure<!--v-if--></span>
1267+
<!--v-if-->
1268+
</a></li>
1269+
<li class="ps-1.5 -ms-px"><a href="/getting-started/content" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1270+
<!--v-if--><span class="truncate">Content<!--v-if--></span>
1271+
<!--v-if-->
1272+
</a></li>
1273+
</ul>
1274+
</div>
1275+
</li>
1276+
<li data-state="open" data-orientation="vertical" class="flex flex-col data-[state=open]:mb-1.5"><button type="button" aria-controls="" aria-expanded="true" data-state="open" id="reka-accordion-trigger-v-0-0-2" data-reka-collection-item="" data-orientation="vertical" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors font-semibold focus-visible:ring-primary">
1277+
<!--v-if--><span class="truncate">Components<!--v-if--></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><span class="iconify i-lucide:chevron-down size-5 transform transition-transform duration-200 shrink-0 group-data-[state=open]:rotate-180" aria-hidden="true"></span></span>
1278+
</button>
1279+
<div role="region" aria-labelledby="reka-accordion-trigger-v-0-0-2" data-orientation="vertical" style="--reka-accordion-content-width: var(--reka-collapsible-content-width); --reka-accordion-content-height: var(--reka-collapsible-content-height); --reka-collapsible-content-height: 0px; --reka-collapsible-content-width: 0px; transition-duration: 0s; animation-name: none;" class="data-[state=open]:animate-[accordion-down_200ms_ease-out] data-[state=closed]:animate-[accordion-up_200ms_ease-out] overflow-hidden focus:outline-none" id="reka-collapsible-content-v-0-0-3">
1280+
<!---->
1281+
<ul class="ms-5 border-s border-default">
1282+
<li class="ps-1.5 -ms-px"><a href="/components/content-navigation" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1283+
<!--v-if--><span class="truncate">ContentNavigation<!--v-if--></span>
1284+
<!--v-if-->
1285+
</a></li>
1286+
<li class="ps-1.5 -ms-px"><a href="/components/content-search" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1287+
<!--v-if--><span class="truncate">ContentSearch<!--v-if--></span>
1288+
<!--v-if-->
1289+
</a></li>
1290+
<li class="ps-1.5 -ms-px"><a href="/components/content-surround" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1291+
<!--v-if--><span class="truncate">ContentSurround<!--v-if--></span>
1292+
<!--v-if-->
1293+
</a></li>
1294+
<li class="ps-1.5 -ms-px"><a href="/components/content-toc" class="group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2 focus-visible:before:ring-primary text-muted hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted transition-colors before:transition-colors">
1295+
<!--v-if--><span class="truncate">ContentToc<!--v-if--></span>
1296+
<!--v-if-->
1297+
</a></li>
1298+
</ul>
1299+
</div>
1300+
</li>
1301+
</ul>
1302+
</nav>"
1303+
`;
1304+
12431305
exports[`ContentNavigation > renders without defaultOpen correctly 1`] = `
12441306
"<nav>
12451307
<ul class="isolate -mx-2.5 -mt-1.5">

0 commit comments

Comments
 (0)