diff --git a/packages/react-components/src/MasterDetailLayout.tsx b/packages/react-components/src/MasterDetailLayout.tsx index 34cb029a..f93f3917 100644 --- a/packages/react-components/src/MasterDetailLayout.tsx +++ b/packages/react-components/src/MasterDetailLayout.tsx @@ -70,6 +70,10 @@ function Detail({ children }: DetailProps) { const nextDetailsKey = currentDetailsKey.current + 1; const [state, setState] = useState('idle'); const [currentChildren, setCurrentChildren] = useState(children); + // The transition completion handler closes over the children from when the + // transition started, so read the latest ones through a ref instead. + const latestChildren = useRef(children); + latestChildren.current = children; useLayoutEffect(() => { const layout = currentDetailsRef.current?.closest( @@ -92,6 +96,7 @@ function Detail({ children }: DetailProps) { // _startTransition calls the callback synchronously for add/replace, // and asynchronously for remove. + let outgoingClone: HTMLElement | undefined; layout ._startTransition(transitionType, async () => { if (transitionType === 'replace' && currentDetailsRef.current) { @@ -100,6 +105,7 @@ function Detail({ children }: DetailProps) { // WC can animate the clone out, then hide the React-managed original // so the WC's post-animation cleanup won't remove it from the DOM. const clone = currentDetailsRef.current.cloneNode(true) as HTMLElement; + outgoingClone = clone; clone.setAttribute('slot', 'detail-outgoing'); layout.appendChild(clone); currentDetailsRef.current.setAttribute('slot', 'detail-hidden'); @@ -119,8 +125,10 @@ function Detail({ children }: DetailProps) { layout.recalculateLayout(); }) .then(() => { - // Animation finished — sync React state to match DOM reality - setCurrentChildren(children); + // Animation finished — remove the clone the WC does not own, then + // sync React state to match DOM reality + outgoingClone?.remove(); + setCurrentChildren(latestChildren.current); currentDetailsKey.current = nextDetailsKey; setState('idle'); }); diff --git a/test/MasterDetailLayout.spec.tsx b/test/MasterDetailLayout.spec.tsx index b69f3a07..1c4f2e71 100644 --- a/test/MasterDetailLayout.spec.tsx +++ b/test/MasterDetailLayout.spec.tsx @@ -388,4 +388,85 @@ describe('MasterDetailLayout', () => { ); }); }); + + describe('real transitions', () => { + function ViewA() { + return