dishui 0.0.108 → 0.0.110
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/.release-verified.json +3 -2
- package/dist/components/Accordion/index.js.map +1 -1
- package/dist/components/Avatar/index.js.map +1 -1
- package/dist/components/Badge/index.js.map +1 -1
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/ButtonMenu/index.js.map +1 -1
- package/dist/components/Card/Metric2.js.map +1 -1
- package/dist/components/Card/Ticket2.js.map +1 -1
- package/dist/components/Card/index.js.map +1 -1
- package/dist/components/Chart/Chart.js.map +1 -1
- package/dist/components/Checkbox/index.js.map +1 -1
- package/dist/components/ChoicePicker/index.js.map +1 -1
- package/dist/components/Column/index.js.map +1 -1
- package/dist/components/ConfirmDialog/index.js.map +1 -1
- package/dist/components/DateTimeInput/index.js.map +1 -1
- package/dist/components/Demo/index.js.map +1 -1
- package/dist/components/Demo/source.js.map +1 -1
- package/dist/components/Divider/index.js.map +1 -1
- package/dist/components/EmptyState/index.js.map +1 -1
- package/dist/components/Field/index.js.map +1 -1
- package/dist/components/FileUploader/DropZone.js.map +1 -1
- package/dist/components/FileUploader/FileItem.js.map +1 -1
- package/dist/components/FileUploader/FileUploader.js.map +1 -1
- package/dist/components/FileUploader/UploadQueue.js.map +1 -1
- package/dist/components/GroupButton/index.js.map +1 -1
- package/dist/components/GroupedTable/index.js.map +1 -1
- package/dist/components/Icon/index.js.map +1 -1
- package/dist/components/Image/index.js.map +1 -1
- package/dist/components/Input/index.js.map +1 -1
- package/dist/components/Label/index.js.map +1 -1
- package/dist/components/Layout/index.js.map +1 -1
- package/dist/components/LayoutSuite/DashboardSuite.js.map +1 -1
- package/dist/components/LayoutSuite/index.js.map +1 -1
- package/dist/components/List/index.js.map +1 -1
- package/dist/components/Markdown/Markdown.js.map +1 -1
- package/dist/components/Markdown/codeThemes.js.map +1 -1
- package/dist/components/Markdown/markdownComponents.js.map +1 -1
- package/dist/components/Markdown/parseCodeBlockMeta.js.map +1 -1
- package/dist/components/Markdown/useMarkdownSource.js.map +1 -1
- package/dist/components/Markdown/useMarkmapRenderer.js.map +1 -1
- package/dist/components/Markdown/useMermaidRenderer.js.map +1 -1
- package/dist/components/Modal/focusScope.js.map +1 -1
- package/dist/components/Modal/index.js.map +1 -1
- package/dist/components/MultipleChoice/index.js.map +1 -1
- package/dist/components/NavigationList/index.js.map +1 -1
- package/dist/components/Page/Float2.js.map +1 -1
- package/dist/components/Page/index.js.map +1 -1
- package/dist/components/Page/resize2.js.map +1 -1
- package/dist/components/PageHeader/index.js.map +1 -1
- package/dist/components/PagePanel/index.js.map +1 -1
- package/dist/components/ProtectedRoute/index.js.map +1 -1
- package/dist/components/Resizable/ResizeGrip.js.map +1 -1
- package/dist/components/Resizable/index.js.map +1 -1
- package/dist/components/Resizable/useResize.js.map +1 -1
- package/dist/components/Row/index.js.map +1 -1
- package/dist/components/Section/index.js.map +1 -1
- package/dist/components/Select/index.js.map +1 -1
- package/dist/components/SidebarToggleButton/index.js.map +1 -1
- package/dist/components/Skeleton/index.js.map +1 -1
- package/dist/components/Slider/index.js.map +1 -1
- package/dist/components/Switch/index.js.map +1 -1
- package/dist/components/Tab/index.js.map +1 -1
- package/dist/components/Table/index.js.map +1 -1
- package/dist/components/Tabs/index.js.map +1 -1
- package/dist/components/Tabs/tabNavigation.js.map +1 -1
- package/dist/components/Text/index.js.map +1 -1
- package/dist/components/Textarea/index.js.map +1 -1
- package/dist/components/Tooltip/index.js.map +1 -1
- package/dist/components/Tree/Tree.js.map +1 -1
- package/dist/components/ai/AgentChat/index.js.map +1 -1
- package/dist/components/ai/AgentRunCard/index.js.map +1 -1
- package/dist/components/ai/AgentScreen/index.js.map +1 -1
- package/dist/components/ai/ApprovalCard/index.js.map +1 -1
- package/dist/components/ai/CodeView/index.js.map +1 -1
- package/dist/components/ai/CommandSearch/index.js.map +1 -1
- package/dist/components/ai/ContextCards/index.js.map +1 -1
- package/dist/components/ai/DiffTable/index.js.map +1 -1
- package/dist/components/ai/FilterTable/index.js.map +1 -1
- package/dist/components/ai/FineTuneCard/index.js.map +1 -1
- package/dist/components/ai/InsightCards/index.js.map +1 -1
- package/dist/components/ai/IssueCard/index.js.map +1 -1
- package/dist/components/ai/LoadingState/index.js.map +1 -1
- package/dist/components/ai/PromptBar/index.js.map +1 -1
- package/dist/components/ai/RecommendationCard/index.js.map +1 -1
- package/dist/components/ai/RecordsTable/index.js.map +1 -1
- package/dist/components/ai/SelectionActions/index.js.map +1 -1
- package/dist/components/ai/StateFlow/index.js.map +1 -1
- package/dist/components/ai/StreamingText/index.js.map +1 -1
- package/dist/components/ai/TaskRows/index.js.map +1 -1
- package/dist/components/ai/Thinking/index.js.map +1 -1
- package/dist/components/ai/ToolChips/index.js.map +1 -1
- package/dist/components/ai/shared.js.map +1 -1
- package/dist/components/pro/ArticleContextMenu/index.js.map +1 -1
- package/dist/components/pro/ArticleControl/ArticleControl2.js.map +1 -1
- package/dist/components/pro/ArticleControl/buildHeadingTree.js.map +1 -1
- package/dist/components/pro/ArticleControl/useArticleToc.js.map +1 -1
- package/dist/components/pro/Calendar/Calendar.js +165 -160
- package/dist/components/pro/Calendar/Calendar.js.map +1 -1
- package/dist/components/pro/Calendar/hooks/useCalendarDrag.js.map +1 -1
- package/dist/components/pro/Calendar/hooks/useCalendarState.js +31 -31
- package/dist/components/pro/Calendar/hooks/useCalendarState.js.map +1 -1
- package/dist/components/pro/Calendar/utils.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
- package/dist/components/pro/CodeEditor/editors/markdownExtensions.js.map +1 -1
- package/dist/components/pro/CodeEditor/extensions/contextMenu.js.map +1 -1
- package/dist/components/pro/CodeEditor/extensions/index.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/index.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/javascript.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/python.js.map +1 -1
- package/dist/components/pro/CodeEditor/langs/snippets.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/FootnotePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/HistoryPanel.js +65 -59
- package/dist/components/pro/CodeEditor/panels/HistoryPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/TableOfContentsPanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/panels/VariablePanel.js.map +1 -1
- package/dist/components/pro/CodeEditor/themes.js.map +1 -1
- package/dist/components/pro/CodeEditor/utils.js.map +1 -1
- package/dist/components/pro/DataTable/DataTable.js.map +1 -1
- package/dist/components/pro/DataTable/Filters.js.map +1 -1
- package/dist/components/pro/DataTable/PivotPanel.js.map +1 -1
- package/dist/components/pro/DataTable/PivotView.js.map +1 -1
- package/dist/components/pro/DataTable/components/BulkActions.js.map +1 -1
- package/dist/components/pro/DataTable/components/ColumnSelector.js.map +1 -1
- package/dist/components/pro/DataTable/components/FilterBar.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableHeader.js.map +1 -1
- package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
- package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
- package/dist/components/pro/DataTable/extension.js.map +1 -1
- package/dist/components/pro/DataTable/pivotEngine.js.map +1 -1
- package/dist/components/pro/DataTable/pivotExtension.js.map +1 -1
- package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
- package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
- package/dist/components/pro/DataTable/treeDataUtils.js.map +1 -1
- package/dist/components/pro/DataTable/useColumnDragReorder.js.map +1 -1
- package/dist/components/pro/DataTable/useDataTableModel.js +119 -104
- package/dist/components/pro/DataTable/useDataTableModel.js.map +1 -1
- package/dist/components/pro/DataTable/utils.js.map +1 -1
- package/dist/components/pro/FileExplorer/Breadcrumb.js.map +1 -1
- package/dist/components/pro/FileExplorer/CreateDialog.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileExplorer.js.map +1 -1
- package/dist/components/pro/FileExplorer/FileIcon.js.map +1 -1
- package/dist/components/pro/FileExplorer/GridView.js.map +1 -1
- package/dist/components/pro/FileExplorer/ListView.js.map +1 -1
- package/dist/components/pro/FileExplorer/Toolbar.js.map +1 -1
- package/dist/components/pro/Flow/Flow.js.map +1 -1
- package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
- package/dist/components/pro/Flow/archify/build.js.map +1 -1
- package/dist/components/pro/Flow/archify/convert.js.map +1 -1
- package/dist/components/pro/Flow/archify/palette.js.map +1 -1
- package/dist/components/pro/Flow/archify/presets.js.map +1 -1
- package/dist/components/pro/Flow/archify/spec.js.map +1 -1
- package/dist/components/pro/Flow/canvas/AlignmentGuides.js.map +1 -1
- package/dist/components/pro/Flow/canvas/GridRenderer.js.map +1 -1
- package/dist/components/pro/Flow/canvas/MiniMapRenderer.js.map +1 -1
- package/dist/components/pro/Flow/canvas/PixiApp.js.map +1 -1
- package/dist/components/pro/Flow/canvas/SelectionOverlay.js.map +1 -1
- package/dist/components/pro/Flow/canvas/ViewportContainer.js.map +1 -1
- package/dist/components/pro/Flow/constants.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowContext.js.map +1 -1
- package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
- package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/edges/edgeMarkers.js.map +1 -1
- package/dist/components/pro/Flow/edges/edgePaths.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useAlignmentGuides.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useCompactMode.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useDeleteSelection.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useDraggablePanel.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useEdgeMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLayoutActions.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useLineMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useNodeMutations.js.map +1 -1
- package/dist/components/pro/Flow/hooks/usePdfExport.js.map +1 -1
- package/dist/components/pro/Flow/hooks/usePixiApp.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useResizablePanel.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useSelection.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useUndoRedo.js.map +1 -1
- package/dist/components/pro/Flow/hooks/useViewport.js.map +1 -1
- package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/GeometricLineTool.js.map +1 -1
- package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
- package/dist/components/pro/Flow/lines/lineSmoothing.js.map +1 -1
- package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
- package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
- package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeHandles.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
- package/dist/components/pro/Flow/nodes/NodeText.js.map +1 -1
- package/dist/components/pro/Flow/nodes/aiClient.js.map +1 -1
- package/dist/components/pro/Flow/nodes/animAnchors.js.map +1 -1
- package/dist/components/pro/Flow/nodes/chartGeometryBudget.js.map +1 -1
- package/dist/components/pro/Flow/nodes/dataUtils.js.map +1 -1
- package/dist/components/pro/Flow/nodes/demandRender.js.map +1 -1
- package/dist/components/pro/Flow/nodes/nodeUtils.js.map +1 -1
- package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
- package/dist/components/pro/Flow/nodes/svgIconTexture.js.map +1 -1
- package/dist/components/pro/Flow/nodes/svgIcons.js.map +1 -1
- package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/Breadcrumb.js.map +1 -1
- package/dist/components/pro/Flow/panels/ContextMenu.js.map +1 -1
- package/dist/components/pro/Flow/panels/DataInspectorSection.js.map +1 -1
- package/dist/components/pro/Flow/panels/ExpandableTextarea.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
- package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
- package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
- package/dist/components/pro/Flow/panels/PresentationMode.js.map +1 -1
- package/dist/components/pro/Flow/panels/ProjectTitle.js.map +1 -1
- package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
- package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
- package/dist/components/pro/Flow/types.js.map +1 -1
- package/dist/components/pro/Flow/utils/dashedLine.js.map +1 -1
- package/dist/components/pro/Flow/utils/gradient.js.map +1 -1
- package/dist/components/pro/Flow/utils/pdfExport.js.map +1 -1
- package/dist/components/pro/Flow/utils/themeColor.js.map +1 -1
- package/dist/components/pro/Gantt/Gantt.js.map +1 -1
- package/dist/components/pro/Gantt/hooks/useGanttDrag.js.map +1 -1
- package/dist/components/pro/Gantt/hooks/useGanttState.js +79 -71
- package/dist/components/pro/Gantt/hooks/useGanttState.js.map +1 -1
- package/dist/components/pro/Gantt/utils.js.map +1 -1
- package/dist/components/pro/Kanban/Kanban.js.map +1 -1
- package/dist/components/pro/Kanban/Swimlanes.js.map +1 -1
- package/dist/components/pro/Kanban/useKanbanDrag.js.map +1 -1
- package/dist/components/pro/Kanban/utils.js.map +1 -1
- package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
- package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
- package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
- package/dist/components/pro/RichTextEditor/ContextMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
- package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/SelectDropdown.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js.map +1 -1
- package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/CommentMark.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/FontSize.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/ResizableImage.js.map +1 -1
- package/dist/components/pro/RichTextEditor/extensions/legacyMermaid.js.map +1 -1
- package/dist/components/pro/RichTextEditor/types.js.map +1 -1
- package/dist/components/pro/Sprite/Molly/animations.d.ts +6 -0
- package/dist/components/pro/Sprite/Molly/animations.js +52 -0
- package/dist/components/pro/Sprite/Molly/animations.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/events.d.ts +2 -0
- package/dist/components/pro/Sprite/Molly/events.js +46 -0
- package/dist/components/pro/Sprite/Molly/events.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/index.d.ts +1 -0
- package/dist/components/pro/Sprite/Molly/index.js +12 -0
- package/dist/components/pro/Sprite/Molly/index.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/legFlexion.d.ts +3 -0
- package/dist/components/pro/Sprite/Molly/legFlexion.js +48 -0
- package/dist/components/pro/Sprite/Molly/legFlexion.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/locomotion.d.ts +4 -0
- package/dist/components/pro/Sprite/Molly/locomotion.js +51 -0
- package/dist/components/pro/Sprite/Molly/locomotion.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/model.d.ts +23 -0
- package/dist/components/pro/Sprite/Molly/model.js +614 -0
- package/dist/components/pro/Sprite/Molly/model.js.map +1 -0
- package/dist/components/pro/Sprite/Molly/rig.d.ts +25 -0
- package/dist/components/pro/Sprite/Molly/rig.js +102 -0
- package/dist/components/pro/Sprite/Molly/rig.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/animations.d.ts +6 -0
- package/dist/components/pro/Sprite/Ruby/animations.js +58 -0
- package/dist/components/pro/Sprite/Ruby/animations.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/events.d.ts +2 -0
- package/dist/components/pro/Sprite/Ruby/events.js +46 -0
- package/dist/components/pro/Sprite/Ruby/events.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/index.d.ts +1 -0
- package/dist/components/pro/Sprite/Ruby/index.js +12 -0
- package/dist/components/pro/Sprite/Ruby/index.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/locomotion.d.ts +4 -0
- package/dist/components/pro/Sprite/Ruby/locomotion.js +41 -0
- package/dist/components/pro/Sprite/Ruby/locomotion.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/model.d.ts +23 -0
- package/dist/components/pro/Sprite/Ruby/model.js +605 -0
- package/dist/components/pro/Sprite/Ruby/model.js.map +1 -0
- package/dist/components/pro/Sprite/Ruby/rig.d.ts +26 -0
- package/dist/components/pro/Sprite/Ruby/rig.js +112 -0
- package/dist/components/pro/Sprite/Ruby/rig.js.map +1 -0
- package/dist/components/pro/Sprite/Sprite.d.ts +23 -0
- package/dist/components/pro/Sprite/Sprite2.js +224 -0
- package/dist/components/pro/Sprite/Sprite2.js.map +1 -0
- package/dist/components/pro/Sprite/actions.d.ts +3 -0
- package/dist/components/pro/Sprite/actions.js +16 -0
- package/dist/components/pro/Sprite/actions.js.map +1 -0
- package/dist/components/pro/Sprite/createSpriteScene.d.ts +4 -0
- package/dist/components/pro/Sprite/createSpriteScene.js +14 -0
- package/dist/components/pro/Sprite/createSpriteScene.js.map +1 -0
- package/dist/components/pro/Sprite/index.d.ts +4 -0
- package/dist/components/pro/Sprite/shared/animation.d.ts +33 -0
- package/dist/components/pro/Sprite/shared/animation.js +39 -0
- package/dist/components/pro/Sprite/shared/animation.js.map +1 -0
- package/dist/components/pro/Sprite/shared/createSpriteStage.d.ts +14 -0
- package/dist/components/pro/Sprite/shared/createSpriteStage.js +127 -0
- package/dist/components/pro/Sprite/shared/createSpriteStage.js.map +1 -0
- package/dist/components/pro/Sprite/shared/events.d.ts +5 -0
- package/dist/components/pro/Sprite/shared/events.js +21 -0
- package/dist/components/pro/Sprite/shared/events.js.map +1 -0
- package/dist/components/pro/Sprite/shared/face.d.ts +15 -0
- package/dist/components/pro/Sprite/shared/face.js +33 -0
- package/dist/components/pro/Sprite/shared/face.js.map +1 -0
- package/dist/components/pro/Sprite/shared/faceSurface.d.ts +6 -0
- package/dist/components/pro/Sprite/shared/faceSurface.js +66 -0
- package/dist/components/pro/Sprite/shared/faceSurface.js.map +1 -0
- package/dist/components/pro/Sprite/shared/gait.d.ts +5 -0
- package/dist/components/pro/Sprite/shared/gait.js +19 -0
- package/dist/components/pro/Sprite/shared/gait.js.map +1 -0
- package/dist/components/pro/Sprite/shared/geometry.d.ts +8 -0
- package/dist/components/pro/Sprite/shared/geometry.js +59 -0
- package/dist/components/pro/Sprite/shared/geometry.js.map +1 -0
- package/dist/components/pro/Sprite/shared/magicEffect.d.ts +27 -0
- package/dist/components/pro/Sprite/shared/magicEffect.js +61 -0
- package/dist/components/pro/Sprite/shared/magicEffect.js.map +1 -0
- package/dist/components/pro/Sprite/shared/playback.d.ts +8 -0
- package/dist/components/pro/Sprite/shared/playback.js +74 -0
- package/dist/components/pro/Sprite/shared/playback.js.map +1 -0
- package/dist/components/pro/Sprite/shared/rig.d.ts +6 -0
- package/dist/components/pro/Sprite/shared/rig.js +48 -0
- package/dist/components/pro/Sprite/shared/rig.js.map +1 -0
- package/dist/components/pro/Sprite/shared/scene.d.ts +9 -0
- package/dist/components/pro/Sprite/shared/scene.js +21 -0
- package/dist/components/pro/Sprite/shared/scene.js.map +1 -0
- package/dist/components/pro/Sprite/shared/sculptor.d.ts +14 -0
- package/dist/components/pro/Sprite/shared/sculptor.js +78 -0
- package/dist/components/pro/Sprite/shared/sculptor.js.map +1 -0
- package/dist/components/pro/Sprite/shared/speechBubble.d.ts +15 -0
- package/dist/components/pro/Sprite/shared/speechBubble.js +129 -0
- package/dist/components/pro/Sprite/shared/speechBubble.js.map +1 -0
- package/dist/components/pro/Sprite/types.d.ts +40 -0
- package/dist/contexts/AppContext.js.map +1 -1
- package/dist/contexts/authentication.js.map +1 -1
- package/dist/data-table.js +3 -3
- package/dist/data-table.js.map +1 -1
- package/dist/dishui.css +1 -1
- package/dist/hooks/useClickOutside.js.map +1 -1
- package/dist/hooks/useContainerElement.js.map +1 -1
- package/dist/hooks/useControllableState.js.map +1 -1
- package/dist/hooks/useCopyToClipboard.js.map +1 -1
- package/dist/hooks/useDebounce.js.map +1 -1
- package/dist/hooks/useDraggable.js.map +1 -1
- package/dist/hooks/useTableColumns.js.map +1 -1
- package/dist/hooks/useTableData.js.map +1 -1
- package/dist/index-nostyled.d.ts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +116 -115
- package/dist/layouts/MainLayout.js.map +1 -1
- package/dist/layouts/Navbar.js.map +1 -1
- package/dist/layouts/Sidebar.js.map +1 -1
- package/dist/layouts/headbar/Headbar.js.map +1 -1
- package/dist/layouts/headbar/HeadbarLangSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarSearch.js.map +1 -1
- package/dist/layouts/headbar/HeadbarThemeSwitcher.js.map +1 -1
- package/dist/layouts/headbar/HeadbarTitle.js.map +1 -1
- package/dist/sprite.js +2 -0
- package/dist/styles/themeStyles.js.map +1 -1
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/flexLayout.js.map +1 -1
- package/dist/utils/i18n.js.map +1 -1
- package/dist/utils/menu.js.map +1 -1
- package/dist/utils/rehype-code-meta.js.map +1 -1
- package/dist/utils/remark-code-meta.js.map +1 -1
- package/dist/utils/routerBuilder.js.map +1 -1
- package/dist/utils/safeStorage.js.map +1 -1
- package/dist/utils/selection.js +29 -20
- package/dist/utils/selection.js.map +1 -1
- package/dist/utils/themes.js.map +1 -1
- package/package.json +15 -11
|
@@ -1 +1 @@
|
|
|
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 followSelection?: boolean;\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, followSelection = false, 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 const [selectionSnapshot, setSelectionSnapshot] = useState(() => ({ from: selectionRange.from, to: selectionRange.to, text: initialSelection }));\n const snapshotRef = useRef(selectionSnapshot);\n\n const cancelRequest = useCallback(() => {\n const request = abortRef.current;\n abortRef.current = null;\n request?.abort();\n }, []);\n\n useEffect(() => {\n snapshotRef.current = { from: selectionRange.from, to: selectionRange.to, text: initialSelection };\n setSelectionSnapshot(snapshotRef.current);\n }, [initialSelection, selectionRange.from, selectionRange.to]);\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 const onSelection = () => {\n if (!followSelection || editor.isDestroyed || !editor.isEditable || editor.state.doc !== sourceDoc.current || invalidRef.current) return;\n const { from, to } = editor.state.selection;\n const previous = snapshotRef.current;\n // Ignore collapsed selections caused by focusing the AI prompt or toolbar.\n if (from === to || (from === previous.from && to === previous.to)) return;\n const next = { from, to, text: editor.state.doc.textBetween(from, to, ' ') };\n snapshotRef.current = next;\n setSelectionSnapshot(next);\n cancelRequest();\n setIsProcessing(false);\n setStreamedText('');\n setError(null);\n };\n invalidate();\n editor.on('update', invalidate);\n editor.on('transaction', invalidate);\n editor.on('selectionUpdate', onSelection);\n editor.on('destroy', invalidate);\n return () => {\n cancelRequest();\n editor.off('update', invalidate);\n editor.off('transaction', invalidate);\n editor.off('selectionUpdate', onSelection);\n editor.off('destroy', invalidate);\n };\n }, [editor, cancelRequest, followSelection]);\n\n const selectedText = selectionSnapshot.text;\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 } = snapshotRef.current;\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, 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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"}
|
|
1
|
+
{"version":3,"file":"AIRewrite.js","names":["StreamingText","LoadingState","QUICK_ACTIONS","getSystemPrompt","action","customPrompt","readSSE","reader","response","decoder","buffer","data","done","value","newline","line","streamOpenAI","config","body","systemPrompt","text","payload","content","streamAnthropic","getStream","request","signal","AIRewrite","propsLabels","labels","defaultLabels","promptId","useId","prompt","setPrompt","useState","isProcessing","setIsProcessing","streamedText","setStreamedText","error","setError","abortRef","useRef","promptRef","editable","setEditable","editor","invalid","setInvalid","sourceDoc","invalidRef","selectionSnapshot","setSelectionSnapshot","selectionRange","initialSelection","snapshotRef","cancelRequest","useCallback","useEffect","invalidate","onSelection","followSelection","previous","from","to","next","selectedText","handleGenerate","mode","actionPrompt","customPromptOverride","aiConfig","userText","abort","result","chunk","err","handleAccept","onClose","handleReject","handleKeyDown","key","labelKey","icon"],"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 followSelection?: boolean;\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, followSelection = false, 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 const [selectionSnapshot, setSelectionSnapshot] = useState(() => ({ from: selectionRange.from, to: selectionRange.to, text: initialSelection }));\n const snapshotRef = useRef(selectionSnapshot);\n\n const cancelRequest = useCallback(() => {\n const request = abortRef.current;\n abortRef.current = null;\n request?.abort();\n }, []);\n\n useEffect(() => {\n snapshotRef.current = { from: selectionRange.from, to: selectionRange.to, text: initialSelection };\n setSelectionSnapshot(snapshotRef.current);\n }, [initialSelection, selectionRange.from, selectionRange.to]);\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 const onSelection = () => {\n if (!followSelection || editor.isDestroyed || !editor.isEditable || editor.state.doc !== sourceDoc.current || invalidRef.current) return;\n const { from, to } = editor.state.selection;\n const previous = snapshotRef.current;\n // Ignore collapsed selections caused by focusing the AI prompt or toolbar.\n if (from === to || (from === previous.from && to === previous.to)) return;\n const next = { from, to, text: editor.state.doc.textBetween(from, to, ' ') };\n snapshotRef.current = next;\n setSelectionSnapshot(next);\n cancelRequest();\n setIsProcessing(false);\n setStreamedText('');\n setError(null);\n };\n invalidate();\n editor.on('update', invalidate);\n editor.on('transaction', invalidate);\n editor.on('selectionUpdate', onSelection);\n editor.on('destroy', invalidate);\n return () => {\n cancelRequest();\n editor.off('update', invalidate);\n editor.off('transaction', invalidate);\n editor.off('selectionUpdate', onSelection);\n editor.off('destroy', invalidate);\n };\n }, [editor, cancelRequest, followSelection]);\n\n const selectedText = selectionSnapshot.text;\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 } = snapshotRef.current;\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, 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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BlockHandle.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/BlockHandle.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef, useCallback } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { JSONContent } from '@tiptap/core';\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport { NodeSelection, Selection } from '@tiptap/pm/state';\n\ninterface BlockHandleProps {\n editor: Editor;\n /** Keep the left control rail visible instead of revealing it only on hover. */\n persistent?: boolean;\n}\n\ninterface BlockInfo {\n pos: number;\n size: number;\n domTop: number;\n domBottom: number;\n}\n\nconst BlockHandle: React.FC<BlockHandleProps> = ({ editor, persistent = false }) => {\n const [visible, setVisible] = useState(false);\n const [handleTop, setHandleTop] = useState(0);\n const [showMenu, setShowMenu] = useState(false);\n const [menuMode, setMenuMode] = useState<'add' | 'actions'>('add');\n const [menuPos, setMenuPos] = useState({ left: 4, top: 0 });\n const target = useRef<{ pos: number; node: ProseMirrorNode } | null>(null);\n const dragCleanup = useRef<(() => void) | null>(null);\n const suppressClick = useRef(false);\n const [currentBlockIndex, setCurrentBlockIndex] = useState(-1);\n const [isDragging, setIsDragging] = useState(false);\n const [dropIndicator, setDropIndicator] = useState<{ top: number } | null>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const handleRef = useRef<HTMLDivElement>(null);\n const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hoveringHandle = useRef(false);\n\n const cancelHide = useCallback(() => {\n if (hideTimer.current) {\n clearTimeout(hideTimer.current);\n hideTimer.current = null;\n }\n }, []);\n\n const scheduleHide = useCallback(() => {\n cancelHide();\n hideTimer.current = setTimeout(() => {\n if (!hoveringHandle.current && !showMenu && !isDragging && !handleRef.current?.contains(document.activeElement) && !menuRef.current?.contains(document.activeElement)) {\n setVisible(false);\n }\n }, 200);\n }, [cancelHide, showMenu, isDragging]);\n\n const getBlocks = useCallback((): BlockInfo[] => {\n if (editor.isDestroyed) return [];\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return [];\n const wrapperRect = wrapperEl.getBoundingClientRect();\n const scrollTop = wrapperEl.scrollTop;\n const blocks: BlockInfo[] = [];\n\n editor.state.doc.forEach((node, offset) => {\n const domNode = editor.view.nodeDOM(offset) as HTMLElement | null;\n if (domNode instanceof HTMLElement) {\n const rect = domNode.getBoundingClientRect();\n blocks.push({\n pos: offset,\n size: node.nodeSize,\n domTop: rect.top - wrapperRect.top - wrapperEl.clientTop + scrollTop,\n domBottom: rect.bottom - wrapperRect.top - wrapperEl.clientTop + scrollTop,\n });\n }\n });\n return blocks;\n }, [editor]);\n\n const findBlockByClientY = useCallback((clientY: number): number => {\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return -1;\n const wrapperRect = wrapperEl.getBoundingClientRect();\n const y = clientY - wrapperRect.top - wrapperEl.clientTop + wrapperEl.scrollTop;\n return getBlocks().findIndex((block) => y >= block.domTop && y <= block.domBottom);\n }, [editor, getBlocks]);\n\n const selectBlockAtClientY = useCallback((clientY: number): boolean => {\n const blocks = getBlocks();\n const idx = findBlockByClientY(clientY);\n if (idx < 0 || idx >= blocks.length) return false;\n const block = blocks[idx];\n const node = editor.state.doc.nodeAt(block.pos);\n if (!node) return false;\n target.current = { pos: block.pos, node };\n setCurrentBlockIndex(idx);\n setHandleTop(block.domTop);\n setVisible(true);\n return true;\n }, [editor, findBlockByClientY, getBlocks]);\n\n const findDropSlot = useCallback((clientY: number): { slotIndex: number; indicatorTop: number } | null => {\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return null;\n const wrapperRect = wrapperEl.getBoundingClientRect();\n const y = clientY - wrapperRect.top - wrapperEl.clientTop + wrapperEl.scrollTop;\n\n const blocks = getBlocks();\n if (blocks.length === 0) return null;\n\n // When the pointer is over a row, use the drag direction to choose that\n // row's near edge. This makes dropping a lower row anywhere on the first\n // row reliably place it first instead of accidentally placing it second.\n const source = target.current;\n const sourceIndex = source ? blocks.findIndex((block) => block.pos === source.pos) : -1;\n const hoveredIndex = blocks.findIndex((block) => y >= block.domTop && y <= block.domBottom);\n if (sourceIndex > hoveredIndex && hoveredIndex >= 0) {\n return { slotIndex: hoveredIndex, indicatorTop: blocks[hoveredIndex].domTop };\n }\n\n let bestSlot = 0;\n let bestDist = Infinity;\n let bestTop = blocks[0].domTop;\n\n for (let i = 0; i <= blocks.length; i++) {\n const edgeY = i < blocks.length ? blocks[i].domTop : blocks[blocks.length - 1].domBottom;\n const dist = Math.abs(y - edgeY);\n if (dist < bestDist) {\n bestDist = dist;\n bestSlot = i;\n bestTop = edgeY;\n }\n }\n\n return { slotIndex: bestSlot, indicatorTop: bestTop };\n }, [editor, getBlocks]);\n\n useEffect(() => {\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n if (isDragging || dragCleanup.current || showMenu || hoveringHandle.current || !editor.isEditable || editor.view.composing) return;\n if (handleRef.current?.contains(e.target as Node) || menuRef.current?.contains(e.target as Node)) return;\n\n const idx = findBlockByClientY(e.clientY);\n if (idx < 0) { scheduleHide(); return; }\n\n const blocks = getBlocks();\n if (idx >= blocks.length || !selectBlockAtClientY(e.clientY)) return;\n\n // Keep the handle reachable when the top of a long block has scrolled away.\n const viewportTop = Math.max(0, -wrapperEl.getBoundingClientRect().top);\n setHandleTop(Math.max(blocks[idx].domTop, wrapperEl.scrollTop + viewportTop + 4));\n cancelHide();\n };\n\n const handleMouseLeave = () => {\n if (!isDragging) scheduleHide();\n };\n\n const handleTouchStart = (e: TouchEvent) => {\n if (!editor.isEditable || editor.view.composing) return;\n const touch = e.touches[0];\n if (!touch) return;\n selectBlockAtClientY(touch.clientY);\n };\n\n wrapperEl.addEventListener('mousemove', handleMouseMove);\n wrapperEl.addEventListener('mouseleave', handleMouseLeave);\n wrapperEl.addEventListener('touchstart', handleTouchStart);\n const initialFrame = persistent\n ? requestAnimationFrame(() => {\n const blocks = getBlocks();\n const node = blocks[0] ? editor.state.doc.nodeAt(blocks[0].pos) : null;\n if (blocks[0] && node) {\n target.current = { pos: blocks[0].pos, node };\n setCurrentBlockIndex(0);\n setHandleTop(blocks[0].domTop);\n setVisible(true);\n }\n })\n : null;\n return () => {\n wrapperEl.removeEventListener('mousemove', handleMouseMove);\n wrapperEl.removeEventListener('mouseleave', handleMouseLeave);\n wrapperEl.removeEventListener('touchstart', handleTouchStart);\n if (initialFrame !== null) cancelAnimationFrame(initialFrame);\n cancelHide();\n };\n }, [editor, cancelHide, scheduleHide, isDragging, showMenu, findBlockByClientY, getBlocks, selectBlockAtClientY, persistent]);\n\n useEffect(() => {\n if (!showMenu) return;\n const handler = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node) && !handleRef.current?.contains(e.target as Node)) {\n hoveringHandle.current = false;\n setShowMenu(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [showMenu]);\n\n const getTarget = useCallback(() => {\n const block = target.current;\n if (editor.isDestroyed || !editor.isEditable || editor.view.composing || !block || editor.state.doc.nodeAt(block.pos) !== block.node) return null;\n return block;\n }, [editor]);\n\n const addBlockBelow = useCallback((content: JSONContent) => {\n const block = getTarget();\n if (!block) return;\n const insertPos = block.pos + block.node.nodeSize;\n editor.chain().focus().insertContentAt(insertPos, content).command(({ tr }) => {\n tr.setSelection(Selection.near(tr.doc.resolve(insertPos + 1)));\n return true;\n }).run();\n setShowMenu(false);\n }, [editor, getTarget]);\n\n const moveBlock = useCallback((slotIndex: number) => {\n const block = getTarget();\n const blocks = getBlocks();\n if (!block || slotIndex < 0 || slotIndex > blocks.length) return;\n const index = blocks.findIndex((item) => item.pos === block.pos);\n if (index < 0 || slotIndex === index || slotIndex === index + 1) return;\n const insertBefore = blocks[slotIndex]?.pos ?? editor.state.doc.content.size;\n const tr = editor.state.tr.delete(block.pos, block.pos + block.node.nodeSize);\n const destination = tr.mapping.map(insertBefore);\n tr.insert(destination, block.node);\n tr.setSelection(NodeSelection.isSelectable(block.node)\n ? NodeSelection.create(tr.doc, destination)\n : Selection.near(tr.doc.resolve(destination)));\n editor.view.dispatch(tr.scrollIntoView());\n editor.view.focus();\n }, [editor, getTarget, getBlocks]);\n\n useEffect(() => {\n // Invalidate instead of trusting an index after external edits, undo or collaboration.\n const reset = () => {\n dragCleanup.current?.();\n target.current = null;\n hoveringHandle.current = false;\n setVisible(persistent);\n setShowMenu(false);\n cancelHide();\n };\n const transaction = ({ transaction: tr }: { transaction: import('@tiptap/pm/state').Transaction }) => {\n if (tr.docChanged || !editor.isEditable) reset();\n };\n const scroll = (event: Event) => {\n if (!(event.target instanceof Node) || !menuRef.current?.contains(event.target)) reset();\n };\n editor.on('transaction', transaction);\n const dom = editor.view.dom;\n dom.addEventListener('compositionstart', reset);\n window.addEventListener('scroll', scroll, true);\n window.addEventListener('resize', reset);\n window.addEventListener('blur', reset);\n return () => {\n editor.off('transaction', transaction);\n dom.removeEventListener('compositionstart', reset);\n window.removeEventListener('scroll', scroll, true);\n window.removeEventListener('resize', reset);\n window.removeEventListener('blur', reset);\n dragCleanup.current?.();\n cancelHide();\n };\n }, [editor, cancelHide, persistent]);\n\n useLayoutEffect(() => {\n if (!showMenu) return;\n const menu = menuRef.current;\n const handle = handleRef.current;\n const wrapper = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!menu || !handle || !wrapper) return;\n const rect = wrapper.getBoundingClientRect();\n const anchor = handle.getBoundingClientRect();\n const left = Math.max(8, rect.left + wrapper.clientLeft);\n const right = Math.min(window.innerWidth - 8, rect.right);\n const top = Math.max(8, rect.top + wrapper.clientTop);\n const bottom = Math.min(window.innerHeight - 8, rect.bottom);\n const below = bottom - anchor.bottom - 4;\n const above = anchor.top - top - 4;\n const flip = below < menu.scrollHeight && above > below;\n menu.style.maxHeight = `${Math.max(0, Math.min(320, flip ? above : below))}px`;\n menu.style.minWidth = '0';\n menu.style.width = `${Math.max(0, Math.min(220, right - left))}px`;\n setMenuPos({\n left: Math.max(left, Math.min(anchor.left, right - menu.offsetWidth)) - rect.left - wrapper.clientLeft + wrapper.scrollLeft,\n top: (flip ? anchor.top - menu.offsetHeight - 4 : anchor.bottom + 4) - rect.top - wrapper.clientTop + wrapper.scrollTop,\n });\n const firstItem = menuMode === 'actions' ? 'button:not(:disabled)' : 'button';\n menu.querySelector<HTMLButtonElement>(firstItem)?.focus({ preventScroll: true });\n }, [editor, showMenu, menuMode]);\n\n const handleDragStart = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Re-resolve from the pointer at drag start. The visible rail can outlive a\n // previous hover, so relying on its cached target may move the wrong block.\n if (e.button !== 0 || !selectBlockAtClientY(e.clientY) || !getTarget()) return;\n dragCleanup.current?.();\n suppressClick.current = false;\n const startX = e.clientX;\n const startY = e.clientY;\n let moved = false;\n\n const handleDragMove = (ev: MouseEvent) => {\n if (!moved && Math.hypot(ev.clientX - startX, ev.clientY - startY) < 5) return;\n moved = true;\n suppressClick.current = true;\n setShowMenu(false);\n setIsDragging(true);\n const slot = findDropSlot(ev.clientY);\n if (slot) {\n setDropIndicator({ top: slot.indicatorTop });\n }\n };\n\n const cleanup = () => {\n document.removeEventListener('mousemove', handleDragMove);\n document.removeEventListener('mouseup', handleDragEnd);\n document.removeEventListener('keydown', cancel, true);\n dragCleanup.current = null;\n setIsDragging(false);\n setDropIndicator(null);\n };\n const cancel = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopImmediatePropagation();\n suppressClick.current = true;\n cleanup();\n };\n const handleDragEnd = (ev: MouseEvent) => {\n cleanup();\n if (!moved) return;\n const rect = editor.view.dom.closest('.rte-editor-wrapper')?.getBoundingClientRect();\n if (!rect || ev.clientX < rect.left || ev.clientX > rect.right || ev.clientY < rect.top || ev.clientY > rect.bottom) return;\n const slot = findDropSlot(ev.clientY);\n if (slot) moveBlock(slot.slotIndex);\n };\n\n dragCleanup.current = cleanup;\n document.addEventListener('mousemove', handleDragMove);\n document.addEventListener('mouseup', handleDragEnd);\n document.addEventListener('keydown', cancel, true);\n }, [editor, getTarget, moveBlock, findDropSlot, selectBlockAtClientY]);\n\n const paragraph = { type: 'paragraph' };\n const addItems: { label: string; content: JSONContent }[] = [\n { label: 'Text', content: paragraph },\n ...([1, 2, 3] as const).map((level) => ({ label: `Heading ${level}`, content: { type: 'heading', attrs: { level } } })),\n { label: 'Bullet List', content: { type: 'bulletList', content: [{ type: 'listItem', content: [paragraph] }] } },\n { label: 'Numbered List', content: { type: 'orderedList', content: [{ type: 'listItem', content: [paragraph] }] } },\n { label: 'Task List', content: { type: 'taskList', content: [{ type: 'taskItem', attrs: { checked: false }, content: [paragraph] }] } },\n { label: 'Blockquote', content: { type: 'blockquote', content: [paragraph] } },\n { label: 'Code Block', content: { type: 'codeBlock' } },\n { label: 'Divider', content: { type: 'horizontalRule' } },\n { label: 'Table 3×3', content: { type: 'table', content: Array.from({ length: 3 }, (_, row) => ({\n type: 'tableRow', content: Array.from({ length: 3 }, () => ({ type: row === 0 ? 'tableHeader' : 'tableCell', content: [paragraph] })),\n })) } },\n ];\n const menuItems: { label: string; content?: JSONContent; disabled?: boolean }[] = menuMode === 'add'\n ? addItems.filter((item) => editor.schema.nodes[item.content.type!])\n : [\n { label: 'Duplicate' },\n { label: 'Delete' },\n { label: 'Move up', disabled: currentBlockIndex <= 0 },\n { label: 'Move down', disabled: currentBlockIndex >= editor.state.doc.childCount - 1 },\n ];\n\n const executeMenuItem = (item: typeof menuItems[number]) => {\n if (item.disabled) return;\n const block = getTarget();\n if (!block) return;\n if (item.content) addBlockBelow(item.content);\n else if (item.label === 'Duplicate') {\n const pos = block.pos + block.node.nodeSize;\n const tr = editor.state.tr.insert(pos, block.node);\n tr.setSelection(Selection.near(tr.doc.resolve(pos + 1)));\n editor.view.dispatch(tr.scrollIntoView());\n editor.view.focus();\n } else if (item.label === 'Delete') {\n editor.chain().focus().deleteRange({ from: block.pos, to: block.pos + block.node.nodeSize }).run();\n } else if (item.label === 'Move up') moveBlock(currentBlockIndex - 1);\n else if (item.label === 'Move down') moveBlock(currentBlockIndex + 2);\n };\n\n if (!visible && !showMenu && !isDragging) return null;\n\n return (\n <>\n <div\n ref={handleRef}\n className={`rte-block-handle ${persistent ? 'rte-block-handle--persistent' : ''}`}\n style={{ top: handleTop }}\n onFocus={cancelHide}\n onBlur={scheduleHide}\n onMouseEnter={() => { hoveringHandle.current = true; cancelHide(); }}\n onMouseLeave={() => { hoveringHandle.current = false; if (!isDragging) scheduleHide(); }}\n onMouseDown={(e) => { e.stopPropagation(); e.preventDefault(); }}\n >\n <button\n type=\"button\"\n className=\"rte-block-handle__btn rte-block-handle__btn--add\"\n onMouseDown={(e) => { e.stopPropagation(); e.preventDefault(); }}\n onTouchStart={(e) => {\n e.stopPropagation();\n suppressClick.current = true;\n if (getTarget()) { setMenuMode('add'); setShowMenu(!showMenu || menuMode !== 'add'); }\n }}\n onClick={(e) => {\n e.stopPropagation();\n if (suppressClick.current) { suppressClick.current = false; return; }\n if (getTarget()) { setMenuMode('add'); setShowMenu(!showMenu || menuMode !== 'add'); }\n }}\n aria-label=\"Add block\"\n aria-haspopup=\"menu\"\n aria-expanded={showMenu && menuMode === 'add'}\n title=\"Add block\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" /></svg>\n </button>\n <button\n type=\"button\"\n className={`rte-block-handle__btn rte-block-handle__btn--drag ${isDragging ? 'rte-block-handle__btn--dragging' : ''}`}\n title=\"Drag to reorder or click for block actions\"\n aria-label=\"Block actions\"\n aria-haspopup=\"menu\"\n aria-expanded={showMenu && menuMode === 'actions'}\n onMouseDown={handleDragStart}\n onTouchStart={(e) => {\n e.stopPropagation();\n suppressClick.current = true;\n setMenuMode('actions');\n setShowMenu(!showMenu || menuMode !== 'actions');\n }}\n onClick={(e) => {\n e.stopPropagation();\n if (suppressClick.current) { suppressClick.current = false; return; }\n if (getTarget()) { setMenuMode('actions'); setShowMenu(!showMenu || menuMode !== 'actions'); }\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" /><circle cx=\"15\" cy=\"6\" r=\"1.5\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" /><circle cx=\"15\" cy=\"12\" r=\"1.5\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" /><circle cx=\"15\" cy=\"18\" r=\"1.5\" />\n </svg>\n </button>\n </div>\n\n {showMenu && (\n <div\n ref={menuRef}\n className=\"rte-block-handle__menu\"\n role=\"menu\"\n aria-label={menuMode === 'add' ? 'Add block' : 'Block actions'}\n style={{ ...menuPos, overflowY: 'auto' }}\n onMouseEnter={() => { hoveringHandle.current = true; cancelHide(); }}\n onMouseLeave={() => { hoveringHandle.current = false; }}\n onMouseDown={(e) => { e.stopPropagation(); e.preventDefault(); }}\n onKeyDown={(e) => {\n if (e.nativeEvent.isComposing || e.keyCode === 229) return;\n if (e.key === 'Escape' || e.key === 'Tab') {\n if (e.key === 'Escape') e.preventDefault();\n e.stopPropagation();\n hoveringHandle.current = false;\n setShowMenu(false);\n handleRef.current?.querySelector<HTMLButtonElement>(menuMode === 'add' ? '.rte-block-handle__btn--add' : '.rte-block-handle__btn--drag')?.focus({ preventScroll: true });\n return;\n }\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key)) return;\n e.preventDefault();\n e.stopPropagation();\n const buttons = Array.from(e.currentTarget.querySelectorAll<HTMLButtonElement>('button:not(:disabled)'));\n const index = buttons.indexOf(document.activeElement as HTMLButtonElement);\n const next = e.key === 'Home' ? 0 : e.key === 'End' ? buttons.length - 1 : (index + (e.key === 'ArrowDown' ? 1 : -1) + buttons.length) % buttons.length;\n buttons[next]?.focus({ preventScroll: true });\n const item = buttons[next];\n if (item && item.offsetTop < e.currentTarget.scrollTop) e.currentTarget.scrollTop = item.offsetTop;\n else if (item && item.offsetTop + item.offsetHeight > e.currentTarget.scrollTop + e.currentTarget.clientHeight) {\n e.currentTarget.scrollTop = item.offsetTop + item.offsetHeight - e.currentTarget.clientHeight;\n }\n }}\n >\n {menuItems.map((item) => (\n <button\n key={item.label}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n style={item.disabled ? { opacity: 0.45, cursor: 'default' } : undefined}\n className=\"rte-block-handle__menu-item\"\n onMouseDown={(e) => e.stopPropagation()}\n onClick={(e) => { e.stopPropagation(); executeMenuItem(item); setShowMenu(false); hoveringHandle.current = false; }}\n >\n {item.label}\n </button>\n ))}\n </div>\n )}\n\n {isDragging && dropIndicator && (\n <div className=\"rte-block-handle__drop-indicator\" style={{ top: dropIndicator.top }} />\n )}\n </>\n );\n};\n\nexport default BlockHandle;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BlockHandle.js","names":["_Fragment","BlockHandle","visible","setVisible","useState","handleTop","setHandleTop","showMenu","setShowMenu","menuMode","setMenuMode","menuPos","setMenuPos","target","useRef","dragCleanup","suppressClick","currentBlockIndex","setCurrentBlockIndex","isDragging","setIsDragging","dropIndicator","setDropIndicator","menuRef","handleRef","hideTimer","hoveringHandle","cancelHide","useCallback","scheduleHide","getBlocks","editor","wrapperEl","wrapperRect","scrollTop","blocks","domNode","offset","rect","node","findBlockByClientY","y","clientY","block","selectBlockAtClientY","idx","findDropSlot","source","sourceIndex","hoveredIndex","bestSlot","bestDist","bestTop","i","edgeY","dist","useEffect","handleMouseMove","e","viewportTop","handleMouseLeave","handleTouchStart","touch","initialFrame","persistent","handler","getTarget","addBlockBelow","insertPos","content","tr","Selection","moveBlock","slotIndex","index","item","insertBefore","destination","NodeSelection","reset","transaction","scroll","event","dom","useLayoutEffect","menu","handle","wrapper","anchor","left","right","top","below","above","flip","firstItem","handleDragStart","startX","startY","moved","handleDragMove","ev","slot","cleanup","handleDragEnd","cancel","paragraph","addItems","level","row","menuItems","executeMenuItem","pos","Fragment","buttons","next"],"sources":["../../../../src/components/pro/RichTextEditor/BlockHandle.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef, useCallback } from 'react';\nimport type { Editor } from '@tiptap/react';\nimport type { JSONContent } from '@tiptap/core';\nimport type { Node as ProseMirrorNode } from '@tiptap/pm/model';\nimport { NodeSelection, Selection } from '@tiptap/pm/state';\n\ninterface BlockHandleProps {\n editor: Editor;\n /** Keep the left control rail visible instead of revealing it only on hover. */\n persistent?: boolean;\n}\n\ninterface BlockInfo {\n pos: number;\n size: number;\n domTop: number;\n domBottom: number;\n}\n\nconst BlockHandle: React.FC<BlockHandleProps> = ({ editor, persistent = false }) => {\n const [visible, setVisible] = useState(false);\n const [handleTop, setHandleTop] = useState(0);\n const [showMenu, setShowMenu] = useState(false);\n const [menuMode, setMenuMode] = useState<'add' | 'actions'>('add');\n const [menuPos, setMenuPos] = useState({ left: 4, top: 0 });\n const target = useRef<{ pos: number; node: ProseMirrorNode } | null>(null);\n const dragCleanup = useRef<(() => void) | null>(null);\n const suppressClick = useRef(false);\n const [currentBlockIndex, setCurrentBlockIndex] = useState(-1);\n const [isDragging, setIsDragging] = useState(false);\n const [dropIndicator, setDropIndicator] = useState<{ top: number } | null>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const handleRef = useRef<HTMLDivElement>(null);\n const hideTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hoveringHandle = useRef(false);\n\n const cancelHide = useCallback(() => {\n if (hideTimer.current) {\n clearTimeout(hideTimer.current);\n hideTimer.current = null;\n }\n }, []);\n\n const scheduleHide = useCallback(() => {\n cancelHide();\n hideTimer.current = setTimeout(() => {\n if (!hoveringHandle.current && !showMenu && !isDragging && !handleRef.current?.contains(document.activeElement) && !menuRef.current?.contains(document.activeElement)) {\n setVisible(false);\n }\n }, 200);\n }, [cancelHide, showMenu, isDragging]);\n\n const getBlocks = useCallback((): BlockInfo[] => {\n if (editor.isDestroyed) return [];\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return [];\n const wrapperRect = wrapperEl.getBoundingClientRect();\n const scrollTop = wrapperEl.scrollTop;\n const blocks: BlockInfo[] = [];\n\n editor.state.doc.forEach((node, offset) => {\n const domNode = editor.view.nodeDOM(offset) as HTMLElement | null;\n if (domNode instanceof HTMLElement) {\n const rect = domNode.getBoundingClientRect();\n blocks.push({\n pos: offset,\n size: node.nodeSize,\n domTop: rect.top - wrapperRect.top - wrapperEl.clientTop + scrollTop,\n domBottom: rect.bottom - wrapperRect.top - wrapperEl.clientTop + scrollTop,\n });\n }\n });\n return blocks;\n }, [editor]);\n\n const findBlockByClientY = useCallback((clientY: number): number => {\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return -1;\n const wrapperRect = wrapperEl.getBoundingClientRect();\n const y = clientY - wrapperRect.top - wrapperEl.clientTop + wrapperEl.scrollTop;\n return getBlocks().findIndex((block) => y >= block.domTop && y <= block.domBottom);\n }, [editor, getBlocks]);\n\n const selectBlockAtClientY = useCallback((clientY: number): boolean => {\n const blocks = getBlocks();\n const idx = findBlockByClientY(clientY);\n if (idx < 0 || idx >= blocks.length) return false;\n const block = blocks[idx];\n const node = editor.state.doc.nodeAt(block.pos);\n if (!node) return false;\n target.current = { pos: block.pos, node };\n setCurrentBlockIndex(idx);\n setHandleTop(block.domTop);\n setVisible(true);\n return true;\n }, [editor, findBlockByClientY, getBlocks]);\n\n const findDropSlot = useCallback((clientY: number): { slotIndex: number; indicatorTop: number } | null => {\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return null;\n const wrapperRect = wrapperEl.getBoundingClientRect();\n const y = clientY - wrapperRect.top - wrapperEl.clientTop + wrapperEl.scrollTop;\n\n const blocks = getBlocks();\n if (blocks.length === 0) return null;\n\n // When the pointer is over a row, use the drag direction to choose that\n // row's near edge. This makes dropping a lower row anywhere on the first\n // row reliably place it first instead of accidentally placing it second.\n const source = target.current;\n const sourceIndex = source ? blocks.findIndex((block) => block.pos === source.pos) : -1;\n const hoveredIndex = blocks.findIndex((block) => y >= block.domTop && y <= block.domBottom);\n if (sourceIndex > hoveredIndex && hoveredIndex >= 0) {\n return { slotIndex: hoveredIndex, indicatorTop: blocks[hoveredIndex].domTop };\n }\n\n let bestSlot = 0;\n let bestDist = Infinity;\n let bestTop = blocks[0].domTop;\n\n for (let i = 0; i <= blocks.length; i++) {\n const edgeY = i < blocks.length ? blocks[i].domTop : blocks[blocks.length - 1].domBottom;\n const dist = Math.abs(y - edgeY);\n if (dist < bestDist) {\n bestDist = dist;\n bestSlot = i;\n bestTop = edgeY;\n }\n }\n\n return { slotIndex: bestSlot, indicatorTop: bestTop };\n }, [editor, getBlocks]);\n\n useEffect(() => {\n const wrapperEl = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!wrapperEl) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n if (isDragging || dragCleanup.current || showMenu || hoveringHandle.current || !editor.isEditable || editor.view.composing) return;\n if (handleRef.current?.contains(e.target as Node) || menuRef.current?.contains(e.target as Node)) return;\n\n const idx = findBlockByClientY(e.clientY);\n if (idx < 0) { scheduleHide(); return; }\n\n const blocks = getBlocks();\n if (idx >= blocks.length || !selectBlockAtClientY(e.clientY)) return;\n\n // Keep the handle reachable when the top of a long block has scrolled away.\n const viewportTop = Math.max(0, -wrapperEl.getBoundingClientRect().top);\n setHandleTop(Math.max(blocks[idx].domTop, wrapperEl.scrollTop + viewportTop + 4));\n cancelHide();\n };\n\n const handleMouseLeave = () => {\n if (!isDragging) scheduleHide();\n };\n\n const handleTouchStart = (e: TouchEvent) => {\n if (!editor.isEditable || editor.view.composing) return;\n const touch = e.touches[0];\n if (!touch) return;\n selectBlockAtClientY(touch.clientY);\n };\n\n wrapperEl.addEventListener('mousemove', handleMouseMove);\n wrapperEl.addEventListener('mouseleave', handleMouseLeave);\n wrapperEl.addEventListener('touchstart', handleTouchStart);\n const initialFrame = persistent\n ? requestAnimationFrame(() => {\n const blocks = getBlocks();\n const node = blocks[0] ? editor.state.doc.nodeAt(blocks[0].pos) : null;\n if (blocks[0] && node) {\n target.current = { pos: blocks[0].pos, node };\n setCurrentBlockIndex(0);\n setHandleTop(blocks[0].domTop);\n setVisible(true);\n }\n })\n : null;\n return () => {\n wrapperEl.removeEventListener('mousemove', handleMouseMove);\n wrapperEl.removeEventListener('mouseleave', handleMouseLeave);\n wrapperEl.removeEventListener('touchstart', handleTouchStart);\n if (initialFrame !== null) cancelAnimationFrame(initialFrame);\n cancelHide();\n };\n }, [editor, cancelHide, scheduleHide, isDragging, showMenu, findBlockByClientY, getBlocks, selectBlockAtClientY, persistent]);\n\n useEffect(() => {\n if (!showMenu) return;\n const handler = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node) && !handleRef.current?.contains(e.target as Node)) {\n hoveringHandle.current = false;\n setShowMenu(false);\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [showMenu]);\n\n const getTarget = useCallback(() => {\n const block = target.current;\n if (editor.isDestroyed || !editor.isEditable || editor.view.composing || !block || editor.state.doc.nodeAt(block.pos) !== block.node) return null;\n return block;\n }, [editor]);\n\n const addBlockBelow = useCallback((content: JSONContent) => {\n const block = getTarget();\n if (!block) return;\n const insertPos = block.pos + block.node.nodeSize;\n editor.chain().focus().insertContentAt(insertPos, content).command(({ tr }) => {\n tr.setSelection(Selection.near(tr.doc.resolve(insertPos + 1)));\n return true;\n }).run();\n setShowMenu(false);\n }, [editor, getTarget]);\n\n const moveBlock = useCallback((slotIndex: number) => {\n const block = getTarget();\n const blocks = getBlocks();\n if (!block || slotIndex < 0 || slotIndex > blocks.length) return;\n const index = blocks.findIndex((item) => item.pos === block.pos);\n if (index < 0 || slotIndex === index || slotIndex === index + 1) return;\n const insertBefore = blocks[slotIndex]?.pos ?? editor.state.doc.content.size;\n const tr = editor.state.tr.delete(block.pos, block.pos + block.node.nodeSize);\n const destination = tr.mapping.map(insertBefore);\n tr.insert(destination, block.node);\n tr.setSelection(NodeSelection.isSelectable(block.node)\n ? NodeSelection.create(tr.doc, destination)\n : Selection.near(tr.doc.resolve(destination)));\n editor.view.dispatch(tr.scrollIntoView());\n editor.view.focus();\n }, [editor, getTarget, getBlocks]);\n\n useEffect(() => {\n // Invalidate instead of trusting an index after external edits, undo or collaboration.\n const reset = () => {\n dragCleanup.current?.();\n target.current = null;\n hoveringHandle.current = false;\n setVisible(persistent);\n setShowMenu(false);\n cancelHide();\n };\n const transaction = ({ transaction: tr }: { transaction: import('@tiptap/pm/state').Transaction }) => {\n if (tr.docChanged || !editor.isEditable) reset();\n };\n const scroll = (event: Event) => {\n if (!(event.target instanceof Node) || !menuRef.current?.contains(event.target)) reset();\n };\n editor.on('transaction', transaction);\n const dom = editor.view.dom;\n dom.addEventListener('compositionstart', reset);\n window.addEventListener('scroll', scroll, true);\n window.addEventListener('resize', reset);\n window.addEventListener('blur', reset);\n return () => {\n editor.off('transaction', transaction);\n dom.removeEventListener('compositionstart', reset);\n window.removeEventListener('scroll', scroll, true);\n window.removeEventListener('resize', reset);\n window.removeEventListener('blur', reset);\n dragCleanup.current?.();\n cancelHide();\n };\n }, [editor, cancelHide, persistent]);\n\n useLayoutEffect(() => {\n if (!showMenu) return;\n const menu = menuRef.current;\n const handle = handleRef.current;\n const wrapper = editor.view.dom.closest('.rte-editor-wrapper') as HTMLElement | null;\n if (!menu || !handle || !wrapper) return;\n const rect = wrapper.getBoundingClientRect();\n const anchor = handle.getBoundingClientRect();\n const left = Math.max(8, rect.left + wrapper.clientLeft);\n const right = Math.min(window.innerWidth - 8, rect.right);\n const top = Math.max(8, rect.top + wrapper.clientTop);\n const bottom = Math.min(window.innerHeight - 8, rect.bottom);\n const below = bottom - anchor.bottom - 4;\n const above = anchor.top - top - 4;\n const flip = below < menu.scrollHeight && above > below;\n menu.style.maxHeight = `${Math.max(0, Math.min(320, flip ? above : below))}px`;\n menu.style.minWidth = '0';\n menu.style.width = `${Math.max(0, Math.min(220, right - left))}px`;\n setMenuPos({\n left: Math.max(left, Math.min(anchor.left, right - menu.offsetWidth)) - rect.left - wrapper.clientLeft + wrapper.scrollLeft,\n top: (flip ? anchor.top - menu.offsetHeight - 4 : anchor.bottom + 4) - rect.top - wrapper.clientTop + wrapper.scrollTop,\n });\n const firstItem = menuMode === 'actions' ? 'button:not(:disabled)' : 'button';\n menu.querySelector<HTMLButtonElement>(firstItem)?.focus({ preventScroll: true });\n }, [editor, showMenu, menuMode]);\n\n const handleDragStart = useCallback((e: React.MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n // Re-resolve from the pointer at drag start. The visible rail can outlive a\n // previous hover, so relying on its cached target may move the wrong block.\n if (e.button !== 0 || !selectBlockAtClientY(e.clientY) || !getTarget()) return;\n dragCleanup.current?.();\n suppressClick.current = false;\n const startX = e.clientX;\n const startY = e.clientY;\n let moved = false;\n\n const handleDragMove = (ev: MouseEvent) => {\n if (!moved && Math.hypot(ev.clientX - startX, ev.clientY - startY) < 5) return;\n moved = true;\n suppressClick.current = true;\n setShowMenu(false);\n setIsDragging(true);\n const slot = findDropSlot(ev.clientY);\n if (slot) {\n setDropIndicator({ top: slot.indicatorTop });\n }\n };\n\n const cleanup = () => {\n document.removeEventListener('mousemove', handleDragMove);\n document.removeEventListener('mouseup', handleDragEnd);\n document.removeEventListener('keydown', cancel, true);\n dragCleanup.current = null;\n setIsDragging(false);\n setDropIndicator(null);\n };\n const cancel = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopImmediatePropagation();\n suppressClick.current = true;\n cleanup();\n };\n const handleDragEnd = (ev: MouseEvent) => {\n cleanup();\n if (!moved) return;\n const rect = editor.view.dom.closest('.rte-editor-wrapper')?.getBoundingClientRect();\n if (!rect || ev.clientX < rect.left || ev.clientX > rect.right || ev.clientY < rect.top || ev.clientY > rect.bottom) return;\n const slot = findDropSlot(ev.clientY);\n if (slot) moveBlock(slot.slotIndex);\n };\n\n dragCleanup.current = cleanup;\n document.addEventListener('mousemove', handleDragMove);\n document.addEventListener('mouseup', handleDragEnd);\n document.addEventListener('keydown', cancel, true);\n }, [editor, getTarget, moveBlock, findDropSlot, selectBlockAtClientY]);\n\n const paragraph = { type: 'paragraph' };\n const addItems: { label: string; content: JSONContent }[] = [\n { label: 'Text', content: paragraph },\n ...([1, 2, 3] as const).map((level) => ({ label: `Heading ${level}`, content: { type: 'heading', attrs: { level } } })),\n { label: 'Bullet List', content: { type: 'bulletList', content: [{ type: 'listItem', content: [paragraph] }] } },\n { label: 'Numbered List', content: { type: 'orderedList', content: [{ type: 'listItem', content: [paragraph] }] } },\n { label: 'Task List', content: { type: 'taskList', content: [{ type: 'taskItem', attrs: { checked: false }, content: [paragraph] }] } },\n { label: 'Blockquote', content: { type: 'blockquote', content: [paragraph] } },\n { label: 'Code Block', content: { type: 'codeBlock' } },\n { label: 'Divider', content: { type: 'horizontalRule' } },\n { label: 'Table 3×3', content: { type: 'table', content: Array.from({ length: 3 }, (_, row) => ({\n type: 'tableRow', content: Array.from({ length: 3 }, () => ({ type: row === 0 ? 'tableHeader' : 'tableCell', content: [paragraph] })),\n })) } },\n ];\n const menuItems: { label: string; content?: JSONContent; disabled?: boolean }[] = menuMode === 'add'\n ? addItems.filter((item) => editor.schema.nodes[item.content.type!])\n : [\n { label: 'Duplicate' },\n { label: 'Delete' },\n { label: 'Move up', disabled: currentBlockIndex <= 0 },\n { label: 'Move down', disabled: currentBlockIndex >= editor.state.doc.childCount - 1 },\n ];\n\n const executeMenuItem = (item: typeof menuItems[number]) => {\n if (item.disabled) return;\n const block = getTarget();\n if (!block) return;\n if (item.content) addBlockBelow(item.content);\n else if (item.label === 'Duplicate') {\n const pos = block.pos + block.node.nodeSize;\n const tr = editor.state.tr.insert(pos, block.node);\n tr.setSelection(Selection.near(tr.doc.resolve(pos + 1)));\n editor.view.dispatch(tr.scrollIntoView());\n editor.view.focus();\n } else if (item.label === 'Delete') {\n editor.chain().focus().deleteRange({ from: block.pos, to: block.pos + block.node.nodeSize }).run();\n } else if (item.label === 'Move up') moveBlock(currentBlockIndex - 1);\n else if (item.label === 'Move down') moveBlock(currentBlockIndex + 2);\n };\n\n if (!visible && !showMenu && !isDragging) return null;\n\n return (\n <>\n <div\n ref={handleRef}\n className={`rte-block-handle ${persistent ? 'rte-block-handle--persistent' : ''}`}\n style={{ top: handleTop }}\n onFocus={cancelHide}\n onBlur={scheduleHide}\n onMouseEnter={() => { hoveringHandle.current = true; cancelHide(); }}\n onMouseLeave={() => { hoveringHandle.current = false; if (!isDragging) scheduleHide(); }}\n onMouseDown={(e) => { e.stopPropagation(); e.preventDefault(); }}\n >\n <button\n type=\"button\"\n className=\"rte-block-handle__btn rte-block-handle__btn--add\"\n onMouseDown={(e) => { e.stopPropagation(); e.preventDefault(); }}\n onTouchStart={(e) => {\n e.stopPropagation();\n suppressClick.current = true;\n if (getTarget()) { setMenuMode('add'); setShowMenu(!showMenu || menuMode !== 'add'); }\n }}\n onClick={(e) => {\n e.stopPropagation();\n if (suppressClick.current) { suppressClick.current = false; return; }\n if (getTarget()) { setMenuMode('add'); setShowMenu(!showMenu || menuMode !== 'add'); }\n }}\n aria-label=\"Add block\"\n aria-haspopup=\"menu\"\n aria-expanded={showMenu && menuMode === 'add'}\n title=\"Add block\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" /></svg>\n </button>\n <button\n type=\"button\"\n className={`rte-block-handle__btn rte-block-handle__btn--drag ${isDragging ? 'rte-block-handle__btn--dragging' : ''}`}\n title=\"Drag to reorder or click for block actions\"\n aria-label=\"Block actions\"\n aria-haspopup=\"menu\"\n aria-expanded={showMenu && menuMode === 'actions'}\n onMouseDown={handleDragStart}\n onTouchStart={(e) => {\n e.stopPropagation();\n suppressClick.current = true;\n setMenuMode('actions');\n setShowMenu(!showMenu || menuMode !== 'actions');\n }}\n onClick={(e) => {\n e.stopPropagation();\n if (suppressClick.current) { suppressClick.current = false; return; }\n if (getTarget()) { setMenuMode('actions'); setShowMenu(!showMenu || menuMode !== 'actions'); }\n }}\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\">\n <circle cx=\"9\" cy=\"6\" r=\"1.5\" /><circle cx=\"15\" cy=\"6\" r=\"1.5\" />\n <circle cx=\"9\" cy=\"12\" r=\"1.5\" /><circle cx=\"15\" cy=\"12\" r=\"1.5\" />\n <circle cx=\"9\" cy=\"18\" r=\"1.5\" /><circle cx=\"15\" cy=\"18\" r=\"1.5\" />\n </svg>\n </button>\n </div>\n\n {showMenu && (\n <div\n ref={menuRef}\n className=\"rte-block-handle__menu\"\n role=\"menu\"\n aria-label={menuMode === 'add' ? 'Add block' : 'Block actions'}\n style={{ ...menuPos, overflowY: 'auto' }}\n onMouseEnter={() => { hoveringHandle.current = true; cancelHide(); }}\n onMouseLeave={() => { hoveringHandle.current = false; }}\n onMouseDown={(e) => { e.stopPropagation(); e.preventDefault(); }}\n onKeyDown={(e) => {\n if (e.nativeEvent.isComposing || e.keyCode === 229) return;\n if (e.key === 'Escape' || e.key === 'Tab') {\n if (e.key === 'Escape') e.preventDefault();\n e.stopPropagation();\n hoveringHandle.current = false;\n setShowMenu(false);\n handleRef.current?.querySelector<HTMLButtonElement>(menuMode === 'add' ? '.rte-block-handle__btn--add' : '.rte-block-handle__btn--drag')?.focus({ preventScroll: true });\n return;\n }\n if (!['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(e.key)) return;\n e.preventDefault();\n e.stopPropagation();\n const buttons = Array.from(e.currentTarget.querySelectorAll<HTMLButtonElement>('button:not(:disabled)'));\n const index = buttons.indexOf(document.activeElement as HTMLButtonElement);\n const next = e.key === 'Home' ? 0 : e.key === 'End' ? buttons.length - 1 : (index + (e.key === 'ArrowDown' ? 1 : -1) + buttons.length) % buttons.length;\n buttons[next]?.focus({ preventScroll: true });\n const item = buttons[next];\n if (item && item.offsetTop < e.currentTarget.scrollTop) e.currentTarget.scrollTop = item.offsetTop;\n else if (item && item.offsetTop + item.offsetHeight > e.currentTarget.scrollTop + e.currentTarget.clientHeight) {\n e.currentTarget.scrollTop = item.offsetTop + item.offsetHeight - e.currentTarget.clientHeight;\n }\n }}\n >\n {menuItems.map((item) => (\n <button\n key={item.label}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n style={item.disabled ? { opacity: 0.45, cursor: 'default' } : undefined}\n className=\"rte-block-handle__menu-item\"\n onMouseDown={(e) => e.stopPropagation()}\n onClick={(e) => { e.stopPropagation(); executeMenuItem(item); setShowMenu(false); hoveringHandle.current = false; }}\n >\n {item.label}\n </button>\n ))}\n </div>\n )}\n\n {isDragging && dropIndicator && (\n <div className=\"rte-block-handle__drop-indicator\" style={{ top: dropIndicator.top }} />\n )}\n </>\n );\n};\n\nexport default BlockHandle;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BubbleToolbar.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/BubbleToolbar.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef, useId, useCallback } from 'react';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport { TextSelection } from '@tiptap/pm/state';\nimport { ColorPicker } from './Toolbar/ColorPicker';\nimport { SelectDropdown, FONT_FAMILIES, FONT_SIZES } from './Toolbar/SelectDropdown';\n\ninterface BubbleToolbarProps {\n editor: Editor;\n onAddComment?: () => void;\n}\n\nconst BubbleToolbar: React.FC<BubbleToolbarProps> = ({ editor, onAddComment }) => {\n useEditorState({ editor, selector: ({ transactionNumber }) => transactionNumber });\n const [visible, setVisible] = useState(false);\n const [pos, setPos] = useState({ x: 0, y: 0 });\n const ref = useRef<HTMLDivElement>(null);\n const bubbleId = useId();\n const ownsPalette = useCallback((target: EventTarget | null) =>\n target instanceof Element && target.closest(`[data-rte-palette-owner=\"${bubbleId}\"]`) !== null, [bubbleId]);\n\n useEffect(() => {\n if (editor.isDestroyed) return;\n const doc = editor.view.dom.ownerDocument;\n const win = doc.defaultView;\n if (!win) return;\n let frame: number | null = null;\n const hide = () => {\n if (frame !== null) win.cancelAnimationFrame(frame);\n frame = null;\n setVisible(false);\n };\n const update = () => {\n frame = null;\n if (editor.isDestroyed) { hide(); return; }\n const { from, to } = editor.state.selection;\n if (!editor.isEditable || !(editor.state.selection instanceof TextSelection) || from === to || (!editor.isFocused && !ref.current?.contains(doc.activeElement) && !ownsPalette(doc.activeElement))) {\n setVisible(false);\n return;\n }\n const coords = editor.view.coordsAtPos(from);\n const endCoords = editor.view.coordsAtPos(to);\n const wrapperEl = editor.view.dom.closest<HTMLElement>('.rte-editor-wrapper');\n if (!wrapperEl) { hide(); return; }\n const rect = wrapperEl.getBoundingClientRect();\n\n const centerX = (coords.left + endCoords.left) / 2 - rect.left - wrapperEl.clientLeft + wrapperEl.scrollLeft;\n const topY = Math.min(coords.top, endCoords.top) - rect.top - wrapperEl.clientTop + wrapperEl.scrollTop - 44;\n\n setPos({ x: centerX, y: topY });\n setVisible(true);\n };\n\n const scheduleUpdate = () => {\n if (frame !== null) win.cancelAnimationFrame(frame);\n frame = win.requestAnimationFrame(update);\n };\n const onBlur = ({ event }: { event: FocusEvent }) => {\n if (event.relatedTarget instanceof Node && (ref.current?.contains(event.relatedTarget) || ownsPalette(event.relatedTarget))) return;\n hide();\n };\n editor.on('transaction', scheduleUpdate);\n editor.on('selectionUpdate', scheduleUpdate);\n editor.on('focus', scheduleUpdate);\n editor.on('blur', onBlur);\n editor.on('destroy', hide);\n doc.addEventListener('scroll', scheduleUpdate, true);\n win.addEventListener('resize', scheduleUpdate);\n update();\n return () => {\n if (frame !== null) win.cancelAnimationFrame(frame);\n editor.off('transaction', scheduleUpdate);\n editor.off('selectionUpdate', scheduleUpdate);\n editor.off('focus', scheduleUpdate);\n editor.off('blur', onBlur);\n editor.off('destroy', hide);\n doc.removeEventListener('scroll', scheduleUpdate, true);\n win.removeEventListener('resize', scheduleUpdate);\n };\n }, [editor, ownsPalette]);\n\n // A transform here turns fixed-position color palettes into descendants of\n // the scrolling editor, where overflow clips them. Position the bubble's\n // left edge directly instead of centering it with translateX(-50%).\n useLayoutEffect(() => {\n if (!visible || !ref.current) return;\n const el = ref.current;\n const wrapper = el.parentElement;\n if (!wrapper) return;\n const width = el.offsetWidth;\n el.style.left = `${Math.max(0, Math.min(pos.x - width / 2, wrapper.clientWidth - width))}px`;\n }, [visible, pos.x]);\n\n if (!visible || editor.isDestroyed || !editor.isEditable) return null;\n\n const btn = (onClick: () => void, title: string, isActive: boolean | undefined, children: React.ReactNode) => (\n <button\n type=\"button\"\n className={`rte-bubble__btn ${isActive ? 'rte-bubble__btn--active' : ''}`}\n onClick={() => { if (!editor.isDestroyed && editor.isEditable) onClick(); }}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n onMouseDown={(e) => e.preventDefault()}\n >\n {children}\n </button>\n );\n\n return (\n <div ref={ref} className=\"rte-bubble\" role=\"group\" aria-label=\"Selection formatting\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget) && !ownsPalette(event.relatedTarget) && !editor.isFocused) setVisible(false);\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n editor.commands.focus();\n setVisible(false);\n }\n }}\n style={{ top: pos.y }}>\n {btn(() => editor.chain().focus().toggleBold().run(), 'Bold', editor.isActive('bold'),\n <strong style={{ fontSize: 13 }}>B</strong>)}\n {btn(() => editor.chain().focus().toggleItalic().run(), 'Italic', editor.isActive('italic'),\n <em style={{ fontSize: 13 }}>I</em>)}\n {btn(() => editor.chain().focus().toggleUnderline().run(), 'Underline', editor.isActive('underline'),\n <span style={{ fontSize: 13, textDecoration: 'underline' }}>U</span>)}\n {btn(() => editor.chain().focus().toggleStrike().run(), 'Strike', editor.isActive('strike'),\n <span style={{ fontSize: 13, textDecoration: 'line-through' }}>S</span>)}\n {btn(() => editor.chain().focus().toggleCode().run(), 'Code', editor.isActive('code'),\n <span style={{ fontSize: 11, fontFamily: 'monospace' }}></></span>)}\n {btn(() => {\n const url = window.prompt('URL:', editor.getAttributes('link').href || '');\n if (url === null || editor.isDestroyed || !editor.isEditable) return;\n const chain = editor.chain().focus().extendMarkRange('link');\n if (url.trim() === '') chain.unsetLink().run();\n else chain.setLink({ href: url.trim() }).run();\n }, 'Link', editor.isActive('link'),\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71\" /><path d=\"M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71\" /></svg>)}\n <div className=\"rte-bubble__divider\" />\n <ColorPicker\n value={editor.getAttributes('textStyle').color || ''}\n onChange={(color) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (color) editor.chain().focus().setColor(color).run();\n else editor.chain().focus().unsetColor().run();\n }}\n title=\"Text color\"\n buttonClassName=\"rte-bubble__btn\"\n portalOwner={bubbleId}\n kind=\"text\"\n />\n <ColorPicker\n value={editor.getAttributes('highlight').color || ''}\n onChange={(color) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (color) editor.chain().focus().toggleHighlight({ color }).run();\n else editor.chain().focus().unsetHighlight().run();\n }}\n title=\"Highlight color\"\n buttonClassName=\"rte-bubble__btn\"\n portalOwner={bubbleId}\n kind=\"highlight\"\n />\n <div className=\"rte-bubble__divider\" />\n <SelectDropdown\n className=\"rte-bubble__select\"\n width={96}\n value={editor.getAttributes('textStyle').fontFamily || ''}\n options={FONT_FAMILIES}\n onChange={(value) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (value) editor.chain().focus().setFontFamily(value).run();\n else editor.chain().focus().unsetFontFamily().run();\n }}\n title=\"Font family\"\n />\n <SelectDropdown\n className=\"rte-bubble__select rte-bubble__select--size\"\n width={72}\n value={editor.getAttributes('textStyle').fontSize || ''}\n options={FONT_SIZES}\n onChange={(value) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (value) (editor.chain().focus() as any).setFontSize(value).run();\n else (editor.chain().focus() as any).unsetFontSize().run();\n }}\n title=\"Font size\"\n />\n {onAddComment && (\n <>\n <div className=\"rte-bubble__divider\" />\n {btn(onAddComment, 'Comment', undefined,\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" /></svg>)}\n </>\n )}\n </div>\n );\n};\n\nexport default BubbleToolbar;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BubbleToolbar.js","names":["_Fragment","BubbleToolbar","transactionNumber","visible","setVisible","useState","pos","setPos","ref","useRef","bubbleId","useId","ownsPalette","useCallback","target","useEffect","editor","doc","win","frame","hide","update","TextSelection","from","to","coords","endCoords","wrapperEl","rect","centerX","topY","scheduleUpdate","onBlur","event","useLayoutEffect","el","wrapper","width","btn","isActive","onClick","title","url","chain","ColorPicker","color","SelectDropdown","FONT_FAMILIES","value","FONT_SIZES","onAddComment","Fragment"],"sources":["../../../../src/components/pro/RichTextEditor/BubbleToolbar.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef, useId, useCallback } from 'react';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport { TextSelection } from '@tiptap/pm/state';\nimport { ColorPicker } from './Toolbar/ColorPicker';\nimport { SelectDropdown, FONT_FAMILIES, FONT_SIZES } from './Toolbar/SelectDropdown';\n\ninterface BubbleToolbarProps {\n editor: Editor;\n onAddComment?: () => void;\n}\n\nconst BubbleToolbar: React.FC<BubbleToolbarProps> = ({ editor, onAddComment }) => {\n useEditorState({ editor, selector: ({ transactionNumber }) => transactionNumber });\n const [visible, setVisible] = useState(false);\n const [pos, setPos] = useState({ x: 0, y: 0 });\n const ref = useRef<HTMLDivElement>(null);\n const bubbleId = useId();\n const ownsPalette = useCallback((target: EventTarget | null) =>\n target instanceof Element && target.closest(`[data-rte-palette-owner=\"${bubbleId}\"]`) !== null, [bubbleId]);\n\n useEffect(() => {\n if (editor.isDestroyed) return;\n const doc = editor.view.dom.ownerDocument;\n const win = doc.defaultView;\n if (!win) return;\n let frame: number | null = null;\n const hide = () => {\n if (frame !== null) win.cancelAnimationFrame(frame);\n frame = null;\n setVisible(false);\n };\n const update = () => {\n frame = null;\n if (editor.isDestroyed) { hide(); return; }\n const { from, to } = editor.state.selection;\n if (!editor.isEditable || !(editor.state.selection instanceof TextSelection) || from === to || (!editor.isFocused && !ref.current?.contains(doc.activeElement) && !ownsPalette(doc.activeElement))) {\n setVisible(false);\n return;\n }\n const coords = editor.view.coordsAtPos(from);\n const endCoords = editor.view.coordsAtPos(to);\n const wrapperEl = editor.view.dom.closest<HTMLElement>('.rte-editor-wrapper');\n if (!wrapperEl) { hide(); return; }\n const rect = wrapperEl.getBoundingClientRect();\n\n const centerX = (coords.left + endCoords.left) / 2 - rect.left - wrapperEl.clientLeft + wrapperEl.scrollLeft;\n const topY = Math.min(coords.top, endCoords.top) - rect.top - wrapperEl.clientTop + wrapperEl.scrollTop - 44;\n\n setPos({ x: centerX, y: topY });\n setVisible(true);\n };\n\n const scheduleUpdate = () => {\n if (frame !== null) win.cancelAnimationFrame(frame);\n frame = win.requestAnimationFrame(update);\n };\n const onBlur = ({ event }: { event: FocusEvent }) => {\n if (event.relatedTarget instanceof Node && (ref.current?.contains(event.relatedTarget) || ownsPalette(event.relatedTarget))) return;\n hide();\n };\n editor.on('transaction', scheduleUpdate);\n editor.on('selectionUpdate', scheduleUpdate);\n editor.on('focus', scheduleUpdate);\n editor.on('blur', onBlur);\n editor.on('destroy', hide);\n doc.addEventListener('scroll', scheduleUpdate, true);\n win.addEventListener('resize', scheduleUpdate);\n update();\n return () => {\n if (frame !== null) win.cancelAnimationFrame(frame);\n editor.off('transaction', scheduleUpdate);\n editor.off('selectionUpdate', scheduleUpdate);\n editor.off('focus', scheduleUpdate);\n editor.off('blur', onBlur);\n editor.off('destroy', hide);\n doc.removeEventListener('scroll', scheduleUpdate, true);\n win.removeEventListener('resize', scheduleUpdate);\n };\n }, [editor, ownsPalette]);\n\n // A transform here turns fixed-position color palettes into descendants of\n // the scrolling editor, where overflow clips them. Position the bubble's\n // left edge directly instead of centering it with translateX(-50%).\n useLayoutEffect(() => {\n if (!visible || !ref.current) return;\n const el = ref.current;\n const wrapper = el.parentElement;\n if (!wrapper) return;\n const width = el.offsetWidth;\n el.style.left = `${Math.max(0, Math.min(pos.x - width / 2, wrapper.clientWidth - width))}px`;\n }, [visible, pos.x]);\n\n if (!visible || editor.isDestroyed || !editor.isEditable) return null;\n\n const btn = (onClick: () => void, title: string, isActive: boolean | undefined, children: React.ReactNode) => (\n <button\n type=\"button\"\n className={`rte-bubble__btn ${isActive ? 'rte-bubble__btn--active' : ''}`}\n onClick={() => { if (!editor.isDestroyed && editor.isEditable) onClick(); }}\n title={title}\n aria-label={title}\n aria-pressed={isActive}\n onMouseDown={(e) => e.preventDefault()}\n >\n {children}\n </button>\n );\n\n return (\n <div ref={ref} className=\"rte-bubble\" role=\"group\" aria-label=\"Selection formatting\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget) && !ownsPalette(event.relatedTarget) && !editor.isFocused) setVisible(false);\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n editor.commands.focus();\n setVisible(false);\n }\n }}\n style={{ top: pos.y }}>\n {btn(() => editor.chain().focus().toggleBold().run(), 'Bold', editor.isActive('bold'),\n <strong style={{ fontSize: 13 }}>B</strong>)}\n {btn(() => editor.chain().focus().toggleItalic().run(), 'Italic', editor.isActive('italic'),\n <em style={{ fontSize: 13 }}>I</em>)}\n {btn(() => editor.chain().focus().toggleUnderline().run(), 'Underline', editor.isActive('underline'),\n <span style={{ fontSize: 13, textDecoration: 'underline' }}>U</span>)}\n {btn(() => editor.chain().focus().toggleStrike().run(), 'Strike', editor.isActive('strike'),\n <span style={{ fontSize: 13, textDecoration: 'line-through' }}>S</span>)}\n {btn(() => editor.chain().focus().toggleCode().run(), 'Code', editor.isActive('code'),\n <span style={{ fontSize: 11, fontFamily: 'monospace' }}></></span>)}\n {btn(() => {\n const url = window.prompt('URL:', editor.getAttributes('link').href || '');\n if (url === null || editor.isDestroyed || !editor.isEditable) return;\n const chain = editor.chain().focus().extendMarkRange('link');\n if (url.trim() === '') chain.unsetLink().run();\n else chain.setLink({ href: url.trim() }).run();\n }, 'Link', editor.isActive('link'),\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71\" /><path d=\"M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71\" /></svg>)}\n <div className=\"rte-bubble__divider\" />\n <ColorPicker\n value={editor.getAttributes('textStyle').color || ''}\n onChange={(color) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (color) editor.chain().focus().setColor(color).run();\n else editor.chain().focus().unsetColor().run();\n }}\n title=\"Text color\"\n buttonClassName=\"rte-bubble__btn\"\n portalOwner={bubbleId}\n kind=\"text\"\n />\n <ColorPicker\n value={editor.getAttributes('highlight').color || ''}\n onChange={(color) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (color) editor.chain().focus().toggleHighlight({ color }).run();\n else editor.chain().focus().unsetHighlight().run();\n }}\n title=\"Highlight color\"\n buttonClassName=\"rte-bubble__btn\"\n portalOwner={bubbleId}\n kind=\"highlight\"\n />\n <div className=\"rte-bubble__divider\" />\n <SelectDropdown\n className=\"rte-bubble__select\"\n width={96}\n value={editor.getAttributes('textStyle').fontFamily || ''}\n options={FONT_FAMILIES}\n onChange={(value) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (value) editor.chain().focus().setFontFamily(value).run();\n else editor.chain().focus().unsetFontFamily().run();\n }}\n title=\"Font family\"\n />\n <SelectDropdown\n className=\"rte-bubble__select rte-bubble__select--size\"\n width={72}\n value={editor.getAttributes('textStyle').fontSize || ''}\n options={FONT_SIZES}\n onChange={(value) => {\n if (editor.isDestroyed || !editor.isEditable) return;\n if (value) (editor.chain().focus() as any).setFontSize(value).run();\n else (editor.chain().focus() as any).unsetFontSize().run();\n }}\n title=\"Font size\"\n />\n {onAddComment && (\n <>\n <div className=\"rte-bubble__divider\" />\n {btn(onAddComment, 'Comment', undefined,\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z\" /></svg>)}\n </>\n )}\n </div>\n );\n};\n\nexport default BubbleToolbar;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentDialog.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/CommentDialog.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\n\ninterface CommentDialogProps {\n open: boolean;\n onSubmit: (text: string) => void;\n onClose: () => void;\n}\n\nconst CommentDialog: React.FC<CommentDialogProps> = ({ open, onSubmit, onClose }) => {\n const [text, setText] = useState('');\n const inputRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n if (open) {\n setText('');\n setTimeout(() => inputRef.current?.focus(), 50);\n }\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [open, onClose]);\n\n if (!open) return null;\n\n const handleSubmit = () => {\n if (text.trim()) {\n onSubmit(text.trim());\n setText('');\n }\n };\n\n return (\n <div className=\"rte-dialog-overlay\" onClick={onClose}>\n <div className=\"rte-dialog\" onClick={(e) => e.stopPropagation()}>\n <div className=\"rte-dialog__header\">\n <span className=\"rte-dialog__title\">Add Comment</span>\n <button type=\"button\" className=\"rte-dialog__close\" onClick={onClose}>\n <svg width=\"16\" height=\"16\" 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 className=\"rte-dialog__body\">\n <textarea\n ref={inputRef}\n className=\"rte-dialog__textarea\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit(); }\n }}\n placeholder=\"Write your comment...\"\n rows={3}\n />\n </div>\n <div className=\"rte-dialog__footer\">\n <button type=\"button\" className=\"rte-dialog__btn rte-dialog__btn--cancel\" onClick={onClose}>Cancel</button>\n <button type=\"button\" className=\"rte-dialog__btn rte-dialog__btn--submit\" onClick={handleSubmit} disabled={!text.trim()}>Add Comment</button>\n </div>\n </div>\n </div>\n );\n};\n\nexport default CommentDialog;\n"],"mappings":";;;AAQA,
|
|
1
|
+
{"version":3,"file":"CommentDialog.js","names":["CommentDialog","text","setText","useState","inputRef","useRef","useEffect","open","handleKey","onClose","handleSubmit","onSubmit"],"sources":["../../../../src/components/pro/RichTextEditor/CommentDialog.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\n\ninterface CommentDialogProps {\n open: boolean;\n onSubmit: (text: string) => void;\n onClose: () => void;\n}\n\nconst CommentDialog: React.FC<CommentDialogProps> = ({ open, onSubmit, onClose }) => {\n const [text, setText] = useState('');\n const inputRef = useRef<HTMLTextAreaElement>(null);\n\n useEffect(() => {\n if (open) {\n setText('');\n setTimeout(() => inputRef.current?.focus(), 50);\n }\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handleKey);\n return () => document.removeEventListener('keydown', handleKey);\n }, [open, onClose]);\n\n if (!open) return null;\n\n const handleSubmit = () => {\n if (text.trim()) {\n onSubmit(text.trim());\n setText('');\n }\n };\n\n return (\n <div className=\"rte-dialog-overlay\" onClick={onClose}>\n <div className=\"rte-dialog\" onClick={(e) => e.stopPropagation()}>\n <div className=\"rte-dialog__header\">\n <span className=\"rte-dialog__title\">Add Comment</span>\n <button type=\"button\" className=\"rte-dialog__close\" onClick={onClose}>\n <svg width=\"16\" height=\"16\" 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 className=\"rte-dialog__body\">\n <textarea\n ref={inputRef}\n className=\"rte-dialog__textarea\"\n value={text}\n onChange={(e) => setText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit(); }\n }}\n placeholder=\"Write your comment...\"\n rows={3}\n />\n </div>\n <div className=\"rte-dialog__footer\">\n <button type=\"button\" className=\"rte-dialog__btn rte-dialog__btn--cancel\" onClick={onClose}>Cancel</button>\n <button type=\"button\" className=\"rte-dialog__btn rte-dialog__btn--submit\" onClick={handleSubmit} disabled={!text.trim()}>Add Comment</button>\n </div>\n </div>\n </div>\n );\n};\n\nexport default CommentDialog;\n"],"mappings":";;;AAQA,IAAMA,KAA+C,EAAE,SAAM,aAAU,iBAAc;CACnF,IAAM,CAACC,GAAMC,KAAWC,EAAS,EAAE,GAC7BC,IAAWC,EAA4B,IAAI;CAkBjD,IAhBAC,QAAgB;EACd,AAAIC,MACFL,EAAQ,EAAE,GACV,iBAAiBE,EAAS,SAAS,MAAM,GAAG,EAAE;CAElD,GAAG,CAACG,CAAI,CAAC,GAETD,QAAgB;EACd,IAAI,CAACC,GAAM;EACX,IAAMC,KAAa,MAAqB;GACtC,AAAI,EAAE,QAAQ,YAAUC,EAAQ;EAClC;EAEA,OADA,SAAS,iBAAiB,WAAWD,CAAS,SACjC,SAAS,oBAAoB,WAAWA,CAAS;CAChE,GAAG,CAACD,GAAME,CAAO,CAAC,GAEd,CAACF,GAAM,OAAO;CAElB,IAAMG,UAAqB;EACzB,AAAIT,EAAK,KAAK,MACZU,EAASV,EAAK,KAAK,CAAC,GACpBC,EAAQ,EAAE;CAEd;CAEA,OACE,kBAAC,OAAD;EAAK,WAAU;EAAqB,SAASO;EAC3C,UAAA,kBAAC,OAAD;GAAK,WAAU;GAAa,UAAU,MAAM,EAAE,gBAAgB;GAA9D,UAAA;IACE,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,QAAD;MAAM,WAAU;MAAoB,UAAA;KAAiB,CAAA,GACrD,kBAAC,UAAD;MAAQ,MAAK;MAAS,WAAU;MAAoB,SAASA;MAC3D,UAAA,kBAAC,OAAD;OAAK,OAAM;OAAK,QAAO;OAAK,SAAQ;OAAY,MAAK;OAAO,QAAO;OAAe,aAAY;OAA9F,UAAA,CAAkG,kBAAC,QAAD;QAAM,IAAG;QAAK,IAAG;QAAI,IAAG;QAAI,IAAG;OAAM,CAAA,GAAC,kBAAC,QAAD;QAAM,IAAG;QAAI,IAAG;QAAI,IAAG;QAAK,IAAG;OAAM,CAAA,CAAM;;KAC7K,CAAA,CACL;;IACL,kBAAC,OAAD;KAAK,WAAU;KACb,UAAA,kBAAC,YAAD;MACE,KAAKL;MACL,WAAU;MACV,OAAOH;MACP,WAAW,MAAMC,EAAQ,EAAE,OAAO,KAAK;MACvC,YAAY,MAAM;OAChB,AAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,aAAY,EAAE,eAAe,GAAGQ,EAAa;MAC3E;MACA,aAAY;MACZ,MAAM;KACP,CAAA;IACE,CAAA;IACL,kBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,kBAAC,UAAD;MAAQ,MAAK;MAAS,WAAU;MAA0C,SAASD;MAAS,UAAA;KAAc,CAAA,GAC1G,kBAAC,UAAD;MAAQ,MAAK;MAAS,WAAU;MAA0C,SAASC;MAAc,UAAU,CAACT,EAAK,KAAK;MAAG,UAAA;KAAmB,CAAA,CACzI;;GACF;;CACF,CAAA;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentPanel.js","names":[],"sources":["../../../../src/components/pro/RichTextEditor/CommentPanel.tsx"],"sourcesContent":["import React, { useState, useCallback, useRef, useEffect, useImperativeHandle, forwardRef } from 'react';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport type { CommentThread, CommentItem } from './extensions/CommentMark';\n\nexport interface CommentPanelHandle {\n scrollToThread: (id: string) => void;\n}\n\ninterface CommentPanelProps {\n editor: Editor;\n threads: CommentThread[];\n onThreadsChange: (threads: CommentThread[]) => void;\n onRequestAddComment: () => void;\n currentUser?: string;\n editable?: boolean;\n}\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\nconst CommentPanel = forwardRef<CommentPanelHandle, CommentPanelProps>(({\n editor,\n threads,\n onThreadsChange,\n onRequestAddComment,\n currentUser = 'User',\n editable = true,\n}, ref) => {\n const [replyingTo, setReplyingTo] = useState<string | null>(null);\n const [replyText, setReplyText] = useState('');\n const replyInputRef = useRef<HTMLInputElement>(null);\n const threadRefs = useRef<Map<string, HTMLDivElement>>(new Map());\n const listRef = useRef<HTMLDivElement>(null);\n const latest = useRef({ editable, threads });\n latest.current = { editable, threads };\n const editorEditable = useEditorState({ editor, selector: ({ editor }) => editor.isEditable });\n const canEdit = editable && editorEditable;\n\n useImperativeHandle(ref, () => ({\n scrollToThread: (id: string) => {\n const el = threadRefs.current.get(id);\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n el.classList.add('rte-comments__thread--highlight');\n setTimeout(() => el.classList.remove('rte-comments__thread--highlight'), 1500);\n }\n },\n }));\n\n useEffect(() => {\n if (replyingTo && replyInputRef.current) {\n replyInputRef.current.focus();\n }\n }, [replyingTo]);\n\n const toggleResolve = useCallback((threadId: string) => {\n if (!latest.current.editable || !editor.isEditable) return;\n const thread = latest.current.threads.find((t) => t.id === threadId);\n if (!thread) return;\n const resolved = !thread.resolved;\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 === threadId) {\n tr.removeMark(pos, pos + node.nodeSize, mark)\n .addMark(pos, pos + node.nodeSize, mark.type.create({ ...mark.attrs, resolved }));\n }\n });\n });\n if (tr.docChanged) editor.view.dispatch(tr);\n onThreadsChange(latest.current.threads.map((t) => t.id === threadId ? { ...t, resolved } : t));\n }, [editor, threads, onThreadsChange]);\n\n const addReply = useCallback((threadId: string) => {\n if (!latest.current.editable || !editor.isEditable || !replyText.trim()) return;\n if (!latest.current.threads.some((t) => t.id === threadId && !t.resolved)) 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 === threadId ? { ...t, comments: [...t.comments, reply] } : t\n );\n onThreadsChange(updated);\n setReplyText('');\n setReplyingTo(null);\n }, [editor, replyText, threads, onThreadsChange, currentUser]);\n\n const deleteThread = useCallback((threadId: string) => {\n if (!latest.current.editable || !editor.isEditable) return;\n if (!latest.current.threads.some((t) => t.id === threadId)) 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 === threadId) {\n tr.removeMark(pos, pos + node.nodeSize, mark);\n }\n });\n });\n if (tr.docChanged) editor.view.dispatch(tr);\n onThreadsChange(latest.current.threads.filter((t) => t.id !== threadId));\n }, [editor, threads, onThreadsChange]);\n\n const activeThreads = threads.filter((t) => !t.resolved);\n const resolvedThreads = threads.filter((t) => t.resolved);\n\n const renderThread = (thread: CommentThread) => (\n <div\n key={thread.id}\n ref={(el) => { if (el) threadRefs.current.set(thread.id, el); else threadRefs.current.delete(thread.id); }}\n className={`rte-comments__thread ${thread.resolved ? 'rte-comments__thread--resolved' : ''}`}\n >\n <div className=\"rte-comments__thread-header\">\n <span className={`rte-comments__status ${thread.resolved ? 'rte-comments__status--resolved' : ''}`}>\n {thread.resolved ? '✓ Resolved' : 'Open'}\n </span>\n {canEdit && <div className=\"rte-comments__thread-actions\">\n <button\n type=\"button\"\n className=\"rte-comments__icon-btn\"\n onClick={() => toggleResolve(thread.id)}\n title={thread.resolved ? 'Unresolve' : 'Resolve'}\n >\n {thread.resolved ? (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-4 0h4\" /></svg>\n ) : (\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 )}\n </button>\n <button\n type=\"button\"\n className=\"rte-comments__icon-btn rte-comments__icon-btn--danger\"\n onClick={() => deleteThread(thread.id)}\n title=\"Delete thread\"\n >\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 {thread.comments.map((c) => (\n <div key={c.id} className=\"rte-comments__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 && !thread.resolved && (replyingTo === thread.id ? (\n <div className=\"rte-comments__reply-form\">\n <input\n ref={replyInputRef}\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(thread.id); }\n if (e.key === 'Escape') { setReplyingTo(null); setReplyText(''); }\n }}\n placeholder=\"Reply...\"\n />\n <button type=\"button\" className=\"rte-comments__reply-send\" onClick={() => addReply(thread.id)}>\n <svg width=\"14\" height=\"14\" 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 ) : (\n <button\n type=\"button\"\n className=\"rte-comments__reply-trigger\"\n onClick={() => {\n if (!latest.current.editable || !editor.isEditable) return;\n if (!latest.current.threads.some((t) => t.id === thread.id && !t.resolved)) return;\n setReplyingTo(thread.id);\n }}\n >\n Reply...\n </button>\n ))}\n </div>\n );\n\n return (\n <div className=\"rte-comments\">\n <div className=\"rte-comments__header\">\n <span className=\"rte-comments__title\">\n Comments\n {activeThreads.length > 0 && <span className=\"rte-comments__badge\">{activeThreads.length}</span>}\n </span>\n {canEdit && <button\n type=\"button\"\n className=\"rte-comments__add-btn\"\n onClick={() => {\n if (latest.current.editable && editor.isEditable) onRequestAddComment();\n }}\n title=\"Add comment to selection\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" /></svg>\n </button>}\n </div>\n\n <div ref={listRef} className=\"rte-comments__list\">\n {threads.length === 0 ? (\n <div className=\"rte-comments__empty\">{canEdit ? 'Select text and click + to add a comment' : 'No comments'}</div>\n ) : (\n <>\n {activeThreads.map(renderThread)}\n {resolvedThreads.length > 0 && (\n <>\n <div className=\"rte-comments__section-label\">Resolved ({resolvedThreads.length})</div>\n {resolvedThreads.map(renderThread)}\n </>\n )}\n </>\n )}\n </div>\n </div>\n );\n});\n\nCommentPanel.displayName = 'CommentPanel';\n\nexport default CommentPanel;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CommentPanel.js","names":["_Fragment","generateId","timeAgo","diff","ts","sec","min","hr","CommentPanel","forwardRef","replyingTo","setReplyingTo","useState","replyText","setReplyText","replyInputRef","useRef","threadRefs","listRef","latest","editorEditable","useEditorState","editor","canEdit","editable","useImperativeHandle","ref","el","id","useEffect","toggleResolve","useCallback","thread","t","threadId","resolved","tr","mark","pos","node","onThreadsChange","threads","addReply","reply","currentUser","deleteThread","activeThreads","resolvedThreads","renderThread","c","onRequestAddComment","Fragment"],"sources":["../../../../src/components/pro/RichTextEditor/CommentPanel.tsx"],"sourcesContent":["import React, { useState, useCallback, useRef, useEffect, useImperativeHandle, forwardRef } from 'react';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport type { CommentThread, CommentItem } from './extensions/CommentMark';\n\nexport interface CommentPanelHandle {\n scrollToThread: (id: string) => void;\n}\n\ninterface CommentPanelProps {\n editor: Editor;\n threads: CommentThread[];\n onThreadsChange: (threads: CommentThread[]) => void;\n onRequestAddComment: () => void;\n currentUser?: string;\n editable?: boolean;\n}\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\nconst CommentPanel = forwardRef<CommentPanelHandle, CommentPanelProps>(({\n editor,\n threads,\n onThreadsChange,\n onRequestAddComment,\n currentUser = 'User',\n editable = true,\n}, ref) => {\n const [replyingTo, setReplyingTo] = useState<string | null>(null);\n const [replyText, setReplyText] = useState('');\n const replyInputRef = useRef<HTMLInputElement>(null);\n const threadRefs = useRef<Map<string, HTMLDivElement>>(new Map());\n const listRef = useRef<HTMLDivElement>(null);\n const latest = useRef({ editable, threads });\n latest.current = { editable, threads };\n const editorEditable = useEditorState({ editor, selector: ({ editor }) => editor.isEditable });\n const canEdit = editable && editorEditable;\n\n useImperativeHandle(ref, () => ({\n scrollToThread: (id: string) => {\n const el = threadRefs.current.get(id);\n if (el) {\n el.scrollIntoView({ behavior: 'smooth', block: 'center' });\n el.classList.add('rte-comments__thread--highlight');\n setTimeout(() => el.classList.remove('rte-comments__thread--highlight'), 1500);\n }\n },\n }));\n\n useEffect(() => {\n if (replyingTo && replyInputRef.current) {\n replyInputRef.current.focus();\n }\n }, [replyingTo]);\n\n const toggleResolve = useCallback((threadId: string) => {\n if (!latest.current.editable || !editor.isEditable) return;\n const thread = latest.current.threads.find((t) => t.id === threadId);\n if (!thread) return;\n const resolved = !thread.resolved;\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 === threadId) {\n tr.removeMark(pos, pos + node.nodeSize, mark)\n .addMark(pos, pos + node.nodeSize, mark.type.create({ ...mark.attrs, resolved }));\n }\n });\n });\n if (tr.docChanged) editor.view.dispatch(tr);\n onThreadsChange(latest.current.threads.map((t) => t.id === threadId ? { ...t, resolved } : t));\n }, [editor, threads, onThreadsChange]);\n\n const addReply = useCallback((threadId: string) => {\n if (!latest.current.editable || !editor.isEditable || !replyText.trim()) return;\n if (!latest.current.threads.some((t) => t.id === threadId && !t.resolved)) 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 === threadId ? { ...t, comments: [...t.comments, reply] } : t\n );\n onThreadsChange(updated);\n setReplyText('');\n setReplyingTo(null);\n }, [editor, replyText, threads, onThreadsChange, currentUser]);\n\n const deleteThread = useCallback((threadId: string) => {\n if (!latest.current.editable || !editor.isEditable) return;\n if (!latest.current.threads.some((t) => t.id === threadId)) 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 === threadId) {\n tr.removeMark(pos, pos + node.nodeSize, mark);\n }\n });\n });\n if (tr.docChanged) editor.view.dispatch(tr);\n onThreadsChange(latest.current.threads.filter((t) => t.id !== threadId));\n }, [editor, threads, onThreadsChange]);\n\n const activeThreads = threads.filter((t) => !t.resolved);\n const resolvedThreads = threads.filter((t) => t.resolved);\n\n const renderThread = (thread: CommentThread) => (\n <div\n key={thread.id}\n ref={(el) => { if (el) threadRefs.current.set(thread.id, el); else threadRefs.current.delete(thread.id); }}\n className={`rte-comments__thread ${thread.resolved ? 'rte-comments__thread--resolved' : ''}`}\n >\n <div className=\"rte-comments__thread-header\">\n <span className={`rte-comments__status ${thread.resolved ? 'rte-comments__status--resolved' : ''}`}>\n {thread.resolved ? '✓ Resolved' : 'Open'}\n </span>\n {canEdit && <div className=\"rte-comments__thread-actions\">\n <button\n type=\"button\"\n className=\"rte-comments__icon-btn\"\n onClick={() => toggleResolve(thread.id)}\n title={thread.resolved ? 'Unresolve' : 'Resolve'}\n >\n {thread.resolved ? (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><path d=\"M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-4 0h4\" /></svg>\n ) : (\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 )}\n </button>\n <button\n type=\"button\"\n className=\"rte-comments__icon-btn rte-comments__icon-btn--danger\"\n onClick={() => deleteThread(thread.id)}\n title=\"Delete thread\"\n >\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 {thread.comments.map((c) => (\n <div key={c.id} className=\"rte-comments__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 && !thread.resolved && (replyingTo === thread.id ? (\n <div className=\"rte-comments__reply-form\">\n <input\n ref={replyInputRef}\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(thread.id); }\n if (e.key === 'Escape') { setReplyingTo(null); setReplyText(''); }\n }}\n placeholder=\"Reply...\"\n />\n <button type=\"button\" className=\"rte-comments__reply-send\" onClick={() => addReply(thread.id)}>\n <svg width=\"14\" height=\"14\" 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 ) : (\n <button\n type=\"button\"\n className=\"rte-comments__reply-trigger\"\n onClick={() => {\n if (!latest.current.editable || !editor.isEditable) return;\n if (!latest.current.threads.some((t) => t.id === thread.id && !t.resolved)) return;\n setReplyingTo(thread.id);\n }}\n >\n Reply...\n </button>\n ))}\n </div>\n );\n\n return (\n <div className=\"rte-comments\">\n <div className=\"rte-comments__header\">\n <span className=\"rte-comments__title\">\n Comments\n {activeThreads.length > 0 && <span className=\"rte-comments__badge\">{activeThreads.length}</span>}\n </span>\n {canEdit && <button\n type=\"button\"\n className=\"rte-comments__add-btn\"\n onClick={() => {\n if (latest.current.editable && editor.isEditable) onRequestAddComment();\n }}\n title=\"Add comment to selection\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\" /><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\" /></svg>\n </button>}\n </div>\n\n <div ref={listRef} className=\"rte-comments__list\">\n {threads.length === 0 ? (\n <div className=\"rte-comments__empty\">{canEdit ? 'Select text and click + to add a comment' : 'No comments'}</div>\n ) : (\n <>\n {activeThreads.map(renderThread)}\n {resolvedThreads.length > 0 && (\n <>\n <div className=\"rte-comments__section-label\">Resolved ({resolvedThreads.length})</div>\n {resolvedThreads.map(renderThread)}\n </>\n )}\n </>\n )}\n </div>\n </div>\n );\n});\n\nCommentPanel.displayName = 'CommentPanel';\n\nexport default CommentPanel;\n"],"mappings":"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"}
|