1- import React , { useCallback , useEffect , useMemo , useState } from "react" ;
1+ import React , {
2+ useCallback ,
3+ useEffect ,
4+ useLayoutEffect ,
5+ useMemo ,
6+ useState ,
7+ } from "react" ;
28import { TreeView } from "@editor-ui/editor" ;
39import {
410 LayerRow ,
@@ -16,11 +22,36 @@ import {
1622 FlattenedDisplayItemNode ,
1723} from "./editor-layer-heriarchy-controller" ;
1824import type { ReflectSceneNode } from "@design-sdk/figma-node" ;
25+ import type { IVirtualizedList } from "@editor-ui/listview" ;
26+ import useMeasure from "react-use-measure" ;
27+ import { p } from "@tree-/q" ;
1928
2029// TODO:
2130// - add navigate context menu
2231// - add go to main component
23- // - add reveal and focus to selected layers
32+
33+ function useAutoFocus ( {
34+ ref,
35+ layers,
36+ targets,
37+ } : {
38+ ref : React . RefObject < IVirtualizedList > ;
39+ targets : string [ ] ;
40+ layers : FlattenedDisplayItemNode [ ] [ ] ;
41+ } ) {
42+ // TODO: we use useLayoutEffect to focus to the selection, because it relates to auto expand & layer calculation.
43+ // this can be simplified. and we can use plain old useEffect.
44+ useLayoutEffect ( ( ) => {
45+ // auto focus to selection
46+ const focusnode = targets [ 0 ] ;
47+ if ( focusnode ) {
48+ const index = layers . flat ( ) . findIndex ( ( i ) => i . id == focusnode ) ;
49+ if ( index ) {
50+ ref . current ?. scrollToIndex ( index ) ;
51+ }
52+ }
53+ } , [ ref , targets , layers ] ) ;
54+ }
2455
2556/**
2657 *
@@ -35,13 +66,18 @@ export function DesignLayerHierarchy({
3566 rootNodeIDs ?: string [ ] ;
3667 expandAll ?: boolean ;
3768} ) {
69+ const [ sizeRef , { height, width } ] = useMeasure ( {
70+ debounce : { scroll : 100 , resize : 100 } ,
71+ } ) ;
3872 const [ state ] = useEditorState ( ) ;
3973 const { selectedNodes, selectedPage, design } = state ;
4074 const { highlightLayer, highlightedLayer } = useWorkspace ( ) ;
4175 const dispatch = useDispatch ( ) ;
4276
4377 const [ expands , setExpands ] = useState < string [ ] > ( state ?. selectedNodes ?? [ ] ) ;
4478
79+ const ref = React . useRef < IVirtualizedList > ( null ) ;
80+
4581 // get the root nodes (if the rootNodeIDs is not specified, use the selected page's children)
4682 let roots : ReflectSceneNode [ ] = [ ] ;
4783 if ( rootNodeIDs ?. length > 0 ) {
@@ -63,6 +99,13 @@ export function DesignLayerHierarchy({
6399 : [ ] ;
64100 } , [ roots , state ?. selectedNodes , expands ] ) ;
65101
102+ useAutoFocus ( {
103+ ref,
104+ layers,
105+ targets : selectedNodes ,
106+ } ) ;
107+
108+ // exapnd all nodes
66109 useEffect ( ( ) => {
67110 if ( expandAll ) {
68111 const ids = layers . reduce ( ( acc , item ) => {
@@ -73,6 +116,26 @@ export function DesignLayerHierarchy({
73116 }
74117 } , [ layers , expandAll ] ) ;
75118
119+ // automatically expand the selected nodes' parents
120+ useEffect ( ( ) => {
121+ const newexpands = [ ] ;
122+
123+ // loop through all roots
124+ for ( const child of roots ) {
125+ // if the node contains the selected node, add to expands.
126+ selectedNodes . forEach ( ( id ) => {
127+ const path = p ( id , { data : child } ) ;
128+ if ( path . length > 0 ) {
129+ newexpands . push ( ...path ) ;
130+ }
131+ } ) ;
132+ }
133+
134+ setExpands (
135+ Array . from ( new Set ( [ ...expands , ...newexpands ] ) ) . filter ( Boolean )
136+ ) ;
137+ } , [ selectedNodes ] ) ;
138+
76139 const renderItem = useCallback (
77140 ( {
78141 id,
@@ -123,13 +186,27 @@ export function DesignLayerHierarchy({
123186 ) ;
124187
125188 return (
126- < TreeView . Root
127- data = { layers . flat ( ) }
128- keyExtractor = { useCallback ( ( item : any ) => item . id , [ ] ) }
129- renderItem = { renderItem }
130- />
189+ < div
190+ style = { {
191+ width : "100%" ,
192+ height : "100%" ,
193+ } }
194+ ref = { sizeRef }
195+ >
196+ < TreeView . Root
197+ ref = { ref }
198+ data = { layers . flat ( ) }
199+ keyExtractor = { useCallback ( ( item : any ) => item . id , [ ] ) }
200+ renderItem = { renderItem }
201+ scrollable
202+ expandable
203+ virtualized = { {
204+ width : width ,
205+ height : height ,
206+ } }
207+ />
208+ </ div >
131209 ) ;
132- //
133210}
134211
135212/**
0 commit comments