dishui 0.0.97 → 0.0.104

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.
Files changed (84) hide show
  1. package/dist/.release-verified.json +2 -2
  2. package/dist/ai.js +17 -15
  3. package/dist/components/Card/Ticket.d.ts +52 -0
  4. package/dist/components/Card/Ticket2.js +218 -0
  5. package/dist/components/Card/Ticket2.js.map +1 -0
  6. package/dist/components/Card/index.d.ts +12 -0
  7. package/dist/components/Card/index.js +142 -139
  8. package/dist/components/Card/index.js.map +1 -1
  9. package/dist/components/ai/AgentRunCard/index.d.ts +38 -0
  10. package/dist/components/ai/AgentRunCard/index.js +100 -0
  11. package/dist/components/ai/AgentRunCard/index.js.map +1 -0
  12. package/dist/components/ai/IssueCard/index.d.ts +39 -0
  13. package/dist/components/ai/IssueCard/index.js +78 -0
  14. package/dist/components/ai/IssueCard/index.js.map +1 -0
  15. package/dist/components/ai/index.d.ts +4 -0
  16. package/dist/components/pro/Flow/constants.js +3 -3
  17. package/dist/components/pro/Flow/constants.js.map +1 -1
  18. package/dist/components/pro/Flow/context/FlowAIContext.d.ts +2 -0
  19. package/dist/components/pro/Flow/context/FlowAIContext.js +9 -4
  20. package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -1
  21. package/dist/components/pro/Flow/nodes/MediaContent.d.ts +3 -2
  22. package/dist/components/pro/Flow/nodes/MediaContent.js +16 -16
  23. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  24. package/dist/components/pro/Flow/nodes/MediaOverlay.js +25 -23
  25. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  26. package/dist/components/pro/Flow/nodes/shapes.js +3 -3
  27. package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
  28. package/dist/components/pro/Flow/panels/InspectorPanel.js +396 -384
  29. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  30. package/dist/components/pro/Flow/utils/themeColor.d.ts +2 -2
  31. package/dist/components/pro/Flow/utils/themeColor.js +2 -2
  32. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -1
  33. package/dist/components/pro/Kanban/Kanban.d.ts +3 -0
  34. package/dist/components/pro/Kanban/Kanban.js +339 -0
  35. package/dist/components/pro/Kanban/Kanban.js.map +1 -0
  36. package/dist/components/pro/Kanban/Swimlanes.d.ts +3 -0
  37. package/dist/components/pro/Kanban/Swimlanes.js +60 -0
  38. package/dist/components/pro/Kanban/Swimlanes.js.map +1 -0
  39. package/dist/components/pro/Kanban/index.d.ts +5 -0
  40. package/dist/components/pro/Kanban/types.d.ts +103 -0
  41. package/dist/components/pro/Kanban/useKanbanDrag.d.ts +17 -0
  42. package/dist/components/pro/Kanban/useKanbanDrag.js +69 -0
  43. package/dist/components/pro/Kanban/useKanbanDrag.js.map +1 -0
  44. package/dist/components/pro/Kanban/utils.d.ts +13 -0
  45. package/dist/components/pro/Kanban/utils.js +48 -0
  46. package/dist/components/pro/Kanban/utils.js.map +1 -0
  47. package/dist/components/pro/RichTextEditor/AIRewrite.js +158 -127
  48. package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
  49. package/dist/components/pro/RichTextEditor/BlockHandle.d.ts +2 -0
  50. package/dist/components/pro/RichTextEditor/BlockHandle.js +156 -115
  51. package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
  52. package/dist/components/pro/RichTextEditor/RichTextEditor.js +136 -159
  53. package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
  54. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js +44 -41
  55. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
  56. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js +59 -53
  57. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
  58. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js +48 -44
  59. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
  60. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js +67 -63
  61. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
  62. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.d.ts +1 -0
  63. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js +182 -129
  64. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
  65. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.d.ts +1 -0
  66. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js +3 -3
  67. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js.map +1 -1
  68. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.d.ts +3 -0
  69. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js +31 -0
  70. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js.map +1 -0
  71. package/dist/components/pro/RichTextEditor/index.d.ts +1 -1
  72. package/dist/components/pro/RichTextEditor/types.d.ts +78 -11
  73. package/dist/components/pro/RichTextEditor/types.js +11 -0
  74. package/dist/components/pro/RichTextEditor/types.js.map +1 -1
  75. package/dist/dishui.css +1 -1
  76. package/dist/index-nostyled.d.ts +1 -1
  77. package/dist/index.d.ts +4 -2
  78. package/dist/index.js +128 -122
  79. package/dist/kanban.js +5 -0
  80. package/dist/utils/i18n.js +20 -0
  81. package/dist/utils/i18n.js.map +1 -1
  82. package/dist/utils/menu.js +1 -1
  83. package/dist/utils/menu.js.map +1 -1
  84. package/package.json +5 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AIRewrite.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/AIRewrite.tsx"],"sourcesContent":["import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { AIConfig, AIAction, RichTextEditorLabels } from './types';\nimport { defaultLabels } from './types';\n\ninterface AIRewriteProps {\n editor: Editor;\n aiConfig: AIConfig;\n labels?: RichTextEditorLabels;\n initialSelection: string;\n selectionRange: { from: number; to: number };\n onClose: () => void;\n}\n\nconst QUICK_ACTIONS: { key: AIAction; labelKey: keyof RichTextEditorLabels; icon: string }[] = [\n { key: 'rewrite', labelKey: 'aiRewrite', icon: '✏' },\n { key: 'shorten', labelKey: 'aiShorten', icon: '📝' },\n { key: 'expand', labelKey: 'aiExpand', icon: '📄' },\n { key: 'fix_grammar', labelKey: 'aiFixGrammar', icon: '✓' },\n { key: 'translate_en', labelKey: 'aiTranslateEn', icon: 'EN' },\n { key: 'translate_zh', labelKey: 'aiTranslateZh', icon: '中' },\n { key: 'professional', labelKey: 'aiProfessional', icon: '💼' },\n { key: 'casual', labelKey: 'aiCasual', icon: '💬' },\n];\n\nfunction getSystemPrompt(action: AIAction | 'custom', customPrompt?: string): string {\n if (action === 'custom') return customPrompt || 'Follow the user instructions.';\n const prompts: Record<AIAction, string> = {\n rewrite: 'Rewrite the following text to improve clarity and readability. Keep the same meaning and tone. Return only the rewritten text.',\n shorten: 'Shorten the following text while preserving its key meaning. Be concise. Return only the shortened text.',\n expand: 'Expand the following text with more details and examples while keeping the same tone. Return only the expanded text.',\n fix_grammar: 'Fix any grammar, spelling, and punctuation errors in the following text. Return only the corrected text.',\n translate_en: 'Translate the following text to English. Return only the translated text.',\n translate_zh: 'Translate the following text to Chinese. Return only the translated text.',\n professional: 'Rewrite the following text in a professional, formal tone. Return only the rewritten text.',\n casual: 'Rewrite the following text in a casual, friendly tone. Return only the rewritten text.',\n };\n return customPrompt || prompts[action];\n}\n\nasync function* readSSE(response: Response): AsyncGenerator<string> {\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n const decoder = new TextDecoder();\n let buffer = '';\n let data: string[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n // Normalize CRLF only when the complete line is available (chunks may split it).\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newline).replace(/\\r$/, '');\n buffer = buffer.slice(newline + 1);\n if (!line) {\n if (data.length) yield data.join('\\n');\n data = [];\n } else if (line.startsWith('data:')) {\n data.push(line.slice(5).replace(/^ /, ''));\n }\n }\n if (done) {\n if (buffer.startsWith('data:')) data.push(buffer.slice(5).replace(/^ /, '').replace(/\\r$/, ''));\n if (data.length) yield data.join('\\n');\n return;\n }\n }\n } finally {\n try { await reader.cancel(); } catch { /* The request may already be aborted. */ }\n reader.releaseLock();\n }\n}\n\nasync function* streamOpenAI(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: text },\n ],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n for await (const payload of readSSE(response)) {\n if (payload.trim() === '[DONE]') return;\n let data;\n try { data = JSON.parse(payload); } catch { continue; }\n if (data?.error) throw new Error(data.error.message || 'AI stream error');\n const content = data?.choices?.[0]?.delta?.content;\n if (typeof content === 'string') yield content;\n }\n}\n\nasync function* streamAnthropic(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const body = JSON.stringify({\n model: config.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: text }],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),\n 'anthropic-version': '2023-06-01',\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n for await (const payload of readSSE(response)) {\n let data;\n try { data = JSON.parse(payload); } catch { continue; }\n if (data?.type === 'error') throw new Error(data.error?.message || 'AI stream error');\n if (data?.type === 'message_stop') return;\n if (data?.type === 'content_block_delta' && typeof data.delta?.text === 'string') yield data.delta.text;\n }\n}\n\nfunction getStream(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n action: AIAction | 'custom',\n signal: AbortSignal,\n): AsyncIterable<string> {\n if (config.protocol === 'custom') {\n if (!config.customHandler) throw new Error('Custom AI protocol requires customHandler');\n return config.customHandler({ text, action: action === 'custom' ? 'rewrite' : action, signal });\n }\n if (config.protocol === 'anthropic') return streamAnthropic(config, text, systemPrompt, signal);\n return streamOpenAI(config, text, systemPrompt, signal);\n}\n\nconst AIRewrite: React.FC<AIRewriteProps> = ({ editor, aiConfig, labels: propsLabels, initialSelection, selectionRange, onClose }) => {\n const labels = { ...defaultLabels, ...propsLabels };\n const [prompt, setPrompt] = useState('');\n const [isProcessing, setIsProcessing] = useState(false);\n const [streamedText, setStreamedText] = useState('');\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const promptRef = useRef<HTMLTextAreaElement>(null);\n const [editable, setEditable] = useState(() => !editor.isDestroyed && editor.isEditable);\n const [invalid, setInvalid] = useState(false);\n const sourceDoc = useRef(editor.state.doc);\n const invalidRef = useRef(false);\n\n const cancelRequest = useCallback(() => {\n const request = abortRef.current;\n abortRef.current = null;\n request?.abort();\n }, []);\n\n useEffect(() => {\n sourceDoc.current = editor.state.doc;\n invalidRef.current = false;\n setInvalid(false);\n setStreamedText('');\n setIsProcessing(false);\n setError(null);\n const invalidate = () => {\n setEditable(!editor.isDestroyed && editor.isEditable);\n if (editor.isDestroyed || !editor.isEditable || editor.state.doc !== sourceDoc.current) {\n invalidRef.current = true;\n setInvalid(true);\n cancelRequest();\n setIsProcessing(false);\n setStreamedText('');\n setError('The document or editing permissions changed. Close and reopen AI Assistant.');\n }\n };\n invalidate();\n editor.on('update', invalidate);\n editor.on('transaction', invalidate);\n editor.on('destroy', invalidate);\n return () => {\n cancelRequest();\n editor.off('update', invalidate);\n editor.off('transaction', invalidate);\n editor.off('destroy', invalidate);\n };\n }, [editor, initialSelection, selectionRange.from, selectionRange.to, cancelRequest]);\n\n const selectedText = initialSelection;\n\n useEffect(() => {\n if (promptRef.current) promptRef.current.focus();\n }, []);\n\n const handleGenerate = useCallback(async (action: AIAction | 'custom' = 'custom', customPromptOverride?: string) => {\n if (editor.isDestroyed || !editor.isEditable || invalidRef.current || abortRef.current) return;\n const text = selectedText || editor.state.doc.textContent;\n if (!text.trim() && !prompt.trim()) return;\n\n const systemPrompt = action === 'custom'\n ? (prompt || 'Improve the following text. Return only the improved text.')\n : getSystemPrompt(action, customPromptOverride);\n\n const userText = action === 'custom' && prompt\n ? `Instructions: ${prompt}\\n\\nText:\\n${text}`\n : text;\n\n setIsProcessing(true);\n setStreamedText('');\n setError(null);\n\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n let result = '';\n for await (const chunk of getStream(aiConfig, userText, systemPrompt, action, abort.signal)) {\n if (abort.signal.aborted || abortRef.current !== abort) break;\n result += chunk;\n setStreamedText(result);\n }\n } catch (err: unknown) {\n if (abort.signal.aborted || abortRef.current !== abort) return;\n setStreamedText('');\n setError(String(err instanceof Error ? err.message : err));\n } finally {\n if (abortRef.current === abort) {\n abortRef.current = null;\n setIsProcessing(false);\n }\n }\n }, [editor, aiConfig, selectedText, prompt]);\n\n const handleAccept = useCallback(() => {\n if (!streamedText || abortRef.current || editor.isDestroyed || !editor.isEditable || invalidRef.current) return;\n const { from, to } = selectionRange;\n if (editor.state.doc !== sourceDoc.current || !Number.isInteger(from) || !Number.isInteger(to) || from < 0 || to < from || to > editor.state.doc.content.size) {\n setError('The original selection is no longer valid. Close and reopen AI Assistant.');\n return;\n }\n // AI output is plain text, never HTML. Use the captured range even if the cursor moved.\n editor.view.dispatch(editor.state.tr.insertText(streamedText, from, to));\n setStreamedText('');\n setPrompt('');\n onClose();\n }, [editor, streamedText, selectionRange, onClose]);\n\n const handleReject = useCallback(() => {\n cancelRequest();\n setStreamedText('');\n setIsProcessing(false);\n setError(null);\n }, [cancelRequest]);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleGenerate();\n }\n }, [handleGenerate]);\n\n return (\n <div className=\"rte-ai-panel-v2\">\n <div className=\"rte-ai-panel-v2__header\">\n <span className=\"rte-ai-panel-v2__title\">✨ {labels.ai || 'AI Assistant'}</span>\n <button type=\"button\" className=\"rte-ai-panel-v2__close-btn\" onClick={() => { cancelRequest(); onClose(); }} title=\"Close\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n {/* Prompt input */}\n <div className=\"rte-ai-panel-v2__prompt-section\">\n <label className=\"rte-ai-panel-v2__label\">Prompt</label>\n <textarea\n ref={promptRef}\n className=\"rte-ai-panel-v2__prompt-input\"\n value={prompt}\n onChange={(e) => setPrompt(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Describe what AI should do... (Ctrl+Enter to generate)\"\n rows={3}\n disabled={isProcessing || !editable || invalid}\n />\n </div>\n\n {/* Selected text display */}\n <div className=\"rte-ai-panel-v2__selection-section\">\n <label className=\"rte-ai-panel-v2__label\">Selected Text</label>\n <div className=\"rte-ai-panel-v2__selection-box\">\n {selectedText ? (\n <span>{selectedText.length > 300 ? selectedText.slice(0, 300) + '...' : selectedText}</span>\n ) : (\n <span className=\"rte-ai-panel-v2__empty\">No text selected (will use all content)</span>\n )}\n </div>\n </div>\n\n {/* Quick actions */}\n <div className=\"rte-ai-panel-v2__quick-actions\">\n {QUICK_ACTIONS.map(({ key, labelKey, icon }) => (\n <button\n key={key}\n type=\"button\"\n className=\"rte-ai-panel-v2__quick-btn\"\n onClick={() => handleGenerate(key)}\n disabled={isProcessing || !editable || invalid}\n title={labels[labelKey]}\n >\n <span>{icon}</span>\n <span>{labels[labelKey]}</span>\n </button>\n ))}\n </div>\n\n {/* Generate button */}\n <div className=\"rte-ai-panel-v2__actions\">\n <button\n type=\"button\"\n className=\"rte-ai-panel-v2__generate-btn\"\n onClick={() => handleGenerate()}\n disabled={isProcessing || !editable || invalid || (!prompt.trim() && !selectedText.trim())}\n >\n {isProcessing ? (\n <><div className=\"rte-ai-panel__spinner\" /> {labels.aiProcessing}</>\n ) : (\n '✨ Generate'\n )}\n </button>\n {isProcessing && (\n <button type=\"button\" className=\"rte-ai-panel-v2__cancel-btn\" onClick={handleReject}>\n Cancel\n </button>\n )}\n </div>\n\n {/* Streaming result */}\n {streamedText && (\n <div className=\"rte-ai-panel-v2__result\">\n <label className=\"rte-ai-panel-v2__label\">Result</label>\n <div className=\"rte-ai-panel-v2__result-text\">{streamedText}</div>\n <div className=\"rte-ai-panel-v2__result-actions\">\n <button type=\"button\" className=\"rte-ai-panel-v2__accept-btn\" disabled={isProcessing || !editable || invalid} onClick={handleAccept}>\n {labels.aiAccept}\n </button>\n <button type=\"button\" className=\"rte-ai-panel-v2__reject-btn\" onClick={handleReject}>\n {labels.aiReject}\n </button>\n </div>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"rte-ai-panel-v2__error\">\n <span>{error}</span>\n <button type=\"button\" onClick={() => setError(null)}>Dismiss</button>\n </div>\n )}\n </div>\n );\n};\n\nexport default AIRewrite;\n"],"mappings":"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"}
1
+ {"version":3,"file":"AIRewrite.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/AIRewrite.tsx"],"sourcesContent":["import React, { useState, useRef, useCallback, useEffect, useId } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { AIConfig, AIAction, RichTextEditorLabels } from './types';\nimport { defaultLabels } from './types';\nimport StreamingText from '../../ai/StreamingText';\nimport LoadingState from '../../ai/LoadingState';\n\ninterface AIRewriteProps {\n editor: Editor;\n aiConfig: AIConfig;\n labels?: RichTextEditorLabels;\n initialSelection: string;\n selectionRange: { from: number; to: number };\n onClose: () => void;\n}\n\nconst QUICK_ACTIONS: { key: AIAction; labelKey: keyof RichTextEditorLabels; icon: string }[] = [\n { key: 'rewrite', labelKey: 'aiRewrite', icon: '✏' },\n { key: 'shorten', labelKey: 'aiShorten', icon: '📝' },\n { key: 'expand', labelKey: 'aiExpand', icon: '📄' },\n { key: 'fix_grammar', labelKey: 'aiFixGrammar', icon: '✓' },\n { key: 'translate_en', labelKey: 'aiTranslateEn', icon: 'EN' },\n { key: 'translate_zh', labelKey: 'aiTranslateZh', icon: '中' },\n { key: 'professional', labelKey: 'aiProfessional', icon: '💼' },\n { key: 'casual', labelKey: 'aiCasual', icon: '💬' },\n];\n\nfunction getSystemPrompt(action: AIAction | 'custom', customPrompt?: string): string {\n if (action === 'custom') return customPrompt || 'Follow the user instructions.';\n const prompts: Record<AIAction, string> = {\n rewrite: 'Rewrite the following text to improve clarity and readability. Keep the same meaning and tone. Return only the rewritten text.',\n shorten: 'Shorten the following text while preserving its key meaning. Be concise. Return only the shortened text.',\n expand: 'Expand the following text with more details and examples while keeping the same tone. Return only the expanded text.',\n fix_grammar: 'Fix any grammar, spelling, and punctuation errors in the following text. Return only the corrected text.',\n translate_en: 'Translate the following text to English. Return only the translated text.',\n translate_zh: 'Translate the following text to Chinese. Return only the translated text.',\n professional: 'Rewrite the following text in a professional, formal tone. Return only the rewritten text.',\n casual: 'Rewrite the following text in a casual, friendly tone. Return only the rewritten text.',\n };\n return customPrompt || prompts[action];\n}\n\nasync function* readSSE(response: Response): AsyncGenerator<string> {\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No response body');\n const decoder = new TextDecoder();\n let buffer = '';\n let data: string[] = [];\n try {\n while (true) {\n const { done, value } = await reader.read();\n buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n // Normalize CRLF only when the complete line is available (chunks may split it).\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, newline).replace(/\\r$/, '');\n buffer = buffer.slice(newline + 1);\n if (!line) {\n if (data.length) yield data.join('\\n');\n data = [];\n } else if (line.startsWith('data:')) {\n data.push(line.slice(5).replace(/^ /, ''));\n }\n }\n if (done) {\n if (buffer.startsWith('data:')) data.push(buffer.slice(5).replace(/^ /, '').replace(/\\r$/, ''));\n if (data.length) yield data.join('\\n');\n return;\n }\n }\n } finally {\n try { await reader.cancel(); } catch { /* The request may already be aborted. */ }\n reader.releaseLock();\n }\n}\n\nasync function* streamOpenAI(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n if (!config.gateway || !config.model) throw new Error('OpenAI protocol requires gateway and model');\n const body = JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: text },\n ],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}),\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n for await (const payload of readSSE(response)) {\n if (payload.trim() === '[DONE]') return;\n let data;\n try { data = JSON.parse(payload); } catch { continue; }\n if (data?.error) throw new Error(data.error.message || 'AI stream error');\n const content = data?.choices?.[0]?.delta?.content;\n if (typeof content === 'string') yield content;\n }\n}\n\nasync function* streamAnthropic(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n if (!config.gateway || !config.model) throw new Error('Anthropic protocol requires gateway and model');\n const body = JSON.stringify({\n model: config.model,\n max_tokens: 4096,\n system: systemPrompt,\n messages: [{ role: 'user', content: text }],\n stream: true,\n });\n\n const response = await fetch(config.gateway, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(config.apiKey ? { 'x-api-key': config.apiKey } : {}),\n 'anthropic-version': '2023-06-01',\n ...config.headers,\n },\n body,\n signal,\n });\n\n if (!response.ok) throw new Error(`AI API error: ${response.status} ${response.statusText}`);\n for await (const payload of readSSE(response)) {\n let data;\n try { data = JSON.parse(payload); } catch { continue; }\n if (data?.type === 'error') throw new Error(data.error?.message || 'AI stream error');\n if (data?.type === 'message_stop') return;\n if (data?.type === 'content_block_delta' && typeof data.delta?.text === 'string') yield data.delta.text;\n }\n}\n\nfunction getStream(\n config: AIConfig,\n text: string,\n systemPrompt: string,\n action: AIAction | 'custom',\n signal: AbortSignal,\n request?: { prompt: string; selectedText: string; mode: 'replace' | 'insert' },\n): AsyncIterable<string> {\n if (config.protocol === 'custom') {\n if (!config.customHandler) throw new Error('Custom AI protocol requires customHandler');\n return config.customHandler({\n text,\n action: action === 'custom' ? 'rewrite' : action,\n systemPrompt,\n signal,\n prompt: request?.prompt ?? '',\n selectedText: request?.selectedText ?? text,\n mode: request?.mode ?? 'replace',\n });\n }\n if (config.protocol === 'anthropic') return streamAnthropic(config, text, systemPrompt, signal);\n return streamOpenAI(config, text, systemPrompt, signal);\n}\n\nconst AIRewrite: React.FC<AIRewriteProps> = ({ editor, aiConfig, labels: propsLabels, initialSelection, selectionRange, onClose }) => {\n const labels = { ...defaultLabels, ...propsLabels };\n const promptId = useId();\n const [prompt, setPrompt] = useState('');\n const [isProcessing, setIsProcessing] = useState(false);\n const [streamedText, setStreamedText] = useState('');\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const promptRef = useRef<HTMLTextAreaElement>(null);\n const [editable, setEditable] = useState(() => !editor.isDestroyed && editor.isEditable);\n const [invalid, setInvalid] = useState(false);\n const sourceDoc = useRef(editor.state.doc);\n const invalidRef = useRef(false);\n\n const cancelRequest = useCallback(() => {\n const request = abortRef.current;\n abortRef.current = null;\n request?.abort();\n }, []);\n\n useEffect(() => {\n sourceDoc.current = editor.state.doc;\n invalidRef.current = false;\n setInvalid(false);\n setStreamedText('');\n setIsProcessing(false);\n setError(null);\n const invalidate = () => {\n setEditable(!editor.isDestroyed && editor.isEditable);\n if (editor.isDestroyed || !editor.isEditable || editor.state.doc !== sourceDoc.current) {\n invalidRef.current = true;\n setInvalid(true);\n cancelRequest();\n setIsProcessing(false);\n setStreamedText('');\n setError('The document or editing permissions changed. Close and reopen AI Assistant.');\n }\n };\n invalidate();\n editor.on('update', invalidate);\n editor.on('transaction', invalidate);\n editor.on('destroy', invalidate);\n return () => {\n cancelRequest();\n editor.off('update', invalidate);\n editor.off('transaction', invalidate);\n editor.off('destroy', invalidate);\n };\n }, [editor, initialSelection, selectionRange.from, selectionRange.to, cancelRequest]);\n\n const selectedText = initialSelection;\n\n useEffect(() => {\n if (promptRef.current) promptRef.current.focus();\n }, []);\n\n const handleGenerate = useCallback(async (action: AIAction | 'custom' = 'custom', customPromptOverride?: string) => {\n if (editor.isDestroyed || !editor.isEditable || invalidRef.current || abortRef.current) return;\n const mode = selectedText ? 'replace' : 'insert';\n if (mode === 'insert' && !prompt.trim()) return;\n\n const actionPrompt = action === 'custom'\n ? (mode === 'replace'\n ? 'Edit the selected text according to the user instruction. Return only the replacement text.'\n : 'Generate text according to the user instruction. Return only the text to insert.')\n : getSystemPrompt(action, customPromptOverride);\n const systemPrompt = [aiConfig.systemPrompt, actionPrompt].filter(Boolean).join('\\n\\n');\n const userText = mode === 'replace'\n ? (prompt.trim()\n ? `Instruction:\\n${prompt.trim()}\\n\\nSelected text:\\n${selectedText}`\n : selectedText)\n : prompt.trim();\n\n setIsProcessing(true);\n setStreamedText('');\n setError(null);\n\n const abort = new AbortController();\n abortRef.current = abort;\n\n try {\n let result = '';\n for await (const chunk of getStream(aiConfig, userText, systemPrompt, action, abort.signal, {\n prompt: prompt.trim(),\n selectedText,\n mode,\n })) {\n if (abort.signal.aborted || abortRef.current !== abort) break;\n result += chunk;\n setStreamedText(result);\n }\n } catch (err: unknown) {\n if (abort.signal.aborted || abortRef.current !== abort) return;\n setStreamedText('');\n setError(String(err instanceof Error ? err.message : err));\n } finally {\n if (abortRef.current === abort) {\n abortRef.current = null;\n setIsProcessing(false);\n }\n }\n }, [editor, aiConfig, selectedText, prompt]);\n\n const handleAccept = useCallback(() => {\n if (!streamedText || abortRef.current || editor.isDestroyed || !editor.isEditable || invalidRef.current) return;\n const { from, to } = selectionRange;\n if (editor.state.doc !== sourceDoc.current || !Number.isInteger(from) || !Number.isInteger(to) || from < 0 || to < from || to > editor.state.doc.content.size) {\n setError('The original selection is no longer valid. Close and reopen AI Assistant.');\n return;\n }\n // AI output is plain text, never HTML. Use the captured range even if the cursor moved.\n editor.view.dispatch(editor.state.tr.insertText(streamedText, from, to));\n setStreamedText('');\n setPrompt('');\n onClose();\n }, [editor, streamedText, selectionRange, onClose]);\n\n const handleReject = useCallback(() => {\n cancelRequest();\n setStreamedText('');\n setIsProcessing(false);\n setError(null);\n }, [cancelRequest]);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleGenerate();\n }\n }, [handleGenerate]);\n\n return (\n <div className=\"rte-ai-panel-v2\">\n <div className=\"rte-ai-panel-v2__header\">\n <span className=\"rte-ai-panel-v2__title\">✨ {labels.ai || 'AI Assistant'}</span>\n <button type=\"button\" className=\"rte-ai-panel-v2__close-btn\" onClick={() => { cancelRequest(); onClose(); }} title={labels.aiClose} aria-label={labels.aiClose}>\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" /><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n {/* Prompt input */}\n <div className=\"rte-ai-panel-v2__prompt-section\">\n <label className=\"rte-ai-panel-v2__label\" htmlFor={promptId}>{labels.aiPromptLabel}</label>\n <textarea\n id={promptId}\n ref={promptRef}\n className=\"rte-ai-panel-v2__prompt-input\"\n value={prompt}\n onChange={(e) => setPrompt(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={labels.aiPromptPlaceholder}\n rows={3}\n disabled={isProcessing || !editable || invalid}\n />\n </div>\n\n {/* Selected text display */}\n <div className=\"rte-ai-panel-v2__selection-section\">\n <span className=\"rte-ai-panel-v2__label\">{labels.aiSelectedText}</span>\n <div className=\"rte-ai-panel-v2__selection-box\">\n {selectedText ? (\n <span>{selectedText.length > 300 ? selectedText.slice(0, 300) + '...' : selectedText}</span>\n ) : (\n <span className=\"rte-ai-panel-v2__empty\">{labels.aiInsertHint}</span>\n )}\n </div>\n </div>\n\n {/* Quick actions */}\n <div className=\"rte-ai-panel-v2__quick-actions\">\n {QUICK_ACTIONS.map(({ key, labelKey, icon }) => (\n <button\n key={key}\n type=\"button\"\n className=\"rte-ai-panel-v2__quick-btn\"\n onClick={() => handleGenerate(key)}\n disabled={isProcessing || !editable || invalid || !selectedText.trim()}\n title={selectedText ? labels[labelKey] : labels.aiInsertHint}\n >\n <span>{icon}</span>\n <span>{labels[labelKey]}</span>\n </button>\n ))}\n </div>\n\n {/* Generate button */}\n <div className=\"rte-ai-panel-v2__actions\">\n <button\n type=\"button\"\n className=\"rte-ai-panel-v2__generate-btn\"\n onClick={() => handleGenerate()}\n disabled={isProcessing || !editable || invalid || (!prompt.trim() && !selectedText.trim())}\n >\n {isProcessing ? labels.aiProcessing : `✨ ${labels.aiGenerate}`}\n </button>\n {isProcessing && (\n <button type=\"button\" className=\"rte-ai-panel-v2__cancel-btn\" onClick={handleReject}>\n {labels.aiCancel}\n </button>\n )}\n </div>\n\n {/* Streaming result */}\n {isProcessing && !streamedText && (\n <LoadingState\n className=\"rte-ai-panel-v2__loading\"\n label={labels.aiProcessing}\n variant=\"dots\"\n layout=\"block\"\n size=\"sm\"\n />\n )}\n {streamedText && (\n <div className=\"rte-ai-panel-v2__result\">\n <div className=\"rte-ai-panel-v2__result-header\">\n <span className=\"rte-ai-panel-v2__label\">{labels.aiResult}</span>\n <span className={`rte-ai-panel-v2__stream-status ${isProcessing ? 'rte-ai-panel-v2__stream-status--live' : ''}`} role=\"status\">\n <span className=\"rte-ai-panel-v2__stream-dot\" aria-hidden=\"true\" />\n {isProcessing ? labels.aiProcessing : `${streamedText.length} chars`}\n </span>\n </div>\n <div className=\"rte-ai-panel-v2__result-text\">\n <StreamingText text={streamedText} streaming={isProcessing} />\n </div>\n <div className=\"rte-ai-panel-v2__result-actions\">\n <button type=\"button\" className=\"rte-ai-panel-v2__accept-btn\" disabled={isProcessing || !editable || invalid} onClick={handleAccept}>\n {labels.aiAccept}\n </button>\n <button type=\"button\" className=\"rte-ai-panel-v2__reject-btn\" onClick={handleReject}>\n {labels.aiReject}\n </button>\n </div>\n </div>\n )}\n\n {/* Error */}\n {error && (\n <div className=\"rte-ai-panel-v2__error\">\n <span>{error}</span>\n <button type=\"button\" onClick={() => setError(null)}>{labels.aiDismiss}</button>\n </div>\n )}\n </div>\n );\n};\n\nexport default AIRewrite;\n"],"mappings":"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"}
@@ -2,6 +2,8 @@ import React from 'react';
2
2
  import type { Editor } from '@tiptap/react';
3
3
  interface BlockHandleProps {
4
4
  editor: Editor;
5
+ /** Keep the left control rail visible instead of revealing it only on hover. */
6
+ persistent?: boolean;
5
7
  }
6
8
  declare const BlockHandle: React.FC<BlockHandleProps>;
7
9
  export default BlockHandle;
@@ -2,21 +2,21 @@ import { useCallback as e, useEffect as t, useLayoutEffect as n, useRef as r, us
2
2
  import { Fragment as a, jsx as o, jsxs as s } from "react/jsx-runtime";
3
3
  import { NodeSelection as c, Selection as l } from "@tiptap/pm/state";
4
4
  //#region src/components/pro/RichTextEditor/BlockHandle.tsx
5
- var u = ({ editor: u }) => {
6
- let [d, f] = i(!1), [p, m] = i(0), [h, g] = i(!1), [_, v] = i("add"), [y, b] = i({
5
+ var u = ({ editor: u, persistent: d = !1 }) => {
6
+ let [f, p] = i(!1), [m, h] = i(0), [g, _] = i(!1), [v, y] = i("add"), [b, x] = i({
7
7
  left: 4,
8
8
  top: 0
9
- }), x = r(null), S = r(null), C = r(!1), [w, T] = i(-1), [E, D] = i(!1), [O, k] = i(null), A = r(null), j = r(null), M = r(null), N = r(!1), P = e(() => {
10
- M.current &&= (clearTimeout(M.current), null);
11
- }, []), F = e(() => {
12
- P(), M.current = setTimeout(() => {
13
- !N.current && !h && !E && !j.current?.contains(document.activeElement) && !A.current?.contains(document.activeElement) && f(!1);
9
+ }), S = r(null), C = r(null), w = r(!1), [T, E] = i(-1), [D, O] = i(!1), [k, A] = i(null), j = r(null), M = r(null), N = r(null), P = r(!1), F = e(() => {
10
+ N.current &&= (clearTimeout(N.current), null);
11
+ }, []), I = e(() => {
12
+ F(), N.current = setTimeout(() => {
13
+ !P.current && !g && !D && !M.current?.contains(document.activeElement) && !j.current?.contains(document.activeElement) && p(!1);
14
14
  }, 200);
15
15
  }, [
16
- P,
17
- h,
18
- E
19
- ]), I = e(() => {
16
+ F,
17
+ g,
18
+ D
19
+ ]), L = e(() => {
20
20
  if (u.isDestroyed) return [];
21
21
  let e = u.view.dom.closest(".rte-editor-wrapper");
22
22
  if (!e) return [];
@@ -33,76 +33,102 @@ var u = ({ editor: u }) => {
33
33
  });
34
34
  }
35
35
  }), r;
36
- }, [u]), L = e((e) => {
36
+ }, [u]), R = e((e) => {
37
37
  let t = u.view.dom.closest(".rte-editor-wrapper");
38
38
  if (!t) return -1;
39
39
  let n = e - t.getBoundingClientRect().top - t.clientTop + t.scrollTop;
40
- return I().findIndex((e) => n >= e.domTop && n <= e.domBottom);
41
- }, [u, I]), R = e((e) => {
40
+ return L().findIndex((e) => n >= e.domTop && n <= e.domBottom);
41
+ }, [u, L]), z = e((e) => {
42
+ let t = L(), n = R(e);
43
+ if (n < 0 || n >= t.length) return !1;
44
+ let r = t[n], i = u.state.doc.nodeAt(r.pos);
45
+ return i ? (S.current = {
46
+ pos: r.pos,
47
+ node: i
48
+ }, E(n), h(r.domTop), p(!0), !0) : !1;
49
+ }, [
50
+ u,
51
+ R,
52
+ L
53
+ ]), B = e((e) => {
42
54
  let t = u.view.dom.closest(".rte-editor-wrapper");
43
55
  if (!t) return null;
44
- let n = e - t.getBoundingClientRect().top - t.clientTop + t.scrollTop, r = I();
56
+ let n = e - t.getBoundingClientRect().top - t.clientTop + t.scrollTop, r = L();
45
57
  if (r.length === 0) return null;
46
- let i = 0, a = Infinity, o = r[0].domTop;
58
+ let i = S.current, a = i ? r.findIndex((e) => e.pos === i.pos) : -1, o = r.findIndex((e) => n >= e.domTop && n <= e.domBottom);
59
+ if (a > o && o >= 0) return {
60
+ slotIndex: o,
61
+ indicatorTop: r[o].domTop
62
+ };
63
+ let s = 0, c = Infinity, l = r[0].domTop;
47
64
  for (let e = 0; e <= r.length; e++) {
48
- let t = e < r.length ? r[e].domTop : r[r.length - 1].domBottom, s = Math.abs(n - t);
49
- s < a && (a = s, i = e, o = t);
65
+ let t = e < r.length ? r[e].domTop : r[r.length - 1].domBottom, i = Math.abs(n - t);
66
+ i < c && (c = i, s = e, l = t);
50
67
  }
51
68
  return {
52
- slotIndex: i,
53
- indicatorTop: o
69
+ slotIndex: s,
70
+ indicatorTop: l
54
71
  };
55
- }, [u, I]);
72
+ }, [u, L]);
56
73
  t(() => {
57
74
  let e = u.view.dom.closest(".rte-editor-wrapper");
58
75
  if (!e) return;
59
76
  let t = (t) => {
60
- if (E || S.current || h || N.current || !u.isEditable || u.view.composing || j.current?.contains(t.target) || A.current?.contains(t.target)) return;
61
- let n = L(t.clientY);
77
+ if (D || C.current || g || P.current || !u.isEditable || u.view.composing || M.current?.contains(t.target) || j.current?.contains(t.target)) return;
78
+ let n = R(t.clientY);
62
79
  if (n < 0) {
63
- F();
80
+ I();
64
81
  return;
65
82
  }
66
- let r = I();
67
- if (n >= r.length) return;
83
+ let r = L();
84
+ if (n >= r.length || !z(t.clientY)) return;
68
85
  let i = Math.max(0, -e.getBoundingClientRect().top);
69
- m(Math.max(r[n].domTop, e.scrollTop + i + 4)), T(n);
70
- let a = u.state.doc.nodeAt(r[n].pos);
71
- x.current = a ? {
72
- pos: r[n].pos,
73
- node: a
74
- } : null, P(), f(!0);
86
+ h(Math.max(r[n].domTop, e.scrollTop + i + 4)), F();
75
87
  }, n = () => {
76
- E || F();
88
+ D || I();
89
+ }, r = (e) => {
90
+ if (!u.isEditable || u.view.composing) return;
91
+ let t = e.touches[0];
92
+ t && z(t.clientY);
77
93
  };
78
- return e.addEventListener("mousemove", t), e.addEventListener("mouseleave", n), () => {
79
- e.removeEventListener("mousemove", t), e.removeEventListener("mouseleave", n), P();
94
+ e.addEventListener("mousemove", t), e.addEventListener("mouseleave", n), e.addEventListener("touchstart", r);
95
+ let i = d ? requestAnimationFrame(() => {
96
+ let e = L(), t = e[0] ? u.state.doc.nodeAt(e[0].pos) : null;
97
+ e[0] && t && (S.current = {
98
+ pos: e[0].pos,
99
+ node: t
100
+ }, E(0), h(e[0].domTop), p(!0));
101
+ }) : null;
102
+ return () => {
103
+ e.removeEventListener("mousemove", t), e.removeEventListener("mouseleave", n), e.removeEventListener("touchstart", r), i !== null && cancelAnimationFrame(i), F();
80
104
  };
81
105
  }, [
82
106
  u,
83
- P,
84
107
  F,
85
- E,
86
- h,
108
+ I,
109
+ D,
110
+ g,
111
+ R,
87
112
  L,
88
- I
113
+ z,
114
+ d
89
115
  ]), t(() => {
90
- if (!h) return;
116
+ if (!g) return;
91
117
  let e = (e) => {
92
- A.current && !A.current.contains(e.target) && !j.current?.contains(e.target) && (N.current = !1, g(!1));
118
+ j.current && !j.current.contains(e.target) && !M.current?.contains(e.target) && (P.current = !1, _(!1));
93
119
  };
94
120
  return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
95
- }, [h]);
96
- let z = e(() => {
97
- let e = x.current;
121
+ }, [g]);
122
+ let V = e(() => {
123
+ let e = S.current;
98
124
  return u.isDestroyed || !u.isEditable || u.view.composing || !e || u.state.doc.nodeAt(e.pos) !== e.node ? null : e;
99
- }, [u]), B = e((e) => {
100
- let t = z();
125
+ }, [u]), H = e((e) => {
126
+ let t = V();
101
127
  if (!t) return;
102
128
  let n = t.pos + t.node.nodeSize;
103
- u.chain().focus().insertContentAt(n, e).command(({ tr: e }) => (e.setSelection(l.near(e.doc.resolve(n + 1))), !0)).run(), g(!1);
104
- }, [u, z]), V = e((e) => {
105
- let t = z(), n = I();
129
+ u.chain().focus().insertContentAt(n, e).command(({ tr: e }) => (e.setSelection(l.near(e.doc.resolve(n + 1))), !0)).run(), _(!1);
130
+ }, [u, V]), U = e((e) => {
131
+ let t = V(), n = L();
106
132
  if (!t || e < 0 || e > n.length) return;
107
133
  let r = n.findIndex((e) => e.pos === t.pos);
108
134
  if (r < 0 || e === r || e === r + 1) return;
@@ -110,67 +136,72 @@ var u = ({ editor: u }) => {
110
136
  a.insert(o, t.node), a.setSelection(c.isSelectable(t.node) ? c.create(a.doc, o) : l.near(a.doc.resolve(o))), u.view.dispatch(a.scrollIntoView()), u.view.focus();
111
137
  }, [
112
138
  u,
113
- z,
114
- I
139
+ V,
140
+ L
115
141
  ]);
116
142
  t(() => {
117
143
  let e = () => {
118
- S.current?.(), x.current = null, N.current = !1, f(!1), g(!1), P();
144
+ C.current?.(), S.current = null, P.current = !1, p(d), _(!1), F();
119
145
  }, t = ({ transaction: t }) => {
120
146
  (t.docChanged || !u.isEditable) && e();
121
147
  }, n = (t) => {
122
- (!(t.target instanceof Node) || !A.current?.contains(t.target)) && e();
148
+ (!(t.target instanceof Node) || !j.current?.contains(t.target)) && e();
123
149
  };
124
150
  u.on("transaction", t);
125
151
  let r = u.view.dom;
126
152
  return r.addEventListener("compositionstart", e), window.addEventListener("scroll", n, !0), window.addEventListener("resize", e), window.addEventListener("blur", e), () => {
127
- u.off("transaction", t), r.removeEventListener("compositionstart", e), window.removeEventListener("scroll", n, !0), window.removeEventListener("resize", e), window.removeEventListener("blur", e), S.current?.(), P();
153
+ u.off("transaction", t), r.removeEventListener("compositionstart", e), window.removeEventListener("scroll", n, !0), window.removeEventListener("resize", e), window.removeEventListener("blur", e), C.current?.(), F();
128
154
  };
129
- }, [u, P]), n(() => {
130
- if (!h) return;
131
- let e = A.current, t = j.current, n = u.view.dom.closest(".rte-editor-wrapper");
155
+ }, [
156
+ u,
157
+ F,
158
+ d
159
+ ]), n(() => {
160
+ if (!g) return;
161
+ let e = j.current, t = M.current, n = u.view.dom.closest(".rte-editor-wrapper");
132
162
  if (!e || !t || !n) return;
133
163
  let r = n.getBoundingClientRect(), i = t.getBoundingClientRect(), a = Math.max(8, r.left + n.clientLeft), o = Math.min(window.innerWidth - 8, r.right), s = Math.max(8, r.top + n.clientTop), c = Math.min(window.innerHeight - 8, r.bottom) - i.bottom - 4, l = i.top - s - 4, d = c < e.scrollHeight && l > c;
134
- e.style.maxHeight = `${Math.max(0, Math.min(320, d ? l : c))}px`, e.style.minWidth = "0", e.style.width = `${Math.max(0, Math.min(220, o - a))}px`, b({
164
+ e.style.maxHeight = `${Math.max(0, Math.min(320, d ? l : c))}px`, e.style.minWidth = "0", e.style.width = `${Math.max(0, Math.min(220, o - a))}px`, x({
135
165
  left: Math.max(a, Math.min(i.left, o - e.offsetWidth)) - r.left - n.clientLeft + n.scrollLeft,
136
166
  top: (d ? i.top - e.offsetHeight - 4 : i.bottom + 4) - r.top - n.clientTop + n.scrollTop
137
167
  });
138
- let f = _ === "actions" ? "button:not(:disabled)" : "button";
168
+ let f = v === "actions" ? "button:not(:disabled)" : "button";
139
169
  e.querySelector(f)?.focus({ preventScroll: !0 });
140
170
  }, [
141
171
  u,
142
- h,
143
- _
172
+ g,
173
+ v
144
174
  ]);
145
- let H = e((e) => {
146
- if (e.preventDefault(), e.stopPropagation(), e.button !== 0 || !z()) return;
147
- S.current?.(), C.current = !1;
175
+ let W = e((e) => {
176
+ if (e.preventDefault(), e.stopPropagation(), e.button !== 0 || !z(e.clientY) || !V()) return;
177
+ C.current?.(), w.current = !1;
148
178
  let t = e.clientX, n = e.clientY, r = !1, i = (e) => {
149
179
  if (!r && Math.hypot(e.clientX - t, e.clientY - n) < 5) return;
150
- r = !0, C.current = !0, g(!1), D(!0);
151
- let i = R(e.clientY);
152
- i && k({ top: i.indicatorTop });
180
+ r = !0, w.current = !0, _(!1), O(!0);
181
+ let i = B(e.clientY);
182
+ i && A({ top: i.indicatorTop });
153
183
  }, a = () => {
154
- document.removeEventListener("mousemove", i), document.removeEventListener("mouseup", s), document.removeEventListener("keydown", o, !0), S.current = null, D(!1), k(null);
184
+ document.removeEventListener("mousemove", i), document.removeEventListener("mouseup", s), document.removeEventListener("keydown", o, !0), C.current = null, O(!1), A(null);
155
185
  }, o = (e) => {
156
- e.key === "Escape" && (e.preventDefault(), e.stopImmediatePropagation(), C.current = !0, a());
186
+ e.key === "Escape" && (e.preventDefault(), e.stopImmediatePropagation(), w.current = !0, a());
157
187
  }, s = (e) => {
158
188
  if (a(), !r) return;
159
189
  let t = u.view.dom.closest(".rte-editor-wrapper")?.getBoundingClientRect();
160
190
  if (!t || e.clientX < t.left || e.clientX > t.right || e.clientY < t.top || e.clientY > t.bottom) return;
161
- let n = R(e.clientY);
162
- n && V(n.slotIndex);
191
+ let n = B(e.clientY);
192
+ n && U(n.slotIndex);
163
193
  };
164
- S.current = a, document.addEventListener("mousemove", i), document.addEventListener("mouseup", s), document.addEventListener("keydown", o, !0);
194
+ C.current = a, document.addEventListener("mousemove", i), document.addEventListener("mouseup", s), document.addEventListener("keydown", o, !0);
165
195
  }, [
166
196
  u,
167
- z,
168
197
  V,
169
- R
170
- ]), U = { type: "paragraph" }, W = [
198
+ U,
199
+ B,
200
+ z
201
+ ]), G = { type: "paragraph" }, K = [
171
202
  {
172
203
  label: "Text",
173
- content: U
204
+ content: G
174
205
  },
175
206
  ...[
176
207
  1,
@@ -189,7 +220,7 @@ var u = ({ editor: u }) => {
189
220
  type: "bulletList",
190
221
  content: [{
191
222
  type: "listItem",
192
- content: [U]
223
+ content: [G]
193
224
  }]
194
225
  }
195
226
  },
@@ -199,7 +230,7 @@ var u = ({ editor: u }) => {
199
230
  type: "orderedList",
200
231
  content: [{
201
232
  type: "listItem",
202
- content: [U]
233
+ content: [G]
203
234
  }]
204
235
  }
205
236
  },
@@ -210,7 +241,7 @@ var u = ({ editor: u }) => {
210
241
  content: [{
211
242
  type: "taskItem",
212
243
  attrs: { checked: !1 },
213
- content: [U]
244
+ content: [G]
214
245
  }]
215
246
  }
216
247
  },
@@ -218,7 +249,7 @@ var u = ({ editor: u }) => {
218
249
  label: "Blockquote",
219
250
  content: {
220
251
  type: "blockquote",
221
- content: [U]
252
+ content: [G]
222
253
  }
223
254
  },
224
255
  {
@@ -237,48 +268,48 @@ var u = ({ editor: u }) => {
237
268
  type: "tableRow",
238
269
  content: Array.from({ length: 3 }, () => ({
239
270
  type: t === 0 ? "tableHeader" : "tableCell",
240
- content: [U]
271
+ content: [G]
241
272
  }))
242
273
  }))
243
274
  }
244
275
  }
245
- ], G = _ === "add" ? W.filter((e) => u.schema.nodes[e.content.type]) : [
276
+ ], q = v === "add" ? K.filter((e) => u.schema.nodes[e.content.type]) : [
246
277
  { label: "Duplicate" },
247
278
  { label: "Delete" },
248
279
  {
249
280
  label: "Move up",
250
- disabled: w <= 0
281
+ disabled: T <= 0
251
282
  },
252
283
  {
253
284
  label: "Move down",
254
- disabled: w >= u.state.doc.childCount - 1
285
+ disabled: T >= u.state.doc.childCount - 1
255
286
  }
256
- ], K = (e) => {
287
+ ], J = (e) => {
257
288
  if (e.disabled) return;
258
- let t = z();
289
+ let t = V();
259
290
  if (t) {
260
- if (e.content) B(e.content);
291
+ if (e.content) H(e.content);
261
292
  else if (e.label === "Duplicate") {
262
293
  let e = t.pos + t.node.nodeSize, n = u.state.tr.insert(e, t.node);
263
294
  n.setSelection(l.near(n.doc.resolve(e + 1))), u.view.dispatch(n.scrollIntoView()), u.view.focus();
264
295
  } else e.label === "Delete" ? u.chain().focus().deleteRange({
265
296
  from: t.pos,
266
297
  to: t.pos + t.node.nodeSize
267
- }).run() : e.label === "Move up" ? V(w - 1) : e.label === "Move down" && V(w + 2);
298
+ }).run() : e.label === "Move up" ? U(T - 1) : e.label === "Move down" && U(T + 2);
268
299
  }
269
300
  };
