Skip to content

Commit ffe3825

Browse files
Jonathan de FlaugerguesJonathan de Flaugergues
authored andcommitted
feat(VBreadcrumbs): add list-item slot for customizing collapsed menu
1 parent c77b459 commit ffe3825

File tree

5 files changed

+123
-16
lines changed

5 files changed

+123
-16
lines changed

packages/api-generator/src/locale/en/VBreadcrumbs.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"slots": {
1313
"divider": "The slot used for dividers.",
1414
"prepend": "The slot used for prepend content.",
15-
"title": "The slot used to display the title of each breadcrumb."
15+
"title": "The slot used to display the title of each breadcrumb.",
16+
"listItem": "The slot used for customizing each item inside the contextual menu when breadcrumbs items are collapsed."
1617
}
1718
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<template>
2+
<v-breadcrumbs :items="items" :total-visible="3" collapse-in-menu>
3+
<template v-slot:list-item="{ item, index }">
4+
<v-list-item :key="index" :disabled="item.disabled" :href="item.href">
5+
<v-list-item-title>
6+
<span v-if="item.disabled">🔒 </span>{{ item.title }}
7+
</v-list-item-title>
8+
</v-list-item>
9+
</template>
10+
</v-breadcrumbs>
11+
</template>
12+
13+
<script setup>
14+
const items = [
15+
{
16+
title: 'Dashboard',
17+
disabled: false,
18+
href: 'breadcrumbs_dashboard',
19+
},
20+
{
21+
title: 'Link 1',
22+
disabled: false,
23+
href: 'breadcrumbs_link_1',
24+
},
25+
{
26+
title: 'Link 2',
27+
disabled: true,
28+
href: 'breadcrumbs_link_2',
29+
},
30+
{
31+
title: 'Link 3',
32+
disabled: false,
33+
href: 'breadcrumbs_link_3',
34+
},
35+
{
36+
title: 'Link 4',
37+
disabled: true,
38+
href: 'breadcrumbs_link_4',
39+
},
40+
]
41+
</script>
42+
43+
<script>
44+
export default {
45+
data: () => ({
46+
items: [
47+
{
48+
title: 'Dashboard',
49+
disabled: false,
50+
href: 'breadcrumbs_dashboard',
51+
},
52+
{
53+
title: 'Link 1',
54+
disabled: false,
55+
href: 'breadcrumbs_link_1',
56+
},
57+
{
58+
title: 'Link 2',
59+
disabled: false,
60+
href: 'breadcrumbs_link_2',
61+
},
62+
{
63+
title: 'Link 3',
64+
disabled: false,
65+
href: 'breadcrumbs_link_3',
66+
},
67+
{
68+
title: 'Link 4',
69+
disabled: true,
70+
href: 'breadcrumbs_link_4',
71+
},
72+
],
73+
}),
74+
}
75+
</script>

packages/docs/src/pages/en/components/breadcrumbs.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,10 @@ You can use the `totalVisible` prop to redefine the maximum number of breadcrumb
9090
You can use the `collapseInMenu` prop to display the collapsed breadcrumb items inside a dropdown menu.
9191

9292
<ExamplesExample file="v-breadcrumbs/slot-collapse-in-menu" />
93+
94+
#### Collapsed with custom menu
95+
96+
You can use the `list-item` slot to customize how each breadcrumb item is rendered inside the collapsed menu when `collapseInMenu` is enabled.
97+
98+
<ExamplesExample file="v-breadcrumbs/slot-list-item" />
99+

packages/vuetify/playgrounds/Playground.breadcrumbs.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33
<v-container>
44
<v-breadcrumbs :items="items" :total-visible="3" />
55
<v-breadcrumbs :items="items" :total-visible="3" collapse-in-menu />
6+
<v-breadcrumbs :items="items" :total-visible="3" collapse-in-menu>
7+
<template v-slot:list-item="{ item, index }">
8+
<v-list-item :key="index" :disabled="item.disabled" :href="item.href">
9+
<v-list-item-title>
10+
<span v-if="item.disabled">🔒 </span>{{ item.title }}
11+
</v-list-item-title>
12+
</v-list-item>
13+
</template>
14+
</v-breadcrumbs>
615
</v-container>
716
</v-app>
817
</template>
@@ -11,7 +20,7 @@
1120
export default {
1221
name: 'Playground',
1322
data: () => ({
14-
items: Array.from({ length: 4 }, (k, v) => ({ title: `Link ${v + 1}`, href: `breadcrumbs_link_${v + 1}` })),
23+
items: Array.from({ length: 4 }, (k, v) => ({ title: `Link ${v + 1}`, href: `breadcrumbs_link_${v + 1}`, disabled: v === 2 })),
1524
}),
1625
}
1726
</script>

