UNPKG

@limetech/lime-elements

Version:
341 lines (340 loc) • 9.14 kB
import { h, } from '@stencil/core'; import CodeMirror from 'codemirror'; import 'codemirror/mode/javascript/javascript'; import 'codemirror/mode/jinja2/jinja2'; import 'codemirror/addon/selection/active-line'; import 'codemirror/addon/edit/matchbrackets'; import 'codemirror/addon/lint/lint'; import 'codemirror/addon/lint/json-lint'; import 'codemirror/addon/fold/foldgutter'; import 'codemirror/addon/fold/brace-fold'; import jslint from 'jsonlint-mod'; /** * @exampleComponent limel-example-code-editor * @exampleComponent limel-example-code-editor-readonly-with-line-numbers * @exampleComponent limel-example-code-editor-fold-lint */ export class CodeEditor { constructor() { this.handleChangeDarkMode = () => { if (this.colorScheme !== 'auto') { return; } this.forceRedraw(); }; this.handleChange = () => { this.change.emit(this.editor.getValue()); }; this.handleResize = () => { if (!this.editor) { return; } this.editor.refresh(); }; this.value = ''; this.language = undefined; this.readonly = false; this.lineNumbers = false; this.fold = false; this.lint = false; this.colorScheme = 'auto'; this.random = undefined; } connectedCallback() { this.observer = new ResizeObserver(this.handleResize); this.observer.observe(this.host); this.darkMode.addEventListener('change', this.handleChangeDarkMode); } disconnectedCallback() { var _a; this.observer.unobserve(this.host); (_a = this.editor) === null || _a === void 0 ? void 0 : _a.off('change', this.handleChange); this.editor = null; this.darkMode.removeEventListener('change', this.handleChangeDarkMode); const editorElement = this.host.shadowRoot.querySelector('.editor'); // eslint-disable-next-line no-unsafe-optional-chaining for (const child of editorElement === null || editorElement === void 0 ? void 0 : editorElement.childNodes) { child.remove(); } } componentDidRender() { if (this.editor) { return; } this.editor = this.createEditor(); } watchValue(newValue) { if (!this.editor) { return; } const currentValue = this.editor.getValue(); if (newValue === currentValue) { // Circuit breaker for when the change comes from the editor itself // The caret position will be reset without this return; } this.editor.getDoc().setValue(newValue || ''); } createEditor() { const options = this.getOptions(); const editor = CodeMirror(this.host.shadowRoot.querySelector('.editor'), options); editor.on('change', this.handleChange); // Replace tab with spaces and use the actual indent setting for // the space count editor.setOption('extraKeys', { Tab: (codeMirror) => { const spaces = [codeMirror.getOption('indentUnit') + 1].join(' '); codeMirror.replaceSelection(spaces); }, }); return editor; } getOptions() { let mode = this.language; const TAB_SIZE = 4; let theme = 'lime light'; const gutters = []; if (this.isDarkMode()) { theme = 'lime dark'; } if (this.language === 'json') { mode = { name: 'application/json', json: true, }; if (this.lint) { gutters.push('CodeMirror-lint-markers'); if (!('jsonlint' in window)) { window['jsonlint'] = jslint; } } } else if (this.language === 'typescript') { mode = { name: 'application/typescript', typescript: true, }; } if (this.fold) { gutters.push('CodeMirror-foldgutter'); } return { mode: mode, value: this.value || '', theme: theme, readOnly: this.readonly, tabSize: TAB_SIZE, indentUnit: TAB_SIZE, lineNumbers: this.lineNumbers, styleActiveLine: true, matchBrackets: true, lint: this.lint, foldGutter: this.fold, gutters: gutters, }; } isDarkMode() { if (this.colorScheme !== 'auto') { return this.colorScheme === 'dark'; } return this.darkMode.matches; } render() { const classList = { editor: true, readonly: this.readonly, 'is-dark-mode': this.isDarkMode(), 'is-light-mode': !this.isDarkMode(), }; return h("div", { class: classList }); } forceRedraw() { // eslint-disable-next-line sonarjs/pseudo-random this.random = Math.random(); } get darkMode() { return matchMedia('(prefers-color-scheme: dark)'); } static get is() { return "limel-code-editor"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["code-editor.scss"] }; } static get styleUrls() { return { "$": ["code-editor.css"] }; } static get properties() { return { "value": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The code to be rendered" }, "attribute": "value", "reflect": false, "defaultValue": "''" }, "language": { "type": "string", "mutable": false, "complexType": { "original": "Language", "resolved": "\"javascript\" | \"jinja2\" | \"json\" | \"typescript\"", "references": { "Language": { "location": "import", "path": "./code-editor.types" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "The language of the code" }, "attribute": "language", "reflect": false }, "readonly": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Disables editing of the editor content" }, "attribute": "readonly", "reflect": false, "defaultValue": "false" }, "lineNumbers": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Displays line numbers in the editor" }, "attribute": "line-numbers", "reflect": false, "defaultValue": "false" }, "fold": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Allows the user to fold code" }, "attribute": "fold", "reflect": false, "defaultValue": "false" }, "lint": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Enables linting of JSON content" }, "attribute": "lint", "reflect": false, "defaultValue": "false" }, "colorScheme": { "type": "string", "mutable": false, "complexType": { "original": "ColorScheme", "resolved": "\"auto\" | \"dark\" | \"light\"", "references": { "ColorScheme": { "location": "import", "path": "./code-editor.types" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Select color scheme for the editor" }, "attribute": "color-scheme", "reflect": false, "defaultValue": "'auto'" } }; } static get states() { return { "random": {} }; } static get events() { return [{ "method": "change", "name": "change", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the code has changed. Will only be emitted when the code\narea has lost focus" }, "complexType": { "original": "string", "resolved": "string", "references": {} } }]; } static get elementRef() { return "host"; } static get watchers() { return [{ "propName": "value", "methodName": "watchValue" }]; } } //# sourceMappingURL=code-editor.js.map