270
- return !d && !h && !E ? null : /* @__PURE__ */ s(a, { children: [
301
+ return !f && !g && !D ? null : /* @__PURE__ */ s(a, { children: [
271
302
  /* @__PURE__ */ s("div", {
272
- ref: j,
273
- className: "rte-block-handle",
274
- style: { top: p },
275
- onFocus: P,
276
- onBlur: F,
303
+ ref: M,
304
+ className: `rte-block-handle ${d ? "rte-block-handle--persistent" : ""}`,
305
+ style: { top: m },
306
+ onFocus: F,
307
+ onBlur: I,
277
308
  onMouseEnter: () => {
278
- N.current = !0, P();
309
+ P.current = !0, F();
279
310
  },
280
311
  onMouseLeave: () => {
281
- N.current = !1, E || F();
312
+ P.current = !1, D || I();
282
313
  },
283
314
  onMouseDown: (e) => {
284
315
  e.stopPropagation(), e.preventDefault();
@@ -289,12 +320,19 @@ var u = ({ editor: u }) => {
289
320
  onMouseDown: (e) => {
290
321
  e.stopPropagation(), e.preventDefault();
291
322
  },
323
+ onTouchStart: (e) => {
324
+ e.stopPropagation(), w.current = !0, V() && (y("add"), _(!g || v !== "add"));
325
+ },
292
326
  onClick: (e) => {
293
- e.stopPropagation(), z() && (v("add"), g(!h || _ !== "add"));
327
+ if (e.stopPropagation(), w.current) {
328
+ w.current = !1;
329
+ return;
330
+ }
331
+ V() && (y("add"), _(!g || v !== "add"));
294
332
  },
295
333
  "aria-label": "Add block",
296
334
  "aria-haspopup": "menu",
297
- "aria-expanded": h && _ === "add",
335
+ "aria-expanded": g && v === "add",
298
336
  title: "Add block",
299
337
  children: /* @__PURE__ */ s("svg", {
300
338
  width: "14",
@@ -317,18 +355,21 @@ var u = ({ editor: u }) => {
317
355
  })
318
356
  }), /* @__PURE__ */ o("button", {
319
357
  type: "button",
320
- className: `rte-block-handle__btn rte-block-handle__btn--drag ${E ? "rte-block-handle__btn--dragging" : ""}`,
358
+ className: `rte-block-handle__btn rte-block-handle__btn--drag ${D ? "rte-block-handle__btn--dragging" : ""}`,
321
359
  title: "Drag to reorder or click for block actions",
322
360
  "aria-label": "Block actions",
323
361
  "aria-haspopup": "menu",
324
- "aria-expanded": h && _ === "actions",
325
- onMouseDown: H,
362
+ "aria-expanded": g && v === "actions",
363
+ onMouseDown: W,
364
+ onTouchStart: (e) => {
365
+ e.stopPropagation(), w.current = !0, y("actions"), _(!g || v !== "actions");
366
+ },
326
367
  onClick: (e) => {
327
- if (e.stopPropagation(), C.current) {
328
- C.current = !1;
368
+ if (e.stopPropagation(), w.current) {
369
+ w.current = !1;
329
370
  return;
330
371
  }
331
- z() && (v("actions"), g(!h || _ !== "actions"));
372
+ V() && (y("actions"), _(!g || v !== "actions"));
332
373
  },
333
374
  children: /* @__PURE__ */ s("svg", {
334
375
  width: "14",
@@ -372,20 +413,20 @@ var u = ({ editor: u }) => {
372
413
  })
373
414
  })]
374
415
  }),
375
- h && /* @__PURE__ */ o("div", {
376
- ref: A,
416
+ g && /* @__PURE__ */ o("div", {
417
+ ref: j,
377
418
  className: "rte-block-handle__menu",
378
419
  role: "menu",
379
- "aria-label": _ === "add" ? "Add block" : "Block actions",
420
+ "aria-label": v === "add" ? "Add block" : "Block actions",
380
421
  style: {
381
- ...y,
422
+ ...b,
382
423
  overflowY: "auto"
383
424
  },
384
425
  onMouseEnter: () => {
385
- N.current = !0, P();
426
+ P.current = !0, F();
386
427
  },
387
428
  onMouseLeave: () => {
388
- N.current = !1;
429
+ P.current = !1;
389
430
  },
390
431
  onMouseDown: (e) => {
391
432
  e.stopPropagation(), e.preventDefault();
@@ -393,7 +434,7 @@ var u = ({ editor: u }) => {
393
434
  onKeyDown: (e) => {
394
435
  if (e.nativeEvent.isComposing || e.keyCode === 229) return;
395
436
  if (e.key === "Escape" || e.key === "Tab") {
396
- e.key === "Escape" && e.preventDefault(), e.stopPropagation(), N.current = !1, g(!1), j.current?.querySelector(_ === "add" ? ".rte-block-handle__btn--add" : ".rte-block-handle__btn--drag")?.focus({ preventScroll: !0 });
437
+ e.key === "Escape" && e.preventDefault(), e.stopPropagation(), P.current = !1, _(!1), M.current?.querySelector(v === "add" ? ".rte-block-handle__btn--add" : ".rte-block-handle__btn--drag")?.focus({ preventScroll: !0 });
397
438
  return;
398
439
  }
399
440
  if (![
@@ -408,7 +449,7 @@ var u = ({ editor: u }) => {
408
449
  let i = t[r];
409
450
  i && i.offsetTop < e.currentTarget.scrollTop ? e.currentTarget.scrollTop = i.offsetTop : i && i.offsetTop + i.offsetHeight > e.currentTarget.scrollTop + e.currentTarget.clientHeight && (e.currentTarget.scrollTop = i.offsetTop + i.offsetHeight - e.currentTarget.clientHeight);
410
451
  },
411
- children: G.map((e) => /* @__PURE__ */ o("button", {
452
+ children: q.map((e) => /* @__PURE__ */ o("button", {
412
453
  type: "button",
413
454
  role: "menuitem",
414
455
  disabled: e.disabled,
@@ -419,14 +460,14 @@ var u = ({ editor: u }) => {
419
460
  className: "rte-block-handle__menu-item",
420
461
  onMouseDown: (e) => e.stopPropagation(),
421
462
  onClick: (t) => {
422
- t.stopPropagation(), K(e), g(!1), N.current = !1;
463
+ t.stopPropagation(), J(e), _(!1), P.current = !1;
423
464
  },
424
465
  children: e.label
425
466
  }, e.label))
426
467
  }),
427
- E && O && /* @__PURE__ */ o("div", {
468
+ D && k && /* @__PURE__ */ o("div", {
428
469
  className: "rte-block-handle__drop-indicator",
429
- style: { top: O.top }
470
+ style: { top: k.top }
430
471
  })
431
472
  ] });
432
473
  };