Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/apps/playground/__tests__/e2e/page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ function formatPrint(data: Array<string>): Promise<string> {

async function expandConfigs(page: Page): Promise<void> {
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 }) {
Expand Down
178 changes: 99 additions & 79 deletions compiler/apps/playground/components/Editor/ConfigEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ 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';
Expand All @@ -36,15 +42,27 @@ export default function ConfigEditor({
display: isExpanded ? 'block' : 'none',
}}>
<ExpandedEditor
onToggle={setIsExpanded}
onToggle={() => {
startTransition(() => {
addTransitionType('config-panel');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type could be a constant as its important it matches across usages through these modules but should also be unique from anything used in future unrelated transitions.

You could have something like apps/playground/lib/transitionTypes.ts where you export from.

setIsExpanded(false);
});
}}
appliedOptions={appliedOptions}
/>
</div>
<div
style={{
display: !isExpanded ? 'block' : 'none',
}}>
<CollapsedEditor onToggle={setIsExpanded} />
<CollapsedEditor
onToggle={() => {
startTransition(() => {
addTransitionType('config-panel');
setIsExpanded(true);
});
}}
/>{' '}
</div>
</>
);
Expand All @@ -54,7 +72,7 @@ function ExpandedEditor({
onToggle,
appliedOptions,
}: {
onToggle: (expanded: boolean) => void;
onToggle: () => void;
appliedOptions: PluginOptions | null;
}): React.ReactElement {
const store = useStore();
Expand Down Expand Up @@ -111,90 +129,92 @@ function ExpandedEditor({
: 'Invalid configs';

return (
<Resizable
minWidth={300}
maxWidth={600}
defaultSize={{width: 350}}
enable={{right: true, bottom: false}}>
<div className="bg-blue-10 relative h-full flex flex-col !h-[calc(100vh_-_3.5rem)] border border-gray-300">
<div
className="absolute w-8 h-16 bg-blue-10 rounded-r-full flex items-center justify-center z-[2] cursor-pointer border border-l-0 border-gray-300"
title="Minimize config editor"
onClick={() => onToggle(false)}
style={{
top: '50%',
marginTop: '-32px',
right: '-32px',
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
}}>
<IconChevron displayDirection="left" className="text-blue-50" />
</div>

<div className="flex-1 flex flex-col m-2 mb-2">
<div className="pb-2">
<h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">
Config Overrides
</h2>
</div>
<div className="flex-1 rounded-lg overflow-hidden border border-gray-300">
<MonacoEditor
path={'config.ts'}
language={'typescript'}
value={store.config}
onMount={handleMount}
onChange={handleChange}
loading={''}
className="monaco-editor-config"
options={{
...monacoOptions,
lineNumbers: 'off',
renderLineHighlight: 'none',
overviewRulerBorder: false,
overviewRulerLanes: 0,
fontSize: 12,
scrollBeyondLastLine: false,
glyphMargin: false,
}}
/>
<ViewTransition update={{'config-panel': 'slide-in', default: 'none'}}>
<Resizable
minWidth={300}
maxWidth={600}
defaultSize={{width: 350}}
enable={{right: true, bottom: false}}>
<div className="bg-blue-10 relative h-full flex flex-col !h-[calc(100vh_-_3.5rem)] border border-gray-300">
<div
className="absolute w-8 h-16 bg-blue-10 rounded-r-full flex items-center justify-center z-[2] cursor-pointer border border-l-0 border-gray-300"
title="Minimize config editor"
onClick={onToggle}
style={{
top: '50%',
marginTop: '-32px',
right: '-32px',
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0,
}}>
<IconChevron displayDirection="left" className="text-blue-50" />
</div>
</div>
<div className="flex-1 flex flex-col m-2">
<div className="pb-2">
<h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">
Applied Configs
</h2>

<div className="flex-1 flex flex-col m-2 mb-2">
<div className="pb-2">
<h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">
Config Overrides
</h2>
</div>
<div className="flex-1 rounded-lg overflow-hidden border border-gray-300">
<MonacoEditor
path={'config.ts'}
language={'typescript'}
value={store.config}
onMount={handleMount}
onChange={handleChange}
loading={''}
className="monaco-editor-config"
options={{
...monacoOptions,
lineNumbers: 'off',
renderLineHighlight: 'none',
overviewRulerBorder: false,
overviewRulerLanes: 0,
fontSize: 12,
scrollBeyondLastLine: false,
glyphMargin: false,
}}
/>
</div>
</div>
<div className="flex-1 rounded-lg overflow-hidden border border-gray-300">
<MonacoEditor
path={'applied-config.js'}
language={'javascript'}
value={formattedAppliedOptions}
loading={''}
className="monaco-editor-applied-config"
options={{
...monacoOptions,
lineNumbers: 'off',
renderLineHighlight: 'none',
overviewRulerBorder: false,
overviewRulerLanes: 0,
fontSize: 12,
scrollBeyondLastLine: false,
readOnly: true,
glyphMargin: false,
}}
/>
<div className="flex-1 flex flex-col m-2">
<div className="pb-2">
<h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">
Applied Configs
</h2>
</div>
<div className="flex-1 rounded-lg overflow-hidden border border-gray-300">
<MonacoEditor
path={'applied-config.js'}
language={'javascript'}
value={formattedAppliedOptions}
loading={''}
className="monaco-editor-applied-config"
options={{
...monacoOptions,
lineNumbers: 'off',
renderLineHighlight: 'none',
overviewRulerBorder: false,
overviewRulerLanes: 0,
fontSize: 12,
scrollBeyondLastLine: false,
readOnly: true,
glyphMargin: false,
}}
/>
</div>
</div>
</div>
</div>
</Resizable>
</Resizable>
</ViewTransition>
);
}

function CollapsedEditor({
onToggle,
}: {
onToggle: (expanded: boolean) => void;
onToggle: () => void;
}): React.ReactElement {
return (
<div
Expand All @@ -203,7 +223,7 @@ function CollapsedEditor({
<div
className="absolute w-10 h-16 bg-blue-10 hover:translate-x-2 transition-transform rounded-r-full flex items-center justify-center z-[2] cursor-pointer border border-gray-300"
title="Expand config editor"
onClick={() => onToggle(true)}
onClick={onToggle}
style={{
top: '50%',
marginTop: '-32px',
Expand Down
27 changes: 19 additions & 8 deletions compiler/apps/playground/components/Editor/EditorImpl.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import BabelPluginReactCompiler, {
printFunctionWithOutlined,
type LoggerEvent,
} from 'babel-plugin-react-compiler';
import {useDeferredValue, useMemo} from 'react';
import {
useDeferredValue,
useMemo,
unstable_ViewTransition as ViewTransition,
} from 'react';
import {useStore} from '../StoreContext';
import ConfigEditor from './ConfigEditor';
import Input from './Input';
Expand Down Expand Up @@ -342,14 +346,21 @@ export default function Editor(): JSX.Element {
<div className="flex-shrink-0">
<ConfigEditor appliedOptions={appliedOptions} />
</div>
<div className="flex flex-1 min-w-0">
<div className="flex-1 min-w-[550px] sm:min-w-0">
<Input language={language} errors={errors} />
</div>
<div className="flex-1 min-w-[550px] sm:min-w-0">
<Output store={deferredStore} compilerOutput={mergedOutput} />

<ViewTransition
update={{
'config-panel': 'container',
default: 'none',
}}>
<div className="flex flex-1 min-w-0">
<div className="flex-1 min-w-[550px] sm:min-w-0">
<Input language={language} errors={errors} />
</div>
<div className="flex-1 min-w-[550px] sm:min-w-0">
<Output store={deferredStore} compilerOutput={mergedOutput} />
</div>
</div>
</div>
</ViewTransition>
</div>
</>
);
Expand Down
45 changes: 34 additions & 11 deletions compiler/apps/playground/components/Editor/Output.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import {
import parserBabel from 'prettier/plugins/babel';
import * as prettierPluginEstree from 'prettier/plugins/estree';
import * as prettier from 'prettier/standalone';
import {memo, ReactNode, useEffect, useState} from 'react';
import {type Store} from '../../lib/stores';
import {memo, ReactNode, use, useState, Suspense} from 'react';
import AccordionWindow from '../AccordionWindow';
import TabbedWindow from '../TabbedWindow';
import {monacoOptions} from './monacoOptions';
Expand All @@ -32,6 +32,8 @@ export default MemoizedOutput;

export const BASIC_OUTPUT_TAB_NAMES = ['Output', 'SourceMap'];

let tabifyCache = new Map<Store, Promise<Map<string, ReactNode>>>();

export type PrintedCompilerPipelineValue =
| {
kind: 'hir';
Expand Down Expand Up @@ -200,6 +202,28 @@ ${code}
return reorderedTabs;
}

function tabifyCached(
store: Store,
compilerOutput: CompilerOutput,
): Promise<Map<string, ReactNode>> {
const key = store;
if (tabifyCache.has(key)) {
return tabifyCache.get(key)!;
}
const result = tabify(store.source, compilerOutput, store.showInternals);
tabifyCache.set(key, result);
return result;
}

function Fallback(): JSX.Element {
console.log('Fallback');
return (
<div className="w-full h-monaco_small sm:h-monaco flex items-center justify-center">
Loading...
</div>
);
}

function utf16ToUTF8(s: string): string {
return unescape(encodeURIComponent(s));
}
Expand All @@ -213,12 +237,17 @@ function getSourceMapUrl(code: string, map: string): string | null {
}

function Output({store, compilerOutput}: Props): JSX.Element {
return (
<Suspense fallback={<Fallback />}>
<OutputContent store={store} compilerOutput={compilerOutput} />
</Suspense>
);
}

function OutputContent({store, compilerOutput}: Props): JSX.Element {
const [tabsOpen, setTabsOpen] = useState<Set<string>>(
() => new Set(['Output']),
);
const [tabs, setTabs] = useState<Map<string, React.ReactNode>>(
() => new Map(),
);
const [activeTab, setActiveTab] = useState<string>('Output');

/*
Expand All @@ -233,13 +262,6 @@ function Output({store, compilerOutput}: Props): JSX.Element {
setTabsOpen(new Set(['Output']));
setActiveTab('Output');
}

useEffect(() => {
tabify(store.source, compilerOutput, store.showInternals).then(tabs => {
setTabs(tabs);
});
}, [store.source, compilerOutput, store.showInternals]);

const changedPasses: Set<string> = new Set(['Output', 'HIR']); // Initial and final passes should always be bold
let lastResult: string = '';
for (const [passName, results] of compilerOutput.results) {
Expand All @@ -254,6 +276,7 @@ function Output({store, compilerOutput}: Props): JSX.Element {
lastResult = currResult;
}
}
const tabs = use(tabifyCached(store, compilerOutput));

if (!store.showInternals) {
return (
Expand Down
1 change: 1 addition & 0 deletions compiler/apps/playground/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const path = require('path');
const nextConfig = {
experimental: {
reactCompiler: true,
viewTransition: true,
},
reactStrictMode: true,
webpack: (config, options) => {
Expand Down
Loading
Loading