diff --git a/compiler/forget/packages/playground/components/Editor/Output.tsx b/compiler/forget/packages/playground/components/Editor/Output.tsx index 1056d5098b..11d40cfbbc 100644 --- a/compiler/forget/packages/playground/components/Editor/Output.tsx +++ b/compiler/forget/packages/playground/components/Editor/Output.tsx @@ -1,24 +1,21 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. +/** + * 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. */ +import TabbedWindow from "../TabbedWindow"; import MonacoEditor from "@monaco-editor/react"; import { + CompilerOutputs, OutputKind, stringifyCompilerOutputs, type Diagnostic, } from "babel-plugin-react-forget"; -import clsx from "clsx"; -import { memo, useEffect, useMemo, useState } from "react"; +import { memo, useEffect, useMemo } from "react"; import compile from "../../lib/compilerDriver"; -import { - getSelectedFile, - getVisualizedGraphKind, - isGraph, - isVisualizedGraph, - type OutputTabKind, - type Store, -} from "../../lib/stores"; +import { getSelectedFile, type Store } from "../../lib/stores"; import GraphView from "../GraphView"; import Preview from "../Preview"; import { monacoOptions } from "./monacoOptions"; @@ -33,118 +30,74 @@ type Props = { }; function Output({ store, updateDiagnostics }: Props) { - const [selectedTab, setSelectedTab] = useState("Preview"); const { outputs, diagnostics } = useMemo( () => compile(getSelectedFile(store), store.compilerFlags), [store] ); + useEffect(() => { + updateDiagnostics(diagnostics); + }, [diagnostics, updateDiagnostics]); + return ( + , + IR: , + HIR: , + CFG: , + ValGraph: ( + + ), + SCCGraph: ( + + ), + RedGraph: ( + + ), + LIR: , + JS: , + }} + /> + ); +} + +function TextTabContent({ + outputs, + kind, +}: { + outputs: CompilerOutputs; + kind: OutputKind; +}) { const prettyOutputs = useMemo( () => stringifyCompilerOutputs(outputs), [outputs] ); - const outputTabs = [ - ["Preview", "Preview"] as const, - ...Object.entries(OutputKind), - ]; - useEffect(() => { - updateDiagnostics(diagnostics); - }, [diagnostics, updateDiagnostics]); - - const outputContainer = () => { - // Special-case Preview to keep it mounted, saving its state. - if (selectedTab === "Preview") return null; - if (isVisualizedGraph(selectedTab)) { - const graphKind = getVisualizedGraphKind(selectedTab); - return ( -
- -
- ); - } - return ( -
- -
- ); - }; - - // TODO: Abstract into "TabbedWindow" component to reuse across input/output. - // TODO: Add indicator that output tabs have overflowed as part of responsive design. return ( -
-
- {outputTabs.map(([outputName, outputKind], index) => { - const isGraphViewSelected = selectedTab === `Visualized${outputKind}`; - const isTextViewSelected = selectedTab === outputKind; - const shouldDivide = index < outputTabs.length - 1; +
+ +
+ ); +} - return ( -
-
- - {isGraph(outputKind) ? ( - - ) : null} -
- {shouldDivide && ( -
- )} -
- ); - })} -
-
- -
- {outputContainer()} +function GraphTabContent({ + outputs, + kind, +}: { + outputs: CompilerOutputs; + kind: OutputKind.ValGraph | OutputKind.SCCGraph | OutputKind.RedGraph; +}) { + return ( +
+
); } diff --git a/compiler/forget/packages/playground/components/TabbedWindow.tsx b/compiler/forget/packages/playground/components/TabbedWindow.tsx new file mode 100644 index 0000000000..a08a4370eb --- /dev/null +++ b/compiler/forget/packages/playground/components/TabbedWindow.tsx @@ -0,0 +1,54 @@ +/** + * 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. + */ + +import clsx from "clsx"; +import React, { useState } from "react"; + +export default function TabbedWindow(props: { + defaultTab: string | null; + tabs: { [name: string]: React.ReactNode }; +}): React.ReactElement { + let [selected, setSelected] = useState(props.defaultTab); + if (selected === null) { + selected = Object.keys(props.tabs)[0]; + } + + return ( +
+
+ {Object.keys(props.tabs).map((name, index, all) => { + const isFirst = index === 0; + const isSelected = name === selected; + return ( + + {isFirst ? null : ( +
+ )} +
+ +
+ + ); + })} +
+ {props.tabs[selected]} +
+ ); +} diff --git a/compiler/forget/packages/playground/lib/stores/store.ts b/compiler/forget/packages/playground/lib/stores/store.ts index 2bc19b4432..b43339792e 100644 --- a/compiler/forget/packages/playground/lib/stores/store.ts +++ b/compiler/forget/packages/playground/lib/stores/store.ts @@ -9,37 +9,6 @@ import { codec } from "../utils"; import { ForgetCompilerFlags } from "../compilerDriver"; import { parseCompilerFlags } from "babel-plugin-react-forget"; -type VisualizedGraph = - | `Visualized${OutputKind.ValGraph}` - | `Visualized${OutputKind.SCCGraph}` - | `Visualized${OutputKind.RedGraph}`; - -export type OutputTabKind = OutputKind | VisualizedGraph | "Preview"; - -export function isGraph( - tabKind: OutputTabKind -): tabKind is - | OutputKind.ValGraph - | OutputKind.SCCGraph - | OutputKind.RedGraph - | VisualizedGraph { - return tabKind.endsWith("Graph"); -} - -export function isVisualizedGraph( - tabKind: OutputTabKind -): tabKind is VisualizedGraph { - return tabKind.startsWith("Visualized"); -} - -export function getVisualizedGraphKind(graphKind: VisualizedGraph) { - const kind = graphKind.slice("Visualized".length); - return kind as - | OutputKind.ValGraph - | OutputKind.SCCGraph - | OutputKind.RedGraph; -} - export enum FileExt { js = "javascript", jsx = "javascript",