Skip to content

Commit f859963

Browse files
[Error Overlay] New design (#75679)
This PR implements a new design for the experimental Next.js Error Overlay: - Border-less body design - Notch cut-out for the navigation and version info <img width="1088" alt="image" src="https://github.com/user-attachments/assets/31385793-82c4-41ab-a34d-6b49955f5823" /> --- - Closes [NDX-782](https://linear.app/vercel/issue/NDX-782/re-redesign-contents-in-a-single-body-with-padding) - Closes [NDX-781](https://linear.app/vercel/issue/NDX-781/re-redesign-navigation-header) --------- Co-authored-by: devjiwonchoi <[email protected]>
1 parent a32f14e commit f859963

File tree

16 files changed

+275
-248
lines changed

16 files changed

+275
-248
lines changed

Diff for: packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx

+1-16
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export const CallStackFrame: React.FC<{
5252
<div
5353
data-nextjs-call-stack-frame
5454
data-nextjs-call-stack-frame-ignored={!hasSource}
55-
data-animate={frame.ignored}
5655
{...props}
5756
style={
5857
{
@@ -89,25 +88,17 @@ export const CALL_STACK_FRAME_STYLES = css`
8988
user-select: text;
9089
display: block;
9190
box-sizing: border-box;
92-
width: 100%;
9391
9492
user-select: text;
9593
-webkit-user-select: text;
9694
-moz-user-select: text;
9795
-ms-user-select: text;
9896
99-
padding: var(--size-1_5) var(--size-2);
100-
margin-bottom: var(--size-1);
97+
padding: 6px 8px;
10198
10299
border-radius: var(--rounded-lg);
103100
transition: background 100ms ease-out;
104101
105-
&[data-animate='true'] {
106-
filter: blur(4px);
107-
animation: fadeIn 250ms var(--timing-swift) forwards
108-
calc(var(--index) * 25ms);
109-
}
110-
111102
&:not(:disabled)[role='button']:hover {
112103
background: var(--color-gray-alpha-100);
113104
cursor: pointer;
@@ -141,10 +132,4 @@ export const CALL_STACK_FRAME_STYLES = css`
141132
font-size: var(--size-font-small);
142133
line-height: var(--size-5);
143134
}
144-
145-
@keyframes fadeIn {
146-
to {
147-
filter: blur(0px);
148-
}
149-
}
150135
`

Diff for: packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/code-frame/code-frame.tsx

+9-8
Original file line numberDiff line numberDiff line change
@@ -104,28 +104,29 @@ export const CODE_FRAME_STYLES = css`
104104
overflow: hidden;
105105
color: var(--color-gray-1000);
106106
text-overflow: ellipsis;
107+
border: 1px solid var(--color-gray-400);
108+
border-radius: 8px;
107109
font-family: var(--font-stack-monospace);
108110
font-size: 12px;
109111
line-height: 16px;
110-
margin: var(--size-4) var(--size-4) var(--size-2);
111-
border: 1px solid var(--color-gray-400);
112-
border-radius: var(--size-2);
112+
margin: var(--next-dialog-row-padding);
113+
114+
&:has(~ [data-nextjs-call-stack]) {
115+
margin-bottom: 0;
116+
}
113117
}
114118
115119
.code-frame-link,
116120
.code-frame-pre {
117121
padding: 12px;
118122
}
119123
120-
.code-frame-pre {
121-
white-space: pre-wrap;
122-
}
123-
124124
.code-frame-header {
125125
width: 100%;
126126
cursor: pointer;
127-
border-bottom: 1px solid var(--color-gray-400);
128127
transition: background 100ms ease-out;
128+
border-radius: 8px 8px 0 0;
129+
border-bottom: 1px solid var(--color-gray-400);
129130
130131
&:focus-visible {
131132
outline: var(--focus-ring);

Diff for: packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/dialog/styles.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ const styles = css`
55
--next-dialog-radius: var(--rounded-xl);
66
--next-dialog-footer-height: 48px;
77
--next-dialog-max-width: 960px;
8+
--next-dialog-row-padding: 16px;
89
910
display: flex;
10-
flex-direction: column;
11+
flex-direction: column-reverse;
1112
width: 100%;
1213
max-height: calc(100% - 56px);
1314
max-width: var(--next-dialog-max-width);
@@ -48,6 +49,7 @@ const styles = css`
4849
}
4950
5051
[data-nextjs-dialog-content] {
52+
overflow-y: auto;
5153
border: none;
5254
margin: 0;
5355
display: flex;
@@ -62,7 +64,8 @@ const styles = css`
6264
6365
[data-nextjs-dialog-content] > [data-nextjs-dialog-header] {
6466
flex-shrink: 0;
65-
padding: var(--size-4);
67+
padding: var(--next-dialog-row-padding);
68+
padding-bottom: 0;
6669
}
6770
6871
[data-nextjs-dialog-content] > [data-nextjs-dialog-body] {

Diff for: packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/call-stack/call-stack.tsx

+24-43
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,15 @@ import type { OriginalStackFrame } from '../../../../../internal/helpers/stack-f
22
import { useMemo, useState, useRef } from 'react'
33
import { CallStackFrame } from '../../call-stack-frame/call-stack-frame'
44
import { noop as css } from '../../../helpers/noop-template'
5-
import { useMeasureHeight } from '../../../hooks/use-measure-height'
65

76
interface CallStackProps {
87
frames: OriginalStackFrame[]
98
dialogResizerRef: React.RefObject<HTMLDivElement | null>
109
}
1110

1211
export function CallStack({ frames, dialogResizerRef }: CallStackProps) {
13-
const ignoreListRef = useRef<HTMLDivElement | null>(null)
1412
const initialDialogHeight = useRef<number>(NaN)
1513
const [isIgnoreListOpen, setIsIgnoreListOpen] = useState(false)
16-
const [ignoreListHeight] = useMeasureHeight(ignoreListRef)
1714

1815
const { visibleFrames, ignoredFrames, ignoreListLength } = useMemo(() => {
1916
const visible: OriginalStackFrame[] = []
@@ -50,14 +47,13 @@ export function CallStack({ frames, dialogResizerRef }: CallStackProps) {
5047

5148
if (isIgnoreListOpen) {
5249
function onTransitionEnd() {
53-
setIsIgnoreListOpen(false)
5450
dialog.removeEventListener('transitionend', onTransitionEnd)
51+
setIsIgnoreListOpen(false)
5552
}
5653
dialog.style.height = `${initialDialogHeight.current}px`
5754
dialog.addEventListener('transitionend', onTransitionEnd)
5855
} else {
59-
dialog.style.height = `${initialDialogHeight.current + ignoreListHeight}px`
60-
setIsIgnoreListOpen(!isIgnoreListOpen)
56+
setIsIgnoreListOpen(true)
6157
}
6258
}
6359

@@ -81,27 +77,25 @@ export function CallStack({ frames, dialogResizerRef }: CallStackProps) {
8177
</button>
8278
)}
8379
</div>
84-
<div className="error-overlay-call-stack-body">
85-
{visibleFrames.map((frame, frameIndex) => (
86-
<CallStackFrame
87-
key={`call-stack-leading-${frameIndex}`}
88-
frame={frame}
89-
index={frameIndex}
90-
/>
91-
))}
92-
93-
{isIgnoreListOpen && (
94-
<div ref={ignoreListRef}>
95-
{ignoredFrames.map((frame, frameIndex) => (
96-
<CallStackFrame
97-
key={`call-stack-ignored-${frameIndex}`}
98-
frame={frame}
99-
index={frameIndex}
100-
/>
101-
))}
102-
</div>
103-
)}
104-
</div>
80+
{visibleFrames.map((frame, frameIndex) => (
81+
<CallStackFrame
82+
key={`call-stack-leading-${frameIndex}`}
83+
frame={frame}
84+
index={frameIndex}
85+
/>
86+
))}
87+
88+
{isIgnoreListOpen && (
89+
<>
90+
{ignoredFrames.map((frame, frameIndex) => (
91+
<CallStackFrame
92+
key={`call-stack-ignored-${frameIndex}`}
93+
frame={frame}
94+
index={frameIndex}
95+
/>
96+
))}
97+
</>
98+
)}
10599
</div>
106100
)
107101
}
@@ -128,33 +122,20 @@ function ChevronUpDown() {
128122
export const CALL_STACK_STYLES = css`
129123
.error-overlay-call-stack-container {
130124
position: relative;
131-
}
132-
133-
.error-overlay-call-stack-body {
134125
padding: var(--size-4) var(--size-3);
135-
padding-top: 0;
136126
/* To optically align last item */
137127
padding-bottom: 8px;
128+
position: relative;
138129
}
139130
140131
.error-overlay-call-stack-header {
141132
display: flex;
142133
justify-content: space-between;
143134
align-items: center;
144135
min-height: 28px;
145-
padding: var(--size-4) var(--size-5) var(--size-3) var(--size-4);
146-
background: rgba(255, 255, 255, 0.7);
147-
mask-image: linear-gradient(to top, transparent, #000 12%);
148-
backdrop-filter: blur(8px);
136+
margin-bottom: var(--size-3);
137+
padding: 0 var(--size-2);
149138
width: 100%;
150-
position: fixed;
151-
position: sticky;
152-
top: 0;
153-
z-index: 2;
154-
155-
@media (prefers-color-scheme: dark) {
156-
background: #0a0a0a70;
157-
}
158139
}
159140
160141
.error-overlay-call-stack-title {

Diff for: packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dialog/dialog.tsx

+6-23
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ import { Dialog } from '../../dialog/dialog'
22
import { noop as css } from '../../../helpers/noop-template'
33

44
type ErrorOverlayDialogProps = {
5-
isTurbopack?: boolean
65
children?: React.ReactNode
76
onClose?: () => void
87
dialogResizerRef?: React.RefObject<HTMLDivElement | null>
98
}
109

1110
export function ErrorOverlayDialog({
12-
isTurbopack,
1311
children,
1412
onClose,
1513
...props
@@ -21,7 +19,6 @@ export function ErrorOverlayDialog({
2119
aria-describedby="nextjs__container_errors_desc"
2220
onClose={onClose}
2321
className="error-overlay-dialog"
24-
data-turbo={isTurbopack}
2522
{...props}
2623
>
2724
{children}
@@ -44,26 +41,12 @@ export const DIALOG_STYLES = css`
4441
border-color: var(--color-gray-400);
4542
}
4643
47-
&[data-turbo='true']::after {
48-
content: '';
49-
--size: 1px;
50-
--gradient: linear-gradient(
51-
to right top,
52-
transparent 75%,
53-
var(--color-turbopack-border-blue) 87.5%,
54-
var(--color-turbopack-border-red) 100%
55-
);
56-
position: absolute;
57-
inset: -1px;
58-
pointer-events: none;
59-
border-radius: var(--next-dialog-radius);
60-
padding: var(--size);
61-
background: var(--gradient);
62-
mask:
63-
linear-gradient(black, black) content-box,
64-
linear-gradient(black, black);
65-
-webkit-mask-composite: xor;
66-
mask-composite: exclude;
44+
&:has(~ .error-overlay-nav .error-overlay-notch[data-side='left']) {
45+
border-top-left-radius: 0;
46+
}
47+
48+
&:has(~ .error-overlay-nav .error-overlay-notch[data-side='right']) {
49+
border-top-right-radius: 0;
6750
}
6851
}
6952
`

Diff for: packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/dialog/header.tsx

+1-18
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
import { DialogHeader } from '../../dialog/dialog-header'
22
import { noop as css } from '../../../helpers/noop-template'
3-
import { cx } from '../../../helpers/cx'
43

54
type ErrorOverlayDialogHeaderProps = {
65
children?: React.ReactNode
7-
isTurbopack?: boolean
86
}
97

108
export function ErrorOverlayDialogHeader({
119
children,
12-
isTurbopack,
1310
}: ErrorOverlayDialogHeaderProps) {
1411
return (
15-
<DialogHeader
16-
className={cx(
17-
'nextjs-container-errors-header',
18-
isTurbopack && 'nextjs-error-overlay-dialog-header-turbopack-background'
19-
)}
20-
>
12+
<DialogHeader className="nextjs-container-errors-header">
2113
{children}
2214
</DialogHeader>
2315
)
@@ -56,13 +48,4 @@ export const DIALOG_HEADER_STYLES = css`
5648
top: var(--size-4);
5749
right: var(--size-4);
5850
}
59-
60-
.nextjs-error-overlay-dialog-header-turbopack-background {
61-
background-image: linear-gradient(
62-
10deg,
63-
var(--color-background-100) 60%,
64-
var(--color-turbopack-background-red) 75%,
65-
var(--color-turbopack-background-blue) 100%
66-
);
67-
}
6851
`

Diff for: packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/errors/error-overlay-floating-header/error-overlay-floating-header.tsx

-52
This file was deleted.

0 commit comments

Comments
 (0)