import { BoxProps, Fade, HStack, useColorModeValue, useDisclosure, } from '@chakra-ui/react' import { useEffect, useRef, useState } from 'react' import { useDebouncedCallback } from 'use-debounce' import { VariablesButton } from '@/features/variables' import { Variable } from 'models' import { env } from 'utils' import CodeMirror, { ReactCodeMirrorRef } from '@uiw/react-codemirror' import { tokyoNight } from '@uiw/codemirror-theme-tokyo-night' import { githubLight } from '@uiw/codemirror-theme-github' import { LanguageName, loadLanguage } from '@uiw/codemirror-extensions-langs' import { isDefined } from '@udecode/plate-common' import { CopyButton } from './CopyButton' type Props = { value?: string defaultValue?: string lang: LanguageName isReadOnly?: boolean debounceTimeout?: number withVariableButton?: boolean height?: string onChange?: (value: string) => void } export const CodeEditor = ({ defaultValue, lang, onChange, height = '250px', withVariableButton = true, isReadOnly = false, debounceTimeout = 1000, ...props }: Props & Omit) => { const theme = useColorModeValue(githubLight, tokyoNight) const codeEditor = useRef(null) const [carretPosition, setCarretPosition] = useState(0) const isVariableButtonDisplayed = withVariableButton && !isReadOnly const [value, _setValue] = useState(defaultValue ?? '') const { onOpen, onClose, isOpen } = useDisclosure() const setValue = useDebouncedCallback( (value) => { _setValue(value) onChange && onChange(value) }, env('E2E_TEST') === 'true' ? 0 : debounceTimeout ) const handleVariableSelected = (variable?: Pick) => { codeEditor.current?.view?.focus() const insert = `{{${variable?.name}}}` codeEditor.current?.view?.dispatch({ changes: { from: carretPosition, insert, }, selection: { anchor: carretPosition + insert.length }, }) } const handleChange = (newValue: string) => { if (isDefined(props.value)) return setValue(newValue) setCarretPosition(codeEditor.current?.state?.selection.main.head ?? 0) } useEffect( () => () => { setValue.flush() }, [setValue] ) return ( {isVariableButtonDisplayed && ( )} {isReadOnly && ( )} ) }