mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
Fixed two small issues with the config panel in the compiler playground: 1. Object descriptions were being confined in the config box and most of it would not be visible upon hover 2. Changed it so that "Applied Configs" would only display a valid set of configs, rather than switching between "Invalid Configs" and the set of options. This would be less visually jarring for users as the Output panel already displays errors. Additionally, if users want to see the list of config options but have a currently broken config, they would previously not know how to fix it. Object hover before: <img width="702" height="481" alt="Screenshot 2025-09-26 at 10 41 03 AM" src="https://github.com/user-attachments/assets/b2ddec2f-16ba-41a1-be1f-96211f46764c" /> Hover after: <img width="702" height="481" alt="Screenshot 2025-09-26 at 10 40 37 AM" src="https://github.com/user-attachments/assets/dc713a22-4710-46a8-a5d7-485060cc9074" /> Applied Configs always displays the last valid set of configs: https://github.com/user-attachments/assets/2fb9232f-7388-4488-9b7a-bb48bf09e4ca
216 lines
6.7 KiB
TypeScript
216 lines
6.7 KiB
TypeScript
/**
|
|
* 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 MonacoEditor, {loader, type Monaco} from '@monaco-editor/react';
|
|
import type {editor} from 'monaco-editor';
|
|
import * as monaco from 'monaco-editor';
|
|
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 {monacoConfigOptions} from './monacoOptions';
|
|
import {IconChevron} from '../Icons/IconChevron';
|
|
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';
|
|
|
|
loader.config({monaco});
|
|
|
|
export default function ConfigEditor({
|
|
formattedAppliedConfig,
|
|
}: {
|
|
formattedAppliedConfig: string;
|
|
}): React.ReactElement {
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
|
|
return (
|
|
// TODO: Use <Activity> when it is compatible with Monaco: https://github.com/suren-atoyan/monaco-react/issues/753
|
|
<>
|
|
<div
|
|
style={{
|
|
display: isExpanded ? 'block' : 'none',
|
|
}}>
|
|
<ExpandedEditor
|
|
onToggle={() => {
|
|
startTransition(() => {
|
|
addTransitionType(CONFIG_PANEL_TRANSITION);
|
|
setIsExpanded(false);
|
|
});
|
|
}}
|
|
formattedAppliedConfig={formattedAppliedConfig}
|
|
/>
|
|
</div>
|
|
<div
|
|
style={{
|
|
display: !isExpanded ? 'block' : 'none',
|
|
}}>
|
|
<CollapsedEditor
|
|
onToggle={() => {
|
|
startTransition(() => {
|
|
addTransitionType(CONFIG_PANEL_TRANSITION);
|
|
setIsExpanded(true);
|
|
});
|
|
}}
|
|
/>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function ExpandedEditor({
|
|
onToggle,
|
|
formattedAppliedConfig,
|
|
}: {
|
|
onToggle: (expanded: boolean) => void;
|
|
formattedAppliedConfig: string;
|
|
}): React.ReactElement {
|
|
const store = useStore();
|
|
const dispatchStore = useStoreDispatch();
|
|
const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
|
|
const handleChange: (value: string | undefined) => void = (
|
|
value: string | undefined,
|
|
) => {
|
|
if (value === undefined) return;
|
|
|
|
if (debounceTimerRef.current) {
|
|
clearTimeout(debounceTimerRef.current);
|
|
}
|
|
|
|
debounceTimerRef.current = setTimeout(() => {
|
|
dispatchStore({
|
|
type: 'updateConfig',
|
|
payload: {
|
|
config: value,
|
|
},
|
|
});
|
|
}, 500); // 500ms debounce delay
|
|
};
|
|
|
|
const handleMount: (
|
|
_: editor.IStandaloneCodeEditor,
|
|
monaco: Monaco,
|
|
) => void = (_, monaco) => {
|
|
// Add the babel-plugin-react-compiler type definitions to Monaco
|
|
monaco.languages.typescript.typescriptDefaults.addExtraLib(
|
|
//@ts-expect-error - compilerTypeDefs is a string
|
|
compilerTypeDefs,
|
|
'file:///node_modules/babel-plugin-react-compiler/dist/index.d.ts',
|
|
);
|
|
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
|
|
target: monaco.languages.typescript.ScriptTarget.Latest,
|
|
allowNonTsExtensions: true,
|
|
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
|
|
module: monaco.languages.typescript.ModuleKind.ESNext,
|
|
noEmit: true,
|
|
strict: false,
|
|
esModuleInterop: true,
|
|
allowSyntheticDefaultImports: true,
|
|
jsx: monaco.languages.typescript.JsxEmit.React,
|
|
});
|
|
};
|
|
|
|
return (
|
|
<ViewTransition
|
|
update={{[CONFIG_PANEL_TRANSITION]: '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 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 border border-gray-300">
|
|
<MonacoEditor
|
|
path={'config.ts'}
|
|
language={'typescript'}
|
|
value={store.config}
|
|
onMount={handleMount}
|
|
onChange={handleChange}
|
|
loading={''}
|
|
className="monaco-editor-config"
|
|
options={monacoConfigOptions}
|
|
/>
|
|
</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>
|
|
<div className="flex-1 border border-gray-300">
|
|
<MonacoEditor
|
|
path={'applied-config.js'}
|
|
language={'javascript'}
|
|
value={formattedAppliedConfig}
|
|
loading={''}
|
|
className="monaco-editor-applied-config"
|
|
options={{
|
|
...monacoConfigOptions,
|
|
readOnly: true,
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Resizable>
|
|
</ViewTransition>
|
|
);
|
|
}
|
|
|
|
function CollapsedEditor({
|
|
onToggle,
|
|
}: {
|
|
onToggle: () => void;
|
|
}): React.ReactElement {
|
|
return (
|
|
<div
|
|
className="w-4 !h-[calc(100vh_-_3.5rem)]"
|
|
style={{position: 'relative'}}>
|
|
<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}
|
|
style={{
|
|
top: '50%',
|
|
marginTop: '-32px',
|
|
left: '-8px',
|
|
borderTopLeftRadius: 0,
|
|
borderBottomLeftRadius: 0,
|
|
}}>
|
|
<IconChevron displayDirection="right" className="text-blue-50" />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|