1- import { useEffect , useState , useRef , useCallback , startTransition } from "react" ;
1+ import {
2+ useEffect ,
3+ useState ,
4+ useRef ,
5+ useCallback ,
6+ startTransition ,
7+ RefObject ,
8+ } from "react" ;
29import { SimpleToolbar } from "./simple-toolbar" ;
3- import { TOOLBAR_HEIGHT_PX , TOOLBAR_SHOW_THRESHOLD , TOOLBAR_HIDE_THRESHOLD } from "./constants" ;
10+ import {
11+ TOOLBAR_HEIGHT_PX ,
12+ TOOLBAR_SHOW_THRESHOLD ,
13+ TOOLBAR_HIDE_THRESHOLD ,
14+ } from "./constants" ;
415
516interface FloatingToolbarProps {
617 /** Editor container ref for scroll detection */
@@ -29,24 +40,26 @@ export const FloatingToolbar: React.FC<FloatingToolbarProps> = ({
2940 headerHeight ,
3041 onOriginalToolbarVisibilityChange
3142 ) ;
32-
43+
3344 const { floatingRef, styles } = useToolbarPositioning ( editorRef , isVisible ) ;
34-
45+
3546 useScrollEventManagement ( editorRef , checkVisibility ) ;
36-
47+
3748 return renderFloatingToolbar ( floatingRef , isVisible , styles , editorRef ) ;
3849} ;
3950
4051/** Cancels any pending debounced visibility update */
41- const cancelDebouncedUpdate = ( timerRef : React . MutableRefObject < NodeJS . Timeout | null > ) => {
52+ const cancelDebouncedUpdate = (
53+ timerRef : RefObject < NodeJS . Timeout | null >
54+ ) => {
4255 if ( timerRef . current ) {
4356 clearTimeout ( timerRef . current ) ;
4457 }
4558} ;
4659
4760/** Schedules a debounced visibility update after 10ms delay */
4861const scheduleDebouncedUpdate = (
49- timerRef : React . MutableRefObject < NodeJS . Timeout | null > ,
62+ timerRef : React . RefObject < NodeJS . Timeout | null > ,
5063 editorRef : React . RefObject < HTMLDivElement > ,
5164 toolbarRef : React . RefObject < HTMLDivElement > ,
5265 headerHeight : number ,
@@ -146,10 +159,10 @@ const useScrollEventManagement = (
146159 useEffect ( ( ) => {
147160 // Initial visibility check
148161 onScroll ( ) ;
149-
162+
150163 // Setup scroll listeners on window and scrollable parents
151164 const cleanup = setupAllScrollListeners ( editorRef , onScroll ) ;
152-
165+
153166 return cleanup ;
154167 } , [ editorRef , onScroll ] ) ;
155168} ;
@@ -168,7 +181,7 @@ const calculateTransitionPoint = (
168181 editorTop : number ,
169182 threshold : number
170183) : number => {
171- return editorTop + ( TOOLBAR_HEIGHT_PX * threshold ) ;
184+ return editorTop + TOOLBAR_HEIGHT_PX * threshold ;
172185} ;
173186
174187/** Checks if threshold point has crossed below the header */
@@ -198,12 +211,15 @@ const calculateToolbarVisibility = (
198211 const editorRect = editorRef . current . getBoundingClientRect ( ) ;
199212 const threshold = selectThresholdForTransition ( currentlyVisible ) ;
200213 const thresholdPosition = calculateTransitionPoint ( editorRect . top , threshold ) ;
201- const thresholdCrossed = hasThresholdCrossedHeader ( thresholdPosition , headerHeight ) ;
214+ const thresholdCrossed = hasThresholdCrossedHeader (
215+ thresholdPosition ,
216+ headerHeight
217+ ) ;
202218 const editorVisible = isEditorInViewport ( editorRect ) ;
203219
204220 return {
205221 shouldShow : thresholdCrossed && editorVisible ,
206- editorVisible
222+ editorVisible,
207223 } ;
208224} ;
209225
@@ -225,14 +241,14 @@ const updateVisibilityState = (
225241
226242const getDefaultStyles = ( ) => ( {
227243 left : "auto" ,
228- right : "auto" ,
244+ right : "auto" ,
229245 width : "auto" ,
230246 minWidth : "auto" ,
231247} ) ;
232248
233249const calculateFloatingPosition = ( editorElement : HTMLElement ) => {
234250 const editorRect = editorElement . getBoundingClientRect ( ) ;
235-
251+
236252 return {
237253 left : `${ editorRect . left + 16 } px` , // 1rem margin
238254 right : "auto" ,
@@ -241,45 +257,48 @@ const calculateFloatingPosition = (editorElement: HTMLElement) => {
241257 } ;
242258} ;
243259
244- /**
260+ /**
245261 * Sets up scroll listeners on window and all scrollable parent elements.
246262 * Tracks scroll events to update toolbar visibility when editor position changes.
247263 */
248264const setupAllScrollListeners = (
249265 editorRef : React . RefObject < HTMLDivElement > ,
250266 onScroll : ( ) => void
251267) : ( ( ) => void ) => {
252- const listeners : Array < { element : Element | Window ; handler : ( ) => void } > = [ ] ;
253-
268+ const listeners : Array < { element : Element | Window ; handler : ( ) => void } > =
269+ [ ] ;
270+
254271 // Window scroll and resize handlers
255272 const handleScroll = ( ) => onScroll ( ) ;
256273 const handleResize = ( ) => onScroll ( ) ;
257-
274+
258275 window . addEventListener ( "scroll" , handleScroll , { passive : true } ) ;
259276 window . addEventListener ( "resize" , handleResize , { passive : true } ) ;
260-
277+
261278 listeners . push (
262279 { element : window , handler : handleScroll } ,
263280 { element : window , handler : handleResize }
264281 ) ;
265-
282+
266283 // Traverse up DOM tree to find scrollable containers
267284 let currentElement = editorRef . current ?. parentElement ;
268-
285+
269286 while ( currentElement ) {
270287 if ( isScrollableElement ( currentElement ) ) {
271288 const elementHandler = ( ) => onScroll ( ) ;
272- currentElement . addEventListener ( "scroll" , elementHandler , { passive : true } ) ;
289+ currentElement . addEventListener ( "scroll" , elementHandler , {
290+ passive : true ,
291+ } ) ;
273292 listeners . push ( { element : currentElement , handler : elementHandler } ) ;
274293 }
275294 currentElement = currentElement . parentElement ;
276295 }
277-
296+
278297 // Cleanup function removes all listeners
279298 return ( ) => {
280299 window . removeEventListener ( "scroll" , handleScroll ) ;
281300 window . removeEventListener ( "resize" , handleResize ) ;
282-
301+
283302 listeners . forEach ( ( { element, handler } ) => {
284303 if ( element !== window ) {
285304 element . removeEventListener ( "scroll" , handler ) ;
@@ -318,4 +337,4 @@ const renderFloatingToolbar = (
318337 < SimpleToolbar />
319338 </ div >
320339 </ div >
321- ) ;
340+ ) ;
0 commit comments