feat: control editor focus (#43882)

* refactor: MultifileEditor to functional component.

* fix: make editor acquire focus once on mount

Now the editors can leave the dom (e.g. if a tab is clicked), but an
editor will only call for focus if the MultifileEditor itself remounts
This commit is contained in:
Oliver Eyton-Williams
2021-10-19 17:52:51 +02:00
committed by GitHub
parent 2bddbbff42
commit 6c20301204
2 changed files with 148 additions and 145 deletions

View File

@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import React, { useRef } from 'react';
import { connect } from 'react-redux';
import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex';
import { createSelector } from 'reselect';
@ -73,14 +73,7 @@ const mapDispatchToProps = {
updateFile
};
class MultifileEditor extends Component {
focusOnHotkeys() {
if (this.props.containerRef.current) {
this.props.containerRef.current.focus();
}
}
render() {
const MultifileEditor = props => {
const {
challengeFiles,
containerRef,
@ -92,7 +85,7 @@ class MultifileEditor extends Component {
title,
visibleEditors: { indexcss, indexhtml, indexjs, indexjsx },
usesMultifileEditor
} = this.props;
} = props;
const editorTheme = theme === 'night' ? 'vs-dark-custom' : 'vs-custom';
// TODO: the tabs mess up the rendering (scroll doesn't work properly and
// the in-editor description)
@ -126,6 +119,11 @@ class MultifileEditor extends Component {
// TODO: the tabs mess up the rendering (scroll doesn't work properly and
// the in-editor description)
const targetEditor = getTargetEditor(challengeFiles);
// Only one editor should be focused and that should happen once, after it has
// been mounted. This ref allows the editors to co-ordinate, without having to
// resort to redux.
const canFocusOnMountRef = useRef(true);
return (
<ReflexContainer
orientation='horizontal'
@ -138,6 +136,7 @@ class MultifileEditor extends Component {
{indexjsx && (
<ReflexElement {...reflexProps} {...resizeProps}>
<Editor
canFocusOnMountRef={canFocusOnMountRef}
challengeFiles={challengeFiles}
containerRef={containerRef}
description={targetEditor === 'indexjsx' ? description : null}
@ -158,11 +157,10 @@ class MultifileEditor extends Component {
{indexhtml && (
<ReflexElement {...reflexProps} {...resizeProps}>
<Editor
canFocusOnMountRef={canFocusOnMountRef}
challengeFiles={challengeFiles}
containerRef={containerRef}
description={
targetEditor === 'indexhtml' ? description : null
}
description={targetEditor === 'indexhtml' ? description : null}
editorRef={editorRef}
fileKey='indexhtml'
initialTests={initialTests}
@ -180,6 +178,7 @@ class MultifileEditor extends Component {
{indexcss && (
<ReflexElement {...reflexProps} {...resizeProps}>
<Editor
canFocusOnMountRef={canFocusOnMountRef}
challengeFiles={challengeFiles}
containerRef={containerRef}
description={targetEditor === 'indexcss' ? description : null}
@ -201,6 +200,7 @@ class MultifileEditor extends Component {
{indexjs && (
<ReflexElement {...reflexProps} {...resizeProps}>
<Editor
canFocusOnMountRef={canFocusOnMountRef}
challengeFiles={challengeFiles}
containerRef={containerRef}
description={targetEditor === 'indexjs' ? description : null}
@ -219,8 +219,7 @@ class MultifileEditor extends Component {
</ReflexElement>
</ReflexContainer>
);
}
}
};
MultifileEditor.displayName = 'MultifileEditor';
MultifileEditor.propTypes = propTypes;

View File

@ -57,6 +57,7 @@ interface EditorProps {
executeChallenge: (options?: { showCompletionModal: boolean }) => void;
ext: ExtTypes;
fileKey: FileKeyTypes;
canFocusOnMountRef: MutableRefObject<boolean>;
initialEditorContent: string;
initialExt: string;
initTests: (tests: Test[]) => void;
@ -631,12 +632,15 @@ const Editor = (props: EditorProps): JSX.Element => {
function focusIfTargetEditor() {
const { editor } = dataRef.current;
if (!editor) return;
const { canFocusOnMountRef } = props;
if (!editor || !canFocusOnMountRef.current) return;
if (!props.usesMultifileEditor) {
// Only one editor? Focus it.
editor.focus();
canFocusOnMountRef.current = false;
} else if (hasEditableRegion()) {
editor.focus();
canFocusOnMountRef.current = false;
}
}