From 385cd944c2101ae8452c10fb55e3b375a65cd10f Mon Sep 17 00:00:00 2001 From: Yuchao Wu Date: Sat, 7 Sep 2024 22:21:16 +1000 Subject: [PATCH 1/5] fix(nested): use reactive proxied opened object --- packages/vuetify/src/composables/nested/nested.ts | 6 +++--- packages/vuetify/src/composables/nested/openStrategies.ts | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/vuetify/src/composables/nested/nested.ts b/packages/vuetify/src/composables/nested/nested.ts index c5b013a3de0..84f9e7dca66 100644 --- a/packages/vuetify/src/composables/nested/nested.ts +++ b/packages/vuetify/src/composables/nested/nested.ts @@ -2,7 +2,7 @@ import { useProxiedModel } from '@/composables/proxiedModel' // Utilities -import { computed, inject, onBeforeUnmount, provide, ref, shallowRef, toRaw, toRef } from 'vue' +import { computed, inject, isRef, onBeforeUnmount, provide, ref, shallowRef, toRaw, toRef } from 'vue' import { independentActiveStrategy, independentSingleActiveStrategy, @@ -120,7 +120,7 @@ export const useNested = (props: NestedProps) => { const children = ref(new Map()) const parents = ref(new Map()) - const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(toRaw(v)), v => [...v.values()]) + const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(isRef(v) ? v.value : v), v => [...v.values()]) const activeStrategy = computed(() => { if (typeof props.activeStrategy === 'object') return props.activeStrategy @@ -323,7 +323,7 @@ export const useNestedItem = (id: Ref, isGroup: boolean) => { id: computedId, open: (open: boolean, e: Event) => parent.root.open(toRaw(computedId.value), open, e), openOnSelect: (open: boolean, e?: Event) => parent.root.openOnSelect(computedId.value, open, e), - isOpen: computed(() => parent.root.opened.value.has(toRaw(computedId.value))), + isOpen: computed(() => parent.root.opened.value.has(computedId.value)), parent: computed(() => parent.root.parents.value.get(computedId.value)), activate: (activated: boolean, e?: Event) => parent.root.activate(computedId.value, activated, e), isActivated: computed(() => parent.root.activated.value.has(toRaw(computedId.value))), diff --git a/packages/vuetify/src/composables/nested/openStrategies.ts b/packages/vuetify/src/composables/nested/openStrategies.ts index ff0f2b3d514..5136d4c4a96 100644 --- a/packages/vuetify/src/composables/nested/openStrategies.ts +++ b/packages/vuetify/src/composables/nested/openStrategies.ts @@ -1,6 +1,3 @@ -// Utilities -import { toRaw } from 'vue' - export type OpenStrategyFn = (data: { id: unknown value: boolean @@ -50,12 +47,12 @@ export const singleOpenStrategy: OpenStrategy = { export const multipleOpenStrategy: OpenStrategy = { open: ({ id, value, opened, parents }) => { if (value) { - let parent = toRaw(parents.get(id)) + let parent = parents.get(id) opened.add(id) while (parent != null && parent !== id) { opened.add(parent) - parent = toRaw(parents.get(parent)) + parent = parents.get(parent) } return opened From b6bc4a3eb474c3b35108e75f792b68309572d661 Mon Sep 17 00:00:00 2001 From: Yuchao Wu Date: Sat, 7 Sep 2024 22:26:59 +1000 Subject: [PATCH 2/5] chore: remove unnecessary change --- packages/vuetify/src/composables/nested/nested.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vuetify/src/composables/nested/nested.ts b/packages/vuetify/src/composables/nested/nested.ts index 84f9e7dca66..667cb96e897 100644 --- a/packages/vuetify/src/composables/nested/nested.ts +++ b/packages/vuetify/src/composables/nested/nested.ts @@ -2,7 +2,7 @@ import { useProxiedModel } from '@/composables/proxiedModel' // Utilities -import { computed, inject, isRef, onBeforeUnmount, provide, ref, shallowRef, toRaw, toRef } from 'vue' +import { computed, inject, onBeforeUnmount, provide, ref, shallowRef, toRaw, toRef } from 'vue' import { independentActiveStrategy, independentSingleActiveStrategy, @@ -120,7 +120,7 @@ export const useNested = (props: NestedProps) => { const children = ref(new Map()) const parents = ref(new Map()) - const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(isRef(v) ? v.value : v), v => [...v.values()]) + const opened = useProxiedModel(props, 'opened', props.opened, v => new Set(v), v => [...v.values()]) const activeStrategy = computed(() => { if (typeof props.activeStrategy === 'object') return props.activeStrategy From 1305cf186d5d19f48dfb142931e6e0d7c8050881 Mon Sep 17 00:00:00 2001 From: Yuchao Wu Date: Tue, 10 Sep 2024 10:17:00 +1000 Subject: [PATCH 3/5] fix: expand doesn't open when using return-object --- packages/vuetify/src/composables/nested/nested.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vuetify/src/composables/nested/nested.ts b/packages/vuetify/src/composables/nested/nested.ts index 667cb96e897..33fdf075aae 100644 --- a/packages/vuetify/src/composables/nested/nested.ts +++ b/packages/vuetify/src/composables/nested/nested.ts @@ -321,7 +321,7 @@ export const useNestedItem = (id: Ref, isGroup: boolean) => { const item = { ...parent, id: computedId, - open: (open: boolean, e: Event) => parent.root.open(toRaw(computedId.value), open, e), + open: (open: boolean, e: Event) => parent.root.open(computedId.value, open, e), openOnSelect: (open: boolean, e?: Event) => parent.root.openOnSelect(computedId.value, open, e), isOpen: computed(() => parent.root.opened.value.has(computedId.value)), parent: computed(() => parent.root.parents.value.get(computedId.value)), From 9ec5a30e0abd68b9cebbc608a26ca047d0e2076c Mon Sep 17 00:00:00 2001 From: Yuchao Wu Date: Tue, 10 Sep 2024 17:43:52 +1000 Subject: [PATCH 4/5] chore: add cy test --- .../VList/__tests__/VListGroup.spec.cy.tsx | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx b/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx index 8529294be27..787065d34c6 100644 --- a/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx +++ b/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx @@ -5,8 +5,13 @@ import { VListGroup } from '../VListGroup' import { VListItem } from '../VListItem' import { VList } from '../VList' +// Components +import { VBtn } from '@/components/VBtn' + // Utilities import { ref } from 'vue' +// Types +import type { Ref } from 'vue' describe('VListGroup', () => { function mountFunction (content: JSX.Element) { @@ -29,7 +34,7 @@ describe('VListGroup', () => { wrapper.get('.v-list-item-title').contains('Group') }) - it('supports children', () => { + it.only('supports children', () => { const wrapper = mountFunction((

