e-chan1007 / nuxt-monaco-editor

Integrate monaco-editor with Nuxt
https://e-chan1007.github.io/nuxt-monaco-editor
MIT License
119 stars 15 forks source link

fix: use `watch` for the target element #47

Closed L422Y closed 10 months ago

L422Y commented 10 months ago

Instead of onMounted we use a watch which guarantees the target element will be available for attaching the editor instance, also switch to onBeforeUnmount

Fixes https://github.com/e-chan1007/nuxt-monaco-editor/issues/46

andywillekens commented 10 months ago

I used this to fix my local enviorment by changing the MonacoEditor.client.vue with you're code. But i still got errors about the onBeforeMount not included and undefined useMonaco.

By adding back the import for useMonaco and the onBeforeMount @ "vue" it worked.

<template>
  <div v-show="!isLoading" ref="editorElement" class="editor"/>
</template>
<script lang="ts" setup>
import type * as Monaco from "monaco-editor"
import { computed, ref, shallowRef, watch, onBeforeUnmount } from "vue"
import { defu } from "defu"
import { useMonaco } from './composables'

interface Props {
  /**
   * Programming Language (Not a locale for UI);
   * overrides `options.language`
   */
  lang?: string;
  /**
   * Options passed to the second argument of `monaco.editor.create`
   */
  options?: Monaco.editor.IStandaloneEditorConstructionOptions;
  modelValue?: string;
}

interface Emits {
  (event: "update:modelValue", value: string): void

  (event: "load", editor: Monaco.editor.IStandaloneCodeEditor): void
}

const props = withDefaults(defineProps<Props>(), {
  lang: () => "plaintext",
  options: () => ( {} ),
  modelValue: () => ""
})

const emit = defineEmits<Emits>()
const isLoading = ref(true)
const lang = computed(() => props.lang || props.options.language)
const editorRef = shallowRef<Monaco.editor.IStandaloneCodeEditor>()
const editorElement = ref<HTMLDivElement>()
const monaco = useMonaco()!
const defaultOptions: Monaco.editor.IStandaloneEditorConstructionOptions = {
  automaticLayout: true
}

let editor: Monaco.editor.IStandaloneCodeEditor
let model: Monaco.editor.ITextModel

watch(() => props.modelValue, () => {
  if (editor?.getValue() !== props.modelValue) {
      editor?.setValue(props.modelValue)
  }
})

watch(() => props.lang, () => {
  if (model) {
      model.dispose()
  }
  model = monaco.editor.createModel(props.modelValue, lang.value)
  editor?.setModel(model)
})

watch(() => props.options, () => {
  editor?.updateOptions(defu(props.options, defaultOptions))
})

watch(editorElement, (newValue, oldValue) => {
  if (!editorElement.value || oldValue) return
  editor = monaco.editor.create(editorElement.value!, defu(props.options, defaultOptions))
  model = monaco.editor.createModel(props.modelValue, lang.value)
  editorRef.value = editor
  editor.layout()
  editor.setModel(model)
  editor.onDidChangeModelContent(() => {
      emit("update:modelValue", editor.getValue())
  })
  isLoading.value = false
  emit("load", editor)
})

defineExpose({
  /**
   * Monaco editor instance
   */
  $editor: editorRef
})

onBeforeUnmount(() => {
  editor?.dispose()
  model?.dispose()
})
</script>
e-chan1007 commented 10 months ago

Thanks for your pull request! Could you modify MonacoDiffEditor.client.vue in the same way and run ESLint for both files? Then I will be merge them soon.

L422Y commented 10 months ago

should be good to go, let me know if there's anything else