From 488fc0221e7957dbfac6d680f2ea40bb25412d5d Mon Sep 17 00:00:00 2001 From: Kael Date: Thu, 17 Oct 2024 18:09:37 +1100 Subject: [PATCH] fix(VTreeview): allow multiple nodes to be loading fixes #19390 closes #20404 --- .../src/labs/VTreeview/VTreeviewChildren.tsx | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx b/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx index d5d0d05ff79..89a88fdfc7c 100644 --- a/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx +++ b/packages/vuetify/src/labs/VTreeview/VTreeviewChildren.tsx @@ -7,7 +7,7 @@ import { VCheckboxBtn } from '@/components/VCheckbox' import { IconValue } from '@/composables/icons' // Utilities -import { computed, shallowRef, toRaw, withModifiers } from 'vue' +import { computed, reactive, toRaw, withModifiers } from 'vue' import { genericComponent, propsFactory } from '@/util' // Types @@ -18,10 +18,17 @@ import type { SelectStrategyProp } from '@/composables/nested/nested' import type { GenericProps } from '@/util' export type VTreeviewChildrenSlots = { - [K in keyof Omit]: VListItemSlots[K] & { item: T } + [K in keyof Omit]: VListItemSlots[K] & { + item: T + internalItem: InternalListItem + } } & { default: never - item: { props: InternalListItem['props'] } + item: { + props: InternalListItem['props'] + item: T + internalItem: InternalListItem + } } export const makeVTreeviewChildrenProps = propsFactory({ @@ -57,26 +64,22 @@ export const VTreeviewChildren = genericComponent()) const isClickOnOpen = computed(() => props.openOnClick != null ? props.openOnClick : props.selectable) - function checkChildren (item: any) { - return new Promise(resolve => { - if (!props.items?.length || !props.loadChildren) return resolve() + async function checkChildren (item: InternalListItem) { + try { + if (!props.items?.length || !props.loadChildren) return if (item?.children?.length === 0) { - isLoading.value = item.value - props.loadChildren(item).then(resolve) - - return + isLoading.add(item.value) + await props.loadChildren(item.raw) } - - resolve() - }).finally(() => { - isLoading.value = null - }) + } finally { + isLoading.delete(item.value) + } } function selectItem (select: (value: boolean) => void, isSelected: boolean) { @@ -85,8 +88,9 @@ export const VTreeviewChildren = genericComponent slots.default?.() ?? props.items?.map(({ children, props: itemProps, raw: item }) => { - const loading = isLoading.value === item.value + return () => slots.default?.() ?? props.items?.map(item => { + const { children, props: itemProps } = item + const loading = isLoading.has(item.value) const slotsWithItem = { prepend: slotProps => ( <> @@ -111,11 +115,11 @@ export const VTreeviewChildren = genericComponent )} - { slots.prepend?.({ ...slotProps, item }) } + { slots.prepend?.({ ...slotProps, item: item.raw, internalItem: item }) } ), - append: slots.append ? slotProps => slots.append?.({ ...slotProps, item }) : undefined, - title: slots.title ? slotProps => slots.title?.({ ...slotProps, item }) : undefined, + append: slots.append ? slotProps => slots.append?.({ ...slotProps, item: item.raw, internalItem: item }) : undefined, + title: slots.title ? slotProps => slots.title?.({ ...slotProps, item: item.raw, internalItem: item }) : undefined, } satisfies VTreeviewItem['$props']['$children'] const treeviewGroupProps = VTreeviewGroup.filterProps(itemProps) @@ -124,7 +128,7 @@ export const VTreeviewChildren = genericComponent {{ activator: ({ props: activatorProps }) => { @@ -139,7 +143,7 @@ export const VTreeviewChildren = genericComponent @@ -156,10 +160,10 @@ export const VTreeviewChildren = genericComponent ) : ( - slots.item?.({ props: itemProps }) ?? ( + slots.item?.({ props: itemProps, item: item.raw, internalItem: item }) ?? ( ))