vitest/packages/ui/client/components/CodeMirrorContainer.vue

78 lines
2.1 KiB
Vue

<script setup lang="ts">
import type { EditorFromTextArea } from 'codemirror'
import type { Ref } from 'vue'
import { onMounted, ref, useAttrs } from 'vue'
import { codemirrorRef, useCodeMirror } from '~/composables/codemirror'
const { mode, readOnly } = defineProps<{
mode?: string
readOnly?: boolean
saving?: boolean
}>()
const emit = defineEmits<{
(event: 'save', content: string): void
(event: 'codemirror', codemirror: EditorFromTextArea): void
}>()
const modelValue = defineModel<string>()
const attrs = useAttrs()
const modeMap: Record<string, any> = {
html: 'htmlmixed',
vue: 'htmlmixed',
svelte: 'htmlmixed',
js: 'javascript',
mjs: 'javascript',
cjs: 'javascript',
ts: { name: 'javascript', typescript: true },
mts: { name: 'javascript', typescript: true },
cts: { name: 'javascript', typescript: true },
jsx: { name: 'javascript', jsx: true },
tsx: { name: 'javascript', typescript: true, jsx: true },
}
const el = ref<HTMLTextAreaElement>()
onMounted(async () => {
// useCodeMirror will remove the codemirrorRef.value on onUnmounted callback
const codemirror = useCodeMirror(el, modelValue as unknown as Ref<string>, {
...attrs,
mode: modeMap[mode || ''] || mode,
readOnly: readOnly ? true : undefined,
extraKeys: {
'Cmd-S': function (cm) {
const isReadonly = cm.getOption('readOnly')
if (!isReadonly) {
emit('save', cm.getValue())
}
},
'Ctrl-S': function (cm) {
const isReadonly = cm.getOption('readOnly')
if (!isReadonly) {
emit('save', cm.getValue())
}
},
},
})
codemirror.on('refresh', () => {
emit('codemirror', codemirror)
})
codemirror.on('change', () => {
emit('codemirror', codemirror)
})
codemirror.setSize('100%', '100%')
codemirror.clearHistory()
codemirrorRef.value = codemirror
setTimeout(() => codemirrorRef.value?.refresh(), 100)
})
</script>
<template>
<div relative font-mono text-sm class="codemirror-scrolls" :class="saving ? 'codemirror-busy' : undefined">
<textarea ref="el" />
</div>
</template>