@@ -5,6 +5,7 @@ import React, { useState, useEffect, useRef } from 'react'
55import { NextLogo } from './internal/next-logo'
66import { useIsDevBuilding } from '../../../../../../../dev/dev-build-indicator/internal/initialize-for-new-overlay'
77import { useIsDevRendering } from './internal/dev-render-indicator'
8+ import { useDelayedRender } from './internal/use-delayed-render'
89
910// TODO: test a11y
1011// TODO: add E2E tests to cover different scenarios
@@ -36,6 +37,9 @@ export function DevToolsIndicator({
3637 )
3738}
3839
40+ const ANIMATE_OUT_DURATION_MS = 200
41+ const ANIMATE_OUT_TIMING_FUNCTION = 'cubic-bezier(0.175, 0.885, 0.32, 1.1)'
42+
3943const DevToolsPopover = ( {
4044 onIssuesClick,
4145 issueCount,
@@ -55,6 +59,13 @@ const DevToolsPopover = ({
5559 const buttonRef = useRef < HTMLDivElement > ( null )
5660 const [ isPopoverOpen , setIsPopoverOpen ] = useState ( false )
5761
62+ const { mounted, rendered } = useDelayedRender ( isPopoverOpen , {
63+ // Intentionally no fade in, makes the UI feel more immediate
64+ enterDelay : 0 ,
65+ // Graceful fade out to confirm that the UI did not break
66+ exitDelay : ANIMATE_OUT_DURATION_MS ,
67+ } )
68+
5869 useEffect ( ( ) => {
5970 // Close popover when clicking outside of it or its button
6071 const handleClickOutside = ( event : MouseEvent ) => {
@@ -114,13 +125,20 @@ const DevToolsPopover = ({
114125 />
115126 </ div >
116127
117- { isPopoverOpen && (
128+ { mounted && (
118129 < div
119130 ref = { popoverRef }
120131 id = "dev-tools-popover"
121132 role = "dialog"
122133 aria-labelledby = "dev-tools-title"
123134 data-nextjs-dev-tools-popover
135+ data-rendered = { rendered }
136+ style = {
137+ {
138+ '--animate-out-duration-ms' : `${ ANIMATE_OUT_DURATION_MS } ms` ,
139+ '--animate-out-timing-function' : ANIMATE_OUT_TIMING_FUNCTION ,
140+ } as React . CSSProperties
141+ }
124142 tabIndex = { - 1 }
125143 >
126144 < div data-nextjs-dev-tools-content >
0 commit comments