@@ -717,6 +717,52 @@ function DropdownMenuWithNestedSubpages() {
717717 )
718718}
719719
720+ function DropdownMenuWithMeasuredNestedSubpages ( ) {
721+ return (
722+ < DropdownMenu . Root >
723+ < DropdownMenu . Trigger data-testid = "trigger" >
724+ Open Menu
725+ </ DropdownMenu . Trigger >
726+ < DropdownMenu . Portal >
727+ < DropdownMenu . Positioner >
728+ < DropdownMenu . Popup >
729+ < DropdownMenu . Surface data-testid = "root-surface" >
730+ < DropdownMenu . List data-testid = "root-list" >
731+ < DropdownMenu . SubpageTrigger
732+ data-testid = "subpage-trigger-1"
733+ targetPageId = "page-1"
734+ data-measure-width = "420"
735+ >
736+ Root Wide Item
737+ </ DropdownMenu . SubpageTrigger >
738+ </ DropdownMenu . List >
739+ </ DropdownMenu . Surface >
740+
741+ < DropdownMenu . Subpage pageId = "page-1" >
742+ < DropdownMenu . Surface data-testid = "subpage-surface-1" >
743+ < DropdownMenu . List data-testid = "subpage-list-1" >
744+ < DropdownMenu . SubpageBackItem
745+ data-testid = "subpage-back-item-1"
746+ data-measure-width = "180"
747+ >
748+ Back
749+ </ DropdownMenu . SubpageBackItem >
750+ < DropdownMenu . Item
751+ data-testid = "subpage-item-1"
752+ data-measure-width = "200"
753+ >
754+ Narrow Item
755+ </ DropdownMenu . Item >
756+ </ DropdownMenu . List >
757+ </ DropdownMenu . Surface >
758+ </ DropdownMenu . Subpage >
759+ </ DropdownMenu . Popup >
760+ </ DropdownMenu . Positioner >
761+ </ DropdownMenu . Portal >
762+ </ DropdownMenu . Root >
763+ )
764+ }
765+
720766function DropdownMenuWithAsyncSubpageBackItem ( {
721767 onSelectAsync,
722768} : {
@@ -2396,6 +2442,69 @@ describe('<DropdownMenu.Root />', () => {
23962442 } )
23972443 } )
23982444
2445+ it ( 'keeps sticky row width between subpage navigations in the same popup' , async ( ) => {
2446+ const user = userEvent . setup ( )
2447+
2448+ const getMockWidth = ( element : HTMLElement ) => {
2449+ const rawWidth = element . getAttribute ( 'data-measure-width' )
2450+ if ( ! rawWidth ) {
2451+ return 0
2452+ }
2453+
2454+ const parsedWidth = Number . parseFloat ( rawWidth )
2455+ return Number . isFinite ( parsedWidth ) ? parsedWidth : 0
2456+ }
2457+
2458+ const requestAnimationFrameSpy = vi
2459+ . spyOn ( window , 'requestAnimationFrame' )
2460+ . mockImplementation ( ( callback : FrameRequestCallback ) => {
2461+ callback ( 0 )
2462+ return 1
2463+ } )
2464+ const cancelAnimationFrameSpy = vi
2465+ . spyOn ( window , 'cancelAnimationFrame' )
2466+ . mockImplementation ( ( ) => { } )
2467+ const scrollWidthSpy = vi
2468+ . spyOn ( HTMLElement . prototype , 'scrollWidth' , 'get' )
2469+ . mockImplementation ( function ( this : HTMLElement ) {
2470+ return getMockWidth ( this )
2471+ } )
2472+ const offsetWidthSpy = vi
2473+ . spyOn ( HTMLElement . prototype , 'offsetWidth' , 'get' )
2474+ . mockImplementation ( function ( this : HTMLElement ) {
2475+ return getMockWidth ( this )
2476+ } )
2477+
2478+ try {
2479+ render ( < DropdownMenuWithMeasuredNestedSubpages /> )
2480+
2481+ await user . click ( screen . getByTestId ( 'trigger' ) )
2482+
2483+ await waitFor ( ( ) => {
2484+ expect ( screen . getByTestId ( 'root-surface' ) ) . toBeInTheDocument ( )
2485+ } )
2486+
2487+ const popup = screen . getByRole ( 'dialog' )
2488+
2489+ await waitFor ( ( ) => {
2490+ expect ( popup . style . getPropertyValue ( '--row-width' ) ) . toBe ( '421px' )
2491+ } )
2492+
2493+ await user . click ( screen . getByTestId ( 'subpage-trigger-1' ) )
2494+
2495+ await waitFor ( ( ) => {
2496+ expect ( screen . getByTestId ( 'subpage-surface-1' ) ) . toBeInTheDocument ( )
2497+ } )
2498+
2499+ expect ( popup . style . getPropertyValue ( '--row-width' ) ) . toBe ( '421px' )
2500+ } finally {
2501+ requestAnimationFrameSpy . mockRestore ( )
2502+ cancelAnimationFrameSpy . mockRestore ( )
2503+ scrollWidthSpy . mockRestore ( )
2504+ offsetWidthSpy . mockRestore ( )
2505+ }
2506+ } )
2507+
23992508 it ( 'goes back one page with ArrowLeft' , async ( ) => {
24002509 const user = userEvent . setup ( )
24012510 render ( < DropdownMenuWithNestedSubpages /> )
0 commit comments