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 type {editor} from 'monaco-editor';10import * as monaco from 'monaco-editor';11import React, {12 useState,13 useRef,14 unstable_ViewTransition as ViewTransition,15 unstable_addTransitionType as addTransitionType,16 startTransition,17} from 'react';18import {Resizable} from 're-resizable';19import {useStore, useStoreDispatch} from '../StoreContext';20import {monacoConfigOptions} from './monacoOptions';21import {IconChevron} from '../Icons/IconChevron';22import {CONFIG_PANEL_TRANSITION} from '../../lib/transitionTypes';2324loader.config({monaco});2526export default function ConfigEditor({27 formattedAppliedConfig,28}: {29 formattedAppliedConfig: string;30}): React.ReactElement {31 const [isExpanded, setIsExpanded] = useState(false);3233 // TODO: Add back <Activity> after upgrading next.js34 return (35 <>36 <div37 style={{38 display: isExpanded ? 'block' : 'none',39 }}>40 {/* <Activity mode={isExpanded ? 'visible' : 'hidden'}> */}41 <ExpandedEditor42 onToggle={() => {43 startTransition(() => {44 addTransitionType(CONFIG_PANEL_TRANSITION);45 setIsExpanded(false);46 });47 }}48 formattedAppliedConfig={formattedAppliedConfig}49 />50 </div>51 <div52 style={{53 display: !isExpanded ? 'block' : 'none',54 }}>55 {/* </Activity>56 <Activity mode={isExpanded ? 'hidden' : 'visible'}></Activity> */}57 <CollapsedEditor58 onToggle={() => {59 startTransition(() => {60 addTransitionType(CONFIG_PANEL_TRANSITION);61 setIsExpanded(true);62 });63 }}64 />65 </div>66 {/* </Activity> */}67 </>68 );69}7071function ExpandedEditor({72 onToggle,73 formattedAppliedConfig,74}: {75 onToggle: (expanded: boolean) => void;76 formattedAppliedConfig: string;77}): React.ReactElement {78 const store = useStore();79 const dispatchStore = useStoreDispatch();80 const debounceTimerRef = useRef<NodeJS.Timeout | null>(null);8182 const handleChange: (value: string | undefined) => void = (83 value: string | undefined,84 ) => {85 if (value === undefined) return;8687 if (debounceTimerRef.current) {88 clearTimeout(debounceTimerRef.current);89 }9091 debounceTimerRef.current = setTimeout(() => {92 dispatchStore({93 type: 'updateConfig',94 payload: {95 config: value,96 },97 });98 }, 500); // 500ms debounce delay99 };100101 const handleMount: (102 _: editor.IStandaloneCodeEditor,103 monaco: Monaco,104 ) => void = (_, monaco) => {105 // Enable comments in JSON for JSON5-style config106 monaco.languages.json.jsonDefaults.setDiagnosticsOptions({107 allowComments: true,108 trailingCommas: 'ignore',109 });110 };111112 return (113 <ViewTransition114 update={{[CONFIG_PANEL_TRANSITION]: 'slide-in', default: 'none'}}>115 {/* enter={{[CONFIG_PANEL_TRANSITION]: 'slide-in', default: 'none'}}116 exit={{[CONFIG_PANEL_TRANSITION]: 'slide-out', default: 'none'}}> */}117 <Resizable118 minWidth={300}119 maxWidth={600}120 defaultSize={{width: 350}}121 enable={{right: true, bottom: false}}>122 <div className="bg-blue-10 relative h-full flex flex-col !h-[calc(100vh_-_3.5rem)] border border-gray-300">123 <div124 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"125 title="Minimize config editor"126 onClick={onToggle}127 style={{128 top: '50%',129 marginTop: '-32px',130 right: '-32px',131 borderTopLeftRadius: 0,132 borderBottomLeftRadius: 0,133 }}>134 <IconChevron displayDirection="left" className="text-blue-50" />135 </div>136137 <div className="flex-1 flex flex-col m-2 mb-2">138 <div className="pb-2">139 <h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">140 Config Overrides141 </h2>142 </div>143 <div className="flex-1 border border-gray-300">144 <MonacoEditor145 path={'config.json5'}146 language={'json'}147 value={store.config}148 onMount={handleMount}149 onChange={handleChange}150 loading={''}151 className="monaco-editor-config"152 options={monacoConfigOptions}153 />154 </div>155 </div>156 <div className="flex-1 flex flex-col m-2">157 <div className="pb-2">158 <h2 className="inline-block text-blue-50 py-1.5 px-1.5 xs:px-3 sm:px-4 text-sm">159 Applied Configs160 </h2>161 </div>162 <div className="flex-1 border border-gray-300">163 <MonacoEditor164 path={'applied-config.js'}165 language={'javascript'}166 value={formattedAppliedConfig}167 loading={''}168 className="monaco-editor-applied-config"169 options={{170 ...monacoConfigOptions,171 readOnly: true,172 }}173 />174 </div>175 </div>176 </div>177 </Resizable>178 </ViewTransition>179 );180}181182function CollapsedEditor({183 onToggle,184}: {185 onToggle: () => void;186}): React.ReactElement {187 return (188 <div189 className="w-4 !h-[calc(100vh_-_3.5rem)]"190 style={{position: 'relative'}}>191 <div192 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"193 title="Expand config editor"194 onClick={onToggle}195 style={{196 top: '50%',197 marginTop: '-32px',198 left: '-8px',199 borderTopLeftRadius: 0,200 borderBottomLeftRadius: 0,201 }}>202 <IconChevron displayDirection="right" className="text-blue-50" />203 </div>204 </div>205 );206}
Findings
✓ No findings reported for this file.