obsidian-visualiser/components/Editor.vue

101 lines
3.2 KiB
Vue

<script lang="ts">
const External = Annotation.define<boolean>();
</script>
<script setup lang="ts">
import { dropCursor, crosshairCursor, keymap, EditorView, ViewUpdate, placeholder as placeholderExtension } from '@codemirror/view';
import { Annotation, EditorState } from '@codemirror/state';
import { indentOnInput, syntaxHighlighting, defaultHighlightStyle, bracketMatching, foldKeymap } from '@codemirror/language';
import { history, defaultKeymap, historyKeymap } from '@codemirror/commands';
import { search, searchKeymap } from '@codemirror/search';
import { closeBrackets, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete';
import { lintKeymap } from '@codemirror/lint';
const editor = useTemplateRef('editor');
const view = ref<EditorView>();
const state = ref<EditorState>();
const { placeholder } = defineProps<{
placeholder?: string
}>();
const model = defineModel<string>();
onMounted(() => {
if(editor.value)
{
state.value = EditorState.create({
doc: model.value,
extensions: [
history(),
search(),
dropCursor(),
EditorState.allowMultipleSelections.of(true),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
bracketMatching(),
closeBrackets(),
crosshairCursor(),
placeholderExtension(placeholder ?? ''),
EditorView.lineWrapping,
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...searchKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
...lintKeymap
]),
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
if (viewUpdate.docChanged && !viewUpdate.transactions.some(tr => tr.annotation(External)))
{
model.value = viewUpdate.state.doc.toString();
}
}),
EditorView.contentAttributes.of({spellcheck: "true"}),
]
});
view.value = new EditorView({
state: state.value,
parent: editor.value,
});
}
})
onBeforeUnmount(() => {
if (view.value) {
view.value?.destroy()
view.value = undefined
}
});
watchEffect(() => {
if (model.value === void 0) {
return;
}
const currentValue = view.value ? view.value.state.doc.toString() : "";
if (view.value && model.value !== currentValue) {
view.value.dispatch({
changes: { from: 0, to: currentValue.length, insert: model.value || "" },
annotations: [External.of(true)],
});
}
});
</script>
<template>
<div ref="editor" class="flex flex-1 w-full justify-stretch items-stretch border border-light-35 dark:border-dark-35 caret-light-100 dark:caret-dark-100 py-2 px-1.5 font-sans text-base" />
</template>
<style>
.cm-editor
{
@apply bg-transparent;
@apply flex-1;
}
.cm-editor .cm-content
{
@apply caret-light-100;
@apply dark:caret-dark-100;
}
</style>