@@ -228,6 +228,150 @@ describe('<Toast.Root />', () => {
228228 } ) ;
229229 } ) ;
230230
231+ it . skipIf ( isJSDOM ) (
232+ 'clears the starting state and restores the height when re-adding an ending toast' ,
233+ async ( ) => {
234+ const animationsDisabled = globalThis . BASE_UI_ANIMATIONS_DISABLED ;
235+ globalThis . BASE_UI_ANIMATIONS_DISABLED = false ;
236+
237+ function App ( ) {
238+ const { add, close, toasts } = Toast . useToastManager ( ) ;
239+
240+ return (
241+ < React . Fragment >
242+ < style >
243+ { `
244+ [data-testid="toast-root"] {
245+ opacity: 1;
246+ transition: opacity 10s;
247+ }
248+
249+ [data-testid="toast-root"][data-ending-style] {
250+ opacity: 0;
251+ }
252+ ` }
253+ </ style >
254+ < button type = "button" onClick = { ( ) => add ( { id : 'save' , title : 'Saved' , timeout : 0 } ) } >
255+ add
256+ </ button >
257+ < button type = "button" onClick = { ( ) => close ( 'save' ) } >
258+ close
259+ </ button >
260+ < Toast . Viewport >
261+ { toasts . map ( ( toastItem ) => (
262+ < Toast . Root key = { toastItem . id } toast = { toastItem } data-testid = "toast-root" >
263+ < Toast . Title />
264+ </ Toast . Root >
265+ ) ) }
266+ </ Toast . Viewport >
267+ </ React . Fragment >
268+ ) ;
269+ }
270+
271+ try {
272+ const { user } = await render (
273+ < Toast . Provider >
274+ < App />
275+ </ Toast . Provider > ,
276+ ) ;
277+
278+ await user . click ( screen . getByRole ( 'button' , { name : 'add' } ) ) ;
279+ const toastRoot = screen . getByTestId ( 'toast-root' ) ;
280+ expect ( toastRoot ) . not . toHaveAttribute ( 'data-starting-style' ) ;
281+ const initialHeight = toastRoot . style . getPropertyValue ( '--toast-height' ) ;
282+ expect ( initialHeight ) . not . toBe ( '' ) ;
283+
284+ await user . click ( screen . getByRole ( 'button' , { name : 'close' } ) ) ;
285+ expect ( toastRoot ) . toHaveAttribute ( 'data-ending-style' ) ;
286+ expect ( toastRoot . style . getPropertyValue ( '--toast-height' ) ) . toBe ( '' ) ;
287+
288+ await user . click ( screen . getByRole ( 'button' , { name : 'add' } ) ) ;
289+ expect ( screen . getByTestId ( 'toast-root' ) ) . toBe ( toastRoot ) ;
290+
291+ await waitFor ( ( ) => {
292+ expect ( toastRoot ) . not . toHaveAttribute ( 'data-starting-style' ) ;
293+ } ) ;
294+ await waitFor ( ( ) => {
295+ expect ( toastRoot . style . getPropertyValue ( '--toast-height' ) ) . toBe ( initialHeight ) ;
296+ } ) ;
297+ } finally {
298+ globalThis . BASE_UI_ANIMATIONS_DISABLED = animationsDisabled ;
299+ }
300+ } ,
301+ ) ;
302+
303+ it . skipIf ( isJSDOM ) ( 'registers an active toast after its root remounts' , async ( ) => {
304+ function App ( ) {
305+ const { add, toasts } = Toast . useToastManager ( ) ;
306+ const [ showToasts , setShowToasts ] = React . useState ( true ) ;
307+ const [ longTitle , setLongTitle ] = React . useState ( false ) ;
308+
309+ return (
310+ < React . Fragment >
311+ < button type = "button" onClick = { ( ) => add ( { id : 'save' , title : 'Saved' , timeout : 0 } ) } >
312+ add
313+ </ button >
314+ < button type = "button" onClick = { ( ) => setShowToasts ( false ) } >
315+ hide
316+ </ button >
317+ < button
318+ type = "button"
319+ onClick = { ( ) => {
320+ setLongTitle ( true ) ;
321+ setShowToasts ( true ) ;
322+ } }
323+ >
324+ show
325+ </ button >
326+ < Toast . Viewport >
327+ { showToasts
328+ ? toasts . map ( ( toastItem ) => (
329+ < Toast . Root
330+ key = { toastItem . id }
331+ toast = { toastItem }
332+ data-testid = "toast-root"
333+ style = { { width : 30 } }
334+ >
335+ < Toast . Title >
336+ { longTitle ? 'This title is much longer than before' : undefined }
337+ </ Toast . Title >
338+ </ Toast . Root >
339+ ) )
340+ : null }
341+ </ Toast . Viewport >
342+ </ React . Fragment >
343+ ) ;
344+ }
345+
346+ const { user } = await render (
347+ < Toast . Provider >
348+ < App />
349+ </ Toast . Provider > ,
350+ ) ;
351+
352+ await user . click ( screen . getByRole ( 'button' , { name : 'add' } ) ) ;
353+ const initialRoot = screen . getByTestId ( 'toast-root' ) ;
354+ expect ( initialRoot ) . not . toHaveAttribute ( 'data-starting-style' ) ;
355+ const initialHeight = parseInt ( initialRoot . style . getPropertyValue ( '--toast-height' ) , 10 ) ;
356+
357+ await user . click ( screen . getByRole ( 'button' , { name : 'hide' } ) ) ;
358+ expect ( screen . queryByTestId ( 'toast-root' ) ) . toBe ( null ) ;
359+
360+ await user . click ( screen . getByRole ( 'button' , { name : 'show' } ) ) ;
361+ const remountedRoot = screen . getByTestId ( 'toast-root' ) ;
362+ expect ( remountedRoot ) . not . toBe ( initialRoot ) ;
363+
364+ await waitFor ( ( ) => {
365+ const remountedHeight = parseInt ( remountedRoot . style . getPropertyValue ( '--toast-height' ) , 10 ) ;
366+ expect ( remountedHeight ) . toBeGreaterThan ( initialHeight ) ;
367+ } ) ;
368+
369+ await user . keyboard ( '{F6}' ) ;
370+ await user . keyboard ( '{Tab}' ) ;
371+
372+ expect ( remountedRoot ) . toHaveFocus ( ) ;
373+ } ) ;
374+
231375 // requires :focus-visible check
232376 it . skipIf ( isJSDOM ) ( 'closes when pressing escape' , async ( ) => {
233377 const { user } = await render (
0 commit comments