Skip to content

Commit 324a854

Browse files
authored
Revert "[dev-overlay] Fix error dialog resizing logic" (#77849)
Reverts #77830 This was breaking the react 18.3 tests, where the toggling stack frames is not working in 18.3. Possibly broken by the ref related changes. x-ref: https://github.com/vercel/next.js/actions/runs/14274082641/job/40015934515
1 parent fd5669d commit 324a854

File tree

11 files changed

+95
-132
lines changed

11 files changed

+95
-132
lines changed

packages/next/src/client/components/react-dev-overlay/ui/components/dialog/dialog.tsx

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react'
22
import { useOnClickOutside } from '../../hooks/use-on-click-outside'
3+
import { useMeasureHeight } from '../../hooks/use-measure-height'
34

45
export type DialogProps = {
56
children?: React.ReactNode
@@ -36,6 +37,9 @@ const Dialog: React.FC<DialogProps> = function Dialog({
3637
: undefined
3738
)
3839

40+
const ref = React.useRef<HTMLDivElement | null>(null)
41+
const [height, pristine] = useMeasureHeight(ref)
42+
3943
useOnClickOutside(
4044
dialogRef.current,
4145
CSS_SELECTORS_TO_EXCLUDE_ON_CLICK_OUTSIDE,
@@ -98,7 +102,19 @@ const Dialog: React.FC<DialogProps> = function Dialog({
98102
}}
99103
{...props}
100104
>
101-
{children}
105+
<div
106+
ref={dialogResizerRef}
107+
data-nextjs-dialog-sizer
108+
// [x] Don't animate on initial load
109+
// [x] No duplicate elements
110+
// [x] Responds to content growth
111+
style={{
112+
height,
113+
transition: pristine ? undefined : 'height 250ms var(--timing-swift)',
114+
}}
115+
>
116+
<div ref={ref}>{children}</div>
117+
</div>
102118
</div>
103119
)
104120
}

packages/next/src/client/components/react-dev-overlay/ui/components/dialog/styles.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const styles = `
33
--next-dialog-radius: var(--rounded-xl);
44
--next-dialog-max-width: 960px;
55
--next-dialog-row-padding: 16px;
6-
--next-dialog-padding: 12px;
6+
--next-dialog-padding-x: 12px;
77
--next-dialog-notch-height: 42px;
88
--next-dialog-border-width: 1px;
99
@@ -14,7 +14,7 @@ const styles = `
1414
max-width: var(--next-dialog-max-width);
1515
margin-right: auto;
1616
margin-left: auto;
17-
scale: 0.97;
17+
scale: 0.98;
1818
opacity: 0;
1919
transition-property: scale, opacity;
2020
transition-duration: var(--transition-duration);
@@ -28,7 +28,7 @@ const styles = `
2828
[data-nextjs-scroll-fader][data-side="top"] {
2929
left: 1px;
3030
top: calc(var(--next-dialog-notch-height) + var(--next-dialog-border-width));
31-
width: calc(100% - var(--next-dialog-padding));
31+
width: calc(100% - var(--next-dialog-padding-x));
3232
opacity: 0;
3333
}
3434
}
@@ -82,7 +82,7 @@ const styles = `
8282
display: flex;
8383
flex-direction: column;
8484
position: relative;
85-
padding: var(--next-dialog-padding);
85+
padding: 16px var(--next-dialog-padding-x);
8686
}
8787
8888
[data-nextjs-dialog-content] > [data-nextjs-dialog-header] {

packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay-layout/error-overlay-layout.test.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ const renderTestComponent = () => {
2424
rendered={true}
2525
transitionDurationMs={200}
2626
isTurbopack={false}
27-
errorCount={1}
2827
versionInfo={{
2928
installed: '15.0.0',
3029
staleness: 'fresh',

packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay-layout/error-overlay-layout.tsx

+23-50
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import type { ReadyRuntimeError } from '../../../../utils/get-error-by-type'
3636
import { EnvironmentNameLabel } from '../environment-name-label/environment-name-label'
3737
import { useFocusTrap } from '../dev-tools-indicator/utils'
3838
import { Fader } from '../../fader'
39-
import { Resizer } from '../../resizer'
4039

4140
export interface ErrorOverlayLayoutProps extends ErrorBaseProps {
4241
errorMessage: ErrorMessageType
@@ -60,7 +59,6 @@ export function ErrorOverlayLayout({
6059
errorType,
6160
children,
6261
errorCode,
63-
errorCount,
6462
error,
6563
debugInfo,
6664
isBuildError,
@@ -85,10 +83,6 @@ export function ErrorOverlayLayout({
8583
} as React.CSSProperties,
8684
}
8785

88-
const [animating, setAnimating] = React.useState(
89-
Boolean(transitionDurationMs)
90-
)
91-
9286
const faderRef = React.useRef<HTMLDivElement | null>(null)
9387
const hasFooter = Boolean(footerMessage || errorCode)
9488
const dialogRef = React.useRef<HTMLDivElement | null>(null)
@@ -101,23 +95,9 @@ export function ErrorOverlayLayout({
10195
}
10296
}
10397

104-
function onTransitionEnd({ propertyName, target }: React.TransitionEvent) {
105-
// We can only measure height after the `scale` transition ends,
106-
// otherwise we will measure height as a multiple of the animating value
107-
// which will give us an incorrect value.
108-
if (propertyName === 'scale' && target === dialogRef.current) {
109-
setAnimating(false)
110-
}
111-
}
112-
11398
return (
11499
<ErrorOverlayOverlay fixed={isBuildError} {...animationProps}>
115-
<div
116-
data-nextjs-dialog-root
117-
onTransitionEnd={onTransitionEnd}
118-
ref={dialogRef}
119-
{...animationProps}
120-
>
100+
<div data-nextjs-dialog-root ref={dialogRef} {...animationProps}>
121101
<ErrorOverlayNav
122102
runtimeErrors={runtimeErrors}
123103
activeIdx={activeIdx}
@@ -139,37 +119,30 @@ export function ErrorOverlayLayout({
139119
)
140120
}
141121
>
142-
<Resizer
143-
ref={dialogResizerRef}
144-
measure={!animating}
145-
data-nextjs-dialog-sizer
146-
>
147-
<DialogContent>
148-
<ErrorOverlayDialogHeader>
149-
<div
150-
className="nextjs__container_errors__error_title"
151-
// allow assertion in tests before error rating is implemented
152-
data-nextjs-error-code={errorCode}
153-
>
154-
<span data-nextjs-error-label-group>
155-
<ErrorTypeLabel errorType={errorType} />
156-
{error.environmentName && (
157-
<EnvironmentNameLabel
158-
environmentName={error.environmentName}
159-
/>
160-
)}
161-
</span>
162-
<ErrorOverlayToolbar error={error} debugInfo={debugInfo} />
163-
</div>
164-
<ErrorMessage errorMessage={errorMessage} />
165-
</ErrorOverlayDialogHeader>
166-
167-
<ErrorOverlayDialogBody>{children}</ErrorOverlayDialogBody>
168-
</DialogContent>
169-
</Resizer>
122+
<DialogContent>
123+
<ErrorOverlayDialogHeader>
124+
<div
125+
className="nextjs__container_errors__error_title"
126+
// allow assertion in tests before error rating is implemented
127+
data-nextjs-error-code={errorCode}
128+
>
129+
<span data-nextjs-error-label-group>
130+
<ErrorTypeLabel errorType={errorType} />
131+
{error.environmentName && (
132+
<EnvironmentNameLabel
133+
environmentName={error.environmentName}
134+
/>
135+
)}
136+
</span>
137+
<ErrorOverlayToolbar error={error} debugInfo={debugInfo} />
138+
</div>
139+
<ErrorMessage errorMessage={errorMessage} />
140+
</ErrorOverlayDialogHeader>
170141

142+
<ErrorOverlayDialogBody>{children}</ErrorOverlayDialogBody>
143+
</DialogContent>
171144
<ErrorOverlayBottomStack
172-
errorCount={errorCount}
145+
errorCount={runtimeErrors?.length ?? 0}
173146
activeIdx={activeIdx ?? 0}
174147
/>
175148
</ErrorOverlayDialog>

packages/next/src/client/components/react-dev-overlay/ui/components/errors/error-overlay/error-overlay.tsx

-4
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,18 @@ export interface ErrorBaseProps {
1313
transitionDurationMs: number
1414
isTurbopack: boolean
1515
versionInfo: OverlayState['versionInfo']
16-
errorCount: number
1716
}
1817

1918
export function ErrorOverlay({
2019
state,
2120
runtimeErrors,
2221
isErrorOverlayOpen,
2322
setIsErrorOverlayOpen,
24-
errorCount,
2523
}: {
2624
state: OverlayState
2725
runtimeErrors: ReadyRuntimeError[]
2826
isErrorOverlayOpen: boolean
2927
setIsErrorOverlayOpen: (value: boolean) => void
30-
errorCount: number
3128
}) {
3229
const isTurbopack = !!process.env.TURBOPACK
3330

@@ -41,7 +38,6 @@ export function ErrorOverlay({
4138
transitionDurationMs,
4239
isTurbopack,
4340
versionInfo: state.versionInfo,
44-
errorCount,
4541
}
4642

4743
if (state.buildError !== null) {

packages/next/src/client/components/react-dev-overlay/ui/components/resizer/index.tsx

-65
This file was deleted.

packages/next/src/client/components/react-dev-overlay/ui/container/errors.tsx

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useMemo, useRef, Suspense } from 'react'
1+
import { useState, useMemo, useEffect, useRef, Suspense } from 'react'
22
import type { DebugInfo } from '../../types'
33
import { Overlay } from '../components/overlay'
44
import { RuntimeError } from './runtime-error'
@@ -89,6 +89,18 @@ export function Errors({
8989
}: ErrorsProps) {
9090
const dialogResizerRef = useRef<HTMLDivElement | null>(null)
9191

92+
useEffect(() => {
93+
// Close the error overlay when pressing escape
94+
function handleKeyDown(event: KeyboardEvent) {
95+
if (event.key === 'Escape') {
96+
onClose()
97+
}
98+
}
99+
100+
document.addEventListener('keydown', handleKeyDown)
101+
return () => document.removeEventListener('keydown', handleKeyDown)
102+
}, [onClose])
103+
92104
const isLoading = useMemo<boolean>(() => {
93105
return runtimeErrors.length < 1
94106
}, [runtimeErrors.length])

packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.stories.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,9 @@ export const Default: Story = {
9292
src={imgApp}
9393
style={{
9494
width: '100%',
95-
height: '100vh',
95+
height: '100%',
9696
objectFit: 'contain',
97+
filter: 'invert(1)',
9798
}}
9899
/>
99100
<DevOverlay

packages/next/src/client/components/react-dev-overlay/ui/dev-overlay.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ export function DevOverlay({
5050
<ErrorOverlay
5151
state={state}
5252
runtimeErrors={runtimeErrors}
53-
errorCount={totalErrorCount}
5453
isErrorOverlayOpen={isErrorOverlayOpen}
5554
setIsErrorOverlayOpen={setIsErrorOverlayOpen}
5655
/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useEffect, useState } from 'react'
2+
3+
export function useMeasureHeight(
4+
ref: React.RefObject<HTMLDivElement | null>
5+
): [number, boolean] {
6+
const [pristine, setPristine] = useState<boolean>(true)
7+
const [height, setHeight] = useState<number>(0)
8+
9+
useEffect(() => {
10+
const el = ref.current
11+
12+
if (!el) {
13+
return
14+
}
15+
16+
const observer = new ResizeObserver(() => {
17+
const { height: h } = el.getBoundingClientRect()
18+
setHeight((prevHeight) => {
19+
if (prevHeight !== 0) {
20+
setPristine(false)
21+
}
22+
return h
23+
})
24+
})
25+
26+
observer.observe(el)
27+
return () => {
28+
observer.disconnect()
29+
setPristine(true)
30+
}
31+
// eslint-disable-next-line react-hooks/exhaustive-deps
32+
}, [])
33+
34+
return [height, pristine]
35+
}

test/development/acceptance/ReactRefreshLogBox.test.ts

+1-4
Original file line numberDiff line numberDiff line change
@@ -1161,10 +1161,7 @@ describe('ReactRefreshLogBox', () => {
11611161
`)
11621162
}
11631163

1164-
// TODO: fix the broken collapsing in callstack
1165-
if (!isReact18) {
1166-
await toggleCollapseCallStackFrames(browser)
1167-
}
1164+
await toggleCollapseCallStackFrames(browser)
11681165

11691166
// Expect more than the default amount of frames
11701167
// The default stackTraceLimit results in max 9 [data-nextjs-call-stack-frame] elements

0 commit comments

Comments
 (0)