diff --git a/client/modules/IDE/components/ConsoleInput.jsx b/client/modules/IDE/components/ConsoleInput.jsx index 759ccdd10d..1e45024bce 100644 --- a/client/modules/IDE/components/ConsoleInput.jsx +++ b/client/modules/IDE/components/ConsoleInput.jsx @@ -1,39 +1,33 @@ +import React, { useRef, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; -import React from 'react'; import CodeMirror from 'codemirror'; import { Encode } from 'console-feed'; import RightArrowIcon from '../../../images/right-arrow.svg'; import { dispatchMessage, MessageTypes } from '../../../utils/dispatcher'; -// heavily inspired by -// https://github.com/codesandbox/codesandbox-client/blob/92a1131f4ded6f7d9c16945dc7c18aa97c8ada27/packages/app/src/app/components/Preview/DevTools/Console/Input/index.tsx +const ConsoleInput = ({ theme, dispatchConsoleEvent, fontSize }) => { + const [commandHistory, setCommandHistory] = useState([]); + const [commandCursor, setCommandCursor] = useState(-1); -class ConsoleInput extends React.Component { - constructor(props) { - super(props); - this.state = { - commandHistory: [], - commandCursor: -1 - }; - } + const codemirrorContainerRef = useRef(null); + const codemirrorRef = useRef(null); - componentDidMount() { - this._cm = CodeMirror(this.codemirrorContainer, { - // eslint-disable-line - theme: `p5-${this.props.theme}`, + useEffect(() => { + codemirrorRef.current = CodeMirror(codemirrorContainerRef.current, { + theme: `p5-${theme}`, scrollbarStyle: null, keymap: 'sublime', mode: 'javascript', inputStyle: 'contenteditable' }); - this._cm.on('keydown', (cm, e) => { + const handleKeyDown = (cm, e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); e.stopPropagation(); const value = cm.getValue(); - if (value.trim(' ') === '') { + if (value.trim() === '') { return false; } const messages = [ @@ -47,92 +41,84 @@ class ConsoleInput extends React.Component { messages } }); - this.props.dispatchConsoleEvent(consoleEvent); + dispatchConsoleEvent(consoleEvent); cm.setValue(''); - this.setState((state) => ({ - commandCursor: -1, - commandHistory: [value, ...state.commandHistory] - })); + setCommandCursor(-1); + setCommandHistory((prevHistory) => [value, ...prevHistory]); } else if (e.key === 'ArrowUp') { - const lineNumber = this._cm.getDoc().getCursor().line; + const lineNumber = cm.getDoc().getCursor().line; if (lineNumber !== 0) { return false; } - this.setState((state) => { - const newCursor = Math.min( - state.commandCursor + 1, - state.commandHistory.length - 1 - ); - this._cm.getDoc().setValue(state.commandHistory[newCursor] || ''); - const cursorPos = this._cm.getDoc().getLine(0).length - 1; - this._cm.getDoc().setCursor({ line: 0, ch: cursorPos }); - return { commandCursor: newCursor }; + setCommandCursor((prevCursor) => { + const newCursor = Math.min(prevCursor + 1, commandHistory.length - 1); + cm.getDoc().setValue(commandHistory[newCursor] || ''); + const cursorPos = cm.getDoc().getLine(0).length - 1; + cm.getDoc().setCursor({ line: 0, ch: cursorPos }); + return newCursor; }); } else if (e.key === 'ArrowDown') { - const lineNumber = this._cm.getDoc().getCursor().line; - const lineCount = this._cm.getValue().split('\n').length; + const lineNumber = cm.getDoc().getCursor().line; + const lineCount = cm.getValue().split('\n').length; if (lineNumber + 1 !== lineCount) { return false; } - this.setState((state) => { - const newCursor = Math.max(state.commandCursor - 1, -1); - this._cm.getDoc().setValue(state.commandHistory[newCursor] || ''); - const newLineCount = this._cm.getValue().split('\n').length; - const newLine = this._cm.getDoc().getLine(newLineCount); + setCommandCursor((prevCursor) => { + const newCursor = Math.max(prevCursor - 1, -1); + cm.getDoc().setValue(commandHistory[newCursor] || ''); + const newLineCount = cm.getValue().split('\n').length; + const newLine = cm.getDoc().getLine(newLineCount); const cursorPos = newLine ? newLine.length - 1 : 1; - this._cm.getDoc().setCursor({ line: lineCount, ch: cursorPos }); - return { commandCursor: newCursor }; + cm.getDoc().setCursor({ line: lineCount, ch: cursorPos }); + return newCursor; }); } return true; - }); + }; - this._cm.getWrapperElement().style[ + codemirrorRef.current.on('keydown', handleKeyDown); + codemirrorRef.current.getWrapperElement().style[ 'font-size' - ] = `${this.props.fontSize}px`; - } + ] = `${fontSize}px`; - componentDidUpdate(prevProps) { - this._cm.setOption('theme', `p5-${this.props.theme}`); - this._cm.getWrapperElement().style[ - 'font-size' - ] = `${this.props.fontSize}px`; - this._cm.refresh(); - } + return () => { + codemirrorRef.current.off('keydown', handleKeyDown); + codemirrorRef.current = null; + }; + }, [theme, dispatchConsoleEvent, fontSize]); - componentWillUnmount() { - this._cm = null; - } + useEffect(() => { + if (codemirrorRef.current) { + codemirrorRef.current.setOption('theme', `p5-${theme}`); + codemirrorRef.current.getWrapperElement().style[ + 'font-size' + ] = `${fontSize}px`; + codemirrorRef.current.refresh(); + } + }, [theme, fontSize]); - render() { - return ( -