dishui 0.0.106 → 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.d.ts +1 -0
- package/dist/components/pro/RichTextEditor/AIRewrite.js +109 -88
- 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 +133 -132
- 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.d.ts +2 -0
- 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":"AIPanel.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/AIPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport Button from '../../../Button';\nimport Input from '../../../Input';\nimport Select from '../../../Select';\nimport Label from '../../../Label';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowAI } from '../context/FlowAIContext';\nimport { completeAIChatStream } from '../nodes/aiClient';\nimport { ROOT_CANVAS_ID, DEFAULT_NODE_DATA, DEFAULT_EDGE_DATA } from '../constants';\nimport type { FlowAIConfig, FlowDocument } from '../types';\n\n/**\n * System prompt that constrains the model to emit a FlowDocument JSON so the\n * result can be parsed and loaded directly onto the canvas.\n */\nconst SYSTEM_PROMPT = `You are a diagramming assistant for a flowchart editor. Convert the user's request (a description, or an uploaded diagram image to reproduce) into a flow document.\n\nReply with ONE fenced \\`\\`\\`json code block and nothing else. The JSON must match:\n{\n \"canvases\": {\n \"root\": {\n \"nodes\": [\n { \"id\": \"n1\", \"type\": \"shapeRoundRect\", \"position\": {\"x\": 80, \"y\": 80}, \"width\": 160, \"height\": 64,\n \"data\": { \"label\": \"Start\" } }\n ],\n \"edges\": [\n { \"id\": \"e1\", \"source\": \"n1\", \"target\": \"n2\", \"type\": \"smoothstep\",\n \"data\": { \"labelText\": \"yes\" } }\n ],\n \"lines\": []\n }\n },\n \"stack\": [\"root\"]\n}\n\nRules:\n- Node \"type\" is one of: shapeRect, shapeRoundRect, shapeEllipse, shapeDiamond, shapeParallelogram, shapeDocument, shapeHexagon. Use shapeDiamond for decisions, shapeRoundRect for processes, shapeEllipse for start/end.\n- Give every node a unique \"id\". Every edge \"source\"/\"target\" must reference an existing node id.\n- Lay nodes out on a readable grid (top-to-bottom or left-to-right), spacing ~180px, no overlaps. Widths ~140-180, heights ~56-72 (diamonds ~120x100).\n- Put a short \"label\" on each node. Optional edge label goes in data.labelText.\n- Do NOT include colors; the editor themes them automatically.\n- Output ONLY the JSON code block.`;\n\n/** Extract and parse the first JSON object from an AI reply. */\nfunction parseFlowJson(text: string): FlowDocument | null {\n let raw = text.trim();\n const fence = /```(?:json)?\\s*([\\s\\S]*?)```/i.exec(raw);\n if (fence) raw = fence[1].trim();\n else {\n const start = raw.indexOf('{');\n const end = raw.lastIndexOf('}');\n if (start >= 0 && end > start) raw = raw.slice(start, end + 1);\n }\n try {\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || !parsed.canvases) return null;\n return parsed as FlowDocument;\n } catch {\n return null;\n }\n}\n\n/** Normalize an AI-produced document: fill defaults, ensure a root canvas. */\nfunction normalizeAIDocument(doc: FlowDocument): FlowDocument {\n const canvases = doc.canvases ?? {};\n const rootKey = doc.stack?.[doc.stack.length - 1] ?? ROOT_CANVAS_ID;\n const canvas = canvases[rootKey] ?? canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n const nodes = (canvas.nodes ?? []).map((n: any, i: number) => ({\n id: n.id ?? `n${i + 1}`,\n type: n.type ?? 'shapeRoundRect',\n position: { x: Number(n.position?.x ?? 80), y: Number(n.position?.y ?? 80 + i * 120) },\n width: Number(n.width ?? 160),\n height: Number(n.height ?? 64),\n zIndex: n.zIndex ?? i,\n data: { ...DEFAULT_NODE_DATA, ...n.data, label: n.data?.label ?? n.label ?? 'Node' },\n }));\n const nodeById = new Map<string, any>(nodes.map((n) => [n.id, n]));\n const edges = (canvas.edges ?? []).map((e: any, i: number) => ({\n id: e.id ?? `e${i + 1}`,\n source: e.source,\n target: e.target,\n type: e.type ?? 'smoothstep',\n data: { ...DEFAULT_EDGE_DATA, ...e.data },\n })).filter((e: any) => e.source && e.target)\n .map((e: any) => pinEdgeToSideMidpoints(e, nodeById));\n return {\n canvases: { [ROOT_CANVAS_ID]: { nodes, edges, lines: [] } },\n stack: [ROOT_CANVAS_ID],\n };\n}\n\n/**\n * Pin an AI-generated edge to the midpoint handles of the facing node sides\n * (`r_0.5` / `l_0.5` / `t_0.5` / `b_0.5`) so connections attach at the center\n * of each side instead of sliding along the side toward the other node.\n */\nfunction pinEdgeToSideMidpoints(edge: any, nodeById: Map<string, any>): any {\n const s = nodeById.get(edge.source);\n const t = nodeById.get(edge.target);\n if (!s || !t || s === t) return edge;\n const dx = (t.position.x + t.width / 2) - (s.position.x + s.width / 2);\n const dy = (t.position.y + t.height / 2) - (s.position.y + s.height / 2);\n if (Math.abs(dx) >= Math.abs(dy)) {\n const forward = dx >= 0;\n return {\n ...edge,\n sourceHandle: forward ? 'r_0.5' : 'l_0.5',\n targetHandle: forward ? 'l_0.5' : 'r_0.5',\n };\n }\n const forward = dy >= 0;\n return {\n ...edge,\n sourceHandle: forward ? 'b_0.5' : 't_0.5',\n targetHandle: forward ? 't_0.5' : 'b_0.5',\n };\n}\n\nconst PROTOCOL_OPTIONS = [\n { value: 'openai', label: 'OpenAI 兼容' },\n { value: 'anthropic', label: 'Anthropic' },\n];\n\n/** Char count at which the simulated progress bar saturates (99%). */\nconst PROGRESS_FULL_CHARS = 20000;\n\nexport function AIPanelContent() {\n const { setDoc } = useFlowContext();\n const { aiConfig, setAIConfig, showAIConfig } = useFlowAI();\n\n const [prompt, setPrompt] = useState('');\n const [imageDataUrl, setImageDataUrl] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [status, setStatus] = useState<string | null>(null);\n const [streamOpen, setStreamOpen] = useState(false);\n const [finished, setFinished] = useState(false);\n const [pendingDoc, setPendingDoc] = useState<FlowDocument | null>(null);\n const [displayLen, setDisplayLen] = useState(0);\n const abortRef = useRef<AbortController | null>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const streamBodyRef = useRef<HTMLPreElement>(null);\n const streamTailRef = useRef<HTMLPreElement>(null);\n /** Full text received from the model so far (grows on every SSE delta). */\n const targetRef = useRef('');\n\n const updateConfig = useCallback((patch: Partial<FlowAIConfig>) => {\n setAIConfig({ ...aiConfig, ...patch });\n }, [aiConfig, setAIConfig]);\n\n const onPickImage = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => setImageDataUrl(reader.result as string);\n reader.readAsDataURL(file);\n }, []);\n\n // Accept an image pasted from the clipboard (Ctrl/Cmd+V) anywhere in the panel\n // or into the textarea. Falls through to normal text paste otherwise.\n const onPaste = useCallback((e: React.ClipboardEvent) => {\n const items = e.clipboardData?.items;\n if (!items) return;\n for (const item of items) {\n if (item.type.startsWith('image/')) {\n const file = item.getAsFile();\n if (file) {\n e.preventDefault();\n const reader = new FileReader();\n reader.onload = () => setImageDataUrl(reader.result as string);\n reader.readAsDataURL(file);\n return;\n }\n }\n }\n }, []);\n\n // Progressive reveal: SSE deltas land in `targetRef` (often several chunks\n // per network read, which React would batch into a single paint), and this\n // timer types the text out with an exponential catch-up so the panel always\n // shows the reply growing character-by-character.\n useEffect(() => {\n const timer = window.setInterval(() => {\n setDisplayLen((len) => {\n const target = targetRef.current.length;\n if (len >= target) return len;\n return len + Math.max(8, Math.ceil((target - len) / 8));\n });\n }, 40);\n return () => window.clearInterval(timer);\n }, []);\n\n const streamText = targetRef.current.slice(0, displayLen);\n\n // Keep the streaming output pinned to the latest chunk while visible.\n useEffect(() => {\n const el = streamBodyRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n const tail = streamTailRef.current;\n if (tail) tail.scrollTop = tail.scrollHeight;\n }, [streamText, streamOpen]);\n\n const generate = useCallback(async () => {\n if (busy) return;\n if (!aiConfig.gateway || !aiConfig.model) {\n setError('请先配置 AI 接口地址与模型');\n return;\n }\n if (!prompt.trim() && !imageDataUrl) {\n setError('请输入需求描述,或上传一张流程图');\n return;\n }\n setError(null);\n setStatus('正在生成…');\n targetRef.current = '';\n setDisplayLen(0);\n setFinished(false);\n setPendingDoc(null);\n setBusy(true);\n const ac = new AbortController();\n abortRef.current = ac;\n try {\n const text = await completeAIChatStream(\n aiConfig,\n prompt.trim() || '请根据这张图片复刻出对应的流程图。',\n {\n imageDataUrl: imageDataUrl ?? undefined,\n systemPrompt: SYSTEM_PROMPT,\n signal: ac.signal,\n onDelta: (accumulated) => { targetRef.current = accumulated; },\n },\n );\n setFinished(true);\n const parsed = parseFlowJson(text);\n if (!parsed) {\n setError('AI 返回内容无法解析为流程图,请重试或调整描述');\n setStatus(null);\n return;\n }\n setPendingDoc(normalizeAIDocument(parsed));\n setStatus(null);\n } catch (err: any) {\n if (err?.name !== 'AbortError') setError(err?.message ?? '生成失败');\n setStatus(null);\n } finally {\n setBusy(false);\n abortRef.current = null;\n }\n }, [busy, aiConfig, prompt, imageDataUrl]);\n\n const cancel = useCallback(() => abortRef.current?.abort(), []);\n\n /** Merge the generated canvas into the current canvas, remapping ids. */\n const applyInsert = useCallback(() => {\n if (!pendingDoc) return;\n const gen = pendingDoc.canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n setDoc((prev) => {\n const canvasId = prev.stack[prev.stack.length - 1] ?? ROOT_CANVAS_ID;\n const cur = prev.canvases[canvasId] ?? { nodes: [], edges: [], lines: [] };\n const used = new Set([\n ...cur.nodes.map((n) => n.id),\n ...cur.edges.map((e) => e.id),\n ...cur.lines.map((l) => l.id),\n ]);\n const fresh = (id: string) => {\n let next = id;\n let i = 1;\n while (used.has(next)) next = `${id}_${i++}`;\n used.add(next);\n return next;\n };\n const idMap = new Map<string, string>();\n const nodes = gen.nodes.map((n) => {\n const id = fresh(n.id);\n idMap.set(n.id, id);\n return { ...n, id };\n });\n const edges = gen.edges.map((e) => ({\n ...e,\n id: fresh(e.id),\n source: idMap.get(e.source) ?? e.source,\n target: idMap.get(e.target) ?? e.target,\n }));\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [canvasId]: { nodes: [...cur.nodes, ...nodes], edges: [...cur.edges, ...edges], lines: cur.lines },\n },\n };\n });\n setPendingDoc(null);\n setStatus('已插入流程图');\n }, [pendingDoc, setDoc]);\n\n /** Clear the current canvas, then place the generated content onto it. */\n const applyReplace = useCallback(() => {\n if (!pendingDoc) return;\n const gen = pendingDoc.canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n setDoc((prev) => {\n const canvasId = prev.stack[prev.stack.length - 1] ?? ROOT_CANVAS_ID;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [canvasId]: { nodes: gen.nodes, edges: gen.edges, lines: [] },\n },\n };\n });\n setPendingDoc(null);\n setStatus('已替换画布');\n }, [pendingDoc, setDoc]);\n\n const charCount = streamText.length;\n const fullyRevealed = charCount >= targetRef.current.length;\n const progress = finished && fullyRevealed\n ? 100\n : Math.min(99, Math.floor((charCount / PROGRESS_FULL_CHARS) * 99));\n\n return (\n <div className=\"flow-ai-panel\" onPaste={onPaste}>\n {showAIConfig && (\n <div className=\"flow-ai-section\">\n <div className=\"flow-ai-section-title\">模型配置</div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">协议</Label>\n <Select\n options={PROTOCOL_OPTIONS}\n value={aiConfig.protocol}\n onChange={(v) => updateConfig({ protocol: v as FlowAIConfig['protocol'] })}\n style={{ fontSize: 12 }}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">接口地址</Label>\n <Input\n size=\"xs\"\n value={aiConfig.gateway}\n placeholder=\"https://api.moonshot.cn/v1\"\n onChange={(e) => updateConfig({ gateway: e.target.value })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">模型</Label>\n <Input\n size=\"xs\"\n value={aiConfig.model}\n placeholder=\"gpt-4o-mini\"\n onChange={(e) => updateConfig({ model: e.target.value })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">API Key</Label>\n <Input\n size=\"xs\"\n type=\"password\"\n value={aiConfig.apiKey ?? ''}\n placeholder=\"sk-…\"\n onChange={(e) => updateConfig({ apiKey: e.target.value })}\n />\n </div>\n </div>\n )}\n\n <div className=\"flow-ai-section\">\n <div className=\"flow-ai-section-title\">生成流程图</div>\n <textarea\n className=\"flow-ai-textarea\"\n value={prompt}\n placeholder=\"描述你想要的流程,例如:用户注册流程,包含邮箱校验、发送验证码、创建账号等步骤(可直接粘贴图片)\"\n onChange={(e) => setPrompt(e.target.value)}\n onPaste={onPaste}\n onPointerDown={(e) => e.stopPropagation()}\n />\n\n <div className=\"flow-ai-image-row\">\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"image/*\"\n style={{ display: 'none' }}\n onChange={onPickImage}\n />\n {imageDataUrl ? (\n <div className=\"flow-ai-image-preview\">\n <img src={imageDataUrl} alt=\"参考图\" />\n <button\n type=\"button\"\n className=\"flow-ai-image-remove\"\n title=\"移除图片\"\n onClick={() => setImageDataUrl(null)}\n >×</button>\n </div>\n ) : (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => fileRef.current?.click()}>\n 上传流程图图片\n </Button>\n )}\n <span className=\"flow-ai-hint\">或粘贴图片 (Ctrl/⌘+V)</span>\n </div>\n\n <div className=\"flow-ai-actions\">\n {busy ? (\n <Button size=\"xs\" variant=\"ghost\" onClick={cancel}>停止</Button>\n ) : (\n <Button size=\"xs\" variant=\"primary\" onClick={generate}>生成流程图</Button>\n )}\n </div>\n\n {(busy || streamText) && (\n <div className=\"flow-ai-stream\">\n <div className=\"flow-ai-progress\">\n <div className=\"flow-ai-progress-track\">\n <div className=\"flow-ai-progress-bar\" style={{ width: `${progress}%` }} />\n </div>\n <span className=\"flow-ai-progress-label\">{progress}%</span>\n </div>\n <button\n type=\"button\"\n className=\"flow-ai-stream-header\"\n onClick={() => setStreamOpen((open) => !open)}\n >\n <span className={`flow-ai-stream-chevron${streamOpen ? ' flow-ai-stream-chevron--open' : ''}`}>▸</span>\n <span>返回内容</span>\n <span className=\"flow-ai-stream-count\">{charCount.toLocaleString()} 字符</span>\n </button>\n {streamOpen ? (\n <pre ref={streamBodyRef} className=\"flow-ai-stream-body\">{streamText || '等待返回…'}</pre>\n ) : (\n streamText && <pre ref={streamTailRef} className=\"flow-ai-stream-tail\">{streamText}</pre>\n )}\n </div>\n )}\n\n {status && !error && <div className=\"flow-ai-status\">{status}</div>}\n {error && <div className=\"flow-media-error\">{error}</div>}\n </div>\n\n {pendingDoc && (\n <div className=\"flow-ai-dialog-overlay\" onClick={() => setPendingDoc(null)}>\n <div\n className=\"flow-ai-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"流程图已生成\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flow-ai-dialog-title\">流程图已生成</div>\n <div className=\"flow-ai-dialog-desc\">\n 插入:将生成内容追加到当前画布;替换:清空当前画布后再插入。\n </div>\n <div className=\"flow-ai-dialog-actions\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setPendingDoc(null)}>取消</Button>\n <Button size=\"xs\" variant=\"neutral\" outline onClick={applyInsert}>插入</Button>\n <Button size=\"xs\" variant=\"primary\" onClick={applyReplace}>替换</Button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AIPanel.js","names":["Button","ButtonWithCompounds","Input","Label","Select","SYSTEM_PROMPT","parseFlowJson","raw","text","fence","start","end","parsed","normalizeAIDocument","canvases","doc","canvas","\"root\"","nodes","n","i","DEFAULT_NODE_DATA","nodeById","edges","DEFAULT_EDGE_DATA","pinEdgeToSideMidpoints","ROOT_CANVAS_ID","s","edge","t","dx","dy","forward","PROTOCOL_OPTIONS","PROGRESS_FULL_CHARS","AIPanelContent","useFlowContext","useFlowAI","prompt","setPrompt","useState","imageDataUrl","setImageDataUrl","busy","setBusy","error","setError","status","setStatus","streamOpen","setStreamOpen","finished","setFinished","pendingDoc","setPendingDoc","displayLen","setDisplayLen","abortRef","useRef","fileRef","streamBodyRef","streamTailRef","targetRef","updateConfig","useCallback","aiConfig","patch","setAIConfig","onPickImage","file","reader","onPaste","items","item","timer","target","len","streamText","el","tail","generate","ac","completeAIChatStream","accumulated","err","cancel","applyInsert","gen","setDoc","canvasId","prev","cur","used","l","fresh","next","id","idMap","applyReplace","charCount","fullyRevealed","progress","showAIConfig","v","open"],"sources":["../../../../../src/components/pro/Flow/panels/AIPanel.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport Button from '../../../Button';\nimport Input from '../../../Input';\nimport Select from '../../../Select';\nimport Label from '../../../Label';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowAI } from '../context/FlowAIContext';\nimport { completeAIChatStream } from '../nodes/aiClient';\nimport { ROOT_CANVAS_ID, DEFAULT_NODE_DATA, DEFAULT_EDGE_DATA } from '../constants';\nimport type { FlowAIConfig, FlowDocument } from '../types';\n\n/**\n * System prompt that constrains the model to emit a FlowDocument JSON so the\n * result can be parsed and loaded directly onto the canvas.\n */\nconst SYSTEM_PROMPT = `You are a diagramming assistant for a flowchart editor. Convert the user's request (a description, or an uploaded diagram image to reproduce) into a flow document.\n\nReply with ONE fenced \\`\\`\\`json code block and nothing else. The JSON must match:\n{\n \"canvases\": {\n \"root\": {\n \"nodes\": [\n { \"id\": \"n1\", \"type\": \"shapeRoundRect\", \"position\": {\"x\": 80, \"y\": 80}, \"width\": 160, \"height\": 64,\n \"data\": { \"label\": \"Start\" } }\n ],\n \"edges\": [\n { \"id\": \"e1\", \"source\": \"n1\", \"target\": \"n2\", \"type\": \"smoothstep\",\n \"data\": { \"labelText\": \"yes\" } }\n ],\n \"lines\": []\n }\n },\n \"stack\": [\"root\"]\n}\n\nRules:\n- Node \"type\" is one of: shapeRect, shapeRoundRect, shapeEllipse, shapeDiamond, shapeParallelogram, shapeDocument, shapeHexagon. Use shapeDiamond for decisions, shapeRoundRect for processes, shapeEllipse for start/end.\n- Give every node a unique \"id\". Every edge \"source\"/\"target\" must reference an existing node id.\n- Lay nodes out on a readable grid (top-to-bottom or left-to-right), spacing ~180px, no overlaps. Widths ~140-180, heights ~56-72 (diamonds ~120x100).\n- Put a short \"label\" on each node. Optional edge label goes in data.labelText.\n- Do NOT include colors; the editor themes them automatically.\n- Output ONLY the JSON code block.`;\n\n/** Extract and parse the first JSON object from an AI reply. */\nfunction parseFlowJson(text: string): FlowDocument | null {\n let raw = text.trim();\n const fence = /```(?:json)?\\s*([\\s\\S]*?)```/i.exec(raw);\n if (fence) raw = fence[1].trim();\n else {\n const start = raw.indexOf('{');\n const end = raw.lastIndexOf('}');\n if (start >= 0 && end > start) raw = raw.slice(start, end + 1);\n }\n try {\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== 'object' || !parsed.canvases) return null;\n return parsed as FlowDocument;\n } catch {\n return null;\n }\n}\n\n/** Normalize an AI-produced document: fill defaults, ensure a root canvas. */\nfunction normalizeAIDocument(doc: FlowDocument): FlowDocument {\n const canvases = doc.canvases ?? {};\n const rootKey = doc.stack?.[doc.stack.length - 1] ?? ROOT_CANVAS_ID;\n const canvas = canvases[rootKey] ?? canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n const nodes = (canvas.nodes ?? []).map((n: any, i: number) => ({\n id: n.id ?? `n${i + 1}`,\n type: n.type ?? 'shapeRoundRect',\n position: { x: Number(n.position?.x ?? 80), y: Number(n.position?.y ?? 80 + i * 120) },\n width: Number(n.width ?? 160),\n height: Number(n.height ?? 64),\n zIndex: n.zIndex ?? i,\n data: { ...DEFAULT_NODE_DATA, ...n.data, label: n.data?.label ?? n.label ?? 'Node' },\n }));\n const nodeById = new Map<string, any>(nodes.map((n) => [n.id, n]));\n const edges = (canvas.edges ?? []).map((e: any, i: number) => ({\n id: e.id ?? `e${i + 1}`,\n source: e.source,\n target: e.target,\n type: e.type ?? 'smoothstep',\n data: { ...DEFAULT_EDGE_DATA, ...e.data },\n })).filter((e: any) => e.source && e.target)\n .map((e: any) => pinEdgeToSideMidpoints(e, nodeById));\n return {\n canvases: { [ROOT_CANVAS_ID]: { nodes, edges, lines: [] } },\n stack: [ROOT_CANVAS_ID],\n };\n}\n\n/**\n * Pin an AI-generated edge to the midpoint handles of the facing node sides\n * (`r_0.5` / `l_0.5` / `t_0.5` / `b_0.5`) so connections attach at the center\n * of each side instead of sliding along the side toward the other node.\n */\nfunction pinEdgeToSideMidpoints(edge: any, nodeById: Map<string, any>): any {\n const s = nodeById.get(edge.source);\n const t = nodeById.get(edge.target);\n if (!s || !t || s === t) return edge;\n const dx = (t.position.x + t.width / 2) - (s.position.x + s.width / 2);\n const dy = (t.position.y + t.height / 2) - (s.position.y + s.height / 2);\n if (Math.abs(dx) >= Math.abs(dy)) {\n const forward = dx >= 0;\n return {\n ...edge,\n sourceHandle: forward ? 'r_0.5' : 'l_0.5',\n targetHandle: forward ? 'l_0.5' : 'r_0.5',\n };\n }\n const forward = dy >= 0;\n return {\n ...edge,\n sourceHandle: forward ? 'b_0.5' : 't_0.5',\n targetHandle: forward ? 't_0.5' : 'b_0.5',\n };\n}\n\nconst PROTOCOL_OPTIONS = [\n { value: 'openai', label: 'OpenAI 兼容' },\n { value: 'anthropic', label: 'Anthropic' },\n];\n\n/** Char count at which the simulated progress bar saturates (99%). */\nconst PROGRESS_FULL_CHARS = 20000;\n\nexport function AIPanelContent() {\n const { setDoc } = useFlowContext();\n const { aiConfig, setAIConfig, showAIConfig } = useFlowAI();\n\n const [prompt, setPrompt] = useState('');\n const [imageDataUrl, setImageDataUrl] = useState<string | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [status, setStatus] = useState<string | null>(null);\n const [streamOpen, setStreamOpen] = useState(false);\n const [finished, setFinished] = useState(false);\n const [pendingDoc, setPendingDoc] = useState<FlowDocument | null>(null);\n const [displayLen, setDisplayLen] = useState(0);\n const abortRef = useRef<AbortController | null>(null);\n const fileRef = useRef<HTMLInputElement>(null);\n const streamBodyRef = useRef<HTMLPreElement>(null);\n const streamTailRef = useRef<HTMLPreElement>(null);\n /** Full text received from the model so far (grows on every SSE delta). */\n const targetRef = useRef('');\n\n const updateConfig = useCallback((patch: Partial<FlowAIConfig>) => {\n setAIConfig({ ...aiConfig, ...patch });\n }, [aiConfig, setAIConfig]);\n\n const onPickImage = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => setImageDataUrl(reader.result as string);\n reader.readAsDataURL(file);\n }, []);\n\n // Accept an image pasted from the clipboard (Ctrl/Cmd+V) anywhere in the panel\n // or into the textarea. Falls through to normal text paste otherwise.\n const onPaste = useCallback((e: React.ClipboardEvent) => {\n const items = e.clipboardData?.items;\n if (!items) return;\n for (const item of items) {\n if (item.type.startsWith('image/')) {\n const file = item.getAsFile();\n if (file) {\n e.preventDefault();\n const reader = new FileReader();\n reader.onload = () => setImageDataUrl(reader.result as string);\n reader.readAsDataURL(file);\n return;\n }\n }\n }\n }, []);\n\n // Progressive reveal: SSE deltas land in `targetRef` (often several chunks\n // per network read, which React would batch into a single paint), and this\n // timer types the text out with an exponential catch-up so the panel always\n // shows the reply growing character-by-character.\n useEffect(() => {\n const timer = window.setInterval(() => {\n setDisplayLen((len) => {\n const target = targetRef.current.length;\n if (len >= target) return len;\n return len + Math.max(8, Math.ceil((target - len) / 8));\n });\n }, 40);\n return () => window.clearInterval(timer);\n }, []);\n\n const streamText = targetRef.current.slice(0, displayLen);\n\n // Keep the streaming output pinned to the latest chunk while visible.\n useEffect(() => {\n const el = streamBodyRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n const tail = streamTailRef.current;\n if (tail) tail.scrollTop = tail.scrollHeight;\n }, [streamText, streamOpen]);\n\n const generate = useCallback(async () => {\n if (busy) return;\n if (!aiConfig.gateway || !aiConfig.model) {\n setError('请先配置 AI 接口地址与模型');\n return;\n }\n if (!prompt.trim() && !imageDataUrl) {\n setError('请输入需求描述,或上传一张流程图');\n return;\n }\n setError(null);\n setStatus('正在生成…');\n targetRef.current = '';\n setDisplayLen(0);\n setFinished(false);\n setPendingDoc(null);\n setBusy(true);\n const ac = new AbortController();\n abortRef.current = ac;\n try {\n const text = await completeAIChatStream(\n aiConfig,\n prompt.trim() || '请根据这张图片复刻出对应的流程图。',\n {\n imageDataUrl: imageDataUrl ?? undefined,\n systemPrompt: SYSTEM_PROMPT,\n signal: ac.signal,\n onDelta: (accumulated) => { targetRef.current = accumulated; },\n },\n );\n setFinished(true);\n const parsed = parseFlowJson(text);\n if (!parsed) {\n setError('AI 返回内容无法解析为流程图,请重试或调整描述');\n setStatus(null);\n return;\n }\n setPendingDoc(normalizeAIDocument(parsed));\n setStatus(null);\n } catch (err: any) {\n if (err?.name !== 'AbortError') setError(err?.message ?? '生成失败');\n setStatus(null);\n } finally {\n setBusy(false);\n abortRef.current = null;\n }\n }, [busy, aiConfig, prompt, imageDataUrl]);\n\n const cancel = useCallback(() => abortRef.current?.abort(), []);\n\n /** Merge the generated canvas into the current canvas, remapping ids. */\n const applyInsert = useCallback(() => {\n if (!pendingDoc) return;\n const gen = pendingDoc.canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n setDoc((prev) => {\n const canvasId = prev.stack[prev.stack.length - 1] ?? ROOT_CANVAS_ID;\n const cur = prev.canvases[canvasId] ?? { nodes: [], edges: [], lines: [] };\n const used = new Set([\n ...cur.nodes.map((n) => n.id),\n ...cur.edges.map((e) => e.id),\n ...cur.lines.map((l) => l.id),\n ]);\n const fresh = (id: string) => {\n let next = id;\n let i = 1;\n while (used.has(next)) next = `${id}_${i++}`;\n used.add(next);\n return next;\n };\n const idMap = new Map<string, string>();\n const nodes = gen.nodes.map((n) => {\n const id = fresh(n.id);\n idMap.set(n.id, id);\n return { ...n, id };\n });\n const edges = gen.edges.map((e) => ({\n ...e,\n id: fresh(e.id),\n source: idMap.get(e.source) ?? e.source,\n target: idMap.get(e.target) ?? e.target,\n }));\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [canvasId]: { nodes: [...cur.nodes, ...nodes], edges: [...cur.edges, ...edges], lines: cur.lines },\n },\n };\n });\n setPendingDoc(null);\n setStatus('已插入流程图');\n }, [pendingDoc, setDoc]);\n\n /** Clear the current canvas, then place the generated content onto it. */\n const applyReplace = useCallback(() => {\n if (!pendingDoc) return;\n const gen = pendingDoc.canvases[ROOT_CANVAS_ID] ?? { nodes: [], edges: [], lines: [] };\n setDoc((prev) => {\n const canvasId = prev.stack[prev.stack.length - 1] ?? ROOT_CANVAS_ID;\n return {\n ...prev,\n canvases: {\n ...prev.canvases,\n [canvasId]: { nodes: gen.nodes, edges: gen.edges, lines: [] },\n },\n };\n });\n setPendingDoc(null);\n setStatus('已替换画布');\n }, [pendingDoc, setDoc]);\n\n const charCount = streamText.length;\n const fullyRevealed = charCount >= targetRef.current.length;\n const progress = finished && fullyRevealed\n ? 100\n : Math.min(99, Math.floor((charCount / PROGRESS_FULL_CHARS) * 99));\n\n return (\n <div className=\"flow-ai-panel\" onPaste={onPaste}>\n {showAIConfig && (\n <div className=\"flow-ai-section\">\n <div className=\"flow-ai-section-title\">模型配置</div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">协议</Label>\n <Select\n options={PROTOCOL_OPTIONS}\n value={aiConfig.protocol}\n onChange={(v) => updateConfig({ protocol: v as FlowAIConfig['protocol'] })}\n style={{ fontSize: 12 }}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">接口地址</Label>\n <Input\n size=\"xs\"\n value={aiConfig.gateway}\n placeholder=\"https://api.moonshot.cn/v1\"\n onChange={(e) => updateConfig({ gateway: e.target.value })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">模型</Label>\n <Input\n size=\"xs\"\n value={aiConfig.model}\n placeholder=\"gpt-4o-mini\"\n onChange={(e) => updateConfig({ model: e.target.value })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">API Key</Label>\n <Input\n size=\"xs\"\n type=\"password\"\n value={aiConfig.apiKey ?? ''}\n placeholder=\"sk-…\"\n onChange={(e) => updateConfig({ apiKey: e.target.value })}\n />\n </div>\n </div>\n )}\n\n <div className=\"flow-ai-section\">\n <div className=\"flow-ai-section-title\">生成流程图</div>\n <textarea\n className=\"flow-ai-textarea\"\n value={prompt}\n placeholder=\"描述你想要的流程,例如:用户注册流程,包含邮箱校验、发送验证码、创建账号等步骤(可直接粘贴图片)\"\n onChange={(e) => setPrompt(e.target.value)}\n onPaste={onPaste}\n onPointerDown={(e) => e.stopPropagation()}\n />\n\n <div className=\"flow-ai-image-row\">\n <input\n ref={fileRef}\n type=\"file\"\n accept=\"image/*\"\n style={{ display: 'none' }}\n onChange={onPickImage}\n />\n {imageDataUrl ? (\n <div className=\"flow-ai-image-preview\">\n <img src={imageDataUrl} alt=\"参考图\" />\n <button\n type=\"button\"\n className=\"flow-ai-image-remove\"\n title=\"移除图片\"\n onClick={() => setImageDataUrl(null)}\n >×</button>\n </div>\n ) : (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => fileRef.current?.click()}>\n 上传流程图图片\n </Button>\n )}\n <span className=\"flow-ai-hint\">或粘贴图片 (Ctrl/⌘+V)</span>\n </div>\n\n <div className=\"flow-ai-actions\">\n {busy ? (\n <Button size=\"xs\" variant=\"ghost\" onClick={cancel}>停止</Button>\n ) : (\n <Button size=\"xs\" variant=\"primary\" onClick={generate}>生成流程图</Button>\n )}\n </div>\n\n {(busy || streamText) && (\n <div className=\"flow-ai-stream\">\n <div className=\"flow-ai-progress\">\n <div className=\"flow-ai-progress-track\">\n <div className=\"flow-ai-progress-bar\" style={{ width: `${progress}%` }} />\n </div>\n <span className=\"flow-ai-progress-label\">{progress}%</span>\n </div>\n <button\n type=\"button\"\n className=\"flow-ai-stream-header\"\n onClick={() => setStreamOpen((open) => !open)}\n >\n <span className={`flow-ai-stream-chevron${streamOpen ? ' flow-ai-stream-chevron--open' : ''}`}>▸</span>\n <span>返回内容</span>\n <span className=\"flow-ai-stream-count\">{charCount.toLocaleString()} 字符</span>\n </button>\n {streamOpen ? (\n <pre ref={streamBodyRef} className=\"flow-ai-stream-body\">{streamText || '等待返回…'}</pre>\n ) : (\n streamText && <pre ref={streamTailRef} className=\"flow-ai-stream-tail\">{streamText}</pre>\n )}\n </div>\n )}\n\n {status && !error && <div className=\"flow-ai-status\">{status}</div>}\n {error && <div className=\"flow-media-error\">{error}</div>}\n </div>\n\n {pendingDoc && (\n <div className=\"flow-ai-dialog-overlay\" onClick={() => setPendingDoc(null)}>\n <div\n className=\"flow-ai-dialog\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"流程图已生成\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"flow-ai-dialog-title\">流程图已生成</div>\n <div className=\"flow-ai-dialog-desc\">\n 插入:将生成内容追加到当前画布;替换:清空当前画布后再插入。\n </div>\n <div className=\"flow-ai-dialog-actions\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setPendingDoc(null)}>取消</Button>\n <Button size=\"xs\" variant=\"neutral\" outline onClick={applyInsert}>插入</Button>\n <Button size=\"xs\" variant=\"primary\" onClick={applyReplace}>替换</Button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAeA,IAAMK,IAAgB;AA6BtB,SAASC,GAAc,GAAmC;CACxD,IAAIC,IAAMC,EAAK,KAAK,GACdC,IAAQ,gCAAgC,KAAKF,CAAG;CACtD,IAAIE,GAAO,IAAMA,EAAM,EAAE,CAAC,KAAK;MAC1B;EACH,IAAMC,IAAQH,EAAI,QAAQ,GAAG,GACvBI,IAAMJ,EAAI,YAAY,GAAG;EAC/B,AAAIG,KAAS,KAAKC,IAAMD,MAAO,IAAMH,EAAI,MAAMG,GAAOC,IAAM,CAAC;CAC/D;CACA,IAAI;EACF,IAAMC,IAAS,KAAK,MAAML,CAAG;EAE7B,OADI,CAACK,KAAU,OAAOA,KAAW,YAAY,CAACA,EAAO,WAAiB,OAC/DA;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAGA,SAASC,EAAoB,GAAiC;CAC5D,IAAMC,IAAWC,EAAI,YAAY,CAAC,GAE5BC,IAASF,EADCC,EAAI,QAAQA,EAAI,MAAM,SAAS,MAAA,WACXD,EAAAG,QAA4B;EAAE,OAAO,CAAC;EAAG,OAAO,CAAC;EAAG,OAAO,CAAC;CAAE,GAC5FC,KAASF,EAAO,SAAS,CAAC,EAAA,CAAG,KAAK,GAAQ,OAAe;EAC7D,IAAIG,EAAE,MAAM,IAAIC,IAAI;EACpB,MAAMD,EAAE,QAAQ;EAChB,UAAU;GAAE,GAAG,OAAOA,EAAE,UAAU,KAAK,EAAE;GAAG,GAAG,OAAOA,EAAE,UAAU,KAAK,KAAKC,IAAI,GAAG;EAAE;EACrF,OAAO,OAAOD,EAAE,SAAS,GAAG;EAC5B,QAAQ,OAAOA,EAAE,UAAU,EAAE;EAC7B,QAAQA,EAAE,UAAUC;EACpB,MAAM;GAAE,GAAGC;GAAmB,GAAGF,EAAE;GAAM,OAAOA,EAAE,MAAM,SAASA,EAAE,SAAS;EAAO;CACrF,EAAE,GACIG,IAAW,IAAI,IAAiBJ,EAAM,KAAK,MAAM,CAACC,EAAE,IAAIA,CAAC,CAAC,CAAC,GAC3DI,KAASP,EAAO,SAAS,CAAC,EAAA,CAAG,KAAK,GAAQ,OAAe;EAC7D,IAAI,EAAE,MAAM,IAAII,IAAI;EACpB,QAAQ,EAAE;EACV,QAAQ,EAAE;EACV,MAAM,EAAE,QAAQ;EAChB,MAAM;GAAE,GAAGI;GAAmB,GAAG,EAAE;EAAK;CAC1C,EAAE,CAAC,CAAC,QAAQ,MAAW,EAAE,UAAU,EAAE,MAAM,CAAC,CACzC,KAAK,MAAWC,EAAuB,GAAGH,CAAQ,CAAC;CACtD,OAAO;EACL,UAAU,GAAGI,IAAiB;GAAE;GAAO;GAAO,OAAO,CAAC;EAAE,EAAE;EAC1D,OAAO,CAACA,CAAc;CACxB;AACF;AAOA,SAASD,EAAuB,GAAW,GAAiC;CAC1E,IAAME,IAAIL,EAAS,IAAIM,EAAK,MAAM,GAC5BC,IAAIP,EAAS,IAAIM,EAAK,MAAM;CAClC,IAAI,CAACD,KAAK,CAACE,KAAKF,MAAME,GAAG,OAAOD;CAChC,IAAME,IAAMD,EAAE,SAAS,IAAIA,EAAE,QAAQ,KAAMF,EAAE,SAAS,IAAIA,EAAE,QAAQ,IAC9DI,IAAMF,EAAE,SAAS,IAAIA,EAAE,SAAS,KAAMF,EAAE,SAAS,IAAIA,EAAE,SAAS;CACtE,IAAI,KAAK,IAAIG,CAAE,KAAK,KAAK,IAAIC,CAAE,GAAG;EAChC,IAAMC,IAAUF,KAAM;EACtB,OAAO;GACL,GAAGF;GACH,cAAcI,IAAU,UAAU;GAClC,cAAcA,IAAU,UAAU;EACpC;CACF;CACA,IAAMA,IAAUD,KAAM;CACtB,OAAO;EACL,GAAGH;EACH,cAAcI,IAAU,UAAU;EAClC,cAAcA,IAAU,UAAU;CACpC;AACF;AAEA,IAAMC,IAAmB,CACvB;CAAE,OAAO;CAAU,OAAO;AAAY,GACtC;CAAE,OAAO;CAAa,OAAO;AAAY,CAC3C,GAGMC,IAAsB;AAE5B,SAAgBC,IAAiB;CAC/B,IAAM,EAAE,cAAWC,EAAe,GAC5B,EAAE,aAAU,gBAAa,oBAAiBC,EAAU,GAEpD,CAACC,GAAQC,KAAaC,EAAS,EAAE,GACjC,CAACC,GAAcC,KAAmBF,EAAwB,IAAI,GAC9D,CAACG,GAAMC,KAAWJ,EAAS,EAAK,GAChC,CAACK,GAAOC,KAAYN,EAAwB,IAAI,GAChD,CAACO,GAAQC,KAAaR,EAAwB,IAAI,GAClD,CAACS,GAAYC,KAAiBV,EAAS,EAAK,GAC5C,CAACW,GAAUC,KAAeZ,EAAS,EAAK,GACxC,CAACa,GAAYC,KAAiBd,EAA8B,IAAI,GAChE,CAACe,GAAYC,KAAiBhB,EAAS,CAAC,GACxCiB,IAAWC,EAA+B,IAAI,GAC9CC,IAAUD,EAAyB,IAAI,GACvCE,IAAgBF,EAAuB,IAAI,GAC3CG,IAAgBH,EAAuB,IAAI,GAE3CI,IAAYJ,EAAO,EAAE,GAErBK,IAAeC,GAAa,MAAiC;EACjE,EAAY;GAAE,GAAGC;GAAU,GAAGC;EAAM,CAAC;CACvC,GAAG,CAACD,GAAUE,CAAW,CAAC,GAEpBC,IAAcJ,GAAa,MAA2C;EAC1E,IAAMK,IAAO,EAAE,OAAO,QAAQ;EAE9B,IADA,EAAE,OAAO,QAAQ,IACb,CAACA,GAAM;EACX,IAAMC,IAAS,IAAI,WAAW;EAE9B,AADA,EAAO,eAAe5B,EAAgB4B,EAAO,MAAgB,GAC7DA,EAAO,cAAcD,CAAI;CAC3B,GAAG,CAAC,CAAC,GAICE,IAAUP,GAAa,MAA4B;EACvD,IAAMQ,IAAQ,EAAE,eAAe;EAC/B,IAAKA,GACL;QAAK,IAAMC,KAAQD,GACjB,IAAIC,EAAK,KAAK,WAAW,QAAQ,GAAG;IAClC,IAAMJ,IAAOI,EAAK,UAAU;IAC5B,IAAIJ,GAAM;KACR,EAAE,eAAe;KACjB,IAAMC,IAAS,IAAI,WAAW;KAE9B,AADA,EAAO,eAAe5B,EAAgB4B,EAAO,MAAgB,GAC7DA,EAAO,cAAcD,CAAI;KACzB;IACF;GACF;;CAEJ,GAAG,CAAC,CAAC;CAML,QAAgB;EACd,IAAMK,IAAQ,OAAO,kBAAkB;GACrC,GAAe,MAAQ;IACrB,IAAMC,IAASb,EAAU,QAAQ;IAEjC,OADIc,KAAOD,IAAeC,IACnBA,IAAM,KAAK,IAAI,GAAG,KAAK,MAAMD,IAASC,KAAO,CAAC,CAAC;GACxD,CAAC;EACH,GAAG,EAAE;EACL,aAAa,OAAO,cAAcF,CAAK;CACzC,GAAG,CAAC,CAAC;CAEL,IAAMG,IAAaf,EAAU,QAAQ,MAAM,GAAGP,CAAU;CAGxD,QAAgB;EACd,IAAMuB,IAAKlB,EAAc;EACzB,AAAIkB,MAAI,EAAG,YAAYA,EAAG;EAC1B,IAAMC,IAAOlB,EAAc;EAC3B,AAAIkB,MAAM,EAAK,YAAYA,EAAK;CAClC,GAAG,CAACF,GAAY5B,CAAU,CAAC;CAE3B,IAAM+B,IAAWhB,EAAY,YAAY;EACvC,IAAIrB,GAAM;EACV,IAAI,CAACsB,EAAS,WAAW,CAACA,EAAS,OAAO;GACxC,EAAS,iBAAiB;GAC1B;EACF;EACA,IAAI,CAAC3B,EAAO,KAAK,KAAK,CAACG,GAAc;GACnC,EAAS,kBAAkB;GAC3B;EACF;EAOA,AANAK,EAAS,IAAI,GACbE,EAAU,OAAO,GACjB,EAAU,UAAU,IACpBQ,EAAc,CAAC,GACfJ,EAAY,EAAK,GACjBE,EAAc,IAAI,GAClBV,EAAQ,EAAI;EACZ,IAAMqC,IAAK,IAAI,gBAAgB;EAC/B,EAAS,UAAUA;EACnB,IAAI;GACF,IAAMzE,IAAO,MAAM0E,EACjBjB,GACA3B,EAAO,KAAK,KAAK,qBACjB;IACE,cAAcG,KAAgB,KAAA;IAC9B,cAAcpC;IACd,QAAQ4E,EAAG;IACX,UAAU,MAAgB;KAAE,EAAU,UAAUE;IAAa;GAC/D,CACF;GACA,EAAY,EAAI;GAChB,IAAMvE,IAASN,GAAcE,CAAI;GACjC,IAAI,CAACI,GAAQ;IAEX,AADAkC,EAAS,0BAA0B,GACnCE,EAAU,IAAI;IACd;GACF;GAEA,AADAM,EAAczC,EAAoBD,CAAM,CAAC,GACzCoC,EAAU,IAAI;EAChB,SAASoC,GAAU;GAEjB,AADIA,GAAK,SAAS,gBAActC,EAASsC,GAAK,WAAW,MAAM,GAC/DpC,EAAU,IAAI;EAChB,UAAU;GAER,AADAJ,EAAQ,EAAK,GACb,EAAS,UAAU;EACrB;CACF,GAAG;EAACD;EAAMsB;EAAU3B;EAAQG;CAAY,CAAC,GAEnC4C,IAASrB,QAAkBP,EAAS,SAAS,MAAM,GAAG,CAAC,CAAC,GAGxD6B,IAActB,QAAkB;EACpC,IAAI,CAACX,GAAY;EACjB,IAAMkC,IAAMlC,EAAW,SAAApC,QAA4B;GAAE,OAAO,CAAC;GAAG,OAAO,CAAC;GAAG,OAAO,CAAC;EAAE;EAqCrF,AApCAuE,GAAQ,MAAS;GACf,IAAMC,IAAWC,EAAK,MAAMA,EAAK,MAAM,SAAS,MAAA,QAC1CC,IAAMD,EAAK,SAASD,MAAa;IAAE,OAAO,CAAC;IAAG,OAAO,CAAC;IAAG,OAAO,CAAC;GAAE,GACnEG,oBAAO,IAAI,IAAI;IACnB,GAAGD,EAAI,MAAM,KAAK,MAAMxE,EAAE,EAAE;IAC5B,GAAGwE,EAAI,MAAM,KAAK,MAAM,EAAE,EAAE;IAC5B,GAAGA,EAAI,MAAM,KAAK,MAAME,EAAE,EAAE;GAC9B,CAAC,GACKC,KAAS,MAAe;IAC5B,IAAIC,IAAOC,GACP5E,IAAI;IACR,OAAOwE,EAAK,IAAIG,CAAI,IAAG,IAAO,GAAGC,EAAG,GAAG;IAEvC,OADAJ,EAAK,IAAIG,CAAI,GACNA;GACT,GACME,oBAAQ,IAAI,IAAoB,GAChC/E,IAAQqE,EAAI,MAAM,KAAK,MAAM;IACjC,IAAMS,IAAKF,EAAM3E,EAAE,EAAE;IAErB,OADA8E,EAAM,IAAI9E,EAAE,IAAI6E,CAAE,GACX;KAAE,GAAG7E;KAAG;IAAG;GACpB,CAAC,GACKI,IAAQgE,EAAI,MAAM,KAAK,OAAO;IAClC,GAAG;IACH,IAAIO,EAAM,EAAE,EAAE;IACd,QAAQG,EAAM,IAAI,EAAE,MAAM,KAAK,EAAE;IACjC,QAAQA,EAAM,IAAI,EAAE,MAAM,KAAK,EAAE;GACnC,EAAE;GACF,OAAO;IACL,GAAGP;IACH,UAAU;KACR,GAAGA,EAAK;MACPD,IAAW;MAAE,OAAO,CAAC,GAAGE,EAAI,OAAO,GAAGzE,CAAK;MAAG,OAAO,CAAC,GAAGyE,EAAI,OAAO,GAAGpE,CAAK;MAAG,OAAOoE,EAAI;KAAM;IACnG;GACF;EACF,CAAC,GACDrC,EAAc,IAAI,GAClBN,EAAU,QAAQ;CACpB,GAAG,CAACK,GAAYmC,CAAM,CAAC,GAGjBU,IAAelC,QAAkB;EACrC,IAAI,CAACX,GAAY;EACjB,IAAMkC,IAAMlC,EAAW,SAAApC,QAA4B;GAAE,OAAO,CAAC;GAAG,OAAO,CAAC;GAAG,OAAO,CAAC;EAAE;EAYrF,AAXAuE,GAAQ,MAAS;GACf,IAAMC,IAAWC,EAAK,MAAMA,EAAK,MAAM,SAAS,MAAA;GAChD,OAAO;IACL,GAAGA;IACH,UAAU;KACR,GAAGA,EAAK;MACPD,IAAW;MAAE,OAAOF,EAAI;MAAO,OAAOA,EAAI;MAAO,OAAO,CAAC;KAAE;IAC9D;GACF;EACF,CAAC,GACDjC,EAAc,IAAI,GAClBN,EAAU,OAAO;CACnB,GAAG,CAACK,GAAYmC,CAAM,CAAC,GAEjBW,IAAYtB,EAAW,QACvBuB,KAAgBD,KAAarC,EAAU,QAAQ,QAC/CuC,IAAWlD,KAAYiD,KACzB,MACA,KAAK,IAAI,IAAI,KAAK,MAAOD,IAAYjE,IAAuB,EAAE,CAAC;CAEnE,OACE,kBAAC,OAAD;EAAK,WAAU;EAAyB;EAAxC,UAAA;GACGoE,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;MAAwB,UAAA;KAAS,CAAA;KAChD,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAACnG,GAAD;OAAO,MAAK;OAAK,WAAU;OAAuB,UAAA;MAAS,CAAA,GAC3D,kBAACC,GAAD;OACE,SAAS6B;OACT,OAAOgC,EAAS;OAChB,WAAW,MAAMF,EAAa,EAAE,UAAUwC,EAA8B,CAAC;OACzE,OAAO,EAAE,UAAU,GAAG;MACvB,CAAA,CACE;;KACL,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAACpG,GAAD;OAAO,MAAK;OAAK,WAAU;OAAuB,UAAA;MAAW,CAAA,GAC7D,kBAACD,GAAD;OACE,MAAK;OACL,OAAO+D,EAAS;OAChB,aAAY;OACZ,WAAW,MAAMF,EAAa,EAAE,SAAS,EAAE,OAAO,MAAM,CAAC;MAC1D,CAAA,CACE;;KACL,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC5D,GAAD;OAAO,MAAK;OAAK,WAAU;OAAuB,UAAA;MAAS,CAAA,GAC3D,kBAACD,GAAD;OACE,MAAK;OACL,OAAO+D,EAAS;OAChB,aAAY;OACZ,WAAW,MAAMF,EAAa,EAAE,OAAO,EAAE,OAAO,MAAM,CAAC;MACxD,CAAA,CACE;;KACL,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,kBAAC5D,GAAD;OAAO,MAAK;OAAK,WAAU;OAAuB,UAAA;MAAc,CAAA,GAChE,kBAACD,GAAD;OACE,MAAK;OACL,MAAK;OACL,OAAO+D,EAAS,UAAU;OAC1B,aAAY;OACZ,WAAW,MAAMF,EAAa,EAAE,QAAQ,EAAE,OAAO,MAAM,CAAC;MACzD,CAAA,CACE;;IACF;;GAGP,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;MAAwB,UAAA;KAAU,CAAA;KACjD,kBAAC,YAAD;MACE,WAAU;MACV,OAAOzB;MACP,aAAY;MACZ,WAAW,MAAMC,EAAU,EAAE,OAAO,KAAK;MAChC;MACT,gBAAgB,MAAM,EAAE,gBAAgB;KACzC,CAAA;KAED,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,SAAD;QACE,KAAKoB;QACL,MAAK;QACL,QAAO;QACP,OAAO,EAAE,SAAS,OAAO;QACzB,UAAUS;OACX,CAAA;OACA3B,IACC,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,OAAD;SAAK,KAAKA;SAAc,KAAI;QAAO,CAAA,GACnC,kBAAC,UAAD;SACE,MAAK;SACL,WAAU;SACV,OAAM;SACN,eAAeC,EAAgB,IAAI;SACpC,UAAA;QAAS,CAAA,CACP;OAEL,CAAA,IAAA,kBAAC1C,GAAD;QAAQ,MAAK;QAAK,SAAQ;QAAQ,eAAe2D,EAAQ,SAAS,MAAM;QAAG,UAAA;OAEnE,CAAA;OAEV,kBAAC,QAAD;QAAM,WAAU;QAAe,UAAA;OAAsB,CAAA;MAClD;;KAEL,kBAAC,OAAD;MAAK,WAAU;MACZ,UAAAhB,IACC,kBAAC3C,GAAD;OAAQ,MAAK;OAAK,SAAQ;OAAQ,SAASqF;OAAQ,UAAA;MAAU,CAAA,IAE7D,kBAACrF,GAAD;OAAQ,MAAK;OAAK,SAAQ;OAAU,SAASgF;OAAU,UAAA;MAAa,CAAA;KAEnE,CAAA;MAEHrC,KAAQkC,MACR,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,OAAD;SAAK,WAAU;SACb,UAAA,kBAAC,OAAD;UAAK,WAAU;UAAuB,OAAO,EAAE,OAAO,GAAGwB,EAAS,GAAG;SAAI,CAAA;QACtE,CAAA,GACL,kBAAC,QAAD;SAAM,WAAU;SAAhB,UAAA,CAA0CA,GAAS,GAAO;QACvD,CAAA,CAAA;;OACL,kBAAC,UAAD;QACE,MAAK;QACL,WAAU;QACV,eAAenD,GAAe,MAAS,CAACsD,CAAI;QAH9C,UAAA;SAKE,kBAAC,QAAD;UAAM,WAAW,yBAAyBvD,IAAa,kCAAkC;UAAM,UAAA;SAAO,CAAA;SACtG,kBAAC,QAAD,EAAA,UAAM,OAAU,CAAA;SAChB,kBAAC,QAAD;UAAM,WAAU;UAAhB,UAAA,CAAwCkD,EAAU,eAAe,GAAE,KAAS;;QACtE;;OACPlD,IACC,kBAAC,OAAD;QAAK,KAAKW;QAAe,WAAU;QAAuB,UAAAiB,KAAc;OAAa,CAAA,IAErFA,KAAc,kBAAC,OAAD;QAAK,KAAKhB;QAAe,WAAU;QAAuB,UAAAgB;OAAgB,CAAA;MAEvF;;KAGN9B,KAAU,CAACF,KAAS,kBAAC,OAAD;MAAK,WAAU;MAAkB,UAAAE;KAAY,CAAA;KACjEF,KAAS,kBAAC,OAAD;MAAK,WAAU;MAAoB,UAAAA;KAAW,CAAA;IACrD;;GAEJQ,KACC,kBAAC,OAAD;IAAK,WAAU;IAAyB,eAAeC,EAAc,IAAI;IACvE,UAAA,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,cAAW;KACX,cAAW;KACX,UAAU,MAAM,EAAE,gBAAgB;KALpC,UAAA;MAOE,kBAAC,OAAD;OAAK,WAAU;OAAuB,UAAA;MAAW,CAAA;MACjD,kBAAC,OAAD;OAAK,WAAU;OAAsB,UAAA;MAEhC,CAAA;MACL,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,kBAACtD,GAAD;SAAQ,MAAK;SAAK,SAAQ;SAAQ,eAAesD,EAAc,IAAI;SAAG,UAAA;QAAU,CAAA;QAChF,kBAACtD,GAAD;SAAQ,MAAK;SAAK,SAAQ;SAAU,SAAA;SAAQ,SAASsF;SAAa,UAAA;QAAU,CAAA;QAC5E,kBAACtF,GAAD;SAAQ,MAAK;SAAK,SAAQ;SAAU,SAASkG;SAAc,UAAA;QAAU,CAAA;OAClE;;KACF;;GACF,CAAA;EAEJ;;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Breadcrumb.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/Breadcrumb.tsx"],"sourcesContent":["import React from 'react';\nimport Button from '../../../Button';\nimport { useFlowContext } from '../context/FlowContext';\nimport { ROOT_CANVAS_ID } from '../constants';\n\nfunction findNodeLabel(doc: ReturnType<typeof useFlowContext>['doc'], canvasId: string): string {\n if (canvasId === ROOT_CANVAS_ID) return 'Root';\n for (const [, canvas] of Object.entries(doc.canvases)) {\n for (const node of canvas.nodes) {\n if (node.data.childCanvasId === canvasId) {\n return node.data.label || node.type;\n }\n }\n }\n return canvasId;\n}\n\nexport default function Breadcrumb() {\n const { doc, setDoc, setSelection } = useFlowContext();\n const { stack } = doc;\n\n if (stack.length <= 1) return null;\n\n const handleClick = (index: number) => {\n if (index === stack.length - 1) return;\n setDoc(prev => ({\n ...prev,\n stack: prev.stack.slice(0, index + 1),\n }));\n setSelection({ nodeIds: new Set(), edgeIds: new Set(), lineIds: new Set() });\n };\n\n return (\n <div className=\"flow-breadcrumb\">\n {stack.map((canvasId, i) => {\n const label = findNodeLabel(doc, canvasId);\n const isLast = i === stack.length - 1;\n return (\n <React.Fragment key={canvasId}>\n {i > 0 && <span className=\"flow-breadcrumb-sep\">›</span>}\n <Button\n variant=\"ghost\"\n size=\"xs\"\n className={`flow-breadcrumb-item ${isLast ? 'flow-breadcrumb-item--active' : ''}`}\n onClick={() => handleClick(i)}\n disabled={isLast}\n >\n {label}\n </Button>\n </React.Fragment>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,
|
|
1
|
+
{"version":3,"file":"Breadcrumb.js","names":["Button","ButtonWithCompounds","React","findNodeLabel","canvasId","canvas","doc","node","Breadcrumb","useFlowContext","stack","handleClick","index","setDoc","prev","setSelection","label","isLast","i"],"sources":["../../../../../src/components/pro/Flow/panels/Breadcrumb.tsx"],"sourcesContent":["import React from 'react';\nimport Button from '../../../Button';\nimport { useFlowContext } from '../context/FlowContext';\nimport { ROOT_CANVAS_ID } from '../constants';\n\nfunction findNodeLabel(doc: ReturnType<typeof useFlowContext>['doc'], canvasId: string): string {\n if (canvasId === ROOT_CANVAS_ID) return 'Root';\n for (const [, canvas] of Object.entries(doc.canvases)) {\n for (const node of canvas.nodes) {\n if (node.data.childCanvasId === canvasId) {\n return node.data.label || node.type;\n }\n }\n }\n return canvasId;\n}\n\nexport default function Breadcrumb() {\n const { doc, setDoc, setSelection } = useFlowContext();\n const { stack } = doc;\n\n if (stack.length <= 1) return null;\n\n const handleClick = (index: number) => {\n if (index === stack.length - 1) return;\n setDoc(prev => ({\n ...prev,\n stack: prev.stack.slice(0, index + 1),\n }));\n setSelection({ nodeIds: new Set(), edgeIds: new Set(), lineIds: new Set() });\n };\n\n return (\n <div className=\"flow-breadcrumb\">\n {stack.map((canvasId, i) => {\n const label = findNodeLabel(doc, canvasId);\n const isLast = i === stack.length - 1;\n return (\n <React.Fragment key={canvasId}>\n {i > 0 && <span className=\"flow-breadcrumb-sep\">›</span>}\n <Button\n variant=\"ghost\"\n size=\"xs\"\n className={`flow-breadcrumb-item ${isLast ? 'flow-breadcrumb-item--active' : ''}`}\n onClick={() => handleClick(i)}\n disabled={isLast}\n >\n {label}\n </Button>\n </React.Fragment>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;AAKA,SAASG,EAAc,GAA+C,GAA0B;CAC9F,IAAIC,MAAA,QAA6B,OAAO;CACxC,KAAK,IAAM,GAAGC,MAAW,OAAO,QAAQC,EAAI,QAAQ,GAClD,KAAK,IAAMC,KAAQF,EAAO,OACxB,IAAIE,EAAK,KAAK,kBAAkBH,GAC9B,OAAOG,EAAK,KAAK,SAASA,EAAK;CAIrC,OAAOH;AACT;AAEA,SAAwBI,IAAa;CACnC,IAAM,EAAE,QAAK,WAAQ,oBAAiBC,EAAe,GAC/C,EAAE,aAAUH;CAElB,IAAII,EAAM,UAAU,GAAG,OAAO;CAE9B,IAAMC,KAAe,MAAkB;EACrC,AAAIC,MAAUF,EAAM,SAAS,MAC7BG,GAAO,OAAS;GACd,GAAGC;GACH,OAAOA,EAAK,MAAM,MAAM,GAAGF,IAAQ,CAAC;EACtC,EAAE,GACFG,EAAa;GAAE,yBAAS,IAAI,IAAI;GAAG,yBAAS,IAAI,IAAI;GAAG,yBAAS,IAAI,IAAI;EAAE,CAAC;CAC7E;CAEA,OACE,kBAAC,OAAD;EAAK,WAAU;EACZ,UAAAL,EAAM,KAAK,GAAU,MAAM;GAC1B,IAAMM,IAAQb,EAAcG,GAAKF,CAAQ,GACnCa,IAASC,MAAMR,EAAM,SAAS;GACpC,OACE,kBAACR,EAAM,UAAP,EAAA,UAAA,CACGgB,IAAI,KAAK,kBAAC,QAAD;IAAM,WAAU;IAAsB,UAAA;GAAO,CAAA,GACvD,kBAAClB,GAAD;IACE,SAAQ;IACR,MAAK;IACL,WAAW,wBAAwBiB,IAAS,iCAAiC;IAC7E,eAAeN,EAAYO,CAAC;IAC5B,UAAUD;IAET,UAAAD;GACK,CAAA,CACM,EAAA,GAXKZ,CAWL;EAEpB,CAAC;CACE,CAAA;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextMenu.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/ContextMenu.tsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\n\nexport interface ContextMenuItem {\n label: string;\n icon?: string;\n action: () => void;\n danger?: boolean;\n disabled?: boolean;\n}\n\nexport interface ContextMenuProps {\n x: number;\n y: number;\n items: ContextMenuItem[];\n onClose: () => void;\n}\n\nexport default function ContextMenu({ x, y, items, onClose }: ContextMenuProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n onClose();\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [onClose]);\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [onClose]);\n\n return (\n <div ref={ref} className=\"flow-context-menu\" style={{ left: x, top: y }}>\n {items.map((item, i) => {\n if (item.label === '---') {\n return <div key={i} className=\"flow-context-menu-separator\" />;\n }\n return (\n <div\n key={i}\n className=\"flow-context-menu-item\"\n style={{\n opacity: item.disabled ? 0.4 : 1,\n pointerEvents: item.disabled ? 'none' : undefined,\n color: item.danger ? 'oklch(var(--er))' : undefined,\n }}\n onClick={() => { item.action(); onClose(); }}\n >\n {item.icon && <span>{item.icon}</span>}\n <span>{item.label}</span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AAiBA,
|
|
1
|
+
{"version":3,"file":"ContextMenu.js","names":["ContextMenu","ref","useRef","useEffect","handler","onClose","x","y","items","item","i"],"sources":["../../../../../src/components/pro/Flow/panels/ContextMenu.tsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\n\nexport interface ContextMenuItem {\n label: string;\n icon?: string;\n action: () => void;\n danger?: boolean;\n disabled?: boolean;\n}\n\nexport interface ContextMenuProps {\n x: number;\n y: number;\n items: ContextMenuItem[];\n onClose: () => void;\n}\n\nexport default function ContextMenu({ x, y, items, onClose }: ContextMenuProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n onClose();\n }\n };\n document.addEventListener('mousedown', handler);\n return () => document.removeEventListener('mousedown', handler);\n }, [onClose]);\n\n useEffect(() => {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n document.addEventListener('keydown', handler);\n return () => document.removeEventListener('keydown', handler);\n }, [onClose]);\n\n return (\n <div ref={ref} className=\"flow-context-menu\" style={{ left: x, top: y }}>\n {items.map((item, i) => {\n if (item.label === '---') {\n return <div key={i} className=\"flow-context-menu-separator\" />;\n }\n return (\n <div\n key={i}\n className=\"flow-context-menu-item\"\n style={{\n opacity: item.disabled ? 0.4 : 1,\n pointerEvents: item.disabled ? 'none' : undefined,\n color: item.danger ? 'oklch(var(--er))' : undefined,\n }}\n onClick={() => { item.action(); onClose(); }}\n >\n {item.icon && <span>{item.icon}</span>}\n <span>{item.label}</span>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;AAiBA,SAAwBA,EAAY,EAAE,MAAG,MAAG,UAAO,cAA6B;CAC9E,IAAMC,IAAMC,EAAuB,IAAI;CAoBvC,OAlBAC,QAAgB;EACd,IAAMC,KAAW,MAAkB;GACjC,AAAIH,EAAI,WAAW,CAACA,EAAI,QAAQ,SAAS,EAAE,MAAc,KACvDI,EAAQ;EAEZ;EAEA,OADA,SAAS,iBAAiB,aAAaD,CAAO,SACjC,SAAS,oBAAoB,aAAaA,CAAO;CAChE,GAAG,CAACC,CAAO,CAAC,GAEZF,QAAgB;EACd,IAAMC,KAAW,MAAqB;GACpC,AAAI,EAAE,QAAQ,YAAUC,EAAQ;EAClC;EAEA,OADA,SAAS,iBAAiB,WAAWD,CAAO,SAC/B,SAAS,oBAAoB,WAAWA,CAAO;CAC9D,GAAG,CAACC,CAAO,CAAC,GAGV,kBAAC,OAAD;EAAU;EAAK,WAAU;EAAoB,OAAO;GAAE,MAAMC;GAAG,KAAKC;EAAE;EACnE,UAAAC,EAAM,KAAK,GAAM,MACZC,EAAK,UAAU,QACV,kBAAC,OAAD,EAAa,WAAU,8BAA+B,GAA5CC,CAA4C,IAG7D,kBAAC,OAAD;GAEE,WAAU;GACV,OAAO;IACL,SAASD,EAAK,WAAW,KAAM;IAC/B,eAAeA,EAAK,WAAW,SAAS,KAAA;IACxC,OAAOA,EAAK,SAAS,qBAAqB,KAAA;GAC5C;GACA,eAAe;IAAiB,AAAfA,EAAK,OAAO,GAAGJ,EAAQ;GAAG;GAR7C,UAAA,CAUGI,EAAK,QAAQ,kBAAC,QAAD,EAAA,UAAOA,EAAK,KAAW,CAAA,GACrC,kBAAC,QAAD,EAAA,UAAOA,EAAK,MAAY,CAAA,CACrB;EAXE,GAAAC,CAWF,CAER;CACE,CAAA;AAET"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataInspectorSection.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/DataInspectorSection.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Input from '../../../Input';\nimport Select from '../../../Select';\nimport Button from '../../../Button';\nimport Label from '../../../Label';\nimport { ExpandableTextarea } from './ExpandableTextarea';\nimport type {\n FlowNode,\n FlowDataConfig,\n FlowDataColumn,\n FlowDataColumnType,\n FlowDataChartType,\n FlowDataView,\n FlowDataPivotPanelPlacement,\n} from '../types';\nimport {\n parseDataFile,\n parseCsv,\n matrixToTable,\n makeDefaultDataConfig,\n applyCsvText,\n toCsv,\n numericFields,\n labelFor,\n DATA_CHART_PALETTE,\n} from '../nodes/dataUtils';\n\nconst COLUMN_TYPE_OPTIONS: Array<{ value: FlowDataColumnType; label: string }> = [\n { value: 'string', label: '文本' },\n { value: 'number', label: '数值' },\n { value: 'date', label: '日期' },\n { value: 'boolean', label: '布尔' },\n];\n\nconst CHART_TYPE_OPTIONS: Array<{ value: FlowDataChartType; label: string }> = [\n { value: 'bar', label: '柱状图' },\n { value: 'barHorizontal', label: '横向柱状图' },\n { value: 'line', label: '折线图' },\n { value: 'area', label: '面积图' },\n { value: 'scatter', label: '散点图' },\n { value: 'pie', label: '饼图' },\n];\n\nconst PIVOT_PLACEMENT_OPTIONS: Array<{ value: FlowDataPivotPanelPlacement; label: string }> = [\n { value: 'top', label: '上方' },\n { value: 'bottom', label: '下方' },\n { value: 'left', label: '左侧' },\n { value: 'right', label: '右侧' },\n];\n\nconst EMPTY_CONFIG: FlowDataConfig = { columns: [], rows: [], view: 'table' };\n\n/**\n * Inspector controls for a Data node: upload CSV/Excel, edit columns, edit rows\n * as CSV text (with fullscreen), and configure the table (pivot) or chart view.\n */\nexport function DataInspectorSection({\n node,\n onUpdateData,\n}: {\n node: FlowNode;\n onUpdateData: (id: string, key: string, value: any) => void;\n}) {\n const config = node.data.dataConfig ?? EMPTY_CONFIG;\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const update = (patch: Partial<FlowDataConfig>) => {\n onUpdateData(node.id, 'dataConfig', { ...config, ...patch });\n };\n\n // ── CSV text editing (local draft, committed on blur) ────────────────────\n // The textarea edits a CSV serialization of columns+rows. We keep a local\n // draft so typing isn't interrupted by re-parsing; the parse (which re-infers\n // nothing for known columns and preserves chart/pivot field refs) runs once\n // on blur / fullscreen close. When the config changes externally (upload,\n // paste), the draft is re-synced.\n const csvText = useMemo(() => toCsv(config.columns, config.rows), [config.columns, config.rows]);\n const [csvDraft, setCsvDraft] = useState(csvText);\n const lastCommitted = useRef(csvText);\n useEffect(() => {\n if (csvText !== lastCommitted.current) {\n lastCommitted.current = csvText;\n setCsvDraft(csvText);\n }\n }, [csvText]);\n\n const commitCsv = (text: string) => {\n if (text === lastCommitted.current) return;\n lastCommitted.current = text;\n onUpdateData(node.id, 'dataConfig', applyCsvText(config, text));\n };\n\n // ── File upload ────────────────────────────────────────────────────────\n const handleFile = async (file: File) => {\n try {\n const parsed = await parseDataFile(file);\n if (parsed.columns.length === 0) {\n window.alert('未能从文件中解析出任何数据。');\n return;\n }\n onUpdateData(node.id, 'dataConfig', makeDefaultDataConfig(parsed, file.name));\n } catch (e: any) {\n window.alert(`解析失败:${e?.message ?? e}`);\n }\n };\n\n // ── Column editing ─────────────────────────────────────────────────────\n const setColumn = (index: number, patch: Partial<FlowDataColumn>) => {\n const columns = config.columns.map((c, i) => (i === index ? { ...c, ...patch } : c));\n update({ columns });\n };\n\n const addColumn = () => {\n const used = new Set(config.columns.map((c) => c.key));\n let key = 'col';\n let n = 1;\n while (used.has(key)) key = `col_${n++}`;\n const columns: FlowDataColumn[] = [...config.columns, { key, label: key, type: 'string' }];\n // pad existing rows with an empty value for the new column\n const rows = config.rows.map((r) => ({ ...r, [key]: '' }));\n update({ columns, rows });\n };\n\n const removeColumn = (index: number) => {\n const col = config.columns[index];\n const columns = config.columns.filter((_, i) => i !== index);\n const rows = config.rows.map((r) => {\n const { [col.key]: _drop, ...rest } = r;\n return rest;\n });\n // prune chart/pivot references to the removed column\n const chart = config.chart\n ? {\n ...config.chart,\n xField: config.chart.xField === col.key ? columns.find((c) => c.type !== 'number')?.key ?? columns[0]?.key : config.chart.xField,\n yFields: (config.chart.yFields ?? []).filter((f) => f !== col.key),\n }\n : config.chart;\n const pivot = config.pivot\n ? {\n ...config.pivot,\n rowFields: config.pivot.rowFields.filter((f) => f !== col.key),\n colFields: config.pivot.colFields.filter((f) => f !== col.key),\n values: config.pivot.values.filter((v) => v.field !== col.key),\n }\n : config.pivot;\n update({ columns, rows, chart, pivot });\n };\n\n // ── Paste CSV (replace whole table) ─────────────────────────────────────\n const pasteCsv = () => {\n const text = window.prompt('粘贴 CSV 文本(第一行为表头):');\n if (!text) return;\n const parsed = matrixToTable(parseCsv(text));\n if (parsed.columns.length === 0) {\n window.alert('未能解析出数据。');\n return;\n }\n onUpdateData(node.id, 'dataConfig', makeDefaultDataConfig(parsed));\n };\n\n const nums = numericFields(config.columns);\n const chart = config.chart ?? { type: 'bar' as FlowDataChartType };\n const setChart = (patch: Partial<typeof chart>) => update({ chart: { ...chart, ...patch } });\n\n const setSeriesColor = (field: string, color: string) => {\n setChart({ seriesColors: { ...chart.seriesColors, [field]: color } });\n };\n const resetSeriesColor = (field: string) => {\n const next = { ...chart.seriesColors };\n delete next[field];\n setChart({ seriesColors: Object.keys(next).length ? next : undefined });\n };\n\n const palette = chart.palette?.length ? chart.palette : DATA_CHART_PALETTE;\n const setPaletteColor = (i: number, color: string) => {\n const next = DATA_CHART_PALETTE.map((c, j) => (j === i ? color : (chart.palette?.[j] ?? c)));\n setChart({ palette: next });\n };\n\n const pivot = config.pivot ?? { enabled: false, rowFields: [], colFields: [], values: [] };\n const setPivot = (patch: Partial<typeof pivot>) => update({ pivot: { ...pivot, ...patch } });\n\n return (\n <div className=\"flow-inspector-section\">\n <div className=\"flow-inspector-section-title\">Data</div>\n\n {/* Import controls */}\n <div className=\"flow-inspector-row\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".csv,.tsv,.txt,.xlsx,.xlsm,text/csv\"\n hidden\n onChange={(e) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (file) void handleFile(file);\n }}\n />\n <Button size=\"xs\" variant=\"neutral\" onClick={() => fileInputRef.current?.click()}>\n 上传 CSV / Excel\n </Button>\n <Button size=\"xs\" variant=\"ghost\" onClick={pasteCsv}>\n 粘贴 CSV\n </Button>\n </div>\n {config.sourceName && (\n <div className=\"flow-inspector-help\">来源:{config.sourceName}</div>\n )}\n\n {/* View toggle */}\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">视图</Label>\n <Select\n options={[\n { value: 'table', label: '表格 / 透视' },\n { value: 'chart', label: '图表' },\n ]}\n value={config.view}\n onChange={(v) => update({ view: v as FlowDataView })}\n />\n </div>\n\n {/* Columns editor */}\n <div className=\"flow-inspector-subtitle\">列配置({config.columns.length})</div>\n {config.columns.map((col, i) => (\n <div key={i} className=\"flow-data-col-row\">\n <Input\n size=\"xs\"\n value={col.label ?? col.key}\n placeholder=\"列名\"\n onChange={(e) => setColumn(i, { label: e.target.value })}\n className=\"flex-1\"\n />\n <Select\n options={COLUMN_TYPE_OPTIONS}\n value={col.type}\n onChange={(v) => setColumn(i, { type: v as FlowDataColumnType })}\n />\n <Button size=\"xs\" variant=\"ghost\" onClick={() => removeColumn(i)}>\n ✕\n </Button>\n </div>\n ))}\n <div className=\"flow-inspector-row\">\n <Button size=\"xs\" variant=\"ghost\" onClick={addColumn}>+ 添加列</Button>\n </div>\n\n {/* Rows editor: CSV text with fullscreen */}\n <div className=\"flow-inspector-subtitle\">数据(CSV · {config.rows.length} 行)</div>\n <ExpandableTextarea\n label=\"CSV 数据(首行为表头)\"\n value={csvDraft}\n onChange={setCsvDraft}\n onBlur={commitCsv}\n rows={8}\n placeholder=\"类别,数值 A,30 B,45\"\n />\n <div className=\"flow-inspector-help\">\n 直接编辑 CSV 文本,失焦或关闭全屏后生效。已有列的类型会保留。\n </div>\n\n {/* Chart config */}\n {config.view === 'chart' && (\n <>\n <div className=\"flow-inspector-subtitle\">图表配置</div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">类型</Label>\n <Select\n options={CHART_TYPE_OPTIONS}\n value={chart.type}\n onChange={(v) => setChart({ type: v as FlowDataChartType })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">\n {chart.type === 'scatter' ? 'X 字段' : '类别轴'}\n </Label>\n <Select\n options={config.columns.map((c) => ({ value: c.key, label: c.label ?? c.key }))}\n value={chart.xField ?? ''}\n onChange={(v) => setChart({ xField: typeof v === 'string' ? v : String(v) })}\n />\n </div>\n <div className=\"flow-inspector-subtitle-sm\">\n {chart.type === 'scatter' || chart.type === 'pie' ? '数值字段' : '数值字段(可多选,多系列)'}\n </div>\n {nums.length === 0 && (\n <div className=\"flow-inspector-help\">没有数值列,请先将某列类型设为「数值」。</div>\n )}\n {nums.map((f) => {\n const selected = (chart.yFields ?? []).includes(f);\n const single = chart.type === 'scatter' || chart.type === 'pie';\n return (\n <label key={f} className=\"flow-data-field-toggle\">\n <input\n type={single ? 'radio' : 'checkbox'}\n className={single ? 'radio radio-xs radio-primary' : 'checkbox checkbox-xs checkbox-primary'}\n checked={selected}\n onChange={(e) => {\n if (single) {\n setChart({ yFields: [f] });\n return;\n }\n const current = new Set(chart.yFields ?? []);\n if (e.target.checked) current.add(f);\n else current.delete(f);\n setChart({ yFields: Array.from(current) });\n }}\n />\n <span>{labelFor(config.columns, f)}</span>\n </label>\n );\n })}\n\n {/* Chart colors */}\n {(chart.yFields ?? []).length > 0 && chart.type !== 'pie' && (\n <>\n <div className=\"flow-inspector-subtitle-sm\">系列颜色</div>\n {(chart.yFields ?? []).map((f, i) => {\n const color = chart.seriesColors?.[f] ?? DATA_CHART_PALETTE[i % DATA_CHART_PALETTE.length];\n const overridden = !!chart.seriesColors?.[f];\n return (\n <div key={f} className=\"flow-data-color-row\">\n <input\n type=\"color\"\n value={color}\n onChange={(e) => setSeriesColor(f, e.target.value)}\n />\n <span className=\"flow-data-color-label\">{labelFor(config.columns, f)}</span>\n {overridden && (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => resetSeriesColor(f)}>\n 重置\n </Button>\n )}\n </div>\n );\n })}\n </>\n )}\n {chart.type === 'pie' && (\n <>\n <div className=\"flow-inspector-subtitle-sm\">饼图配色</div>\n <div className=\"flow-data-palette\">\n {DATA_CHART_PALETTE.map((_, i) => (\n <input\n key={i}\n type=\"color\"\n value={palette[i % palette.length]}\n onChange={(e) => setPaletteColor(i, e.target.value)}\n />\n ))}\n </div>\n {chart.palette && (\n <div className=\"flow-inspector-row\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setChart({ palette: undefined })}>\n 重置为默认配色\n </Button>\n </div>\n )}\n </>\n )}\n </>\n )}\n\n {/* Pivot config */}\n {config.view === 'table' && (\n <>\n <div className=\"flow-inspector-subtitle\">透视(Pivot)</div>\n <label className=\"flow-data-field-toggle\">\n <input\n type=\"checkbox\"\n className=\"toggle toggle-xs toggle-primary\"\n checked={pivot.enabled}\n onChange={(e) => setPivot({ enabled: e.target.checked })}\n />\n <span>开启透视模式</span>\n </label>\n {pivot.enabled && (\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">面板位置</Label>\n <Select\n options={PIVOT_PLACEMENT_OPTIONS}\n value={pivot.panelPlacement ?? 'top'}\n onChange={(v) => setPivot({ panelPlacement: v as FlowDataPivotPanelPlacement })}\n />\n </div>\n )}\n <div className=\"flow-inspector-help\">\n 透视的行/列/度量可在画布节点内的透视面板上交互拖拽调整。\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport default DataInspectorSection;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataInspectorSection.js","names":["Button","_Fragment","ButtonWithCompounds","Input","Label","Select","COLUMN_TYPE_OPTIONS","CHART_TYPE_OPTIONS","PIVOT_PLACEMENT_OPTIONS","EMPTY_CONFIG","DataInspectorSection","config","node","fileInputRef","useRef","update","patch","csvText","useMemo","toCsv","csvDraft","setCsvDraft","useState","lastCommitted","commitCsv","text","onUpdateData","applyCsvText","handleFile","parsed","parseDataFile","file","makeDefaultDataConfig","setColumn","columns","i","index","c","addColumn","used","key","rows","r","removeColumn","col","_drop","rest","chart","f","pivot","v","pasteCsv","matrixToTable","parseCsv","nums","numericFields","setChart","setSeriesColor","field","color","resetSeriesColor","next","palette","DATA_CHART_PALETTE","setPaletteColor","j","setPivot","ExpandableTextarea","Fragment","selected","single","current","e","labelFor","overridden"],"sources":["../../../../../src/components/pro/Flow/panels/DataInspectorSection.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport Input from '../../../Input';\nimport Select from '../../../Select';\nimport Button from '../../../Button';\nimport Label from '../../../Label';\nimport { ExpandableTextarea } from './ExpandableTextarea';\nimport type {\n FlowNode,\n FlowDataConfig,\n FlowDataColumn,\n FlowDataColumnType,\n FlowDataChartType,\n FlowDataView,\n FlowDataPivotPanelPlacement,\n} from '../types';\nimport {\n parseDataFile,\n parseCsv,\n matrixToTable,\n makeDefaultDataConfig,\n applyCsvText,\n toCsv,\n numericFields,\n labelFor,\n DATA_CHART_PALETTE,\n} from '../nodes/dataUtils';\n\nconst COLUMN_TYPE_OPTIONS: Array<{ value: FlowDataColumnType; label: string }> = [\n { value: 'string', label: '文本' },\n { value: 'number', label: '数值' },\n { value: 'date', label: '日期' },\n { value: 'boolean', label: '布尔' },\n];\n\nconst CHART_TYPE_OPTIONS: Array<{ value: FlowDataChartType; label: string }> = [\n { value: 'bar', label: '柱状图' },\n { value: 'barHorizontal', label: '横向柱状图' },\n { value: 'line', label: '折线图' },\n { value: 'area', label: '面积图' },\n { value: 'scatter', label: '散点图' },\n { value: 'pie', label: '饼图' },\n];\n\nconst PIVOT_PLACEMENT_OPTIONS: Array<{ value: FlowDataPivotPanelPlacement; label: string }> = [\n { value: 'top', label: '上方' },\n { value: 'bottom', label: '下方' },\n { value: 'left', label: '左侧' },\n { value: 'right', label: '右侧' },\n];\n\nconst EMPTY_CONFIG: FlowDataConfig = { columns: [], rows: [], view: 'table' };\n\n/**\n * Inspector controls for a Data node: upload CSV/Excel, edit columns, edit rows\n * as CSV text (with fullscreen), and configure the table (pivot) or chart view.\n */\nexport function DataInspectorSection({\n node,\n onUpdateData,\n}: {\n node: FlowNode;\n onUpdateData: (id: string, key: string, value: any) => void;\n}) {\n const config = node.data.dataConfig ?? EMPTY_CONFIG;\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const update = (patch: Partial<FlowDataConfig>) => {\n onUpdateData(node.id, 'dataConfig', { ...config, ...patch });\n };\n\n // ── CSV text editing (local draft, committed on blur) ────────────────────\n // The textarea edits a CSV serialization of columns+rows. We keep a local\n // draft so typing isn't interrupted by re-parsing; the parse (which re-infers\n // nothing for known columns and preserves chart/pivot field refs) runs once\n // on blur / fullscreen close. When the config changes externally (upload,\n // paste), the draft is re-synced.\n const csvText = useMemo(() => toCsv(config.columns, config.rows), [config.columns, config.rows]);\n const [csvDraft, setCsvDraft] = useState(csvText);\n const lastCommitted = useRef(csvText);\n useEffect(() => {\n if (csvText !== lastCommitted.current) {\n lastCommitted.current = csvText;\n setCsvDraft(csvText);\n }\n }, [csvText]);\n\n const commitCsv = (text: string) => {\n if (text === lastCommitted.current) return;\n lastCommitted.current = text;\n onUpdateData(node.id, 'dataConfig', applyCsvText(config, text));\n };\n\n // ── File upload ────────────────────────────────────────────────────────\n const handleFile = async (file: File) => {\n try {\n const parsed = await parseDataFile(file);\n if (parsed.columns.length === 0) {\n window.alert('未能从文件中解析出任何数据。');\n return;\n }\n onUpdateData(node.id, 'dataConfig', makeDefaultDataConfig(parsed, file.name));\n } catch (e: any) {\n window.alert(`解析失败:${e?.message ?? e}`);\n }\n };\n\n // ── Column editing ─────────────────────────────────────────────────────\n const setColumn = (index: number, patch: Partial<FlowDataColumn>) => {\n const columns = config.columns.map((c, i) => (i === index ? { ...c, ...patch } : c));\n update({ columns });\n };\n\n const addColumn = () => {\n const used = new Set(config.columns.map((c) => c.key));\n let key = 'col';\n let n = 1;\n while (used.has(key)) key = `col_${n++}`;\n const columns: FlowDataColumn[] = [...config.columns, { key, label: key, type: 'string' }];\n // pad existing rows with an empty value for the new column\n const rows = config.rows.map((r) => ({ ...r, [key]: '' }));\n update({ columns, rows });\n };\n\n const removeColumn = (index: number) => {\n const col = config.columns[index];\n const columns = config.columns.filter((_, i) => i !== index);\n const rows = config.rows.map((r) => {\n const { [col.key]: _drop, ...rest } = r;\n return rest;\n });\n // prune chart/pivot references to the removed column\n const chart = config.chart\n ? {\n ...config.chart,\n xField: config.chart.xField === col.key ? columns.find((c) => c.type !== 'number')?.key ?? columns[0]?.key : config.chart.xField,\n yFields: (config.chart.yFields ?? []).filter((f) => f !== col.key),\n }\n : config.chart;\n const pivot = config.pivot\n ? {\n ...config.pivot,\n rowFields: config.pivot.rowFields.filter((f) => f !== col.key),\n colFields: config.pivot.colFields.filter((f) => f !== col.key),\n values: config.pivot.values.filter((v) => v.field !== col.key),\n }\n : config.pivot;\n update({ columns, rows, chart, pivot });\n };\n\n // ── Paste CSV (replace whole table) ─────────────────────────────────────\n const pasteCsv = () => {\n const text = window.prompt('粘贴 CSV 文本(第一行为表头):');\n if (!text) return;\n const parsed = matrixToTable(parseCsv(text));\n if (parsed.columns.length === 0) {\n window.alert('未能解析出数据。');\n return;\n }\n onUpdateData(node.id, 'dataConfig', makeDefaultDataConfig(parsed));\n };\n\n const nums = numericFields(config.columns);\n const chart = config.chart ?? { type: 'bar' as FlowDataChartType };\n const setChart = (patch: Partial<typeof chart>) => update({ chart: { ...chart, ...patch } });\n\n const setSeriesColor = (field: string, color: string) => {\n setChart({ seriesColors: { ...chart.seriesColors, [field]: color } });\n };\n const resetSeriesColor = (field: string) => {\n const next = { ...chart.seriesColors };\n delete next[field];\n setChart({ seriesColors: Object.keys(next).length ? next : undefined });\n };\n\n const palette = chart.palette?.length ? chart.palette : DATA_CHART_PALETTE;\n const setPaletteColor = (i: number, color: string) => {\n const next = DATA_CHART_PALETTE.map((c, j) => (j === i ? color : (chart.palette?.[j] ?? c)));\n setChart({ palette: next });\n };\n\n const pivot = config.pivot ?? { enabled: false, rowFields: [], colFields: [], values: [] };\n const setPivot = (patch: Partial<typeof pivot>) => update({ pivot: { ...pivot, ...patch } });\n\n return (\n <div className=\"flow-inspector-section\">\n <div className=\"flow-inspector-section-title\">Data</div>\n\n {/* Import controls */}\n <div className=\"flow-inspector-row\">\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".csv,.tsv,.txt,.xlsx,.xlsm,text/csv\"\n hidden\n onChange={(e) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (file) void handleFile(file);\n }}\n />\n <Button size=\"xs\" variant=\"neutral\" onClick={() => fileInputRef.current?.click()}>\n 上传 CSV / Excel\n </Button>\n <Button size=\"xs\" variant=\"ghost\" onClick={pasteCsv}>\n 粘贴 CSV\n </Button>\n </div>\n {config.sourceName && (\n <div className=\"flow-inspector-help\">来源:{config.sourceName}</div>\n )}\n\n {/* View toggle */}\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">视图</Label>\n <Select\n options={[\n { value: 'table', label: '表格 / 透视' },\n { value: 'chart', label: '图表' },\n ]}\n value={config.view}\n onChange={(v) => update({ view: v as FlowDataView })}\n />\n </div>\n\n {/* Columns editor */}\n <div className=\"flow-inspector-subtitle\">列配置({config.columns.length})</div>\n {config.columns.map((col, i) => (\n <div key={i} className=\"flow-data-col-row\">\n <Input\n size=\"xs\"\n value={col.label ?? col.key}\n placeholder=\"列名\"\n onChange={(e) => setColumn(i, { label: e.target.value })}\n className=\"flex-1\"\n />\n <Select\n options={COLUMN_TYPE_OPTIONS}\n value={col.type}\n onChange={(v) => setColumn(i, { type: v as FlowDataColumnType })}\n />\n <Button size=\"xs\" variant=\"ghost\" onClick={() => removeColumn(i)}>\n ✕\n </Button>\n </div>\n ))}\n <div className=\"flow-inspector-row\">\n <Button size=\"xs\" variant=\"ghost\" onClick={addColumn}>+ 添加列</Button>\n </div>\n\n {/* Rows editor: CSV text with fullscreen */}\n <div className=\"flow-inspector-subtitle\">数据(CSV · {config.rows.length} 行)</div>\n <ExpandableTextarea\n label=\"CSV 数据(首行为表头)\"\n value={csvDraft}\n onChange={setCsvDraft}\n onBlur={commitCsv}\n rows={8}\n placeholder=\"类别,数值 A,30 B,45\"\n />\n <div className=\"flow-inspector-help\">\n 直接编辑 CSV 文本,失焦或关闭全屏后生效。已有列的类型会保留。\n </div>\n\n {/* Chart config */}\n {config.view === 'chart' && (\n <>\n <div className=\"flow-inspector-subtitle\">图表配置</div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">类型</Label>\n <Select\n options={CHART_TYPE_OPTIONS}\n value={chart.type}\n onChange={(v) => setChart({ type: v as FlowDataChartType })}\n />\n </div>\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">\n {chart.type === 'scatter' ? 'X 字段' : '类别轴'}\n </Label>\n <Select\n options={config.columns.map((c) => ({ value: c.key, label: c.label ?? c.key }))}\n value={chart.xField ?? ''}\n onChange={(v) => setChart({ xField: typeof v === 'string' ? v : String(v) })}\n />\n </div>\n <div className=\"flow-inspector-subtitle-sm\">\n {chart.type === 'scatter' || chart.type === 'pie' ? '数值字段' : '数值字段(可多选,多系列)'}\n </div>\n {nums.length === 0 && (\n <div className=\"flow-inspector-help\">没有数值列,请先将某列类型设为「数值」。</div>\n )}\n {nums.map((f) => {\n const selected = (chart.yFields ?? []).includes(f);\n const single = chart.type === 'scatter' || chart.type === 'pie';\n return (\n <label key={f} className=\"flow-data-field-toggle\">\n <input\n type={single ? 'radio' : 'checkbox'}\n className={single ? 'radio radio-xs radio-primary' : 'checkbox checkbox-xs checkbox-primary'}\n checked={selected}\n onChange={(e) => {\n if (single) {\n setChart({ yFields: [f] });\n return;\n }\n const current = new Set(chart.yFields ?? []);\n if (e.target.checked) current.add(f);\n else current.delete(f);\n setChart({ yFields: Array.from(current) });\n }}\n />\n <span>{labelFor(config.columns, f)}</span>\n </label>\n );\n })}\n\n {/* Chart colors */}\n {(chart.yFields ?? []).length > 0 && chart.type !== 'pie' && (\n <>\n <div className=\"flow-inspector-subtitle-sm\">系列颜色</div>\n {(chart.yFields ?? []).map((f, i) => {\n const color = chart.seriesColors?.[f] ?? DATA_CHART_PALETTE[i % DATA_CHART_PALETTE.length];\n const overridden = !!chart.seriesColors?.[f];\n return (\n <div key={f} className=\"flow-data-color-row\">\n <input\n type=\"color\"\n value={color}\n onChange={(e) => setSeriesColor(f, e.target.value)}\n />\n <span className=\"flow-data-color-label\">{labelFor(config.columns, f)}</span>\n {overridden && (\n <Button size=\"xs\" variant=\"ghost\" onClick={() => resetSeriesColor(f)}>\n 重置\n </Button>\n )}\n </div>\n );\n })}\n </>\n )}\n {chart.type === 'pie' && (\n <>\n <div className=\"flow-inspector-subtitle-sm\">饼图配色</div>\n <div className=\"flow-data-palette\">\n {DATA_CHART_PALETTE.map((_, i) => (\n <input\n key={i}\n type=\"color\"\n value={palette[i % palette.length]}\n onChange={(e) => setPaletteColor(i, e.target.value)}\n />\n ))}\n </div>\n {chart.palette && (\n <div className=\"flow-inspector-row\">\n <Button size=\"xs\" variant=\"ghost\" onClick={() => setChart({ palette: undefined })}>\n 重置为默认配色\n </Button>\n </div>\n )}\n </>\n )}\n </>\n )}\n\n {/* Pivot config */}\n {config.view === 'table' && (\n <>\n <div className=\"flow-inspector-subtitle\">透视(Pivot)</div>\n <label className=\"flow-data-field-toggle\">\n <input\n type=\"checkbox\"\n className=\"toggle toggle-xs toggle-primary\"\n checked={pivot.enabled}\n onChange={(e) => setPivot({ enabled: e.target.checked })}\n />\n <span>开启透视模式</span>\n </label>\n {pivot.enabled && (\n <div className=\"flow-inspector-row\">\n <Label size=\"xs\" className=\"flow-inspector-label\">面板位置</Label>\n <Select\n options={PIVOT_PLACEMENT_OPTIONS}\n value={pivot.panelPlacement ?? 'top'}\n onChange={(v) => setPivot({ panelPlacement: v as FlowDataPivotPanelPlacement })}\n />\n </div>\n )}\n <div className=\"flow-inspector-help\">\n 透视的行/列/度量可在画布节点内的透视面板上交互拖拽调整。\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport default DataInspectorSection;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpandableTextarea.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/ExpandableTextarea.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport Button from '../../../Button';\nimport Label from '../../../Label';\n\n/**\n * Textarea with a \"fullscreen\" expand button. The fullscreen overlay edits the\n * same value; `onBlur`/`onDone` let callers commit expensive parses only when\n * editing finishes instead of on every keystroke.\n */\nexport function ExpandableTextarea({\n label,\n value,\n onChange,\n onBlur,\n rows,\n placeholder,\n}: {\n label: string;\n value: string;\n onChange: (value: string) => void;\n /** Called when the inline textarea loses focus or fullscreen is closed. */\n onBlur?: (value: string) => void;\n rows: number;\n placeholder?: string;\n}) {\n const [expanded, setExpanded] = useState(false);\n\n const closeFullscreen = () => {\n setExpanded(false);\n onBlur?.(value);\n };\n\n return (\n <>\n <div className=\"flow-inspector-row flow-inspector-multiline\">\n <div className=\"flow-inspector-field-heading\">\n <Label size=\"xs\" className=\"flow-inspector-label\">{label}</Label>\n <Button size=\"xs\" variant=\"ghost\" square onClick={() => setExpanded(true)}>\n <span aria-label=\"全屏编辑\" title=\"全屏编辑\">↗</span>\n </Button>\n </div>\n <textarea\n className=\"flow-inspector-textarea\"\n value={value}\n placeholder={placeholder}\n onChange={(event) => onChange(event.target.value)}\n onBlur={() => onBlur?.(value)}\n rows={rows}\n spellCheck={false}\n />\n </div>\n {expanded && (\n <div className=\"flow-editor-fullscreen\" role=\"dialog\" aria-modal=\"true\" aria-label={`${label} 全屏编辑`}>\n <div className=\"flow-editor-fullscreen-header\">\n <strong>{label}</strong>\n <Button size=\"sm\" variant=\"ghost\" onClick={closeFullscreen}>完成</Button>\n </div>\n <textarea\n className=\"flow-inspector-textarea flow-editor-fullscreen-input\"\n value={value}\n placeholder={placeholder}\n onChange={(event) => onChange(event.target.value)}\n spellCheck={false}\n autoFocus\n />\n </div>\n )}\n </>\n );\n}\n\nexport default ExpandableTextarea;\n"],"mappings":";;;;;AASA,
|
|
1
|
+
{"version":3,"file":"ExpandableTextarea.js","names":["_Fragment","Button","ButtonWithCompounds","Label","ExpandableTextarea","expanded","setExpanded","useState","Fragment","label","onChange","event","onBlur","value"],"sources":["../../../../../src/components/pro/Flow/panels/ExpandableTextarea.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport Button from '../../../Button';\nimport Label from '../../../Label';\n\n/**\n * Textarea with a \"fullscreen\" expand button. The fullscreen overlay edits the\n * same value; `onBlur`/`onDone` let callers commit expensive parses only when\n * editing finishes instead of on every keystroke.\n */\nexport function ExpandableTextarea({\n label,\n value,\n onChange,\n onBlur,\n rows,\n placeholder,\n}: {\n label: string;\n value: string;\n onChange: (value: string) => void;\n /** Called when the inline textarea loses focus or fullscreen is closed. */\n onBlur?: (value: string) => void;\n rows: number;\n placeholder?: string;\n}) {\n const [expanded, setExpanded] = useState(false);\n\n const closeFullscreen = () => {\n setExpanded(false);\n onBlur?.(value);\n };\n\n return (\n <>\n <div className=\"flow-inspector-row flow-inspector-multiline\">\n <div className=\"flow-inspector-field-heading\">\n <Label size=\"xs\" className=\"flow-inspector-label\">{label}</Label>\n <Button size=\"xs\" variant=\"ghost\" square onClick={() => setExpanded(true)}>\n <span aria-label=\"全屏编辑\" title=\"全屏编辑\">↗</span>\n </Button>\n </div>\n <textarea\n className=\"flow-inspector-textarea\"\n value={value}\n placeholder={placeholder}\n onChange={(event) => onChange(event.target.value)}\n onBlur={() => onBlur?.(value)}\n rows={rows}\n spellCheck={false}\n />\n </div>\n {expanded && (\n <div className=\"flow-editor-fullscreen\" role=\"dialog\" aria-modal=\"true\" aria-label={`${label} 全屏编辑`}>\n <div className=\"flow-editor-fullscreen-header\">\n <strong>{label}</strong>\n <Button size=\"sm\" variant=\"ghost\" onClick={closeFullscreen}>完成</Button>\n </div>\n <textarea\n className=\"flow-inspector-textarea flow-editor-fullscreen-input\"\n value={value}\n placeholder={placeholder}\n onChange={(event) => onChange(event.target.value)}\n spellCheck={false}\n autoFocus\n />\n </div>\n )}\n </>\n );\n}\n\nexport default ExpandableTextarea;\n"],"mappings":";;;;;AASA,SAAgBI,EAAmB,EACjC,UACA,UACA,aACA,WACA,SACA,kBASC;CACD,IAAM,CAACC,GAAUC,KAAeC,EAAS,EAAK;CAO9C,OACE,kBAAAP,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAACG,GAAD;IAAO,MAAK;IAAK,WAAU;IAAwB,UAAAM;GAAa,CAAA,GAChE,kBAACR,GAAD;IAAQ,MAAK;IAAK,SAAQ;IAAQ,QAAA;IAAO,eAAeK,EAAY,EAAI;IACtE,UAAA,kBAAC,QAAD;KAAM,cAAW;KAAO,OAAM;KAAO,UAAA;IAAO,CAAA;GACtC,CAAA,CACL;EACL,CAAA,GAAA,kBAAC,YAAD;GACE,WAAU;GACH;GACM;GACb,WAAW,MAAUI,EAASC,EAAM,OAAO,KAAK;GAChD,cAAcC,IAASC,CAAK;GACtB;GACN,YAAY;EACb,CAAA,CACE;CACJ,CAAA,GAAAR,KACC,kBAAC,OAAD;EAAK,WAAU;EAAyB,MAAK;EAAS,cAAW;EAAO,cAAY,GAAGI,EAAM;EAA7F,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,UAAD,EAAA,UAASA,EAAc,CAAA,GACvB,kBAACR,GAAD;IAAQ,MAAK;IAAK,SAAQ;IAAQ,eA5Bd;KAE5B,AADAK,EAAY,EAAK,GACjBM,IAASC,CAAK;IAChB;IAyBsE,UAAA;GAAU,CAAA,CACnE;EACL,CAAA,GAAA,kBAAC,YAAD;GACE,WAAU;GACH;GACM;GACb,WAAW,MAAUH,EAASC,EAAM,OAAO,KAAK;GAChD,YAAY;GACZ,WAAA;EACD,CAAA,CACE;CAEP,CAAA,CAAA,EAAA,CAAA;AAEN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowPanelGroup.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/FlowPanelGroup.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport Select from '../../../Select';\nimport { useDraggablePanel } from '../hooks/useDraggablePanel';\nimport { useResizablePanel, type ResizeEdge } from '../hooks/useResizablePanel';\nimport type { FlowPanelDock } from '../context/FlowUIContext';\n\nexport interface PanelTab {\n id: string;\n label: string;\n icon?: React.ReactNode;\n content: React.ReactNode;\n}\n\ninterface FlowPanelGroupProps {\n tabs: PanelTab[];\n defaultTab?: string;\n className?: string;\n resizeEdge: ResizeEdge;\n defaultWidth: number;\n style?: React.CSSProperties;\n /** Which dock this group occupies ('float' = draggable overlay). */\n dock?: FlowPanelDock;\n /** Request moving the current tab to another dock (left/right/float). */\n onDock?: (tabId: string, dock: FlowPanelDock) => void;\n /** Floating panels report the dock edge they hover while dragging. */\n onDragHintChange?: (side: 'left' | 'right' | null) => void;\n /** Close (hide) the current panel; it can be reopened via the toolbar. */\n onClose?: (tabId: string) => void;\n}\n\n/** Header buttons offered per current dock, in display order. */\nconst DOCK_ACTIONS: Record<FlowPanelDock, Array<{ target: FlowPanelDock; glyph: string; title: string }>> = {\n left: [\n { target: 'float', glyph: '⬈', title: '浮动面板' },\n { target: 'right', glyph: '⇥', title: '停靠到右侧' },\n ],\n right: [\n { target: 'left', glyph: '⇤', title: '停靠到左侧' },\n { target: 'float', glyph: '⬈', title: '浮动面板' },\n ],\n float: [\n { target: 'left', glyph: '⇤', title: '停靠到左侧' },\n { target: 'right', glyph: '⇥', title: '停靠到右侧' },\n ],\n};\n\nexport default function FlowPanelGroup({\n tabs,\n defaultTab,\n className,\n resizeEdge,\n defaultWidth,\n style,\n dock,\n onDock,\n onDragHintChange,\n onClose,\n}: FlowPanelGroupProps) {\n const [activeTab, setActiveTab] = useState(defaultTab ?? tabs[0]?.id);\n const isFloating = dock === 'float';\n const currentId = tabs.find(t => t.id === activeTab)?.id ?? tabs[0]?.id;\n const { panelStyle, handleProps } = useDraggablePanel(\n isFloating\n ? {\n onDropDock: (side) => { if (currentId) onDock?.(currentId, side); },\n onDragHintChange,\n }\n : undefined,\n );\n const { panelWidth, resizeHandleProps } = useResizablePanel(resizeEdge, defaultWidth);\n\n useEffect(() => {\n if (tabs.length > 0 && !tabs.find(t => t.id === activeTab)) {\n setActiveTab(tabs[0].id);\n }\n }, [tabs, activeTab]);\n\n const handleDock = useCallback((target: FlowPanelDock) => {\n if (currentId) onDock?.(currentId, target);\n }, [currentId, onDock]);\n\n if (tabs.length === 0) return null;\n\n const current = tabs.find(t => t.id === activeTab) ?? tabs[0];\n const showSwitcher = tabs.length > 1;\n const actions = DOCK_ACTIONS[dock ?? 'left'];\n\n return (\n <div\n className={`${className ?? 'flow-palette'}${isFloating ? ' flow-panel--detached' : ' flow-panel--docked'}`}\n data-flow-panel\n style={{ ...style, ...(isFloating ? panelStyle : undefined), width: panelWidth }}\n >\n <div\n className={`flow-panel-resize-handle flow-panel-resize-handle--${resizeEdge}`}\n {...resizeHandleProps}\n />\n <div className=\"flow-panel-header\">\n {isFloating && (\n <span className=\"flow-panel-grip\" title=\"拖动移动面板\" {...handleProps}>⠿</span>\n )}\n {showSwitcher ? (\n <Select\n className=\"flow-panel-select\"\n options={tabs.map(t => ({\n value: t.id,\n label: typeof t.icon === 'string' && t.icon ? `${t.icon} ${t.label}` : t.label,\n }))}\n value={current.id}\n onChange={(v) => setActiveTab(String(v))}\n />\n ) : (\n <span className=\"flow-panel-header-label\">\n {current.icon && <span className=\"flow-panel-tab-icon\">{current.icon}</span>}\n {current.label}\n </span>\n )}\n <span className=\"flow-panel-header-actions\">\n {actions.map(a => (\n <button\n key={a.target}\n type=\"button\"\n className=\"flow-panel-dock-btn\"\n title={a.title}\n onClick={() => handleDock(a.target)}\n >{a.glyph}</button>\n ))}\n {onClose && (\n <button\n type=\"button\"\n className=\"flow-panel-dock-btn flow-panel-close-btn\"\n title=\"关闭面板(可从工具栏重新打开)\"\n onClick={() => { if (currentId) onClose(currentId); }}\n >✕</button>\n )}\n </span>\n </div>\n <div className=\"flow-palette-content\">\n {current.content}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;AA+BA,
|
|
1
|
+
{"version":3,"file":"FlowPanelGroup.js","names":["Select","DOCK_ACTIONS","FlowPanelGroup","activeTab","setActiveTab","useState","defaultTab","tabs","isFloating","dock","currentId","t","useDraggablePanel","onDock","side","useResizablePanel","resizeEdge","defaultWidth","handleDock","useCallback","target","current","showSwitcher","actions","className","style","panelStyle","panelWidth","resizeHandleProps","handleProps","v","a","onClose"],"sources":["../../../../../src/components/pro/Flow/panels/FlowPanelGroup.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport Select from '../../../Select';\nimport { useDraggablePanel } from '../hooks/useDraggablePanel';\nimport { useResizablePanel, type ResizeEdge } from '../hooks/useResizablePanel';\nimport type { FlowPanelDock } from '../context/FlowUIContext';\n\nexport interface PanelTab {\n id: string;\n label: string;\n icon?: React.ReactNode;\n content: React.ReactNode;\n}\n\ninterface FlowPanelGroupProps {\n tabs: PanelTab[];\n defaultTab?: string;\n className?: string;\n resizeEdge: ResizeEdge;\n defaultWidth: number;\n style?: React.CSSProperties;\n /** Which dock this group occupies ('float' = draggable overlay). */\n dock?: FlowPanelDock;\n /** Request moving the current tab to another dock (left/right/float). */\n onDock?: (tabId: string, dock: FlowPanelDock) => void;\n /** Floating panels report the dock edge they hover while dragging. */\n onDragHintChange?: (side: 'left' | 'right' | null) => void;\n /** Close (hide) the current panel; it can be reopened via the toolbar. */\n onClose?: (tabId: string) => void;\n}\n\n/** Header buttons offered per current dock, in display order. */\nconst DOCK_ACTIONS: Record<FlowPanelDock, Array<{ target: FlowPanelDock; glyph: string; title: string }>> = {\n left: [\n { target: 'float', glyph: '⬈', title: '浮动面板' },\n { target: 'right', glyph: '⇥', title: '停靠到右侧' },\n ],\n right: [\n { target: 'left', glyph: '⇤', title: '停靠到左侧' },\n { target: 'float', glyph: '⬈', title: '浮动面板' },\n ],\n float: [\n { target: 'left', glyph: '⇤', title: '停靠到左侧' },\n { target: 'right', glyph: '⇥', title: '停靠到右侧' },\n ],\n};\n\nexport default function FlowPanelGroup({\n tabs,\n defaultTab,\n className,\n resizeEdge,\n defaultWidth,\n style,\n dock,\n onDock,\n onDragHintChange,\n onClose,\n}: FlowPanelGroupProps) {\n const [activeTab, setActiveTab] = useState(defaultTab ?? tabs[0]?.id);\n const isFloating = dock === 'float';\n const currentId = tabs.find(t => t.id === activeTab)?.id ?? tabs[0]?.id;\n const { panelStyle, handleProps } = useDraggablePanel(\n isFloating\n ? {\n onDropDock: (side) => { if (currentId) onDock?.(currentId, side); },\n onDragHintChange,\n }\n : undefined,\n );\n const { panelWidth, resizeHandleProps } = useResizablePanel(resizeEdge, defaultWidth);\n\n useEffect(() => {\n if (tabs.length > 0 && !tabs.find(t => t.id === activeTab)) {\n setActiveTab(tabs[0].id);\n }\n }, [tabs, activeTab]);\n\n const handleDock = useCallback((target: FlowPanelDock) => {\n if (currentId) onDock?.(currentId, target);\n }, [currentId, onDock]);\n\n if (tabs.length === 0) return null;\n\n const current = tabs.find(t => t.id === activeTab) ?? tabs[0];\n const showSwitcher = tabs.length > 1;\n const actions = DOCK_ACTIONS[dock ?? 'left'];\n\n return (\n <div\n className={`${className ?? 'flow-palette'}${isFloating ? ' flow-panel--detached' : ' flow-panel--docked'}`}\n data-flow-panel\n style={{ ...style, ...(isFloating ? panelStyle : undefined), width: panelWidth }}\n >\n <div\n className={`flow-panel-resize-handle flow-panel-resize-handle--${resizeEdge}`}\n {...resizeHandleProps}\n />\n <div className=\"flow-panel-header\">\n {isFloating && (\n <span className=\"flow-panel-grip\" title=\"拖动移动面板\" {...handleProps}>⠿</span>\n )}\n {showSwitcher ? (\n <Select\n className=\"flow-panel-select\"\n options={tabs.map(t => ({\n value: t.id,\n label: typeof t.icon === 'string' && t.icon ? `${t.icon} ${t.label}` : t.label,\n }))}\n value={current.id}\n onChange={(v) => setActiveTab(String(v))}\n />\n ) : (\n <span className=\"flow-panel-header-label\">\n {current.icon && <span className=\"flow-panel-tab-icon\">{current.icon}</span>}\n {current.label}\n </span>\n )}\n <span className=\"flow-panel-header-actions\">\n {actions.map(a => (\n <button\n key={a.target}\n type=\"button\"\n className=\"flow-panel-dock-btn\"\n title={a.title}\n onClick={() => handleDock(a.target)}\n >{a.glyph}</button>\n ))}\n {onClose && (\n <button\n type=\"button\"\n className=\"flow-panel-dock-btn flow-panel-close-btn\"\n title=\"关闭面板(可从工具栏重新打开)\"\n onClick={() => { if (currentId) onClose(currentId); }}\n >✕</button>\n )}\n </span>\n </div>\n <div className=\"flow-palette-content\">\n {current.content}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FlowToolbar.js","names":[],"sources":["../../../../../src/components/pro/Flow/panels/FlowToolbar.tsx"],"sourcesContent":["import React, { useRef, useCallback } from 'react';\nimport Button from '../../../Button';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { useFlowContext } from '../context/FlowContext';\nimport ProjectTitle from './ProjectTitle';\nimport { useFlowImportExport, downloadDataURL, safeFileBaseName } from '../hooks/useFlowImportExport';\nimport { useLayoutActions } from '../hooks/useLayoutActions';\n\n\nimport {\n IconBack,\n IconUndo,\n IconRedo,\n IconGroup,\n IconGeoGroup,\n IconUngroup,\n IconAlign,\n IconZoomIn,\n IconZoomOut,\n IconFitView,\n IconAutoFocus,\n IconShapes,\n IconInspector,\n IconOutline,\n IconJson,\n IconAI,\n IconGrid,\n IconMagnet,\n IconMiniMap,\n IconImport,\n IconExportJson,\n IconExportPng,\n IconExportPdf,\n IconExportMarkdown,\n IconLayer,\n IconPublish,\n IconAnchorVisible,\n IconPresent,\n} from './toolbarIcons';\n\n/** Compact zoom / view controls floated over the bottom-left of the canvas. */\nexport function FlowZoomControls() {\n const { viewport, setViewport, autoFocus, setAutoFocus } = useFlowUI();\n const zoomPercent = Math.round(viewport.zoom * 100);\n\n const handleZoomIn = () => {\n setViewport({ ...viewport, zoom: Math.min(4, viewport.zoom * 1.2) });\n };\n const handleZoomOut = () => {\n setViewport({ ...viewport, zoom: Math.max(0.1, viewport.zoom / 1.2) });\n };\n const handleFitView = () => {\n setViewport({ x: 0, y: 0, zoom: 1 });\n };\n\n return (\n <div className=\"flow-zoom-controls\">\n <ToolButton tip=\"缩小\" onClick={handleZoomOut}>\n <IconZoomOut />\n </ToolButton>\n <span className=\"flow-zoom-info\">{zoomPercent}%</span>\n <ToolButton tip=\"放大\" onClick={handleZoomIn}>\n <IconZoomIn />\n </ToolButton>\n <ToolButton tip=\"适应视图\" onClick={handleFitView}>\n <IconFitView />\n </ToolButton>\n <ToolButton\n tip={autoFocus ? '关闭 Auto Focus' : '开启 Auto Focus'}\n active={autoFocus}\n onClick={() => setAutoFocus(!autoFocus)}\n >\n <IconAutoFocus />\n </ToolButton>\n </div>\n );\n}\n\n\n/** A toolbar button with an accessible, hover-revealed tooltip below it. */\ninterface ToolButtonProps {\n tip: string;\n shortcut?: string;\n onClick: () => void;\n active?: boolean;\n disabled?: boolean;\n children: React.ReactNode;\n}\n\nfunction ToolButton({ tip, shortcut, onClick, active, disabled, children }: ToolButtonProps) {\n const label = shortcut ? `${tip} (${shortcut})` : tip;\n return (\n <span className=\"flow-tip\">\n <Button\n size=\"xs\"\n variant={active ? 'primary' : 'ghost'}\n onClick={onClick}\n disabled={disabled}\n square\n >\n <span aria-label={label} style={{ display: 'inline-flex' }}>{children}</span>\n </Button>\n <span className=\"flow-tip-label\" role=\"tooltip\">{label}</span>\n </span>\n );\n}\n\nexport interface FlowToolbarProps {\n onBack?: () => void;\n onUndo?: () => void;\n onRedo?: () => void;\n canUndo?: boolean;\n canRedo?: boolean;\n onGroup?: () => void;\n onGeoGroup?: () => void;\n onUngroup?: () => void;\n onExportPNG?: () => void | Promise<void>;\n /** Export anchors as a PDF slideshow from the built-in toolbar. */\n onExportPDF?: () => void | Promise<void>;\n onPublish?: () => void;\n /** Small-screen (container-width) layout: the title gets its own row and\n * button groups wrap below instead of sliding under the absolute title. */\n compact?: boolean;\n}\n\nexport default function FlowToolbar({ onBack, onUndo, onRedo, canUndo, canRedo, onGroup, onGeoGroup, onUngroup, onExportPNG, onExportPDF, onPublish, compact }: FlowToolbarProps) {\n const {\n showGrid, setShowGrid,\n showPalette, setShowPalette,\n showInspector, setShowInspector,\n showOutline, setShowOutline,\n showJson, setShowJson,\n showAI, setShowAI,\n showMiniMap, setShowMiniMap,\n showAnchors, setShowAnchors,\n presentation, setPresentation,\n placementSnap, setPlacementSnap,\n } = useFlowUI();\n const { doc, selection, currentCanvas, setDoc, currentCanvasId } = useFlowContext();\n const { exportJSON, importJSON, exportMarkdown } = useFlowImportExport();\n const { align, distribute, changeZIndex } = useLayoutActions();\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const selTotalCount = selection.nodeIds.size + selection.lineIds.size;\n const hasGroupSelected = selection.nodeIds.size > 0 && currentCanvas.nodes.some(\n n => selection.nodeIds.has(n.id) && (n.type === 'flowGroup' || n.type === 'geometryGroup' || n.data.isGroup),\n );\n const hasAnchors = Object.values(doc.canvases).some(canvas =>\n canvas.nodes.some(node => node.type === 'animAnchor'),\n );\n\n\n const handleExportJSON = useCallback(() => {\n const json = exportJSON();\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n downloadDataURL(url, `${safeFileBaseName(doc.title)}.json`);\n URL.revokeObjectURL(url);\n }, [exportJSON, doc.title]);\n\n const handleExportMarkdown = useCallback(() => {\n const md = exportMarkdown();\n const blob = new Blob([md], { type: 'text/markdown' });\n const url = URL.createObjectURL(blob);\n downloadDataURL(url, `${safeFileBaseName(doc.title)}.md`);\n URL.revokeObjectURL(url);\n }, [exportMarkdown, doc.title]);\n\n const handleImportJSON = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n if (typeof reader.result === 'string') importJSON(reader.result);\n };\n reader.readAsText(file);\n e.target.value = '';\n }, [importJSON]);\n\n return (\n <div className={`flow-toolbar${compact ? ' flow-toolbar--compact' : ''}`}>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".json\"\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n\n {/* Editable project title, anchored to the toolbar's left edge. Hidden\n in compact mode: the host app's header already shows the name, and\n the narrow toolbar needs the row for buttons. */}\n {!compact && <ProjectTitle />}\n\n {onBack && (\n <>\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"返回列表\" onClick={onBack}>\n <IconBack />\n </ToolButton>\n </div>\n <div className=\"flow-toolbar-divider\" />\n </>\n )}\n\n {/* 历史:撤销 / 重做 */}\n {(onUndo || onRedo) && (\n <div className=\"flow-toolbar-group\">\n {onUndo && (\n <ToolButton tip=\"撤销\" shortcut=\"Ctrl+Z\" onClick={onUndo} disabled={!canUndo}>\n <IconUndo />\n </ToolButton>\n )}\n {onRedo && (\n <ToolButton tip=\"重做\" shortcut=\"Ctrl+Shift+Z\" onClick={onRedo} disabled={!canRedo}>\n <IconRedo />\n </ToolButton>\n )}\n </div>\n )}\n\n {/* 排列:对齐 / 平分 */}\n {selection.nodeIds.size >= 2 && (\n <>\n <div className=\"flow-toolbar-divider\" />\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"居左\" onClick={() => align('left')}><IconAlign kind=\"left\" /></ToolButton>\n <ToolButton tip=\"水平居中\" onClick={() => align('center-h')}><IconAlign kind=\"center-h\" /></ToolButton>\n <ToolButton tip=\"居右\" onClick={() => align('right')}><IconAlign kind=\"right\" /></ToolButton>\n <ToolButton tip=\"居上\" onClick={() => align('top')}><IconAlign kind=\"top\" /></ToolButton>\n <ToolButton tip=\"垂直居中\" onClick={() => align('center-v')}><IconAlign kind=\"center-v\" /></ToolButton>\n <ToolButton tip=\"居下\" onClick={() => align('bottom')}><IconAlign kind=\"bottom\" /></ToolButton>\n <ToolButton tip=\"水平平分\" onClick={() => distribute('horizontal')} disabled={selection.nodeIds.size < 3}>\n <IconAlign kind=\"distribute-h\" />\n </ToolButton>\n <ToolButton tip=\"垂直平分\" onClick={() => distribute('vertical')} disabled={selection.nodeIds.size < 3}>\n <IconAlign kind=\"distribute-v\" />\n </ToolButton>\n </div>\n </>\n )}\n\n {/* 图层:置顶 / 上移 / 下移 / 置底 */}\n {selTotalCount >= 1 && (\n <>\n <div className=\"flow-toolbar-divider\" />\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"置于顶层\" onClick={() => changeZIndex('front')}><IconLayer kind=\"front\" /></ToolButton>\n <ToolButton tip=\"上移一层\" onClick={() => changeZIndex('up')}><IconLayer kind=\"up\" /></ToolButton>\n <ToolButton tip=\"下移一层\" onClick={() => changeZIndex('down')}><IconLayer kind=\"down\" /></ToolButton>\n <ToolButton tip=\"置于底层\" onClick={() => changeZIndex('back')}><IconLayer kind=\"back\" /></ToolButton>\n </div>\n </>\n )}\n\n {/* 组合:成组 / 几何分组 / 取消成组 */}\n {(onGroup || onGeoGroup || onUngroup) && (\n <>\n <div className=\"flow-toolbar-divider\" />\n <div className=\"flow-toolbar-group\">\n {onGroup && (\n <ToolButton tip=\"成组\" shortcut=\"⌘G\" onClick={onGroup} disabled={selTotalCount < 2}>\n <IconGroup />\n </ToolButton>\n )}\n {onGeoGroup && (\n <ToolButton tip=\"几何分组\" shortcut=\"⌘⌥G\" onClick={onGeoGroup} disabled={selTotalCount < 2}>\n <IconGeoGroup />\n </ToolButton>\n )}\n {onUngroup && (\n <ToolButton tip=\"取消成组\" shortcut=\"⌘⇧G\" onClick={onUngroup} disabled={!hasGroupSelected}>\n <IconUngroup />\n </ToolButton>\n )}\n </div>\n </>\n )}\n\n <div className=\"flow-toolbar-divider\" />\n\n {/* 视图:网格 / 缩略图 / Anchor / 动画预览 */}\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"网格\" active={showGrid} onClick={() => setShowGrid(!showGrid)}>\n <IconGrid />\n </ToolButton>\n <ToolButton\n tip={placementSnap ? '放置吸附网格:开(盖章自动贴近网格)' : '放置吸附网格:关(自由放置)'}\n active={placementSnap}\n onClick={() => setPlacementSnap(!placementSnap)}\n >\n <IconMagnet />\n </ToolButton>\n <ToolButton tip=\"缩略图\" active={showMiniMap} onClick={() => setShowMiniMap(!showMiniMap)}>\n <IconMiniMap />\n </ToolButton>\n <ToolButton\n tip={showAnchors ? '隐藏所有 Anchor 对象' : '显示所有 Anchor 对象'}\n active={showAnchors}\n disabled={!hasAnchors}\n onClick={() => {\n if (hasAnchors) setShowAnchors(!showAnchors);\n }}\n >\n <IconAnchorVisible visible={showAnchors} />\n </ToolButton>\n <ToolButton\n tip=\"动画预览\"\n active={presentation !== null}\n onClick={() => setPresentation(presentation ? null : { current: 0, showAnchor: false })}\n >\n <IconPresent />\n </ToolButton>\n </div>\n\n <div className=\"flow-toolbar-divider\" />\n\n {/* 面板:形状 / 属性 / 大纲 / JSON */}\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"形状面板\" active={showPalette} onClick={() => setShowPalette(!showPalette)}>\n <IconShapes />\n </ToolButton>\n <ToolButton tip=\"属性面板\" active={showInspector} onClick={() => setShowInspector(!showInspector)}>\n <IconInspector />\n </ToolButton>\n <ToolButton tip=\"大纲\" active={showOutline} onClick={() => setShowOutline(!showOutline)}>\n <IconOutline />\n </ToolButton>\n <ToolButton tip=\"JSON\" active={showJson} onClick={() => setShowJson(!showJson)}>\n <IconJson />\n </ToolButton>\n <ToolButton tip=\"AI 助手\" active={showAI} onClick={() => setShowAI(!showAI)}>\n <IconAI />\n </ToolButton>\n </div>\n\n <div className=\"flow-toolbar-divider\" />\n\n {/* 文件:导入 / 导出 / 发布 */}\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"导入 JSON\" onClick={handleImportJSON}>\n <IconImport />\n </ToolButton>\n <ToolButton tip=\"导出 JSON\" onClick={handleExportJSON}>\n <IconExportJson />\n </ToolButton>\n <ToolButton tip=\"导出 Markdown\" onClick={handleExportMarkdown}>\n <IconExportMarkdown />\n </ToolButton>\n {onExportPNG && (\n <ToolButton tip=\"导出 PNG\" onClick={() => void onExportPNG()}>\n <IconExportPng />\n </ToolButton>\n )}\n {onExportPDF && hasAnchors && (\n <ToolButton tip=\"导出 PDF(按锦点顺序)\" onClick={() => void onExportPDF()}>\n <IconExportPdf />\n </ToolButton>\n )}\n {onPublish && (\n <ToolButton tip=\"发布与共享\" onClick={onPublish}>\n <IconPublish />\n </ToolButton>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAyCA,SAAgB,IAAmB;CACjC,IAAM,EAAE,aAAU,gBAAa,cAAW,oBAAiB,EAAU,GAC/D,IAAc,KAAK,MAAM,EAAS,OAAO,GAAG;CAYlD,OACE,kBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,kBAAC,GAAD;IAAY,KAAI;IAAK,eATG;KAC1B,EAAY;MAAE,GAAG;MAAU,MAAM,KAAK,IAAI,IAAK,EAAS,OAAO,GAAG;KAAE,CAAC;IACvE;IAQM,UAAA,kBAAC,GAAD,CAAc,CAAA;GACJ,CAAA;GACZ,kBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA,CAAkC,GAAY,GAAO;;GACrD,kBAAC,GAAD;IAAY,KAAI;IAAK,eAhBE;KACzB,EAAY;MAAE,GAAG;MAAU,MAAM,KAAK,IAAI,GAAG,EAAS,OAAO,GAAG;KAAE,CAAC;IACrE;IAeM,UAAA,kBAAC,GAAD,CAAa,CAAA;GACH,CAAA;GACZ,kBAAC,GAAD;IAAY,KAAI;IAAO,eAbC;KAC1B,EAAY;MAAE,GAAG;MAAG,GAAG;MAAG,MAAM;KAAE,CAAC;IACrC;IAYM,UAAA,kBAAC,GAAD,CAAc,CAAA;GACJ,CAAA;GACZ,kBAAC,GAAD;IACE,KAAK,IAAY,kBAAkB;IACnC,QAAQ;IACR,eAAe,EAAa,CAAC,CAAS;IAEtC,UAAA,kBAAC,GAAD,CAAgB,CAAA;GACN,CAAA;EACT;;AAET;AAaA,SAAS,EAAW,EAAE,QAAK,aAAU,YAAS,WAAQ,aAAU,eAA6B;CAC3F,IAAM,IAAQ,IAAW,GAAG,EAAI,IAAI,EAAS,KAAK;CAClD,OACE,kBAAC,QAAD;EAAM,WAAU;EAAhB,UAAA,CACE,kBAAC,GAAD;GACE,MAAK;GACL,SAAS,IAAS,YAAY;GACrB;GACC;GACV,QAAA;GAEA,UAAA,kBAAC,QAAD;IAAM,cAAY;IAAO,OAAO,EAAE,SAAS,cAAc;IAAI;GAAe,CAAA;EACtE,CAAA,GACR,kBAAC,QAAD;GAAM,WAAU;GAAiB,MAAK;GAAW,UAAA;EAAY,CAAA,CACzD;;AAEV;AAoBA,SAAwB,EAAY,EAAE,WAAQ,WAAQ,WAAQ,YAAS,YAAS,YAAS,eAAY,cAAW,gBAAa,gBAAa,cAAW,cAA6B;CAChL,IAAM,EACJ,aAAU,gBACV,gBAAa,mBACb,kBAAe,qBACf,gBAAa,oBACb,aAAU,iBACV,WAAQ,eACR,gBAAa,oBACb,gBAAa,oBACb,iBAAc,qBACd,kBAAe,yBACb,EAAU,GACR,EAAE,QAAK,cAAW,mBAAe,YAAQ,wBAAoB,EAAe,GAC5E,EAAE,eAAY,eAAY,sBAAmB,EAAoB,GACjE,EAAE,UAAO,eAAY,oBAAiB,EAAiB,GACvD,IAAe,GAAyB,IAAI,GAE5C,IAAgB,EAAU,QAAQ,OAAO,EAAU,QAAQ,MAC3D,KAAmB,EAAU,QAAQ,OAAO,KAAK,GAAc,MAAM,MACzE,MAAK,EAAU,QAAQ,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,eAAe,EAAE,SAAS,mBAAmB,EAAE,KAAK,QACtG,GACM,IAAa,OAAO,OAAO,EAAI,QAAQ,CAAC,CAAC,MAAK,MAClD,EAAO,MAAM,MAAK,MAAQ,EAAK,SAAS,YAAY,CACtD,GAGM,KAAmB,QAAkB;EACzC,IAAM,IAAO,EAAW,GAClB,IAAO,IAAI,KAAK,CAAC,CAAI,GAAG,EAAE,MAAM,mBAAmB,CAAC,GACpD,IAAM,IAAI,gBAAgB,CAAI;EAEpC,AADA,EAAgB,GAAK,GAAG,EAAiB,EAAI,KAAK,EAAE,MAAM,GAC1D,IAAI,gBAAgB,CAAG;CACzB,GAAG,CAAC,GAAY,EAAI,KAAK,CAAC,GAEpB,KAAuB,QAAkB;EAC7C,IAAM,IAAK,EAAe,GACpB,IAAO,IAAI,KAAK,CAAC,CAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC,GAC/C,IAAM,IAAI,gBAAgB,CAAI;EAEpC,AADA,EAAgB,GAAK,GAAG,EAAiB,EAAI,KAAK,EAAE,IAAI,GACxD,IAAI,gBAAgB,CAAG;CACzB,GAAG,CAAC,GAAgB,EAAI,KAAK,CAAC,GAExB,IAAmB,QAAkB;EACzC,EAAa,SAAS,MAAM;CAC9B,GAAG,CAAC,CAAC,GAEC,KAAmB,GAAa,MAA2C;EAC/E,IAAM,IAAO,EAAE,OAAO,QAAQ;EAC9B,IAAI,CAAC,GAAM;EACX,IAAM,IAAS,IAAI,WAAW;EAK9B,AAJA,EAAO,eAAe;GACpB,AAAI,OAAO,EAAO,UAAW,YAAU,EAAW,EAAO,MAAM;EACjE,GACA,EAAO,WAAW,CAAI,GACtB,EAAE,OAAO,QAAQ;CACnB,GAAG,CAAC,CAAU,CAAC;CAEf,OACE,kBAAC,OAAD;EAAK,WAAW,eAAe,IAAU,2BAA2B;EAApE,UAAA;GACE,kBAAC,SAAD;IACE,KAAK;IACL,MAAK;IACL,QAAO;IACP,OAAO,EAAE,SAAS,OAAO;IACzB,UAAU;GACX,CAAA;GAKA,CAAC,KAAW,kBAAC,GAAD,CAAe,CAAA;GAE3B,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD;KAAY,KAAI;KAAO,SAAS;KAC9B,UAAA,kBAAC,IAAD,CAAW,CAAA;IACD,CAAA;GACT,CAAA,GACL,kBAAC,OAAD,EAAK,WAAU,uBAAwB,CAAA,CACvC,EAAA,CAAA;IAIF,KAAU,MACV,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,KACC,kBAAC,GAAD;KAAY,KAAI;KAAK,UAAS;KAAS,SAAS;KAAQ,UAAU,CAAC;KACjE,UAAA,kBAAC,IAAD,CAAW,CAAA;IACD,CAAA,GAEb,KACC,kBAAC,GAAD;KAAY,KAAI;KAAK,UAAS;KAAe,SAAS;KAAQ,UAAU,CAAC;KACvE,UAAA,kBAAC,IAAD,CAAW,CAAA;IACD,CAAA,CAEX;;GAIN,EAAU,QAAQ,QAAQ,KACzB,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAK,WAAU,uBAAwB,CAAA,GACvC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAY,KAAI;MAAK,eAAe,EAAM,MAAM;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,OAAQ,CAAA;KAAa,CAAA;KACxF,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAM,UAAU;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,WAAY,CAAA;KAAa,CAAA;KAClG,kBAAC,GAAD;MAAY,KAAI;MAAK,eAAe,EAAM,OAAO;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,QAAS,CAAA;KAAa,CAAA;KAC1F,kBAAC,GAAD;MAAY,KAAI;MAAK,eAAe,EAAM,KAAK;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,MAAO,CAAA;KAAa,CAAA;KACtF,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAM,UAAU;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,WAAY,CAAA;KAAa,CAAA;KAClG,kBAAC,GAAD;MAAY,KAAI;MAAK,eAAe,EAAM,QAAQ;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,SAAU,CAAA;KAAa,CAAA;KAC5F,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAW,YAAY;MAAG,UAAU,EAAU,QAAQ,OAAO;MACjG,UAAA,kBAAC,GAAD,EAAW,MAAK,eAAgB,CAAA;KACtB,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAW,UAAU;MAAG,UAAU,EAAU,QAAQ,OAAO;MAC/F,UAAA,kBAAC,GAAD,EAAW,MAAK,eAAgB,CAAA;KACtB,CAAA;IACT;GACL,CAAA,CAAA,EAAA,CAAA;GAIH,KAAiB,KAChB,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAK,WAAU,uBAAwB,CAAA,GACvC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAa,OAAO;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,QAAS,CAAA;KAAa,CAAA;KACnG,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAa,IAAI;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,KAAM,CAAA;KAAa,CAAA;KAC7F,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAa,MAAM;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,OAAQ,CAAA;KAAa,CAAA;KACjG,kBAAC,GAAD;MAAY,KAAI;MAAO,eAAe,EAAa,MAAM;MAAG,UAAA,kBAAC,GAAD,EAAW,MAAK,OAAQ,CAAA;KAAa,CAAA;IAC9F;GACL,CAAA,CAAA,EAAA,CAAA;IAIF,KAAW,KAAc,MACzB,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD,EAAK,WAAU,uBAAwB,CAAA,GACvC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACG,KACC,kBAAC,GAAD;MAAY,KAAI;MAAK,UAAS;MAAK,SAAS;MAAS,UAAU,IAAgB;MAC7E,UAAA,kBAAC,IAAD,CAAY,CAAA;KACF,CAAA;KAEb,KACC,kBAAC,GAAD;MAAY,KAAI;MAAO,UAAS;MAAM,SAAS;MAAY,UAAU,IAAgB;MACnF,UAAA,kBAAC,IAAD,CAAe,CAAA;KACL,CAAA;KAEb,KACC,kBAAC,GAAD;MAAY,KAAI;MAAO,UAAS;MAAM,SAAS;MAAW,UAAU,CAAC;MACnE,UAAA,kBAAC,GAAD,CAAc,CAAA;KACJ,CAAA;IAEX;GACL,CAAA,CAAA,EAAA,CAAA;GAGJ,kBAAC,OAAD,EAAK,WAAU,uBAAwB,CAAA;GAGvC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAY,KAAI;MAAK,QAAQ;MAAU,eAAe,EAAY,CAAC,CAAQ;MACzE,UAAA,kBAAC,IAAD,CAAW,CAAA;KACD,CAAA;KACZ,kBAAC,GAAD;MACE,KAAK,IAAgB,uBAAuB;MAC5C,QAAQ;MACR,eAAe,GAAiB,CAAC,CAAa;MAE9C,UAAA,kBAAC,GAAD,CAAa,CAAA;KACH,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAM,QAAQ;MAAa,eAAe,GAAe,CAAC,CAAW;MACnF,UAAA,kBAAC,GAAD,CAAc,CAAA;KACJ,CAAA;KACZ,kBAAC,GAAD;MACE,KAAK,IAAc,mBAAmB;MACtC,QAAQ;MACR,UAAU,CAAC;MACX,eAAe;OACb,AAAI,KAAY,GAAe,CAAC,CAAW;MAC7C;MAEA,UAAA,kBAAC,IAAD,EAAmB,SAAS,EAAc,CAAA;KAChC,CAAA;KACZ,kBAAC,GAAD;MACE,KAAI;MACJ,QAAQ,MAAiB;MACzB,eAAe,GAAgB,IAAe,OAAO;OAAE,SAAS;OAAG,YAAY;MAAM,CAAC;MAEtF,UAAA,kBAAC,IAAD,CAAc,CAAA;KACJ,CAAA;IACT;;GAEL,kBAAC,OAAD,EAAK,WAAU,uBAAwB,CAAA;GAGvC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAY,KAAI;MAAO,QAAQ;MAAa,eAAe,EAAe,CAAC,CAAW;MACpF,UAAA,kBAAC,IAAD,CAAa,CAAA;KACH,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAO,QAAQ;MAAe,eAAe,EAAiB,CAAC,CAAa;MAC1F,UAAA,kBAAC,IAAD,CAAgB,CAAA;KACN,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAK,QAAQ;MAAa,eAAe,GAAe,CAAC,CAAW;MAClF,UAAA,kBAAC,IAAD,CAAc,CAAA;KACJ,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAO,QAAQ;MAAU,eAAe,GAAY,CAAC,CAAQ;MAC3E,UAAA,kBAAC,IAAD,CAAW,CAAA;KACD,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAQ,QAAQ;MAAQ,eAAe,GAAU,CAAC,CAAM;MACtE,UAAA,kBAAC,IAAD,CAAS,CAAA;KACC,CAAA;IACT;;GAEL,kBAAC,OAAD,EAAK,WAAU,uBAAwB,CAAA;GAGvC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAY,KAAI;MAAU,SAAS;MACjC,UAAA,kBAAC,IAAD,CAAa,CAAA;KACH,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAU,SAAS;MACjC,UAAA,kBAAC,IAAD,CAAiB,CAAA;KACP,CAAA;KACZ,kBAAC,GAAD;MAAY,KAAI;MAAc,SAAS;MACrC,UAAA,kBAAC,IAAD,CAAqB,CAAA;KACX,CAAA;KACX,KACC,kBAAC,GAAD;MAAY,KAAI;MAAS,eAAe,KAAK,EAAY;MACvD,UAAA,kBAAC,IAAD,CAAgB,CAAA;KACN,CAAA;KAEb,KAAe,KACd,kBAAC,GAAD;MAAY,KAAI;MAAgB,eAAe,KAAK,EAAY;MAC9D,UAAA,kBAAC,IAAD,CAAgB,CAAA;KACN,CAAA;KAEb,KACC,kBAAC,GAAD;MAAY,KAAI;MAAQ,SAAS;MAC/B,UAAA,kBAAC,IAAD,CAAc,CAAA;KACJ,CAAA;IAEX;;EACF;;AAET"}
|
|
1
|
+
{"version":3,"file":"FlowToolbar.js","names":["Button","_Fragment","ButtonWithCompounds","ProjectTitle","FlowZoomControls","useFlowUI","zoomPercent","viewport","ToolButton","IconZoomOut","IconZoomIn","IconFitView","autoFocus","setAutoFocus","IconAutoFocus","label","shortcut","tip","active","FlowToolbar","useFlowContext","useFlowImportExport","useLayoutActions","fileInputRef","useRef","selTotalCount","selection","hasGroupSelected","currentCanvas","n","hasAnchors","doc","canvas","node","handleExportJSON","useCallback","json","exportJSON","blob","url","downloadDataURL","safeFileBaseName","handleExportMarkdown","md","exportMarkdown","handleImportJSON","handleFileChange","file","reader","importJSON","compact","onBack","Fragment","IconBack","onUndo","onRedo","canUndo","IconUndo","canRedo","IconRedo","align","IconAlign","distribute","changeZIndex","IconLayer","onGroup","onGeoGroup","onUngroup","IconGroup","IconGeoGroup","IconUngroup","showGrid","setShowGrid","IconGrid","placementSnap","setPlacementSnap","IconMagnet","showMiniMap","setShowMiniMap","IconMiniMap","showAnchors","setShowAnchors","IconAnchorVisible","presentation","setPresentation","IconPresent","showPalette","setShowPalette","IconShapes","showInspector","setShowInspector","IconInspector","showOutline","setShowOutline","IconOutline","showJson","setShowJson","IconJson","showAI","setShowAI","IconAI","IconImport","IconExportJson","IconExportMarkdown","onExportPNG","IconExportPng","onExportPDF","IconExportPdf","onPublish","IconPublish"],"sources":["../../../../../src/components/pro/Flow/panels/FlowToolbar.tsx"],"sourcesContent":["import React, { useRef, useCallback } from 'react';\nimport Button from '../../../Button';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { useFlowContext } from '../context/FlowContext';\nimport ProjectTitle from './ProjectTitle';\nimport { useFlowImportExport, downloadDataURL, safeFileBaseName } from '../hooks/useFlowImportExport';\nimport { useLayoutActions } from '../hooks/useLayoutActions';\n\n\nimport {\n IconBack,\n IconUndo,\n IconRedo,\n IconGroup,\n IconGeoGroup,\n IconUngroup,\n IconAlign,\n IconZoomIn,\n IconZoomOut,\n IconFitView,\n IconAutoFocus,\n IconShapes,\n IconInspector,\n IconOutline,\n IconJson,\n IconAI,\n IconGrid,\n IconMagnet,\n IconMiniMap,\n IconImport,\n IconExportJson,\n IconExportPng,\n IconExportPdf,\n IconExportMarkdown,\n IconLayer,\n IconPublish,\n IconAnchorVisible,\n IconPresent,\n} from './toolbarIcons';\n\n/** Compact zoom / view controls floated over the bottom-left of the canvas. */\nexport function FlowZoomControls() {\n const { viewport, setViewport, autoFocus, setAutoFocus } = useFlowUI();\n const zoomPercent = Math.round(viewport.zoom * 100);\n\n const handleZoomIn = () => {\n setViewport({ ...viewport, zoom: Math.min(4, viewport.zoom * 1.2) });\n };\n const handleZoomOut = () => {\n setViewport({ ...viewport, zoom: Math.max(0.1, viewport.zoom / 1.2) });\n };\n const handleFitView = () => {\n setViewport({ x: 0, y: 0, zoom: 1 });\n };\n\n return (\n <div className=\"flow-zoom-controls\">\n <ToolButton tip=\"缩小\" onClick={handleZoomOut}>\n <IconZoomOut />\n </ToolButton>\n <span className=\"flow-zoom-info\">{zoomPercent}%</span>\n <ToolButton tip=\"放大\" onClick={handleZoomIn}>\n <IconZoomIn />\n </ToolButton>\n <ToolButton tip=\"适应视图\" onClick={handleFitView}>\n <IconFitView />\n </ToolButton>\n <ToolButton\n tip={autoFocus ? '关闭 Auto Focus' : '开启 Auto Focus'}\n active={autoFocus}\n onClick={() => setAutoFocus(!autoFocus)}\n >\n <IconAutoFocus />\n </ToolButton>\n </div>\n );\n}\n\n\n/** A toolbar button with an accessible, hover-revealed tooltip below it. */\ninterface ToolButtonProps {\n tip: string;\n shortcut?: string;\n onClick: () => void;\n active?: boolean;\n disabled?: boolean;\n children: React.ReactNode;\n}\n\nfunction ToolButton({ tip, shortcut, onClick, active, disabled, children }: ToolButtonProps) {\n const label = shortcut ? `${tip} (${shortcut})` : tip;\n return (\n <span className=\"flow-tip\">\n <Button\n size=\"xs\"\n variant={active ? 'primary' : 'ghost'}\n onClick={onClick}\n disabled={disabled}\n square\n >\n <span aria-label={label} style={{ display: 'inline-flex' }}>{children}</span>\n </Button>\n <span className=\"flow-tip-label\" role=\"tooltip\">{label}</span>\n </span>\n );\n}\n\nexport interface FlowToolbarProps {\n onBack?: () => void;\n onUndo?: () => void;\n onRedo?: () => void;\n canUndo?: boolean;\n canRedo?: boolean;\n onGroup?: () => void;\n onGeoGroup?: () => void;\n onUngroup?: () => void;\n onExportPNG?: () => void | Promise<void>;\n /** Export anchors as a PDF slideshow from the built-in toolbar. */\n onExportPDF?: () => void | Promise<void>;\n onPublish?: () => void;\n /** Small-screen (container-width) layout: the title gets its own row and\n * button groups wrap below instead of sliding under the absolute title. */\n compact?: boolean;\n}\n\nexport default function FlowToolbar({ onBack, onUndo, onRedo, canUndo, canRedo, onGroup, onGeoGroup, onUngroup, onExportPNG, onExportPDF, onPublish, compact }: FlowToolbarProps) {\n const {\n showGrid, setShowGrid,\n showPalette, setShowPalette,\n showInspector, setShowInspector,\n showOutline, setShowOutline,\n showJson, setShowJson,\n showAI, setShowAI,\n showMiniMap, setShowMiniMap,\n showAnchors, setShowAnchors,\n presentation, setPresentation,\n placementSnap, setPlacementSnap,\n } = useFlowUI();\n const { doc, selection, currentCanvas, setDoc, currentCanvasId } = useFlowContext();\n const { exportJSON, importJSON, exportMarkdown } = useFlowImportExport();\n const { align, distribute, changeZIndex } = useLayoutActions();\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const selTotalCount = selection.nodeIds.size + selection.lineIds.size;\n const hasGroupSelected = selection.nodeIds.size > 0 && currentCanvas.nodes.some(\n n => selection.nodeIds.has(n.id) && (n.type === 'flowGroup' || n.type === 'geometryGroup' || n.data.isGroup),\n );\n const hasAnchors = Object.values(doc.canvases).some(canvas =>\n canvas.nodes.some(node => node.type === 'animAnchor'),\n );\n\n\n const handleExportJSON = useCallback(() => {\n const json = exportJSON();\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n downloadDataURL(url, `${safeFileBaseName(doc.title)}.json`);\n URL.revokeObjectURL(url);\n }, [exportJSON, doc.title]);\n\n const handleExportMarkdown = useCallback(() => {\n const md = exportMarkdown();\n const blob = new Blob([md], { type: 'text/markdown' });\n const url = URL.createObjectURL(blob);\n downloadDataURL(url, `${safeFileBaseName(doc.title)}.md`);\n URL.revokeObjectURL(url);\n }, [exportMarkdown, doc.title]);\n\n const handleImportJSON = useCallback(() => {\n fileInputRef.current?.click();\n }, []);\n\n const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n const reader = new FileReader();\n reader.onload = () => {\n if (typeof reader.result === 'string') importJSON(reader.result);\n };\n reader.readAsText(file);\n e.target.value = '';\n }, [importJSON]);\n\n return (\n <div className={`flow-toolbar${compact ? ' flow-toolbar--compact' : ''}`}>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".json\"\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n\n {/* Editable project title, anchored to the toolbar's left edge. Hidden\n in compact mode: the host app's header already shows the name, and\n the narrow toolbar needs the row for buttons. */}\n {!compact && <ProjectTitle />}\n\n {onBack && (\n <>\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"返回列表\" onClick={onBack}>\n <IconBack />\n </ToolButton>\n </div>\n <div className=\"flow-toolbar-divider\" />\n </>\n )}\n\n {/* 历史:撤销 / 重做 */}\n {(onUndo || onRedo) && (\n <div className=\"flow-toolbar-group\">\n {onUndo && (\n <ToolButton tip=\"撤销\" shortcut=\"Ctrl+Z\" onClick={onUndo} disabled={!canUndo}>\n <IconUndo />\n </ToolButton>\n )}\n {onRedo && (\n <ToolButton tip=\"重做\" shortcut=\"Ctrl+Shift+Z\" onClick={onRedo} disabled={!canRedo}>\n <IconRedo />\n </ToolButton>\n )}\n </div>\n )}\n\n {/* 排列:对齐 / 平分 */}\n {selection.nodeIds.size >= 2 && (\n <>\n <div className=\"flow-toolbar-divider\" />\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"居左\" onClick={() => align('left')}><IconAlign kind=\"left\" /></ToolButton>\n <ToolButton tip=\"水平居中\" onClick={() => align('center-h')}><IconAlign kind=\"center-h\" /></ToolButton>\n <ToolButton tip=\"居右\" onClick={() => align('right')}><IconAlign kind=\"right\" /></ToolButton>\n <ToolButton tip=\"居上\" onClick={() => align('top')}><IconAlign kind=\"top\" /></ToolButton>\n <ToolButton tip=\"垂直居中\" onClick={() => align('center-v')}><IconAlign kind=\"center-v\" /></ToolButton>\n <ToolButton tip=\"居下\" onClick={() => align('bottom')}><IconAlign kind=\"bottom\" /></ToolButton>\n <ToolButton tip=\"水平平分\" onClick={() => distribute('horizontal')} disabled={selection.nodeIds.size < 3}>\n <IconAlign kind=\"distribute-h\" />\n </ToolButton>\n <ToolButton tip=\"垂直平分\" onClick={() => distribute('vertical')} disabled={selection.nodeIds.size < 3}>\n <IconAlign kind=\"distribute-v\" />\n </ToolButton>\n </div>\n </>\n )}\n\n {/* 图层:置顶 / 上移 / 下移 / 置底 */}\n {selTotalCount >= 1 && (\n <>\n <div className=\"flow-toolbar-divider\" />\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"置于顶层\" onClick={() => changeZIndex('front')}><IconLayer kind=\"front\" /></ToolButton>\n <ToolButton tip=\"上移一层\" onClick={() => changeZIndex('up')}><IconLayer kind=\"up\" /></ToolButton>\n <ToolButton tip=\"下移一层\" onClick={() => changeZIndex('down')}><IconLayer kind=\"down\" /></ToolButton>\n <ToolButton tip=\"置于底层\" onClick={() => changeZIndex('back')}><IconLayer kind=\"back\" /></ToolButton>\n </div>\n </>\n )}\n\n {/* 组合:成组 / 几何分组 / 取消成组 */}\n {(onGroup || onGeoGroup || onUngroup) && (\n <>\n <div className=\"flow-toolbar-divider\" />\n <div className=\"flow-toolbar-group\">\n {onGroup && (\n <ToolButton tip=\"成组\" shortcut=\"⌘G\" onClick={onGroup} disabled={selTotalCount < 2}>\n <IconGroup />\n </ToolButton>\n )}\n {onGeoGroup && (\n <ToolButton tip=\"几何分组\" shortcut=\"⌘⌥G\" onClick={onGeoGroup} disabled={selTotalCount < 2}>\n <IconGeoGroup />\n </ToolButton>\n )}\n {onUngroup && (\n <ToolButton tip=\"取消成组\" shortcut=\"⌘⇧G\" onClick={onUngroup} disabled={!hasGroupSelected}>\n <IconUngroup />\n </ToolButton>\n )}\n </div>\n </>\n )}\n\n <div className=\"flow-toolbar-divider\" />\n\n {/* 视图:网格 / 缩略图 / Anchor / 动画预览 */}\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"网格\" active={showGrid} onClick={() => setShowGrid(!showGrid)}>\n <IconGrid />\n </ToolButton>\n <ToolButton\n tip={placementSnap ? '放置吸附网格:开(盖章自动贴近网格)' : '放置吸附网格:关(自由放置)'}\n active={placementSnap}\n onClick={() => setPlacementSnap(!placementSnap)}\n >\n <IconMagnet />\n </ToolButton>\n <ToolButton tip=\"缩略图\" active={showMiniMap} onClick={() => setShowMiniMap(!showMiniMap)}>\n <IconMiniMap />\n </ToolButton>\n <ToolButton\n tip={showAnchors ? '隐藏所有 Anchor 对象' : '显示所有 Anchor 对象'}\n active={showAnchors}\n disabled={!hasAnchors}\n onClick={() => {\n if (hasAnchors) setShowAnchors(!showAnchors);\n }}\n >\n <IconAnchorVisible visible={showAnchors} />\n </ToolButton>\n <ToolButton\n tip=\"动画预览\"\n active={presentation !== null}\n onClick={() => setPresentation(presentation ? null : { current: 0, showAnchor: false })}\n >\n <IconPresent />\n </ToolButton>\n </div>\n\n <div className=\"flow-toolbar-divider\" />\n\n {/* 面板:形状 / 属性 / 大纲 / JSON */}\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"形状面板\" active={showPalette} onClick={() => setShowPalette(!showPalette)}>\n <IconShapes />\n </ToolButton>\n <ToolButton tip=\"属性面板\" active={showInspector} onClick={() => setShowInspector(!showInspector)}>\n <IconInspector />\n </ToolButton>\n <ToolButton tip=\"大纲\" active={showOutline} onClick={() => setShowOutline(!showOutline)}>\n <IconOutline />\n </ToolButton>\n <ToolButton tip=\"JSON\" active={showJson} onClick={() => setShowJson(!showJson)}>\n <IconJson />\n </ToolButton>\n <ToolButton tip=\"AI 助手\" active={showAI} onClick={() => setShowAI(!showAI)}>\n <IconAI />\n </ToolButton>\n </div>\n\n <div className=\"flow-toolbar-divider\" />\n\n {/* 文件:导入 / 导出 / 发布 */}\n <div className=\"flow-toolbar-group\">\n <ToolButton tip=\"导入 JSON\" onClick={handleImportJSON}>\n <IconImport />\n </ToolButton>\n <ToolButton tip=\"导出 JSON\" onClick={handleExportJSON}>\n <IconExportJson />\n </ToolButton>\n <ToolButton tip=\"导出 Markdown\" onClick={handleExportMarkdown}>\n <IconExportMarkdown />\n </ToolButton>\n {onExportPNG && (\n <ToolButton tip=\"导出 PNG\" onClick={() => void onExportPNG()}>\n <IconExportPng />\n </ToolButton>\n )}\n {onExportPDF && hasAnchors && (\n <ToolButton tip=\"导出 PDF(按锦点顺序)\" onClick={() => void onExportPDF()}>\n <IconExportPdf />\n </ToolButton>\n )}\n {onPublish && (\n <ToolButton tip=\"发布与共享\" onClick={onPublish}>\n <IconPublish />\n </ToolButton>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|