diff --git a/docs/components/markdown-editor.md b/docs/components/markdown-editor.md index 8d3ad813c..a0f96cb88 100644 --- a/docs/components/markdown-editor.md +++ b/docs/components/markdown-editor.md @@ -3,6 +3,7 @@ import { ref } from "vue"; const description = ref(null); +const description1 = ref(null); const description2 = ref(null); const description3 = ref(null); @@ -27,6 +28,20 @@ const description = ref(null) ``` +## With options + + + + +```vue + + + +``` + ## With image upload @@ -41,6 +56,9 @@ const description = ref(null) const onImageUpload = (file: File): string => { // Upload the file to your server and return a URL // This example url will not work bc of proxy + + // If the upload fails, throw an error and it will show as + // a Validation Error to the user return URL.createObjectURL(file).replace("blob:", ""); }; diff --git a/lib/assets/styles/classes.scss b/lib/assets/styles/classes.scss index e6643be77..bbce8abf0 100644 --- a/lib/assets/styles/classes.scss +++ b/lib/assets/styles/classes.scss @@ -70,8 +70,6 @@ :where(input) { box-sizing: border-box; max-height: 40px; - width: 24rem; - flex-basis: 24rem; &:not(.stylized-toggle) { max-width: 100%; diff --git a/lib/components/base/MarkdownEditor.vue b/lib/components/base/MarkdownEditor.vue index 6f18f8b44..3c8042427 100644 --- a/lib/components/base/MarkdownEditor.vue +++ b/lib/components/base/MarkdownEditor.vue @@ -223,11 +223,19 @@
- - - This editor supports - Markdown formatting. - +
+ + This editor supports + Markdown formatting. +
+
+ Max length: + {{ props.maxLength ?? 'Unlimited' }} +
Promise + placeholder?: string + maxLength?: number }>(), { modelValue: '', disabled: false, headingButtons: true, onImageUpload: undefined, + placeholder: undefined, + maxLength: undefined, } ) @@ -321,7 +338,6 @@ onMounted(() => { paste: (ev, view) => { // If the user's pasting a url, automatically convert it to a link with the selection as the text or the url itself if no selection content. const url = ev.clipboardData?.getData('text/plain') - if (url) { try { cleanUrl(url) @@ -337,6 +353,35 @@ onMounted(() => { const linkMarkdown = `[${linkText}](${url})` return markdownCommands.replaceSelection(view, linkMarkdown) } + // Check if the length of the document is greater than the max length. If it is, prevent the paste. + if (props.maxLength && view.state.doc.length > props.maxLength) { + ev.preventDefault() + return false + } + }, + beforeinput: (ev, view) => { + if (props.maxLength && view.state.doc.length > props.maxLength) { + ev.preventDefault() + // Calculate how many characters to remove from the end + const excessLength = view.state.doc.length - props.maxLength + // Dispatch transaction to remove excess characters + view.dispatch({ + changes: { from: view.state.doc.length - excessLength, to: view.state.doc.length }, + selection: { anchor: props.maxLength, head: props.maxLength }, // Place cursor at the end + }) + return true + } + }, + blur: (_, view) => { + if (props.maxLength && view.state.doc.length > props.maxLength) { + // Calculate how many characters to remove from the end + const excessLength = view.state.doc.length - props.maxLength + // Dispatch transaction to remove excess characters + view.dispatch({ + changes: { from: view.state.doc.length - excessLength, to: view.state.doc.length }, + selection: { anchor: props.maxLength, head: props.maxLength }, // Place cursor at the end + }) + } }, }) @@ -353,6 +398,7 @@ onMounted(() => { addKeymap: false, }), keymap.of(historyKeymap), + cm_placeholder(props.placeholder || ''), ], }) @@ -532,6 +578,9 @@ const handleImageUpload = async (files: FileList) => { linkUrl.value = url validateURL() } catch (error) { + if (error instanceof Error) { + linkValidationErrorMessage.value = error.message + } console.error(error) } } @@ -577,7 +626,7 @@ function openVideoModal() { } -