Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(VList): add prependSpacer prop #20616

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from
1 change: 1 addition & 0 deletions packages/api-generator/src/locale/en/VList.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"nav": "An alternative styling that reduces `v-list-item` width and rounds the corners. Typically used with **[v-navigation-drawer](/components/navigation-drawers)**.",
"subheader": "Removes the top padding from `v-list-subheader` components. When used as a **String**, renders a subheader for you.",
"slim": "Reduces horizontal spacing for badges, icons, tooltips, and avatars within slim list items to create a more compact visual representation.",
"slimWidth": "Sets the horizontal spacing for badges, icons, tooltips, and avatars within slim list items to create a custom visual representation when slim is enabled.",
"collapseIcon": "Icon to display when the list item is expanded.",
"expandIcon": "Icon to display when the list item is collapsed.",
"selectable": "Designates whether the list items are selectable."
Expand Down
6 changes: 4 additions & 2 deletions packages/docs/src/examples/v-list/prop-sub-group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
<v-list v-model:opened="open">
<v-list-item prepend-icon="mdi-home" title="Home"></v-list-item>

<v-list-group value="Users">
<v-list-group
prepend-icon="mdi-account-circle"
value="Users"
>
<template v-slot:activator="{ props }">
<v-list-item
v-bind="props"
prepend-icon="mdi-account-circle"
title="Users"
></v-list-item>
</template>
Expand Down
27 changes: 27 additions & 0 deletions packages/docs/src/pages/en/components/lists.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,33 @@ Lists come in three main variations. **single-line** (default), **two-line** and

<ApiInline hide-links />

## Caveats

::: warning
To ensure proper indentation when using **v-list-group** with a **prepend-icon**, the **prepend-icon** must be applied directly to the **v-list-group** instead of its activator **v-list-item**.

For instance, the following example works:
```html
<template>
<v-list-group prepend-icon="mdi-home" >
<template v-slot:activator="{ props }">
<v-list-item v-bind="props"></v-list-item>
</template>
</v-list-group>
</template>
```
However, this one does not:
```html
<template>
<v-list-group>
<template v-slot:activator="{ props }">
<v-list-item v-bind="props" prepend-icon="mdi-home"></v-list-item>
</template>
</v-list-group>
</template>
```
:::

## Examples

### Props
Expand Down
13 changes: 11 additions & 2 deletions packages/vuetify/src/components/VList/VList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import { makeThemeProps, provideTheme } from '@/composables/theme'
import { makeVariantProps } from '@/composables/variant'

// Utilities
import { computed, ref, shallowRef, toRef } from 'vue'
import { EventProp, focusChild, genericComponent, getPropertyFromItem, omit, propsFactory, useRender } from '@/util'
import { computed, ref, shallowRef, toRef, watch } from 'vue'
import { convertToUnit, EventProp, focusChild, genericComponent, getPropertyFromItem, omit, propsFactory, useRender } from '@/util'

// Types
import type { PropType } from 'vue'
Expand Down Expand Up @@ -93,6 +93,7 @@ export const makeVListProps = propsFactory({
default: 'one',
},
slim: Boolean,
slimWidth: [Number, String],
nav: Boolean,

'onClick:open': EventProp<[{ id: unknown, value: boolean, path: unknown[] }]>(),
Expand Down Expand Up @@ -239,6 +240,14 @@ export const VList = genericComponent<new <
}
}

watch([contentRef, () => props.slimWidth], () => {
if (props.slimWidth && contentRef.value) {
const spacer = convertToUnit(props.slimWidth)

if (spacer) contentRef.value.style.setProperty('--v-list-slim-spacer-width', spacer)
}
}, { immediate: true })

useRender(() => {
return (
<props.tag
Expand Down
4 changes: 1 addition & 3 deletions packages/vuetify/src/components/VList/VListGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { VExpandTransition } from '@/components/transitions'
import { VDefaultsProvider } from '@/components/VDefaultsProvider'

// Composables
import { useList } from './list'
import { makeComponentProps } from '@/composables/component'
import { IconValue } from '@/composables/icons'
import { useNestedGroupActivator, useNestedItem } from '@/composables/nested/nested'
Expand Down Expand Up @@ -62,7 +61,6 @@ export const VListGroup = genericComponent<VListGroupSlots>()({
setup (props, { slots }) {
const { isOpen, open, id: _id } = useNestedItem(toRef(props, 'value'), true)
const id = computed(() => `v-list-group--id-${String(_id.value)}`)
const list = useList()
const { isBooted } = useSsrBoot()

function onClick (e: Event) {
Expand Down Expand Up @@ -95,8 +93,8 @@ export const VListGroup = genericComponent<VListGroupSlots>()({
class={[
'v-list-group',
{
'v-list-group--prepend': list?.hasPrepend.value,
'v-list-group--fluid': props.fluid,
'v-list-group--has-prepend-icon': props.prependIcon,
'v-list-group--subgroup': props.subgroup,
'v-list-group--open': isOpen.value,
},
Expand Down
9 changes: 3 additions & 6 deletions packages/vuetify/src/components/VList/VListItem.sass
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
> .v-icon,
> .v-tooltip
~ .v-list-item__spacer
width: $list-item-slim-spacer-width
width: var(--v-list-slim-spacer-width, $list-item-slim-spacer-width)

> .v-avatar,
> .v-badge:is(:has(.v-avatar))
Expand Down Expand Up @@ -133,7 +133,7 @@
> .v-icon,
> .v-tooltip
~ .v-list-item__spacer
width: $list-item-slim-spacer-width
width: var(--v-list-slim-spacer-width, $list-item-slim-spacer-width)

> .v-avatar,
> .v-badge:is(:has(.v-avatar))
Expand Down Expand Up @@ -313,12 +313,9 @@
&--fluid
--list-indent-size: 0px

&--prepend
&--has-prepend-icon
--parent-padding: calc(var(--indent-padding) + var(--prepend-width))

&--fluid.v-list-group--prepend
--parent-padding: var(--indent-padding)

.v-list-group__items
--indent-padding: calc(var(--parent-padding) + var(--list-indent-size))

Expand Down
1 change: 0 additions & 1 deletion packages/vuetify/src/components/VList/VListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ export const VListItem = genericComponent<VListItemSlots>()({
'v-list-item--disabled': props.disabled,
'v-list-item--link': isClickable.value,
'v-list-item--nav': props.nav,
'v-list-item--prepend': !hasPrepend && list?.hasPrepend.value,
'v-list-item--slim': props.slim,
[`${props.activeClass}`]: props.activeClass && isActive.value,
},
Expand Down
2 changes: 2 additions & 0 deletions packages/vuetify/src/labs/VTreeview/VTreeviewGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export const VTreeviewGroup = genericComponent<VListGroupSlots>()({
ref={ vListGroupRef }
class={[
'v-treeview-group',
// VTreeviewGroup always has an activator containing toggle icon in prepend
'v-list-group--has-prepend-icon',
props.class,
]}
subgroup
Expand Down
Loading