diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/call-stack/call-stack.stories.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/call-stack/call-stack.stories.tsx new file mode 100644 index 0000000000000..09afec5f9c3b3 --- /dev/null +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/call-stack/call-stack.stories.tsx @@ -0,0 +1,74 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { CallStack } from './call-stack' +import { withShadowPortal } from '../../../storybook/with-shadow-portal' + +const meta: Meta = { + title: 'CallStack', + component: CallStack, + parameters: { + layout: 'fullscreen', + }, + decorators: [withShadowPortal], +} + +export default meta +type Story = StoryObj + +const frame = { + originalStackFrame: { + file: './app/page.tsx', + methodName: 'MyComponent', + arguments: [], + lineNumber: 10, + column: 5, + ignored: false, + }, + sourceStackFrame: { + file: './app/page.tsx', + methodName: 'MyComponent', + arguments: [], + lineNumber: 10, + column: 5, + }, + originalCodeFrame: 'export default function MyComponent() {', + error: false, + reason: null, + external: false, + ignored: false, +} + +const ignoredFrame = { + ...frame, + ignored: true, +} + +export const SingleFrame: Story = { + args: { + frames: [frame], + }, +} + +export const MultipleFrames: Story = { + args: { + frames: [ + frame, + { + ...frame, + originalStackFrame: { + ...frame.originalStackFrame, + methodName: 'ParentComponent', + lineNumber: 5, + }, + }, + { + ...frame, + originalStackFrame: { + ...frame.originalStackFrame, + methodName: 'GrandparentComponent', + lineNumber: 1, + }, + }, + ...Array(5).fill(ignoredFrame), + ], + }, +} diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/call-stack/call-stack.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/call-stack/call-stack.tsx new file mode 100644 index 0000000000000..bc383762cfa15 --- /dev/null +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/call-stack/call-stack.tsx @@ -0,0 +1,141 @@ +import type { OriginalStackFrame } from '../../../helpers/stack-frame' +import { useMemo, useState } from 'react' +import { CallStackFrame } from '../../call-stack-frame/call-stack-frame' +import { noop as css } from '../../../helpers/noop-template' + +type CallStackProps = { + frames: OriginalStackFrame[] +} + +export function CallStack({ frames }: CallStackProps) { + const [isIgnoreListOpen, setIsIgnoreListOpen] = useState(false) + + const { filteredFrames, ignoreListLength } = useMemo(() => { + const filtered = [] + let ignoredLength = 0 + + for (const frame of frames) { + if (isIgnoreListOpen || !frame.ignored) { + filtered.push(frame) + } + if (frame.ignored) { + ignoredLength++ + } + } + + return { + filteredFrames: filtered, + ignoreListLength: ignoredLength, + } + }, [frames, isIgnoreListOpen]) + + return ( +
+
+

+ Call Stack{' '} + + {frames.length} + +

+ {ignoreListLength > 0 && ( + + )} +
+ {filteredFrames.map((frame, frameIndex) => ( + + ))} +
+ ) +} + +function ChevronUpDown() { + return ( + + + + ) +} + +export const CALL_STACK_STYLES = css` + .error-overlay-call-stack-container { + border-top: 1px solid var(--color-gray-400); + padding: var(--size-4) var(--size-3); + } + + .error-overlay-call-stack-header { + display: flex; + justify-content: space-between; + align-items: center; + + margin-bottom: var(--size-3); + + padding: 0 var(--size-2); + } + + .error-overlay-call-stack-title { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--size-2); + + margin: 0; + + color: var(--color-gray-1000); + font-size: var(--size-font); + font-weight: 500; + line-height: var(--size-5); + } + + .error-overlay-call-stack-count { + display: flex; + justify-content: center; + align-items: center; + + width: var(--size-5); + height: var(--size-5); + padding: var(--size-0_5) var(--size-1_5); + gap: var(--size-1); + + color: var(--color-gray-1000); + text-align: center; + font-size: var(--size-font-11); + font-weight: 500; + line-height: var(--size-4); + + border-radius: var(--rounded-full); + background: var(--color-gray-300); + } + + .error-overlay-call-stack-ignored-list-toggle-button { + all: unset; + color: var(--color-gray-900); + font-size: var(--size-font-small); + line-height: var(--size-5); + + &:focus { + outline: none; + } + } +` diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/error-overlay-layout/error-overlay-layout.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/error-overlay-layout/error-overlay-layout.tsx index e6766bfd7ac96..a36df4b6b12b5 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/error-overlay-layout/error-overlay-layout.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/Errors/error-overlay-layout/error-overlay-layout.tsx @@ -32,6 +32,7 @@ import { DIALOG_HEADER_STYLES, } from '../dialog/header' import { ErrorOverlayDialogBody, DIALOG_BODY_STYLES } from '../dialog/body' +import { CALL_STACK_STYLES } from '../call-stack/call-stack' type ErrorOverlayLayoutProps = { errorMessage: ErrorMessageType @@ -118,4 +119,5 @@ export const styles = css` ${errorTypeLabelStyles} ${errorMessageStyles} ${toolbarStyles} + ${CALL_STACK_STYLES} ` diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.stories.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.stories.tsx new file mode 100644 index 0000000000000..30bb6887ca965 --- /dev/null +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.stories.tsx @@ -0,0 +1,52 @@ +import type { Meta, StoryObj } from '@storybook/react' +import { CallStackFrame } from './call-stack-frame' +import { withShadowPortal } from '../../storybook/with-shadow-portal' + +const meta: Meta = { + title: 'CallStackFrame', + component: CallStackFrame, + parameters: { + layout: 'fullscreen', + }, + decorators: [withShadowPortal], +} + +export default meta +type Story = StoryObj + +const frame = { + originalStackFrame: { + file: './app/page.tsx', + methodName: 'MyComponent', + arguments: [], + lineNumber: 10, + column: 5, + ignored: false, + }, + sourceStackFrame: { + file: './app/page.tsx', + methodName: 'MyComponent', + arguments: [], + lineNumber: 10, + column: 5, + }, + error: false, + reason: null, + external: false, + ignored: false, +} + +export const HasSource: Story = { + args: { + frame: { + ...frame, + originalCodeFrame: 'export default function MyComponent() {', + }, + }, +} + +export const NoSource: Story = { + args: { + frame, + }, +} diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx new file mode 100644 index 0000000000000..2a8cfe64a1084 --- /dev/null +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/call-stack-frame/call-stack-frame.tsx @@ -0,0 +1,140 @@ +import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' +import type { OriginalStackFrame } from '../../helpers/stack-frame' + +import { HotlinkedText } from '../hot-linked-text' +import { getFrameSource } from '../../helpers/stack-frame' +import { useOpenInEditor } from '../../helpers/use-open-in-editor' +import { noop as css } from '../../helpers/noop-template' + +export const CallStackFrame: React.FC<{ + frame: OriginalStackFrame +}> = function CallStackFrame({ frame }) { + // TODO: ability to expand resolved frames + // TODO: render error or external indicator + + const f: StackFrame = frame.originalStackFrame ?? frame.sourceStackFrame + const hasSource = Boolean(frame.originalCodeFrame) + const open = useOpenInEditor( + hasSource + ? { + file: f.file, + lineNumber: f.lineNumber, + column: f.column, + } + : undefined + ) + + // Format method to strip out the webpack layer prefix. + // e.g. (app-pages-browser)/./app/page.tsx -> ./app/page.tsx + const formattedMethod = f.methodName.replace(/^\([\w-]+\)\//, '') + + // Formatted file source could be empty. e.g. will be formatted to empty string, + // we'll skip rendering the frame in this case. + const fileSource = getFrameSource(f) + if (!fileSource) { + return null + } + + return ( +
+ + + {hasSource && } + + + {fileSource} + +
+ ) +} + +function External() { + return ( + + + + ) +} + +export const CALL_STACK_FRAME_STYLES = css` + [data-nextjs-call-stack-frame-ignored] { + padding: var(--size-1_5) var(--size-2); + margin-bottom: var(--size-1); + + border-radius: var(--rounded-lg); + } + + [data-nextjs-call-stack-frame] { + 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); + + border-radius: var(--rounded-lg); + + &:not(:disabled):hover { + background: var(--color-gray-alpha-100); + cursor: pointer; + } + + &:not(:disabled):active { + background: var(--color-gray-alpha-200); + } + + &:focus { + outline: none; + } + } + + .call-stack-frame-method-name { + display: flex; + align-items: center; + gap: var(--size-1); + + margin-bottom: var(--size-1); + + color: var(--color-gray-1000); + font-size: var(--size-font-small); + font-weight: 500; + line-height: var(--size-5); + } + + .call-stack-frame-file-source { + color: var(--color-gray-900); + font-size: var(--size-font-small); + line-height: var(--size-5); + } +` diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/copy-button/index.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/copy-button/index.tsx index afbb284927f8e..5006128cdc870 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/copy-button/index.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/components/copy-button/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react' +import { noop as css } from '../../helpers/noop-template' function useCopyLegacy(content: string) { type CopyState = @@ -230,3 +231,36 @@ function CopySuccessIcon() { ) } + +// TODO(jiwon): Is not used anymore, should we decouple the styles? +export const COPY_BUTTON_STYLES = css` + [data-nextjs-data-runtime-error-copy-button], + [data-nextjs-data-runtime-error-copy-button]:focus:not(:focus-visible) { + position: relative; + margin-left: var(--size-gap); + padding: 0; + border: none; + background: none; + outline: none; + } + [data-nextjs-data-runtime-error-copy-button] > svg { + vertical-align: middle; + } + .nextjs-data-runtime-error-copy-button { + color: inherit; + } + .nextjs-data-runtime-error-copy-button--initial:hover { + cursor: pointer; + } + .nextjs-data-runtime-error-copy-button[aria-disabled='true'] { + opacity: 0.3; + cursor: not-allowed; + } + .nextjs-data-runtime-error-copy-button--error, + .nextjs-data-runtime-error-copy-button--error:hover { + color: var(--color-ansi-red); + } + .nextjs-data-runtime-error-copy-button--success { + color: var(--color-ansi-green); + } +` diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/CallStackFrame.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/CallStackFrame.tsx deleted file mode 100644 index 72d3442836ad4..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/CallStackFrame.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' -import { - getFrameSource, - type OriginalStackFrame, -} from '../../helpers/stack-frame' -import { useOpenInEditor } from '../../helpers/use-open-in-editor' -import { HotlinkedText } from '../../components/hot-linked-text' - -export const CallStackFrame: React.FC<{ - frame: OriginalStackFrame -}> = function CallStackFrame({ frame }) { - // TODO: ability to expand resolved frames - // TODO: render error or external indicator - - const f: StackFrame = frame.originalStackFrame ?? frame.sourceStackFrame - const hasSource = Boolean(frame.originalCodeFrame) - const open = useOpenInEditor( - hasSource - ? { - file: f.file, - lineNumber: f.lineNumber, - column: f.column, - } - : undefined - ) - - // Format method to strip out the webpack layer prefix. - // e.g. (app-pages-browser)/./app/page.tsx -> ./app/page.tsx - const formattedMethod = f.methodName.replace(/^\([\w-]+\)\//, '') - - // Formatted file source could be empty. e.g. will be formatted to empty string, - // we'll skip rendering the frame in this case. - const fileSource = getFrameSource(f) - if (!fileSource) { - return null - } - - return ( -
-

- -

-
- {fileSource} - - - - - -
-
- ) -} diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/ComponentStackFrameRow.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/ComponentStackFrameRow.tsx deleted file mode 100644 index 774d39d1c1d0d..0000000000000 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/ComponentStackFrameRow.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import React from 'react' -import type { ComponentStackFrame } from '../../helpers/parse-component-stack' -import { useOpenInEditor } from '../../helpers/use-open-in-editor' -import { HotlinkedText } from '../../components/hot-linked-text' - -function EditorLink({ - children, - componentStackFrame: { file, column, lineNumber }, -}: { - children: React.ReactNode - componentStackFrame: ComponentStackFrame -}) { - const open = useOpenInEditor({ - file, - column, - lineNumber, - }) - - return ( -
- {children} - - - - - -
- ) -} - -function formatLineNumber(lineNumber: number, column: number | undefined) { - if (!column) { - return lineNumber - } - - return `${lineNumber}:${column}` -} - -function LocationLine({ - componentStackFrame, -}: { - componentStackFrame: ComponentStackFrame -}) { - const { file, lineNumber, column } = componentStackFrame - return ( - <> - {file} {lineNumber ? `(${formatLineNumber(lineNumber, column)})` : ''} - - ) -} - -function SourceLocation({ - componentStackFrame, -}: { - componentStackFrame: ComponentStackFrame -}) { - const { file, canOpenInEditor } = componentStackFrame - - if (file && canOpenInEditor) { - return ( - - - - - - ) - } - - return ( -
- -
- ) -} - -export function ComponentStackFrameRow({ - componentStackFrame, -}: { - componentStackFrame: ComponentStackFrame -}) { - const { component } = componentStackFrame - - return ( -
-

- -

- -
- ) -} diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/component-stack-pseudo-html.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/component-stack-pseudo-html.tsx index 5f893ae26e2d8..31708915277b5 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/component-stack-pseudo-html.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/component-stack-pseudo-html.tsx @@ -1,6 +1,7 @@ import { useMemo, Fragment, useState } from 'react' import type { ComponentStackFrame } from '../../helpers/parse-component-stack' import { CollapseIcon } from '../../icons/CollapseIcon' +import { noop as css } from '../../helpers/noop-template' function getAdjacentProps(isAdj: boolean) { return { 'data-nextjs-container-errors-pseudo-html--tag-adjacent': isAdj } @@ -307,3 +308,36 @@ export function PseudoHtmlDiff({ ) } + +export const PSEUDO_HTML_DIFF_STYLES = css` + [data-nextjs-container-errors-pseudo-html] { + position: relative; + } + [data-nextjs-container-errors-pseudo-html-collapse] { + position: absolute; + left: 10px; + top: 10px; + color: inherit; + background: none; + border: none; + padding: 0; + } + [data-nextjs-container-errors-pseudo-html--diff='add'] { + color: var(--color-ansi-green); + } + [data-nextjs-container-errors-pseudo-html--diff='remove'] { + color: var(--color-ansi-red); + } + [data-nextjs-container-errors-pseudo-html--tag-error] { + color: var(--color-ansi-red); + font-weight: bold; + } + /* hide but text are still accessible in DOM */ + [data-nextjs-container-errors-pseudo-html--hint] { + display: inline-block; + font-size: 0; + } + [data-nextjs-container-errors-pseudo-html--tag-adjacent='false'] { + color: var(--color-accents-1); + } +` diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/index.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/index.tsx index a8c588495d7fb..47abcbd25758f 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/index.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/container/RuntimeError/index.tsx @@ -1,24 +1,16 @@ -import * as React from 'react' -import { CodeFrame } from '../../components/CodeFrame' import type { ReadyRuntimeError } from '../../helpers/get-error-by-type' + +import { useMemo } from 'react' +import { CodeFrame } from '../../components/CodeFrame' +import { CallStack } from '../../components/Errors/call-stack/call-stack' import { noop as css } from '../../helpers/noop-template' -import { CallStackFrame } from './CallStackFrame' +import { PSEUDO_HTML_DIFF_STYLES } from './component-stack-pseudo-html' export type RuntimeErrorProps = { error: ReadyRuntimeError } export function RuntimeError({ error }: RuntimeErrorProps) { - const [isIgnoredExpanded, setIsIgnoredExpanded] = React.useState(false) - const { - firstFrame, - allLeadingFrames, - trailingCallStackFrames, - displayedFramesCount, - } = React.useMemo(() => { - const filteredFrames = error.frames.filter((frame) => - isIgnoredExpanded ? true : !frame.ignored - ) - - const firstFirstPartyFrameIndex = filteredFrames.findIndex( + const { firstFrame } = useMemo(() => { + const firstFirstPartyFrameIndex = error.frames.findIndex( (entry) => !entry.ignored && Boolean(entry.originalCodeFrame) && @@ -26,188 +18,24 @@ export function RuntimeError({ error }: RuntimeErrorProps) { ) return { - displayedFramesCount: filteredFrames.length, - firstFrame: filteredFrames[firstFirstPartyFrameIndex] ?? null, - allLeadingFrames: - firstFirstPartyFrameIndex < 0 - ? [] - : filteredFrames.slice(0, firstFirstPartyFrameIndex), - trailingCallStackFrames: filteredFrames.slice( - firstFirstPartyFrameIndex + 1 - ), + firstFrame: error.frames[firstFirstPartyFrameIndex] ?? null, } - }, [error.frames, isIgnoredExpanded]) + }, [error.frames]) return ( - - {firstFrame ? ( - <> -

Source

- {allLeadingFrames.map((frame, frameIndex) => ( - - ))} - - - ) : undefined} - - {trailingCallStackFrames.map((frame, frameIndex) => ( - + {firstFrame && ( + - ))} - { - // if the default displayed ignored frames count is equal equal to the total frames count, hide the button - displayedFramesCount === error.frames.length && - !isIgnoredExpanded ? null : ( - - ) - } -
+ )} + + {error.frames.length > 0 && } + ) } export const styles = css` - [data-nextjs-call-stack-frame] { - padding: var(--size-4); - } - - [data-nextjs-call-stack-frame]:not(:last-child), - [data-nextjs-component-stack-frame]:not(:last-child) { - margin-bottom: var(--size-gap-double); - } - - [data-expand-ignore-button]:focus:not(:focus-visible), - [data-expand-ignore-button] { - background: none; - border: none; - color: var(--color-font); - cursor: pointer; - font-size: var(--size-font); - margin: var(--size-gap) 0; - padding: 0; - text-decoration: underline; - outline: none; - } - - .nextjs-data-runtime-error-copy-button--error, - .nextjs-data-runtime-error-copy-button--error:hover { - color: var(--color-ansi-red); - } - .nextjs-data-runtime-error-copy-button--success { - color: var(--color-ansi-green); - } - - [data-nextjs-call-stack-frame] > h3, - [data-nextjs-component-stack-frame] > h3 { - margin-top: 0; - margin-bottom: 0; - font-family: var(--font-stack-monospace); - font-size: var(--size-font); - } - [data-nextjs-call-stack-frame] > h3[data-nextjs-frame-expanded='false'] { - color: #666; - display: inline-block; - } - [data-nextjs-call-stack-frame] > div, - [data-nextjs-component-stack-frame] > div { - display: flex; - align-items: center; - padding-left: calc(var(--size-gap) + var(--size-gap-half)); - font-size: var(--size-font-small); - color: #999; - } - [data-nextjs-call-stack-frame] > div > svg, - [data-nextjs-component-stack-frame] > [role='link'] > svg { - width: auto; - height: var(--size-font-small); - margin-left: var(--size-gap); - flex-shrink: 0; - display: none; - } - - [data-nextjs-call-stack-frame] > div[data-has-source], - [data-nextjs-component-stack-frame] > [role='link'] { - cursor: pointer; - } - [data-nextjs-call-stack-frame] > div[data-has-source]:hover, - [data-nextjs-component-stack-frame] > [role='link']:hover { - text-decoration: underline dotted; - } - [data-nextjs-call-stack-frame] > div[data-has-source] > svg, - [data-nextjs-component-stack-frame] > [role='link'] > svg { - display: unset; - } - - [data-nextjs-call-stack-framework-icon] { - margin-right: var(--size-gap); - } - [data-nextjs-call-stack-framework-icon='next'] > mask { - mask-type: alpha; - } - [data-nextjs-call-stack-framework-icon='react'] { - color: rgb(20, 158, 202); - } - [data-nextjs-collapsed-call-stack-details][open] - [data-nextjs-call-stack-chevron-icon] { - transform: rotate(90deg); - } - [data-nextjs-collapsed-call-stack-details] summary { - display: flex; - align-items: center; - margin-bottom: var(--size-gap); - list-style: none; - } - [data-nextjs-collapsed-call-stack-details] summary::-webkit-details-marker { - display: none; - } - - [data-nextjs-collapsed-call-stack-details] h3 { - color: #666; - } - [data-nextjs-collapsed-call-stack-details] [data-nextjs-call-stack-frame] { - margin-bottom: var(--size-gap-double); - } - - [data-nextjs-container-errors-pseudo-html] { - position: relative; - } - [data-nextjs-container-errors-pseudo-html-collapse] { - position: absolute; - left: 10px; - top: 10px; - color: inherit; - background: none; - border: none; - padding: 0; - } - [data-nextjs-container-errors-pseudo-html--diff='add'] { - color: var(--color-ansi-green); - } - [data-nextjs-container-errors-pseudo-html--diff='remove'] { - color: var(--color-ansi-red); - } - [data-nextjs-container-errors-pseudo-html--tag-error] { - color: var(--color-ansi-red); - font-weight: bold; - } - /* hide but text are still accessible in DOM */ - [data-nextjs-container-errors-pseudo-html--hint] { - display: inline-block; - font-size: 0; - } - [data-nextjs-container-errors-pseudo-html--tag-adjacent='false'] { - color: var(--color-accents-1); - } + ${PSEUDO_HTML_DIFF_STYLES} ` diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/CollapseIcon.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/CollapseIcon.tsx index 4e38bd16b2ddc..8dab41204c571 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/CollapseIcon.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/icons/CollapseIcon.tsx @@ -13,7 +13,6 @@ export function CollapseIcon({ collapsed }: { collapsed?: boolean } = {}) { strokeWidth="2" viewBox="0 0 24 24" // rotate 90 degrees if not collapsed. - // If collapsed isn't present, the rotation is applied via the `data-nextjs-collapsed-call-stack-details` element's `open` attribute {...(typeof collapsed === 'boolean' ? { style: { transform: collapsed ? undefined : 'rotate(90deg)' } } : {})} diff --git a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/styles/ComponentStyles.tsx b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/styles/ComponentStyles.tsx index 9b3e4e8d97ffc..1e0d51bfd895b 100644 --- a/packages/next/src/client/components/react-dev-overlay/_experimental/internal/styles/ComponentStyles.tsx +++ b/packages/next/src/client/components/react-dev-overlay/_experimental/internal/styles/ComponentStyles.tsx @@ -11,6 +11,8 @@ import { styles as versionStaleness } from '../components/VersionStalenessInfo/V import { styles as buildErrorStyles } from '../container/BuildError' import { styles as containerErrorStyles } from '../container/Errors' import { styles as containerRuntimeErrorStyles } from '../container/RuntimeError' +import { COPY_BUTTON_STYLES } from '../components/copy-button' +import { CALL_STACK_FRAME_STYLES } from '../components/call-stack-frame/call-stack-frame' import { styles as devToolsIndicator } from '../components/Errors/dev-tools-indicator/styles' import { noop as css } from '../helpers/noop-template' @@ -18,6 +20,8 @@ export function ComponentStyles() { return (