add code editor focus/blur keyboard controls

This commit is contained in:
Keith Grant
2021-02-05 11:58:23 -08:00
committed by Keith J. Grant
parent 1afdd7ac1d
commit 4e9c6a956d

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useRef, useCallback } from 'react';
import { oneOf, bool, number, string, func } from 'prop-types'; import { oneOf, bool, number, string, func } from 'prop-types';
import AceEditor from 'react-ace'; import AceEditor from 'react-ace';
// import * as ace from 'ace-builds'; // import * as ace from 'ace-builds';
@@ -79,6 +79,7 @@ const CodeMirror = styled(ReactCodeMirror)`
`; `;
function CodeMirrorInput({ function CodeMirrorInput({
id,
value, value,
onChange, onChange,
mode, mode,
@@ -89,19 +90,33 @@ function CodeMirrorInput({
className, className,
placeholder, placeholder,
}) { }) {
// Workaround for CodeMirror bug: If CodeMirror renders in a modal on the const wrapper = useRef(null);
// modal's initial render, it appears as an empty box due to mis-calculated const editor = useRef(null);
// element height. Forcing an initial render before mounting <CodeMirror>
// fixes this. useEffect(function removeTextareaTabIndex() {
const [isInitialized, setIsInitialized] = useState(false); const editorInput = editor.current.refEditor?.querySelector('textarea');
useEffect(() => { if (editorInput) {
if (!isInitialized) { editorInput.tabIndex = -1;
setIsInitialized(true);
} }
}, [isInitialized]); }, []);
if (!isInitialized) {
return <div />; const listen = useCallback(event => {
} if (wrapper.current === document.activeElement && event.key === 'Enter') {
const editorInput = editor.current.refEditor?.querySelector('textarea');
if (editorInput) {
editorInput.focus();
}
}
}, []);
useEffect(function addKeyEventListeners() {
const wrapperEl = wrapper.current;
wrapperEl.addEventListener('keydown', listen);
return () => {
wrapperEl.removeEventListener('keydown', listen);
};
});
return ( return (
<> <>
@@ -121,19 +136,38 @@ function CodeMirrorInput({
fullHeight={fullHeight} fullHeight={fullHeight}
rows={rows} rows={rows}
/> */} /> */}
<AceEditor <div ref={wrapper} tabIndex={0}>
mode={mode === 'javascript' ? 'json' : mode} <AceEditor
theme="github" mode={mode === 'javascript' ? 'json' : mode}
onChange={onChange} theme="github"
value={value} onChange={onChange}
name="UNIQUE_ID_OF_DIV" value={value}
editorProps={{ $blockScrolling: true }} name={id || 'code-editor'}
width="100%" editorProps={{ $blockScrolling: true }}
setOptions={{ width="100%"
readOnly, setOptions={{
useWorker: false, readOnly,
}} useWorker: false,
/> }}
commands={[
{
name: 'escape',
bindKey: { win: 'Esc', mac: 'Esc' },
exec: () => {
wrapper.current.focus();
},
},
{
name: 'tab escape',
bindKey: { win: 'Shift-Tab', mac: 'Shift-Tab' },
exec: () => {
wrapper.current.focus();
},
},
]}
ref={editor}
/>
</div>
</> </>
); );
} }