ListGroup

@@ -91,4 +96,34 @@ describe('VListGroup', () => { .get('.v-list-group').should('exist') .get('.v-list-group__items').should('be.visible') }) + + // https://github.com/vuetifyjs/vuetify/issues/20354 + it('should support programmatically expand group via open model', () => { + const opened: Ref = ref([]) + + cy.mount(() => ( + <> + { opened.value.push('Users') } }>Click me + + + {{ + activator: ({ props }) => , + default: () => ( + <> + + + + ), + }} + + + + )) + + cy.get('button').click({ waitForAnimations: true }) + .then(_ => { + expect(opened.value).to.deep.equal(['Users']) + }) + .get('.v-list-group__items').should('be.visible') + }) }) From 0d42dedae5c607dd940d2d74bb7b14d6b27e6101 Mon Sep 17 00:00:00 2001 From: Yuchao Wu Date: Tue, 10 Sep 2024 21:23:02 +1000 Subject: [PATCH 5/5] chore: add one more cy test --- .../VList/__tests__/VListGroup.spec.cy.tsx | 4 ++-- .../VTreeview/__tests__/VTreeview.spec.cy.tsx | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx b/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx index 787065d34c6..c86d5b57f20 100644 --- a/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx +++ b/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx @@ -34,7 +34,7 @@ describe('VListGroup', () => { wrapper.get('.v-list-item-title').contains('Group') }) - it.only('supports children', () => { + it('supports children', () => { const wrapper = mountFunction((

ListGroup

@@ -120,7 +120,7 @@ describe('VListGroup', () => { )) - cy.get('button').click({ waitForAnimations: true }) + cy.get('button').click() .then(_ => { expect(opened.value).to.deep.equal(['Users']) }) diff --git a/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx b/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx index 365646f11ee..541b9f929df 100644 --- a/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx +++ b/packages/vuetify/src/labs/VTreeview/__tests__/VTreeview.spec.cy.tsx @@ -300,6 +300,22 @@ describe('VTreeview', () => { describe('return-object', () => { describe('open', () => { + it('open and collapse should both work', () => { + cy.mount(() => ( + <> + + + )) + .get('.v-list-item-action .v-btn').eq(0).click() + .get('.v-list-group__items').eq(0).should('be.visible') + .get('.v-list-item-action .v-btn').eq(0).click() + .get('.v-list-group__items').eq(0).should('not.be.visible') + }) it('opan-all should work', () => { cy.mount(() => ( <>