mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 09:57:35 -02:30
add keyboard navigation help text to CodeEditor
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useCallback } from 'react';
|
import React, { useEffect, useRef, useCallback, useState } from 'react';
|
||||||
import { oneOf, bool, number, string, func } from 'prop-types';
|
import { oneOf, bool, number, string, func } from 'prop-types';
|
||||||
import ReactAce from 'react-ace';
|
import ReactAce from 'react-ace';
|
||||||
import 'ace-builds/src-noconflict/mode-json';
|
import 'ace-builds/src-noconflict/mode-json';
|
||||||
@@ -6,11 +6,23 @@ import 'ace-builds/src-noconflict/mode-javascript';
|
|||||||
import 'ace-builds/src-noconflict/mode-yaml';
|
import 'ace-builds/src-noconflict/mode-yaml';
|
||||||
import 'ace-builds/src-noconflict/mode-django';
|
import 'ace-builds/src-noconflict/mode-django';
|
||||||
import 'ace-builds/src-noconflict/theme-github';
|
import 'ace-builds/src-noconflict/theme-github';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
const LINE_HEIGHT = 24;
|
const LINE_HEIGHT = 24;
|
||||||
const PADDING = 12;
|
const PADDING = 12;
|
||||||
|
|
||||||
|
const FocusWrapper = styled.div`
|
||||||
|
&& + .pf-c-form__helper-text {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within + .pf-c-form__helper-text {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const AceEditor = styled(ReactAce)`
|
const AceEditor = styled(ReactAce)`
|
||||||
font-family: var(--pf-global--FontFamily--monospace);
|
font-family: var(--pf-global--FontFamily--monospace);
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
@@ -45,16 +57,21 @@ function CodeEditor({
|
|||||||
rows,
|
rows,
|
||||||
fullHeight,
|
fullHeight,
|
||||||
className,
|
className,
|
||||||
|
i18n,
|
||||||
}) {
|
}) {
|
||||||
|
const [isKeyboardFocused, setIsKeyboardFocused] = useState(false);
|
||||||
const wrapper = useRef(null);
|
const wrapper = useRef(null);
|
||||||
const editor = useRef(null);
|
const editor = useRef(null);
|
||||||
|
|
||||||
useEffect(function removeTextareaTabIndex() {
|
useEffect(
|
||||||
const editorInput = editor.current.refEditor?.querySelector('textarea');
|
function removeTextareaTabIndex() {
|
||||||
if (editorInput) {
|
const editorInput = editor.current.refEditor?.querySelector('textarea');
|
||||||
editorInput.tabIndex = -1;
|
if (editorInput && !readOnly) {
|
||||||
}
|
editorInput.tabIndex = -1;
|
||||||
}, []);
|
}
|
||||||
|
},
|
||||||
|
[readOnly]
|
||||||
|
);
|
||||||
|
|
||||||
const listen = useCallback(event => {
|
const listen = useCallback(event => {
|
||||||
if (
|
if (
|
||||||
@@ -88,43 +105,60 @@ function CodeEditor({
|
|||||||
const numRows = fullHeight ? value.split('\n').length : rows;
|
const numRows = fullHeight ? value.split('\n').length : rows;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
<>
|
||||||
<div ref={wrapper} tabIndex={0}>
|
<FocusWrapper
|
||||||
<AceEditor
|
ref={wrapper}
|
||||||
mode={aceModes[mode] || 'text'}
|
tabIndex={readOnly ? -1 : 0}
|
||||||
className={`pf-c-form-control ${className}`}
|
onFocus={e => {
|
||||||
theme="github"
|
if (e.target === e.currentTarget) {
|
||||||
onChange={onChange}
|
setIsKeyboardFocused(true);
|
||||||
value={value}
|
}
|
||||||
name={id || 'code-editor'}
|
if (e.target.className.includes('ace_scrollbar')) {
|
||||||
editorProps={{ $blockScrolling: true }}
|
setIsKeyboardFocused(false);
|
||||||
fontSize={16}
|
}
|
||||||
width="100%"
|
|
||||||
height={`${numRows * LINE_HEIGHT + PADDING}px`}
|
|
||||||
hasErrors={hasErrors}
|
|
||||||
setOptions={{
|
|
||||||
readOnly,
|
|
||||||
useWorker: false,
|
|
||||||
}}
|
}}
|
||||||
commands={[
|
>
|
||||||
{
|
<AceEditor
|
||||||
name: 'escape',
|
mode={aceModes[mode] || 'text'}
|
||||||
bindKey: { win: 'Esc', mac: 'Esc' },
|
className={`pf-c-form-control ${className}`}
|
||||||
exec: () => {
|
theme="github"
|
||||||
wrapper.current.focus();
|
onChange={onChange}
|
||||||
|
value={value}
|
||||||
|
name={id || 'code-editor'}
|
||||||
|
editorProps={{ $blockScrolling: true }}
|
||||||
|
fontSize={16}
|
||||||
|
width="100%"
|
||||||
|
height={`${numRows * LINE_HEIGHT + PADDING}px`}
|
||||||
|
hasErrors={hasErrors}
|
||||||
|
setOptions={{
|
||||||
|
readOnly,
|
||||||
|
useWorker: false,
|
||||||
|
}}
|
||||||
|
commands={[
|
||||||
|
{
|
||||||
|
name: 'escape',
|
||||||
|
bindKey: { win: 'Esc', mac: 'Esc' },
|
||||||
|
exec: () => {
|
||||||
|
wrapper.current.focus();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: 'tab escape',
|
||||||
name: 'tab escape',
|
bindKey: { win: 'Shift-Tab', mac: 'Shift-Tab' },
|
||||||
bindKey: { win: 'Shift-Tab', mac: 'Shift-Tab' },
|
exec: () => {
|
||||||
exec: () => {
|
wrapper.current.focus();
|
||||||
wrapper.current.focus();
|
},
|
||||||
},
|
},
|
||||||
},
|
]}
|
||||||
]}
|
ref={editor}
|
||||||
ref={editor}
|
/>
|
||||||
/>
|
</FocusWrapper>
|
||||||
</div>
|
{isKeyboardFocused && (
|
||||||
|
<div className="pf-c-form__helper-text" aria-live="polite">
|
||||||
|
{i18n._(t`Press Enter to edit. Press ESC to stop editing.`)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
CodeEditor.propTypes = {
|
CodeEditor.propTypes = {
|
||||||
@@ -146,4 +180,4 @@ CodeEditor.defaultProps = {
|
|||||||
className: '',
|
className: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CodeEditor;
|
export default withI18n()(CodeEditor);
|
||||||
|
|||||||
Reference in New Issue
Block a user