packages/vuetify/src/components/VBreadcrumbs/VBreadcrumbs.tsx

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ export const makeVBreadcrumbsProps = propsFactory({
5555
default: () => ([]),
5656
},
5757
itemProps: Boolean,
58+
listProps: {
59+
type: Object as PropType<VList['$props']>,
60+
},
61+
menuProps: {
62+
type: Object as PropType<VMenu['$props']>,
63+
},
5864
totalVisible: Number,
5965

6066
...makeComponentProps(),
@@ -72,6 +78,7 @@ export const VBreadcrumbs = genericComponent<new <T extends BreadcrumbItem>(
7278
title: { item: InternalBreadcrumbItem, index: number }
7379
divider: { item: T, index: number }
7480
item: { item: InternalBreadcrumbItem, index: number }
81+
'list-item': { item: InternalBreadcrumbItem, index: number }
7582
default: never
7683
}
7784
) => GenericProps<typeof props, typeof slots>>()({
@@ -99,15 +106,15 @@ export const VBreadcrumbs = genericComponent<new <T extends BreadcrumbItem>(
99106
const items = computed(() => props.items.map(item => {
100107
return typeof item === 'string' ? { item: { title: item }, raw: item } : { item, raw: item }
101108
}))
102-
const showEllipsis = toRef(() => props.totalVisible ? items.value.length > props.totalVisible : false)
103-
const enableEllipsis = ref(showEllipsis.value)
109+
const ellipsisEnabled = toRef(() => props.totalVisible ? items.value.length > props.totalVisible : false)
110+
const hasEllipsis = ref(ellipsisEnabled.value)
104111

105112
const onClickEllipsis = () => {
106-
enableEllipsis.value = false
113+
hasEllipsis.value = false
107114
}
108115

109-
watch(showEllipsis, (value: boolean) => {
110-
enableEllipsis.value = value
116+
watch(ellipsisEnabled, (value: boolean) => {
117+
hasEllipsis.value = value
111118
})
112119

113120
useRender(() => {
@@ -153,7 +160,7 @@ export const VBreadcrumbs = genericComponent<new <T extends BreadcrumbItem>(
153160
</li>
154161
)}
155162

156-
{ !enableEllipsis.value && items.value.map(({ item, raw }, index, array) => (
163+
{ !hasEllipsis.value && items.value.map(({ item, raw }, index, array) => (
157164
<>
158165
{ slots.item?.({ item, index }) ?? (
159166
<VBreadcrumbsItem
@@ -177,7 +184,7 @@ export const VBreadcrumbs = genericComponent<new <T extends BreadcrumbItem>(
177184
</>
178185
))}
179186

180-
{ enableEllipsis.value && (
187+
{ hasEllipsis.value && (
181188
<>
182189
{ (() => {
183190
const { item } = items.value[0]
@@ -202,15 +209,23 @@ export const VBreadcrumbs = genericComponent<new <T extends BreadcrumbItem>(
202209
>
203210
{ props.ellipsis }
204211
{ props.collapseInMenu ? (
205-
<VMenu activator="parent">
212+
<VMenu
213+
activator="parent"
214+
{ ...props.menuProps }
215+
>
206216
{{
207217
default: () => (
208-
<VList>
209-
{ items.value.slice(1, items.value.length - 1).map(({ item }, index) => (
210-
<VListItem key={ index } value={ index } component="a" href={ 'href' in item ? item.href : undefined }>
211-
<VListItemTitle>{ item.title }</VListItemTitle>
212-
</VListItem>
213-
))}
218+
<VList { ...props.listProps }>
219+
{ items.value.slice(1, items.value.length - 1).map(({ item }, index) => {
220+
if (slots['list-item']) {
221+
return slots['list-item']({ item, index })
222+
}
223+
return (
224+
<VListItem key={ index } value={ index } href={ 'href' in item ? item.href : undefined }>
225+
<VListItemTitle>{ item.title }</VListItemTitle>
226+
</VListItem>
227+
)
228+
})}
214229
</VList>
215230
),
216231
}}

0 commit comments

Comments
 (0)