dishui 0.0.71 → 0.0.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Button/index.d.ts +4 -4
- package/dist/components/Button/index.js +18 -17
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Card/Metric.d.ts +17 -0
- package/dist/components/Card/Metric2.js +50 -0
- package/dist/components/Card/Metric2.js.map +1 -0
- package/dist/components/Card/index.d.ts +3 -0
- package/dist/components/Card/index.js +118 -117
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/Group/index.d.ts +2 -0
- package/dist/components/GroupButton/index.d.ts +16 -0
- package/dist/components/GroupButton/index.js +41 -0
- package/dist/components/GroupButton/index.js.map +1 -0
- package/dist/components/GroupedTable/index.d.ts +38 -0
- package/dist/components/GroupedTable/index.js +92 -0
- package/dist/components/GroupedTable/index.js.map +1 -0
- package/dist/components/Layout/index.d.ts +4 -2
- package/dist/components/Layout/index.js +1 -1
- package/dist/components/Layout/index.js.map +1 -1
- package/dist/components/NavigationList/index.d.ts +17 -0
- package/dist/components/NavigationList/index.js +48 -0
- package/dist/components/NavigationList/index.js.map +1 -0
- package/dist/components/Section/index.d.ts +28 -0
- package/dist/components/Section/index.js +58 -0
- package/dist/components/Section/index.js.map +1 -0
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Select/index.js +83 -82
- package/dist/components/Select/index.js.map +1 -1
- package/dist/components/SidebarToggleButton/index.d.ts +16 -1
- package/dist/components/SidebarToggleButton/index.js +90 -30
- package/dist/components/SidebarToggleButton/index.js.map +1 -1
- package/dist/components/Skeleton/index.d.ts +7 -0
- package/dist/components/Skeleton/index.js +21 -0
- package/dist/components/Skeleton/index.js.map +1 -0
- package/dist/components/Tree/Tree.js +5 -2
- package/dist/components/Tree/Tree.js.map +1 -1
- package/dist/components/pro/RichTextEditor/AIRewrite.js +114 -72
- package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BlockHandle.js +315 -196
- package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BubbleToolbar.d.ts +1 -1
- package/dist/components/pro/RichTextEditor/BubbleToolbar.js +69 -33
- package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPanel.d.ts +2 -1
- package/dist/components/pro/RichTextEditor/CommentPanel.js +100 -81
- package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPopover.d.ts +2 -1
- package/dist/components/pro/RichTextEditor/CommentPopover.js +92 -68
- package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
- package/dist/components/pro/RichTextEditor/RichTextEditor.js +24 -22
- package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
- package/dist/components/pro/RichTextEditor/SearchReplace.d.ts +7 -0
- package/dist/components/pro/RichTextEditor/SlashMenu.js +136 -73
- package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.d.ts +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js +346 -313
- package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js +114 -146
- package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CommentMark.js +2 -2
- package/dist/components/pro/RichTextEditor/extensions/CommentMark.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js +178 -163
- package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FontSize.js +8 -5
- package/dist/components/pro/RichTextEditor/extensions/FontSize.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.d.ts +6 -0
- package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js +85 -74
- package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
- package/dist/components/pro/RichTextEditor/searchUtils.d.ts +23 -0
- package/dist/contexts/AppContext.js +47 -45
- package/dist/contexts/AppContext.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/index-nostyled.d.ts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +119 -114
- package/dist/layouts/MainLayout.js +9 -10
- package/dist/layouts/MainLayout.js.map +1 -1
- package/dist/layouts/Sidebar.d.ts +9 -0
- package/dist/layouts/Sidebar.js +99 -80
- package/dist/layouts/Sidebar.js.map +1 -1
- package/dist/layouts/headbar/Headbar.d.ts +1 -1
- package/dist/layouts/headbar/Headbar.js +2 -2
- package/dist/layouts/headbar/Headbar.js.map +1 -1
- package/dist/lite.d.ts +19 -1
- package/dist/lite.js +17 -8
- package/dist/styles/themeStyles.js +6 -6
- package/dist/styles/themeStyles.js.map +1 -1
- package/dist/utils/i18n.d.ts +3 -0
- package/dist/utils/i18n.js +78 -0
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/menu.js +23 -6
- package/dist/utils/menu.js.map +1 -1
- package/package.json +8 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentPopover.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/CommentPopover.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { CommentThread, CommentItem } from './extensions/CommentMark';\n\nfunction generateId() {\n return `c_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction timeAgo(ts: number): string {\n const diff = Date.now() - ts;\n const sec = Math.floor(diff / 1000);\n if (sec < 60) return 'just now';\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const d = Math.floor(hr / 24);\n return `${d}d ago`;\n}\n\ninterface CommentPopoverProps {\n editor: Editor;\n threads: CommentThread[];\n onThreadsChange: (threads: CommentThread[]) => void;\n showPanel: boolean;\n onOpenPanel: () => void;\n onScrollToThread: (id: string) => void;\n currentUser?: string;\n}\n\nconst CommentPopover: React.FC<CommentPopoverProps> = ({\n editor,\n threads,\n onThreadsChange,\n showPanel,\n onOpenPanel,\n onScrollToThread,\n currentUser = 'User',\n}) => {\n const [activeThread, setActiveThread] = useState<CommentThread | null>(null);\n const [pos, setPos] = useState({ x: 0, y: 0 });\n const [replyText, setReplyText] = useState('');\n const popRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n const dom = editor.view.dom;\n const handleClick = (e: Event) => {\n const target = e.target as HTMLElement;\n const commentEl = target.closest('.rte-comment-mark') as HTMLElement | null;\n if (!commentEl) { setActiveThread(null); return; }\n\n const commentId = commentEl.getAttribute('data-comment-id');\n if (!commentId) return;\n\n const thread = threads.find((t) => t.id === commentId);\n if (!thread || thread.resolved) return;\n\n if (showPanel) {\n onScrollToThread(commentId);\n setActiveThread(null);\n return;\n }\n\n const wrapperEl = dom.closest('.rte-editor-wrapper');\n if (!wrapperEl) return;\n const wRect = wrapperEl.getBoundingClientRect();\n const elRect = commentEl.getBoundingClientRect();\n\n setPos({\n x: elRect.left - wRect.left + elRect.width / 2,\n y: elRect.bottom - wRect.top + 6,\n });\n setActiveThread(thread);\n setReplyText('');\n };\n\n dom.addEventListener('click', handleClick);\n return () => dom.removeEventListener('click', handleClick);\n }, [editor, threads, showPanel, onScrollToThread]);\n\n useEffect(() => {\n if (!activeThread) return;\n const handler = (e: MouseEvent) => {\n if (popRef.current && !popRef.current.contains(e.target as Node)) {\n setActiveThread(null);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [activeThread]);\n\n useEffect(() => {\n if (activeThread && inputRef.current) inputRef.current.focus();\n }, [activeThread]);\n\n const toggleResolve = useCallback(() => {\n if (!activeThread) return;\n const updated = threads.map((t) => {\n if (t.id !== activeThread.id) return t;\n editor.state.doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type.name === 'comment' && mark.attrs.commentId === activeThread.id) {\n editor.view.dispatch(\n editor.state.tr\n .removeMark(pos, pos + node.nodeSize, mark)\n .addMark(pos, pos + node.nodeSize, mark.type.create({ ...mark.attrs, resolved: true }))\n );\n }\n });\n });\n return { ...t, resolved: true };\n });\n onThreadsChange(updated);\n setActiveThread(null);\n }, [activeThread, editor, threads, onThreadsChange]);\n\n const addReply = useCallback(() => {\n if (!activeThread || !replyText.trim()) return;\n const reply: CommentItem = {\n id: generateId(),\n author: currentUser,\n text: replyText.trim(),\n createdAt: Date.now(),\n };\n const updated = threads.map((t) =>\n t.id === activeThread.id ? { ...t, comments: [...t.comments, reply] } : t\n );\n onThreadsChange(updated);\n setActiveThread(updated.find((t) => t.id === activeThread.id) || null);\n setReplyText('');\n }, [activeThread, replyText, threads, onThreadsChange, currentUser]);\n\n if (!activeThread) return null;\n\n return (\n <div ref={popRef} className=\"rte-comment-popover\" style={{ left: pos.x, top: pos.y }}>\n <div className=\"rte-comment-popover__header\">\n <span className=\"rte-comment-popover__status\">Open</span>\n <div className=\"rte-comment-popover__actions\">\n <button type=\"button\" className=\"rte-comments__icon-btn\" onClick={toggleResolve} title=\"Resolve\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><polyline points=\"20 6 9 17 4 12\" /></svg>\n </button>\n <button type=\"button\" className=\"rte-comments__icon-btn\" onClick={() => { onOpenPanel(); setActiveThread(null); }} title=\"Open panel\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><polyline points=\"15 3 21 3 21 9\" /><polyline points=\"9 21 3 21 3 15\" /><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" /><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" /></svg>\n </button>\n <button type=\"button\" className=\"rte-comments__icon-btn\" onClick={() => setActiveThread(null)} title=\"Close\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" /></svg>\n </button>\n </div>\n </div>\n\n {activeThread.comments.map((c) => (\n <div key={c.id} className=\"rte-comment-popover__comment\">\n <div className=\"rte-comments__comment-meta\">\n <span className=\"rte-comments__author\">{c.author}</span>\n <span className=\"rte-comments__time\">{timeAgo(c.createdAt)}</span>\n </div>\n <div className=\"rte-comments__comment-text\">{c.text}</div>\n </div>\n ))}\n\n <div className=\"rte-comment-popover__reply\">\n <input\n ref={inputRef}\n className=\"rte-comments__reply-input\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') addReply();\n if (e.key === 'Escape') setActiveThread(null);\n }}\n placeholder=\"Reply...\"\n />\n <button type=\"button\" className=\"rte-comments__reply-send\" onClick={addReply} disabled={!replyText.trim()}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" /><polygon points=\"22 2 15 22 11 13 2 9 22 2\" /></svg>\n </button>\n </div>\n </div>\n );\n};\n\nexport default CommentPopover;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CommentPopover.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/CommentPopover.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport type { CommentThread, CommentItem } from './extensions/CommentMark';\n\nfunction generateId() {\n return `c_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\nfunction timeAgo(ts: number): string {\n const diff = Date.now() - ts;\n const sec = Math.floor(diff / 1000);\n if (sec < 60) return 'just now';\n const min = Math.floor(sec / 60);\n if (min < 60) return `${min}m ago`;\n const hr = Math.floor(min / 60);\n if (hr < 24) return `${hr}h ago`;\n const d = Math.floor(hr / 24);\n return `${d}d ago`;\n}\n\ninterface CommentPopoverProps {\n editor: Editor;\n threads: CommentThread[];\n onThreadsChange: (threads: CommentThread[]) => void;\n showPanel: boolean;\n onOpenPanel: () => void;\n onScrollToThread: (id: string) => void;\n currentUser?: string;\n editable?: boolean;\n}\n\nconst CommentPopover: React.FC<CommentPopoverProps> = ({\n editor,\n threads,\n onThreadsChange,\n showPanel,\n onOpenPanel,\n onScrollToThread,\n currentUser = 'User',\n editable = true,\n}) => {\n const [activeThreadId, setActiveThreadId] = useState<string | null>(null);\n const activeThread = threads.find((t) => t.id === activeThreadId && !t.resolved);\n const latest = useRef({ editable, threads, activeThreadId });\n latest.current = { editable, threads, activeThreadId };\n const editorEditable = useEditorState({ editor, selector: ({ editor }) => editor.isEditable });\n const canEdit = editable && editorEditable;\n const [pos, setPos] = useState({ x: 0, y: 0 });\n const [replyText, setReplyText] = useState('');\n const popRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLInputElement>(null);\n\n useEffect(() => {\n const dom = editor.view.dom;\n const handleClick = (e: Event) => {\n const target = e.target as HTMLElement;\n const commentEl = target.closest('.rte-comment-mark') as HTMLElement | null;\n if (!commentEl) { setActiveThreadId(null); return; }\n\n const commentId = commentEl.getAttribute('data-comment-id');\n const thread = latest.current.threads.find((t) => t.id === commentId);\n if (!commentId || !thread || thread.resolved) { setActiveThreadId(null); return; }\n\n if (showPanel) {\n onScrollToThread(commentId);\n setActiveThreadId(null);\n return;\n }\n\n const wrapperEl = dom.closest('.rte-editor-wrapper');\n if (!wrapperEl) return;\n const wRect = wrapperEl.getBoundingClientRect();\n const elRect = commentEl.getBoundingClientRect();\n\n setPos({\n x: elRect.left - wRect.left + elRect.width / 2,\n y: elRect.bottom - wRect.top + 6,\n });\n setActiveThreadId(thread.id);\n setReplyText('');\n };\n\n dom.addEventListener('click', handleClick);\n return () => dom.removeEventListener('click', handleClick);\n }, [editor, threads, showPanel, onScrollToThread]);\n\n useEffect(() => {\n if (!activeThread) return;\n const handler = (e: MouseEvent) => {\n if (popRef.current && !popRef.current.contains(e.target as Node)) {\n setActiveThreadId(null);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [activeThread]);\n\n useEffect(() => {\n if (activeThreadId && inputRef.current) inputRef.current.focus();\n }, [activeThreadId, canEdit]);\n\n useEffect(() => {\n if (!activeThread || showPanel) {\n setActiveThreadId(null);\n setReplyText('');\n }\n }, [activeThread, showPanel]);\n\n const toggleResolve = useCallback(() => {\n if (!latest.current.editable || !editor.isEditable) return;\n const thread = latest.current.threads.find((t) => t.id === latest.current.activeThreadId && !t.resolved);\n if (!thread) return;\n const tr = editor.state.tr;\n editor.state.doc.descendants((node, pos) => {\n node.marks.forEach((mark) => {\n if (mark.type.name === 'comment' && mark.attrs.commentId === thread.id) {\n tr.removeMark(pos, pos + node.nodeSize, mark)\n .addMark(pos, pos + node.nodeSize, mark.type.create({ ...mark.attrs, resolved: true }));\n }\n });\n });\n if (tr.docChanged) editor.view.dispatch(tr);\n onThreadsChange(latest.current.threads.map((t) => t.id === thread.id ? { ...t, resolved: true } : t));\n setActiveThreadId(null);\n }, [activeThread, editor, threads, onThreadsChange]);\n\n const addReply = useCallback(() => {\n if (!latest.current.editable || !editor.isEditable || !replyText.trim()) return;\n const thread = latest.current.threads.find((t) => t.id === latest.current.activeThreadId && !t.resolved);\n if (!thread) return;\n const reply: CommentItem = {\n id: generateId(),\n author: currentUser,\n text: replyText.trim(),\n createdAt: Date.now(),\n };\n const updated = latest.current.threads.map((t) =>\n t.id === thread.id ? { ...t, comments: [...t.comments, reply] } : t\n );\n onThreadsChange(updated);\n setReplyText('');\n }, [editor, activeThread, replyText, threads, onThreadsChange, currentUser]);\n\n if (!activeThread || showPanel) return null;\n\n return (\n <div ref={popRef} className=\"rte-comment-popover\" style={{ left: pos.x, top: pos.y }}>\n <div className=\"rte-comment-popover__header\">\n <span className=\"rte-comment-popover__status\">Open</span>\n <div className=\"rte-comment-popover__actions\">\n {canEdit && <button type=\"button\" className=\"rte-comments__icon-btn\" onClick={toggleResolve} title=\"Resolve\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><polyline points=\"20 6 9 17 4 12\" /></svg>\n </button>}\n <button type=\"button\" className=\"rte-comments__icon-btn\" onClick={() => { onOpenPanel(); setActiveThreadId(null); }} title=\"Open panel\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><polyline points=\"15 3 21 3 21 9\" /><polyline points=\"9 21 3 21 3 15\" /><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" /><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" /></svg>\n </button>\n <button type=\"button\" className=\"rte-comments__icon-btn\" onClick={() => setActiveThreadId(null)} title=\"Close\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" /></svg>\n </button>\n </div>\n </div>\n\n {activeThread.comments.map((c) => (\n <div key={c.id} className=\"rte-comment-popover__comment\">\n <div className=\"rte-comments__comment-meta\">\n <span className=\"rte-comments__author\">{c.author}</span>\n <span className=\"rte-comments__time\">{timeAgo(c.createdAt)}</span>\n </div>\n <div className=\"rte-comments__comment-text\">{c.text}</div>\n </div>\n ))}\n\n {canEdit && <div className=\"rte-comment-popover__reply\">\n <input\n ref={inputRef}\n className=\"rte-comments__reply-input\"\n value={replyText}\n onChange={(e) => setReplyText(e.target.value)}\n onKeyDown={(e) => {\n if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return;\n if (e.key === 'Enter') { e.preventDefault(); addReply(); }\n if (e.key === 'Escape') setActiveThreadId(null);\n }}\n placeholder=\"Reply...\"\n />\n <button type=\"button\" className=\"rte-comments__reply-send\" onClick={addReply} disabled={!replyText.trim()}>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\" /><polygon points=\"22 2 15 22 11 13 2 9 22 2\" /></svg>\n </button>\n </div>}\n </div>\n );\n};\n\nexport default CommentPopover;\n"],"mappings":"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"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { cn as e } from "../../../utils/cn.js";
|
|
2
|
-
import {
|
|
3
|
-
import n from "./
|
|
4
|
-
import ee from "./
|
|
5
|
-
import r from "./
|
|
6
|
-
import i from "./
|
|
7
|
-
import a from "./
|
|
8
|
-
import o from "./
|
|
9
|
-
import s from "./
|
|
10
|
-
import c from "./
|
|
11
|
-
import te from "./
|
|
12
|
-
import
|
|
2
|
+
import { MarkdownBlockExtension as t } from "./extensions/MarkdownBlock.js";
|
|
3
|
+
import { FloatingDialogExtension as n } from "./extensions/FloatingDialog.js";
|
|
4
|
+
import ee from "./Toolbar/Toolbar.js";
|
|
5
|
+
import r from "./AIRewrite.js";
|
|
6
|
+
import i from "./ContextMenu.js";
|
|
7
|
+
import a from "./CommentPanel.js";
|
|
8
|
+
import o from "./CommentDialog.js";
|
|
9
|
+
import s from "./CommentPopover.js";
|
|
10
|
+
import c from "./SlashMenu.js";
|
|
11
|
+
import te from "./BubbleToolbar.js";
|
|
12
|
+
import ne from "./BlockHandle.js";
|
|
13
13
|
import { CodeBlockExtension as re } from "./extensions/CodeBlockView.js";
|
|
14
14
|
import ie from "./extensions/FontSize.js";
|
|
15
15
|
import { CommentMark as ae } from "./extensions/CommentMark.js";
|
|
@@ -58,7 +58,9 @@ var w = ({ content: w, value: T, onChange: E, onChangeJSON: D, placeholder: O =
|
|
|
58
58
|
4,
|
|
59
59
|
5,
|
|
60
60
|
6
|
|
61
|
-
] }
|
|
61
|
+
] },
|
|
62
|
+
link: !1,
|
|
63
|
+
underline: !1
|
|
62
64
|
}),
|
|
63
65
|
le,
|
|
64
66
|
ue,
|
|
@@ -87,8 +89,8 @@ var w = ({ content: w, value: T, onChange: E, onChangeJSON: D, placeholder: O =
|
|
|
87
89
|
x,
|
|
88
90
|
S,
|
|
89
91
|
ie,
|
|
92
|
+
n,
|
|
90
93
|
t,
|
|
91
|
-
ne,
|
|
92
94
|
ae
|
|
93
95
|
],
|
|
94
96
|
content: T || w || "",
|
|
@@ -193,7 +195,7 @@ var w = ({ content: w, value: T, onChange: E, onChangeJSON: D, placeholder: O =
|
|
|
193
195
|
maxHeight: Ie
|
|
194
196
|
},
|
|
195
197
|
children: [
|
|
196
|
-
k && !V && /* @__PURE__ */ f(
|
|
198
|
+
k && !V && /* @__PURE__ */ f(ee, {
|
|
197
199
|
editor: X,
|
|
198
200
|
config: j,
|
|
199
201
|
labels: I,
|
|
@@ -220,18 +222,18 @@ var w = ({ content: w, value: T, onChange: E, onChangeJSON: D, placeholder: O =
|
|
|
220
222
|
editor: X,
|
|
221
223
|
className: "rte-editor-content"
|
|
222
224
|
}),
|
|
223
|
-
k && /* @__PURE__ */ f(
|
|
225
|
+
k && /* @__PURE__ */ f(i, {
|
|
224
226
|
editor: X,
|
|
225
227
|
labels: I,
|
|
226
228
|
onAIClick: A ? Z : void 0
|
|
227
229
|
}),
|
|
228
|
-
k && /* @__PURE__ */ f(
|
|
229
|
-
k && V && /* @__PURE__ */ f(
|
|
230
|
+
k && /* @__PURE__ */ f(c, { editor: X }),
|
|
231
|
+
k && V && /* @__PURE__ */ f(te, {
|
|
230
232
|
editor: X,
|
|
231
233
|
onAddComment: Q
|
|
232
234
|
}),
|
|
233
|
-
k && V && /* @__PURE__ */ f(
|
|
234
|
-
/* @__PURE__ */ f(
|
|
235
|
+
k && V && /* @__PURE__ */ f(ne, { editor: X }),
|
|
236
|
+
/* @__PURE__ */ f(s, {
|
|
235
237
|
editor: X,
|
|
236
238
|
threads: J,
|
|
237
239
|
onThreadsChange: Y,
|
|
@@ -241,7 +243,7 @@ var w = ({ content: w, value: T, onChange: E, onChangeJSON: D, placeholder: O =
|
|
|
241
243
|
currentUser: z
|
|
242
244
|
})
|
|
243
245
|
]
|
|
244
|
-
}), U && /* @__PURE__ */ f(
|
|
246
|
+
}), U && /* @__PURE__ */ f(a, {
|
|
245
247
|
ref: q,
|
|
246
248
|
editor: X,
|
|
247
249
|
threads: J,
|
|
@@ -250,7 +252,7 @@ var w = ({ content: w, value: T, onChange: E, onChangeJSON: D, placeholder: O =
|
|
|
250
252
|
currentUser: z
|
|
251
253
|
})]
|
|
252
254
|
}),
|
|
253
|
-
A && we && /* @__PURE__ */ f(
|
|
255
|
+
A && we && /* @__PURE__ */ f(r, {
|
|
254
256
|
editor: X,
|
|
255
257
|
aiConfig: A,
|
|
256
258
|
labels: I,
|
|
@@ -258,7 +260,7 @@ var w = ({ content: w, value: T, onChange: E, onChangeJSON: D, placeholder: O =
|
|
|
258
260
|
selectionRange: De,
|
|
259
261
|
onClose: () => B(!1)
|
|
260
262
|
}),
|
|
261
|
-
/* @__PURE__ */ f(
|
|
263
|
+
/* @__PURE__ */ f(o, {
|
|
262
264
|
open: je,
|
|
263
265
|
onSubmit: Ne,
|
|
264
266
|
onClose: () => G(!1)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichTextEditor.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/RichTextEditor.tsx"],"sourcesContent":["import React, { useEffect, useCallback, useState, useRef } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { useEditor, EditorContent } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport Underline from '@tiptap/extension-underline';\nimport { TextStyle } from '@tiptap/extension-text-style';\nimport Color from '@tiptap/extension-color';\nimport Highlight from '@tiptap/extension-highlight';\nimport TextAlign from '@tiptap/extension-text-align';\nimport Link from '@tiptap/extension-link';\nimport Image from '@tiptap/extension-image';\nimport { Table } from '@tiptap/extension-table';\nimport TableRow from '@tiptap/extension-table-row';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport TaskList from '@tiptap/extension-task-list';\nimport TaskItem from '@tiptap/extension-task-item';\nimport Subscript from '@tiptap/extension-subscript';\nimport Superscript from '@tiptap/extension-superscript';\nimport Typography from '@tiptap/extension-typography';\nimport FontFamily from '@tiptap/extension-font-family';\n\nimport Toolbar from './Toolbar';\nimport AIRewrite from './AIRewrite';\nimport ContextMenu from './ContextMenu';\nimport CommentPanel from './CommentPanel';\nimport type { CommentPanelHandle } from './CommentPanel';\nimport CommentDialog from './CommentDialog';\nimport CommentPopover from './CommentPopover';\nimport SlashMenu from './SlashMenu';\nimport BubbleToolbar from './BubbleToolbar';\nimport BlockHandle from './BlockHandle';\nimport { MarkdownBlockExtension } from './extensions/MarkdownBlock';\nimport { CodeBlockExtension } from './extensions/CodeBlockView';\nimport FontSize from './extensions/FontSize';\nimport { FloatingDialogExtension } from './extensions/FloatingDialog';\nimport { CommentMark } from './extensions/CommentMark';\nimport type { CommentThread } from './extensions/CommentMark';\nimport type { RichTextEditorProps } from './types';\nimport './styles.css';\n\nfunction generateId() {\n return `c_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\nconst RichTextEditor: React.FC<RichTextEditorProps> = ({\n content,\n value,\n onChange,\n onChangeJSON,\n placeholder = 'Start writing...',\n editable = true,\n aiConfig,\n toolbarConfig,\n minHeight = '200px',\n maxHeight,\n className = '',\n autofocus = false,\n labels,\n editorRef,\n notionMode: initialNotionMode = false,\n showComments: initialShowComments = false,\n commentThreads: externalThreads,\n onCommentThreadsChange,\n currentUser,\n}) => {\n const [formatPainterActive, setFormatPainterActive] = useState(false);\n const [showAIPanel, setShowAIPanel] = useState(false);\n const [aiSelection, setAiSelection] = useState('');\n const [aiSelectionRange, setAiSelectionRange] = useState({ from: 0, to: 0 });\n const [notionMode, setNotionMode] = useState(initialNotionMode);\n const [showComments, setShowComments] = useState(initialShowComments);\n const [internalThreads, setInternalThreads] = useState<CommentThread[]>([]);\n const [commentDialogOpen, setCommentDialogOpen] = useState(false);\n const [commentSelectionRange, setCommentSelectionRange] = useState({ from: 0, to: 0 });\n const commentPanelRef = useRef<CommentPanelHandle>(null);\n\n const threads = externalThreads ?? internalThreads;\n const setThreads = onCommentThreadsChange ?? setInternalThreads;\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n codeBlock: false,\n heading: { levels: [1, 2, 3, 4, 5, 6] },\n }),\n Underline,\n TextStyle,\n Color,\n Highlight.configure({ multicolor: true }),\n TextAlign.configure({\n types: ['heading', 'paragraph'],\n }),\n Link.configure({\n openOnClick: false,\n autolink: true,\n HTMLAttributes: { class: 'rte-link' },\n }),\n Image.configure({ inline: false, allowBase64: true }),\n Table.configure({ resizable: true }),\n TableRow,\n TableCell,\n TableHeader,\n Placeholder.configure({ placeholder }),\n CodeBlockExtension,\n TaskList,\n TaskItem.configure({ nested: true }),\n Subscript,\n Superscript,\n Typography,\n FontFamily,\n FontSize,\n FloatingDialogExtension,\n MarkdownBlockExtension,\n CommentMark,\n ],\n content: value || content || '',\n editable,\n autofocus: autofocus ? 'end' : false,\n onUpdate: ({ editor: e }) => {\n onChange?.(e.getHTML());\n onChangeJSON?.(e.getJSON() as Record<string, unknown>);\n },\n });\n\n useEffect(() => {\n if (editorRef && editor) {\n editorRef.current = editor;\n }\n }, [editor, editorRef]);\n\n useEffect(() => {\n if (editor && value !== undefined) {\n const currentHTML = editor.getHTML();\n if (value !== currentHTML) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n }\n }, [editor, value]);\n\n useEffect(() => {\n if (editor) {\n editor.setEditable(editable);\n }\n }, [editor, editable]);\n\n const handleAIClick = useCallback(() => {\n if (!editor) return;\n const { from, to } = editor.state.selection;\n const text = from !== to\n ? editor.state.doc.textBetween(from, to, ' ')\n : '';\n setAiSelection(text);\n setAiSelectionRange({ from, to });\n setShowAIPanel(true);\n }, [editor]);\n\n const requestAddComment = useCallback(() => {\n if (!editor) return;\n const { from, to } = editor.state.selection;\n if (from === to) return;\n setCommentSelectionRange({ from, to });\n setCommentDialogOpen(true);\n }, [editor]);\n\n const handleCommentSubmit = useCallback((text: string) => {\n if (!editor) return;\n const id = generateId();\n const thread: CommentThread = {\n id,\n resolved: false,\n comments: [{\n id: generateId(),\n author: currentUser || 'User',\n text,\n createdAt: Date.now(),\n }],\n createdAt: Date.now(),\n };\n editor.chain()\n .focus()\n .setTextSelection(commentSelectionRange)\n .setComment(id)\n .run();\n setThreads([...threads, thread]);\n setCommentDialogOpen(false);\n }, [editor, commentSelectionRange, threads, setThreads, currentUser]);\n\n const handleScrollToThread = useCallback((id: string) => {\n commentPanelRef.current?.scrollToThread(id);\n }, []);\n\n if (!editor) return null;\n\n const minH = typeof minHeight === 'number' ? `${minHeight}px` : minHeight;\n const maxH = maxHeight ? (typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight) : undefined;\n\n const containerClass = cn(\n 'rte-container',\n formatPainterActive && 'rte-container--format-painter',\n notionMode && 'rte-container--notion',\n className,\n );\n\n const activeCommentCount = threads.filter((t) => !t.resolved).length;\n\n const modeToggle = (\n <div className=\"rte-mode-toggle\">\n <button\n type=\"button\"\n className={`rte-mode-toggle__btn ${!notionMode ? 'rte-mode-toggle__btn--active' : ''}`}\n onClick={() => setNotionMode(false)}\n title=\"Classic mode\"\n >\n Classic\n </button>\n <button\n type=\"button\"\n className={`rte-mode-toggle__btn ${notionMode ? 'rte-mode-toggle__btn--active' : ''}`}\n onClick={() => setNotionMode(true)}\n title=\"Notion-style mode\"\n >\n Notion\n </button>\n <div className=\"rte-toolbar__divider\" style={{ height: 20, margin: '0 4px' }} />\n <button\n type=\"button\"\n className={`rte-toolbar__btn rte-toolbar__comment-btn ${showComments ? 'rte-toolbar__btn--active' : ''}`}\n onClick={() => setShowComments(!showComments)}\n title=\"Toggle comments\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" />\n </svg>\n {activeCommentCount > 0 && <span className=\"rte-toolbar__comment-badge\" />}\n </button>\n </div>\n );\n\n return (\n <div className={containerClass} style={{ minHeight: minH, maxHeight: maxH }}>\n {editable && !notionMode && (\n <Toolbar\n editor={editor}\n config={toolbarConfig}\n labels={labels}\n hasAI={!!aiConfig}\n onAIClick={handleAIClick}\n onFormatPainterChange={setFormatPainterActive}\n >\n {modeToggle}\n </Toolbar>\n )}\n\n {editable && notionMode && (\n <div className=\"rte-notion-topbar\">\n {modeToggle}\n </div>\n )}\n\n <div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>\n <div className=\"rte-editor-wrapper\" style={{ flex: 1 }}>\n <EditorContent editor={editor} className=\"rte-editor-content\" />\n {editable && <ContextMenu editor={editor} labels={labels} onAIClick={aiConfig ? handleAIClick : undefined} />}\n {editable && <SlashMenu editor={editor} />}\n {editable && notionMode && <BubbleToolbar editor={editor} onAddComment={requestAddComment} />}\n {editable && notionMode && <BlockHandle editor={editor} />}\n <CommentPopover\n editor={editor}\n threads={threads}\n onThreadsChange={setThreads}\n showPanel={showComments}\n onOpenPanel={() => setShowComments(true)}\n onScrollToThread={handleScrollToThread}\n currentUser={currentUser}\n />\n </div>\n\n {showComments && (\n <CommentPanel\n ref={commentPanelRef}\n editor={editor}\n threads={threads}\n onThreadsChange={setThreads}\n onRequestAddComment={requestAddComment}\n currentUser={currentUser}\n />\n )}\n </div>\n\n {aiConfig && showAIPanel && (\n <AIRewrite\n editor={editor}\n aiConfig={aiConfig}\n labels={labels}\n initialSelection={aiSelection}\n selectionRange={aiSelectionRange}\n onClose={() => setShowAIPanel(false)}\n />\n )}\n\n <CommentDialog\n open={commentDialogOpen}\n onSubmit={handleCommentSubmit}\n onClose={() => setCommentDialogOpen(false)}\n />\n </div>\n );\n};\n\nexport default RichTextEditor;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,SAAS,IAAa;CACpB,OAAO,KAAK,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;AACjE;AAEA,IAAM,KAAiD,EACrD,YACA,UACA,aACA,iBACA,iBAAc,oBACd,cAAW,IACX,aACA,kBACA,eAAY,SACZ,cACA,eAAY,IACZ,eAAY,IACZ,WACA,cACA,YAAY,IAAoB,IAChC,cAAc,KAAsB,IACpC,gBAAgB,IAChB,4BACA,qBACI;CACJ,IAAM,CAAC,IAAqB,MAA0B,EAAS,EAAK,GAC9D,CAAC,IAAa,KAAkB,EAAS,EAAK,GAC9C,CAAC,IAAa,MAAkB,EAAS,EAAE,GAC3C,CAAC,IAAkB,MAAuB,EAAS;EAAE,MAAM;EAAG,IAAI;CAAE,CAAC,GACrE,CAAC,GAAY,KAAiB,EAAS,CAAiB,GACxD,CAAC,GAAc,KAAmB,EAAS,EAAmB,GAC9D,CAAC,IAAiB,MAAsB,EAA0B,CAAC,CAAC,GACpE,CAAC,IAAmB,KAAwB,EAAS,EAAK,GAC1D,CAAC,GAAuB,MAA4B,EAAS;EAAE,MAAM;EAAG,IAAI;CAAE,CAAC,GAC/E,IAAkB,GAA2B,IAAI,GAEjD,IAAU,MAAmB,IAC7B,IAAa,MAA0B,IAEvC,IAAS,GAAU;EACvB,YAAY;GACV,GAAW,UAAU;IACnB,WAAW;IACX,SAAS,EAAE,QAAQ;KAAC;KAAG;KAAG;KAAG;KAAG;KAAG;IAAC,EAAE;GACxC,CAAC;GACD;GACA;GACA;GACA,GAAU,UAAU,EAAE,YAAY,GAAK,CAAC;GACxC,GAAU,UAAU,EAClB,OAAO,CAAC,WAAW,WAAW,EAChC,CAAC;GACD,GAAK,UAAU;IACb,aAAa;IACb,UAAU;IACV,gBAAgB,EAAE,OAAO,WAAW;GACtC,CAAC;GACD,GAAM,UAAU;IAAE,QAAQ;IAAO,aAAa;GAAK,CAAC;GACpD,GAAM,UAAU,EAAE,WAAW,GAAK,CAAC;GACnC;GACA;GACA;GACA,EAAY,UAAU,EAAE,eAAY,CAAC;GACrC;GACA;GACA,EAAS,UAAU,EAAE,QAAQ,GAAK,CAAC;GACnC;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF;EACA,SAAS,KAAS,KAAW;EAC7B;EACA,WAAW,IAAY,QAAQ;EAC/B,WAAW,EAAE,QAAQ,QAAQ;GAE3B,AADA,IAAW,EAAE,QAAQ,CAAC,GACtB,IAAe,EAAE,QAAQ,CAA4B;EACvD;CACF,CAAC;CAiBD,AAfA,QAAgB;EACd,AAAI,KAAa,MACf,EAAU,UAAU;CAExB,GAAG,CAAC,GAAQ,CAAS,CAAC,GAEtB,QAAgB;EACd,AAAI,KAAU,MAAU,KAAA,KAElB,MADgB,EAAO,QACb,KACZ,EAAO,SAAS,WAAW,GAAO,EAAE,YAAY,GAAM,CAAC;CAG7D,GAAG,CAAC,GAAQ,CAAK,CAAC,GAElB,QAAgB;EACd,AAAI,KACF,EAAO,YAAY,CAAQ;CAE/B,GAAG,CAAC,GAAQ,CAAQ,CAAC;CAErB,IAAM,IAAgB,QAAkB;EACtC,IAAI,CAAC,GAAQ;EACb,IAAM,EAAE,SAAM,UAAO,EAAO,MAAM,WAC5B,IAAO,MAAS,IAElB,KADA,EAAO,MAAM,IAAI,YAAY,GAAM,GAAI,GAAG;EAI9C,AAFA,GAAe,CAAI,GACnB,GAAoB;GAAE;GAAM;EAAG,CAAC,GAChC,EAAe,EAAI;CACrB,GAAG,CAAC,CAAM,CAAC,GAEL,IAAoB,QAAkB;EAC1C,IAAI,CAAC,GAAQ;EACb,IAAM,EAAE,SAAM,UAAO,EAAO,MAAM;EAC9B,MAAS,MACb,GAAyB;GAAE;GAAM;EAAG,CAAC,GACrC,EAAqB,EAAI;CAC3B,GAAG,CAAC,CAAM,CAAC,GAEL,KAAsB,GAAa,MAAiB;EACxD,IAAI,CAAC,GAAQ;EACb,IAAM,IAAK,EAAW,GAChB,IAAwB;GAC5B;GACA,UAAU;GACV,UAAU,CAAC;IACT,IAAI,EAAW;IACf,QAAQ,KAAe;IACvB;IACA,WAAW,KAAK,IAAI;GACtB,CAAC;GACD,WAAW,KAAK,IAAI;EACtB;EAOA,AANA,EAAO,MAAM,CAAC,CACX,MAAM,CAAC,CACP,iBAAiB,CAAqB,CAAC,CACvC,WAAW,CAAE,CAAC,CACd,IAAI,GACP,EAAW,CAAC,GAAG,GAAS,CAAM,CAAC,GAC/B,EAAqB,EAAK;CAC5B,GAAG;EAAC;EAAQ;EAAuB;EAAS;EAAY;CAAW,CAAC,GAE9D,KAAuB,GAAa,MAAe;EACvD,EAAgB,SAAS,eAAe,CAAE;CAC5C,GAAG,CAAC,CAAC;CAEL,IAAI,CAAC,GAAQ,OAAO;CAEpB,IAAM,KAAO,OAAO,KAAc,WAAW,GAAG,EAAU,MAAM,GAC1D,KAAO,IAAa,OAAO,KAAc,WAAW,GAAG,EAAU,MAAM,IAAa,KAAA,GAEpF,KAAiB,EACrB,iBACA,MAAuB,iCACvB,KAAc,yBACd,CACF,GAEM,KAAqB,EAAQ,QAAQ,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,QAExD,IACJ,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,kBAAC,UAAD;IACE,MAAK;IACL,WAAW,wBAAyB,IAA8C,KAAjC;IACjD,eAAe,EAAc,EAAK;IAClC,OAAM;IACP,UAAA;GAEO,CAAA;GACR,kBAAC,UAAD;IACE,MAAK;IACL,WAAW,wBAAwB,IAAa,iCAAiC;IACjF,eAAe,EAAc,EAAI;IACjC,OAAM;IACP,UAAA;GAEO,CAAA;GACR,kBAAC,OAAD;IAAK,WAAU;IAAuB,OAAO;KAAE,QAAQ;KAAI,QAAQ;IAAQ;GAAI,CAAA;GAC/E,kBAAC,UAAD;IACE,MAAK;IACL,WAAW,6CAA6C,IAAe,6BAA6B;IACpG,eAAe,EAAgB,CAAC,CAAY;IAC5C,OAAM;IAJR,UAAA,CAME,kBAAC,OAAD;KAAK,OAAM;KAAK,QAAO;KAAK,SAAQ;KAAY,MAAK;KAAO,QAAO;KAAe,aAAY;KAAI,eAAc;KAAQ,gBAAe;KACrI,UAAA,kBAAC,QAAD,EAAM,GAAE,2DAA4D,CAAA;IACjE,CAAA,GACJ,KAAqB,KAAK,kBAAC,QAAD,EAAM,WAAU,6BAA8B,CAAA,CACnE;;EACL;;CAGP,OACE,kBAAC,OAAD;EAAK,WAAW;EAAgB,OAAO;GAAE,WAAW;GAAM,WAAW;EAAK;EAA1E,UAAA;GACG,KAAY,CAAC,KACZ,kBAAC,GAAD;IACU;IACR,QAAQ;IACA;IACR,OAAO,CAAC,CAAC;IACT,WAAW;IACX,uBAAuB;IAEtB,UAAA;GACM,CAAA;GAGV,KAAY,KACX,kBAAC,OAAD;IAAK,WAAU;IACZ,UAAA;GACE,CAAA;GAGP,kBAAC,OAAD;IAAK,OAAO;KAAE,SAAS;KAAQ,MAAM;KAAG,UAAU;IAAS;IAA3D,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;KAAqB,OAAO,EAAE,MAAM,EAAE;KAArD,UAAA;MACE,kBAAC,GAAD;OAAuB;OAAQ,WAAU;MAAsB,CAAA;MAC9D,KAAY,kBAAC,GAAD;OAAqB;OAAgB;OAAQ,WAAW,IAAW,IAAgB,KAAA;MAAY,CAAA;MAC3G,KAAY,kBAAC,GAAD,EAAmB,UAAS,CAAA;MACxC,KAAY,KAAc,kBAAC,GAAD;OAAuB;OAAQ,cAAc;MAAoB,CAAA;MAC3F,KAAY,KAAc,kBAAC,IAAD,EAAqB,UAAS,CAAA;MACzD,kBAAC,GAAD;OACU;OACC;OACT,iBAAiB;OACjB,WAAW;OACX,mBAAmB,EAAgB,EAAI;OACvC,kBAAkB;OACL;MACd,CAAA;KACE;IAEJ,CAAA,GAAA,KACC,kBAAC,GAAD;KACE,KAAK;KACG;KACC;KACT,iBAAiB;KACjB,qBAAqB;KACR;IACd,CAAA,CAEA;;GAEJ,KAAY,MACX,kBAAC,IAAD;IACU;IACE;IACF;IACR,kBAAkB;IAClB,gBAAgB;IAChB,eAAe,EAAe,EAAK;GACpC,CAAA;GAGH,kBAAC,GAAD;IACE,MAAM;IACN,UAAU;IACV,eAAe,EAAqB,EAAK;GAC1C,CAAA;EACE;;AAET"}
|
|
1
|
+
{"version":3,"file":"RichTextEditor.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/RichTextEditor.tsx"],"sourcesContent":["import React, { useEffect, useCallback, useState, useRef } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { useEditor, EditorContent } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport Underline from '@tiptap/extension-underline';\nimport { TextStyle } from '@tiptap/extension-text-style';\nimport Color from '@tiptap/extension-color';\nimport Highlight from '@tiptap/extension-highlight';\nimport TextAlign from '@tiptap/extension-text-align';\nimport Link from '@tiptap/extension-link';\nimport Image from '@tiptap/extension-image';\nimport { Table } from '@tiptap/extension-table';\nimport TableRow from '@tiptap/extension-table-row';\nimport TableCell from '@tiptap/extension-table-cell';\nimport TableHeader from '@tiptap/extension-table-header';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport TaskList from '@tiptap/extension-task-list';\nimport TaskItem from '@tiptap/extension-task-item';\nimport Subscript from '@tiptap/extension-subscript';\nimport Superscript from '@tiptap/extension-superscript';\nimport Typography from '@tiptap/extension-typography';\nimport FontFamily from '@tiptap/extension-font-family';\n\nimport Toolbar from './Toolbar';\nimport AIRewrite from './AIRewrite';\nimport ContextMenu from './ContextMenu';\nimport CommentPanel from './CommentPanel';\nimport type { CommentPanelHandle } from './CommentPanel';\nimport CommentDialog from './CommentDialog';\nimport CommentPopover from './CommentPopover';\nimport SlashMenu from './SlashMenu';\nimport BubbleToolbar from './BubbleToolbar';\nimport BlockHandle from './BlockHandle';\nimport { MarkdownBlockExtension } from './extensions/MarkdownBlock';\nimport { CodeBlockExtension } from './extensions/CodeBlockView';\nimport FontSize from './extensions/FontSize';\nimport { FloatingDialogExtension } from './extensions/FloatingDialog';\nimport { CommentMark } from './extensions/CommentMark';\nimport type { CommentThread } from './extensions/CommentMark';\nimport type { RichTextEditorProps } from './types';\nimport './styles.css';\n\nfunction generateId() {\n return `c_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n\nconst RichTextEditor: React.FC<RichTextEditorProps> = ({\n content,\n value,\n onChange,\n onChangeJSON,\n placeholder = 'Start writing...',\n editable = true,\n aiConfig,\n toolbarConfig,\n minHeight = '200px',\n maxHeight,\n className = '',\n autofocus = false,\n labels,\n editorRef,\n notionMode: initialNotionMode = false,\n showComments: initialShowComments = false,\n commentThreads: externalThreads,\n onCommentThreadsChange,\n currentUser,\n}) => {\n const [formatPainterActive, setFormatPainterActive] = useState(false);\n const [showAIPanel, setShowAIPanel] = useState(false);\n const [aiSelection, setAiSelection] = useState('');\n const [aiSelectionRange, setAiSelectionRange] = useState({ from: 0, to: 0 });\n const [notionMode, setNotionMode] = useState(initialNotionMode);\n const [showComments, setShowComments] = useState(initialShowComments);\n const [internalThreads, setInternalThreads] = useState<CommentThread[]>([]);\n const [commentDialogOpen, setCommentDialogOpen] = useState(false);\n const [commentSelectionRange, setCommentSelectionRange] = useState({ from: 0, to: 0 });\n const commentPanelRef = useRef<CommentPanelHandle>(null);\n\n const threads = externalThreads ?? internalThreads;\n const setThreads = onCommentThreadsChange ?? setInternalThreads;\n\n const editor = useEditor({\n extensions: [\n StarterKit.configure({\n codeBlock: false,\n heading: { levels: [1, 2, 3, 4, 5, 6] },\n // v3 StarterKit bundles these; explicit extensions below stay in charge.\n link: false,\n underline: false,\n }),\n Underline,\n TextStyle,\n Color,\n Highlight.configure({ multicolor: true }),\n TextAlign.configure({\n types: ['heading', 'paragraph'],\n }),\n Link.configure({\n openOnClick: false,\n autolink: true,\n HTMLAttributes: { class: 'rte-link' },\n }),\n Image.configure({ inline: false, allowBase64: true }),\n Table.configure({ resizable: true }),\n TableRow,\n TableCell,\n TableHeader,\n Placeholder.configure({ placeholder }),\n CodeBlockExtension,\n TaskList,\n TaskItem.configure({ nested: true }),\n Subscript,\n Superscript,\n Typography,\n FontFamily,\n FontSize,\n FloatingDialogExtension,\n MarkdownBlockExtension,\n CommentMark,\n ],\n content: value || content || '',\n editable,\n autofocus: autofocus ? 'end' : false,\n onUpdate: ({ editor: e }) => {\n onChange?.(e.getHTML());\n onChangeJSON?.(e.getJSON() as Record<string, unknown>);\n },\n });\n\n useEffect(() => {\n if (editorRef && editor) {\n editorRef.current = editor;\n }\n }, [editor, editorRef]);\n\n useEffect(() => {\n if (editor && value !== undefined) {\n const currentHTML = editor.getHTML();\n if (value !== currentHTML) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n }\n }, [editor, value]);\n\n useEffect(() => {\n if (editor) {\n editor.setEditable(editable);\n }\n }, [editor, editable]);\n\n const handleAIClick = useCallback(() => {\n if (!editor) return;\n const { from, to } = editor.state.selection;\n const text = from !== to\n ? editor.state.doc.textBetween(from, to, ' ')\n : '';\n setAiSelection(text);\n setAiSelectionRange({ from, to });\n setShowAIPanel(true);\n }, [editor]);\n\n const requestAddComment = useCallback(() => {\n if (!editor) return;\n const { from, to } = editor.state.selection;\n if (from === to) return;\n setCommentSelectionRange({ from, to });\n setCommentDialogOpen(true);\n }, [editor]);\n\n const handleCommentSubmit = useCallback((text: string) => {\n if (!editor) return;\n const id = generateId();\n const thread: CommentThread = {\n id,\n resolved: false,\n comments: [{\n id: generateId(),\n author: currentUser || 'User',\n text,\n createdAt: Date.now(),\n }],\n createdAt: Date.now(),\n };\n editor.chain()\n .focus()\n .setTextSelection(commentSelectionRange)\n .setComment(id)\n .run();\n setThreads([...threads, thread]);\n setCommentDialogOpen(false);\n }, [editor, commentSelectionRange, threads, setThreads, currentUser]);\n\n const handleScrollToThread = useCallback((id: string) => {\n commentPanelRef.current?.scrollToThread(id);\n }, []);\n\n if (!editor) return null;\n\n const minH = typeof minHeight === 'number' ? `${minHeight}px` : minHeight;\n const maxH = maxHeight ? (typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight) : undefined;\n\n const containerClass = cn(\n 'rte-container',\n formatPainterActive && 'rte-container--format-painter',\n notionMode && 'rte-container--notion',\n className,\n );\n\n const activeCommentCount = threads.filter((t) => !t.resolved).length;\n\n const modeToggle = (\n <div className=\"rte-mode-toggle\">\n <button\n type=\"button\"\n className={`rte-mode-toggle__btn ${!notionMode ? 'rte-mode-toggle__btn--active' : ''}`}\n onClick={() => setNotionMode(false)}\n title=\"Classic mode\"\n >\n Classic\n </button>\n <button\n type=\"button\"\n className={`rte-mode-toggle__btn ${notionMode ? 'rte-mode-toggle__btn--active' : ''}`}\n onClick={() => setNotionMode(true)}\n title=\"Notion-style mode\"\n >\n Notion\n </button>\n <div className=\"rte-toolbar__divider\" style={{ height: 20, margin: '0 4px' }} />\n <button\n type=\"button\"\n className={`rte-toolbar__btn rte-toolbar__comment-btn ${showComments ? 'rte-toolbar__btn--active' : ''}`}\n onClick={() => setShowComments(!showComments)}\n title=\"Toggle comments\"\n >\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" />\n </svg>\n {activeCommentCount > 0 && <span className=\"rte-toolbar__comment-badge\" />}\n </button>\n </div>\n );\n\n return (\n <div className={containerClass} style={{ minHeight: minH, maxHeight: maxH }}>\n {editable && !notionMode && (\n <Toolbar\n editor={editor}\n config={toolbarConfig}\n labels={labels}\n hasAI={!!aiConfig}\n onAIClick={handleAIClick}\n onFormatPainterChange={setFormatPainterActive}\n >\n {modeToggle}\n </Toolbar>\n )}\n\n {editable && notionMode && (\n <div className=\"rte-notion-topbar\">\n {modeToggle}\n </div>\n )}\n\n <div style={{ display: 'flex', flex: 1, overflow: 'hidden' }}>\n <div className=\"rte-editor-wrapper\" style={{ flex: 1 }}>\n <EditorContent editor={editor} className=\"rte-editor-content\" />\n {editable && <ContextMenu editor={editor} labels={labels} onAIClick={aiConfig ? handleAIClick : undefined} />}\n {editable && <SlashMenu editor={editor} />}\n {editable && notionMode && <BubbleToolbar editor={editor} onAddComment={requestAddComment} />}\n {editable && notionMode && <BlockHandle editor={editor} />}\n <CommentPopover\n editor={editor}\n threads={threads}\n onThreadsChange={setThreads}\n showPanel={showComments}\n onOpenPanel={() => setShowComments(true)}\n onScrollToThread={handleScrollToThread}\n currentUser={currentUser}\n />\n </div>\n\n {showComments && (\n <CommentPanel\n ref={commentPanelRef}\n editor={editor}\n threads={threads}\n onThreadsChange={setThreads}\n onRequestAddComment={requestAddComment}\n currentUser={currentUser}\n />\n )}\n </div>\n\n {aiConfig && showAIPanel && (\n <AIRewrite\n editor={editor}\n aiConfig={aiConfig}\n labels={labels}\n initialSelection={aiSelection}\n selectionRange={aiSelectionRange}\n onClose={() => setShowAIPanel(false)}\n />\n )}\n\n <CommentDialog\n open={commentDialogOpen}\n onSubmit={handleCommentSubmit}\n onClose={() => setCommentDialogOpen(false)}\n />\n </div>\n );\n};\n\nexport default RichTextEditor;\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useCallback as e, useEffect as t,
|
|
2
|
-
import { jsx as
|
|
1
|
+
import { useCallback as e, useEffect as t, useLayoutEffect as n, useRef as r, useState as i } from "react";
|
|
2
|
+
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
3
|
+
import { TextSelection as s } from "@tiptap/pm/state";
|
|
3
4
|
//#region src/components/pro/RichTextEditor/SlashMenu.tsx
|
|
4
|
-
var
|
|
5
|
+
var c = [
|
|
5
6
|
{
|
|
6
7
|
label: "Text",
|
|
7
8
|
icon: "Aa",
|
|
@@ -11,28 +12,28 @@ var o = [
|
|
|
11
12
|
"text",
|
|
12
13
|
"plain"
|
|
13
14
|
],
|
|
14
|
-
action: (e) => e.
|
|
15
|
+
action: (e) => e.setParagraph()
|
|
15
16
|
},
|
|
16
17
|
{
|
|
17
18
|
label: "Heading 1",
|
|
18
19
|
icon: "H1",
|
|
19
20
|
description: "Large heading",
|
|
20
21
|
keywords: ["h1", "title"],
|
|
21
|
-
action: (e) => e.
|
|
22
|
+
action: (e) => e.setHeading({ level: 1 })
|
|
22
23
|
},
|
|
23
24
|
{
|
|
24
25
|
label: "Heading 2",
|
|
25
26
|
icon: "H2",
|
|
26
27
|
description: "Medium heading",
|
|
27
28
|
keywords: ["h2", "subtitle"],
|
|
28
|
-
action: (e) => e.
|
|
29
|
+
action: (e) => e.setHeading({ level: 2 })
|
|
29
30
|
},
|
|
30
31
|
{
|
|
31
32
|
label: "Heading 3",
|
|
32
33
|
icon: "H3",
|
|
33
34
|
description: "Small heading",
|
|
34
35
|
keywords: ["h3"],
|
|
35
|
-
action: (e) => e.
|
|
36
|
+
action: (e) => e.setHeading({ level: 3 })
|
|
36
37
|
},
|
|
37
38
|
{
|
|
38
39
|
label: "Bullet List",
|
|
@@ -43,7 +44,7 @@ var o = [
|
|
|
43
44
|
"bullet",
|
|
44
45
|
"unordered"
|
|
45
46
|
],
|
|
46
|
-
action: (e) => e.
|
|
47
|
+
action: (e) => e.toggleBulletList()
|
|
47
48
|
},
|
|
48
49
|
{
|
|
49
50
|
label: "Numbered List",
|
|
@@ -54,7 +55,7 @@ var o = [
|
|
|
54
55
|
"ordered",
|
|
55
56
|
"number"
|
|
56
57
|
],
|
|
57
|
-
action: (e) => e.
|
|
58
|
+
action: (e) => e.toggleOrderedList()
|
|
58
59
|
},
|
|
59
60
|
{
|
|
60
61
|
label: "Task List",
|
|
@@ -65,14 +66,14 @@ var o = [
|
|
|
65
66
|
"checkbox",
|
|
66
67
|
"task"
|
|
67
68
|
],
|
|
68
|
-
action: (e) => e.
|
|
69
|
+
action: (e) => e.toggleTaskList()
|
|
69
70
|
},
|
|
70
71
|
{
|
|
71
72
|
label: "Blockquote",
|
|
72
73
|
icon: "\"",
|
|
73
74
|
description: "Quote block",
|
|
74
75
|
keywords: ["quote", "blockquote"],
|
|
75
|
-
action: (e) => e.
|
|
76
|
+
action: (e) => e.toggleBlockquote()
|
|
76
77
|
},
|
|
77
78
|
{
|
|
78
79
|
label: "Code Block",
|
|
@@ -83,7 +84,7 @@ var o = [
|
|
|
83
84
|
"pre",
|
|
84
85
|
"snippet"
|
|
85
86
|
],
|
|
86
|
-
action: (e) => e.
|
|
87
|
+
action: (e) => e.setNode("codeBlock")
|
|
87
88
|
},
|
|
88
89
|
{
|
|
89
90
|
label: "Divider",
|
|
@@ -95,18 +96,18 @@ var o = [
|
|
|
95
96
|
"separator",
|
|
96
97
|
"line"
|
|
97
98
|
],
|
|
98
|
-
action: (e) => e.
|
|
99
|
+
action: (e) => e.setHorizontalRule()
|
|
99
100
|
},
|
|
100
101
|
{
|
|
101
102
|
label: "Table",
|
|
102
103
|
icon: "⊞",
|
|
103
104
|
description: "Insert 3×3 table",
|
|
104
105
|
keywords: ["table", "grid"],
|
|
105
|
-
action: (e) => e.
|
|
106
|
+
action: (e) => e.insertTable({
|
|
106
107
|
rows: 3,
|
|
107
108
|
cols: 3,
|
|
108
109
|
withHeaderRow: !0
|
|
109
|
-
})
|
|
110
|
+
})
|
|
110
111
|
},
|
|
111
112
|
{
|
|
112
113
|
label: "Image",
|
|
@@ -117,93 +118,155 @@ var o = [
|
|
|
117
118
|
"picture",
|
|
118
119
|
"photo"
|
|
119
120
|
],
|
|
120
|
-
action: (e) =>
|
|
121
|
-
let t = window.prompt("Image URL:");
|
|
122
|
-
t && e.chain().focus().setImage({ src: t }).run();
|
|
123
|
-
}
|
|
121
|
+
action: (e) => e
|
|
124
122
|
}
|
|
125
|
-
],
|
|
126
|
-
let [
|
|
123
|
+
], l = ({ editor: l }) => {
|
|
124
|
+
let [u, d] = i(!1), [f, p] = i(""), [m, h] = i({
|
|
127
125
|
x: 0,
|
|
128
126
|
y: 0
|
|
129
|
-
}), [
|
|
130
|
-
|
|
127
|
+
}), [g, _] = i(0), v = r(null), y = r(null), b = r(null), x = r(!1), S = e(() => {
|
|
128
|
+
if (l.isDestroyed || !l.isEditable || l.view.composing || x.current) return null;
|
|
129
|
+
let e = l.state.selection;
|
|
130
|
+
if (!(e instanceof s) || !e.empty || e.$from.parent.type.spec.code || e.$from.marks().some((e) => e.type.spec.code)) return null;
|
|
131
|
+
let { $from: t } = e, n = t.parent.textBetween(0, t.parentOffset, "\n", (e) => e.type.name === "hardBreak" ? "\n" : ""), r = /(?:^|\s)\/([^\s/]*)$/.exec(n);
|
|
132
|
+
return r ? {
|
|
133
|
+
from: t.pos - r[1].length - 1,
|
|
134
|
+
to: t.pos,
|
|
135
|
+
query: r[1]
|
|
136
|
+
} : null;
|
|
137
|
+
}, [l]), C = f ? c.filter((e) => {
|
|
138
|
+
let t = f.toLowerCase();
|
|
131
139
|
return e.label.toLowerCase().includes(t) || e.description.toLowerCase().includes(t) || e.keywords?.some((e) => e.includes(t));
|
|
132
|
-
}) :
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
}) : c, w = e(() => {
|
|
141
|
+
d(!1), p("");
|
|
142
|
+
let e = y.current;
|
|
143
|
+
e && (b.current = `${e.from}:${e.to}:${e.query}`), y.current = null, _(0);
|
|
144
|
+
}, []), T = e((e) => {
|
|
145
|
+
let t = S(), n = y.current;
|
|
146
|
+
if (!t || !n || t.from !== n.from || t.to !== n.to || t.query !== n.query) {
|
|
147
|
+
w();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
let r = e.label === "Image" ? window.prompt("Image URL:")?.trim() : void 0;
|
|
151
|
+
if (e.label === "Image" && !r) {
|
|
152
|
+
w();
|
|
153
|
+
return;
|
|
141
154
|
}
|
|
142
|
-
|
|
155
|
+
w();
|
|
156
|
+
let i = l.chain().focus().deleteRange(t);
|
|
157
|
+
(r ? i.setImage({ src: r }) : e.action(i)).run();
|
|
143
158
|
}, [
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
159
|
+
l,
|
|
160
|
+
S,
|
|
161
|
+
w
|
|
147
162
|
]);
|
|
148
163
|
return t(() => {
|
|
149
|
-
let e = () => {
|
|
150
|
-
let
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
164
|
+
let e, t = () => {
|
|
165
|
+
let e = l.isFocused ? S() : null;
|
|
166
|
+
if (!e) {
|
|
167
|
+
y.current = null, b.current = null, d(!1);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
b.current !== `${e.from}:${e.to}:${e.query}` && ((y.current?.query !== e.query || y.current?.from !== e.from) && _(0), y.current = e, p(e.query), d(!0));
|
|
171
|
+
}, n = () => {
|
|
172
|
+
x.current = !0, w();
|
|
173
|
+
}, r = () => {
|
|
174
|
+
x.current = !1, b.current = null, e = setTimeout(t, 0);
|
|
175
|
+
}, i = l.view.dom;
|
|
176
|
+
return l.on("transaction", t), l.on("blur", w), i.addEventListener("compositionstart", n), i.addEventListener("compositionend", r), () => {
|
|
177
|
+
clearTimeout(e), l.off("transaction", t), l.off("blur", w), i.removeEventListener("compositionstart", n), i.removeEventListener("compositionend", r);
|
|
160
178
|
};
|
|
161
|
-
|
|
162
|
-
|
|
179
|
+
}, [
|
|
180
|
+
l,
|
|
181
|
+
S,
|
|
182
|
+
w
|
|
183
|
+
]), n(() => {
|
|
184
|
+
if (!u || !C.length) return;
|
|
185
|
+
let e = l.view.dom.closest(".rte-editor-wrapper"), t = v.current;
|
|
186
|
+
if (!e || !t) return;
|
|
187
|
+
let n = () => {
|
|
188
|
+
let n = S();
|
|
189
|
+
if (!n) {
|
|
190
|
+
w();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
let r = l.view.coordsAtPos(n.to), i = e.getBoundingClientRect(), a = Math.max(8, i.left + e.clientLeft), o = Math.min(window.innerWidth - 8, i.right), s = Math.max(8, i.top + e.clientTop), c = Math.min(window.innerHeight - 8, i.bottom);
|
|
194
|
+
if (r.bottom < s || r.top > c) {
|
|
195
|
+
w();
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
t.style.minWidth = "0", t.style.width = `${Math.max(0, Math.min(280, o - a))}px`;
|
|
199
|
+
let u = c - r.bottom - 4, d = r.top - s - 4, f = u < Math.min(300, t.scrollHeight) && d > u;
|
|
200
|
+
t.style.maxHeight = `${Math.max(0, Math.min(300, f ? d : u))}px`;
|
|
201
|
+
let p = Math.max(a, Math.min(r.left, o - t.offsetWidth)), m = f ? r.top - t.offsetHeight - 4 : r.bottom + 4;
|
|
202
|
+
h({
|
|
203
|
+
x: p - i.left - e.clientLeft + e.scrollLeft,
|
|
204
|
+
y: m - i.top - e.clientTop + e.scrollTop
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
return n(), window.addEventListener("scroll", n, !0), window.addEventListener("resize", n), l.on("transaction", n), () => {
|
|
208
|
+
window.removeEventListener("scroll", n, !0), window.removeEventListener("resize", n), l.off("transaction", n);
|
|
163
209
|
};
|
|
164
210
|
}, [
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
211
|
+
l,
|
|
212
|
+
u,
|
|
213
|
+
C.length,
|
|
214
|
+
S,
|
|
215
|
+
w
|
|
168
216
|
]), t(() => {
|
|
169
|
-
if (!
|
|
217
|
+
if (!u) return;
|
|
218
|
+
let e = v.current, t = e?.children[g];
|
|
219
|
+
e && t && (t.offsetTop < e.scrollTop ? e.scrollTop = t.offsetTop : t.offsetTop + t.offsetHeight > e.scrollTop + e.clientHeight && (e.scrollTop = t.offsetTop + t.offsetHeight - e.clientHeight));
|
|
220
|
+
}, [g, u]), t(() => {
|
|
221
|
+
if (!u) return;
|
|
170
222
|
let e = (e) => {
|
|
171
|
-
|
|
223
|
+
!l.view.dom.contains(e.target) || !l.isFocused || e.isComposing || e.keyCode === 229 || l.view.composing || x.current || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey || (C.length || e.key === "Escape") && ([
|
|
224
|
+
"ArrowDown",
|
|
225
|
+
"ArrowUp",
|
|
226
|
+
"Enter",
|
|
227
|
+
"Escape"
|
|
228
|
+
].includes(e.key) && e.stopImmediatePropagation(), e.key === "ArrowDown" ? (e.preventDefault(), _((e) => (e + 1) % C.length)) : e.key === "ArrowUp" ? (e.preventDefault(), _((e) => (e - 1 + C.length) % C.length)) : e.key === "Enter" ? (e.preventDefault(), C[g] && T(C[g])) : e.key === "Escape" && (e.preventDefault(), w()));
|
|
172
229
|
};
|
|
173
230
|
return document.addEventListener("keydown", e, !0), () => document.removeEventListener("keydown", e, !0);
|
|
174
231
|
}, [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
232
|
+
l,
|
|
233
|
+
u,
|
|
234
|
+
C,
|
|
235
|
+
g,
|
|
236
|
+
T,
|
|
237
|
+
w
|
|
180
238
|
]), t(() => {
|
|
181
|
-
if (!
|
|
239
|
+
if (!u) return;
|
|
182
240
|
let e = (e) => {
|
|
183
|
-
v.current && !v.current.contains(e.target) &&
|
|
241
|
+
v.current && !v.current.contains(e.target) && w();
|
|
184
242
|
};
|
|
185
243
|
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
|
|
186
|
-
}, [
|
|
244
|
+
}, [u, w]), !u || C.length === 0 ? null : /* @__PURE__ */ a("div", {
|
|
187
245
|
ref: v,
|
|
188
246
|
className: "rte-slash-menu",
|
|
247
|
+
role: "menu",
|
|
248
|
+
"aria-label": "Insert block",
|
|
189
249
|
style: {
|
|
190
|
-
left:
|
|
191
|
-
top:
|
|
250
|
+
left: m.x,
|
|
251
|
+
top: m.y
|
|
192
252
|
},
|
|
193
|
-
|
|
253
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
254
|
+
children: C.map((e, t) => /* @__PURE__ */ o("button", {
|
|
194
255
|
type: "button",
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
256
|
+
role: "menuitem",
|
|
257
|
+
tabIndex: -1,
|
|
258
|
+
className: `rte-slash-menu__item ${t === g ? "rte-slash-menu__item--active" : ""}`,
|
|
259
|
+
onClick: () => T(e),
|
|
260
|
+
onMouseEnter: () => _(t),
|
|
261
|
+
children: [/* @__PURE__ */ a("span", {
|
|
199
262
|
className: "rte-slash-menu__icon",
|
|
200
263
|
children: e.icon
|
|
201
|
-
}), /* @__PURE__ */
|
|
264
|
+
}), /* @__PURE__ */ o("div", {
|
|
202
265
|
className: "rte-slash-menu__text",
|
|
203
|
-
children: [/* @__PURE__ */
|
|
266
|
+
children: [/* @__PURE__ */ a("span", {
|
|
204
267
|
className: "rte-slash-menu__label",
|
|
205
268
|
children: e.label
|
|
206
|
-
}), /* @__PURE__ */
|
|
269
|
+
}), /* @__PURE__ */ a("span", {
|
|
207
270
|
className: "rte-slash-menu__desc",
|
|
208
271
|
children: e.description
|
|
209
272
|
})]
|
|
@@ -212,6 +275,6 @@ var o = [
|
|
|
212
275
|
});
|
|
213
276
|
};
|
|
214
277
|
//#endregion
|
|
215
|
-
export {
|
|
278
|
+
export { l as default };
|
|
216
279
|
|
|
217
280
|
//# sourceMappingURL=SlashMenu.js.map
|