@@ -11,7 +11,7 @@ import type {SuspenseNode} from 'react-devtools-shared/src/frontend/types';
1111import typeof { SyntheticMouseEvent } from 'react-dom-bindings/src/events/SyntheticEvent' ;
1212
1313import * as React from 'react' ;
14- import { useContext , useLayoutEffect , useRef , useState } from 'react' ;
14+ import { Fragment , useContext , useLayoutEffect , useRef , useState } from 'react' ;
1515import Button from '../Button' ;
1616import ButtonIcon from '../ButtonIcon' ;
1717import Tooltip from '../Components/reach-ui/tooltip' ;
@@ -40,20 +40,40 @@ type SuspenseBreadcrumbsFlatListProps = {
4040 scrollIntoView ? : boolean ,
4141 ) => void ,
4242 onItemPointerLeave : ( event : SyntheticMouseEvent ) => void ,
43+ setElementsTotalWidth : ( width : number ) = > void ,
4344} ;
4445
4546function SuspenseBreadcrumbsFlatList ( {
4647 onItemClick,
4748 onItemPointerEnter,
4849 onItemPointerLeave,
50+ setElementsTotalWidth,
4951} : SuspenseBreadcrumbsFlatListProps ) : React$Node {
5052 const store = useContext ( StoreContext ) ;
5153 const { activityID} = useContext ( TreeStateContext ) ;
5254 const { selectedSuspenseID, lineage, roots} = useContext (
5355 SuspenseTreeStateContext ,
5456 ) ;
57+
58+ const containerRef = useRef < HTMLDivElement | null > ( null ) ;
59+ useLayoutEffect ( ( ) => {
60+ const container = containerRef . current ;
61+ if ( container === null ) {
62+ return ;
63+ }
64+
65+ const ResizeObserver = container . ownerDocument . defaultView . ResizeObserver ;
66+ const observer = new ResizeObserver ( entries => {
67+ const entry = entries [ 0 ] ;
68+ setElementsTotalWidth ( entry . contentRect . width ) ;
69+ } ) ;
70+
71+ observer . observe ( container ) ;
72+ return observer . disconnect . bind ( observer ) ;
73+ } , [ ] ) ;
74+
5575 return (
56- < ol className = { styles . SuspenseBreadcrumbsList } >
76+ < ol className = { styles . SuspenseBreadcrumbsList } ref = { containerRef } >
5777 { lineage === null ? null : lineage . length === 0 ? (
5878 // We selected the root. This means that we're currently viewing the Transition
5979 // that rendered the whole screen. In laymans terms this is really "Initial Paint" .
@@ -79,19 +99,25 @@ function SuspenseBreadcrumbsFlatList({
7999 const node = store . getSuspenseByID ( id ) ;
80100
81101 return (
82- < li
83- key = { id }
84- className = { styles . SuspenseBreadcrumbsListItem }
85- aria-current = { selectedSuspenseID === id }
86- onPointerEnter = { onItemPointerEnter . bind ( null , id , false ) }
87- onPointerLeave = { onItemPointerLeave } >
88- < button
89- className = { styles . SuspenseBreadcrumbsButton }
90- onClick = { onItemClick . bind ( null , id ) }
91- type = "button" >
92- { node === null ? 'Unknown' : node . name || 'Unknown' }
93- </ button >
94- </ li >
102+ < Fragment key = { id } >
103+ < li
104+ className = { styles . SuspenseBreadcrumbsListItem }
105+ aria-current = { selectedSuspenseID === id }
106+ onPointerEnter = { onItemPointerEnter . bind ( null , id , false ) }
107+ onPointerLeave = { onItemPointerLeave } >
108+ < button
109+ className = { styles . SuspenseBreadcrumbsButton }
110+ onClick = { onItemClick . bind ( null , id ) }
111+ type = "button" >
112+ { node === null ? 'Unknown' : node . name || 'Unknown' }
113+ </ button >
114+ </ li >
115+ { index < lineage . length - 1 && (
116+ < span className = { styles . SuspenseBreadcrumbsListItemSeparator } >
117+ »
118+ </ span >
119+ ) }
120+ </ Fragment >
95121 ) ;
96122 } )
97123 ) }
@@ -271,37 +297,6 @@ export default function SuspenseBreadcrumbs(): React$Node {
271297 const containerRef = useRef < HTMLDivElement | null > ( null ) ;
272298 const isOverflowing = useIsOverflowing ( containerRef , elementsTotalWidth ) ;
273299
274- useLayoutEffect ( ( ) => {
275- const container = containerRef . current ;
276-
277- if (
278- container === null ||
279- // We want to measure the size of the flat list only when it's being used.
280- isOverflowing
281- ) {
282- return ;
283- }
284-
285- const ResizeObserver = container . ownerDocument . defaultView . ResizeObserver ;
286- const observer = new ResizeObserver ( ( ) => {
287- let totalWidth = 0 ;
288- for ( let i = 0 ; i < container . children . length ; i ++ ) {
289- const element = container . children [ i ] ;
290- const computedStyle = getComputedStyle ( element ) ;
291-
292- totalWidth +=
293- element . offsetWidth +
294- parseInt ( computedStyle . marginLeft , 10 ) +
295- parseInt ( computedStyle . marginRight , 10 ) ;
296- }
297- setElementsTotalWidth ( totalWidth ) ;
298- } ) ;
299-
300- observer . observe ( container ) ;
301-
302- return observer . disconnect . bind ( observer ) ;
303- } , [ containerRef , isOverflowing ] ) ;
304-
305300 return (
306301 < div className = { styles . SuspenseBreadcrumbsContainer } ref = { containerRef } >
307302 { isOverflowing ? (
@@ -315,6 +310,7 @@ export default function SuspenseBreadcrumbs(): React$Node {
315310 onItemClick = { handleClick }
316311 onItemPointerEnter = { highlightHostInstance }
317312 onItemPointerLeave = { clearHighlightHostInstance }
313+ setElementsTotalWidth = { setElementsTotalWidth }
318314 />
319315 ) }
320316 </ div >
0 commit comments