fix(client): re-ref editor (#42799)

This commit is contained in:
Shaun Hamilton
2021-07-09 04:59:11 +01:00
committed by GitHub
parent d95962e405
commit 0891d41c35
2 changed files with 937 additions and 915 deletions

View File

@ -1,4 +1,11 @@
import React, { useState, useEffect, Suspense, RefObject } from 'react'; import React, {
useState,
useEffect,
Suspense,
RefObject,
forwardRef,
ForwardedRef
} from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import Loadable from '@loadable/component'; import Loadable from '@loadable/component';
@ -34,6 +41,7 @@ import type {
Range as RangeType Range as RangeType
// eslint-disable-next-line import/no-duplicates // eslint-disable-next-line import/no-duplicates
} from 'monaco-editor/esm/vs/editor/editor.api'; } from 'monaco-editor/esm/vs/editor/editor.api';
import type ReactMonacoEditor from 'react-monaco-editor';
import './editor.css'; import './editor.css';
@ -174,7 +182,8 @@ const initialData: DataType = {
outputZoneHeight: null outputZoneHeight: null
}; };
const Editor = (props: PropTypes): JSX.Element => { const Editor = forwardRef(
(props: PropTypes, ref: ForwardedRef<ReactMonacoEditor>): JSX.Element => {
// TODO: is there any point in initializing this? It should be fine with // TODO: is there any point in initializing this? It should be fine with
// data = {} // data = {}
const [data, setData] = useState(initialData); const [data, setData] = useState(initialData);
@ -416,7 +425,9 @@ const Editor = (props: PropTypes): JSX.Element => {
} }
}; };
const viewZoneCallback = (changeAccessor: editor.IViewZoneChangeAccessor) => { const viewZoneCallback = (
changeAccessor: editor.IViewZoneChangeAccessor
) => {
// TODO: is there any point creating this here? I know it's cached, but // TODO: is there any point creating this here? I know it's cached, but
// would it not be better just sourced from the overlayWidget? // would it not be better just sourced from the overlayWidget?
const domNode = createDescription(); const domNode = createDescription();
@ -559,11 +570,6 @@ const Editor = (props: PropTypes): JSX.Element => {
} }
} }
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function focusOnEditor() {
_editor?.focus();
}
const onChange = (editorValue: string) => { const onChange = (editorValue: string) => {
const { updateFile } = props; const { updateFile } = props;
// TODO: use fileKey everywhere? // TODO: use fileKey everywhere?
@ -596,7 +602,10 @@ const Editor = (props: PropTypes): JSX.Element => {
lineNumber: editableBoundaries[0] + 1, lineNumber: editableBoundaries[0] + 1,
column: 1 column: 1
}); });
_editor?.revealLinesInCenter(editableBoundaries[0], editableBoundaries[1]); _editor?.revealLinesInCenter(
editableBoundaries[0],
editableBoundaries[1]
);
// } // }
} }
@ -757,7 +766,12 @@ const Editor = (props: PropTypes): JSX.Element => {
// startColumnNumber <= x < endColumnNumber // startColumnNumber <= x < endColumnNumber
// so we add 1 here // so we add 1 here
const endColumn = model?.getLineLength(endLineNumber) + 1; const endColumn = model?.getLineLength(endLineNumber) + 1;
return new _monaco.Range(startLineNumber, 1, endLineNumber, endColumn); return new _monaco.Range(
startLineNumber,
1,
endLineNumber,
endColumn
);
} }
return null; return null;
} }
@ -802,13 +816,15 @@ const Editor = (props: PropTypes): JSX.Element => {
// the first range should expand at the top // the first range should expand at the top
// TODO: Unsure what this should be - returns an array, so I added [0] @ojeytonwilliams // TODO: Unsure what this should be - returns an array, so I added [0] @ojeytonwilliams
data.startEditDecId = highlightLines( data.startEditDecId = highlightLines(
_monaco?.editor?.TrackedRangeStickiness?.GrowsOnlyWhenTypingBefore ?? 2, _monaco?.editor?.TrackedRangeStickiness?.GrowsOnlyWhenTypingBefore ??
2,
model, model,
ranges[0] ranges[0]
)[0]; )[0];
highlightText( highlightText(
_monaco?.editor?.TrackedRangeStickiness?.GrowsOnlyWhenTypingBefore ?? 2, _monaco?.editor?.TrackedRangeStickiness?.GrowsOnlyWhenTypingBefore ??
2,
model, model,
ranges[0] ranges[0]
); );
@ -834,7 +850,8 @@ const Editor = (props: PropTypes): JSX.Element => {
// TODO: handle multiple simultaneous changes (multicursors do this) // TODO: handle multiple simultaneous changes (multicursors do this)
function getDeletedLine(event: editor.IModelContentChangedEvent) { function getDeletedLine(event: editor.IModelContentChangedEvent) {
const isDeleted = const isDeleted =
event.changes[0].text === '' && event.changes[0].range.endColumn === 1; event.changes[0].text === '' &&
event.changes[0].range.endColumn === 1;
return isDeleted ? event.changes[0].range.endLineNumber : 0; return isDeleted ? event.changes[0].range.endLineNumber : 0;
} }
@ -971,8 +988,8 @@ const Editor = (props: PropTypes): JSX.Element => {
...data, ...data,
endEditDecId: preventOverlap( endEditDecId: preventOverlap(
data.endEditDecId ?? '', data.endEditDecId ?? '',
_monaco?.editor?.TrackedRangeStickiness?.GrowsOnlyWhenTypingBefore ?? _monaco?.editor?.TrackedRangeStickiness
2, ?.GrowsOnlyWhenTypingBefore ?? 2,
highlightLines highlightLines
) )
}); });
@ -1021,7 +1038,10 @@ const Editor = (props: PropTypes): JSX.Element => {
// Protect against ranges that extend outside the editor // Protect against ranges that extend outside the editor
const startLineNumber = Math.max(1, range.startLineNumber); const startLineNumber = Math.max(1, range.startLineNumber);
const endLineNumber = Math.min(model?.getLineCount(), range.endLineNumber); const endLineNumber = Math.min(
model?.getLineCount(),
range.endLineNumber
);
const endColumnText = model.getLineContent(endLineNumber); const endColumnText = model.getLineContent(endLineNumber);
// NOTE: the end column is incremented by 2 so that the dangerous range // NOTE: the end column is incremented by 2 so that the dangerous range
// extends far enough to capture new text added to the end. // extends far enough to capture new text added to the end.
@ -1150,17 +1170,19 @@ const Editor = (props: PropTypes): JSX.Element => {
editorWillMount={editorWillMount} editorWillMount={editorWillMount}
onChange={onChange} onChange={onChange}
options={options} options={options}
ref={ref}
theme={editorTheme} theme={editorTheme}
/> />
</span> </span>
</Suspense> </Suspense>
); );
}; }
);
Editor.displayName = 'Editor'; Editor.displayName = 'Editor';
// NOTE: withRef gets replaced by forwardRef in react-redux 6, // NOTE: withRef gets replaced by forwardRef in react-redux 6,
// https://github.com/reduxjs/react-redux/releases/tag/v6.0.0 // https://github.com/reduxjs/react-redux/releases/tag/v6.0.0
export default connect(mapStateToProps, mapDispatchToProps, null, { export default connect(mapStateToProps, mapDispatchToProps, null, {
forwardRef: true withRef: true
})(Editor); })(Editor);

View File

@ -60,7 +60,7 @@ function Hotkeys({
FOCUS_EDITOR: (e: React.KeyboardEvent) => { FOCUS_EDITOR: (e: React.KeyboardEvent) => {
e.preventDefault(); e.preventDefault();
if (editorRef && editorRef.current) { if (editorRef && editorRef.current) {
editorRef.current.getWrappedInstance().focusOnEditor(); editorRef.current.getWrappedInstance().editor.focus();
} }
}, },
NAVIGATION_MODE: () => setEditorFocusability(false), NAVIGATION_MODE: () => setEditorFocusability(false),