mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.0 KiB
132 lines
4.0 KiB
import { target, targetable } from '@github/catalyst/lib/targetable'
|
|
|
|
let loaderPromise = null
|
|
|
|
function loadCodeMirror () {
|
|
if (!loaderPromise) {
|
|
loaderPromise = Promise.all([
|
|
import(/* webpackChunkName: "email-editor" */ '@codemirror/view'),
|
|
import(/* webpackChunkName: "email-editor" */ '@codemirror/commands'),
|
|
import(/* webpackChunkName: "email-editor" */ '@codemirror/language'),
|
|
import(/* webpackChunkName: "email-editor" */ '@codemirror/lang-html'),
|
|
import(/* webpackChunkName: "email-editor" */ '@specious/htmlflow')
|
|
]).then(([view, commands, language, html, htmlflow]) => {
|
|
return {
|
|
minimalSetup: [
|
|
commands.history(),
|
|
language.syntaxHighlighting(language.defaultHighlightStyle, { fallback: true }),
|
|
view.keymap.of([...commands.defaultKeymap, ...commands.historyKeymap])
|
|
],
|
|
EditorView: view.EditorView,
|
|
html: html.html,
|
|
htmlflow: htmlflow.default || htmlflow
|
|
}
|
|
})
|
|
}
|
|
|
|
return loaderPromise
|
|
}
|
|
|
|
export default targetable(class extends HTMLElement {
|
|
static [target.static] = [
|
|
'codeViewTab',
|
|
'previewViewTab',
|
|
'editorContainer',
|
|
'previewIframe'
|
|
]
|
|
|
|
connectedCallback () {
|
|
this.mount()
|
|
|
|
if (this.input.value) {
|
|
this.showPreviewView()
|
|
} else {
|
|
this.showCodeView()
|
|
}
|
|
|
|
this.previewViewTab.addEventListener('click', this.showPreviewView)
|
|
this.codeViewTab.addEventListener('click', this.showCodeView)
|
|
}
|
|
|
|
showCodeView = () => {
|
|
this.editorView.dispatch({
|
|
changes: { from: 0, to: this.editorView.state.doc.length, insert: this.input.value }
|
|
})
|
|
|
|
this.previewViewTab.classList.remove('tab-active', 'tab-bordered')
|
|
this.previewViewTab.classList.add('pb-[3px]')
|
|
this.codeViewTab.classList.remove('pb-[3px]')
|
|
this.codeViewTab.classList.add('tab-active', 'tab-bordered')
|
|
this.editorContainer.classList.remove('hidden')
|
|
this.previewIframe.classList.add('hidden')
|
|
}
|
|
|
|
showPreviewView = () => {
|
|
this.previewIframe.srcdoc = this.input.value
|
|
|
|
this.codeViewTab.classList.remove('tab-active', 'tab-bordered')
|
|
this.codeViewTab.classList.add('pb-[3px]')
|
|
this.previewViewTab.classList.remove('pb-[3px]')
|
|
this.previewViewTab.classList.add('tab-active', 'tab-bordered')
|
|
this.editorContainer.classList.add('hidden')
|
|
this.previewIframe.classList.remove('hidden')
|
|
}
|
|
|
|
async mount () {
|
|
this.input = this.querySelector('input[type="hidden"]')
|
|
this.input.style.display = 'none'
|
|
|
|
const { EditorView, minimalSetup, html, htmlflow } = await loadCodeMirror()
|
|
|
|
this.editorView = new EditorView({
|
|
doc: this.input.value,
|
|
parent: this.editorContainer,
|
|
extensions: [
|
|
html(),
|
|
minimalSetup,
|
|
EditorView.lineWrapping,
|
|
EditorView.updateListener.of(update => {
|
|
if (update.docChanged) this.input.value = update.state.doc.toString()
|
|
}),
|
|
EditorView.theme({
|
|
'&': {
|
|
backgroundColor: 'white',
|
|
color: 'black',
|
|
fontSize: '14px',
|
|
fontFamily: 'monospace'
|
|
},
|
|
'&.cm-focused': {
|
|
outline: 'none'
|
|
},
|
|
'&.cm-editor': {
|
|
borderRadius: '0.375rem',
|
|
border: 'none'
|
|
},
|
|
'.cm-gutters': {
|
|
display: 'none'
|
|
}
|
|
})
|
|
]
|
|
})
|
|
|
|
this.previewIframe.srcdoc = this.editorView.state.doc.toString()
|
|
|
|
this.previewIframe.onload = () => {
|
|
const previewIframeDoc = this.previewIframe.contentDocument
|
|
|
|
if (previewIframeDoc.body) {
|
|
previewIframeDoc.body.contentEditable = true
|
|
}
|
|
|
|
const contentDocument = this.previewIframe.contentDocument || this.previewIframe.contentWindow.document
|
|
|
|
contentDocument.body.addEventListener('input', async () => {
|
|
const html = contentDocument.documentElement.outerHTML.replace(' contenteditable="true"', '')
|
|
const prettifiedHtml = await htmlflow(html)
|
|
|
|
this.input.value = prettifiedHtml
|
|
})
|
|
}
|
|
}
|
|
})
|