Skip to content

Commit 6bcdbea

Browse files
authored
fix(nested): selection should react to items changes (#22236)
fixes #21733
1 parent ae2af38 commit 6bcdbea

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

packages/vuetify/src/composables/nested/nested.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {
3131
leafSingleSelectStrategy,
3232
trunkSelectStrategy,
3333
} from './selectStrategies'
34-
import { consoleError, getCurrentInstance, propsFactory } from '@/util'
34+
import { consoleError, getCurrentInstance, propsFactory, throttle } from '@/util'
3535

3636
// Types
3737
import type { InjectionKey, MaybeRefOrGetter, PropType, Ref } from 'vue'
@@ -220,6 +220,11 @@ export const useNested = (props: NestedProps) => {
220220

221221
const nodeIds = new Set<unknown>()
222222

223+
const itemsUpdatePropagation = throttle(() => {
224+
children.value = new Map(children.value)
225+
parents.value = new Map(parents.value)
226+
}, 100)
227+
223228
const nested: NestedProvide = {
224229
id: shallowRef(),
225230
root: {
@@ -255,6 +260,7 @@ export const useNested = (props: NestedProps) => {
255260
if (parentId != null) {
256261
children.value.set(parentId, [...children.value.get(parentId) || [], id])
257262
}
263+
itemsUpdatePropagation()
258264
},
259265
unregister: id => {
260266
if (isUnmounted) return
@@ -268,6 +274,7 @@ export const useNested = (props: NestedProps) => {
268274
children.value.set(parent, list.filter(child => child !== id))
269275
}
270276
parents.value.delete(id)
277+
itemsUpdatePropagation()
271278
},
272279
open: (id, value, event) => {
273280
vm.emit('click:open', { id, value, path: getPath(id), event })

packages/vuetify/src/util/helpers.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -420,15 +420,39 @@ export function debounce (fn: Function, delay: MaybeRef<number>) {
420420
return wrap
421421
}
422422

423-
export function throttle<T extends (...args: any[]) => any> (fn: T, limit: number) {
423+
export function throttle<T extends (...args: any[]) => any> (
424+
fn: T,
425+
delay: number,
426+
options = { leading: true, trailing: true },
427+
) {
428+
let timeoutId = 0
429+
let lastExec = 0
424430
let throttling = false
425-
return (...args: Parameters<T>): void | ReturnType<T> => {
426-
if (!throttling) {
427-
throttling = true
428-
setTimeout(() => throttling = false, limit)
429-
return fn(...args)
431+
432+
const wrap = (...args: Parameters<T>): void | ReturnType<T> => {
433+
clearTimeout(timeoutId)
434+
const now = Date.now()
435+
const elapsed = now - lastExec
436+
437+
if (!throttling || elapsed >= delay) {
438+
lastExec = now
439+
}
440+
if ((!throttling && options.leading) || elapsed >= delay) {
441+
window.setTimeout(() => fn(...args)) // ignore 'fn' executin errors
430442
}
443+
444+
throttling = true
445+
timeoutId = window.setTimeout(() => {
446+
throttling = false
447+
if (options.trailing) {
448+
fn(...args)
449+
}
450+
}, delay)
431451
}
452+
453+
wrap.clear = () => clearTimeout(timeoutId)
454+
wrap.immediate = fn
455+
return wrap
432456
}
433457

434458
export function clamp (value: number, min = 0, max = 1) {

0 commit comments

Comments
 (0)