UtilCodeEditor.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <template lang="pug">
  2. .util-code-editor(
  3. ref='editorRef'
  4. )
  5. </template>
  6. <script setup>
  7. /* eslint no-unused-vars: "off" */
  8. import { keymap, EditorView, lineNumbers } from '@codemirror/view'
  9. import { EditorState } from '@codemirror/state'
  10. import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands'
  11. import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language'
  12. import { ref, shallowRef, onBeforeMount, onMounted, watch } from 'vue'
  13. // PROPS
  14. const props = defineProps({
  15. modelValue: {
  16. type: String,
  17. default: ''
  18. },
  19. language: {
  20. type: String,
  21. default: 'plaintext'
  22. },
  23. minHeight: {
  24. type: Number,
  25. default: 150
  26. }
  27. })
  28. // EMITS
  29. const emit = defineEmits([
  30. 'update:modelValue'
  31. ])
  32. // STATE
  33. const editor = shallowRef(null)
  34. const editorRef = ref(null)
  35. // WATCHERS
  36. watch(() => props.modelValue, (newVal) => {
  37. // Ignore loopback changes while editing
  38. if (!editor.value.hasFocus) {
  39. editor.value.dispatch({
  40. changes: { from: 0, to: editor.value.state.length, insert: newVal }
  41. })
  42. }
  43. })
  44. // MOUNTED
  45. onMounted(async () => {
  46. let langModule = null
  47. switch (props.language) {
  48. case 'css': {
  49. langModule = (await import('@codemirror/lang-css')).css
  50. break
  51. }
  52. case 'html': {
  53. langModule = (await import('@codemirror/lang-html')).html
  54. break
  55. }
  56. case 'javascript': {
  57. langModule = (await import('@codemirror/lang-javascript')).javascript
  58. break
  59. }
  60. case 'json': {
  61. langModule = (await import('@codemirror/lang-json')).json
  62. break
  63. }
  64. case 'markdown': {
  65. langModule = (await import('@codemirror/lang-markdown')).markdown
  66. break
  67. }
  68. }
  69. editor.value = new EditorView({
  70. state: EditorState.create({
  71. doc: props.modelValue,
  72. extensions: [
  73. history(),
  74. keymap.of([...defaultKeymap, ...historyKeymap, indentWithTab]),
  75. lineNumbers(),
  76. EditorView.theme({
  77. '.cm-content, .cm-gutter': { minHeight: `${props.minHeight}px` }
  78. }),
  79. ...langModule && [langModule()],
  80. syntaxHighlighting(defaultHighlightStyle),
  81. EditorView.updateListener.of(v => {
  82. if (v.docChanged) {
  83. emit('update:modelValue', v.state.doc.toString())
  84. }
  85. })
  86. ]
  87. }),
  88. parent: editorRef.value
  89. })
  90. })
  91. onBeforeMount(() => {
  92. if (editor.value) {
  93. editor.value.destroy()
  94. }
  95. })
  96. </script>
  97. <style lang="scss">
  98. .util-code-editor {
  99. min-height: 100px;
  100. border: 1px solid #CCC;
  101. border-radius: 5px;
  102. overflow: hidden;
  103. > .CodeMirror {
  104. height: 150px;
  105. }
  106. }
  107. </style>