@@ -10,7 +10,6 @@ import {
1010 useState ,
1111 RawHTML ,
1212 useEffect ,
13- useCallback ,
1413 useMemo ,
1514 useRef ,
1615} from '@wordpress/element' ;
@@ -41,7 +40,8 @@ import { unlock } from '../../lock-unlock';
4140import CommentAuthorInfo from './comment-author-info' ;
4241import CommentForm from './comment-form' ;
4342import { focusCommentThread , getCommentExcerpt } from './utils' ;
44- import { useFloatingThread } from './hooks' ;
43+ import { useFloatingBoard , useFloatingThread } from './hooks' ;
44+ import { FloatingContainer } from './floating-container' ;
4545import { AddComment } from './add-comment' ;
4646import { store as editorStore } from '../../store' ;
4747
@@ -58,13 +58,7 @@ export function Comments( {
5858 isFloating = false ,
5959 commentLastUpdated,
6060} ) {
61- const [ heights , setHeights ] = useState ( { } ) ;
62- const [ boardOffsets , setBoardOffsets ] = useState ( { } ) ;
63- const [ blockRefs , setBlockRefs ] = useState ( { } ) ;
64-
65- const { setCanvasMinHeight, selectNote } = unlock (
66- useDispatch ( editorStore )
67- ) ;
61+ const { selectNote } = unlock ( useDispatch ( editorStore ) ) ;
6862 const { selectBlock, toggleBlockSpotlight } = unlock (
6963 useDispatch ( blockEditorStore )
7064 ) ;
@@ -182,151 +176,11 @@ export function Comments( {
182176 }
183177 } , [ noteFocused , selectedNote , selectNote , commentSidebarRef ] ) ;
184178
185- // Recalculate floating comment thread offsets whenever the heights change.
186- useEffect ( ( ) => {
187- /**
188- * Calculate the y offsets for all comment threads. Account for potentially
189- * overlapping threads and adjust their positions accordingly.
190- */
191- const calculateAllOffsets = ( ) => {
192- const offsets = { } ;
193-
194- if ( ! isFloating ) {
195- return { offsets, minHeight : 0 } ;
196- }
197-
198- // Find the index of the selected thread.
199- const selectedThreadIndex = threads . findIndex (
200- ( t ) => t . id === selectedNote
201- ) ;
202-
203- const breakIndex =
204- selectedThreadIndex === - 1 ? 0 : selectedThreadIndex ;
205-
206- // If there is a selected thread, push threads above up and threads below down.
207- const selectedThreadData = threads [ breakIndex ] ;
208-
209- if (
210- ! selectedThreadData ||
211- ! blockRefs [ selectedThreadData . id ]
212- ) {
213- return { offsets, minHeight : 0 } ;
214- }
215-
216- let blockElement = blockRefs [ selectedThreadData . id ] ;
217- let blockRect = blockElement ?. getBoundingClientRect ( ) ;
218- const selectedThreadTop = blockRect ?. top || 0 ;
219- const selectedThreadHeight = heights [ selectedThreadData . id ] || 0 ;
220-
221- offsets [ selectedThreadData . id ] = - 16 ;
222-
223- let previousThreadData = {
224- threadTop : selectedThreadTop - 16 ,
225- threadHeight : selectedThreadHeight ,
226- } ;
227-
228- // Process threads after the selected thread, offsetting any overlapping
229- // threads downward.
230- for ( let i = breakIndex + 1 ; i < threads . length ; i ++ ) {
231- const thread = threads [ i ] ;
232- if ( ! blockRefs [ thread . id ] ) {
233- continue ;
234- }
235-
236- blockElement = blockRefs [ thread . id ] ;
237- blockRect = blockElement ?. getBoundingClientRect ( ) ;
238- const threadTop = blockRect ?. top || 0 ;
239- const threadHeight = heights [ thread . id ] || 0 ;
240-
241- let additionalOffset = - 16 ;
242-
243- // Check if the thread overlaps with the previous one.
244- const previousBottom =
245- previousThreadData . threadTop +
246- previousThreadData . threadHeight ;
247- if ( threadTop < previousBottom + 16 ) {
248- // Shift down by the difference plus a margin to avoid overlap.
249- additionalOffset = previousBottom - threadTop + 20 ;
250- }
251-
252- offsets [ thread . id ] = additionalOffset ;
253-
254- // Update for next iteration.
255- previousThreadData = {
256- threadTop : threadTop + additionalOffset ,
257- threadHeight,
258- } ;
259- }
260-
261- // Process threads before the selected thread, offsetting any overlapping
262- // threads upward.
263- let nextThreadData = {
264- threadTop : selectedThreadTop - 16 ,
265- } ;
266-
267- for ( let i = selectedThreadIndex - 1 ; i >= 0 ; i -- ) {
268- const thread = threads [ i ] ;
269- if ( ! blockRefs [ thread . id ] ) {
270- continue ;
271- }
272-
273- blockElement = blockRefs [ thread . id ] ;
274- blockRect = blockElement ?. getBoundingClientRect ( ) ;
275- const threadTop = blockRect ?. top || 0 ;
276- const threadHeight = heights [ thread . id ] || 0 ;
277-
278- let additionalOffset = - 16 ;
279-
280- // Calculate the bottom position of this thread with default offset.
281- const threadBottom = threadTop + threadHeight ;
282-
283- // Check if this thread's bottom would overlap with the next thread's top.
284- if ( threadBottom > nextThreadData . threadTop ) {
285- // Shift up by the difference plus a margin to avoid overlap.
286- additionalOffset =
287- nextThreadData . threadTop -
288- threadTop -
289- threadHeight -
290- 20 ;
291- }
292-
293- offsets [ thread . id ] = additionalOffset ;
294-
295- // Update for next iteration (going upward).
296- nextThreadData = {
297- threadTop : threadTop + additionalOffset ,
298- } ;
299- }
300-
301- let editorMinHeight = 0 ;
302- // Take the calculated top of the final note plus its height as the editor min height.
303- const lastThread = threads [ threads . length - 1 ] ;
304- if ( blockRefs [ lastThread . id ] ) {
305- const lastBlockElement = blockRefs [ lastThread . id ] ;
306- const lastBlockRect = lastBlockElement ?. getBoundingClientRect ( ) ;
307- const lastThreadTop = lastBlockRect ?. top || 0 ;
308- const lastThreadHeight = heights [ lastThread . id ] || 0 ;
309- const lastThreadOffset = offsets [ lastThread . id ] || 0 ;
310- editorMinHeight =
311- lastThreadTop + lastThreadHeight + lastThreadOffset + 32 ;
312- }
313-
314- return { offsets, minHeight : editorMinHeight } ;
315- } ;
316- const { offsets : newOffsets , minHeight } = calculateAllOffsets ( ) ;
317- if ( Object . keys ( newOffsets ) . length > 0 ) {
318- setBoardOffsets ( newOffsets ) ;
319- }
320- // Ensure the editor has enough height to scroll to all notes.
321- setCanvasMinHeight ( minHeight ) ;
322- } , [
323- heights ,
324- blockRefs ,
325- isFloating ,
179+ const { boardOffsets, registerThread, reportHeight } = useFloatingBoard ( {
326180 threads,
327- selectedNote ,
328- setCanvasMinHeight ,
329- ] ) ;
181+ selectedNoteId : selectedNote ,
182+ isFloating ,
183+ } ) ;
330184
331185 const handleThreadNavigation = ( event , thread , isSelected ) => {
332186 if ( event . defaultPrevented ) {
@@ -393,10 +247,6 @@ export function Comments( {
393247 }
394248 } ;
395249
396- const setBlockRef = useCallback ( ( id , blockRef ) => {
397- setBlockRefs ( ( prev ) => ( { ...prev , [ id ] : blockRef } ) ) ;
398- } , [ ] ) ;
399-
400250 const hasThreads = Array . isArray ( threads ) && threads . length > 0 ;
401251 // A special case for `template-locked` mode - https://github.com/WordPress/gutenberg/pull/72646.
402252 if ( ! hasThreads && ! isFloating ) {
@@ -426,11 +276,17 @@ export function Comments( {
426276 isSelected = { selectedNote === thread . id }
427277 commentSidebarRef = { commentSidebarRef }
428278 reflowComments = { reflowComments }
429- isFloating = { isFloating }
430- calculatedOffset = { boardOffsets [ thread . id ] ?? 0 }
431- setHeights = { setHeights }
432- setBlockRef = { setBlockRef }
433- commentLastUpdated = { commentLastUpdated }
279+ floating = {
280+ isFloating
281+ ? {
282+ calculatedOffset :
283+ boardOffsets [ thread . id ] ?? 0 ,
284+ reportHeight,
285+ registerThread,
286+ commentLastUpdated,
287+ }
288+ : undefined
289+ }
434290 onKeyDown = { ( event ) =>
435291 handleThreadNavigation (
436292 event ,
@@ -452,13 +308,10 @@ function Thread( {
452308 isSelected,
453309 commentSidebarRef,
454310 reflowComments,
455- isFloating,
456- calculatedOffset,
457- setHeights,
458- setBlockRef,
459- commentLastUpdated,
311+ floating,
460312 onKeyDown,
461313} ) {
314+ const isFloating = ! ! floating ;
462315 const { toggleBlockHighlight, selectBlock, toggleBlockSpotlight } = unlock (
463316 useDispatch ( blockEditorStore )
464317 ) ;
@@ -474,11 +327,11 @@ function Thread( {
474327 ) ;
475328 const { y, refs } = useFloatingThread ( {
476329 thread,
477- calculatedOffset,
478- setHeights ,
479- setBlockRef ,
330+ calculatedOffset : floating ?. calculatedOffset ?? 0 ,
331+ reportHeight : floating ?. reportHeight ,
332+ registerThread : floating ?. registerThread ,
480333 selectedThread : selectedNote ,
481- commentLastUpdated,
334+ commentLastUpdated : floating ?. commentLastUpdated ,
482335 } ) ;
483336 const isKeyboardTabbingRef = useRef ( false ) ;
484337
@@ -571,18 +424,16 @@ function Thread( {
571424 onSubmit = { onAddReply }
572425 commentSidebarRef = { commentSidebarRef }
573426 reflowComments = { reflowComments }
574- isFloating = { isFloating }
575- y = { y }
576- refs = { refs }
427+ floating = { { y, refs } }
577428 />
578429 ) ;
579430 }
580431
581432 return (
582- < VStack
433+ < FloatingContainer
434+ floating = { isFloating ? { y, refs } : undefined }
583435 className = { clsx ( 'editor-collab-sidebar-panel__thread' , {
584436 'is-selected' : isSelected ,
585- 'is-floating' : isFloating ,
586437 } ) }
587438 id = { `comment-thread-${ thread . id } ` }
588439 spacing = "3"
@@ -607,8 +458,6 @@ function Thread( {
607458 role = "treeitem"
608459 aria-label = { ariaLabel }
609460 aria-expanded = { isSelected }
610- ref = { isFloating ? refs . setFloating : undefined }
611- style = { isFloating ? { top : y } : undefined }
612461 >
613462 < Button
614463 className = "editor-collab-sidebar-panel__skip-to-comment"
@@ -759,7 +608,7 @@ function Thread( {
759608 { __ ( 'Back to block' ) }
760609 </ Button >
761610 ) }
762- </ VStack >
611+ </ FloatingContainer >
763612 ) ;
764613}
765614
0 commit comments