1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00
lens/dashboard/client/components/ace-editor/ace-editor.tsx
Jari Kolehmainen db4dca3005 lens app source code
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
2020-03-15 09:46:21 +02:00

190 lines
4.3 KiB
TypeScript

// Ace code editor - https://ace.c9.io
// Playground - https://ace.c9.io/build/kitchen-sink.html
import "./ace-editor.scss"
import * as React from "react"
import { observable } from "mobx";
import { observer } from "mobx-react";
import { Ace } from "ace-builds"
import { autobind, cssNames } from "../../utils";
import { Spinner } from "../spinner";
import { themeStore } from "../../theme.store";
interface Props extends Partial<Ace.EditorOptions> {
className?: string;
autoFocus?: boolean;
hidden?: boolean;
cursorPos?: Ace.Point;
onChange?(value: string, delta: Ace.Delta): void;
onCursorPosChange?(point: Ace.Point): void;
}
interface State {
ready?: boolean;
}
const defaultProps: Partial<Props> = {
value: "",
mode: "yaml",
tabSize: 2,
showGutter: true, // line-numbers
foldStyle: "manual",
printMargin: false,
useWorker: false,
};
@observer
export class AceEditor extends React.Component<Props, State> {
static defaultProps = defaultProps as object;
private editor: Ace.Editor;
private elem: HTMLElement;
@observable ready = false;
async loadEditor() {
return await import(
/* webpackChunkName: "ace" */
"ace-builds"
);
}
loadTheme(theme: string) {
return import(
/* webpackChunkName: "ace/[request]" */
`ace-builds/src-min-noconflict/theme-${theme}`
);
}
loadExtension(ext: string) {
return import(
/* webpackChunkName: "ace/[request]" */
`ace-builds/src-min-noconflict/ext-${ext}`
);
}
loadMode(mode: string) {
return import(
/* webpackChunkName: "ace/[request]" */
`ace-builds/src-min-noconflict/mode-${mode}`
)
}
get theme() {
return themeStore.activeTheme.type == "light"
? "dreamweaver" : "terminal";
}
async componentDidMount() {
const {
mode, autoFocus, className, hidden, cursorPos,
onChange, onCursorPosChange, children,
...options
} = this.props;
// load ace-editor, theme and mode
const ace = await this.loadEditor();
await Promise.all([
this.loadTheme(this.theme),
this.loadMode(mode)
]);
// setup editor
this.editor = ace.edit(this.elem, options);
this.setTheme(this.theme);
this.setMode(mode);
this.setCursorPos(cursorPos);
// bind events
this.editor.on("change", this.onChange);
this.editor.selection.on("changeCursor", this.onCursorPosChange);
// load extensions
this.loadExtension("searchbox");
if (autoFocus) this.focus();
this.ready = true;
}
componentDidUpdate() {
if (!this.editor) return;
const { value, cursorPos } = this.props;
if (value !== this.getValue()) {
this.editor.setValue(value);
this.editor.clearSelection();
this.setCursorPos(cursorPos || this.editor.getCursorPosition());
}
}
componentWillUnmount() {
if (this.editor) {
this.editor.destroy();
}
}
resize() {
if (this.editor) {
this.editor.resize();
}
}
focus() {
if (this.editor) {
this.editor.focus();
}
}
getValue() {
return this.editor.getValue()
}
setValue(value: string, cursorPos?: number) {
return this.editor.setValue(value, cursorPos);
}
async setMode(mode: string) {
await this.loadMode(mode);
this.editor.session.setMode(`ace/mode/${mode}`);
}
async setTheme(theme: string) {
await this.loadTheme(theme);
this.editor.setTheme(`ace/theme/${theme}`);
}
setCursorPos(pos: Ace.Point) {
if (!pos) return;
const { row, column } = pos;
this.editor.moveCursorToPosition(pos);
requestAnimationFrame(() => {
this.editor.gotoLine(row + 1, column, false);
});
}
@autobind()
onCursorPosChange() {
const { onCursorPosChange } = this.props;
if (onCursorPosChange) {
onCursorPosChange(this.editor.getCursorPosition());
}
}
@autobind()
onChange(delta: Ace.Delta) {
const { onChange } = this.props;
if (onChange) {
onChange(this.getValue(), delta);
}
}
render() {
const { className, hidden } = this.props;
const themeType = themeStore.activeTheme.type;
return (
<div className={cssNames("AceEditor", className, { hidden }, themeType)}>
<div className="editor" ref={e => this.elem = e}/>
{!this.ready && <Spinner center/>}
</div>
)
}
}