From 2bbb7be0e193e53ee625dfd496a30bcec60bebd5 Mon Sep 17 00:00:00 2001 From: "Sebastian \"Sebbie\" Silbermann" Date: Mon, 29 Sep 2025 15:15:09 +0200 Subject: [PATCH 1/5] [DevTools] Don't call Hooks conditionally (#34644) --- .../views/Profiler/SidebarEventInfo.js | 46 +++++++++++-------- .../views/SuspenseTab/SuspenseTimeline.js | 44 +++++++++--------- 2 files changed, 50 insertions(+), 40 deletions(-) diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js index 77f0d13feb72f..8b55e0f8c0c09 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js @@ -8,6 +8,7 @@ */ import type {SchedulingEvent} from 'react-devtools-timeline/src/types'; +import type {ReactFunctionLocation} from 'shared/ReactTypes'; import * as React from 'react'; import Button from '../Button'; @@ -27,6 +28,28 @@ import styles from './SidebarEventInfo.css'; export type Props = {}; +type FunctionLocationProps = { + location: ReactFunctionLocation, + displayName: string, +}; +function FunctionLocation({location, displayName}: FunctionLocationProps) { + // TODO: We should support symbolication here as well, but + // symbolicating the whole stack can be expensive + const [canViewSource, viewSource] = useOpenResource(location, null); + return ( +
  • + +
  • + ); +} + type SchedulingEventProps = { eventInfo: SchedulingEvent, }; @@ -74,25 +97,12 @@ function SchedulingEventInfo({eventInfo}: SchedulingEventProps) { ); } - // TODO: We should support symbolication here as well, but - // symbolicating the whole stack can be expensive - const [canViewSource, viewSource] = useOpenResource( - location, - null, - ); return ( -
  • - -
  • + ); }, )} diff --git a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseTimeline.js b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseTimeline.js index d618bfcea63b3..51479ac829564 100644 --- a/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseTimeline.js +++ b/packages/react-devtools-shared/src/devtools/views/SuspenseTab/SuspenseTimeline.js @@ -39,28 +39,6 @@ function SuspenseTimelineInput() { const min = 0; const max = timeline.length > 0 ? timeline.length - 1 : 0; - if (rootID === null) { - return ( -
    No root selected.
    - ); - } - - if (!store.supportsTogglingSuspense(rootID)) { - return ( -
    - Can't step through Suspense in production apps. -
    - ); - } - - if (timeline.length === 0) { - return ( -
    - Root contains no Suspense nodes. -
    - ); - } - function switchSuspenseNode(nextTimelineIndex: number) { const nextSelectedSuspenseID = timeline[nextTimelineIndex]; highlightHostInstance(nextSelectedSuspenseID); @@ -175,6 +153,28 @@ function SuspenseTimelineInput() { }; }, [playing]); + if (rootID === null) { + return ( +
    No root selected.
    + ); + } + + if (!store.supportsTogglingSuspense(rootID)) { + return ( +
    + Can't step through Suspense in production apps. +
    + ); + } + + if (timeline.length === 0) { + return ( +
    + Root contains no Suspense nodes. +
    + ); + } + return ( <> - ); - })} - -
    - {tabs.get(activeTab)} +
    +
    +
    + {Array.from(tabs.keys()).map(tab => { + const isActive = activeTab === tab; + return ( + + ); + })} +
    +
    + {tabs.get(activeTab)} +
    ); diff --git a/compiler/apps/playground/lib/transitionTypes.ts b/compiler/apps/playground/lib/transitionTypes.ts new file mode 100644 index 0000000000000..0c39e586fed54 --- /dev/null +++ b/compiler/apps/playground/lib/transitionTypes.ts @@ -0,0 +1,8 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +export const CONFIG_PANEL_TRANSITION = 'config-panel'; diff --git a/compiler/apps/playground/next.config.js b/compiler/apps/playground/next.config.js index fc8a9492e4ed7..f34f958ec6d2d 100644 --- a/compiler/apps/playground/next.config.js +++ b/compiler/apps/playground/next.config.js @@ -11,6 +11,7 @@ const path = require('path'); const nextConfig = { experimental: { reactCompiler: true, + viewTransition: true, }, reactStrictMode: true, webpack: (config, options) => { diff --git a/compiler/apps/playground/styles/globals.css b/compiler/apps/playground/styles/globals.css index c4558eb8b8a91..e8b92e6c7be48 100644 --- a/compiler/apps/playground/styles/globals.css +++ b/compiler/apps/playground/styles/globals.css @@ -69,3 +69,42 @@ scrollbar-width: none; /* Firefox */ } } + +::view-transition-old(.slide-in) { + animation-name: slideOutLeft; +} +::view-transition-new(.slide-in) { + animation-name: slideInLeft; +} +::view-transition-group(.slide-in) { + z-index: 1; +} + +@keyframes slideOutLeft { + from { + transform: translateX(0); + } + to { + transform: translateX(-100%); + } +} +@keyframes slideInLeft { + from { + transform: translateX(-100%); + } + to { + transform: translateX(0); + } +} + +::view-transition-old(.container), +::view-transition-new(.container) { + height: 100%; +} + +::view-transition-old(.accordion-container), +::view-transition-new(.accordion-container) { + height: 100%; + object-fit: none; + object-position: left; +}