-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
codemirror.ts
58 lines (51 loc) · 1.45 KB
/
codemirror.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import type { Ref, WritableComputedRef } from 'vue'
import { onClickOutside } from '@vueuse/core'
import { watch } from 'vue'
import * as _CodeMirror from 'codemirror'
import 'codemirror/mode/javascript/javascript'
import 'codemirror/mode/css/css'
import 'codemirror/mode/markdown/markdown'
import 'codemirror/mode/xml/xml'
import 'codemirror/mode/htmlmixed/htmlmixed'
import 'codemirror/addon/display/placeholder'
import 'codemirror/lib/codemirror.css'
const CodeMirror = _CodeMirror.default ?? ('fromTextArea' in _CodeMirror ? _CodeMirror : globalThis.CodeMirror)
export async function useCodeMirror(
textarea: Ref<HTMLTextAreaElement | null | undefined>,
input: Ref<string> | WritableComputedRef<string>,
options: CodeMirror.EditorConfiguration = {},
) {
const cm = CodeMirror.fromTextArea(
textarea.value!,
{
theme: 'vars',
...options,
},
)
let skip = false
cm.on('change', () => {
if (skip) {
skip = false
return
}
input.value = cm.getValue()
})
watch(
input,
(v) => {
if (v !== cm.getValue()) {
skip = true
const selections = cm.listSelections()
cm.replaceRange(v, cm.posFromIndex(0), cm.posFromIndex(Number.POSITIVE_INFINITY))
cm.setSelections(selections)
}
},
{ immediate: true },
)
onClickOutside(cm.getWrapperElement(), () => {
const el = cm.getInputField()
if (document.activeElement === el)
el.blur()
})
return cm
}