You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
3.1 KiB
JavaScript

export class CodeEdit extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'})
this.shadowRoot.adoptedStyleSheets = [
this.constructor.styleSheet
]
}
connectedCallback() {
this.initEditor()
}
static get styleSheet() {
if (this._styleSheet === undefined) {
this._styleSheet = new CSSStyleSheet()
this._styleSheet.replaceSync(this.css)
}
return this._styleSheet
}
set value(value) {
if (this.view) {
this.view.dispatch({changes: {
from: 0,
to: this.view.state.doc.length,
insert: value
}})
} else {
this._value = value
}
}
get value() {
if (this.view) {
return this.view.state.doc.toString()
} else {
return this._value ?? ''
}
}
set fileType(value) {
this._fileType = value
if (this.view) {
const langPlugins = this.langPlugins
this.view.dispatch({
effects:
this.languageCompartment.reconfigure(langPlugins)
})
}
}
get fileType() {
return this._fileType
}
get langPlugins() {
const cm = window.CodeMirrorBasic
const langPlugins = []
if (['js', 'javascript'].includes(this.fileType)) {
langPlugins.push(cm.javascriptLanguage)
} else if (this.fileType === 'css') {
langPlugins.push(cm.cssLanguage)
} else if (this.fileType === 'html') {
langPlugins.push(cm.htmlLanguage)
} else if (this.fileType === 'json') {
langPlugins.push(cm.jsonLanguage)
}
return langPlugins
}
initEditor() {
const cm = window.CodeMirrorBasic
this.languageCompartment = new cm.Compartment()
const langPlugins = this.langPlugins
const basicSetup = [
cm.lineNumbers(),
cm.highlightActiveLineGutter(),
cm.highlightSpecialChars(),
cm.history(),
cm.foldGutter(),
cm.drawSelection(),
cm.dropCursor(),
cm.EditorState.allowMultipleSelections.of(true),
cm.indentOnInput(),
cm.syntaxHighlighting(
cm.defaultHighlightStyle, {fallback: true}
),
cm.bracketMatching(),
cm.closeBrackets(),
cm.autocompletion(),
cm.rectangularSelection(),
cm.crosshairCursor(),
cm.highlightActiveLine(),
cm.highlightSelectionMatches(),
cm.keymap.of([
...cm.closeBracketsKeymap,
...cm.defaultKeymap,
...cm.searchKeymap,
...cm.historyKeymap,
...cm.foldKeymap,
...cm.completionKeymap,
...cm.lintKeymap
]),
]
this.view = new cm.EditorView({
doc: this._value ?? '',
extensions: [
...basicSetup,
this.languageCompartment.of(langPlugins),
cm.EditorView.updateListener.of(e => {
this.dispatchEvent(new CustomEvent(
'code-input', {bubbles: true, composed: true}
))
}),
],
root: this.shadowRoot,
})
this.shadowRoot.append(this.view.dom)
}
static css = `
:host {
display: flex;
flex-direction: column;
align-items: stretch;
background-color: #fff;
}
:host > * {
flex-grow: 1;
}
`
}