diff --git a/packages/@core/base/icons/src/lucide.ts b/packages/@core/base/icons/src/lucide.ts index 973251317..ce7e930e6 100644 --- a/packages/@core/base/icons/src/lucide.ts +++ b/packages/@core/base/icons/src/lucide.ts @@ -1,4 +1,7 @@ export { + TextAlignCenter as AlignCenter, + TextAlignStart as AlignLeft, + TextAlignEnd as AlignRight, ArrowDown, ArrowLeft, ArrowLeftToLine, @@ -7,6 +10,7 @@ export { ArrowUp, ArrowUpToLine, Bell, + Bold, BookOpenText, Check, ChevronDown, @@ -22,6 +26,7 @@ export { Copy, CornerDownLeft, Ellipsis, + Eraser, Expand, ExternalLink, Eye, @@ -32,12 +37,20 @@ export { Grid, Grip, GripVertical, + Heading1, + Heading2, + Highlighter, Menu as IconDefault, + ImagePlus, Inbox, Info, InspectionPanel, + Italic, Languages, LayoutGrid, + Link2, + List, + ListOrdered, LoaderCircle, LockKeyhole, LogOut, @@ -46,15 +59,19 @@ export { ArrowRightFromLine as MdiMenuClose, ArrowLeftFromLine as MdiMenuOpen, Menu, + MessageSquareCode, Minimize, Minimize2, MoonStar, + Paintbrush, Palette, PanelLeft, PanelRight, Pin, PinOff, Plus, + Redo2, + RemoveFormatting, RotateCw, Search, SearchX, @@ -62,10 +79,16 @@ export { Shrink, Square, SquareCheckBig, + SquareCode, SquareMinus, + Strikethrough, Sun, SunMoon, SwatchBook, + TextQuote, + Underline, + Undo2, + Unlink2, UserRoundPen, X, } from 'lucide-vue-next'; diff --git a/packages/effects/plugins/package.json b/packages/effects/plugins/package.json index eaeb179cb..7b5c5f7bb 100644 --- a/packages/effects/plugins/package.json +++ b/packages/effects/plugins/package.json @@ -22,6 +22,10 @@ "types": "./src/echarts/index.ts", "default": "./src/echarts/index.ts" }, + "./tiptap": { + "types": "./src/tiptap/index.ts", + "default": "./src/tiptap/index.ts" + }, "./vxe-table": { "types": "./src/vxe-table/index.ts", "default": "./src/vxe-table/index.ts" @@ -32,8 +36,20 @@ } }, "dependencies": { + "@tiptap/core": "catalog:", + "@tiptap/extension-doc": "catalog:", + "@tiptap/extension-highlight": "catalog:", + "@tiptap/extension-image": "catalog:", + "@tiptap/extension-link": "catalog:", + "@tiptap/extension-placeholder": "catalog:", + "@tiptap/extension-text-align": "catalog:", + "@tiptap/extension-text-style": "catalog:", + "@tiptap/extension-underline": "catalog:", + "@tiptap/starter-kit": "catalog:", + "@tiptap/vue-3": "catalog:", "@vben-core/design": "workspace:*", "@vben-core/form-ui": "workspace:*", + "@vben-core/popup-ui": "workspace:*", "@vben-core/shadcn-ui": "workspace:*", "@vben-core/shared": "workspace:*", "@vben/hooks": "workspace:*", diff --git a/packages/effects/plugins/src/tiptap/extensions.ts b/packages/effects/plugins/src/tiptap/extensions.ts new file mode 100644 index 000000000..0dd1c0ea9 --- /dev/null +++ b/packages/effects/plugins/src/tiptap/extensions.ts @@ -0,0 +1,55 @@ +import type { Extensions } from '@tiptap/vue-3'; + +import type { VbenTiptapExtensionOptions } from './types'; + +import { $t } from '@vben/locales'; + +import Document from '@tiptap/extension-doc'; +import Highlight from '@tiptap/extension-highlight'; +import Image from '@tiptap/extension-image'; +import Link from '@tiptap/extension-link'; +import Placeholder from '@tiptap/extension-placeholder'; +import TextAlign from '@tiptap/extension-text-align'; +import { Color, TextStyle } from '@tiptap/extension-text-style'; +import Underline from '@tiptap/extension-underline'; +import StarterKit from '@tiptap/starter-kit'; + +export function createDefaultTiptapExtensions( + options: VbenTiptapExtensionOptions = {}, +): Extensions { + return [ + Document, + StarterKit.configure({ + heading: { + levels: [1, 2, 3, 4], + }, + }), + Underline, + TextAlign.configure({ + types: ['heading', 'paragraph'], + }), + TextStyle, + Color.configure({ + types: ['textStyle'], + }), + Highlight.configure({ + multicolor: true, + }), + Link.configure({ + autolink: true, + defaultProtocol: 'https', + enableClickSelection: true, + openOnClick: false, + protocols: ['mailto', { optionalSlashes: true, scheme: 'tel' }], + }), + Image.configure({ + allowBase64: true, + HTMLAttributes: { + class: 'vben-tiptap__image', + }, + }), + Placeholder.configure({ + placeholder: options.placeholder ?? $t('ui.tiptap.placeholder'), + }), + ]; +} diff --git a/packages/effects/plugins/src/tiptap/index.ts b/packages/effects/plugins/src/tiptap/index.ts new file mode 100644 index 000000000..292ead0d2 --- /dev/null +++ b/packages/effects/plugins/src/tiptap/index.ts @@ -0,0 +1,4 @@ +export { default as VbenTiptapPreview } from './preview.vue'; +export { default as VbenTiptap } from './tiptap.vue'; + +export * from './types'; diff --git a/packages/effects/plugins/src/tiptap/preview.vue b/packages/effects/plugins/src/tiptap/preview.vue new file mode 100644 index 000000000..393938e94 --- /dev/null +++ b/packages/effects/plugins/src/tiptap/preview.vue @@ -0,0 +1,33 @@ + + + diff --git a/packages/effects/plugins/src/tiptap/style.css b/packages/effects/plugins/src/tiptap/style.css new file mode 100644 index 000000000..875556cec --- /dev/null +++ b/packages/effects/plugins/src/tiptap/style.css @@ -0,0 +1,56 @@ +@reference "@vben/tailwind-config/theme"; + +.vben-tiptap-content > * + * { + @apply mt-3; +} + +.vben-tiptap-content h1 { + @apply text-2xl font-bold leading-[1.4]; +} + +.vben-tiptap-content h2 { + @apply text-xl font-bold leading-[1.45]; +} + +.vben-tiptap-content h3 { + @apply text-lg font-semibold leading-[1.5]; +} + +.vben-tiptap-content h4 { + @apply text-base font-semibold leading-[1.55]; +} + +.vben-tiptap-content ul { + @apply list-disc pl-6; +} + +.vben-tiptap-content ol { + @apply list-decimal pl-6; +} + +.vben-tiptap-content blockquote { + @apply border-l-4 border-primary pl-4 text-muted-foreground; +} + +.vben-tiptap-content a { + @apply text-primary underline decoration-1 underline-offset-[3px]; +} + +.vben-tiptap-content code { + @apply rounded-[0.45rem] border border-border bg-secondary px-[0.35rem] py-[0.15rem] text-[0.9em] text-primary; +} + +.vben-tiptap-content pre { + @apply overflow-x-auto rounded-[0.9rem] border border-border bg-popover p-4 text-popover-foreground; +} + +.vben-tiptap-content pre code { + @apply border-none bg-transparent p-0 text-inherit; +} + +.vben-tiptap-content img, +.vben-tiptap-content .vben-tiptap__image { + @apply my-4 block h-auto rounded-2xl border border-border; + + max-width: min(100%, 640px); +} diff --git a/packages/effects/plugins/src/tiptap/tiptap.vue b/packages/effects/plugins/src/tiptap/tiptap.vue new file mode 100644 index 000000000..6f92f79ef --- /dev/null +++ b/packages/effects/plugins/src/tiptap/tiptap.vue @@ -0,0 +1,285 @@ + + + + + diff --git a/packages/effects/plugins/src/tiptap/toolbar.ts b/packages/effects/plugins/src/tiptap/toolbar.ts new file mode 100644 index 000000000..c5a15967f --- /dev/null +++ b/packages/effects/plugins/src/tiptap/toolbar.ts @@ -0,0 +1,345 @@ +import type { Editor } from '@tiptap/vue-3'; + +import type { ToolbarAction, ToolbarMenuItem } from './types'; + +import { + AlignCenter, + AlignLeft, + AlignRight, + Bold, + Highlighter, + ImagePlus, + Italic, + Link2, + List, + ListOrdered, + MessageSquareCode, + Paintbrush, + Redo2, + RemoveFormatting, + SquareCode, + Strikethrough, + TextQuote, + Underline, + Undo2, + Unlink2, +} from '@vben/icons'; +import { $t } from '@vben/locales'; +import { COLOR_PRESETS } from '@vben/preferences'; + +import { prompt } from '@vben-core/popup-ui'; + +const headingLevels = [1, 2, 3, 4] as const; +const editorColorPresets = [ + 'hsl(var(--foreground))', + 'hsl(var(--warning))', + 'hsl(var(--success))', + 'hsl(var(--destructive))', + ...COLOR_PRESETS.map((item) => item.color), +]; +const editorHighlightPresets = [ + withAlpha('hsl(var(--warning))', 0.45), + withAlpha('hsl(var(--success))', 0.35), + withAlpha('hsl(var(--primary))', 0.3), + withAlpha('hsl(var(--destructive))', 0.3), + ...COLOR_PRESETS.map((item) => withAlpha(item.color, 0.4)), +]; + +function createHeadingMenuItems(): ToolbarMenuItem[] { + return [ + { + action: (editor) => editor.chain().focus().setParagraph().run(), + can: (editor) => editor.can().chain().focus().setParagraph().run(), + isActive: (editor) => editor.isActive('paragraph'), + label: $t('ui.tiptap.toolbar.paragraph'), + shortLabel: 'P', + }, + ...headingLevels.map((level) => ({ + action: (editor: Editor) => + editor.chain().focus().toggleHeading({ level }).run(), + can: (editor: Editor) => + editor.can().chain().focus().toggleHeading({ level }).run(), + isActive: (editor: Editor) => editor.isActive('heading', { level }), + label: $t(`ui.tiptap.toolbar.heading${level}`), + shortLabel: `H${level}`, + })), + ]; +} + +function getHeadingTriggerText(editor?: Editor) { + if (editor?.isActive('paragraph')) { + return 'P'; + } + + const level = headingLevels.find((headingLevel) => + editor?.isActive('heading', { level: headingLevel }), + ); + + return level ? `H${level}` : 'H'; +} + +function normalizeLinkUrl(url: string) { + if (/^(https?:|mailto:|tel:)/i.test(url)) { + return url; + } + + return `https://${url}`; +} + +function withAlpha(color: string, alpha: number) { + const normalizedAlpha = Math.min(Math.max(alpha, 0), 1); + const hslMatch = color.match(/^hsl\((.+)\)$/); + + if (!hslMatch) { + return color; + } + + return `hsl(${hslMatch[1]} / ${normalizedAlpha})`; +} + +async function handleLinkAction(editor: Editor) { + const currentHref = editor.getAttributes('link').href as string | undefined; + + let url: string | undefined; + + try { + url = await prompt({ + componentProps: { + placeholder: 'https://example.com', + }, + content: $t('ui.tiptap.prompts.link'), + defaultValue: currentHref ?? '', + }); + } catch { + return; + } + + const nextUrl = (url ?? '').trim(); + + if (!nextUrl) { + editor.chain().focus().extendMarkRange('link').unsetLink().run(); + return; + } + + editor + .chain() + .focus() + .extendMarkRange('link') + .setLink({ + href: normalizeLinkUrl(nextUrl), + }) + .run(); +} + +async function handleImageAction(editor: Editor) { + let url: string | undefined; + + try { + url = await prompt({ + componentProps: { + placeholder: 'https://example.com/image.png', + }, + content: $t('ui.tiptap.prompts.image'), + defaultValue: '', + }); + } catch { + return; + } + + const nextUrl = (url ?? '').trim(); + + if (!nextUrl) { + return; + } + + editor.chain().focus().setImage({ src: nextUrl }).run(); +} + +export function createToolbarGroups(): ToolbarAction[][] { + const headingMenuItems = createHeadingMenuItems(); + + return [ + [ + { + action: (editor) => editor.chain().focus().undo().run(), + can: (editor) => editor.can().chain().focus().undo().run(), + icon: Undo2, + label: $t('ui.tiptap.toolbar.undo'), + }, + { + action: (editor) => editor.chain().focus().redo().run(), + can: (editor) => editor.can().chain().focus().redo().run(), + icon: Redo2, + label: $t('ui.tiptap.toolbar.redo'), + }, + { + action: (editor) => + editor.chain().focus().clearNodes().unsetAllMarks().run(), + icon: RemoveFormatting, + label: $t('ui.tiptap.toolbar.clear'), + }, + ], + [ + { + action: (editor) => editor.chain().focus().toggleBold().run(), + active: { name: 'bold' }, + can: (editor) => editor.can().chain().focus().toggleBold().run(), + icon: Bold, + label: $t('ui.tiptap.toolbar.bold'), + }, + { + action: (editor) => editor.chain().focus().toggleItalic().run(), + active: { name: 'italic' }, + can: (editor) => editor.can().chain().focus().toggleItalic().run(), + icon: Italic, + label: $t('ui.tiptap.toolbar.italic'), + }, + { + action: (editor) => editor.chain().focus().toggleUnderline().run(), + active: { name: 'underline' }, + can: (editor) => editor.can().chain().focus().toggleUnderline().run(), + icon: Underline, + label: $t('ui.tiptap.toolbar.underline'), + }, + { + action: (editor) => editor.chain().focus().toggleStrike().run(), + active: { name: 'strike' }, + can: (editor) => editor.can().chain().focus().toggleStrike().run(), + icon: Strikethrough, + label: $t('ui.tiptap.toolbar.strike'), + }, + { + action: (editor) => editor.chain().focus().toggleCode().run(), + active: { name: 'code' }, + can: (editor) => editor.can().chain().focus().toggleCode().run(), + icon: SquareCode, + label: $t('ui.tiptap.toolbar.code'), + }, + ], + [ + { + action: () => {}, + can: (editor) => + headingMenuItems.some((item) => (item.can ? item.can(editor) : true)), + isActive: (editor) => + headingMenuItems.some((item) => item.isActive?.(editor)), + label: $t('ui.tiptap.toolbar.heading'), + menu: { + items: headingMenuItems, + }, + triggerText: (editor) => getHeadingTriggerText(editor), + }, + { + action: (editor) => editor.chain().focus().toggleBulletList().run(), + active: { name: 'bulletList' }, + can: (editor) => editor.can().chain().focus().toggleBulletList().run(), + icon: List, + label: $t('ui.tiptap.toolbar.bulletList'), + }, + { + action: (editor) => editor.chain().focus().toggleOrderedList().run(), + active: { name: 'orderedList' }, + can: (editor) => editor.can().chain().focus().toggleOrderedList().run(), + icon: ListOrdered, + label: $t('ui.tiptap.toolbar.orderedList'), + }, + { + action: (editor) => editor.chain().focus().toggleBlockquote().run(), + active: { name: 'blockquote' }, + can: (editor) => editor.can().chain().focus().toggleBlockquote().run(), + icon: TextQuote, + label: $t('ui.tiptap.toolbar.blockquote'), + }, + { + action: (editor) => editor.chain().focus().toggleCodeBlock().run(), + active: { name: 'codeBlock' }, + can: (editor) => editor.can().chain().focus().toggleCodeBlock().run(), + icon: MessageSquareCode, + label: $t('ui.tiptap.toolbar.codeBlock'), + }, + ], + [ + { + action: (editor) => handleLinkAction(editor), + active: { name: 'link' }, + can: (editor) => + editor.can().chain().focus().extendMarkRange('link').run(), + icon: Link2, + label: $t('ui.tiptap.toolbar.link'), + }, + { + action: (editor) => editor.chain().focus().unsetLink().run(), + can: (editor) => editor.can().chain().focus().unsetLink().run(), + icon: Unlink2, + isActive: (editor) => editor.isActive('link'), + label: $t('ui.tiptap.toolbar.unlink'), + }, + { + action: (editor) => handleImageAction(editor), + icon: ImagePlus, + label: $t('ui.tiptap.toolbar.image'), + }, + ], + [ + { + action: () => {}, + icon: Paintbrush, + indicatorColor: (editor) => + editor.getAttributes('textStyle').color as string | undefined, + isActive: (editor) => Boolean(editor.getAttributes('textStyle').color), + label: $t('ui.tiptap.toolbar.textColor'), + palette: { + apply: (editor, color) => + editor.chain().focus().setColor(color).run(), + clear: (editor) => editor.chain().focus().unsetColor().run(), + colors: editorColorPresets, + currentColor: (editor) => + editor.getAttributes('textStyle').color as string | undefined, + }, + }, + { + action: () => {}, + icon: Highlighter, + indicatorColor: (editor) => + (editor.getAttributes('highlight').color as string | undefined) ?? + '#fef08a', + isActive: (editor) => editor.isActive('highlight'), + label: $t('ui.tiptap.toolbar.highlightColor'), + palette: { + apply: (editor, color) => + editor.chain().focus().setHighlight({ color }).run(), + clear: (editor) => editor.chain().focus().unsetHighlight().run(), + colors: editorHighlightPresets, + currentColor: (editor) => + editor.getAttributes('highlight').color as string | undefined, + }, + }, + ], + [ + { + action: (editor) => editor.chain().focus().setTextAlign('left').run(), + can: (editor) => + editor.can().chain().focus().setTextAlign('left').run(), + icon: AlignLeft, + isActive: (editor) => editor.isActive({ textAlign: 'left' }), + label: $t('ui.tiptap.toolbar.alignLeft'), + }, + { + action: (editor) => editor.chain().focus().setTextAlign('center').run(), + can: (editor) => + editor.can().chain().focus().setTextAlign('center').run(), + icon: AlignCenter, + isActive: (editor) => editor.isActive({ textAlign: 'center' }), + label: $t('ui.tiptap.toolbar.alignCenter'), + }, + { + action: (editor) => editor.chain().focus().setTextAlign('right').run(), + can: (editor) => + editor.can().chain().focus().setTextAlign('right').run(), + icon: AlignRight, + isActive: (editor) => editor.isActive({ textAlign: 'right' }), + label: $t('ui.tiptap.toolbar.alignRight'), + }, + ], + ]; +} diff --git a/packages/effects/plugins/src/tiptap/types.ts b/packages/effects/plugins/src/tiptap/types.ts new file mode 100644 index 000000000..eda32a21e --- /dev/null +++ b/packages/effects/plugins/src/tiptap/types.ts @@ -0,0 +1,60 @@ +import type { Extensions, JSONContent } from '@tiptap/core'; +import type { Editor } from '@tiptap/vue-3'; + +import type { Component } from 'vue'; + +export interface TipTapProps { + editable?: boolean; + extensions?: Extensions; + minHeight?: number | string; + placeholder?: string; + previewable?: boolean; + toolbar?: boolean; +} + +export interface TipTapPreviewProps { + class?: any; + content?: string; + minHeight?: number | string; +} + +export interface VbenTiptapChangeEvent { + html: string; + json: JSONContent; + text: string; +} + +export interface VbenTiptapExtensionOptions { + placeholder?: string; +} + +export interface ToolbarAction { + action: (editor: Editor) => void; + active?: { + attrs?: Record; + name: string; + }; + can?: (editor: Editor) => boolean; + icon?: Component; + indicatorColor?: (editor: Editor) => string | undefined; + isActive?: (editor: Editor) => boolean; + label: string; + menu?: { + items: ToolbarMenuItem[]; + }; + palette?: { + apply: (editor: Editor, color: string) => void; + clear?: (editor: Editor) => void; + colors: string[]; + currentColor?: (editor: Editor) => string | undefined; + }; + triggerText?: ((editor?: Editor) => string) | string; +} + +export interface ToolbarMenuItem { + action: (editor: Editor) => void; + can?: (editor: Editor) => boolean; + isActive?: (editor: Editor) => boolean; + label: string; + shortLabel: string; +} diff --git a/packages/effects/plugins/src/tiptap/use-tiptap-toolbar.ts b/packages/effects/plugins/src/tiptap/use-tiptap-toolbar.ts new file mode 100644 index 000000000..3b2375f22 --- /dev/null +++ b/packages/effects/plugins/src/tiptap/use-tiptap-toolbar.ts @@ -0,0 +1,176 @@ +import type { Editor } from '@tiptap/vue-3'; + +import type { ShallowRef } from 'vue'; + +import type { ToolbarAction, ToolbarMenuItem } from './types'; + +import { cn } from '@vben-core/shared/utils'; + +interface UseTiptapToolbarOptions { + editable: () => boolean; + editor: Readonly>; +} + +export function useTiptapToolbar(options: UseTiptapToolbarOptions) { + const getEditor = () => options.editor.value; + + function getActionIndicatorColor(action: ToolbarAction) { + const currentEditor = getEditor(); + + if (!currentEditor || !action.indicatorColor) { + return undefined; + } + + return action.indicatorColor(currentEditor); + } + + function getPaletteCurrentColor(action: ToolbarAction) { + const currentEditor = getEditor(); + + if (!currentEditor || !action.palette?.currentColor) { + return undefined; + } + + return action.palette.currentColor(currentEditor); + } + + function canRunAction(action: ToolbarAction) { + const currentEditor = getEditor(); + + if (!currentEditor || !options.editable()) { + return false; + } + + return action.can ? action.can(currentEditor) : true; + } + + function canRunMenuItem(item: ToolbarMenuItem) { + const currentEditor = getEditor(); + + if (!currentEditor || !options.editable()) { + return false; + } + + return item.can ? item.can(currentEditor) : true; + } + + function isActionActive(action: ToolbarAction) { + const currentEditor = getEditor(); + + if (!currentEditor) { + return false; + } + + if (action.isActive) { + return action.isActive(currentEditor); + } + + if (!action.active) { + return false; + } + + return currentEditor.isActive(action.active.name, action.active.attrs); + } + + function isMenuItemActive(item: ToolbarMenuItem, currentEditor?: Editor) { + const targetEditor = currentEditor ?? getEditor(); + + if (!targetEditor || !item.isActive) { + return false; + } + + return item.isActive(targetEditor); + } + + function runAction(action: ToolbarAction) { + const currentEditor = getEditor(); + + if (!currentEditor || !options.editable()) { + return; + } + + if (action.menu || action.palette) { + return; + } + + action.action(currentEditor); + } + + function runMenuItem(item: ToolbarMenuItem) { + const currentEditor = getEditor(); + + if (!currentEditor || !options.editable()) { + return; + } + + item.action(currentEditor); + } + + function applyPaletteColor(action: ToolbarAction, color: string) { + const currentEditor = getEditor(); + + if (!currentEditor || !action.palette) { + return; + } + + action.palette.apply(currentEditor, color); + } + + function clearPaletteColor(action: ToolbarAction) { + const currentEditor = getEditor(); + + if (!currentEditor || !action.palette?.clear) { + return; + } + + action.palette.clear(currentEditor); + } + + function getToolbarButtonClass(action: ToolbarAction) { + return cn( + 'relative rounded-[10px] border border-transparent bg-transparent text-muted-foreground shadow-none', + 'transition-[transform,color,background-color,border-color,box-shadow] duration-200 ease-out', + 'enabled:hover:-translate-y-px enabled:hover:border-border disabled:opacity-45', + 'enabled:hover:bg-accent enabled:hover:text-foreground', + isActionActive(action) && + 'border-primary/30 bg-accent text-primary shadow-primary', + ); + } + + function getPaletteSwatchClass(action: ToolbarAction, color: string) { + return cn( + 'inline-flex size-8 items-center justify-center rounded-full border border-border', + 'shadow-accent', + 'transition-[transform,box-shadow,border-color] duration-200 ease-out', + 'hover:-translate-y-px hover:scale-[1.04]', + getPaletteCurrentColor(action) === color && + 'border-primary shadow-primary', + ); + } + + function getMenuItemClass(item: ToolbarMenuItem) { + return cn( + 'flex items-center gap-2 rounded-lg p-2 text-left text-sm transition-colors', + 'disabled:cursor-not-allowed disabled:opacity-45', + isMenuItemActive(item) + ? 'bg-accent text-foreground' + : 'text-muted-foreground hover:bg-accent hover:text-foreground', + ); + } + + return { + applyPaletteColor, + canRunAction, + canRunMenuItem, + clearPaletteColor, + getActionIndicatorColor, + getMenuItemClass, + getPaletteCurrentColor, + getPaletteSwatchClass, + getToolbarButtonClass, + isActionActive, + isMenuItemActive, + runAction, + runMenuItem, + }; +} diff --git a/packages/locales/src/langs/en-US/ui.json b/packages/locales/src/langs/en-US/ui.json index 5e1c8557b..2b2508c70 100644 --- a/packages/locales/src/langs/en-US/ui.json +++ b/packages/locales/src/langs/en-US/ui.json @@ -61,6 +61,42 @@ "cancel": "Cancel cropping", "errorTip": "Cropping error" }, + "tiptap": { + "placeholder": "Please enter content...", + "prompts": { + "image": "Enter image URL", + "link": "Enter link URL" + }, + "toolbar": { + "bold": "Bold", + "italic": "Italic", + "underline": "Underline", + "strike": "Strike", + "code": "Code", + "codeBlock": "Code Block", + "heading": "Heading", + "paragraph": "Paragraph", + "heading1": "H1", + "heading2": "H2", + "heading3": "H3", + "heading4": "H4", + "bulletList": "Bullets", + "orderedList": "Numbering", + "blockquote": "Quote", + "link": "Link", + "unlink": "Unlink", + "image": "Image", + "textColor": "Text Color", + "highlightColor": "Highlight Color", + "alignLeft": "Left", + "alignCenter": "Center", + "alignRight": "Right", + "preview": "Preview", + "undo": "Undo", + "redo": "Redo", + "clear": "Clear" + } + }, "fallback": { "pageNotFound": "Oops! Page Not Found", "pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.", diff --git a/packages/locales/src/langs/zh-CN/ui.json b/packages/locales/src/langs/zh-CN/ui.json index 12306b424..e94b3010c 100644 --- a/packages/locales/src/langs/zh-CN/ui.json +++ b/packages/locales/src/langs/zh-CN/ui.json @@ -61,6 +61,42 @@ "cancel": "取消裁剪", "errorTip": "裁剪错误" }, + "tiptap": { + "placeholder": "请输入内容...", + "prompts": { + "image": "请输入图片地址", + "link": "请输入链接地址" + }, + "toolbar": { + "bold": "加粗", + "italic": "斜体", + "underline": "下划线", + "strike": "删除线", + "code": "行内代码", + "codeBlock": "代码块", + "heading": "标题", + "paragraph": "正文", + "heading1": "标题1", + "heading2": "标题2", + "heading3": "标题3", + "heading4": "标题4", + "bulletList": "无序列表", + "orderedList": "有序列表", + "blockquote": "引用", + "link": "链接", + "unlink": "移除链接", + "image": "图片", + "textColor": "文字颜色", + "highlightColor": "高亮颜色", + "alignLeft": "左对齐", + "alignCenter": "居中", + "alignRight": "右对齐", + "preview": "预览", + "undo": "撤销", + "redo": "重做", + "clear": "清除" + } + }, "fallback": { "pageNotFound": "哎呀!未找到页面", "pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。", diff --git a/playground/src/adapter/component/index.ts b/playground/src/adapter/component/index.ts index 61760514a..1f5e73567 100644 --- a/playground/src/adapter/component/index.ts +++ b/playground/src/adapter/component/index.ts @@ -40,6 +40,7 @@ import { import { useSortable } from '@vben/hooks'; import { IconifyIcon } from '@vben/icons'; import { $t } from '@vben/locales'; +import { VbenTiptap } from '@vben/plugins/tiptap'; import { isEmpty } from '@vben/utils'; import { message, Modal, notification } from 'ant-design-vue'; @@ -583,6 +584,7 @@ export type ComponentType = | 'RadioGroup' | 'RangePicker' | 'Rate' + | 'RichEditor' | 'Select' | 'Space' | 'Switch' @@ -646,6 +648,7 @@ async function initComponentAdapter() { RadioGroup, RangePicker, Rate, + RichEditor: withDefaultPlaceholder(VbenTiptap, 'input'), Select: withDefaultPlaceholder(Select, 'select'), Space, Switch, diff --git a/playground/src/locales/langs/en-US/examples.json b/playground/src/locales/langs/en-US/examples.json index 05035487f..4e65d7fbf 100644 --- a/playground/src/locales/langs/en-US/examples.json +++ b/playground/src/locales/langs/en-US/examples.json @@ -79,5 +79,8 @@ }, "cropper": { "title": "Cropper" + }, + "tiptap": { + "title": "Rich Text Editor" } } diff --git a/playground/src/locales/langs/zh-CN/examples.json b/playground/src/locales/langs/zh-CN/examples.json index 3b0d934cf..22e9e2933 100644 --- a/playground/src/locales/langs/zh-CN/examples.json +++ b/playground/src/locales/langs/zh-CN/examples.json @@ -79,5 +79,8 @@ }, "cropper": { "title": "图片裁剪" + }, + "tiptap": { + "title": "富文本编辑器" } } diff --git a/playground/src/router/routes/modules/examples.ts b/playground/src/router/routes/modules/examples.ts index 017b2c22f..a0cedc09c 100644 --- a/playground/src/router/routes/modules/examples.ts +++ b/playground/src/router/routes/modules/examples.ts @@ -346,6 +346,15 @@ const routes: RouteRecordRaw[] = [ title: $t('examples.cropper.title'), }, }, + { + name: 'TiptapExample', + path: '/examples/tiptap', + component: () => import('#/views/examples/tiptap/index.vue'), + meta: { + icon: 'lucide:square-pen', + title: $t('examples.tiptap.title'), + }, + }, ], }, ]; diff --git a/playground/src/views/examples/form/basic.vue b/playground/src/views/examples/form/basic.vue index d8fde4645..169c0702b 100644 --- a/playground/src/views/examples/form/basic.vue +++ b/playground/src/views/examples/form/basic.vue @@ -409,6 +409,12 @@ const [BaseForm, baseFormApi] = useVbenForm({ }, rules: 'selectRequired', }, + { + component: 'RichEditor', + fieldName: 'richEditor', + label: '富文本', + formItemClass: 'col-span-3 items-baseline', + }, ], // 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个 wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3', @@ -485,6 +491,12 @@ function handleSetFormValue() { timePicker: dayjs('2022-01-01 12:00:00'), treeSelect: 'leaf1', username: '1', + richEditor: ` +

