diff --git a/packages/api-generator/src/locale/en/VListGroup.json b/packages/api-generator/src/locale/en/VListGroup.json index 4054c872d3f..f58bc7f1523 100644 --- a/packages/api-generator/src/locale/en/VListGroup.json +++ b/packages/api-generator/src/locale/en/VListGroup.json @@ -6,6 +6,7 @@ "group": "Assign a route namespace. Accepts a string or regexp for determining active state.", "noAction": "Removes left padding assigned for action icons from group items.", "prependIcon": "Prepends an icon to the component, uses the same syntax as `v-icon`.", + "rawId": "Defines the root element's id attribute in the component. If it is provided, the id attribute will be dynamically generated in the format: \"v-list-group--id-[rawId]\".", "subgroup": "Designate the component as nested list group.", "value": "Expands / Collapse the list-group.", "fluid": "Removes the left padding assigned for action icons from group items." diff --git a/packages/docs/src/components/about/TeamMember.vue b/packages/docs/src/components/about/TeamMember.vue index 2884e44a483..1a06a7c93aa 100644 --- a/packages/docs/src/components/about/TeamMember.vue +++ b/packages/docs/src/components/about/TeamMember.vue @@ -169,15 +169,6 @@ const links = computed(() => { const links = [] - if (props.member.twitter) { - links.push({ - color: '#212121', - href: `https://x.com/${props.member.twitter}`, - icon: '$x', - tooltip: 'Xitter', - }) - } - if (props.member.github) { links.push({ color: '#24292E', diff --git a/packages/docs/src/components/app/bar/EcosystemMenu.vue b/packages/docs/src/components/app/bar/EcosystemMenu.vue index 5f46fd9d7ae..eb6eab7d40e 100644 --- a/packages/docs/src/components/app/bar/EcosystemMenu.vue +++ b/packages/docs/src/components/app/bar/EcosystemMenu.vue @@ -16,11 +16,6 @@ const { t } = useI18n() const items = computed(() => ([ { subheader: t('social') }, - { - title: 'X', - href: 'https://x.com/vuetifyjs', - appendIcon: '$x', - }, { title: 'Discord', href: 'https://community.vuetifyjs.com/', diff --git a/packages/docs/src/components/home/Footer.vue b/packages/docs/src/components/home/Footer.vue index b7062b125a5..427eedadd01 100644 --- a/packages/docs/src/components/home/Footer.vue +++ b/packages/docs/src/components/home/Footer.vue @@ -108,11 +108,6 @@ href: 'https://github.com/vuetifyjs/vuetify', title: 'github', }, - { - icon: '$x', - href: 'https://x.com/vuetifyjs', - title: 'x', - }, { icon: 'mdi-discord', href: 'https://community.vuetifyjs.com', diff --git a/packages/docs/src/data/team.json b/packages/docs/src/data/team.json index 294163b331d..ba6bfeaf6a4 100644 --- a/packages/docs/src/data/team.json +++ b/packages/docs/src/data/team.json @@ -16,7 +16,6 @@ "location": "Keller, TX, USA", "name": "John Leider", "team": "company", - "twitter": "zeroskillz", "work": "Engineer @ Vuetify", "joined": "Jun 2016" }, @@ -31,7 +30,6 @@ "location": "Keller, TX, USA", "name": "Heather Leider", "team": "company", - "twitter": "grneyedgrl01", "work": "COO @ Vuetify", "joined": "Nov 2019" }, @@ -83,7 +81,6 @@ "location": "Rochester, NY, USA", "name": "Andrew Henry", "team": "core", - "twitter": "SeeMWhyK", "joined": "Dec 2018" }, "blalan05": { @@ -127,7 +124,6 @@ ], "location": "Madrid, Spain", "name": "Joaquín Sánchez", - "twitter": "userquin", "team": "core", "joined": "Mar 2024" }, @@ -148,7 +144,6 @@ "location": "California, US", "name": "Ken Kieu", "team": "core", - "twitter": "kieuminhcanh", "joined": "April 2024" }, "MatthewAry": { @@ -161,7 +156,6 @@ ], "location": "Spokane, WA, USA", "name": "Matthew Ary", - "twitter": "MatthewAry", "linkedin": "matthewary", "work": "Director of Product Development at Symplsoft Inc.", "team": "core", @@ -244,7 +238,6 @@ "English", "Persian" ], - "twitter": "yooneskh", "linkedin": "yooneskh ", "location": "Iran", "name": "Yoones Khoshghadam", diff --git a/packages/docs/src/i18n/messages/en.json b/packages/docs/src/i18n/messages/en.json index 045129a726d..901cfd53b1a 100644 --- a/packages/docs/src/i18n/messages/en.json +++ b/packages/docs/src/i18n/messages/en.json @@ -343,7 +343,6 @@ "translations": "Translations", "type": "Type | Types", "types": "Types", - "twitter": "Twitter", "ui-components": "UI Components", "ui-kits": "UI Kits", "ui": "UI", @@ -358,6 +357,5 @@ "view-in-github": "View on GitHub", "view-source": "View source", "viewport": "Viewport", - "vuetify": "Vuetify", - "x": "Xitter" + "vuetify": "Vuetify" } diff --git a/packages/docs/src/stores/team.ts b/packages/docs/src/stores/team.ts index 68f9d879fd4..4d848b98c94 100644 --- a/packages/docs/src/stores/team.ts +++ b/packages/docs/src/stores/team.ts @@ -16,7 +16,6 @@ export type Member = { avatar?: string github?: string team: string - twitter?: string joined?: string } diff --git a/packages/vuetify/src/components/VList/VListChildren.tsx b/packages/vuetify/src/components/VList/VListChildren.tsx index 9f817579f14..86019f58ccd 100644 --- a/packages/vuetify/src/components/VList/VListChildren.tsx +++ b/packages/vuetify/src/components/VList/VListChildren.tsx @@ -67,8 +67,9 @@ export const VListChildren = genericComponent( return children ? ( {{ activator: ({ props: activatorProps }) => { diff --git a/packages/vuetify/src/components/VList/VListGroup.tsx b/packages/vuetify/src/components/VList/VListGroup.tsx index 2d94ce78e31..048be4634ee 100644 --- a/packages/vuetify/src/components/VList/VListGroup.tsx +++ b/packages/vuetify/src/components/VList/VListGroup.tsx @@ -43,6 +43,7 @@ export const makeVListGroupProps = propsFactory({ type: IconValue, default: '$expand', }, + rawId: [String, Number], prependIcon: IconValue, appendIcon: IconValue, fluid: Boolean, @@ -61,7 +62,7 @@ export const VListGroup = genericComponent()({ setup (props, { slots }) { const { isOpen, open, id: _id } = useNestedItem(toRef(props, 'value'), true) - const id = computed(() => `v-list-group--id-${String(_id.value)}`) + const id = computed(() => `v-list-group--id-${String(props.rawId ?? _id.value)}`) const list = useList() const { isBooted } = useSsrBoot() diff --git a/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.browser.tsx b/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.browser.tsx new file mode 100644 index 00000000000..d552cb597bb --- /dev/null +++ b/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.browser.tsx @@ -0,0 +1,156 @@ +import { VListGroup } from '../VListGroup' +import { VListItem } from '../VListItem' +import { VList } from '../VList' + +// Components +import { VBtn } from '@/components/VBtn' + +// Utilities +import { render, screen } from '@test' +import { commands, userEvent } from '@vitest/browser/context' +import { ref } from 'vue' +// Types +import type { Ref } from 'vue' + +describe('VListGroup', () => { + it('supports header slot', () => { + render(() => ( + + + {{ activator: props => }} + + + )) + + expect(screen.getByCSS('.v-list-item-title')).toHaveTextContent('Group') + }) + + it('supports children', () => { + render(() => ( + + + {{ + activator: props => , + default: () => ( + <> + + + + ), + }} + + + )) + + expect(screen.getAllByCSS('.v-list-item-title')[0]).toHaveTextContent('Group') + }) + + it('should not remove opened when unmounted', async () => { + const visible = ref(true) + const opened = ref(['Users']) + render(() => ( + + { + visible.value && ( + + {{ + default: () => ( + <> + + + + ), + }} + + ) + } + + )) + + expect(screen.queryByRole('group')).not.toBeNull() + expect(screen.getByCSS('.v-list-group__items')).toBeVisible() + visible.value = false + await commands.waitStable('.v-list') + expect(screen.queryByRole('group')).toBeNull() + visible.value = true + await commands.waitStable('.v-list') + expect(screen.queryByRole('group')).not.toBeNull() + expect(screen.getByCSS('.v-list-group__items')).toBeVisible() + }) + + // https://github.com/vuetifyjs/vuetify/issues/20354 + it('should support programmatically expand group via open model', async () => { + const opened: Ref = ref([]) + + const { container } = render(() => ( + <> + { opened.value.push('Users') } }>Click me + + + {{ + activator: ({ props }) => , + default: () => ( + <> + + + + ), + }} + + + + )) + + await userEvent.click(container.querySelector('button')!) + expect(opened.value).toStrictEqual(['Users']) + expect(screen.getByCSS('.v-list-group__items')).toBeVisible() + }) + + it('should correctly set v-model:opened when return-object is applied', async () => { + const opened: Ref = ref([]) + const items: Ref = ref([ + { + title: 'Item #1', + newValue: 1, + children: [ + { + title: 'Child 1', + newValue: 100, + }, + ], + }, + { + title: 'Item #2', + newValue: 2, + }, + { + title: 'Item #3', + newValue: 3, + }, + ]) + render(() => ( + + + )) + + expect(opened.value).toStrictEqual([]) + + await userEvent.click(screen.getByCSS('.v-list-group__header')) + + expect(opened.value).toStrictEqual([{ + title: 'Item #1', + newValue: 1, + children: [ + { + title: 'Child 1', + newValue: 100, + }, + ], + }]) + }) +}) diff --git a/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx b/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx deleted file mode 100644 index c86d5b57f20..00000000000 --- a/packages/vuetify/src/components/VList/__tests__/VListGroup.spec.cy.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/// - -import { CenteredGrid } from '@/../cypress/templates' -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) { - return cy.mount(() => content) - } - - it('supports header slot', () => { - const wrapper = mountFunction(( - -

ListGroup

- - - - {{ activator: props => }} - - -
- )) - - wrapper.get('.v-list-item-title').contains('Group') - }) - - it('supports children', () => { - const wrapper = mountFunction(( - -

ListGroup

- - - - {{ - activator: props => , - default: () => ( - <> - - - - ), - }} - - -
- )) - - wrapper.get('.v-list-item-title').contains('Group') - }) - - it('should not remove opened when unmounted', () => { - const visible = ref(true) - const opened = ref(['Users']) - const wrapper = mountFunction(( - -

ListGroup

- - - { - visible.value && ( - - {{ - default: () => ( - <> - - - - ), - }} - - ) - } - -
- )) - - wrapper.get('.v-list .v-list-group').should('exist') - .get('.v-list-group__items').should('be.visible') - .then(() => { - visible.value = false - }) - .get('.v-list.v-list-group').should('not.exist') - .then(() => { - visible.value = true - }) - .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() - .then(_ => { - expect(opened.value).to.deep.equal(['Users']) - }) - .get('.v-list-group__items').should('be.visible') - }) -}) diff --git a/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx b/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx index 442e7cd88f1..4b9c4486e71 100644 --- a/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx +++ b/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx @@ -131,6 +131,7 @@ export const VTreeviewChildren = genericComponent {{ activator: ({ props: activatorProps }) => {