11import type { TreeNode } from "@zag-js/collection"
2+ import type { Params } from "@zag-js/core"
23import { createGuards , createMachine } from "@zag-js/core"
3- import { getByTypeahead , setElementValue } from "@zag-js/dom-query"
4+ import { getByTypeahead , raf , setElementValue } from "@zag-js/dom-query"
45import { addOrRemove , diff , first , isArray , isEqual , last , remove , toArray , uniq } from "@zag-js/utils"
56import { collection } from "./tree-view.collection"
67import * as dom from "./tree-view.dom"
@@ -358,47 +359,63 @@ export const machine = createMachine<TreeViewSchema>({
358359 clearSelected ( { context } ) {
359360 context . set ( "selectedValue" , [ ] )
360361 } ,
361- focusTreeFirstNode ( { prop, scope } ) {
362+ focusTreeFirstNode ( params ) {
363+ const { prop, scope } = params
362364 const collection = prop ( "collection" )
363365 const firstNode = collection . getFirstNode ( )
364366 const firstValue = collection . getNodeValue ( firstNode )
365- dom . focusNode ( scope , firstValue )
367+ const scrolled = scrollToNode ( params , firstValue )
368+ if ( scrolled ) raf ( ( ) => dom . focusNode ( scope , firstValue ) )
369+ else dom . focusNode ( scope , firstValue )
366370 } ,
367371 focusTreeLastNode ( params ) {
368372 const { prop, scope } = params
369373 const collection = prop ( "collection" )
370374 const lastNode = collection . getLastNode ( undefined , { skip : skipFn ( params ) } )
371375 const lastValue = collection . getNodeValue ( lastNode )
372- dom . focusNode ( scope , lastValue )
376+ const scrolled = scrollToNode ( params , lastValue )
377+ if ( scrolled ) raf ( ( ) => dom . focusNode ( scope , lastValue ) )
378+ else dom . focusNode ( scope , lastValue )
373379 } ,
374- focusBranchFirstNode ( { event, prop, scope } ) {
380+ focusBranchFirstNode ( params ) {
381+ const { event, prop, scope } = params
375382 const collection = prop ( "collection" )
376383 const branchNode = collection . findNode ( event . id )
377384 const firstNode = collection . getFirstNode ( branchNode )
378385 const firstValue = collection . getNodeValue ( firstNode )
379- dom . focusNode ( scope , firstValue )
386+ const scrolled = scrollToNode ( params , firstValue )
387+ if ( scrolled ) raf ( ( ) => dom . focusNode ( scope , firstValue ) )
388+ else dom . focusNode ( scope , firstValue )
380389 } ,
381390 focusTreeNextNode ( params ) {
382391 const { event, prop, scope } = params
383392 const collection = prop ( "collection" )
384393 const nextNode = collection . getNextNode ( event . id , { skip : skipFn ( params ) } )
385394 if ( ! nextNode ) return
386395 const nextValue = collection . getNodeValue ( nextNode )
387- dom . focusNode ( scope , nextValue )
396+ const scrolled = scrollToNode ( params , nextValue )
397+ if ( scrolled ) raf ( ( ) => dom . focusNode ( scope , nextValue ) )
398+ else dom . focusNode ( scope , nextValue )
388399 } ,
389400 focusTreePrevNode ( params ) {
390401 const { event, prop, scope } = params
391402 const collection = prop ( "collection" )
392403 const prevNode = collection . getPreviousNode ( event . id , { skip : skipFn ( params ) } )
393404 if ( ! prevNode ) return
394405 const prevValue = collection . getNodeValue ( prevNode )
395- dom . focusNode ( scope , prevValue )
406+ const scrolled = scrollToNode ( params , prevValue )
407+ if ( scrolled ) raf ( ( ) => dom . focusNode ( scope , prevValue ) )
408+ else dom . focusNode ( scope , prevValue )
396409 } ,
397- focusBranchNode ( { event, prop, scope } ) {
410+ focusBranchNode ( params ) {
411+ const { event, prop, scope } = params
398412 const collection = prop ( "collection" )
399413 const parentNode = collection . getParentNode ( event . id )
400414 const parentValue = parentNode ? collection . getNodeValue ( parentNode ) : undefined
401- dom . focusNode ( scope , parentValue )
415+ if ( ! parentValue ) return
416+ const scrolled = scrollToNode ( params , parentValue )
417+ if ( scrolled ) raf ( ( ) => dom . focusNode ( scope , parentValue ) )
418+ else dom . focusNode ( scope , parentValue )
402419 } ,
403420 selectAllNodes ( { context, prop } ) {
404421 context . set ( "selectedValue" , prop ( "collection" ) . getValues ( ) )
@@ -416,7 +433,10 @@ export const machine = createMachine<TreeViewSchema>({
416433 key : event . key ,
417434 } )
418435
419- dom . focusNode ( scope , node ?. id )
436+ if ( ! node ?. id ) return
437+ const scrolled = scrollToNode ( params , node . id )
438+ if ( scrolled ) raf ( ( ) => dom . focusNode ( scope , node . id ) )
439+ else dom . focusNode ( scope , node . id )
420440 } ,
421441 toggleNodeSelection ( { context, event } ) {
422442 const selectedValue = addOrRemove ( context . get ( "selectedValue" ) , event . id )
@@ -641,3 +661,26 @@ export const machine = createMachine<TreeViewSchema>({
641661 } ,
642662 } ,
643663} )
664+
665+ function scrollToNode ( params : Params < TreeViewSchema > , value : string ) : boolean {
666+ const { prop, scope, computed } = params
667+ const scrollToIndexFn = prop ( "scrollToIndexFn" )
668+ if ( ! scrollToIndexFn ) return false
669+
670+ const collection = prop ( "collection" )
671+ const visibleNodes = computed ( "visibleNodes" )
672+
673+ for ( let i = 0 ; i < visibleNodes . length ; i ++ ) {
674+ const { node, indexPath } = visibleNodes [ i ]
675+ if ( collection . getNodeValue ( node ) !== value ) continue
676+ scrollToIndexFn ( {
677+ index : i ,
678+ node,
679+ indexPath,
680+ getElement : ( ) => scope . getById ( dom . getNodeId ( scope , value ) ) ,
681+ } )
682+ return true
683+ }
684+
685+ return false
686+ }
0 commit comments