From d7006e63ea131b5e41e7f3bd638315ded599edcb Mon Sep 17 00:00:00 2001 From: Roman Date: Sat, 9 Oct 2021 21:34:36 +0300 Subject: [PATCH] ui/ux: improved handling editor's focus when interacting with Signed-off-by: Roman --- .../components/dock/dock-tab-content.tsx | 37 ++++++++++++++++--- .../monaco-editor/monaco-editor.tsx | 4 ++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/renderer/components/dock/dock-tab-content.tsx b/src/renderer/components/dock/dock-tab-content.tsx index 3a41107be3..9aaebbdb15 100644 --- a/src/renderer/components/dock/dock-tab-content.tsx +++ b/src/renderer/components/dock/dock-tab-content.tsx @@ -22,11 +22,13 @@ import "./dock-tab-content.scss"; import React from "react"; import { disposeOnUnmount, observer } from "mobx-react"; -import { computed, makeObservable, observable, reaction } from "mobx"; +import { action, computed, makeObservable, observable, reaction } from "mobx"; import type { DockTab, TabId } from "./dock.store"; +import { dockStore } from "./dock.store"; import { cssNames } from "../../utils"; import { DockTabComponents, dockViewsManager } from "./dock.views-manager"; import { MonacoEditor } from "../monaco-editor"; +import throttle from "lodash/throttle"; export interface DockTabContentProps extends React.HTMLAttributes { className?: string; @@ -36,12 +38,20 @@ export interface DockTabContentProps extends React.HTMLAttributes { @observer export class DockTabContent extends React.Component { + @observable.ref editor: MonacoEditor; + constructor(props: DockTabContentProps) { super(props); makeObservable(this); disposeOnUnmount(this, [ - reaction(() => this.tabId, () => this.error = ""), // reset + reaction(() => this.tabId, this.onTabChange, { delay: 100 }), + + // keep focus on editor's area when just opened + reaction(() => dockStore.isOpen, isOpen => isOpen && this.focusEditor()), + + // focus to editor on dock's resize or turning into fullscreen mode + dockStore.onResize(throttle(() => this.focusEditor(), 250)), ]); } @@ -55,6 +65,22 @@ export class DockTabContent extends React.Component { @observable error = ""; + @computed get editorIsVisible() { + return Boolean(this.tabComponents.editor); + } + + focusEditor() { + if (!this.editorIsVisible) return; + + this.editor.focus(); + } + + @action + onTabChange = () => { + this.error = ""; // reset any errors from another tab + this.focusEditor(); // focus to editor if available via registered tab views + }; + /** * Always keep editor in DOM while (while is open/rendered). * This allows to restore editor's model-view state (cursor pos, selection, etc.) @@ -62,20 +88,21 @@ export class DockTabContent extends React.Component { */ renderEditor() { const { tabId, tabComponents: { editor } } = this; - const isHidden = !editor; return ( { this.error = ""; editor?.setValue(tabId, value); }} onError={error => { - this.error = isHidden ? "" : error; + this.error = this.editorIsVisible ? error : ""; }} + ref={editor => this.editor = editor} /> ); } diff --git a/src/renderer/components/monaco-editor/monaco-editor.tsx b/src/renderer/components/monaco-editor/monaco-editor.tsx index b2c27dfba6..c8c59d574a 100644 --- a/src/renderer/components/monaco-editor/monaco-editor.tsx +++ b/src/renderer/components/monaco-editor/monaco-editor.tsx @@ -238,6 +238,10 @@ export class MonacoEditor extends React.Component { return this.editor?.getValue(opts) ?? ""; } + focus(){ + this.editor?.focus(); + } + @action validate = async (value = this.getValue()): Promise => { const { language } = this.props;