Skip to content

Commit

Permalink
[Error Overlay] New design (#75679)
Browse files Browse the repository at this point in the history
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 <devjiwonchoi@gmail.com>
  • Loading branch information
raunofreiberg and devjiwonchoi authored Feb 10, 2025
1 parent a32f14e commit f859963
Show file tree
Hide file tree
Showing 16 changed files with 275 additions and 248 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export const CallStackFrame: React.FC<{
<div
data-nextjs-call-stack-frame
data-nextjs-call-stack-frame-ignored={!hasSource}
data-animate={frame.ignored}
{...props}
style={
{
Expand Down Expand Up @@ -89,25 +88,17 @@ export const CALL_STACK_FRAME_STYLES = css`
user-select: text;
display: block;
box-sizing: border-box;
width: 100%;
user-select: text;
-webkit-user-select: text;
-moz-user-select: text;
-ms-user-select: text;
padding: var(--size-1_5) var(--size-2);
margin-bottom: var(--size-1);
padding: 6px 8px;
border-radius: var(--rounded-lg);
transition: background 100ms ease-out;
&[data-animate='true'] {
filter: blur(4px);
animation: fadeIn 250ms var(--timing-swift) forwards
calc(var(--index) * 25ms);
}
&:not(:disabled)[role='button']:hover {
background: var(--color-gray-alpha-100);
cursor: pointer;
Expand Down Expand Up @@ -141,10 +132,4 @@ export const CALL_STACK_FRAME_STYLES = css`
font-size: var(--size-font-small);
line-height: var(--size-5);
}
@keyframes fadeIn {
to {
filter: blur(0px);
}
}
`
Original file line number Diff line number Diff line change
Expand Up @@ -104,28 +104,29 @@ export const CODE_FRAME_STYLES = css`
overflow: hidden;
color: var(--color-gray-1000);
text-overflow: ellipsis;
border: 1px solid var(--color-gray-400);
border-radius: 8px;
font-family: var(--font-stack-monospace);
font-size: 12px;
line-height: 16px;
margin: var(--size-4) var(--size-4) var(--size-2);
border: 1px solid var(--color-gray-400);
border-radius: var(--size-2);
margin: var(--next-dialog-row-padding);
&:has(~ [data-nextjs-call-stack]) {
margin-bottom: 0;
}
}
.code-frame-link,
.code-frame-pre {
padding: 12px;
}
.code-frame-pre {
white-space: pre-wrap;
}
.code-frame-header {
width: 100%;
cursor: pointer;
border-bottom: 1px solid var(--color-gray-400);
transition: background 100ms ease-out;
border-radius: 8px 8px 0 0;
border-bottom: 1px solid var(--color-gray-400);
&:focus-visible {
outline: var(--focus-ring);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ const styles = css`
--next-dialog-radius: var(--rounded-xl);
--next-dialog-footer-height: 48px;
--next-dialog-max-width: 960px;
--next-dialog-row-padding: 16px;
display: flex;
flex-direction: column;
flex-direction: column-reverse;
width: 100%;
max-height: calc(100% - 56px);
max-width: var(--next-dialog-max-width);
Expand Down Expand Up @@ -48,6 +49,7 @@ const styles = css`
}
[data-nextjs-dialog-content] {
overflow-y: auto;
border: none;
margin: 0;
display: flex;
Expand All @@ -62,7 +64,8 @@ const styles = css`
[data-nextjs-dialog-content] > [data-nextjs-dialog-header] {
flex-shrink: 0;
padding: var(--size-4);
padding: var(--next-dialog-row-padding);
padding-bottom: 0;
}
[data-nextjs-dialog-content] > [data-nextjs-dialog-body] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ import type { OriginalStackFrame } from '../../../../../internal/helpers/stack-f
import { useMemo, useState, useRef } from 'react'
import { CallStackFrame } from '../../call-stack-frame/call-stack-frame'
import { noop as css } from '../../../helpers/noop-template'
import { useMeasureHeight } from '../../../hooks/use-measure-height'

interface CallStackProps {
frames: OriginalStackFrame[]
dialogResizerRef: React.RefObject<HTMLDivElement | null>
}

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

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

if (isIgnoreListOpen) {
function onTransitionEnd() {
setIsIgnoreListOpen(false)
dialog.removeEventListener('transitionend', onTransitionEnd)
setIsIgnoreListOpen(false)
}
dialog.style.height = `${initialDialogHeight.current}px`
dialog.addEventListener('transitionend', onTransitionEnd)
} else {
dialog.style.height = `${initialDialogHeight.current + ignoreListHeight}px`
setIsIgnoreListOpen(!isIgnoreListOpen)
setIsIgnoreListOpen(true)
}
}

Expand All @@ -81,27 +77,25 @@ export function CallStack({ frames, dialogResizerRef }: CallStackProps) {
</button>
)}
</div>
<div className="error-overlay-call-stack-body">
{visibleFrames.map((frame, frameIndex) => (
<CallStackFrame
key={`call-stack-leading-${frameIndex}`}
frame={frame}
index={frameIndex}
/>
))}

{isIgnoreListOpen && (
<div ref={ignoreListRef}>
{ignoredFrames.map((frame, frameIndex) => (
<CallStackFrame
key={`call-stack-ignored-${frameIndex}`}
frame={frame}
index={frameIndex}
/>
))}
</div>
)}
</div>
{visibleFrames.map((frame, frameIndex) => (
<CallStackFrame
key={`call-stack-leading-${frameIndex}`}
frame={frame}
index={frameIndex}
/>
))}

{isIgnoreListOpen && (
<>
{ignoredFrames.map((frame, frameIndex) => (
<CallStackFrame
key={`call-stack-ignored-${frameIndex}`}
frame={frame}
index={frameIndex}
/>
))}
</>
)}
</div>
)
}
Expand All @@ -128,33 +122,20 @@ function ChevronUpDown() {
export const CALL_STACK_STYLES = css`
.error-overlay-call-stack-container {
position: relative;
}
.error-overlay-call-stack-body {
padding: var(--size-4) var(--size-3);
padding-top: 0;
/* To optically align last item */
padding-bottom: 8px;
position: relative;
}
.error-overlay-call-stack-header {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 28px;
padding: var(--size-4) var(--size-5) var(--size-3) var(--size-4);
background: rgba(255, 255, 255, 0.7);
mask-image: linear-gradient(to top, transparent, #000 12%);
backdrop-filter: blur(8px);
margin-bottom: var(--size-3);
padding: 0 var(--size-2);
width: 100%;
position: fixed;
position: sticky;
top: 0;
z-index: 2;
@media (prefers-color-scheme: dark) {
background: #0a0a0a70;
}
}
.error-overlay-call-stack-title {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import { Dialog } from '../../dialog/dialog'
import { noop as css } from '../../../helpers/noop-template'

type ErrorOverlayDialogProps = {
isTurbopack?: boolean
children?: React.ReactNode
onClose?: () => void
dialogResizerRef?: React.RefObject<HTMLDivElement | null>
}

export function ErrorOverlayDialog({
isTurbopack,
children,
onClose,
...props
Expand All @@ -21,7 +19,6 @@ export function ErrorOverlayDialog({
aria-describedby="nextjs__container_errors_desc"
onClose={onClose}
className="error-overlay-dialog"
data-turbo={isTurbopack}
{...props}
>
{children}
Expand All @@ -44,26 +41,12 @@ export const DIALOG_STYLES = css`
border-color: var(--color-gray-400);
}
&[data-turbo='true']::after {
content: '';
--size: 1px;
--gradient: linear-gradient(
to right top,
transparent 75%,
var(--color-turbopack-border-blue) 87.5%,
var(--color-turbopack-border-red) 100%
);
position: absolute;
inset: -1px;
pointer-events: none;
border-radius: var(--next-dialog-radius);
padding: var(--size);
background: var(--gradient);
mask:
linear-gradient(black, black) content-box,
linear-gradient(black, black);
-webkit-mask-composite: xor;
mask-composite: exclude;
&:has(~ .error-overlay-nav .error-overlay-notch[data-side='left']) {
border-top-left-radius: 0;
}
&:has(~ .error-overlay-nav .error-overlay-notch[data-side='right']) {
border-top-right-radius: 0;
}
}
`
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import { DialogHeader } from '../../dialog/dialog-header'
import { noop as css } from '../../../helpers/noop-template'
import { cx } from '../../../helpers/cx'

type ErrorOverlayDialogHeaderProps = {
children?: React.ReactNode
isTurbopack?: boolean
}

export function ErrorOverlayDialogHeader({
children,
isTurbopack,
}: ErrorOverlayDialogHeaderProps) {
return (
<DialogHeader
className={cx(
'nextjs-container-errors-header',
isTurbopack && 'nextjs-error-overlay-dialog-header-turbopack-background'
)}
>
<DialogHeader className="nextjs-container-errors-header">
{children}
</DialogHeader>
)
Expand Down Expand Up @@ -56,13 +48,4 @@ export const DIALOG_HEADER_STYLES = css`
top: var(--size-4);
right: var(--size-4);
}
.nextjs-error-overlay-dialog-header-turbopack-background {
background-image: linear-gradient(
10deg,
var(--color-background-100) 60%,
var(--color-turbopack-background-red) 75%,
var(--color-turbopack-background-blue) 100%
);
}
`

This file was deleted.

Loading

0 comments on commit f859963

Please sign in to comment.