Improve TextEditor
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
ff1fbdfdba
commit
e22cb8c3bd
@ -13,7 +13,7 @@
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('bold') }"
|
:class="{ 'is-active': editor?.isActive('bold') }"
|
||||||
@click="editor?.chain().focus().toggleBold().run()"
|
@click="editor?.chain().focus().toggleBold().run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Bold')"
|
:title="t('Bold')"
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('italic') }"
|
:class="{ 'is-active': editor?.isActive('italic') }"
|
||||||
@click="editor?.chain().focus().toggleItalic().run()"
|
@click="editor?.chain().focus().toggleItalic().run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Italic')"
|
:title="t('Italic')"
|
||||||
@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('underline') }"
|
:class="{ 'is-active': editor?.isActive('underline') }"
|
||||||
@click="editor?.chain().focus().toggleUnderline().run()"
|
@click="editor?.chain().focus().toggleUnderline().run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Underline')"
|
:title="t('Underline')"
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<button
|
<button
|
||||||
v-if="!isBasicMode"
|
v-if="!isBasicMode"
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
|
:class="{ 'is-active': editor?.isActive('heading', { level: 1 }) }"
|
||||||
@click="editor?.chain().focus().toggleHeading({ level: 1 }).run()"
|
@click="editor?.chain().focus().toggleHeading({ level: 1 }).run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Heading Level 1')"
|
:title="t('Heading Level 1')"
|
||||||
@ -55,7 +55,7 @@
|
|||||||
<button
|
<button
|
||||||
v-if="!isBasicMode"
|
v-if="!isBasicMode"
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
|
:class="{ 'is-active': editor?.isActive('heading', { level: 2 }) }"
|
||||||
@click="editor?.chain().focus().toggleHeading({ level: 2 }).run()"
|
@click="editor?.chain().focus().toggleHeading({ level: 2 }).run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Heading Level 2')"
|
:title="t('Heading Level 2')"
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<button
|
<button
|
||||||
v-if="!isBasicMode"
|
v-if="!isBasicMode"
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('heading', { level: 3 }) }"
|
:class="{ 'is-active': editor?.isActive('heading', { level: 3 }) }"
|
||||||
@click="editor?.chain().focus().toggleHeading({ level: 3 }).run()"
|
@click="editor?.chain().focus().toggleHeading({ level: 3 }).run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Heading Level 3')"
|
:title="t('Heading Level 3')"
|
||||||
@ -77,7 +77,7 @@
|
|||||||
<button
|
<button
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
@click="showLinkMenu()"
|
@click="showLinkMenu()"
|
||||||
:class="{ 'is-active': editor.isActive('link') }"
|
:class="{ 'is-active': editor?.isActive('link') }"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Add link')"
|
:title="t('Add link')"
|
||||||
>
|
>
|
||||||
@ -85,7 +85,7 @@
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="editor.isActive('link')"
|
v-if="editor?.isActive('link')"
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
@click="editor?.chain().focus().unsetLink().run()"
|
@click="editor?.chain().focus().unsetLink().run()"
|
||||||
type="button"
|
type="button"
|
||||||
@ -107,7 +107,7 @@
|
|||||||
<button
|
<button
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
v-if="!isBasicMode"
|
v-if="!isBasicMode"
|
||||||
:class="{ 'is-active': editor.isActive('bulletList') }"
|
:class="{ 'is-active': editor?.isActive('bulletList') }"
|
||||||
@click="editor?.chain().focus().toggleBulletList().run()"
|
@click="editor?.chain().focus().toggleBulletList().run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Bullet list')"
|
:title="t('Bullet list')"
|
||||||
@ -118,7 +118,7 @@
|
|||||||
<button
|
<button
|
||||||
v-if="!isBasicMode"
|
v-if="!isBasicMode"
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('orderedList') }"
|
:class="{ 'is-active': editor?.isActive('orderedList') }"
|
||||||
@click="editor?.chain().focus().toggleOrderedList().run()"
|
@click="editor?.chain().focus().toggleOrderedList().run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Ordered list')"
|
:title="t('Ordered list')"
|
||||||
@ -129,7 +129,7 @@
|
|||||||
<button
|
<button
|
||||||
v-if="!isBasicMode"
|
v-if="!isBasicMode"
|
||||||
class="menubar__button"
|
class="menubar__button"
|
||||||
:class="{ 'is-active': editor.isActive('blockquote') }"
|
:class="{ 'is-active': editor?.isActive('blockquote') }"
|
||||||
@click="editor?.chain().focus().toggleBlockquote().run()"
|
@click="editor?.chain().focus().toggleBlockquote().run()"
|
||||||
type="button"
|
type="button"
|
||||||
:title="t('Quote')"
|
:title="t('Quote')"
|
||||||
@ -193,7 +193,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Editor, EditorContent, BubbleMenu } from "@tiptap/vue-3";
|
import { useEditor, EditorContent, BubbleMenu } from "@tiptap/vue-3";
|
||||||
import Blockquote from "@tiptap/extension-blockquote";
|
import Blockquote from "@tiptap/extension-blockquote";
|
||||||
import BulletList from "@tiptap/extension-bullet-list";
|
import BulletList from "@tiptap/extension-bullet-list";
|
||||||
import Heading from "@tiptap/extension-heading";
|
import Heading from "@tiptap/extension-heading";
|
||||||
@ -254,8 +254,6 @@ const props = withDefaults(
|
|||||||
|
|
||||||
const emit = defineEmits(["update:modelValue"]);
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
|
|
||||||
const editor = ref<Editor | null>(null);
|
|
||||||
|
|
||||||
const isDescriptionMode = computed((): boolean => {
|
const isDescriptionMode = computed((): boolean => {
|
||||||
return props.mode === "description" || isBasicMode.value;
|
return props.mode === "description" || isBasicMode.value;
|
||||||
});
|
});
|
||||||
@ -278,47 +276,6 @@ const isBasicMode = computed((): boolean => {
|
|||||||
|
|
||||||
// const observer = ref<MutationObserver | null>(null);
|
// const observer = ref<MutationObserver | null>(null);
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
editor.value = new Editor({
|
|
||||||
editorProps: {
|
|
||||||
attributes: {
|
|
||||||
"aria-multiline": isShortMode.value.toString(),
|
|
||||||
"aria-label": props.ariaLabel ?? "",
|
|
||||||
role: "textbox",
|
|
||||||
},
|
|
||||||
transformPastedHTML: transformPastedHTML,
|
|
||||||
},
|
|
||||||
extensions: [
|
|
||||||
Blockquote,
|
|
||||||
BulletList,
|
|
||||||
Heading,
|
|
||||||
Document,
|
|
||||||
Paragraph,
|
|
||||||
Text,
|
|
||||||
OrderedList,
|
|
||||||
ListItem,
|
|
||||||
Mention.configure(MentionOptions),
|
|
||||||
CustomImage,
|
|
||||||
AutoDir,
|
|
||||||
Underline,
|
|
||||||
Bold,
|
|
||||||
Italic,
|
|
||||||
Strike,
|
|
||||||
Dropcursor,
|
|
||||||
Gapcursor,
|
|
||||||
History,
|
|
||||||
Link.configure({
|
|
||||||
HTMLAttributes: { target: "_blank", rel: "noopener noreferrer ugc" },
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
injectCSS: false,
|
|
||||||
content: props.modelValue,
|
|
||||||
onUpdate: () => {
|
|
||||||
emit("update:modelValue", editor.value?.getHTML());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const transformPastedHTML = (html: string): string => {
|
const transformPastedHTML = (html: string): string => {
|
||||||
// When using comment mode, limit to acceptable tags
|
// When using comment mode, limit to acceptable tags
|
||||||
if (isCommentMode.value) {
|
if (isCommentMode.value) {
|
||||||
@ -333,6 +290,47 @@ const transformPastedHTML = (html: string): string => {
|
|||||||
return html;
|
return html;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const editor = useEditor({
|
||||||
|
editorProps: {
|
||||||
|
attributes: {
|
||||||
|
"aria-multiline": isShortMode.value.toString(),
|
||||||
|
"aria-label": props.ariaLabel ?? "",
|
||||||
|
role: "textbox",
|
||||||
|
class:
|
||||||
|
"prose dark:prose-invert prose-sm sm:prose lg:prose-lg xl:prose-xl m-5 focus:outline-none !max-w-full",
|
||||||
|
},
|
||||||
|
transformPastedHTML: transformPastedHTML,
|
||||||
|
},
|
||||||
|
extensions: [
|
||||||
|
Blockquote,
|
||||||
|
BulletList,
|
||||||
|
Heading,
|
||||||
|
Document,
|
||||||
|
Paragraph,
|
||||||
|
Text,
|
||||||
|
OrderedList,
|
||||||
|
ListItem,
|
||||||
|
Mention.configure(MentionOptions),
|
||||||
|
CustomImage,
|
||||||
|
AutoDir,
|
||||||
|
Underline,
|
||||||
|
Bold,
|
||||||
|
Italic,
|
||||||
|
Strike,
|
||||||
|
Dropcursor,
|
||||||
|
Gapcursor,
|
||||||
|
History,
|
||||||
|
Link.configure({
|
||||||
|
HTMLAttributes: { target: "_blank", rel: "noopener noreferrer ugc" },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
injectCSS: false,
|
||||||
|
content: props.modelValue,
|
||||||
|
onUpdate: () => {
|
||||||
|
emit("update:modelValue", editor.value?.getHTML());
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const value = computed(() => props.modelValue);
|
const value = computed(() => props.modelValue);
|
||||||
|
|
||||||
watch(value, (val: string) => {
|
watch(value, (val: string) => {
|
||||||
@ -351,6 +349,7 @@ const { t } = useI18n({ useScope: "global" });
|
|||||||
const showLinkMenu = (): void => {
|
const showLinkMenu = (): void => {
|
||||||
dialog?.prompt({
|
dialog?.prompt({
|
||||||
message: t("Enter the link URL"),
|
message: t("Enter the link URL"),
|
||||||
|
hasInput: true,
|
||||||
inputAttrs: {
|
inputAttrs: {
|
||||||
type: "url",
|
type: "url",
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user