mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
ui/ux: improved handling editor's focus when interacting with <Dock/>
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
118d07cfb9
commit
d7006e63ea
@ -22,11 +22,13 @@
|
|||||||
import "./dock-tab-content.scss";
|
import "./dock-tab-content.scss";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { disposeOnUnmount, observer } from "mobx-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 type { DockTab, TabId } from "./dock.store";
|
||||||
|
import { dockStore } from "./dock.store";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { DockTabComponents, dockViewsManager } from "./dock.views-manager";
|
import { DockTabComponents, dockViewsManager } from "./dock.views-manager";
|
||||||
import { MonacoEditor } from "../monaco-editor";
|
import { MonacoEditor } from "../monaco-editor";
|
||||||
|
import throttle from "lodash/throttle";
|
||||||
|
|
||||||
export interface DockTabContentProps extends React.HTMLAttributes<any> {
|
export interface DockTabContentProps extends React.HTMLAttributes<any> {
|
||||||
className?: string;
|
className?: string;
|
||||||
@ -36,12 +38,20 @@ export interface DockTabContentProps extends React.HTMLAttributes<any> {
|
|||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class DockTabContent extends React.Component<DockTabContentProps> {
|
export class DockTabContent extends React.Component<DockTabContentProps> {
|
||||||
|
@observable.ref editor: MonacoEditor;
|
||||||
|
|
||||||
constructor(props: DockTabContentProps) {
|
constructor(props: DockTabContentProps) {
|
||||||
super(props);
|
super(props);
|
||||||
makeObservable(this);
|
makeObservable(this);
|
||||||
|
|
||||||
disposeOnUnmount(this, [
|
disposeOnUnmount(this, [
|
||||||
reaction(() => this.tabId, () => this.error = ""), // reset
|
reaction(() => this.tabId, this.onTabChange, { delay: 100 }),
|
||||||
|
|
||||||
|
// keep focus on editor's area when <Dock/> 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<DockTabContentProps> {
|
|||||||
|
|
||||||
@observable error = "";
|
@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 <Dock/> is open/rendered).
|
* Always keep editor in DOM while (while <Dock/> is open/rendered).
|
||||||
* This allows to restore editor's model-view state (cursor pos, selection, etc.)
|
* This allows to restore editor's model-view state (cursor pos, selection, etc.)
|
||||||
@ -62,20 +88,21 @@ export class DockTabContent extends React.Component<DockTabContentProps> {
|
|||||||
*/
|
*/
|
||||||
renderEditor() {
|
renderEditor() {
|
||||||
const { tabId, tabComponents: { editor } } = this;
|
const { tabId, tabComponents: { editor } } = this;
|
||||||
const isHidden = !editor;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
id={tabId}
|
id={tabId}
|
||||||
className={cssNames({ hidden: isHidden })}
|
autoFocus={true}
|
||||||
|
className={cssNames({ hidden: !this.editorIsVisible })}
|
||||||
value={editor?.getValue(tabId) ?? ""}
|
value={editor?.getValue(tabId) ?? ""}
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
this.error = "";
|
this.error = "";
|
||||||
editor?.setValue(tabId, value);
|
editor?.setValue(tabId, value);
|
||||||
}}
|
}}
|
||||||
onError={error => {
|
onError={error => {
|
||||||
this.error = isHidden ? "" : error;
|
this.error = this.editorIsVisible ? error : "";
|
||||||
}}
|
}}
|
||||||
|
ref={editor => this.editor = editor}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -238,6 +238,10 @@ export class MonacoEditor extends React.Component<MonacoEditorProps> {
|
|||||||
return this.editor?.getValue(opts) ?? "";
|
return this.editor?.getValue(opts) ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
focus(){
|
||||||
|
this.editor?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
validate = async (value = this.getValue()): Promise<void> => {
|
validate = async (value = this.getValue()): Promise<void> => {
|
||||||
const { language } = this.props;
|
const { language } = this.props;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user