Vben Tiptap

+

这个编辑器已经被封装在 packages/effects/plugins/src/tiptap 中。

+

你可以直接在各个 app 里通过 @vben/plugins/tiptap 引入。

+
默认内置 StarterKit、Underline、TextAlign、Placeholder。
+ `, }); // 设置单个表单值 diff --git a/playground/src/views/examples/tiptap/index.vue b/playground/src/views/examples/tiptap/index.vue new file mode 100644 index 000000000..009e18c7f --- /dev/null +++ b/playground/src/views/examples/tiptap/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4bbbc7b28..b471f85ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -78,6 +78,36 @@ catalogs: '@tanstack/vue-store': specifier: ^0.9.3 version: 0.9.3 + '@tiptap/core': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/extension-highlight': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/extension-image': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/extension-link': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/extension-placeholder': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/extension-text-align': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/extension-text-style': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/extension-underline': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/starter-kit': + specifier: ^3.21.0 + version: 3.21.0 + '@tiptap/vue-3': + specifier: ^3.21.0 + version: 3.21.0 '@tsdown/css': specifier: ^0.21.7 version: 0.21.7 @@ -1758,12 +1788,45 @@ importers: packages/effects/plugins: dependencies: + '@tiptap/core': + specifier: 'catalog:' + version: 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/extension-highlight': + specifier: 'catalog:' + version: 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-image': + specifier: 'catalog:' + version: 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-link': + specifier: 'catalog:' + version: 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tiptap/extension-placeholder': + specifier: 'catalog:' + version: 3.21.0(@tiptap/extensions@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)) + '@tiptap/extension-text-align': + specifier: 'catalog:' + version: 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-text-style': + specifier: 'catalog:' + version: 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-underline': + specifier: 'catalog:' + version: 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/starter-kit': + specifier: 'catalog:' + version: 3.21.0 + '@tiptap/vue-3': + specifier: 'catalog:' + version: 3.21.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)(vue@3.5.31(typescript@5.9.3)) '@vben-core/design': specifier: workspace:* version: link:../../@core/base/design '@vben-core/form-ui': specifier: workspace:* version: link:../../@core/ui-kit/form-ui + '@vben-core/popup-ui': + specifier: workspace:* + version: link:../../@core/ui-kit/popup-ui '@vben-core/shadcn-ui': specifier: workspace:* version: link:../../@core/ui-kit/shadcn-ui @@ -4474,6 +4537,9 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + '@rolldown/binding-android-arm64@1.0.0-rc.12': resolution: {integrity: sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -5035,6 +5101,178 @@ packages: peerDependencies: vue: ^3.5.31 + '@tiptap/core@3.21.0': + resolution: {integrity: sha512-IfnQiuEeabDSPr1C/zHFTbnvlTf5z0DE/d/xz4C6bkL4ZBDJ3rr99h2qsaV0l8F+kbNswZMlQdM8rxNlMy95fQ==} + peerDependencies: + '@tiptap/pm': ^3.21.0 + + '@tiptap/extension-blockquote@3.21.0': + resolution: {integrity: sha512-JDM/RR6rM0dMCZ1UnEf7eqmN6pAdIa2llhN+E24HdTGNJCklMFhLAGE/OT8/1r7M0WWA9GVO7/PTe4EdGh6+lQ==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-bold@3.21.0': + resolution: {integrity: sha512-iyEJRzG7XTCPlHwEDzUw3HnuYYCfL7lNpcCHmxcpYMrIUA8rv7EUxerIwApT6xY8hQ/07ljuJKgOyPvnJOOzuA==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-bubble-menu@3.21.0': + resolution: {integrity: sha512-/fabRRhhf8i4LAx9e8xz9ppqN5KgdJk3TxMuxAD5vAWGsejvhSoPa8O8H/QwwyntXm1Vue8aQiMHsUk48b2hGQ==} + peerDependencies: + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + + '@tiptap/extension-bullet-list@3.21.0': + resolution: {integrity: sha512-PWNF+xwxgOeXYGD88sCQLKL0eBoQqjUnZNALxBjN3Y7x4llalh42rHOp2Nt2t6UbQgqTBtBzU/uFcussTpxreQ==} + peerDependencies: + '@tiptap/extension-list': ^3.21.0 + + '@tiptap/extension-code-block@3.21.0': + resolution: {integrity: sha512-zrVOcOzDCjHQ8NJcC+qHmZZKiwnP/NMSb3qVJlSMN8TzuHept1MZCDa2Mbo70O6I0txo456SGuXB9sqV1vHmGg==} + peerDependencies: + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + + '@tiptap/extension-code@3.21.0': + resolution: {integrity: sha512-D7wA9jp+4X2r1f3FIoga73s6Rn4rmZY57Jes6a4rK3HY+3yHk1r057pPIZSY8Drfs97jxHQVFdfUYUomLSFYBA==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-document@3.21.0': + resolution: {integrity: sha512-7oCyzXI9ChvJQUlr23AURdfVar4OIsrYUvqdhEwo3bjcI/Q/j0KJiXfuh6ZzL5eVaINSailH53sZaGg4THQtUg==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-dropcursor@3.21.0': + resolution: {integrity: sha512-6fsDSVAM2iz7eElvT6iivMrGBGjIP/oPigVZ/SPm6f31phaYhz6TIOEgV/Lr2jaPIOgyK4U0cU4Yd4KUBCmhzQ==} + peerDependencies: + '@tiptap/extensions': ^3.21.0 + + '@tiptap/extension-floating-menu@3.21.0': + resolution: {integrity: sha512-n2HzTB+I/5rAl8R/1sKMv92JiY1oDK1hroXizxEKYa6dskJcAMW0CfYyPcPOZWQQEe7qoeOvQISr2ooLAKW+Mw==} + peerDependencies: + '@floating-ui/dom': ^1.0.0 + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + + '@tiptap/extension-gapcursor@3.21.0': + resolution: {integrity: sha512-wGjgAoYBTvPAe9QYMI5px355XcNeMkaUrMY9IHbMqgqdmHcDxqooxM4H6sYVX2CRcHwXy4I8NQAoOhSYrQJDMg==} + peerDependencies: + '@tiptap/extensions': ^3.21.0 + + '@tiptap/extension-hard-break@3.21.0': + resolution: {integrity: sha512-6JFVSAOQ1qhQHi9mVcdn2/XO8YIMgYV8zjarzNUzP6Sf2waeE5BLXjlg6rIH/945sY1J+FndTojLru6gQ07a5A==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-heading@3.21.0': + resolution: {integrity: sha512-ji6VJmoRnDzAHYflEYEZohMHRi77UGLW1o3ua7UhI32iJ9nuYssbPNuzEeE4SvENMQwZRszad5+a+dKAa+NC7g==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-highlight@3.21.0': + resolution: {integrity: sha512-3f/bVgfm2dJZxalh07TThDxcTaeXJ+dpYyRY9trnFeHbhyYQXSy6yzkNhNcYB4Ua5jxpKQv4b9Q448QVh+KNzA==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-horizontal-rule@3.21.0': + resolution: {integrity: sha512-vNBnOfFEY62CoJPGo4nonRM7RiOvhII1vhoO+WFr1GxDqCAfmEFjToflt7JT1UJdo6lMVcD+aaaAgOiuSz5p6g==} + peerDependencies: + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + + '@tiptap/extension-image@3.21.0': + resolution: {integrity: sha512-W9786a2K4LSZJMPeRLmoDulJeXOsM0ueRV2MHjTol7ikPRauROB7GUbAz9DyPAJHA2AGUfpswnGAYPO3tz5CLg==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-italic@3.21.0': + resolution: {integrity: sha512-2I8oPvwyXhRn1k8lbDFIutzvhtLEjoO5mmQCNX4TnT4PdxxaSrK9+ihYg12VeqhUeO7dg1MKiFqws0HVBrwzWg==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-link@3.21.0': + resolution: {integrity: sha512-oMU7Yve1sbgBsaFAUc2R0GPf4d3ZPVJeMUFC6b6X9rJIvx/IhEUEn9toQcSBGfp02uWK9NdQyIFYFdWlVXH++w==} + peerDependencies: + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + + '@tiptap/extension-list-item@3.21.0': + resolution: {integrity: sha512-1ZymZmlQVbAoC4q5x3cro0v5+3I6l+BHqbhIMQLjQFlAOJfcE0pvqRzAFW7PduxUj41tXEtsYqp2NREvO9F5Fg==} + peerDependencies: + '@tiptap/extension-list': ^3.21.0 + + '@tiptap/extension-list-keymap@3.21.0': + resolution: {integrity: sha512-EzrfW3ASNFPWKhR8sNOq7Kqw4hvaTAOn4dlI7chB8HIANSrlyPOUn+eKAnO6HQgsUgsbjg2GbTUrGrxcoLykUg==} + peerDependencies: + '@tiptap/extension-list': ^3.21.0 + + '@tiptap/extension-list@3.21.0': + resolution: {integrity: sha512-KeBlEtLrGce2d3dgL89hmwWEtREuzlW4XY5bYWpKNvCbFqvdSb3n7vkdkw32YclZmMWxAcABgW6ucCStkE0rsQ==} + peerDependencies: + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + + '@tiptap/extension-ordered-list@3.21.0': + resolution: {integrity: sha512-+d+0orokMfqaBfvr9tUBgGvo2ZCV+fR3JzsJTmnLBWOkhBSJN7H4pnfXPTue0qwspUwRmkLJxdIlU+J7HkMrng==} + peerDependencies: + '@tiptap/extension-list': ^3.21.0 + + '@tiptap/extension-paragraph@3.21.0': + resolution: {integrity: sha512-cMPG/jCoZ9NmLZ5ctFziILaxJGfDtMTb5OLBhifMFZeMVwF1pEJIygDEfnX/HSruv507weZSQG4pERO2tRszMg==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-placeholder@3.21.0': + resolution: {integrity: sha512-fs+cQqMh1d1naV6OgOhP/0qbRJwtw8DpQMj3/oqGKbaRRKIeecEaZPXYRd7MYa4e9K0Cfk5Bm0MNs9lwu/BYsw==} + peerDependencies: + '@tiptap/extensions': ^3.21.0 + + '@tiptap/extension-strike@3.21.0': + resolution: {integrity: sha512-easnVaN11Wl+5fOtfvzJ10J762S9TRXZaMj5rLBGavgf82DCYHqhGhBqpLQrJ41r4nPABGlYvTRoxfvBLB74Lg==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-text-align@3.21.0': + resolution: {integrity: sha512-XaoUaq45nai9LLoUStumMItHhhCnmXirPR8mTjEDKZ2QD0Kg/YHEr6guJYc6qKB7YA+Wa1EgBIrZOv1+d2Pdag==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-text-style@3.21.0': + resolution: {integrity: sha512-MI/3X75D45Wa/+0Fp8nYfNJq5makkjtG7B2/lIzNUe0kEKJ56RVQoV1GQSXxAiFNyAYRfKFq8dJslhesW3EkWA==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-text@3.21.0': + resolution: {integrity: sha512-Zx8QdB8a5iBuE4uO21c3BjmpBfaJEr2Jd1QFnsdgx11fm6P7dGgZaGko1FaINhfOPRGTN6O/kiF02cDMdOHa/w==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extension-underline@3.21.0': + resolution: {integrity: sha512-gGmBEymbWnr8AIS8bI/bPw5rcwo7wAFcBw/TsLd1nAanu1dDqSRNDBrit3m02Ru+D88u2SfNvmbOPI1pz+1f5w==} + peerDependencies: + '@tiptap/core': ^3.21.0 + + '@tiptap/extensions@3.21.0': + resolution: {integrity: sha512-MN1uh5PmHT1F2BNsbc21MIS0AMFFA73oODlp/4ckpBR4o5AxRwV+8f43Cd52UL4MgMkKj/A+QfZ7iK9IDb0h5A==} + peerDependencies: + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + + '@tiptap/pm@3.21.0': + resolution: {integrity: sha512-I3sNo7oMMsR6FFz1ecvPb9uCF0VQuS2WV67j8Io2M7DJicRWCE/GM5DaiYjTeWBbnByk6BuG0txoJATAqPVliQ==} + + '@tiptap/starter-kit@3.21.0': + resolution: {integrity: sha512-w7fWxglDtqXFBgRYH+LforJyUboSAQllnWQbGVSTyX4rsICqZjkb3f6CTSUWpGoGKmlmbb2ZpEuoik7tur9d8Q==} + + '@tiptap/vue-3@3.21.0': + resolution: {integrity: sha512-dfjxBwxg9+GNvsgkCbxLnj/vmG+YZMdcD/qF7bKM710bANWfqzimRUhH5W2KZcxqlYzqpz0u/P0zi7dUMR5IZA==} + peerDependencies: + '@floating-ui/dom': ^1.0.0 + '@tiptap/core': ^3.21.0 + '@tiptap/pm': ^3.21.0 + vue: ^3.5.31 + '@tsdown/css@0.21.7': resolution: {integrity: sha512-kydfZ109LIXwoBDrdIeEVi+PtM8375X9d/6UtYtjhj6TS94J25gJVUXw9AyJE6THEqB6OdGKM5MLqJPutO4kkA==} engines: {node: '>=20.19.0'} @@ -6045,8 +6283,8 @@ packages: bare-buffer: optional: true - bare-os@3.8.4: - resolution: {integrity: sha512-4JboWUl7/2LhgU536tjUszzaVC8/WEWKtyX5crayvlN71ih8+O2SdvBhotQeDsuhhmPZmLCrPBJEcwVPhI/kkQ==} + bare-os@3.8.6: + resolution: {integrity: sha512-l8xaNWWb/bXuzgsrlF5jaa5QYDJ9S0ddd54cP6CH+081+5iPrbJiCfBWQqrWYzmUhCbsH+WR6qxo9MeHVCr0MQ==} engines: {bare: '>=1.14.0'} bare-path@3.0.0: @@ -6502,6 +6740,9 @@ packages: resolution: {integrity: sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==} engines: {node: '>= 14'} + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + croner@10.0.1: resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==} engines: {node: '>=18.0'} @@ -8303,6 +8544,12 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + linkifyjs@4.3.2: + resolution: {integrity: sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA==} + listhen@1.9.0: resolution: {integrity: sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==} hasBin: true @@ -8457,6 +8704,10 @@ packages: mark.js@8.11.1: resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + markdown-it@14.1.1: + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -8476,6 +8727,9 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + medium-zoom@1.1.0: resolution: {integrity: sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==} @@ -8802,6 +9056,9 @@ packages: resolution: {integrity: sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==} engines: {node: '>=20'} + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} @@ -9159,6 +9416,64 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + prosemirror-changeset@2.4.0: + resolution: {integrity: sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.7.1: + resolution: {integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==} + + prosemirror-dropcursor@1.8.2: + resolution: {integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==} + + prosemirror-gapcursor@1.4.1: + resolution: {integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==} + + prosemirror-history@1.5.0: + resolution: {integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==} + + prosemirror-inputrules@1.5.1: + resolution: {integrity: sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==} + + prosemirror-keymap@1.2.3: + resolution: {integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==} + + prosemirror-markdown@1.13.4: + resolution: {integrity: sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw==} + + prosemirror-menu@1.3.0: + resolution: {integrity: sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg==} + + prosemirror-model@1.25.4: + resolution: {integrity: sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==} + + prosemirror-schema-basic@1.2.4: + resolution: {integrity: sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==} + + prosemirror-schema-list@1.5.1: + resolution: {integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==} + + prosemirror-state@1.4.4: + resolution: {integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==} + + prosemirror-tables@1.8.5: + resolution: {integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.12.0: + resolution: {integrity: sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==} + + prosemirror-view@1.41.7: + resolution: {integrity: sha512-jUwKNCEIGiqdvhlS91/2QAg21e4dfU5bH2iwmSDQeosXJgKF7smG0YSplOWK0cjSNgIqXe7VXqo7EIfUFJdt3w==} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -9174,6 +9489,10 @@ packages: engines: {node: '>=18'} hasBin: true + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -9429,6 +9748,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -10258,6 +10580,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + ufo@1.6.3: resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} @@ -10812,6 +11137,9 @@ packages: vxe-table@4.18.10: resolution: {integrity: sha512-8V9WL83pB4PrvgBS6DoDU7dSRxOlJw9ZkVcxDnKBFQkTTnLVvC8HYOJ75uwfRNyo9cALNIpJnSkow2uqaMKbNQ==} + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + warning@4.0.3: resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} @@ -13573,6 +13901,8 @@ snapshots: dependencies: quansync: 1.0.0 + '@remirror/core-constants@3.0.0': {} + '@rolldown/binding-android-arm64@1.0.0-rc.12': optional: true @@ -14007,6 +14337,196 @@ snapshots: '@tanstack/virtual-core': 3.13.23 vue: 3.5.31(typescript@5.9.3) + '@tiptap/core@3.21.0(@tiptap/pm@3.21.0)': + dependencies: + '@tiptap/pm': 3.21.0 + + '@tiptap/extension-blockquote@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-bold@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-bubble-menu@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)': + dependencies: + '@floating-ui/dom': 1.7.6 + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + optional: true + + '@tiptap/extension-bullet-list@3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/extension-list': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + + '@tiptap/extension-code-block@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + + '@tiptap/extension-code@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-document@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-dropcursor@3.21.0(@tiptap/extensions@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/extensions': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + + '@tiptap/extension-floating-menu@3.21.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)': + dependencies: + '@floating-ui/dom': 1.7.6 + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + optional: true + + '@tiptap/extension-gapcursor@3.21.0(@tiptap/extensions@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/extensions': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + + '@tiptap/extension-hard-break@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-heading@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-highlight@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-horizontal-rule@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + + '@tiptap/extension-image@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-italic@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-link@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + linkifyjs: 4.3.2 + + '@tiptap/extension-list-item@3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/extension-list': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + + '@tiptap/extension-list-keymap@3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/extension-list': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + + '@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + + '@tiptap/extension-ordered-list@3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/extension-list': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + + '@tiptap/extension-paragraph@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-placeholder@3.21.0(@tiptap/extensions@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/extensions': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + + '@tiptap/extension-strike@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-text-align@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-text-style@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-text@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extension-underline@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + + '@tiptap/extensions@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + + '@tiptap/pm@3.21.0': + dependencies: + prosemirror-changeset: 2.4.0 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.7.1 + prosemirror-dropcursor: 1.8.2 + prosemirror-gapcursor: 1.4.1 + prosemirror-history: 1.5.0 + prosemirror-inputrules: 1.5.1 + prosemirror-keymap: 1.2.3 + prosemirror-markdown: 1.13.4 + prosemirror-menu: 1.3.0 + prosemirror-model: 1.25.4 + prosemirror-schema-basic: 1.2.4 + prosemirror-schema-list: 1.5.1 + prosemirror-state: 1.4.4 + prosemirror-tables: 1.8.5 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.7) + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.7 + + '@tiptap/starter-kit@3.21.0': + dependencies: + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/extension-blockquote': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-bold': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-bullet-list': 3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)) + '@tiptap/extension-code': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-code-block': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tiptap/extension-document': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-dropcursor': 3.21.0(@tiptap/extensions@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)) + '@tiptap/extension-gapcursor': 3.21.0(@tiptap/extensions@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)) + '@tiptap/extension-hard-break': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-heading': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-horizontal-rule': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tiptap/extension-italic': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-link': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tiptap/extension-list': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tiptap/extension-list-item': 3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)) + '@tiptap/extension-list-keymap': 3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)) + '@tiptap/extension-ordered-list': 3.21.0(@tiptap/extension-list@3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)) + '@tiptap/extension-paragraph': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-strike': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-text': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extension-underline': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0)) + '@tiptap/extensions': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + + '@tiptap/vue-3@3.21.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0)(vue@3.5.31(typescript@5.9.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@tiptap/core': 3.21.0(@tiptap/pm@3.21.0) + '@tiptap/pm': 3.21.0 + vue: 3.5.31(typescript@5.9.3) + optionalDependencies: + '@tiptap/extension-bubble-menu': 3.21.0(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tiptap/extension-floating-menu': 3.21.0(@floating-ui/dom@1.7.6)(@tiptap/core@3.21.0(@tiptap/pm@3.21.0))(@tiptap/pm@3.21.0) + '@tsdown/css@0.21.7(jiti@2.6.1)(postcss@8.5.8)(sass-embedded@1.98.0)(sass@1.98.0)(tsdown@0.21.7)(yaml@2.8.3)': dependencies: lightningcss: 1.32.0 @@ -15217,11 +15737,11 @@ snapshots: - bare-abort-controller - react-native-b4a - bare-os@3.8.4: {} + bare-os@3.8.6: {} bare-path@3.0.0: dependencies: - bare-os: 3.8.4 + bare-os: 3.8.6 bare-stream@2.11.0(bare-events@2.8.2): dependencies: @@ -15686,6 +16206,8 @@ snapshots: crc-32: 1.2.2 readable-stream: 4.7.0 + crelt@1.0.6: {} + croner@10.0.1: {} cross-env@10.1.0: @@ -17672,6 +18194,12 @@ snapshots: lines-and-columns@1.2.4: {} + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + linkifyjs@4.3.2: {} + listhen@1.9.0: dependencies: '@parcel/watcher': 2.5.6 @@ -17833,6 +18361,15 @@ snapshots: mark.js@8.11.1: {} + markdown-it@14.1.1: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + math-intrinsics@1.1.0: {} mathml-tag-names@4.0.0: {} @@ -17855,6 +18392,8 @@ snapshots: mdn-data@2.27.1: {} + mdurl@2.0.0: {} + medium-zoom@1.1.0: {} memoize-one@6.0.0: {} @@ -18275,6 +18814,8 @@ snapshots: stdin-discarder: 0.3.1 string-width: 8.2.0 + orderedmap@2.1.1: {} + outdent@0.5.0: {} own-keys@1.0.1: @@ -18610,6 +19151,109 @@ snapshots: property-information@7.1.0: {} + prosemirror-changeset@2.4.0: + dependencies: + prosemirror-transform: 1.12.0 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.4 + + prosemirror-commands@1.7.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-dropcursor@1.8.2: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.7 + + prosemirror-gapcursor@1.4.1: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.7 + + prosemirror-history@1.5.0: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.7 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.5.1: + dependencies: + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-keymap@1.2.3: + dependencies: + prosemirror-state: 1.4.4 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.4: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.1 + prosemirror-model: 1.25.4 + + prosemirror-menu@1.3.0: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.7.1 + prosemirror-history: 1.5.0 + prosemirror-state: 1.4.4 + + prosemirror-model@1.25.4: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.4: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-schema-list@1.5.1: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + + prosemirror-state@1.4.4: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.7 + + prosemirror-tables@1.8.5: + dependencies: + prosemirror-keymap: 1.2.3 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + prosemirror-view: 1.41.7 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.7): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-view: 1.41.7 + + prosemirror-transform@1.12.0: + dependencies: + prosemirror-model: 1.25.4 + + prosemirror-view@1.41.7: + dependencies: + prosemirror-model: 1.25.4 + prosemirror-state: 1.4.4 + prosemirror-transform: 1.12.0 + proto-list@1.2.4: {} proxy-from-env@2.1.0: {} @@ -18624,6 +19268,8 @@ snapshots: picocolors: 1.1.1 sade: 1.8.1 + punycode.js@2.3.1: {} + punycode@2.3.1: {} pupa@3.3.0: @@ -18939,6 +19585,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.1 fsevents: 2.3.3 + rope-sequence@1.3.4: {} + run-applescript@7.1.0: {} run-parallel@1.2.0: @@ -19835,6 +20483,8 @@ snapshots: typescript@5.9.3: {} + uc.micro@2.1.0: {} + ufo@1.6.3: {} ultrahtml@1.6.0: {} @@ -20439,6 +21089,8 @@ snapshots: transitivePeerDependencies: - vue + w3c-keyname@2.2.8: {} + warning@4.0.3: dependencies: loose-envify: 1.4.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4c0545fa3..d47112529 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -47,6 +47,17 @@ catalog: '@tailwindcss/vite': ^4.2.2 '@tanstack/vue-query': ^5.95.2 '@tanstack/vue-store': ^0.9.3 + '@tiptap/core': ^3.21.0 + '@tiptap/extension-doc': ^3.21.0 + '@tiptap/extension-highlight': ^3.21.0 + '@tiptap/extension-image': ^3.21.0 + '@tiptap/extension-link': ^3.21.0 + '@tiptap/extension-placeholder': ^3.21.0 + '@tiptap/extension-text-align': ^3.21.0 + '@tiptap/extension-text-style': ^3.21.0 + '@tiptap/extension-underline': ^3.21.0 + '@tiptap/starter-kit': ^3.21.0 + '@tiptap/vue-3': ^3.21.0 '@tsdown/css': ^0.21.7 '@types/archiver': ^7.0.0 '@types/html-minifier-terser': ^7.0.2