@@ -24,6 +24,10 @@ export function TermTip({ children }: { children: React.ReactNode }) {
2424 } ) ;
2525 const [ coords , setCoords ] = useState ( { top : 0 , left : 0 } ) ;
2626 const [ placement , setPlacement ] = useState < Placement > ( "bottom" ) ;
27+ // Whether position has been finalized after measuring the tooltip size.
28+ // Prevents the tooltip from flashing at a guessed position before the real
29+ // coordinates are computed.
30+ const [ positioned , setPositioned ] = useState ( false ) ;
2731
2832 useEffect ( ( ) => {
2933 setMounted ( true ) ;
@@ -73,21 +77,28 @@ export function TermTip({ children }: { children: React.ReactNode }) {
7377
7478 clearTimeout ( hideTimerRef . current ) ;
7579 triggerRef . current = el ;
80+ setPositioned ( false ) ;
7681
7782 const rect = el . getBoundingClientRect ( ) ;
7883 setCoords ( { top : rect . bottom + 10 , left : rect . left } ) ;
7984 setPlacement ( "bottom" ) ;
8085 setTooltip ( { visible : true , text : tip } ) ;
8186
82- requestAnimationFrame ( ( ) => updatePosition ( ) ) ;
87+ requestAnimationFrame ( ( ) => {
88+ updatePosition ( ) ;
89+ setPositioned ( true ) ;
90+ } ) ;
8391 } ,
8492 [ updatePosition ] ,
8593 ) ;
8694
8795 const hide = useCallback ( ( ) => {
8896 hideTimerRef . current = setTimeout ( ( ) => {
8997 setTooltip ( { visible : false , text : "" } ) ;
98+ setCoords ( { top : 0 , left : 0 } ) ;
99+ setPlacement ( "bottom" ) ;
90100 triggerRef . current = null ;
101+ setPositioned ( false ) ;
91102 } , 150 ) ;
92103 } , [ ] ) ;
93104
@@ -141,9 +152,14 @@ export function TermTip({ children }: { children: React.ReactNode }) {
141152 position : "fixed" ,
142153 top : coords . top ,
143154 left : coords . left ,
155+ visibility : positioned ? "visible" : "hidden" ,
144156 } }
145157 initial = { { opacity : 0 , y : placement === "bottom" ? - 4 : 4 } }
146- animate = { { opacity : 1 , y : 0 } }
158+ animate = {
159+ positioned
160+ ? { opacity : 1 , y : 0 }
161+ : { opacity : 0 , y : placement === "bottom" ? - 4 : 4 }
162+ }
147163 exit = { { opacity : 0 } }
148164 transition = { { duration : 0.15 , ease : "easeOut" } }
149165 onMouseEnter = { ( ) => clearTimeout ( hideTimerRef . current ) }
0 commit comments