diff --git a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.css b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.css index 293faa98376a..ca22f6774f09 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.css +++ b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.css @@ -32,6 +32,14 @@ overflow-x: auto; } +.OwnerStackFlatListContainer { + display: inline-flex; +} + +.OwnerStackFlatListSeparator { + user-select: none; +} + .VRule { flex: 0 0 auto; height: 20px; diff --git a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js index 09bdb96af01c..596113bd8631 100644 --- a/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js +++ b/packages/react-devtools-shared/src/devtools/views/Components/OwnersStack.js @@ -77,6 +77,54 @@ function dialogReducer(state: State, action: Action) { } } +type OwnerStackFlatListProps = { + owners: Array, + selectedIndex: number, + selectOwner: SelectOwner, + setElementsTotalWidth: (width: number) => void, +}; + +function OwnerStackFlatList({ + owners, + selectedIndex, + selectOwner, + setElementsTotalWidth, +}: OwnerStackFlatListProps): React.Node { + const containerRef = useRef(null); + useLayoutEffect(() => { + const container = containerRef.current; + if (container === null) { + return; + } + + const ResizeObserver = container.ownerDocument.defaultView.ResizeObserver; + const observer = new ResizeObserver(entries => { + const entry = entries[0]; + setElementsTotalWidth(entry.contentRect.width); + }); + + observer.observe(container); + return observer.disconnect.bind(observer); + }, []); + + return ( +
+ {owners.map((owner, index) => ( + + + {index < owners.length - 1 && ( + » + )} + + ))} +
+ ); +} + export default function OwnerStack(): React.Node { const read = useContext(OwnersListContext); const {ownerID} = useContext(TreeStateContext); @@ -135,32 +183,10 @@ export default function OwnerStack(): React.Node { const selectedOwner = owners[selectedIndex]; - useLayoutEffect(() => { - // If we're already overflowing, then we don't need to re-measure items. - // That's because once the owners stack is open, it can only get larger (by drilling in). - // A totally new stack can only be reached by exiting this mode and re-entering it. - if (elementsBarRef.current === null || isOverflowing) { - return () => {}; - } - - let totalWidth = 0; - for (let i = 0; i < owners.length; i++) { - const element = elementsBarRef.current.children[i]; - const computedStyle = getComputedStyle(element); - - totalWidth += - element.offsetWidth + - parseInt(computedStyle.marginLeft, 10) + - parseInt(computedStyle.marginRight, 10); - } - - setElementsTotalWidth(totalWidth); - }, [elementsBarRef, isOverflowing, owners.length]); - return (
- {isOverflowing && ( + {isOverflowing ? ( )} + ) : ( + )} - {!isOverflowing && - owners.map((owner, index) => ( - - ))}
- + +
  • + +
  • + {index < lineage.length - 1 && ( + + » + + )} +
    ); }) )} @@ -271,37 +297,6 @@ export default function SuspenseBreadcrumbs(): React$Node { const containerRef = useRef(null); const isOverflowing = useIsOverflowing(containerRef, elementsTotalWidth); - useLayoutEffect(() => { - const container = containerRef.current; - - if ( - container === null || - // We want to measure the size of the flat list only when it's being used. - isOverflowing - ) { - return; - } - - const ResizeObserver = container.ownerDocument.defaultView.ResizeObserver; - const observer = new ResizeObserver(() => { - let totalWidth = 0; - for (let i = 0; i < container.children.length; i++) { - const element = container.children[i]; - const computedStyle = getComputedStyle(element); - - totalWidth += - element.offsetWidth + - parseInt(computedStyle.marginLeft, 10) + - parseInt(computedStyle.marginRight, 10); - } - setElementsTotalWidth(totalWidth); - }); - - observer.observe(container); - - return observer.disconnect.bind(observer); - }, [containerRef, isOverflowing]); - return (
    {isOverflowing ? ( @@ -315,6 +310,7 @@ export default function SuspenseBreadcrumbs(): React$Node { onItemClick={handleClick} onItemPointerEnter={highlightHostInstance} onItemPointerLeave={clearHighlightHostInstance} + setElementsTotalWidth={setElementsTotalWidth} /> )}