55 activeElement ,
66 isElementNode ,
77 isFunc ,
8- isTextNode ,
98 rootNode ,
109} from '../index.js' ;
1110import { makeEventListener } from '@solid-primitives/event-listener' ;
@@ -88,41 +87,39 @@ function findElementWithCustomState<TApp extends ElementNode>(
8887 y : number ,
8988 customState : CustomState ,
9089) : ElementNode | undefined {
91- const result = getChildrenByPosition ( myApp , x , y ) . filter ( ( el ) =>
92- hasCustomState ( el , customState ) ,
93- ) ;
94-
95- if ( result . length === 0 ) {
96- return undefined ;
97- }
98-
99- let element : ElementNode | undefined = result [ result . length - 1 ] ;
100-
101- while ( element ) {
102- const elmParent = element . parent ;
103- if ( elmParent ?. forwardStates && hasCustomState ( elmParent , customState ) ) {
104- element = elmParent ;
105- } else {
90+ const path = getChildrenByPosition ( myApp , x , y ) ;
91+ let element : ElementNode | undefined ;
92+ for ( let i = path . length - 1 ; i >= 0 ; i -- ) {
93+ if ( hasCustomState ( path [ i ] ! , customState ) ) {
94+ element = path [ i ] ;
10695 break ;
10796 }
10897 }
98+ if ( ! element ) return undefined ;
10999
100+ let p = element . parent ;
101+ while ( p ?. forwardStates && hasCustomState ( p , customState ) ) {
102+ element = p ;
103+ p = p . parent ;
104+ }
110105 return element ;
111106}
112107
113108function findElementByActiveElement ( e : MouseEvent ) : ElementNode | null {
114109 const active = activeElement ( ) ;
115110 const precision = Config . rendererOptions ?. deviceLogicalPixelRatio || 1 ;
111+ const px = e . clientX / precision ;
112+ const py = e . clientY / precision ;
116113
117114 if (
118115 active instanceof ElementNode &&
119116 testCollision (
120- e . clientX ,
121- e . clientY ,
122- ( ( active . lng . absX as number ) || 0 ) * precision ,
123- ( ( active . lng . absY as number ) || 0 ) * precision ,
124- ( active . width || 0 ) * precision ,
125- ( active . height || 0 ) * precision ,
117+ px ,
118+ py ,
119+ ( active . lng . absX as number ) || 0 ,
120+ ( active . lng . absY as number ) || 0 ,
121+ active . width || 0 ,
122+ active . height || 0 ,
126123 )
127124 ) {
128125 return active ;
@@ -132,14 +129,13 @@ function findElementByActiveElement(e: MouseEvent): ElementNode | null {
132129 while ( parent ) {
133130 if (
134131 isFunc ( parent . onMouseClick ) &&
135- active &&
136132 testCollision (
137- e . clientX ,
138- e . clientY ,
139- ( ( parent . lng . absX as number ) || 0 ) * precision ,
140- ( ( parent . lng . absY as number ) || 0 ) * precision ,
141- ( parent . width || 0 ) * precision ,
142- ( parent . height || 0 ) * precision ,
133+ px ,
134+ py ,
135+ ( parent . lng . absX as number ) || 0 ,
136+ ( parent . lng . absY as number ) || 0 ,
137+ parent . width || 0 ,
138+ parent . height || 0 ,
143139 )
144140 ) {
145141 return parent ;
@@ -256,7 +252,6 @@ function isNodeAtPosition(
256252 node : ElementNode | ElementText | TextNode ,
257253 x : number ,
258254 y : number ,
259- precision : number ,
260255) : node is ElementNode {
261256 if ( ! isElementNode ( node ) ) {
262257 return false ;
@@ -268,66 +263,40 @@ function isNodeAtPosition(
268263 testCollision (
269264 x ,
270265 y ,
271- ( ( node . lng . absX as number ) || 0 ) * precision ,
272- ( ( node . lng . absY as number ) || 0 ) * precision ,
273- ( node . width || 0 ) * precision ,
274- ( node . height || 0 ) * precision ,
266+ ( node . lng . absX as number ) || 0 ,
267+ ( node . lng . absY as number ) || 0 ,
268+ node . width || 0 ,
269+ node . height || 0 ,
275270 )
276271 ) ;
277272}
278273
279- function findHighestZIndexNode ( nodes : ElementNode [ ] ) : ElementNode | undefined {
280- if ( nodes . length === 0 ) {
281- return undefined ;
282- }
283-
284- if ( nodes . length === 1 ) {
285- return nodes [ 0 ] ;
286- }
287-
288- let maxZIndex = - 1 ;
289- let highestNode : ElementNode | undefined = undefined ;
290-
291- for ( const node of nodes ) {
292- const zIndex = node . zIndex ?? - 1 ;
293- if ( zIndex >= maxZIndex ) {
294- maxZIndex = zIndex ;
295- highestNode = node ;
296- }
297- }
298-
299- return highestNode ;
300- }
301-
302274function getChildrenByPosition < TElement extends ElementNode = ElementNode > (
303275 node : TElement ,
304276 x : number ,
305277 y : number ,
306278) : TElement [ ] {
307279 const result : TElement [ ] = [ ] ;
308280 const precision = Config . rendererOptions ?. deviceLogicalPixelRatio || 1 ;
309- // Queue for BFS
310-
311- let queue : ( ElementNode | ElementText | TextNode ) [ ] = [ node ] ;
312-
313- while ( queue . length > 0 ) {
314- // Process nodes at the current level
315- const currentLevelNodes = queue . filter ( ( currentNode ) =>
316- isNodeAtPosition ( currentNode , x , y , precision ) ,
317- ) ;
318-
319- if ( currentLevelNodes . length === 0 ) {
320- break ;
321- }
322-
323- const highestZIndexNode = findHighestZIndexNode ( currentLevelNodes ) ;
324-
325- if ( ! highestZIndexNode || isTextNode ( highestZIndexNode ) ) {
326- break ;
281+ const px = x / precision ;
282+ const py = y / precision ;
283+
284+ let current : ElementNode | ElementText | TextNode | undefined = node ;
285+ while ( current && isNodeAtPosition ( current , px , py ) ) {
286+ result . push ( current as TElement ) ;
287+
288+ let best : ElementNode | undefined ;
289+ let bestZ = - Infinity ;
290+ for ( const child of current . children ) {
291+ if ( ! isNodeAtPosition ( child , px , py ) ) continue ;
292+ const z = child . zIndex ?? - 1 ;
293+ if ( z >= bestZ ) {
294+ bestZ = z ;
295+ best = child ;
296+ }
327297 }
328-
329- result . push ( highestZIndexNode as TElement ) ;
330- queue = highestZIndexNode . children ;
298+ if ( ! best ) break ;
299+ current = best ;
331300 }
332301
333302 return result ;
@@ -358,60 +327,60 @@ export function useMouse<TApp extends ElementNode = ElementNode>(
358327 runWithOwner ( owner , ( ) => handleMouseDown ( e ) ) ;
359328 } ;
360329
330+ const focusKey = Config . focusStateKey ;
331+
361332 makeEventListener ( window , 'wheel' , handleScroll ) ;
362333 makeEventListener ( window , 'click' , handleClickContext ) ;
363334 makeEventListener ( window , 'mousedown' , handleMouseDownContext ) ;
364335 createEffect ( ( ) => {
365- if ( scheduled ( ) ) {
366- const result = getChildrenByPosition ( myApp , pos . x , pos . y ) . filter (
367- ( el ) =>
368- ! ! (
369- el . onEnter ||
370- el . onMouseClick ||
371- el . onFocus ||
372- el [ Config . focusStateKey ] ||
373- ( hoverState ? el [ hoverState ] : false )
374- ) ,
375- ) ;
376-
377- if ( result . length ) {
378- let activeElm : ElementNode | undefined = result [ result . length - 1 ] ;
379-
380- while ( activeElm ) {
381- const elmParent = activeElm . parent ;
382- if ( elmParent ?. forwardStates ) {
383- activeElm = elmParent ;
384- } else {
385- break ;
386- }
387- }
388-
389- if ( ! activeElm ) {
390- return ;
391- }
392-
393- // Update Row & Column Selected property
394- const activeElmParent = activeElm . parent ;
395- if ( activeElmParent ?. selected !== undefined ) {
396- activeElmParent . selected =
397- activeElmParent . children . indexOf ( activeElm ) ;
398- }
399-
400- if ( previousElement && previousElement !== activeElm && hoverState ) {
401- removeCustomStateFromElement ( previousElement , hoverState ) ;
402- }
403-
404- if ( hoverState ) {
405- addCustomStateToElement ( activeElm , hoverState ) ;
406- } else {
407- activeElm . setFocus ( ) ;
408- }
409-
410- previousElement = activeElm ;
411- } else if ( previousElement && hoverState ) {
336+ if ( ! scheduled ( ) ) return ;
337+
338+ const path = getChildrenByPosition ( myApp , pos . x , pos . y ) ;
339+ let activeElm : ElementNode | undefined ;
340+ for ( let i = path . length - 1 ; i >= 0 ; i -- ) {
341+ const el = path [ i ] ! ;
342+ if (
343+ el . onEnter ||
344+ el . onMouseClick ||
345+ el . onFocus ||
346+ el [ focusKey ] ||
347+ ( hoverState && el [ hoverState ] )
348+ ) {
349+ activeElm = el ;
350+ break ;
351+ }
352+ }
353+
354+ if ( ! activeElm ) {
355+ if ( previousElement && hoverState ) {
412356 removeCustomStateFromElement ( previousElement , hoverState ) ;
413357 previousElement = null ;
414358 }
359+ return ;
360+ }
361+
362+ let p = activeElm . parent ;
363+ while ( p ?. forwardStates ) {
364+ activeElm = p ;
365+ p = p . parent ;
415366 }
367+
368+ // Update Row & Column Selected property
369+ const activeElmParent = activeElm . parent ;
370+ if ( activeElmParent ?. selected !== undefined ) {
371+ activeElmParent . selected = activeElmParent . children . indexOf ( activeElm ) ;
372+ }
373+
374+ if ( previousElement && previousElement !== activeElm && hoverState ) {
375+ removeCustomStateFromElement ( previousElement , hoverState ) ;
376+ }
377+
378+ if ( hoverState ) {
379+ addCustomStateToElement ( activeElm , hoverState ) ;
380+ } else {
381+ activeElm . setFocus ( ) ;
382+ }
383+
384+ previousElement = activeElm ;
416385 } ) ;
417386}
0 commit comments