Created
June 6, 2024 02:35
-
-
Save besrabasant/961da9aeac439ba9dfe106bdb8c98c67 to your computer and use it in GitHub Desktop.
Monaco Editor Component in Vue3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script lang="ts" setup> | |
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; | |
import { computed, toRefs } from 'vue'; | |
// Define an interface for the props | |
interface Props { | |
diffEditor?: boolean; | |
width?: string | number; | |
height?: string | number; | |
original?: string; | |
value: string; | |
language?: string; | |
theme?: string; | |
options?: Record<string, unknown>; | |
} | |
type Emits = { | |
(event: 'editorWillMount', value: any): void; | |
(event: 'editorDidMount', value: any): void; | |
(event: 'change', value: any): void; | |
(event: 'update:value', value: string): void; | |
} | |
const props = withDefaults(defineProps<Props>(), { | |
diffEditor: false, | |
width: '100%', | |
height: '100%', | |
language: 'javascript', | |
theme: 'vs', | |
options: () => ({}) | |
}) | |
const emits = defineEmits<Emits>() | |
const { width, height, diffEditor } = toRefs(props) | |
const editor = ref() | |
const monacoEditorRef = ref() | |
const style = computed(() => { | |
const fixedWidth = width.value.toString().includes('%') | |
? width.value | |
: `${width.value}px` | |
const fixedHeight = height.value.toString().includes('%') | |
? height.value | |
: `${height.value}px` | |
return { | |
width: fixedWidth, | |
height: fixedHeight, | |
'text-align': 'left', | |
} | |
}) | |
const _setModel = (value:string, original: string) => { | |
const { language } = props | |
const originalModel = monaco.editor.createModel(original, language) | |
const modifiedModel = monaco.editor.createModel(value, language) | |
editor.value.setModel({ | |
original: originalModel, | |
modified: modifiedModel, | |
}) | |
} | |
const _setValue = (value: string) => { | |
let editor = _getEditor() | |
if (editor) return editor.setValue(value) | |
} | |
const _getValue = () => { | |
let editor = _getEditor() | |
if (!editor) { | |
return '' | |
} | |
return editor.getValue() | |
} | |
const _getEditor = () => { | |
if (!editor.value) { | |
return null | |
} | |
return diffEditor.value ? editor.value.modifiedEditor : editor.value | |
} | |
const _setOriginal = () => { | |
const { original } = editor.value.getModel() | |
original.setValue(original) | |
} | |
const initMonaco = () => { | |
emits('editorWillMount', monaco) | |
const { value, language, theme, options } = props | |
editor.value = monaco.editor[ | |
diffEditor ? 'createDiffEditor' : 'create' | |
](monacoEditorRef.value, { | |
value: props.value, | |
language: language, | |
theme: theme, | |
...options, | |
}) | |
diffEditor.value && _setModel(value, props.original) | |
// @event `change` | |
const editorInstance = _getEditor() | |
editorInstance && | |
editorInstance.onDidChangeModelContent((event) => { | |
const value = editorInstance.getValue() | |
if (value !== value) { | |
emits('change', value, event) | |
emits('update:value', value) | |
} | |
}) | |
emits('editorDidMount', editorInstance) | |
} | |
watch(() => props.options, (options) => { | |
editor.value?.updateOptions(options); | |
}, { deep: true }); | |
watch(() => props.value, (newValue, oldValue) => { | |
if (newValue !== oldValue) { | |
// Assuming _setValue and _getValue methods are correctly defined or imported | |
if (newValue !== _getValue()) { | |
_setValue(newValue); | |
} | |
} | |
}); | |
// Watcher for 'original' | |
watch(() => props.original, () => { | |
// Assuming _setOriginal is a method defined within your component | |
_setOriginal(); | |
}); | |
watch(() => props.language, (newLang) => { | |
if (!editor.value) return; | |
if (props.diffEditor && editor.value.getModel) { | |
const { original: originalModel, modified } = editor.value.getModel(); | |
monaco.editor.setModelLanguage(originalModel, newLang); | |
monaco.editor.setModelLanguage(modified, newLang); | |
} else { | |
monaco.editor.setModelLanguage(editor.value.getModel(), newLang); | |
} | |
}); | |
watch(() => props.theme, (newTheme) => { | |
monaco.editor.setTheme(newTheme); | |
}); | |
onMounted(async () => { | |
initMonaco() | |
}) | |
onBeforeUnmount(() { | |
editor.value && editor.value.dispose() | |
}) | |
</script> | |
<template> | |
<div ref="monaco-editor-ref" class="monaco-editor-vue3" :style="style"></div> | |
</template> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment