diff --git a/compiler/apps/playground/__tests__/e2e/page.spec.ts b/compiler/apps/playground/__tests__/e2e/page.spec.ts index 4a10e8603bb28..94abe40eeb864 100644 --- a/compiler/apps/playground/__tests__/e2e/page.spec.ts +++ b/compiler/apps/playground/__tests__/e2e/page.spec.ts @@ -23,7 +23,8 @@ function formatPrint(data: Array): Promise { async function expandConfigs(page: Page): Promise { const expandButton = page.locator('[title="Expand config editor"]'); - expandButton.click(); + await expandButton.click(); + await page.waitForSelector('.monaco-editor-config', {state: 'visible'}); } const TEST_SOURCE = `export default function TestComponent({ x }) { diff --git a/compiler/apps/playground/components/AccordionWindow.tsx b/compiler/apps/playground/components/AccordionWindow.tsx index bebbb0c4787a5..197f543b4ab4a 100644 --- a/compiler/apps/playground/components/AccordionWindow.tsx +++ b/compiler/apps/playground/components/AccordionWindow.tsx @@ -18,19 +18,21 @@ export default function AccordionWindow(props: { changedPasses: Set; }): React.ReactElement { return ( -
- {Array.from(props.tabs.keys()).map(name => { - return ( - - ); - })} +
+
+ {Array.from(props.tabs.keys()).map(name => { + return ( + + ); + })} +
); } diff --git a/compiler/apps/playground/components/Editor/ConfigEditor.tsx b/compiler/apps/playground/components/Editor/ConfigEditor.tsx index c70cd10ba53e8..d922f27c97864 100644 --- a/compiler/apps/playground/components/Editor/ConfigEditor.tsx +++ b/compiler/apps/playground/components/Editor/ConfigEditor.tsx @@ -9,12 +9,19 @@ import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react'; import {PluginOptions} from 'babel-plugin-react-compiler'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; -import React, {useState, useRef} from 'react'; +import React, { + useState, + useRef, + unstable_ViewTransition as ViewTransition, + unstable_addTransitionType as addTransitionType, + startTransition, +} from 'react'; import {Resizable} from 're-resizable'; import {useStore, useStoreDispatch} from '../StoreContext'; import {monacoOptions} from './monacoOptions'; import {IconChevron} from '../Icons/IconChevron'; import prettyFormat from 'pretty-format'; +import {CONFIG_PANEL_TRANSITION} from '../../lib/transitionTypes'; // @ts-expect-error - webpack asset/source loader handles .d.ts files as strings import compilerTypeDefs from 'babel-plugin-react-compiler/dist/index.d.ts'; @@ -36,7 +43,12 @@ export default function ConfigEditor({ display: isExpanded ? 'block' : 'none', }}> { + startTransition(() => { + addTransitionType(CONFIG_PANEL_TRANSITION); + setIsExpanded(false); + }); + }} appliedOptions={appliedOptions} />
@@ -44,7 +56,14 @@ export default function ConfigEditor({ style={{ display: !isExpanded ? 'block' : 'none', }}> - + { + startTransition(() => { + addTransitionType(CONFIG_PANEL_TRANSITION); + setIsExpanded(true); + }); + }} + /> ); @@ -54,7 +73,7 @@ function ExpandedEditor({ onToggle, appliedOptions, }: { - onToggle: (expanded: boolean) => void; + onToggle: () => void; appliedOptions: PluginOptions | null; }): React.ReactElement { const store = useStore(); @@ -111,90 +130,93 @@ function ExpandedEditor({ : 'Invalid configs'; return ( - -
-
onToggle(false)} - style={{ - top: '50%', - marginTop: '-32px', - right: '-32px', - borderTopLeftRadius: 0, - borderBottomLeftRadius: 0, - }}> - -
- -
-
-

- Config Overrides -

-
-
- + + +
+
+
-
-
-
-

- Applied Configs -

+ +
+
+

+ Config Overrides +

+
+
+ +
-
- +
+
+

+ Applied Configs +

+
+
+ +
-
- + + ); } function CollapsedEditor({ onToggle, }: { - onToggle: (expanded: boolean) => void; + onToggle: () => void; }): React.ReactElement { return (
onToggle(true)} + onClick={onToggle} style={{ top: '50%', marginTop: '-32px', diff --git a/compiler/apps/playground/components/Editor/EditorImpl.tsx b/compiler/apps/playground/components/Editor/EditorImpl.tsx index 696bbd2559c11..9f000f85564a2 100644 --- a/compiler/apps/playground/components/Editor/EditorImpl.tsx +++ b/compiler/apps/playground/components/Editor/EditorImpl.tsx @@ -343,12 +343,8 @@ export default function Editor(): JSX.Element {
-
- -
-
- -
+ +
diff --git a/compiler/apps/playground/components/Editor/Input.tsx b/compiler/apps/playground/components/Editor/Input.tsx index 6cded7656b06f..8c37b12975b8b 100644 --- a/compiler/apps/playground/components/Editor/Input.tsx +++ b/compiler/apps/playground/components/Editor/Input.tsx @@ -13,11 +13,17 @@ import { import invariant from 'invariant'; import type {editor} from 'monaco-editor'; import * as monaco from 'monaco-editor'; -import {useEffect, useState} from 'react'; +import { + useEffect, + useState, + unstable_ViewTransition as ViewTransition, +} from 'react'; import {renderReactCompilerMarkers} from '../../lib/reactCompilerMonacoDiagnostics'; import {useStore, useStoreDispatch} from '../StoreContext'; import TabbedWindow from '../TabbedWindow'; import {monacoOptions} from './monacoOptions'; +import {CONFIG_PANEL_TRANSITION} from '../../lib/transitionTypes'; + // @ts-expect-error TODO: Make TS recognize .d.ts files, in addition to loading them with webpack. import React$Types from '../../node_modules/@types/react/index.d.ts'; @@ -155,9 +161,13 @@ export default function Input({errors, language}: Props): JSX.Element { const [activeTab, setActiveTab] = useState('Input'); return ( -
-
-
+ +
+
-
+ ); } diff --git a/compiler/apps/playground/components/Editor/Output.tsx b/compiler/apps/playground/components/Editor/Output.tsx index dcc8dea5c83bf..0ccc0747a6931 100644 --- a/compiler/apps/playground/components/Editor/Output.tsx +++ b/compiler/apps/playground/components/Editor/Output.tsx @@ -20,11 +20,19 @@ import parserBabel from 'prettier/plugins/babel'; import * as prettierPluginEstree from 'prettier/plugins/estree'; import * as prettier from 'prettier/standalone'; import {type Store} from '../../lib/stores'; -import {memo, ReactNode, use, useState, Suspense} from 'react'; +import { + memo, + ReactNode, + use, + useState, + Suspense, + unstable_ViewTransition as ViewTransition, +} from 'react'; import AccordionWindow from '../AccordionWindow'; import TabbedWindow from '../TabbedWindow'; import {monacoOptions} from './monacoOptions'; import {BabelFileResult} from '@babel/core'; +import {CONFIG_PANEL_TRANSITION} from '../../lib/transitionTypes'; import {LRUCache} from 'lru-cache'; const MemoizedOutput = memo(Output); @@ -280,22 +288,34 @@ function OutputContent({store, compilerOutput}: Props): JSX.Element { if (!store.showInternals) { return ( - + + + ); } return ( - + + + ); } diff --git a/compiler/apps/playground/components/TabbedWindow.tsx b/compiler/apps/playground/components/TabbedWindow.tsx index d2335687c2206..1fd5f188c7de1 100644 --- a/compiler/apps/playground/components/TabbedWindow.tsx +++ b/compiler/apps/playground/components/TabbedWindow.tsx @@ -17,26 +17,28 @@ export default function TabbedWindow({ onTabChange: (tab: string) => void; }): React.ReactElement { return ( -
-
- {Array.from(tabs.keys()).map(tab => { - const isActive = activeTab === tab; - 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; +}