diff --git a/packages/vuetify/src/components/VList/VList.tsx b/packages/vuetify/src/components/VList/VList.tsx index 0749c1d298b..f2ef70e6ce6 100644 --- a/packages/vuetify/src/components/VList/VList.tsx +++ b/packages/vuetify/src/components/VList/VList.tsx @@ -132,7 +132,7 @@ export const VList = genericComponent() => { const { dimensionStyles } = useDimension(props) const { elevationClasses } = useElevation(props) const { roundedClasses } = useRounded(props) - const { open, select } = useNested(props) + const { open, select, getPath } = useNested(props) const lineClasses = computed(() => props.lines ? `v-list--${props.lines}-line` : undefined) const activeColor = toRef(props, 'activeColor') const color = toRef(props, 'color') @@ -258,6 +258,7 @@ export const VList = genericComponent() => { open, select, focus, + getPath, } }, }) diff --git a/packages/vuetify/src/components/VList/__tests__/VList.spec.cy.tsx b/packages/vuetify/src/components/VList/__tests__/VList.spec.cy.tsx index 26f646b42de..8cb4c41fa9b 100644 --- a/packages/vuetify/src/components/VList/__tests__/VList.spec.cy.tsx +++ b/packages/vuetify/src/components/VList/__tests__/VList.spec.cy.tsx @@ -229,4 +229,82 @@ describe('VList', () => { cy.get('.v-list-item').eq(1).should('not.have.class', 'v-list-item--active') }) + + it('should open selected items on mount', () => { + const items = [ + { + title: 'Foo', + subtitle: 'Bar', + value: 'foo', + }, + { + title: 'Group', + value: 'group', + children: [ + { + title: 'Child', + subtitle: 'Subtitle', + value: 'child', + children: [ + { + title: 'Another Child', + value: 'another_child', + }, + ], + }, + ], + }, + ] + + const wrapper = mountFunction(( + + + + )) + + wrapper.get('.v-list-item') + .should('have.length', 4) + .contains('Another Child') + .should('be.visible') + }) + + it('should open all items on mount', () => { + const items = [ + { + title: 'Foo', + subtitle: 'Bar', + value: 'foo', + children: [ + { + title: 'First', + value: 'first', + }, + ], + }, + { + title: 'Group', + value: 'group', + children: [ + { + title: 'Second', + value: 'second', + }, + ], + }, + ] + + const wrapper = mountFunction(( + + + + )) + + wrapper.get('.v-list-item') + .should('have.length', 4) + .contains('First') + .should('be.visible') + .get('.v-list-item') + .contains('Second') + .should('be.visible') + }) }) diff --git a/packages/vuetify/src/composables/nested/nested.ts b/packages/vuetify/src/composables/nested/nested.ts index b96b61a0442..6d7b02ebe6f 100644 --- a/packages/vuetify/src/composables/nested/nested.ts +++ b/packages/vuetify/src/composables/nested/nested.ts @@ -1,6 +1,6 @@ import { useProxiedModel } from '@/composables/proxiedModel' import { getCurrentInstance, getUid, propsFactory } from '@/util' -import { computed, inject, onBeforeUnmount, provide, ref, toRaw } from 'vue' +import { computed, inject, onBeforeUnmount, onMounted, provide, ref, toRaw } from 'vue' import { listOpenStrategy, multipleOpenStrategy, singleOpenStrategy } from './openStrategies' import { classicSelectStrategy, @@ -23,6 +23,7 @@ export interface NestedProps { openStrategy: OpenStrategyProp | undefined selected: unknown[] | undefined opened: unknown[] | undefined + openOnMount?: 'selected' | 'all' mandatory: boolean 'onUpdate:selected': ((val: unknown[]) => void) | undefined 'onUpdate:opened': ((val: unknown[]) => void) | undefined @@ -42,6 +43,7 @@ type NestedProvide = { open: (id: unknown, value: boolean, event?: Event) => void select: (id: unknown, value: boolean, event?: Event) => void openOnSelect: (id: unknown, value: boolean, event?: Event) => void + getPath: (id: unknown) => unknown[] } } @@ -60,6 +62,7 @@ export const emptyNested: NestedProvide = { opened: ref(new Set()), selected: ref(new Map()), selectedValues: ref([]), + getPath: () => [], }, } @@ -69,6 +72,9 @@ export const makeNestedProps = propsFactory({ opened: Array as PropType, selected: Array as PropType, mandatory: Boolean, + openOnMount: { + type: String as PropType<'selected' | 'all'>, + }, }, 'nested') export const useNested = (props: NestedProps) => { @@ -126,6 +132,21 @@ export const useNested = (props: NestedProps) => { return path } + onMounted(() => { + if (props.openOnMount === 'all') { + opened.value = new Set(children.value.keys()) + } else if (props.openOnMount === 'selected') { + const newOpened = new Set(opened.value) + for (const key of selected.value.keys()) { + const path = getPath(key).slice(0, -1) + for (const parent of path) { + newOpened.add(parent) + } + } + opened.value = newOpened + } + }) + const vm = getCurrentInstance('nested') const nested: NestedProvide = { @@ -206,6 +227,7 @@ export const useNested = (props: NestedProps) => { }, children, parents, + getPath, }, }