@limetech/lime-elements
Version:
341 lines (340 loc) • 9.14 kB
JavaScript
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