diff --git a/src/runtime/components/Tree.vue b/src/runtime/components/Tree.vue index a7e687445b..60635083a2 100644 --- a/src/runtime/components/Tree.vue +++ b/src/runtime/components/Tree.vue @@ -227,10 +227,18 @@ function getItemLabel(item: Item): string { return get(item, props.labelKey as string) } +function getItemValueKey(item: Item): string | undefined { + const value = get(item, 'value') + + if (typeof value === 'string' || typeof value === 'number') { + return String(value) + } +} + function getItemKey(item: Item): string { return props.getKey - ? props.getKey(item) || getItemLabel(item) - : getItemLabel(item) + ? props.getKey(item) || getItemValueKey(item) || getItemLabel(item) + : getItemValueKey(item) || getItemLabel(item) } function getDefaultOpenedItems(item: T[number]): string[] { diff --git a/test/components/Tree.spec.ts b/test/components/Tree.spec.ts index 8c1166e59c..087102a70c 100644 --- a/test/components/Tree.spec.ts +++ b/test/components/Tree.spec.ts @@ -87,6 +87,47 @@ describe('Tree', () => { expect(await axe(wrapper.element)).toHaveNoViolations() }) + it('uses item value as the default expansion key before falling back to label', async () => { + const wrapper = await mountSuspended(Tree, { + props: { + items: [ + { + label: 'references', + value: 'root-references', + defaultExpanded: true, + children: [{ label: 'nuxt.md', value: 'root-references/nuxt.md' }] + }, + { + label: 'module', + value: 'module', + defaultExpanded: true, + children: [ + { + label: 'references', + value: 'module/references', + defaultExpanded: true, + children: [{ label: 'querying.md', value: 'module/references/querying.md' }] + } + ] + } + ] + } + }) + + const items = wrapper.findAll('[role="treeitem"]') + const nestedReferences = items.find(item => item.text() === 'references' && item.attributes('aria-level') === '2') + + expect(nestedReferences).toBeDefined() + await nestedReferences!.trigger('click') + + const updatedItems = wrapper.findAll('[role="treeitem"]') + const rootReferences = updatedItems.find(item => item.text() === 'references' && item.attributes('aria-level') === '1') + const reopenedNestedReferences = updatedItems.find(item => item.text() === 'references' && item.attributes('aria-level') === '2') + + expect(rootReferences?.attributes('aria-expanded')).toBe('true') + expect(reopenedNestedReferences?.attributes('aria-expanded')).toBe('false') + }) + test('should have the correct types', () => { expectEmitPayloadType('update:modelValue', () => Tree({ items: [{ label: 'foo' }, { label: 'baz' }]