Skip to content

Instantly share code, notes, and snippets.

@besrabasant
Created June 6, 2024 02:35
Show Gist options
  • Save besrabasant/961da9aeac439ba9dfe106bdb8c98c67 to your computer and use it in GitHub Desktop.
Save besrabasant/961da9aeac439ba9dfe106bdb8c98c67 to your computer and use it in GitHub Desktop.
Monaco Editor Component in Vue3
<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