1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 */78import MonacoEditor, {loader, type Monaco} from '@monaco-editor/react';9import {10 CompilerErrorDetail,11 CompilerDiagnostic,12} from 'babel-plugin-react-compiler';13import invariant from 'invariant';14import type {editor} from 'monaco-editor';15import * as monaco from 'monaco-editor';16import {17 useEffect,18 useState,19 unstable_ViewTransition as ViewTransition,20} from 'react';21import {renderReactCompilerMarkers} from '../../lib/reactCompilerMonacoDiagnostics';22import {useStore, useStoreDispatch} from '../StoreContext';23import TabbedWindow from '../TabbedWindow';24import {monacoOptions} from './monacoOptions';25import {CONFIG_PANEL_TRANSITION} from '../../lib/transitionTypes';2627// @ts-expect-error TODO: Make TS recognize .d.ts files, in addition to loading them with webpack.28import React$Types from '../../node_modules/@types/react/index.d.ts';2930loader.config({monaco});3132type Props = {33 errors: Array<CompilerErrorDetail | CompilerDiagnostic>;34 language: 'flow' | 'typescript';35};3637export default function Input({errors, language}: Props): JSX.Element {38 const [monaco, setMonaco] = useState<Monaco | null>(null);39 const store = useStore();40 const dispatchStore = useStoreDispatch();4142 // Set tab width to 2 spaces for the selected input file.43 useEffect(() => {44 if (!monaco) return;45 const uri = monaco.Uri.parse(`file:///index.js`);46 const model = monaco.editor.getModel(uri);47 invariant(model, 'Model must exist for the selected input file.');48 renderReactCompilerMarkers({49 monaco,50 model,51 details: errors,52 source: store.source,53 });54 }, [monaco, errors, store.source]);5556 useEffect(() => {57 /**58 * Ignore "can only be used in TypeScript files." errors, since59 * we want to support syntax highlighting for Flow (*.js) files60 * and Flow is not a built-in language.61 */62 if (!monaco) return;63 monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({64 diagnosticCodesToIgnore: [65 8002,66 8003,67 8004,68 8005,69 8006,70 8008,71 8009,72 8010,73 8011,74 8012,75 8013,76 ...(language === 'flow'77 ? [7028 /* unused label */, 6133 /* var declared but not read */]78 : []),79 ],80 noSemanticValidation: true,81 // Monaco can't validate Flow component syntax82 noSyntaxValidation: language === 'flow',83 });84 }, [monaco, language]);8586 const handleChange: (value: string | undefined) => void = async value => {87 if (!value) return;8889 dispatchStore({90 type: 'updateSource',91 payload: {92 source: value,93 },94 });95 };9697 const handleMount: (98 _: editor.IStandaloneCodeEditor,99 monaco: Monaco,100 ) => void = (_, monaco) => {101 if (typeof window !== 'undefined') {102 window['__MONACO_LOADED__'] = true;103 }104 setMonaco(monaco);105106 const tscOptions = {107 allowNonTsExtensions: true,108 target: monaco.languages.typescript.ScriptTarget.ES2015,109 moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,110 jsx: monaco.languages.typescript.JsxEmit.Preserve,111 typeRoots: ['node_modules/@types'],112 allowSyntheticDefaultImports: true,113 };114 monaco.languages.typescript.javascriptDefaults.setCompilerOptions(115 tscOptions,116 );117 monaco.languages.typescript.typescriptDefaults.setCompilerOptions({118 ...tscOptions,119 checkJs: true,120 allowJs: true,121 });122123 // Add React type declarations to Monaco124 const reactLib = [125 React$Types,126 'file:///node_modules/@types/react/index.d.ts',127 ] as [any, string];128 monaco.languages.typescript.javascriptDefaults.addExtraLib(...reactLib);129 monaco.languages.typescript.typescriptDefaults.addExtraLib(...reactLib);130131 /**132 * Remeasure the font in case the custom font is loaded only after133 * Monaco Editor is mounted.134 * N.B. that this applies also to the output editor as it seems135 * Monaco Editor instances share the same font config.136 */137 document.fonts.ready.then(() => {138 monaco.editor.remeasureFonts();139 });140 };141142 const editorContent = (143 <MonacoEditor144 path={'index.js'}145 /**146 * .js and .jsx files are specified to be TS so that Monaco can actually147 * check their syntax using its TS language service. They are still JS files148 * due to their extensions, so TS language features don't work.149 */150 language={'javascript'}151 value={store.source}152 onMount={handleMount}153 onChange={handleChange}154 className="monaco-editor-input"155 options={monacoOptions}156 loading={''}157 />158 );159160 const tabs = new Map([['Input', editorContent]]);161 const [activeTab, setActiveTab] = useState('Input');162163 return (164 <ViewTransition165 update={{166 [CONFIG_PANEL_TRANSITION]: 'container',167 default: 'none',168 }}>169 <div className="flex-1 min-w-[550px] sm:min-w-0">170 <div className="flex flex-col h-full !h-[calc(100vh_-_3.5rem)] border-r border-gray-200">171 <TabbedWindow172 tabs={tabs}173 activeTab={activeTab}174 onTabChange={setActiveTab}175 />176 </div>177 </div>178 </ViewTransition>179 );180}
Findings
✓ No findings reported for this file.