diff --git a/docs/components/markdown-editor.md b/docs/components/markdown-editor.md index df35be28..4fd6f74f 100644 --- a/docs/components/markdown-editor.md +++ b/docs/components/markdown-editor.md @@ -7,6 +7,10 @@ const description1 = ref(null); const description2 = ref(null); const description3 = ref(null); +const description4 = ref("Hello, world! This is a **bold** statement."); + +const isDisabled = ref(false); + const onImageUpload = (file) => { return URL.createObjectURL(file).replace("blob:", ""); }; @@ -79,3 +83,34 @@ const description = ref(null) ``` + +## With default value + + + + +```vue + + + +``` + +## Disabled + + + + + +```vue + + + +``` diff --git a/lib/components/base/MarkdownEditor.vue b/lib/components/base/MarkdownEditor.vue index d8cec437..9fe93bd2 100644 --- a/lib/components/base/MarkdownEditor.vue +++ b/lib/components/base/MarkdownEditor.vue @@ -250,7 +250,7 @@ -
+
import { type Component, computed, ref, onMounted, onBeforeUnmount, toRef, watch } from 'vue' -import { EditorState } from '@codemirror/state' +import { Compartment, EditorState } from '@codemirror/state' import { EditorView, keymap, placeholder as cm_placeholder } from '@codemirror/view' import { markdown } from '@codemirror/lang-markdown' import { indentWithTab, historyKeymap, history } from '@codemirror/commands' @@ -327,6 +327,8 @@ const props = withDefaults( const editorRef = ref() let editor: EditorView | null = null +let isDisabledCompartment: Compartment | null = null +let editorThemeCompartment: Compartment | null = null const emit = defineEmits(['update:modelValue']) @@ -337,8 +339,10 @@ onMounted(() => { } }) + editorThemeCompartment = new Compartment() + const theme = EditorView.theme({ - // in defualts.scss there's references to .cm-content and such to inherit global styles + // in defaults.scss there's references to .cm-content and such to inherit global styles '.cm-content': { marginBlockEnd: '0.5rem', padding: '0.5rem', @@ -355,6 +359,10 @@ onMounted(() => { }, }) + isDisabledCompartment = new Compartment() + + const disabledCompartment = EditorState.readOnly.of(props.disabled) + const eventHandlers = EditorView.domEventHandlers({ paste: (ev, view) => { const { clipboardData } = ev @@ -425,7 +433,6 @@ onMounted(() => { const editorState = EditorState.create({ extensions: [ - theme, eventHandlers, updateListener, keymap.of([indentWithTab]), @@ -437,13 +444,24 @@ onMounted(() => { keymap.of(historyKeymap), cm_placeholder(props.placeholder || ''), inputFilter, + isDisabledCompartment.of(disabledCompartment), + editorThemeCompartment.of(theme), ], }) editor = new EditorView({ state: editorState, parent: editorRef.value, - doc: props.modelValue, + doc: props.modelValue ?? '', // This doesn't work for some reason + }) + + // set editor content to props.modelValue + editor?.dispatch({ + changes: { + from: 0, + to: editor.state.doc.length, + insert: props.modelValue, + }, }) }) @@ -541,18 +559,70 @@ const BUTTONS: ButtonGroupMap = { }, } +watch( + () => props.disabled, + (newValue) => { + if (editor) { + if (isDisabledCompartment) { + editor.dispatch({ + effects: [isDisabledCompartment.reconfigure(EditorState.readOnly.of(newValue))], + }) + } + + if (editorThemeCompartment) { + editor.dispatch({ + effects: [ + editorThemeCompartment.reconfigure( + EditorView.theme({ + // in defaults.scss there's references to .cm-content and such to inherit global styles + '.cm-content': { + marginBlockEnd: '0.5rem', + padding: '0.5rem', + minHeight: '200px', + caretColor: 'var(--color-contrast)', + width: '100%', + overflowX: 'scroll', + maxHeight: props.maxHeight ? `${props.maxHeight}px` : 'unset', + overflowY: 'scroll', + + opacity: newValue ? 0.6 : 1, + pointerEvents: newValue ? 'none' : 'all', + cursor: newValue ? 'not-allowed' : 'auto', + }, + '.cm-scroller': { + height: '100%', + overflow: 'visible', + }, + }) + ), + ], + }) + } + } + }, + { + immediate: true, + } +) + const currentValue = toRef(props, 'modelValue') -watch(currentValue, (newValue) => { - if (editor) { - editor.dispatch({ - changes: { - from: 0, - to: editor.state.doc.length, - insert: newValue, - }, - }) +watch( + currentValue, + (newValue) => { + if (editor && newValue !== editor.state.doc.toString()) { + editor.dispatch({ + changes: { + from: 0, + to: editor.state.doc.length, + insert: newValue, + }, + }) + } + }, + { + immediate: true, } -}) +) const updateCurrentValue = (newValue: string) => { emit('update:modelValue', newValue) @@ -873,4 +943,10 @@ function openVideoModal() { justify-content: start; } } + +.cm-disabled { + opacity: 0.6; + pointer-events: none; + cursor: not-allowed; +}