Skip to content

Commit

Permalink
Implementation monaco editor component
Browse files Browse the repository at this point in the history
  • Loading branch information
jianyi-gronk committed Jan 29, 2024
1 parent 9e686b4 commit 9a1e9fc
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
63 changes: 63 additions & 0 deletions ui-vue3/src/components/editor/MonacoEditor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as monaco from 'monaco-editor'

export default function useMonaco(language = 'json') {
let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null
let initReadOnly = false

const updateVal = async (val: string) => {
monacoEditor?.setValue(val)
setTimeout(async () => {
initReadOnly && monacoEditor?.updateOptions({ readOnly: false })
await monacoEditor?.getAction('editor.action.formatDocument')?.run()
initReadOnly && monacoEditor?.updateOptions({ readOnly: true })
}, 100)
}

const createEditor = (
el: HTMLElement | null,
editorOption: monaco.editor.IStandaloneEditorConstructionOptions = {}
) => {
if (monacoEditor) {
return
}
initReadOnly = !!editorOption.readOnly
monacoEditor =
el &&
monaco.editor.create(el, {
language,
minimap: { enabled: false },
theme: 'vs-light',
multiCursorModifier: 'ctrlCmd',
tabSize: 2,
automaticLayout: true, // 自适应宽高
...editorOption
})
return monacoEditor
}
const onFormatDoc = () => {
monacoEditor?.getAction('editor.action.formatDocument')?.run()
}
return {
updateVal,
getEditor: () => monacoEditor,
createEditor,
onFormatDoc
}
}
102 changes: 102 additions & 0 deletions ui-vue3/src/components/editor/MonacoEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<template>
<div
:id="editorId"
:style="{
width: typeof width === 'number' ? width + 'px' : width,
height: typeof height === 'number' ? height + 'px' : height
}"
></div>
</template>

<script lang="ts" setup>
import { defineEmits, onMounted, watch } from 'vue'
import useMonaco from './MonacoEditor'
const emit = defineEmits(['update:modelValue', 'blur'])
const props = defineProps({
modelValue: {
type: String,
default: ''
},
width: {
type: [String, Number],
default: '100%'
},
height: {
type: [String, Number],
default: '100%'
},
theme: {
type: String,
default: 'vs-light'
},
language: {
type: String,
default: 'json'
},
editorId: {
type: String,
default: 'editor'
},
editorOptions: {
type: Object,
default: () => ({})
},
readonly: {
type: Boolean,
default: false
}
})
const { createEditor, updateVal, getEditor, onFormatDoc } = useMonaco(props.language)
const updateMonacoVal = (_val?: string) => {
const val = _val || props.modelValue
updateVal(val)
}
watch(
() => props.modelValue,
(val) => {
val !== getEditor()?.getValue() && updateMonacoVal(val)
}
)
onMounted(() => {
const editor = createEditor(document.querySelector(`#${props.editorId}`), {
theme: props.theme,
readOnly: props.readonly,
...props.editorOptions
})
updateMonacoVal()
if (editor) {
editor.onDidChangeModelContent(() => {
emit('update:modelValue', editor.getValue())
})
editor.onDidBlurEditorText(() => {
emit('blur')
})
}
})
defineExpose({
onFormatDoc
})
</script>
24 changes: 24 additions & 0 deletions ui-vue3/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ import Vue3ColorPicker from 'vue3-colorpicker'
import 'vue3-colorpicker/style.css'
import 'nprogress/nprogress.css'

import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'

self.MonacoEnvironment = {
getWorker(_, label) {
if (label === 'json') {
return new jsonWorker()
}
if (label === 'css' || label === 'scss' || label === 'less') {
return new cssWorker()
}
if (label === 'html' || label === 'handlebars' || label === 'razor') {
return new htmlWorker()
}
if (label === 'typescript' || label === 'javascript') {
return new tsWorker()
}
return new editorWorker()
}
}

const app = createApp(App)

app.use(Antd).use(Vue3ColorPicker).use(i18n).use(router).mount('#app')

0 comments on commit 9a1e9fc

Please sign in to comment.