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.
Files changed (388) hide show
  1. package/dist/.release-verified.json +3 -2
  2. package/dist/components/Accordion/index.js.map +1 -1
  3. package/dist/components/Avatar/index.js.map +1 -1
  4. package/dist/components/Badge/index.js.map +1 -1
  5. package/dist/components/Button/index.js.map +1 -1
  6. package/dist/components/ButtonMenu/index.js.map +1 -1
  7. package/dist/components/Card/Metric2.js.map +1 -1
  8. package/dist/components/Card/Ticket2.js.map +1 -1
  9. package/dist/components/Card/index.js.map +1 -1
  10. package/dist/components/Chart/Chart.js.map +1 -1
  11. package/dist/components/Checkbox/index.js.map +1 -1
  12. package/dist/components/ChoicePicker/index.js.map +1 -1
  13. package/dist/components/Column/index.js.map +1 -1
  14. package/dist/components/ConfirmDialog/index.js.map +1 -1
  15. package/dist/components/DateTimeInput/index.js.map +1 -1
  16. package/dist/components/Demo/index.js.map +1 -1
  17. package/dist/components/Demo/source.js.map +1 -1
  18. package/dist/components/Divider/index.js.map +1 -1
  19. package/dist/components/EmptyState/index.js.map +1 -1
  20. package/dist/components/Field/index.js.map +1 -1
  21. package/dist/components/FileUploader/DropZone.js.map +1 -1
  22. package/dist/components/FileUploader/FileItem.js.map +1 -1
  23. package/dist/components/FileUploader/FileUploader.js.map +1 -1
  24. package/dist/components/FileUploader/UploadQueue.js.map +1 -1
  25. package/dist/components/GroupButton/index.js.map +1 -1
  26. package/dist/components/GroupedTable/index.js.map +1 -1
  27. package/dist/components/Icon/index.js.map +1 -1
  28. package/dist/components/Image/index.js.map +1 -1
  29. package/dist/components/Input/index.js.map +1 -1
  30. package/dist/components/Label/index.js.map +1 -1
  31. package/dist/components/Layout/index.js.map +1 -1
  32. package/dist/components/LayoutSuite/DashboardSuite.js.map +1 -1
  33. package/dist/components/LayoutSuite/index.js.map +1 -1
  34. package/dist/components/List/index.js.map +1 -1
  35. package/dist/components/Markdown/Markdown.js.map +1 -1
  36. package/dist/components/Markdown/codeThemes.js.map +1 -1
  37. package/dist/components/Markdown/markdownComponents.js.map +1 -1
  38. package/dist/components/Markdown/parseCodeBlockMeta.js.map +1 -1
  39. package/dist/components/Markdown/useMarkdownSource.js.map +1 -1
  40. package/dist/components/Markdown/useMarkmapRenderer.js.map +1 -1
  41. package/dist/components/Markdown/useMermaidRenderer.js.map +1 -1
  42. package/dist/components/Modal/focusScope.js.map +1 -1
  43. package/dist/components/Modal/index.js.map +1 -1
  44. package/dist/components/MultipleChoice/index.js.map +1 -1
  45. package/dist/components/NavigationList/index.js.map +1 -1
  46. package/dist/components/Page/Float2.js.map +1 -1
  47. package/dist/components/Page/index.js.map +1 -1
  48. package/dist/components/Page/resize2.js.map +1 -1
  49. package/dist/components/PageHeader/index.js.map +1 -1
  50. package/dist/components/PagePanel/index.js.map +1 -1
  51. package/dist/components/ProtectedRoute/index.js.map +1 -1
  52. package/dist/components/Resizable/ResizeGrip.js.map +1 -1
  53. package/dist/components/Resizable/index.js.map +1 -1
  54. package/dist/components/Resizable/useResize.js.map +1 -1
  55. package/dist/components/Row/index.js.map +1 -1
  56. package/dist/components/Section/index.js.map +1 -1
  57. package/dist/components/Select/index.js.map +1 -1
  58. package/dist/components/SidebarToggleButton/index.js.map +1 -1
  59. package/dist/components/Skeleton/index.js.map +1 -1
  60. package/dist/components/Slider/index.js.map +1 -1
  61. package/dist/components/Switch/index.js.map +1 -1
  62. package/dist/components/Tab/index.js.map +1 -1
  63. package/dist/components/Table/index.js.map +1 -1
  64. package/dist/components/Tabs/index.js.map +1 -1
  65. package/dist/components/Tabs/tabNavigation.js.map +1 -1
  66. package/dist/components/Text/index.js.map +1 -1
  67. package/dist/components/Textarea/index.js.map +1 -1
  68. package/dist/components/Tooltip/index.js.map +1 -1
  69. package/dist/components/Tree/Tree.js.map +1 -1
  70. package/dist/components/ai/AgentChat/index.js.map +1 -1
  71. package/dist/components/ai/AgentRunCard/index.js.map +1 -1
  72. package/dist/components/ai/AgentScreen/index.js.map +1 -1
  73. package/dist/components/ai/ApprovalCard/index.js.map +1 -1
  74. package/dist/components/ai/CodeView/index.js.map +1 -1
  75. package/dist/components/ai/CommandSearch/index.js.map +1 -1
  76. package/dist/components/ai/ContextCards/index.js.map +1 -1
  77. package/dist/components/ai/DiffTable/index.js.map +1 -1
  78. package/dist/components/ai/FilterTable/index.js.map +1 -1
  79. package/dist/components/ai/FineTuneCard/index.js.map +1 -1
  80. package/dist/components/ai/InsightCards/index.js.map +1 -1
  81. package/dist/components/ai/IssueCard/index.js.map +1 -1
  82. package/dist/components/ai/LoadingState/index.js.map +1 -1
  83. package/dist/components/ai/PromptBar/index.js.map +1 -1
  84. package/dist/components/ai/RecommendationCard/index.js.map +1 -1
  85. package/dist/components/ai/RecordsTable/index.js.map +1 -1
  86. package/dist/components/ai/SelectionActions/index.js.map +1 -1
  87. package/dist/components/ai/StateFlow/index.js.map +1 -1
  88. package/dist/components/ai/StreamingText/index.js.map +1 -1
  89. package/dist/components/ai/TaskRows/index.js.map +1 -1
  90. package/dist/components/ai/Thinking/index.js.map +1 -1
  91. package/dist/components/ai/ToolChips/index.js.map +1 -1
  92. package/dist/components/ai/shared.js.map +1 -1
  93. package/dist/components/pro/ArticleContextMenu/index.js.map +1 -1
  94. package/dist/components/pro/ArticleControl/ArticleControl2.js.map +1 -1
  95. package/dist/components/pro/ArticleControl/buildHeadingTree.js.map +1 -1
  96. package/dist/components/pro/ArticleControl/useArticleToc.js.map +1 -1
  97. package/dist/components/pro/Calendar/Calendar.js +165 -160
  98. package/dist/components/pro/Calendar/Calendar.js.map +1 -1
  99. package/dist/components/pro/Calendar/hooks/useCalendarDrag.js.map +1 -1
  100. package/dist/components/pro/Calendar/hooks/useCalendarState.js +31 -31
  101. package/dist/components/pro/Calendar/hooks/useCalendarState.js.map +1 -1
  102. package/dist/components/pro/Calendar/utils.js.map +1 -1
  103. package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
  104. package/dist/components/pro/CodeEditor/editors/MarkdownEditor.js.map +1 -1
  105. package/dist/components/pro/CodeEditor/editors/markdownExtensions.js.map +1 -1
  106. package/dist/components/pro/CodeEditor/extensions/contextMenu.js.map +1 -1
  107. package/dist/components/pro/CodeEditor/extensions/index.js.map +1 -1
  108. package/dist/components/pro/CodeEditor/langs/index.js.map +1 -1
  109. package/dist/components/pro/CodeEditor/langs/javascript.js.map +1 -1
  110. package/dist/components/pro/CodeEditor/langs/python.js.map +1 -1
  111. package/dist/components/pro/CodeEditor/langs/snippets.js.map +1 -1
  112. package/dist/components/pro/CodeEditor/panels/FootnotePanel.js.map +1 -1
  113. package/dist/components/pro/CodeEditor/panels/HistoryPanel.js +65 -59
  114. package/dist/components/pro/CodeEditor/panels/HistoryPanel.js.map +1 -1
  115. package/dist/components/pro/CodeEditor/panels/OutlinePanel.js.map +1 -1
  116. package/dist/components/pro/CodeEditor/panels/TableOfContentsPanel.js.map +1 -1
  117. package/dist/components/pro/CodeEditor/panels/VariablePanel.js.map +1 -1
  118. package/dist/components/pro/CodeEditor/themes.js.map +1 -1
  119. package/dist/components/pro/CodeEditor/utils.js.map +1 -1
  120. package/dist/components/pro/DataTable/DataTable.js.map +1 -1
  121. package/dist/components/pro/DataTable/Filters.js.map +1 -1
  122. package/dist/components/pro/DataTable/PivotPanel.js.map +1 -1
  123. package/dist/components/pro/DataTable/PivotView.js.map +1 -1
  124. package/dist/components/pro/DataTable/components/BulkActions.js.map +1 -1
  125. package/dist/components/pro/DataTable/components/ColumnSelector.js.map +1 -1
  126. package/dist/components/pro/DataTable/components/FilterBar.js.map +1 -1
  127. package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
  128. package/dist/components/pro/DataTable/components/TableHeader.js.map +1 -1
  129. package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
  130. package/dist/components/pro/DataTable/components/TableToolbar.js.map +1 -1
  131. package/dist/components/pro/DataTable/extension.js.map +1 -1
  132. package/dist/components/pro/DataTable/pivotEngine.js.map +1 -1
  133. package/dist/components/pro/DataTable/pivotExtension.js.map +1 -1
  134. package/dist/components/pro/DataTable/rowDetailExtension.js.map +1 -1
  135. package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
  136. package/dist/components/pro/DataTable/treeDataUtils.js.map +1 -1
  137. package/dist/components/pro/DataTable/useColumnDragReorder.js.map +1 -1
  138. package/dist/components/pro/DataTable/useDataTableModel.js +119 -104
  139. package/dist/components/pro/DataTable/useDataTableModel.js.map +1 -1
  140. package/dist/components/pro/DataTable/utils.js.map +1 -1
  141. package/dist/components/pro/FileExplorer/Breadcrumb.js.map +1 -1
  142. package/dist/components/pro/FileExplorer/CreateDialog.js.map +1 -1
  143. package/dist/components/pro/FileExplorer/FileExplorer.js.map +1 -1
  144. package/dist/components/pro/FileExplorer/FileIcon.js.map +1 -1
  145. package/dist/components/pro/FileExplorer/GridView.js.map +1 -1
  146. package/dist/components/pro/FileExplorer/ListView.js.map +1 -1
  147. package/dist/components/pro/FileExplorer/Toolbar.js.map +1 -1
  148. package/dist/components/pro/Flow/Flow.js.map +1 -1
  149. package/dist/components/pro/Flow/FlowCanvas.js.map +1 -1
  150. package/dist/components/pro/Flow/archify/build.js.map +1 -1
  151. package/dist/components/pro/Flow/archify/convert.js.map +1 -1
  152. package/dist/components/pro/Flow/archify/palette.js.map +1 -1
  153. package/dist/components/pro/Flow/archify/presets.js.map +1 -1
  154. package/dist/components/pro/Flow/archify/spec.js.map +1 -1
  155. package/dist/components/pro/Flow/canvas/AlignmentGuides.js.map +1 -1
  156. package/dist/components/pro/Flow/canvas/GridRenderer.js.map +1 -1
  157. package/dist/components/pro/Flow/canvas/MiniMapRenderer.js.map +1 -1
  158. package/dist/components/pro/Flow/canvas/PixiApp.js.map +1 -1
  159. package/dist/components/pro/Flow/canvas/SelectionOverlay.js.map +1 -1
  160. package/dist/components/pro/Flow/canvas/ViewportContainer.js.map +1 -1
  161. package/dist/components/pro/Flow/constants.js.map +1 -1
  162. package/dist/components/pro/Flow/context/FlowAIContext.js.map +1 -1
  163. package/dist/components/pro/Flow/context/FlowContext.js.map +1 -1
  164. package/dist/components/pro/Flow/context/FlowUIContext.js.map +1 -1
  165. package/dist/components/pro/Flow/edges/EdgeRenderer.js.map +1 -1
  166. package/dist/components/pro/Flow/edges/edgeMarkers.js.map +1 -1
  167. package/dist/components/pro/Flow/edges/edgePaths.js.map +1 -1
  168. package/dist/components/pro/Flow/hooks/useAlignmentGuides.js.map +1 -1
  169. package/dist/components/pro/Flow/hooks/useClipboard.js.map +1 -1
  170. package/dist/components/pro/Flow/hooks/useCompactMode.js.map +1 -1
  171. package/dist/components/pro/Flow/hooks/useDeleteSelection.js.map +1 -1
  172. package/dist/components/pro/Flow/hooks/useDraggablePanel.js.map +1 -1
  173. package/dist/components/pro/Flow/hooks/useEdgeMutations.js.map +1 -1
  174. package/dist/components/pro/Flow/hooks/useFlowImportExport.js.map +1 -1
  175. package/dist/components/pro/Flow/hooks/useKeyboardShortcuts.js.map +1 -1
  176. package/dist/components/pro/Flow/hooks/useLayoutActions.js.map +1 -1
  177. package/dist/components/pro/Flow/hooks/useLineMutations.js.map +1 -1
  178. package/dist/components/pro/Flow/hooks/useMindMap.js.map +1 -1
  179. package/dist/components/pro/Flow/hooks/useNodeMutations.js.map +1 -1
  180. package/dist/components/pro/Flow/hooks/usePdfExport.js.map +1 -1
  181. package/dist/components/pro/Flow/hooks/usePixiApp.js.map +1 -1
  182. package/dist/components/pro/Flow/hooks/useResizablePanel.js.map +1 -1
  183. package/dist/components/pro/Flow/hooks/useSelection.js.map +1 -1
  184. package/dist/components/pro/Flow/hooks/useUndoRedo.js.map +1 -1
  185. package/dist/components/pro/Flow/hooks/useViewport.js.map +1 -1
  186. package/dist/components/pro/Flow/lines/FreehandTool.js.map +1 -1
  187. package/dist/components/pro/Flow/lines/GeometricLineTool.js.map +1 -1
  188. package/dist/components/pro/Flow/lines/LineRenderer.js.map +1 -1
  189. package/dist/components/pro/Flow/lines/lineSmoothing.js.map +1 -1
  190. package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
  191. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  192. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  193. package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
  194. package/dist/components/pro/Flow/nodes/NodeHandles.js.map +1 -1
  195. package/dist/components/pro/Flow/nodes/NodeRenderer.js.map +1 -1
  196. package/dist/components/pro/Flow/nodes/NodeText.js.map +1 -1
  197. package/dist/components/pro/Flow/nodes/aiClient.js.map +1 -1
  198. package/dist/components/pro/Flow/nodes/animAnchors.js.map +1 -1
  199. package/dist/components/pro/Flow/nodes/chartGeometryBudget.js.map +1 -1
  200. package/dist/components/pro/Flow/nodes/dataUtils.js.map +1 -1
  201. package/dist/components/pro/Flow/nodes/demandRender.js.map +1 -1
  202. package/dist/components/pro/Flow/nodes/nodeUtils.js.map +1 -1
  203. package/dist/components/pro/Flow/nodes/shapes.js.map +1 -1
  204. package/dist/components/pro/Flow/nodes/svgIconTexture.js.map +1 -1
  205. package/dist/components/pro/Flow/nodes/svgIcons.js.map +1 -1
  206. package/dist/components/pro/Flow/panels/AIPanel.js.map +1 -1
  207. package/dist/components/pro/Flow/panels/Breadcrumb.js.map +1 -1
  208. package/dist/components/pro/Flow/panels/ContextMenu.js.map +1 -1
  209. package/dist/components/pro/Flow/panels/DataInspectorSection.js.map +1 -1
  210. package/dist/components/pro/Flow/panels/ExpandableTextarea.js.map +1 -1
  211. package/dist/components/pro/Flow/panels/FlowPanelGroup.js.map +1 -1
  212. package/dist/components/pro/Flow/panels/FlowToolbar.js.map +1 -1
  213. package/dist/components/pro/Flow/panels/InspectorPanel.js.map +1 -1
  214. package/dist/components/pro/Flow/panels/OutlinePanel.js.map +1 -1
  215. package/dist/components/pro/Flow/panels/PresentationMode.js.map +1 -1
  216. package/dist/components/pro/Flow/panels/ProjectTitle.js.map +1 -1
  217. package/dist/components/pro/Flow/panels/ShapePalette.js.map +1 -1
  218. package/dist/components/pro/Flow/panels/toolbarIcons.js.map +1 -1
  219. package/dist/components/pro/Flow/types.js.map +1 -1
  220. package/dist/components/pro/Flow/utils/dashedLine.js.map +1 -1
  221. package/dist/components/pro/Flow/utils/gradient.js.map +1 -1
  222. package/dist/components/pro/Flow/utils/pdfExport.js.map +1 -1
  223. package/dist/components/pro/Flow/utils/themeColor.js.map +1 -1
  224. package/dist/components/pro/Gantt/Gantt.js.map +1 -1
  225. package/dist/components/pro/Gantt/hooks/useGanttDrag.js.map +1 -1
  226. package/dist/components/pro/Gantt/hooks/useGanttState.js +79 -71
  227. package/dist/components/pro/Gantt/hooks/useGanttState.js.map +1 -1
  228. package/dist/components/pro/Gantt/utils.js.map +1 -1
  229. package/dist/components/pro/Kanban/Kanban.js.map +1 -1
  230. package/dist/components/pro/Kanban/Swimlanes.js.map +1 -1
  231. package/dist/components/pro/Kanban/useKanbanDrag.js.map +1 -1
  232. package/dist/components/pro/Kanban/utils.js.map +1 -1
  233. package/dist/components/pro/RichTextEditor/AIRewrite.d.ts +1 -0
  234. package/dist/components/pro/RichTextEditor/AIRewrite.js +109 -88
  235. package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
  236. package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
  237. package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
  238. package/dist/components/pro/RichTextEditor/CommentDialog.js.map +1 -1
  239. package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
  240. package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
  241. package/dist/components/pro/RichTextEditor/ContextMenu.js.map +1 -1
  242. package/dist/components/pro/RichTextEditor/RichTextEditor.js +133 -132
  243. package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
  244. package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
  245. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
  246. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
  247. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
  248. package/dist/components/pro/RichTextEditor/Toolbar/SelectDropdown.js.map +1 -1
  249. package/dist/components/pro/RichTextEditor/Toolbar/TableOpsMenu.js.map +1 -1
  250. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
  251. package/dist/components/pro/RichTextEditor/Toolbar/ToolbarButton.js.map +1 -1
  252. package/dist/components/pro/RichTextEditor/Toolbar/useAnchoredDropdown.js.map +1 -1
  253. package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
  254. package/dist/components/pro/RichTextEditor/extensions/CommentMark.js.map +1 -1
  255. package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
  256. package/dist/components/pro/RichTextEditor/extensions/FontSize.js.map +1 -1
  257. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
  258. package/dist/components/pro/RichTextEditor/extensions/ResizableImage.js.map +1 -1
  259. package/dist/components/pro/RichTextEditor/extensions/legacyMermaid.js.map +1 -1
  260. package/dist/components/pro/RichTextEditor/types.d.ts +2 -0
  261. package/dist/components/pro/RichTextEditor/types.js.map +1 -1
  262. package/dist/components/pro/Sprite/Molly/animations.d.ts +6 -0
  263. package/dist/components/pro/Sprite/Molly/animations.js +52 -0
  264. package/dist/components/pro/Sprite/Molly/animations.js.map +1 -0
  265. package/dist/components/pro/Sprite/Molly/events.d.ts +2 -0
  266. package/dist/components/pro/Sprite/Molly/events.js +46 -0
  267. package/dist/components/pro/Sprite/Molly/events.js.map +1 -0
  268. package/dist/components/pro/Sprite/Molly/index.d.ts +1 -0
  269. package/dist/components/pro/Sprite/Molly/index.js +12 -0
  270. package/dist/components/pro/Sprite/Molly/index.js.map +1 -0
  271. package/dist/components/pro/Sprite/Molly/legFlexion.d.ts +3 -0
  272. package/dist/components/pro/Sprite/Molly/legFlexion.js +48 -0
  273. package/dist/components/pro/Sprite/Molly/legFlexion.js.map +1 -0
  274. package/dist/components/pro/Sprite/Molly/locomotion.d.ts +4 -0
  275. package/dist/components/pro/Sprite/Molly/locomotion.js +51 -0
  276. package/dist/components/pro/Sprite/Molly/locomotion.js.map +1 -0
  277. package/dist/components/pro/Sprite/Molly/model.d.ts +23 -0
  278. package/dist/components/pro/Sprite/Molly/model.js +614 -0
  279. package/dist/components/pro/Sprite/Molly/model.js.map +1 -0
  280. package/dist/components/pro/Sprite/Molly/rig.d.ts +25 -0
  281. package/dist/components/pro/Sprite/Molly/rig.js +102 -0
  282. package/dist/components/pro/Sprite/Molly/rig.js.map +1 -0
  283. package/dist/components/pro/Sprite/Ruby/animations.d.ts +6 -0
  284. package/dist/components/pro/Sprite/Ruby/animations.js +58 -0
  285. package/dist/components/pro/Sprite/Ruby/animations.js.map +1 -0
  286. package/dist/components/pro/Sprite/Ruby/events.d.ts +2 -0
  287. package/dist/components/pro/Sprite/Ruby/events.js +46 -0
  288. package/dist/components/pro/Sprite/Ruby/events.js.map +1 -0
  289. package/dist/components/pro/Sprite/Ruby/index.d.ts +1 -0
  290. package/dist/components/pro/Sprite/Ruby/index.js +12 -0
  291. package/dist/components/pro/Sprite/Ruby/index.js.map +1 -0
  292. package/dist/components/pro/Sprite/Ruby/locomotion.d.ts +4 -0
  293. package/dist/components/pro/Sprite/Ruby/locomotion.js +41 -0
  294. package/dist/components/pro/Sprite/Ruby/locomotion.js.map +1 -0
  295. package/dist/components/pro/Sprite/Ruby/model.d.ts +23 -0
  296. package/dist/components/pro/Sprite/Ruby/model.js +605 -0
  297. package/dist/components/pro/Sprite/Ruby/model.js.map +1 -0
  298. package/dist/components/pro/Sprite/Ruby/rig.d.ts +26 -0
  299. package/dist/components/pro/Sprite/Ruby/rig.js +112 -0
  300. package/dist/components/pro/Sprite/Ruby/rig.js.map +1 -0
  301. package/dist/components/pro/Sprite/Sprite.d.ts +23 -0
  302. package/dist/components/pro/Sprite/Sprite2.js +224 -0
  303. package/dist/components/pro/Sprite/Sprite2.js.map +1 -0
  304. package/dist/components/pro/Sprite/actions.d.ts +3 -0
  305. package/dist/components/pro/Sprite/actions.js +16 -0
  306. package/dist/components/pro/Sprite/actions.js.map +1 -0
  307. package/dist/components/pro/Sprite/createSpriteScene.d.ts +4 -0
  308. package/dist/components/pro/Sprite/createSpriteScene.js +14 -0
  309. package/dist/components/pro/Sprite/createSpriteScene.js.map +1 -0
  310. package/dist/components/pro/Sprite/index.d.ts +4 -0
  311. package/dist/components/pro/Sprite/shared/animation.d.ts +33 -0
  312. package/dist/components/pro/Sprite/shared/animation.js +39 -0
  313. package/dist/components/pro/Sprite/shared/animation.js.map +1 -0
  314. package/dist/components/pro/Sprite/shared/createSpriteStage.d.ts +14 -0
  315. package/dist/components/pro/Sprite/shared/createSpriteStage.js +127 -0
  316. package/dist/components/pro/Sprite/shared/createSpriteStage.js.map +1 -0
  317. package/dist/components/pro/Sprite/shared/events.d.ts +5 -0
  318. package/dist/components/pro/Sprite/shared/events.js +21 -0
  319. package/dist/components/pro/Sprite/shared/events.js.map +1 -0
  320. package/dist/components/pro/Sprite/shared/face.d.ts +15 -0
  321. package/dist/components/pro/Sprite/shared/face.js +33 -0
  322. package/dist/components/pro/Sprite/shared/face.js.map +1 -0
  323. package/dist/components/pro/Sprite/shared/faceSurface.d.ts +6 -0
  324. package/dist/components/pro/Sprite/shared/faceSurface.js +66 -0
  325. package/dist/components/pro/Sprite/shared/faceSurface.js.map +1 -0
  326. package/dist/components/pro/Sprite/shared/gait.d.ts +5 -0
  327. package/dist/components/pro/Sprite/shared/gait.js +19 -0
  328. package/dist/components/pro/Sprite/shared/gait.js.map +1 -0
  329. package/dist/components/pro/Sprite/shared/geometry.d.ts +8 -0
  330. package/dist/components/pro/Sprite/shared/geometry.js +59 -0
  331. package/dist/components/pro/Sprite/shared/geometry.js.map +1 -0
  332. package/dist/components/pro/Sprite/shared/magicEffect.d.ts +27 -0
  333. package/dist/components/pro/Sprite/shared/magicEffect.js +61 -0
  334. package/dist/components/pro/Sprite/shared/magicEffect.js.map +1 -0
  335. package/dist/components/pro/Sprite/shared/playback.d.ts +8 -0
  336. package/dist/components/pro/Sprite/shared/playback.js +74 -0
  337. package/dist/components/pro/Sprite/shared/playback.js.map +1 -0
  338. package/dist/components/pro/Sprite/shared/rig.d.ts +6 -0
  339. package/dist/components/pro/Sprite/shared/rig.js +48 -0
  340. package/dist/components/pro/Sprite/shared/rig.js.map +1 -0
  341. package/dist/components/pro/Sprite/shared/scene.d.ts +9 -0
  342. package/dist/components/pro/Sprite/shared/scene.js +21 -0
  343. package/dist/components/pro/Sprite/shared/scene.js.map +1 -0
  344. package/dist/components/pro/Sprite/shared/sculptor.d.ts +14 -0
  345. package/dist/components/pro/Sprite/shared/sculptor.js +78 -0
  346. package/dist/components/pro/Sprite/shared/sculptor.js.map +1 -0
  347. package/dist/components/pro/Sprite/shared/speechBubble.d.ts +15 -0
  348. package/dist/components/pro/Sprite/shared/speechBubble.js +129 -0
  349. package/dist/components/pro/Sprite/shared/speechBubble.js.map +1 -0
  350. package/dist/components/pro/Sprite/types.d.ts +40 -0
  351. package/dist/contexts/AppContext.js.map +1 -1
  352. package/dist/contexts/authentication.js.map +1 -1
  353. package/dist/data-table.js +3 -3
  354. package/dist/data-table.js.map +1 -1
  355. package/dist/dishui.css +1 -1
  356. package/dist/hooks/useClickOutside.js.map +1 -1
  357. package/dist/hooks/useContainerElement.js.map +1 -1
  358. package/dist/hooks/useControllableState.js.map +1 -1
  359. package/dist/hooks/useCopyToClipboard.js.map +1 -1
  360. package/dist/hooks/useDebounce.js.map +1 -1
  361. package/dist/hooks/useDraggable.js.map +1 -1
  362. package/dist/hooks/useTableColumns.js.map +1 -1
  363. package/dist/hooks/useTableData.js.map +1 -1
  364. package/dist/index-nostyled.d.ts +2 -0
  365. package/dist/index.d.ts +2 -0
  366. package/dist/index.js +116 -115
  367. package/dist/layouts/MainLayout.js.map +1 -1
  368. package/dist/layouts/Navbar.js.map +1 -1
  369. package/dist/layouts/Sidebar.js.map +1 -1
  370. package/dist/layouts/headbar/Headbar.js.map +1 -1
  371. package/dist/layouts/headbar/HeadbarLangSwitcher.js.map +1 -1
  372. package/dist/layouts/headbar/HeadbarSearch.js.map +1 -1
  373. package/dist/layouts/headbar/HeadbarThemeSwitcher.js.map +1 -1
  374. package/dist/layouts/headbar/HeadbarTitle.js.map +1 -1
  375. package/dist/sprite.js +2 -0
  376. package/dist/styles/themeStyles.js.map +1 -1
  377. package/dist/utils/cn.js.map +1 -1
  378. package/dist/utils/flexLayout.js.map +1 -1
  379. package/dist/utils/i18n.js.map +1 -1
  380. package/dist/utils/menu.js.map +1 -1
  381. package/dist/utils/rehype-code-meta.js.map +1 -1
  382. package/dist/utils/remark-code-meta.js.map +1 -1
  383. package/dist/utils/routerBuilder.js.map +1 -1
  384. package/dist/utils/safeStorage.js.map +1 -1
  385. package/dist/utils/selection.js +29 -20
  386. package/dist/utils/selection.js.map +1 -1
  387. package/dist/utils/themes.js.map +1 -1
  388. package/package.json +15 -11
@@ -1 +1 @@
1
- {"version":3,"file":"LineRenderer.js","names":[],"sources":["../../../../../src/components/pro/Flow/lines/LineRenderer.ts"],"sourcesContent":["import { Container, Graphics } from 'pixi.js';\nimport type { FlowLine } from '../types';\nimport { drawMarker, angleBetween } from '../edges/edgeMarkers';\nimport { drawDashedPolyline } from '../utils/dashedLine';\nimport { resolveThemeColor } from '../utils/themeColor';\n\nfunction getLineDash(style?: string, width = 2): number[] | undefined {\n if (!style || style === 'solid') return undefined;\n if (style === 'dynamic') return [width * 4, width * 3];\n if (style === 'dotted') return [width, width * 2];\n if (style === 'dashed') return [width * 3, width * 2];\n return undefined;\n}\n\ninterface LineDisplay {\n container: Container;\n gfx: Graphics;\n hitArea: Graphics;\n lineId: string;\n}\n\n/**\n * Renders independent FlowLine[] objects on the canvas.\n */\nexport class LineRenderer {\n private world: Container;\n private lineLayer: Container;\n private lines = new Map<string, LineDisplay>();\n private _dynamicOffset = 0;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.lineLayer = new Container({ label: 'lines', sortableChildren: true });\n // Lines on top of edges but below nodes\n this.world.addChildAt(this.lineLayer, Math.min(1, this.world.children.length));\n }\n\n sync(flowLines: FlowLine[], selectedIds: Set<string>): void {\n const seen = new Set<string>();\n\n for (const line of flowLines) {\n seen.add(line.id);\n let display = this.lines.get(line.id);\n if (!display) {\n display = this._create(line);\n this.lines.set(line.id, display);\n }\n this._update(display, line, selectedIds.has(line.id));\n }\n\n for (const [id, display] of this.lines) {\n if (!seen.has(id)) {\n this.lineLayer.removeChild(display.container);\n display.container.destroy({ children: true });\n this.lines.delete(id);\n }\n }\n }\n\n private _create(line: FlowLine): LineDisplay {\n const container = new Container({ label: `line-${line.id}` });\n\n const hitArea = new Graphics();\n hitArea.label = 'line-hitarea';\n hitArea.eventMode = 'static';\n hitArea.cursor = 'pointer';\n hitArea.alpha = 0.001;\n container.addChild(hitArea);\n\n const gfx = new Graphics();\n gfx.label = 'line-gfx';\n container.addChild(gfx);\n\n this.lineLayer.addChild(container);\n return { container, gfx, hitArea, lineId: line.id };\n }\n\n private _update(display: LineDisplay, line: FlowLine, selected: boolean): void {\n display.container.zIndex = line.zIndex ?? 0;\n const { gfx, hitArea } = display;\n const pts = line.points;\n if (pts.length < 2) return;\n\n const color = selected ? '#3b82f6' : resolveThemeColor(line.strokeColor, '#374151');\n const width = line.strokeWidth;\n\n gfx.clear();\n const dash = getLineDash(line.lineStyle, width);\n if (dash) {\n const offset = line.lineStyle === 'dynamic' ? this._dynamicOffset : 0;\n const drawPts = line.closed ? [...pts, pts[0]] : pts;\n drawDashedPolyline(gfx, drawPts, dash, offset);\n gfx.stroke({ color, width, cap: 'round' as const });\n } else {\n gfx.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n gfx.lineTo(pts[i].x, pts[i].y);\n }\n if (line.closed) gfx.closePath();\n gfx.stroke({ color, width });\n }\n\n // Markers\n if (line.markerStart && line.markerStart !== 'none' && pts.length >= 2) {\n const angle = angleBetween(pts[1].x, pts[1].y, pts[0].x, pts[0].y);\n drawMarker(gfx, line.markerStart, pts[0].x, pts[0].y, angle, color);\n }\n if (line.markerEnd && line.markerEnd !== 'none' && pts.length >= 2) {\n const last = pts[pts.length - 1];\n const prev = pts[pts.length - 2];\n const angle = angleBetween(prev.x, prev.y, last.x, last.y);\n drawMarker(gfx, line.markerEnd, last.x, last.y, angle, color);\n }\n\n // Hit area\n hitArea.clear();\n hitArea.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n hitArea.lineTo(pts[i].x, pts[i].y);\n }\n hitArea.stroke({ color: '#000000', width: Math.max(width + 10, 14) });\n hitArea.alpha = 0.001;\n }\n\n destroy(): void {\n for (const [, display] of this.lines) {\n display.container.destroy({ children: true });\n }\n this.lines.clear();\n this.lineLayer.destroy({ children: true });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LineRenderer.js","names":["getLineDash","style","width","LineRenderer","deltaMs","world","Container","seen","line","flowLines","display","selectedIds","id","container","hitArea","Graphics","gfx","pts","color","selected","resolveThemeColor","dash","offset","drawPts","drawDashedPolyline","i","angle","angleBetween","last","prev"],"sources":["../../../../../src/components/pro/Flow/lines/LineRenderer.ts"],"sourcesContent":["import { Container, Graphics } from 'pixi.js';\nimport type { FlowLine } from '../types';\nimport { drawMarker, angleBetween } from '../edges/edgeMarkers';\nimport { drawDashedPolyline } from '../utils/dashedLine';\nimport { resolveThemeColor } from '../utils/themeColor';\n\nfunction getLineDash(style?: string, width = 2): number[] | undefined {\n if (!style || style === 'solid') return undefined;\n if (style === 'dynamic') return [width * 4, width * 3];\n if (style === 'dotted') return [width, width * 2];\n if (style === 'dashed') return [width * 3, width * 2];\n return undefined;\n}\n\ninterface LineDisplay {\n container: Container;\n gfx: Graphics;\n hitArea: Graphics;\n lineId: string;\n}\n\n/**\n * Renders independent FlowLine[] objects on the canvas.\n */\nexport class LineRenderer {\n private world: Container;\n private lineLayer: Container;\n private lines = new Map<string, LineDisplay>();\n private _dynamicOffset = 0;\n\n /** Call once per frame to advance the dynamic dash animation. */\n advanceAnimation(deltaMs: number): void {\n this._dynamicOffset = (this._dynamicOffset + deltaMs * 0.06) % 1000;\n }\n\n constructor(world: Container) {\n this.world = world;\n this.lineLayer = new Container({ label: 'lines', sortableChildren: true });\n // Lines on top of edges but below nodes\n this.world.addChildAt(this.lineLayer, Math.min(1, this.world.children.length));\n }\n\n sync(flowLines: FlowLine[], selectedIds: Set<string>): void {\n const seen = new Set<string>();\n\n for (const line of flowLines) {\n seen.add(line.id);\n let display = this.lines.get(line.id);\n if (!display) {\n display = this._create(line);\n this.lines.set(line.id, display);\n }\n this._update(display, line, selectedIds.has(line.id));\n }\n\n for (const [id, display] of this.lines) {\n if (!seen.has(id)) {\n this.lineLayer.removeChild(display.container);\n display.container.destroy({ children: true });\n this.lines.delete(id);\n }\n }\n }\n\n private _create(line: FlowLine): LineDisplay {\n const container = new Container({ label: `line-${line.id}` });\n\n const hitArea = new Graphics();\n hitArea.label = 'line-hitarea';\n hitArea.eventMode = 'static';\n hitArea.cursor = 'pointer';\n hitArea.alpha = 0.001;\n container.addChild(hitArea);\n\n const gfx = new Graphics();\n gfx.label = 'line-gfx';\n container.addChild(gfx);\n\n this.lineLayer.addChild(container);\n return { container, gfx, hitArea, lineId: line.id };\n }\n\n private _update(display: LineDisplay, line: FlowLine, selected: boolean): void {\n display.container.zIndex = line.zIndex ?? 0;\n const { gfx, hitArea } = display;\n const pts = line.points;\n if (pts.length < 2) return;\n\n const color = selected ? '#3b82f6' : resolveThemeColor(line.strokeColor, '#374151');\n const width = line.strokeWidth;\n\n gfx.clear();\n const dash = getLineDash(line.lineStyle, width);\n if (dash) {\n const offset = line.lineStyle === 'dynamic' ? this._dynamicOffset : 0;\n const drawPts = line.closed ? [...pts, pts[0]] : pts;\n drawDashedPolyline(gfx, drawPts, dash, offset);\n gfx.stroke({ color, width, cap: 'round' as const });\n } else {\n gfx.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n gfx.lineTo(pts[i].x, pts[i].y);\n }\n if (line.closed) gfx.closePath();\n gfx.stroke({ color, width });\n }\n\n // Markers\n if (line.markerStart && line.markerStart !== 'none' && pts.length >= 2) {\n const angle = angleBetween(pts[1].x, pts[1].y, pts[0].x, pts[0].y);\n drawMarker(gfx, line.markerStart, pts[0].x, pts[0].y, angle, color);\n }\n if (line.markerEnd && line.markerEnd !== 'none' && pts.length >= 2) {\n const last = pts[pts.length - 1];\n const prev = pts[pts.length - 2];\n const angle = angleBetween(prev.x, prev.y, last.x, last.y);\n drawMarker(gfx, line.markerEnd, last.x, last.y, angle, color);\n }\n\n // Hit area\n hitArea.clear();\n hitArea.moveTo(pts[0].x, pts[0].y);\n for (let i = 1; i < pts.length; i++) {\n hitArea.lineTo(pts[i].x, pts[i].y);\n }\n hitArea.stroke({ color: '#000000', width: Math.max(width + 10, 14) });\n hitArea.alpha = 0.001;\n }\n\n destroy(): void {\n for (const [, display] of this.lines) {\n display.container.destroy({ children: true });\n }\n this.lines.clear();\n this.lineLayer.destroy({ children: true });\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"lineSmoothing.js","names":[],"sources":["../../../../../src/components/pro/Flow/lines/lineSmoothing.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\n/**\n * Catmull-Rom spline interpolation for smoothing freehand lines.\n * Produces additional intermediate points between each pair of original points.\n */\nexport function smoothCatmullRom(points: Point[], segments = 8): Point[] {\n if (points.length < 3) return [...points];\n\n const result: Point[] = [points[0]];\n\n for (let i = 0; i < points.length - 1; i++) {\n const p0 = points[Math.max(0, i - 1)];\n const p1 = points[i];\n const p2 = points[Math.min(points.length - 1, i + 1)];\n const p3 = points[Math.min(points.length - 1, i + 2)];\n\n for (let t = 1; t <= segments; t++) {\n const f = t / segments;\n const f2 = f * f;\n const f3 = f2 * f;\n\n const x = 0.5 * (\n (2 * p1.x) +\n (-p0.x + p2.x) * f +\n (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * f2 +\n (-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * f3\n );\n const y = 0.5 * (\n (2 * p1.y) +\n (-p0.y + p2.y) * f +\n (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * f2 +\n (-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * f3\n );\n\n result.push({ x, y });\n }\n }\n\n return result;\n}\n\n/**\n * Douglas-Peucker simplification to reduce point count.\n */\nexport function simplifyPath(points: Point[], epsilon = 1.5): Point[] {\n if (points.length < 3) return [...points];\n\n let maxDist = 0;\n let maxIdx = 0;\n const first = points[0];\n const last = points[points.length - 1];\n\n for (let i = 1; i < points.length - 1; i++) {\n const d = perpendicularDistance(points[i], first, last);\n if (d > maxDist) {\n maxDist = d;\n maxIdx = i;\n }\n }\n\n if (maxDist > epsilon) {\n const left = simplifyPath(points.slice(0, maxIdx + 1), epsilon);\n const right = simplifyPath(points.slice(maxIdx), epsilon);\n return [...left.slice(0, -1), ...right];\n }\n\n return [first, last];\n}\n\nfunction perpendicularDistance(point: Point, lineStart: Point, lineEnd: Point): number {\n const dx = lineEnd.x - lineStart.x;\n const dy = lineEnd.y - lineStart.y;\n const lenSq = dx * dx + dy * dy;\n if (lenSq === 0) return Math.hypot(point.x - lineStart.x, point.y - lineStart.y);\n const num = Math.abs(dy * point.x - dx * point.y + lineEnd.x * lineStart.y - lineEnd.y * lineStart.x);\n return num / Math.sqrt(lenSq);\n}\n"],"mappings":";AASA,SAAgB,EAAiB,GAAiB,IAAW,GAAY;CACvE,IAAI,EAAO,SAAS,GAAG,OAAO,CAAC,GAAG,CAAM;CAExC,IAAM,IAAkB,CAAC,EAAO,EAAE;CAElC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAO,SAAS,GAAG,KAAK;EAC1C,IAAM,IAAK,EAAO,KAAK,IAAI,GAAG,IAAI,CAAC,IAC7B,IAAK,EAAO,IACZ,IAAK,EAAO,KAAK,IAAI,EAAO,SAAS,GAAG,IAAI,CAAC,IAC7C,IAAK,EAAO,KAAK,IAAI,EAAO,SAAS,GAAG,IAAI,CAAC;EAEnD,KAAK,IAAI,IAAI,GAAG,KAAK,GAAU,KAAK;GAClC,IAAM,IAAI,IAAI,GACR,IAAK,IAAI,GACT,IAAK,IAAK,GAEV,IAAI,MACP,IAAI,EAAG,KACP,CAAC,EAAG,IAAI,EAAG,KAAK,KAChB,IAAI,EAAG,IAAI,IAAI,EAAG,IAAI,IAAI,EAAG,IAAI,EAAG,KAAK,KACzC,CAAC,EAAG,IAAI,IAAI,EAAG,IAAI,IAAI,EAAG,IAAI,EAAG,KAAK,IAEnC,IAAI,MACP,IAAI,EAAG,KACP,CAAC,EAAG,IAAI,EAAG,KAAK,KAChB,IAAI,EAAG,IAAI,IAAI,EAAG,IAAI,IAAI,EAAG,IAAI,EAAG,KAAK,KACzC,CAAC,EAAG,IAAI,IAAI,EAAG,IAAI,IAAI,EAAG,IAAI,EAAG,KAAK;GAGzC,EAAO,KAAK;IAAE;IAAG;GAAE,CAAC;EACtB;CACF;CAEA,OAAO;AACT;AAKA,SAAgB,EAAa,GAAiB,IAAU,KAAc;CACpE,IAAI,EAAO,SAAS,GAAG,OAAO,CAAC,GAAG,CAAM;CAExC,IAAI,IAAU,GACV,IAAS,GACP,IAAQ,EAAO,IACf,IAAO,EAAO,EAAO,SAAS;CAEpC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAO,SAAS,GAAG,KAAK;EAC1C,IAAM,IAAI,EAAsB,EAAO,IAAI,GAAO,CAAI;EACtD,AAAI,IAAI,MACN,IAAU,GACV,IAAS;CAEb;CAEA,IAAI,IAAU,GAAS;EACrB,IAAM,IAAO,EAAa,EAAO,MAAM,GAAG,IAAS,CAAC,GAAG,CAAO,GACxD,IAAQ,EAAa,EAAO,MAAM,CAAM,GAAG,CAAO;EACxD,OAAO,CAAC,GAAG,EAAK,MAAM,GAAG,EAAE,GAAG,GAAG,CAAK;CACxC;CAEA,OAAO,CAAC,GAAO,CAAI;AACrB;AAEA,SAAS,EAAsB,GAAc,GAAkB,GAAwB;CACrF,IAAM,IAAK,EAAQ,IAAI,EAAU,GAC3B,IAAK,EAAQ,IAAI,EAAU,GAC3B,IAAQ,IAAK,IAAK,IAAK;CAG7B,OAFI,MAAU,IAAU,KAAK,MAAM,EAAM,IAAI,EAAU,GAAG,EAAM,IAAI,EAAU,CAAC,IACnE,KAAK,IAAI,IAAK,EAAM,IAAI,IAAK,EAAM,IAAI,EAAQ,IAAI,EAAU,IAAI,EAAQ,IAAI,EAAU,CAC5F,IAAM,KAAK,KAAK,CAAK;AAC9B"}
1
+ {"version":3,"file":"lineSmoothing.js","names":["smoothCatmullRom","points","result","i","p0","p1","p2","p3","t","segments","f","f2","f3","x","y","simplifyPath","maxDist","maxIdx","first","last","d","perpendicularDistance","epsilon","left","right","dx","lineEnd","lineStart","dy","lenSq","point"],"sources":["../../../../../src/components/pro/Flow/lines/lineSmoothing.ts"],"sourcesContent":["export interface Point {\n x: number;\n y: number;\n}\n\n/**\n * Catmull-Rom spline interpolation for smoothing freehand lines.\n * Produces additional intermediate points between each pair of original points.\n */\nexport function smoothCatmullRom(points: Point[], segments = 8): Point[] {\n if (points.length < 3) return [...points];\n\n const result: Point[] = [points[0]];\n\n for (let i = 0; i < points.length - 1; i++) {\n const p0 = points[Math.max(0, i - 1)];\n const p1 = points[i];\n const p2 = points[Math.min(points.length - 1, i + 1)];\n const p3 = points[Math.min(points.length - 1, i + 2)];\n\n for (let t = 1; t <= segments; t++) {\n const f = t / segments;\n const f2 = f * f;\n const f3 = f2 * f;\n\n const x = 0.5 * (\n (2 * p1.x) +\n (-p0.x + p2.x) * f +\n (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * f2 +\n (-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * f3\n );\n const y = 0.5 * (\n (2 * p1.y) +\n (-p0.y + p2.y) * f +\n (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * f2 +\n (-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * f3\n );\n\n result.push({ x, y });\n }\n }\n\n return result;\n}\n\n/**\n * Douglas-Peucker simplification to reduce point count.\n */\nexport function simplifyPath(points: Point[], epsilon = 1.5): Point[] {\n if (points.length < 3) return [...points];\n\n let maxDist = 0;\n let maxIdx = 0;\n const first = points[0];\n const last = points[points.length - 1];\n\n for (let i = 1; i < points.length - 1; i++) {\n const d = perpendicularDistance(points[i], first, last);\n if (d > maxDist) {\n maxDist = d;\n maxIdx = i;\n }\n }\n\n if (maxDist > epsilon) {\n const left = simplifyPath(points.slice(0, maxIdx + 1), epsilon);\n const right = simplifyPath(points.slice(maxIdx), epsilon);\n return [...left.slice(0, -1), ...right];\n }\n\n return [first, last];\n}\n\nfunction perpendicularDistance(point: Point, lineStart: Point, lineEnd: Point): number {\n const dx = lineEnd.x - lineStart.x;\n const dy = lineEnd.y - lineStart.y;\n const lenSq = dx * dx + dy * dy;\n if (lenSq === 0) return Math.hypot(point.x - lineStart.x, point.y - lineStart.y);\n const num = Math.abs(dy * point.x - dx * point.y + lineEnd.x * lineStart.y - lineEnd.y * lineStart.x);\n return num / Math.sqrt(lenSq);\n}\n"],"mappings":";AASA,SAAgBA,EAAiB,GAAiB,IAAW,GAAY;CACvE,IAAIC,EAAO,SAAS,GAAG,OAAO,CAAC,GAAGA,CAAM;CAExC,IAAMC,IAAkB,CAACD,EAAO,EAAE;CAElC,KAAK,IAAIE,IAAI,GAAGA,IAAIF,EAAO,SAAS,GAAG,KAAK;EAC1C,IAAMG,IAAKH,EAAO,KAAK,IAAI,GAAGE,IAAI,CAAC,IAC7BE,IAAKJ,EAAOE,IACZG,IAAKL,EAAO,KAAK,IAAIA,EAAO,SAAS,GAAGE,IAAI,CAAC,IAC7CI,IAAKN,EAAO,KAAK,IAAIA,EAAO,SAAS,GAAGE,IAAI,CAAC;EAEnD,KAAK,IAAIK,IAAI,GAAGA,KAAKC,GAAU,KAAK;GAClC,IAAMC,IAAIF,IAAIC,GACRE,IAAKD,IAAIA,GACTE,IAAKD,IAAKD,GAEVG,IAAI,MACP,IAAIR,EAAG,KACP,CAACD,EAAG,IAAIE,EAAG,KAAKI,KAChB,IAAIN,EAAG,IAAI,IAAIC,EAAG,IAAI,IAAIC,EAAG,IAAIC,EAAG,KAAKI,KACzC,CAACP,EAAG,IAAI,IAAIC,EAAG,IAAI,IAAIC,EAAG,IAAIC,EAAG,KAAKK,IAEnCE,IAAI,MACP,IAAIT,EAAG,KACP,CAACD,EAAG,IAAIE,EAAG,KAAKI,KAChB,IAAIN,EAAG,IAAI,IAAIC,EAAG,IAAI,IAAIC,EAAG,IAAIC,EAAG,KAAKI,KACzC,CAACP,EAAG,IAAI,IAAIC,EAAG,IAAI,IAAIC,EAAG,IAAIC,EAAG,KAAKK;GAGzC,EAAO,KAAK;IAAE;IAAG;GAAE,CAAC;EACtB;CACF;CAEA,OAAOV;AACT;AAKA,SAAgBa,EAAa,GAAiB,IAAU,KAAc;CACpE,IAAId,EAAO,SAAS,GAAG,OAAO,CAAC,GAAGA,CAAM;CAExC,IAAIe,IAAU,GACVC,IAAS,GACPC,IAAQjB,EAAO,IACfkB,IAAOlB,EAAOA,EAAO,SAAS;CAEpC,KAAK,IAAIE,IAAI,GAAGA,IAAIF,EAAO,SAAS,GAAG,KAAK;EAC1C,IAAMmB,IAAIC,EAAsBpB,EAAOE,IAAIe,GAAOC,CAAI;EACtD,AAAIC,IAAIJ,MACN,IAAUI,GACV,IAASjB;CAEb;CAEA,IAAIa,IAAUM,GAAS;EACrB,IAAMC,IAAOR,EAAad,EAAO,MAAM,GAAGgB,IAAS,CAAC,GAAGK,CAAO,GACxDE,IAAQT,EAAad,EAAO,MAAMgB,CAAM,GAAGK,CAAO;EACxD,OAAO,CAAC,GAAGC,EAAK,MAAM,GAAG,EAAE,GAAG,GAAGC,CAAK;CACxC;CAEA,OAAO,CAACN,GAAOC,CAAI;AACrB;AAEA,SAASE,EAAsB,GAAc,GAAkB,GAAwB;CACrF,IAAMI,IAAKC,EAAQ,IAAIC,EAAU,GAC3BC,IAAKF,EAAQ,IAAIC,EAAU,GAC3BE,IAAQJ,IAAKA,IAAKG,IAAKA;CAG7B,OAFIC,MAAU,IAAU,KAAK,MAAMC,EAAM,IAAIH,EAAU,GAAGG,EAAM,IAAIH,EAAU,CAAC,IACnE,KAAK,IAAIC,IAAKE,EAAM,IAAIL,IAAKK,EAAM,IAAIJ,EAAQ,IAAIC,EAAU,IAAID,EAAQ,IAAIC,EAAU,CAC5F,IAAM,KAAK,KAAKE,CAAK;AAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"DataNodeView.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/DataNodeView.tsx"],"sourcesContent":["import React, { useMemo, useRef, useState, useLayoutEffect } from 'react';\nimport Chart, {\n areaY,\n barX,\n barY,\n defineChart,\n dot,\n lineY,\n} from '../../../Chart';\nimport { scaleBand } from '@tanstack/charts/scales/band';\nimport { scaleLinear } from '@tanstack/charts/scales/linear';\nimport { scalePoint } from '@tanstack/charts/scales/point';\nimport { polar, pie, radialArc } from '@tanstack/charts/polar';\nimport DataTable, {\n createColumn,\n usePivotExtension,\n type ColumnDef,\n type PivotField,\n type PivotValue,\n} from '../../DataTable';\nimport type { FlowDataConfig } from '../types';\nimport { DATA_CHART_PALETTE, labelFor } from './dataUtils';\nimport { showLinePoints, withChartGeometryBudget } from './chartGeometryBudget';\n\n/** Renders the table (optionally pivoted) surface of a Data node. */\nfunction DataTableView({ config }: { config: FlowDataConfig }) {\n const columns = useMemo<ColumnDef<Record<string, unknown>>[]>(\n () =>\n config.columns.map((col) =>\n createColumn<Record<string, unknown>>(col.key, col.label ?? col.key, {\n enableSorting: true,\n }),\n ),\n [config.columns],\n );\n\n const pivotFields = useMemo<PivotField[]>(\n () =>\n config.columns.map((col) => ({\n field: col.key,\n label: col.label ?? col.key,\n numeric: col.type === 'number',\n })),\n [config.columns],\n );\n\n const pivot = config.pivot;\n // Remount the pivot extension when the inspector-controlled bits change, so\n // the enabled toggle / initial fields take effect (the extension keeps its\n // own interactive state otherwise). Panel placement stays reactive.\n const pivotKey = JSON.stringify({\n e: !!pivot?.enabled,\n r: pivot?.rowFields ?? [],\n c: pivot?.colFields ?? [],\n v: pivot?.values ?? [],\n });\n\n return (\n <div className=\"flow-data-table\">\n <PivotableTable\n key={pivotKey}\n config={config}\n columns={columns}\n pivotFields={pivotFields}\n />\n </div>\n );\n}\n\nfunction PivotableTable({\n config,\n columns,\n pivotFields,\n}: {\n config: FlowDataConfig;\n columns: ColumnDef<Record<string, unknown>>[];\n pivotFields: PivotField[];\n}) {\n const pivot = config.pivot;\n const pivotExtension = usePivotExtension<Record<string, unknown>>({\n fields: pivotFields,\n initialActive: !!pivot?.enabled,\n initialRowFields: pivot?.rowFields ?? [],\n initialColFields: pivot?.colFields ?? [],\n initialValues: (pivot?.values as PivotValue[] | undefined) ?? [],\n panelPlacement: pivot?.panelPlacement ?? 'top',\n lang: 'zh',\n // 透视开关由 Inspector 统一控制,节点内不再渲染开关,避免占用空间。\n hideModeToggle: true,\n });\n\n return (\n <DataTable<Record<string, unknown>>\n data={config.rows}\n columns={columns}\n enableSorting\n enablePagination={config.rows.length > 50}\n pageSize={50}\n extensions={[pivotExtension]}\n />\n );\n}\n\n/** Builds a TanStack Charts definition from the Data node's chart config. */\nfunction useChartDefinition(config: FlowDataConfig, width: number, primaryColor?: string) {\n return useMemo(() => {\n const chart = config.chart;\n if (!chart) return null;\n const xField = chart.xField;\n const yFields = (chart.yFields ?? []).filter(Boolean);\n if (!xField || yFields.length === 0) return null;\n\n const rows = config.rows as any[];\n // Series color resolution order: an explicit per-series override, then a\n // configured chart palette, then the node's own `color` (the drawing's\n // primary color), then the built-in default palette.\n const paletteRange = chart.palette?.length ? chart.palette : null;\n const seriesColor = (field: string, i: number) =>\n chart.seriesColors?.[field]\n ?? paletteRange?.[i % paletteRange.length]\n ?? primaryColor\n ?? DATA_CHART_PALETTE[i % DATA_CHART_PALETTE.length];\n\n switch (chart.type) {\n case 'line':\n return defineChart({\n marks: yFields.map((yf, i) =>\n withChartGeometryBudget(lineY(rows, {\n id: yf, x: xField, y: yf, stroke: seriesColor(yf, i),\n points: showLinePoints(rows.length, yFields.length, width),\n })),\n ),\n scales: {\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'area':\n return defineChart({\n marks: yFields.map((yf, i) =>\n withChartGeometryBudget(areaY(rows, {\n id: yf,\n x: xField,\n y: yf,\n fill: seriesColor(yf, i),\n fillOpacity: 0.35,\n stroke: seriesColor(yf, i),\n })),\n ),\n scales: {\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'scatter':\n // Scatter uses the first two numeric fields as x/y.\n return defineChart({\n marks: [\n dot(rows, {\n id: 'points',\n x: xField,\n y: yFields[0],\n r: 6,\n fill: seriesColor(yFields[0], 0),\n }),\n ],\n scales: {\n x: { scale: scaleLinear, nice: true, grid: true },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'pie': {\n // Part-to-whole via a polar pie over the first measure. Duplicate\n // categories are aggregated (summed) so slices are unique.\n const yf = yFields[0];\n const totals = new Map<string, number>();\n for (const r of rows) {\n const k = String(r[xField] ?? '');\n totals.set(k, (totals.get(k) ?? 0) + (Number(r[yf]) || 0));\n }\n const pieRows = Array.from(totals, ([cat, value]) => ({ cat, value }));\n const arranged = pie(pieRows, { value: 'value' });\n const range = chart.palette?.length ? chart.palette : DATA_CHART_PALETTE;\n return defineChart({\n marks: [\n polar({\n marks: [\n radialArc(arranged, {\n startAngle: 'startAngle',\n endAngle: 'endAngle',\n padAngle: 'padAngle',\n innerRadius: 0,\n color: 'cat',\n key: 'cat',\n }),\n ],\n scales: { angle: null, radius: null },\n }),\n ],\n scales: { x: null, y: null },\n color: { domain: pieRows.map((d) => d.cat), range },\n });\n }\n\n case 'barHorizontal':\n return defineChart({\n marks: yFields.map((yf, i) =>\n barX(rows, { id: yf, y: xField, x: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n scales: {\n y: { scale: () => scaleBand<string>().padding(0.25) },\n x: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'bar':\n default:\n return defineChart({\n marks: yFields.map((yf, i) =>\n barY(rows, { id: yf, x: xField, y: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n scales: {\n x: { scale: () => scaleBand<string>().padding(0.25) },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n }\n }, [config, width, primaryColor]);\n}\n\n/** Renders the chart surface of a Data node. */\nfunction DataChartView({ config, surfaceColor, textColor, primaryColor }: { config: FlowDataConfig; surfaceColor?: string; textColor?: string; primaryColor?: string }) {\n const chart = config.chart;\n\n // TanStack Charts needs a concrete pixel height; inside the media overlay the\n // node box is a fixed size but percentage heights don't always resolve before\n // first paint (esp. in read-only / preview renders), leaving the chart blank.\n // Measure the container and pass an explicit height.\n const wrapRef = useRef<HTMLDivElement>(null);\n const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });\n const definition = useChartDefinition(config, size.w, primaryColor);\n useLayoutEffect(() => {\n const el = wrapRef.current;\n if (!el) return;\n const measure = () => {\n const rect = el.getBoundingClientRect();\n // getBoundingClientRect includes the overlay's zoom scale; divide it out\n // so the chart is laid out in unscaled (world) pixels.\n const scale = rect.width && el.offsetWidth ? rect.width / el.offsetWidth : 1;\n const w = Math.max(1, Math.round(rect.width / (scale || 1)));\n const h = Math.max(1, Math.round(rect.height / (scale || 1)));\n setSize(previous => previous.w === w && previous.h === h ? previous : { w, h });\n };\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n if (!definition) {\n return (\n <div className=\"flow-data-empty\">\n {config.columns.length === 0\n ? '尚无数据,请在属性面板上传或填写数据'\n : '请在属性面板选择 X 轴与至少一个数值字段'}\n </div>\n );\n }\n\n const label =\n chart && chart.xField\n ? `${labelFor(config.columns, chart.xField)} · ${(chart.yFields ?? [])\n .map((f) => labelFor(config.columns, f))\n .join(', ')}`\n : 'Chart';\n\n return (\n <div\n className=\"flow-data-chart\"\n ref={wrapRef}\n style={textColor ? ({ color: textColor } as React.CSSProperties) : undefined}\n >\n {size.h > 0 && (\n <Chart\n definition={definition as any}\n aria-label={label}\n height={size.h}\n // Let the media node's fill show through instead of the Chart's\n // default opaque white card, and let axis/label text inherit the\n // node's text color so the chart matches Archify (or any) theming.\n style={{\n background: surfaceColor ?? 'transparent',\n borderColor: 'transparent',\n color: textColor ?? 'inherit',\n padding: 0,\n }}\n />\n )}\n </div>\n );\n}\n\n/** Dispatches to the table or chart surface based on the node's view. */\nexport function DataNodeView({\n config,\n surfaceColor,\n textColor,\n primaryColor,\n}: {\n config: FlowDataConfig;\n surfaceColor?: string;\n textColor?: string;\n primaryColor?: string;\n}) {\n if (!config || config.columns.length === 0) {\n return <div className=\"flow-data-empty\">尚无数据,请在属性面板上传或填写数据</div>;\n }\n return config.view === 'chart' ? (\n <DataChartView config={config} surfaceColor={surfaceColor} textColor={textColor} primaryColor={primaryColor} />\n ) : (\n <DataTableView config={config} />\n );\n}\n\nexport default DataNodeView;\n"],"mappings":"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"}
1
+ {"version":3,"file":"DataNodeView.js","names":["DataTable","DataTable_default","Chart","DataTableView","columns","useMemo","config","createColumn","col","pivotFields","pivot","pivotKey","PivotableTable","pivotExtension","usePivotExtension","useChartDefinition","chart","xField","yFields","rows","paletteRange","seriesColor","field","i","primaryColor","DATA_CHART_PALETTE","defineChart","withChartGeometryBudget","lineY","yf","showLinePoints","width","scalePoint","scaleLinear","areaY","dot","totals","r","k","pieRows","cat","value","arranged","pie","range","polar","radialArc","d","barX","scaleBand","barY","DataChartView","wrapRef","useRef","size","setSize","useState","definition","useLayoutEffect","el","measure","rect","scale","w","h","previous","ro","label","labelFor","f","textColor","surfaceColor","DataNodeView"],"sources":["../../../../../src/components/pro/Flow/nodes/DataNodeView.tsx"],"sourcesContent":["import React, { useMemo, useRef, useState, useLayoutEffect } from 'react';\nimport Chart, {\n areaY,\n barX,\n barY,\n defineChart,\n dot,\n lineY,\n} from '../../../Chart';\nimport { scaleBand } from '@tanstack/charts/scales/band';\nimport { scaleLinear } from '@tanstack/charts/scales/linear';\nimport { scalePoint } from '@tanstack/charts/scales/point';\nimport { polar, pie, radialArc } from '@tanstack/charts/polar';\nimport DataTable, {\n createColumn,\n usePivotExtension,\n type ColumnDef,\n type PivotField,\n type PivotValue,\n} from '../../DataTable';\nimport type { FlowDataConfig } from '../types';\nimport { DATA_CHART_PALETTE, labelFor } from './dataUtils';\nimport { showLinePoints, withChartGeometryBudget } from './chartGeometryBudget';\n\n/** Renders the table (optionally pivoted) surface of a Data node. */\nfunction DataTableView({ config }: { config: FlowDataConfig }) {\n const columns = useMemo<ColumnDef<Record<string, unknown>>[]>(\n () =>\n config.columns.map((col) =>\n createColumn<Record<string, unknown>>(col.key, col.label ?? col.key, {\n enableSorting: true,\n }),\n ),\n [config.columns],\n );\n\n const pivotFields = useMemo<PivotField[]>(\n () =>\n config.columns.map((col) => ({\n field: col.key,\n label: col.label ?? col.key,\n numeric: col.type === 'number',\n })),\n [config.columns],\n );\n\n const pivot = config.pivot;\n // Remount the pivot extension when the inspector-controlled bits change, so\n // the enabled toggle / initial fields take effect (the extension keeps its\n // own interactive state otherwise). Panel placement stays reactive.\n const pivotKey = JSON.stringify({\n e: !!pivot?.enabled,\n r: pivot?.rowFields ?? [],\n c: pivot?.colFields ?? [],\n v: pivot?.values ?? [],\n });\n\n return (\n <div className=\"flow-data-table\">\n <PivotableTable\n key={pivotKey}\n config={config}\n columns={columns}\n pivotFields={pivotFields}\n />\n </div>\n );\n}\n\nfunction PivotableTable({\n config,\n columns,\n pivotFields,\n}: {\n config: FlowDataConfig;\n columns: ColumnDef<Record<string, unknown>>[];\n pivotFields: PivotField[];\n}) {\n const pivot = config.pivot;\n const pivotExtension = usePivotExtension<Record<string, unknown>>({\n fields: pivotFields,\n initialActive: !!pivot?.enabled,\n initialRowFields: pivot?.rowFields ?? [],\n initialColFields: pivot?.colFields ?? [],\n initialValues: (pivot?.values as PivotValue[] | undefined) ?? [],\n panelPlacement: pivot?.panelPlacement ?? 'top',\n lang: 'zh',\n // 透视开关由 Inspector 统一控制,节点内不再渲染开关,避免占用空间。\n hideModeToggle: true,\n });\n\n return (\n <DataTable<Record<string, unknown>>\n data={config.rows}\n columns={columns}\n enableSorting\n enablePagination={config.rows.length > 50}\n pageSize={50}\n extensions={[pivotExtension]}\n />\n );\n}\n\n/** Builds a TanStack Charts definition from the Data node's chart config. */\nfunction useChartDefinition(config: FlowDataConfig, width: number, primaryColor?: string) {\n return useMemo(() => {\n const chart = config.chart;\n if (!chart) return null;\n const xField = chart.xField;\n const yFields = (chart.yFields ?? []).filter(Boolean);\n if (!xField || yFields.length === 0) return null;\n\n const rows = config.rows as any[];\n // Series color resolution order: an explicit per-series override, then a\n // configured chart palette, then the node's own `color` (the drawing's\n // primary color), then the built-in default palette.\n const paletteRange = chart.palette?.length ? chart.palette : null;\n const seriesColor = (field: string, i: number) =>\n chart.seriesColors?.[field]\n ?? paletteRange?.[i % paletteRange.length]\n ?? primaryColor\n ?? DATA_CHART_PALETTE[i % DATA_CHART_PALETTE.length];\n\n switch (chart.type) {\n case 'line':\n return defineChart({\n marks: yFields.map((yf, i) =>\n withChartGeometryBudget(lineY(rows, {\n id: yf, x: xField, y: yf, stroke: seriesColor(yf, i),\n points: showLinePoints(rows.length, yFields.length, width),\n })),\n ),\n scales: {\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'area':\n return defineChart({\n marks: yFields.map((yf, i) =>\n withChartGeometryBudget(areaY(rows, {\n id: yf,\n x: xField,\n y: yf,\n fill: seriesColor(yf, i),\n fillOpacity: 0.35,\n stroke: seriesColor(yf, i),\n })),\n ),\n scales: {\n x: { scale: () => scalePoint<string>().padding(0.35) },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'scatter':\n // Scatter uses the first two numeric fields as x/y.\n return defineChart({\n marks: [\n dot(rows, {\n id: 'points',\n x: xField,\n y: yFields[0],\n r: 6,\n fill: seriesColor(yFields[0], 0),\n }),\n ],\n scales: {\n x: { scale: scaleLinear, nice: true, grid: true },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'pie': {\n // Part-to-whole via a polar pie over the first measure. Duplicate\n // categories are aggregated (summed) so slices are unique.\n const yf = yFields[0];\n const totals = new Map<string, number>();\n for (const r of rows) {\n const k = String(r[xField] ?? '');\n totals.set(k, (totals.get(k) ?? 0) + (Number(r[yf]) || 0));\n }\n const pieRows = Array.from(totals, ([cat, value]) => ({ cat, value }));\n const arranged = pie(pieRows, { value: 'value' });\n const range = chart.palette?.length ? chart.palette : DATA_CHART_PALETTE;\n return defineChart({\n marks: [\n polar({\n marks: [\n radialArc(arranged, {\n startAngle: 'startAngle',\n endAngle: 'endAngle',\n padAngle: 'padAngle',\n innerRadius: 0,\n color: 'cat',\n key: 'cat',\n }),\n ],\n scales: { angle: null, radius: null },\n }),\n ],\n scales: { x: null, y: null },\n color: { domain: pieRows.map((d) => d.cat), range },\n });\n }\n\n case 'barHorizontal':\n return defineChart({\n marks: yFields.map((yf, i) =>\n barX(rows, { id: yf, y: xField, x: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n scales: {\n y: { scale: () => scaleBand<string>().padding(0.25) },\n x: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n\n case 'bar':\n default:\n return defineChart({\n marks: yFields.map((yf, i) =>\n barY(rows, { id: yf, x: xField, y: yf, fill: seriesColor(yf, i), radius: 4 }),\n ),\n scales: {\n x: { scale: () => scaleBand<string>().padding(0.25) },\n y: { scale: scaleLinear, nice: true, grid: true },\n },\n });\n }\n }, [config, width, primaryColor]);\n}\n\n/** Renders the chart surface of a Data node. */\nfunction DataChartView({ config, surfaceColor, textColor, primaryColor }: { config: FlowDataConfig; surfaceColor?: string; textColor?: string; primaryColor?: string }) {\n const chart = config.chart;\n\n // TanStack Charts needs a concrete pixel height; inside the media overlay the\n // node box is a fixed size but percentage heights don't always resolve before\n // first paint (esp. in read-only / preview renders), leaving the chart blank.\n // Measure the container and pass an explicit height.\n const wrapRef = useRef<HTMLDivElement>(null);\n const [size, setSize] = useState<{ w: number; h: number }>({ w: 0, h: 0 });\n const definition = useChartDefinition(config, size.w, primaryColor);\n useLayoutEffect(() => {\n const el = wrapRef.current;\n if (!el) return;\n const measure = () => {\n const rect = el.getBoundingClientRect();\n // getBoundingClientRect includes the overlay's zoom scale; divide it out\n // so the chart is laid out in unscaled (world) pixels.\n const scale = rect.width && el.offsetWidth ? rect.width / el.offsetWidth : 1;\n const w = Math.max(1, Math.round(rect.width / (scale || 1)));\n const h = Math.max(1, Math.round(rect.height / (scale || 1)));\n setSize(previous => previous.w === w && previous.h === h ? previous : { w, h });\n };\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, []);\n\n if (!definition) {\n return (\n <div className=\"flow-data-empty\">\n {config.columns.length === 0\n ? '尚无数据,请在属性面板上传或填写数据'\n : '请在属性面板选择 X 轴与至少一个数值字段'}\n </div>\n );\n }\n\n const label =\n chart && chart.xField\n ? `${labelFor(config.columns, chart.xField)} · ${(chart.yFields ?? [])\n .map((f) => labelFor(config.columns, f))\n .join(', ')}`\n : 'Chart';\n\n return (\n <div\n className=\"flow-data-chart\"\n ref={wrapRef}\n style={textColor ? ({ color: textColor } as React.CSSProperties) : undefined}\n >\n {size.h > 0 && (\n <Chart\n definition={definition as any}\n aria-label={label}\n height={size.h}\n // Let the media node's fill show through instead of the Chart's\n // default opaque white card, and let axis/label text inherit the\n // node's text color so the chart matches Archify (or any) theming.\n style={{\n background: surfaceColor ?? 'transparent',\n borderColor: 'transparent',\n color: textColor ?? 'inherit',\n padding: 0,\n }}\n />\n )}\n </div>\n );\n}\n\n/** Dispatches to the table or chart surface based on the node's view. */\nexport function DataNodeView({\n config,\n surfaceColor,\n textColor,\n primaryColor,\n}: {\n config: FlowDataConfig;\n surfaceColor?: string;\n textColor?: string;\n primaryColor?: string;\n}) {\n if (!config || config.columns.length === 0) {\n return <div className=\"flow-data-empty\">尚无数据,请在属性面板上传或填写数据</div>;\n }\n return config.view === 'chart' ? (\n <DataChartView config={config} surfaceColor={surfaceColor} textColor={textColor} primaryColor={primaryColor} />\n ) : (\n <DataTableView config={config} />\n );\n}\n\nexport default DataNodeView;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MediaContent.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/MediaContent.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport katex from 'katex';\nimport mermaid from 'mermaid';\nimport Markdown from '../../../Markdown';\nimport type { FlowNode, FlowAIConfig } from '../types';\nimport { streamAIChat, type AIChatMessage } from './aiClient';\nimport { resolveThemeColorCss, resolveThemeColor } from '../utils/themeColor';\nimport 'katex/dist/katex.min.css';\nimport { Model3DView } from './Model3DView';\n\n// Data-node view pulls in DataTable + Chart; lazy-load so it only enters the\n// bundle when a data node actually renders.\nconst DataNodeView = React.lazy(() =>\n import('./DataNodeView').then((m) => ({ default: m.DataNodeView })),\n);\n\nlet mermaidReady = false;\nfunction ensureMermaid() {\n if (mermaidReady) return;\n mermaid.initialize({ startOnLoad: false, theme: 'default', securityLevel: 'loose', fontFamily: 'inherit' });\n mermaidReady = true;\n}\n\n/** Renders a Mermaid diagram from source into an inline SVG. */\nfunction MermaidView({ content, color }: { content: string; color?: string }) {\n const [svg, setSvg] = useState('');\n const [error, setError] = useState<string | null>(null);\n const idRef = useRef(`flow-mermaid-${Math.random().toString(36).slice(2)}`);\n\n useEffect(() => {\n let cancelled = false;\n ensureMermaid();\n const src = content.trim();\n if (!src) { setSvg(''); setError(null); return; }\n mermaid\n .render(idRef.current, src)\n .then(({ svg }) => { if (!cancelled) { setSvg(svg); setError(null); } })\n .catch((e) => { if (!cancelled) setError(e?.message ?? 'Mermaid error'); });\n return () => { cancelled = true; };\n }, [content]);\n\n if (error) return <div className=\"flow-media-error\">{error}</div>;\n return <div className=\"flow-media-mermaid\" style={{ color }} dangerouslySetInnerHTML={{ __html: svg }} />;\n}\n\n/** Renders a LaTeX formula (display mode) via KaTeX. */\nfunction MathView({ content, color, fontSize }: { content: string; color?: string; fontSize?: number }) {\n const html = useMemo(() => {\n try {\n return katex.renderToString(content.trim() || '\\\\;', { displayMode: true, throwOnError: false });\n } catch (e: any) {\n return `<span class=\"flow-media-error\">${e?.message ?? 'KaTeX error'}</span>`;\n }\n }, [content]);\n return <div className=\"flow-media-math\" style={{ color, fontSize }} dangerouslySetInnerHTML={{ __html: html }} />;\n}\n\n/** Renders raw HTML in a sandboxed iframe (isolated from the host document).\n * A base stylesheet is injected so the fragment inherits the node's themed\n * text color / font size and a transparent background, keeping it readable on\n * any theme without the author having to set colors.\n * Content is always untrusted: scripts can drive the preview, but the opaque\n * sandbox origin prevents host DOM/storage access. Do not add allow-same-origin\n * alongside allow-scripts; interactive only controls pointer input. */\nfunction HtmlView({ content, interactive, color, fontSize }: { content: string; interactive: boolean; color?: string; fontSize?: number }) {\n const srcDoc = useMemo(() => {\n const base = `<!doctype html><html><head><meta charset=\"utf-8\"><style>\n :root { color-scheme: light dark; }\n html, body { margin: 0; background: transparent; }\n body {\n color: ${color ?? '#111827'};\n font-size: ${fontSize ?? 13}px;\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n line-height: 1.5;\n padding: 0;\n }\n a { color: inherit; }\n </style></head><body>${content}</body></html>`;\n return base;\n }, [content, color, fontSize]);\n return (\n <iframe\n title=\"html-media\"\n className=\"flow-media-iframe\"\n style={{ pointerEvents: interactive ? 'auto' : 'none' }}\n sandbox=\"allow-scripts\"\n srcDoc={srcDoc}\n />\n );\n}\n\nfunction ImageView({ content }: { content: string }) {\n const src = content.trim();\n if (!src) {\n return <div className=\"flow-media-image-empty\">输入图片链接,或直接粘贴图片</div>;\n }\n return (\n <img\n className=\"flow-media-image\"\n src={src}\n alt=\"\"\n draggable={false}\n referrerPolicy=\"no-referrer\"\n />\n );\n}\n\n/** Interactive AI chat backed by an OpenAI/Anthropic-compatible endpoint. */\nfunction AIView({ node, config, interactive, color }: { node: FlowNode; config?: FlowAIConfig; interactive: boolean; color?: string }) {\n const [messages, setMessages] = useState<AIChatMessage[]>([]);\n const [input, setInput] = useState('');\n const [streaming, setStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }, [messages, streaming]);\n\n useEffect(() => () => abortRef.current?.abort(), []);\n\n const canSend = !!config?.gateway && !!config?.model && !streaming;\n\n const send = async () => {\n const text = input.trim();\n if (!text || !config?.gateway) return;\n setError(null);\n // Only keep non-empty assistant messages in history; an aborted/errored\n // request can leave an empty assistant placeholder behind, which the API\n // then rejects (\"assistant message must not be empty\").\n const history = messages.filter(\n (m) => !(m.role === 'assistant' && m.content.trim() === ''),\n );\n const next: AIChatMessage[] = [...history, { role: 'user', content: text }];\n setMessages(next);\n setInput('');\n setStreaming(true);\n const ac = new AbortController();\n abortRef.current = ac;\n let acc = '';\n setMessages((m) => [...m, { role: 'assistant', content: '' }]);\n try {\n for await (const delta of streamAIChat(config, next, ac.signal)) {\n acc += delta;\n setMessages((m) => {\n const copy = m.slice();\n copy[copy.length - 1] = { role: 'assistant', content: acc };\n return copy;\n });\n }\n } catch (e: any) {\n if (e?.name !== 'AbortError') setError(e?.message ?? 'Request failed');\n } finally {\n // Drop the trailing assistant placeholder if nothing streamed in.\n setMessages((m) => {\n const last = m[m.length - 1];\n if (last && last.role === 'assistant' && last.content.trim() === '') {\n return m.slice(0, -1);\n }\n return m;\n });\n setStreaming(false);\n abortRef.current = null;\n }\n };\n\n return (\n <div className=\"flow-media-ai\" style={{ color }}>\n <div className=\"flow-media-ai-header\">\n {config?.model ? `AI · ${config.model}` : (node.data.label || 'AI')}\n </div>\n <div className=\"flow-media-ai-log\" ref={scrollRef}>\n {messages.length === 0 && (\n <div className=\"flow-media-ai-empty\">\n {config?.gateway ? '开始对话…' : '请先配置 AI 接口'}\n </div>\n )}\n {messages.map((m, i) => (\n <div key={i} className={`flow-media-ai-msg flow-media-ai-msg--${m.role}`}>\n {m.role === 'assistant'\n ? <Markdown content={m.content || '…'} enableMermaid={false} enableMarkmap={false} />\n : <span>{m.content}</span>}\n </div>\n ))}\n {error && <div className=\"flow-media-error\">{error}</div>}\n </div>\n <div className=\"flow-media-ai-input\" style={{ pointerEvents: interactive ? 'auto' : 'none' }}>\n <textarea\n value={input}\n placeholder=\"输入消息,Enter 发送\"\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (canSend) send(); }\n }}\n onPointerDown={(e) => e.stopPropagation()}\n />\n {streaming ? (\n <button type=\"button\" onClick={() => abortRef.current?.abort()}>停止</button>\n ) : (\n <button type=\"button\" disabled={!canSend || !input.trim()} onClick={send}>发送</button>\n )}\n </div>\n </div>\n );\n}\n\n/** Dispatches to the correct renderer for the node's media kind. */\nexport function MediaContent({ node, interactive, aiConfig, useSharedAIConfig = false }: { node: FlowNode; interactive: boolean; aiConfig?: FlowAIConfig; useSharedAIConfig?: boolean }) {\n const kind = node.data.mediaKind ?? 'markdown';\n const content = node.data.mediaContent ?? '';\n const textColor = resolveThemeColorCss(node.data.labelColor ?? node.data.color, '#111827');\n\n switch (kind) {\n case 'markdown':\n return (\n <div className=\"flow-media-markdown\" style={{ color: textColor, fontSize: node.data.fontSize }}>\n <Markdown content={content} />\n </div>\n );\n case 'html':\n // The iframe is an isolated document with no access to the parent's CSS\n // variables, so pass a concrete resolved color instead of a var().\n return (\n <HtmlView\n content={content}\n interactive={interactive}\n color={resolveThemeColor(node.data.labelColor ?? node.data.color, '#111827')}\n fontSize={node.data.fontSize}\n />\n );\n case 'mermaid':\n return <MermaidView content={content} color={textColor} />;\n case 'math':\n return <MathView content={content} color={textColor} fontSize={node.data.fontSize} />;\n case 'image':\n return <ImageView content={content} />;\n case 'model3d':\n return (\n <Model3DView\n content={content}\n format={node.data.modelFormat ?? 'stl'}\n interactive={interactive}\n />\n );\n case 'ai':\n return <AIView node={node} config={useSharedAIConfig ? aiConfig : node.data.aiConfig} interactive={interactive} color={textColor} />;\n case 'data':\n return (\n <div className=\"flow-media-data\" style={{ pointerEvents: interactive ? 'auto' : 'none' }}>\n <DataNodeView\n config={node.data.dataConfig ?? { columns: [], rows: [], view: 'table' }}\n surfaceColor={node.data.fill === 'transparent' ? undefined : resolveThemeColorCss(node.data.fill, '')}\n textColor={textColor}\n primaryColor={resolveThemeColorCss(node.data.color, '')}\n />\n </div>\n );\n default:\n return null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MediaContent.js","names":["Markdown","React","mermaid","katex","DataNodeView","m","mermaidReady","ensureMermaid","MermaidView","svg","setSvg","useState","error","setError","idRef","useRef","useEffect","cancelled","src","content","MathView","html","useMemo","HtmlView","srcDoc","color","fontSize","interactive","ImageView","AIView","messages","setMessages","input","setInput","streaming","setStreaming","abortRef","scrollRef","canSend","config","send","text","next","ac","acc","delta","streamAIChat","copy","last","node","i","MediaContent","kind","textColor","resolveThemeColorCss","resolveThemeColor","Model3DView","useSharedAIConfig","aiConfig"],"sources":["../../../../../src/components/pro/Flow/nodes/MediaContent.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useRef, useState } from 'react';\nimport katex from 'katex';\nimport mermaid from 'mermaid';\nimport Markdown from '../../../Markdown';\nimport type { FlowNode, FlowAIConfig } from '../types';\nimport { streamAIChat, type AIChatMessage } from './aiClient';\nimport { resolveThemeColorCss, resolveThemeColor } from '../utils/themeColor';\nimport 'katex/dist/katex.min.css';\nimport { Model3DView } from './Model3DView';\n\n// Data-node view pulls in DataTable + Chart; lazy-load so it only enters the\n// bundle when a data node actually renders.\nconst DataNodeView = React.lazy(() =>\n import('./DataNodeView').then((m) => ({ default: m.DataNodeView })),\n);\n\nlet mermaidReady = false;\nfunction ensureMermaid() {\n if (mermaidReady) return;\n mermaid.initialize({ startOnLoad: false, theme: 'default', securityLevel: 'loose', fontFamily: 'inherit' });\n mermaidReady = true;\n}\n\n/** Renders a Mermaid diagram from source into an inline SVG. */\nfunction MermaidView({ content, color }: { content: string; color?: string }) {\n const [svg, setSvg] = useState('');\n const [error, setError] = useState<string | null>(null);\n const idRef = useRef(`flow-mermaid-${Math.random().toString(36).slice(2)}`);\n\n useEffect(() => {\n let cancelled = false;\n ensureMermaid();\n const src = content.trim();\n if (!src) { setSvg(''); setError(null); return; }\n mermaid\n .render(idRef.current, src)\n .then(({ svg }) => { if (!cancelled) { setSvg(svg); setError(null); } })\n .catch((e) => { if (!cancelled) setError(e?.message ?? 'Mermaid error'); });\n return () => { cancelled = true; };\n }, [content]);\n\n if (error) return <div className=\"flow-media-error\">{error}</div>;\n return <div className=\"flow-media-mermaid\" style={{ color }} dangerouslySetInnerHTML={{ __html: svg }} />;\n}\n\n/** Renders a LaTeX formula (display mode) via KaTeX. */\nfunction MathView({ content, color, fontSize }: { content: string; color?: string; fontSize?: number }) {\n const html = useMemo(() => {\n try {\n return katex.renderToString(content.trim() || '\\\\;', { displayMode: true, throwOnError: false });\n } catch (e: any) {\n return `<span class=\"flow-media-error\">${e?.message ?? 'KaTeX error'}</span>`;\n }\n }, [content]);\n return <div className=\"flow-media-math\" style={{ color, fontSize }} dangerouslySetInnerHTML={{ __html: html }} />;\n}\n\n/** Renders raw HTML in a sandboxed iframe (isolated from the host document).\n * A base stylesheet is injected so the fragment inherits the node's themed\n * text color / font size and a transparent background, keeping it readable on\n * any theme without the author having to set colors.\n * Content is always untrusted: scripts can drive the preview, but the opaque\n * sandbox origin prevents host DOM/storage access. Do not add allow-same-origin\n * alongside allow-scripts; interactive only controls pointer input. */\nfunction HtmlView({ content, interactive, color, fontSize }: { content: string; interactive: boolean; color?: string; fontSize?: number }) {\n const srcDoc = useMemo(() => {\n const base = `<!doctype html><html><head><meta charset=\"utf-8\"><style>\n :root { color-scheme: light dark; }\n html, body { margin: 0; background: transparent; }\n body {\n color: ${color ?? '#111827'};\n font-size: ${fontSize ?? 13}px;\n font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif;\n line-height: 1.5;\n padding: 0;\n }\n a { color: inherit; }\n </style></head><body>${content}</body></html>`;\n return base;\n }, [content, color, fontSize]);\n return (\n <iframe\n title=\"html-media\"\n className=\"flow-media-iframe\"\n style={{ pointerEvents: interactive ? 'auto' : 'none' }}\n sandbox=\"allow-scripts\"\n srcDoc={srcDoc}\n />\n );\n}\n\nfunction ImageView({ content }: { content: string }) {\n const src = content.trim();\n if (!src) {\n return <div className=\"flow-media-image-empty\">输入图片链接,或直接粘贴图片</div>;\n }\n return (\n <img\n className=\"flow-media-image\"\n src={src}\n alt=\"\"\n draggable={false}\n referrerPolicy=\"no-referrer\"\n />\n );\n}\n\n/** Interactive AI chat backed by an OpenAI/Anthropic-compatible endpoint. */\nfunction AIView({ node, config, interactive, color }: { node: FlowNode; config?: FlowAIConfig; interactive: boolean; color?: string }) {\n const [messages, setMessages] = useState<AIChatMessage[]>([]);\n const [input, setInput] = useState('');\n const [streaming, setStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const scrollRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }, [messages, streaming]);\n\n useEffect(() => () => abortRef.current?.abort(), []);\n\n const canSend = !!config?.gateway && !!config?.model && !streaming;\n\n const send = async () => {\n const text = input.trim();\n if (!text || !config?.gateway) return;\n setError(null);\n // Only keep non-empty assistant messages in history; an aborted/errored\n // request can leave an empty assistant placeholder behind, which the API\n // then rejects (\"assistant message must not be empty\").\n const history = messages.filter(\n (m) => !(m.role === 'assistant' && m.content.trim() === ''),\n );\n const next: AIChatMessage[] = [...history, { role: 'user', content: text }];\n setMessages(next);\n setInput('');\n setStreaming(true);\n const ac = new AbortController();\n abortRef.current = ac;\n let acc = '';\n setMessages((m) => [...m, { role: 'assistant', content: '' }]);\n try {\n for await (const delta of streamAIChat(config, next, ac.signal)) {\n acc += delta;\n setMessages((m) => {\n const copy = m.slice();\n copy[copy.length - 1] = { role: 'assistant', content: acc };\n return copy;\n });\n }\n } catch (e: any) {\n if (e?.name !== 'AbortError') setError(e?.message ?? 'Request failed');\n } finally {\n // Drop the trailing assistant placeholder if nothing streamed in.\n setMessages((m) => {\n const last = m[m.length - 1];\n if (last && last.role === 'assistant' && last.content.trim() === '') {\n return m.slice(0, -1);\n }\n return m;\n });\n setStreaming(false);\n abortRef.current = null;\n }\n };\n\n return (\n <div className=\"flow-media-ai\" style={{ color }}>\n <div className=\"flow-media-ai-header\">\n {config?.model ? `AI · ${config.model}` : (node.data.label || 'AI')}\n </div>\n <div className=\"flow-media-ai-log\" ref={scrollRef}>\n {messages.length === 0 && (\n <div className=\"flow-media-ai-empty\">\n {config?.gateway ? '开始对话…' : '请先配置 AI 接口'}\n </div>\n )}\n {messages.map((m, i) => (\n <div key={i} className={`flow-media-ai-msg flow-media-ai-msg--${m.role}`}>\n {m.role === 'assistant'\n ? <Markdown content={m.content || '…'} enableMermaid={false} enableMarkmap={false} />\n : <span>{m.content}</span>}\n </div>\n ))}\n {error && <div className=\"flow-media-error\">{error}</div>}\n </div>\n <div className=\"flow-media-ai-input\" style={{ pointerEvents: interactive ? 'auto' : 'none' }}>\n <textarea\n value={input}\n placeholder=\"输入消息,Enter 发送\"\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); if (canSend) send(); }\n }}\n onPointerDown={(e) => e.stopPropagation()}\n />\n {streaming ? (\n <button type=\"button\" onClick={() => abortRef.current?.abort()}>停止</button>\n ) : (\n <button type=\"button\" disabled={!canSend || !input.trim()} onClick={send}>发送</button>\n )}\n </div>\n </div>\n );\n}\n\n/** Dispatches to the correct renderer for the node's media kind. */\nexport function MediaContent({ node, interactive, aiConfig, useSharedAIConfig = false }: { node: FlowNode; interactive: boolean; aiConfig?: FlowAIConfig; useSharedAIConfig?: boolean }) {\n const kind = node.data.mediaKind ?? 'markdown';\n const content = node.data.mediaContent ?? '';\n const textColor = resolveThemeColorCss(node.data.labelColor ?? node.data.color, '#111827');\n\n switch (kind) {\n case 'markdown':\n return (\n <div className=\"flow-media-markdown\" style={{ color: textColor, fontSize: node.data.fontSize }}>\n <Markdown content={content} />\n </div>\n );\n case 'html':\n // The iframe is an isolated document with no access to the parent's CSS\n // variables, so pass a concrete resolved color instead of a var().\n return (\n <HtmlView\n content={content}\n interactive={interactive}\n color={resolveThemeColor(node.data.labelColor ?? node.data.color, '#111827')}\n fontSize={node.data.fontSize}\n />\n );\n case 'mermaid':\n return <MermaidView content={content} color={textColor} />;\n case 'math':\n return <MathView content={content} color={textColor} fontSize={node.data.fontSize} />;\n case 'image':\n return <ImageView content={content} />;\n case 'model3d':\n return (\n <Model3DView\n content={content}\n format={node.data.modelFormat ?? 'stl'}\n interactive={interactive}\n />\n );\n case 'ai':\n return <AIView node={node} config={useSharedAIConfig ? aiConfig : node.data.aiConfig} interactive={interactive} color={textColor} />;\n case 'data':\n return (\n <div className=\"flow-media-data\" style={{ pointerEvents: interactive ? 'auto' : 'none' }}>\n <DataNodeView\n config={node.data.dataConfig ?? { columns: [], rows: [], view: 'table' }}\n surfaceColor={node.data.fill === 'transparent' ? undefined : resolveThemeColorCss(node.data.fill, '')}\n textColor={textColor}\n primaryColor={resolveThemeColorCss(node.data.color, '')}\n />\n </div>\n );\n default:\n return null;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MediaOverlay.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/MediaOverlay.tsx"],"sourcesContent":["import React, { useMemo, Suspense } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { useFlowAI } from '../context/FlowAIContext';\nimport { resolveThemeColorCss } from '../utils/themeColor';\n\n// Lazy-load the media renderers so the heavy optional deps they pull in\n// (react-markdown, mermaid, katex, markmap, …) are only fetched when a media\n// node actually needs to render. This keeps the base `dishui/flow` bundle\n// lightweight and avoids loading that stack for diagrams without media nodes.\n// Viewport-only updates move the outer box, not the live media subtree. Keep\n// nodes mounted offscreen so iframe/AI state and model camera state survive.\nconst MediaContent = React.memo(React.lazy(() =>\n import('./MediaContent').then((m) => ({ default: m.MediaContent })),\n));\n\n/** Isolates media render/load failures so one bad node never blanks the editor. */\nclass MediaErrorBoundary extends React.Component<\n { children: React.ReactNode },\n { error: Error | null }\n> {\n constructor(props: { children: React.ReactNode }) {\n super(props);\n this.state = { error: null };\n }\n static getDerivedStateFromError(error: Error) {\n return { error };\n }\n render() {\n if (this.state.error) {\n return <div className=\"flow-media-error\">{this.state.error.message}</div>;\n }\n return this.props.children;\n }\n}\n\n/**\n * DOM overlay for media nodes. PixiJS draws the frame; this layer renders the\n * live content (markdown/html/mermaid/math/AI) on top, synced to the viewport\n * so it pans and zooms with the canvas.\n *\n * Event model: a media surface is `pointer-events: none` by default so the\n * canvas underneath can be clicked to select/drag the node's frame. The\n * surface only becomes interactive while its node is selected (so AI chat can\n * be typed into, HTML can be scrolled). This also stops an always-interactive\n * iframe/AI box from swallowing pointer gestures and leaving the drag stuck.\n */\nexport function MediaOverlay() {\n const { currentCanvas, selection } = useFlowContext();\n const { viewport, isNodeDragging, readOnly } = useFlowUI();\n const { aiConfig, hasSharedConfig } = useFlowAI();\n\n const mediaNodes = useMemo(\n () => currentCanvas.nodes.filter((n) => n.type === 'mediaNode'),\n [currentCanvas.nodes],\n );\n\n if (mediaNodes.length === 0) return null;\n\n const { x: vx, y: vy, zoom } = viewport;\n\n return (\n <div className=\"flow-media-layer\">\n {mediaNodes.map((node) => {\n // World → screen (CSS px, matching ViewportManager.worldToScreen).\n const left = node.position.x * zoom + vx;\n const top = node.position.y * zoom + vy;\n // Interactive only while selected, so the canvas stays draggable.\n // Suppress entirely during a drag: an interactive iframe would swallow\n // the pointer and the canvas would never receive pointerup (stuck drag).\n const interactive = (selection.nodeIds.has(node.id) || (readOnly && node.data.mediaKind === 'ai')) && !isNodeDragging;\n // Drive the overlay's background / text from the node's own color data.\n // Theme tokens (`theme:*`) resolve to CSS variables so the media content\n // follows theme switches natively; literal colors are used as-is. This\n // keeps html / ai / data (which render opaque content) in sync with the\n // fill/color chosen in the inspector, matching the PixiJS frame drawn\n // underneath. The border is owned by the Pixi frame (also what PNG/PDF\n // export captures), so we don't redraw it here.\n const fillCss = node.data.fill === 'transparent'\n ? 'transparent'\n : resolveThemeColorCss(node.data.fill, 'transparent');\n const textColor = resolveThemeColorCss(node.data.labelColor ?? node.data.color, '#111827');\n return (\n <div\n key={node.id}\n className=\"flow-media-node\"\n data-media-node={node.id}\n style={{\n position: 'absolute',\n left,\n top,\n width: node.width,\n height: node.height,\n // Scale the fixed-size content box to match zoom without\n // reflowing text on every zoom step.\n transform: `scale(${zoom})`,\n transformOrigin: 'top left',\n // Below the frame's selection outline but above the canvas.\n pointerEvents: 'none',\n }}\n >\n <div\n className=\"flow-media-surface\"\n onWheel={(e) => e.stopPropagation()}\n style={{\n background: fillCss,\n color: textColor,\n }}\n >\n <Suspense fallback={<div className=\"flow-media-loading\">…</div>}>\n <MediaErrorBoundary>\n <MediaContent node={node} interactive={interactive} aiConfig={aiConfig} useSharedAIConfig={hasSharedConfig} />\n </MediaErrorBoundary>\n </Suspense>\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAYA,IAAM,IAAe,EAAM,KAAK,EAAM,WACpC,OAAO,oBAAiB,CAAC,MAAM,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CACpE,CAAC,GAGK,IAAN,cAAiC,EAAM,UAGrC;CACA,YAAY,GAAsC;EAEhD,AADA,MAAM,CAAK,GACX,KAAK,QAAQ,EAAE,OAAO,KAAK;CAC7B;CACA,OAAO,yBAAyB,GAAc;EAC5C,OAAO,EAAE,SAAM;CACjB;CACA,SAAS;EAIP,OAHI,KAAK,MAAM,QACN,kBAAC,OAAD;GAAK,WAAU;GAAoB,UAAA,KAAK,MAAM,MAAM;EAAa,CAAA,IAEnE,KAAK,MAAM;CACpB;AACF;AAaA,SAAgB,IAAe;CAC7B,IAAM,EAAE,kBAAe,iBAAc,EAAe,GAC9C,EAAE,aAAU,mBAAgB,gBAAa,EAAU,GACnD,EAAE,aAAU,uBAAoB,EAAU,GAE1C,IAAa,QACX,EAAc,MAAM,QAAQ,MAAM,EAAE,SAAS,WAAW,GAC9D,CAAC,EAAc,KAAK,CACtB;CAEA,IAAI,EAAW,WAAW,GAAG,OAAO;CAEpC,IAAM,EAAE,GAAG,GAAI,GAAG,GAAI,YAAS;CAE/B,OACE,kBAAC,OAAD;EAAK,WAAU;EACZ,UAAA,EAAW,KAAK,MAAS;GAExB,IAAM,IAAO,EAAK,SAAS,IAAI,IAAO,GAChC,IAAM,EAAK,SAAS,IAAI,IAAO,GAI/B,KAAe,EAAU,QAAQ,IAAI,EAAK,EAAE,KAAM,KAAY,EAAK,KAAK,cAAc,SAAU,CAAC,GAQjG,IAAU,EAAK,KAAK,SAAS,gBAC/B,gBACA,EAAqB,EAAK,KAAK,MAAM,aAAa,GAChD,IAAY,EAAqB,EAAK,KAAK,cAAc,EAAK,KAAK,OAAO,SAAS;GACzF,OACE,kBAAC,OAAD;IAEE,WAAU;IACV,mBAAiB,EAAK;IACtB,OAAO;KACL,UAAU;KACV;KACA;KACA,OAAO,EAAK;KACZ,QAAQ,EAAK;KAGb,WAAW,SAAS,EAAK;KACzB,iBAAiB;KAEjB,eAAe;IACjB;IAEA,UAAA,kBAAC,OAAD;KACE,WAAU;KACV,UAAU,MAAM,EAAE,gBAAgB;KAClC,OAAO;MACL,YAAY;MACZ,OAAO;KACT;KAEA,UAAA,kBAAC,GAAD;MAAU,UAAU,kBAAC,OAAD;OAAK,WAAU;OAAqB,UAAA;MAAM,CAAA;MAC5D,UAAA,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAoB;OAAmB;OAAuB;OAAU,mBAAmB;MAAkB,CAAA,EAC3F,CAAA;KACZ,CAAA;IACP,CAAA;GACF,GA/BE,EAAK,EA+BP;EAET,CAAC;CACE,CAAA;AAET"}
1
+ {"version":3,"file":"MediaOverlay.js","names":["React","MediaContent","m","MediaErrorBoundary","props","MediaOverlay","useFlowContext","useFlowUI","useFlowAI","mediaNodes","useMemo","currentCanvas","n","vx","vy","viewport","left","node","zoom","top","interactive","selection","readOnly","isNodeDragging","fillCss","resolveThemeColorCss","textColor","Suspense","hasSharedConfig"],"sources":["../../../../../src/components/pro/Flow/nodes/MediaOverlay.tsx"],"sourcesContent":["import React, { useMemo, Suspense } from 'react';\nimport { useFlowContext } from '../context/FlowContext';\nimport { useFlowUI } from '../context/FlowUIContext';\nimport { useFlowAI } from '../context/FlowAIContext';\nimport { resolveThemeColorCss } from '../utils/themeColor';\n\n// Lazy-load the media renderers so the heavy optional deps they pull in\n// (react-markdown, mermaid, katex, markmap, …) are only fetched when a media\n// node actually needs to render. This keeps the base `dishui/flow` bundle\n// lightweight and avoids loading that stack for diagrams without media nodes.\n// Viewport-only updates move the outer box, not the live media subtree. Keep\n// nodes mounted offscreen so iframe/AI state and model camera state survive.\nconst MediaContent = React.memo(React.lazy(() =>\n import('./MediaContent').then((m) => ({ default: m.MediaContent })),\n));\n\n/** Isolates media render/load failures so one bad node never blanks the editor. */\nclass MediaErrorBoundary extends React.Component<\n { children: React.ReactNode },\n { error: Error | null }\n> {\n constructor(props: { children: React.ReactNode }) {\n super(props);\n this.state = { error: null };\n }\n static getDerivedStateFromError(error: Error) {\n return { error };\n }\n render() {\n if (this.state.error) {\n return <div className=\"flow-media-error\">{this.state.error.message}</div>;\n }\n return this.props.children;\n }\n}\n\n/**\n * DOM overlay for media nodes. PixiJS draws the frame; this layer renders the\n * live content (markdown/html/mermaid/math/AI) on top, synced to the viewport\n * so it pans and zooms with the canvas.\n *\n * Event model: a media surface is `pointer-events: none` by default so the\n * canvas underneath can be clicked to select/drag the node's frame. The\n * surface only becomes interactive while its node is selected (so AI chat can\n * be typed into, HTML can be scrolled). This also stops an always-interactive\n * iframe/AI box from swallowing pointer gestures and leaving the drag stuck.\n */\nexport function MediaOverlay() {\n const { currentCanvas, selection } = useFlowContext();\n const { viewport, isNodeDragging, readOnly } = useFlowUI();\n const { aiConfig, hasSharedConfig } = useFlowAI();\n\n const mediaNodes = useMemo(\n () => currentCanvas.nodes.filter((n) => n.type === 'mediaNode'),\n [currentCanvas.nodes],\n );\n\n if (mediaNodes.length === 0) return null;\n\n const { x: vx, y: vy, zoom } = viewport;\n\n return (\n <div className=\"flow-media-layer\">\n {mediaNodes.map((node) => {\n // World → screen (CSS px, matching ViewportManager.worldToScreen).\n const left = node.position.x * zoom + vx;\n const top = node.position.y * zoom + vy;\n // Interactive only while selected, so the canvas stays draggable.\n // Suppress entirely during a drag: an interactive iframe would swallow\n // the pointer and the canvas would never receive pointerup (stuck drag).\n const interactive = (selection.nodeIds.has(node.id) || (readOnly && node.data.mediaKind === 'ai')) && !isNodeDragging;\n // Drive the overlay's background / text from the node's own color data.\n // Theme tokens (`theme:*`) resolve to CSS variables so the media content\n // follows theme switches natively; literal colors are used as-is. This\n // keeps html / ai / data (which render opaque content) in sync with the\n // fill/color chosen in the inspector, matching the PixiJS frame drawn\n // underneath. The border is owned by the Pixi frame (also what PNG/PDF\n // export captures), so we don't redraw it here.\n const fillCss = node.data.fill === 'transparent'\n ? 'transparent'\n : resolveThemeColorCss(node.data.fill, 'transparent');\n const textColor = resolveThemeColorCss(node.data.labelColor ?? node.data.color, '#111827');\n return (\n <div\n key={node.id}\n className=\"flow-media-node\"\n data-media-node={node.id}\n style={{\n position: 'absolute',\n left,\n top,\n width: node.width,\n height: node.height,\n // Scale the fixed-size content box to match zoom without\n // reflowing text on every zoom step.\n transform: `scale(${zoom})`,\n transformOrigin: 'top left',\n // Below the frame's selection outline but above the canvas.\n pointerEvents: 'none',\n }}\n >\n <div\n className=\"flow-media-surface\"\n onWheel={(e) => e.stopPropagation()}\n style={{\n background: fillCss,\n color: textColor,\n }}\n >\n <Suspense fallback={<div className=\"flow-media-loading\">…</div>}>\n <MediaErrorBoundary>\n <MediaContent node={node} interactive={interactive} aiConfig={aiConfig} useSharedAIConfig={hasSharedConfig} />\n </MediaErrorBoundary>\n </Suspense>\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;AAYA,IAAMC,IAAeD,EAAM,KAAKA,EAAM,WACpC,OAAO,oBAAiB,CAAC,MAAM,OAAO,EAAE,SAASE,EAAE,aAAa,EAAE,CACpE,CAAC,GAGKC,IAAN,cAAiCH,EAAM,UAGrC;CACA,YAAY,GAAsC;EAEhD,AADA,MAAMI,CAAK,GACX,KAAK,QAAQ,EAAE,OAAO,KAAK;CAC7B;CACA,OAAO,yBAAyB,GAAc;EAC5C,OAAO,EAAE,SAAM;CACjB;CACA,SAAS;EAIP,OAHI,KAAK,MAAM,QACN,kBAAC,OAAD;GAAK,WAAU;GAAoB,UAAA,KAAK,MAAM,MAAM;EAAa,CAAA,IAEnE,KAAK,MAAM;CACpB;AACF;AAaA,SAAgBC,IAAe;CAC7B,IAAM,EAAE,kBAAe,iBAAcC,EAAe,GAC9C,EAAE,aAAU,mBAAgB,gBAAaC,EAAU,GACnD,EAAE,aAAU,uBAAoBC,EAAU,GAE1CC,IAAaC,QACXC,EAAc,MAAM,QAAQ,MAAMC,EAAE,SAAS,WAAW,GAC9D,CAACD,EAAc,KAAK,CACtB;CAEA,IAAIF,EAAW,WAAW,GAAG,OAAO;CAEpC,IAAM,EAAE,GAAGI,GAAI,GAAGC,GAAI,YAASC;CAE/B,OACE,kBAAC,OAAD;EAAK,WAAU;EACZ,UAAAN,EAAW,KAAK,MAAS;GAExB,IAAMO,IAAOC,EAAK,SAAS,IAAIC,IAAOL,GAChCM,IAAMF,EAAK,SAAS,IAAIC,IAAOJ,GAI/BM,KAAeC,EAAU,QAAQ,IAAIJ,EAAK,EAAE,KAAMK,KAAYL,EAAK,KAAK,cAAc,SAAU,CAACM,GAQjGC,IAAUP,EAAK,KAAK,SAAS,gBAC/B,gBACAQ,EAAqBR,EAAK,KAAK,MAAM,aAAa,GAChDS,IAAYD,EAAqBR,EAAK,KAAK,cAAcA,EAAK,KAAK,OAAO,SAAS;GACzF,OACE,kBAAC,OAAD;IAEE,WAAU;IACV,mBAAiBA,EAAK;IACtB,OAAO;KACL,UAAU;KACV;KACA;KACA,OAAOA,EAAK;KACZ,QAAQA,EAAK;KAGb,WAAW,SAASC,EAAK;KACzB,iBAAiB;KAEjB,eAAe;IACjB;IAEA,UAAA,kBAAC,OAAD;KACE,WAAU;KACV,UAAU,MAAM,EAAE,gBAAgB;KAClC,OAAO;MACL,YAAYM;MACZ,OAAOE;KACT;KAEA,UAAA,kBAACC,GAAD;MAAU,UAAU,kBAAC,OAAD;OAAK,WAAU;OAAqB,UAAA;MAAM,CAAA;MAC5D,UAAA,kBAACxB,GAAD,EAAA,UACE,kBAACF,GAAD;OAAoB;OAAmB;OAAuB;OAAU,mBAAmB2B;MAAkB,CAAA,EAC3F,CAAA;KACZ,CAAA;IACP,CAAA;GACF,GA/BEX,EAAK,EA+BP;EAET,CAAC;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"Model3DView.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/Model3DView.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport * as THREE from 'three';\nimport { OrbitControls } from 'three/addons/controls/OrbitControls.js';\nimport { ThreeMFLoader } from 'three/addons/loaders/3MFLoader.js';\nimport { OBJLoader } from 'three/addons/loaders/OBJLoader.js';\nimport { STLLoader } from 'three/addons/loaders/STLLoader.js';\nimport type { FlowModelFormat } from '../types';\nimport { createDemandRender } from './demandRender';\n\nfunction disposeObject(root: any) {\n const materials = new Set<any>();\n const textures = new Set<any>();\n root.traverse((object: any) => {\n if (!(object instanceof THREE.Mesh)) return;\n object.geometry?.dispose();\n const list = Array.isArray(object.material) ? object.material : [object.material];\n for (const material of list) {\n if (!material || materials.has(material)) continue;\n materials.add(material);\n for (const value of Object.values(material)) {\n if (value instanceof THREE.Texture) textures.add(value);\n }\n }\n });\n for (const texture of textures) texture.dispose();\n for (const material of materials) material.dispose();\n}\n\nfunction parseModel(format: FlowModelFormat, data: ArrayBuffer): any {\n if (format === 'stl') {\n const geometry = new STLLoader().parse(data);\n if (!geometry.getAttribute('normal')) geometry.computeVertexNormals();\n return new THREE.Mesh(\n geometry,\n new THREE.MeshStandardMaterial({\n color: 0xb8c2cc,\n metalness: 0.05,\n roughness: 0.72,\n side: THREE.DoubleSide,\n }),\n );\n }\n if (format === 'obj') {\n return new OBJLoader().parse(new TextDecoder().decode(data));\n }\n return new ThreeMFLoader().parse(data);\n}\n\nexport function Model3DView({\n content,\n format,\n interactive,\n}: {\n content: string;\n format: FlowModelFormat;\n interactive: boolean;\n}) {\n const hostRef = useRef<HTMLDivElement>(null);\n const controlsRef = useRef<OrbitControls | null>(null);\n const interactiveRef = useRef(interactive);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n useEffect(() => {\n interactiveRef.current = interactive;\n if (controlsRef.current) controlsRef.current.enabled = interactive;\n }, [interactive]);\n\n useEffect(() => {\n const host = hostRef.current;\n const source = content.trim();\n if (!host || !source) return;\n\n let cancelled = false;\n let model: any = null;\n const abort = new AbortController();\n const scene = new THREE.Scene();\n const camera = new THREE.PerspectiveCamera(45, 1, 0.01, 10000);\n const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });\n renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));\n renderer.outputColorSpace = THREE.SRGBColorSpace;\n renderer.setClearColor(0x000000, 0);\n host.appendChild(renderer.domElement);\n\n scene.add(new THREE.HemisphereLight(0xffffff, 0x445066, 2));\n const directional = new THREE.DirectionalLight(0xffffff, 2.4);\n directional.position.set(3, 5, 4);\n scene.add(directional);\n\n const controls = new OrbitControls(camera, renderer.domElement);\n controls.enableDamping = true;\n controls.enabled = interactiveRef.current;\n controlsRef.current = controls;\n\n const drawing = createDemandRender({\n update: () => controls.update(),\n render: () => renderer.render(scene, camera),\n });\n controls.addEventListener('change', drawing.invalidate);\n // Observe the actual DOM box, including overlay transforms and clipping.\n // Pausing keeps the loaded model, camera and WebGL context intact.\n let intersecting = typeof IntersectionObserver === 'undefined';\n const updateVisibility = () => drawing.setActive(intersecting && !document.hidden);\n const visibilityObserver = typeof IntersectionObserver === 'undefined' ? null : new IntersectionObserver(entries => {\n intersecting = entries.some(entry => entry.isIntersecting && entry.intersectionRect.width > 0 && entry.intersectionRect.height > 0);\n updateVisibility();\n });\n visibilityObserver?.observe(host);\n document.addEventListener('visibilitychange', updateVisibility);\n updateVisibility();\n\n const resize = () => {\n const width = Math.max(1, host.clientWidth);\n const height = Math.max(1, host.clientHeight);\n renderer.setSize(width, height, false);\n camera.aspect = width / height;\n camera.updateProjectionMatrix();\n drawing.invalidate();\n };\n resize();\n const observer = new ResizeObserver(resize);\n observer.observe(host);\n\n setLoading(true);\n setError(null);\n fetch(source, { signal: abort.signal })\n .then(response => {\n if (!response.ok) throw new Error(`模型加载失败:HTTP ${response.status}`);\n return response.arrayBuffer();\n })\n .then(data => {\n if (data.byteLength > 50 * 1024 * 1024) throw new Error('模型超过 50 MiB,无法加载');\n const root = parseModel(format, data);\n if (cancelled) {\n disposeObject(root);\n return;\n }\n model = root;\n root.updateMatrixWorld(true);\n const box = new THREE.Box3().setFromObject(root);\n if (box.isEmpty()) throw new Error('模型不包含可显示的几何体');\n const center = box.getCenter(new THREE.Vector3());\n root.position.sub(center);\n root.updateMatrixWorld(true);\n const sphere = new THREE.Box3().setFromObject(root).getBoundingSphere(new THREE.Sphere());\n if (!Number.isFinite(sphere.radius) || sphere.radius <= 0) throw new Error('模型尺寸无效');\n scene.add(root);\n\n const halfFovY = THREE.MathUtils.degToRad(camera.fov / 2);\n const halfFovX = Math.atan(Math.tan(halfFovY) * camera.aspect);\n const distance = (sphere.radius / Math.sin(Math.min(halfFovX, halfFovY))) * 1.15;\n camera.position.copy(new THREE.Vector3(1, 0.75, 1).normalize().multiplyScalar(distance));\n camera.near = Math.max(sphere.radius / 1000, 0.001);\n camera.far = Math.max(distance + sphere.radius * 10, sphere.radius * 1000);\n camera.updateProjectionMatrix();\n controls.target.set(0, 0, 0);\n controls.minDistance = sphere.radius * 0.05;\n controls.maxDistance = sphere.radius * 100;\n drawing.invalidate();\n })\n .catch(nextError => {\n if (!cancelled && nextError?.name !== 'AbortError') setError(nextError?.message ?? '模型加载失败');\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n abort.abort();\n drawing.dispose();\n observer.disconnect();\n visibilityObserver?.disconnect();\n document.removeEventListener('visibilitychange', updateVisibility);\n controls.removeEventListener('change', drawing.invalidate);\n controls.dispose();\n controlsRef.current = null;\n if (model) disposeObject(model);\n scene.clear();\n renderer.renderLists.dispose();\n renderer.dispose();\n renderer.forceContextLoss();\n renderer.domElement.remove();\n };\n }, [content, format]);\n\n if (!content.trim()) {\n return <div className=\"flow-media-image-empty\">输入 STL、OBJ 或 3MF 模型链接</div>;\n }\n\n return (\n <div\n ref={hostRef}\n className=\"flow-media-model3d\"\n style={{ pointerEvents: interactive ? 'auto' : 'none', touchAction: interactive ? 'none' : 'auto' }}\n onPointerDown={event => { if (interactive) event.stopPropagation(); }}\n onWheel={event => { if (interactive) event.stopPropagation(); }}\n >\n {loading && <div className=\"flow-media-loading flow-media-model3d-status\">加载模型…</div>}\n {error && <div className=\"flow-media-error flow-media-model3d-status\">{error}</div>}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Model3DView.js","names":["THREE","disposeObject","materials","textures","object","list","material","value","texture","parseModel","format","geometry","STLLoader","data","OBJLoader","ThreeMFLoader","Model3DView","hostRef","useRef","controlsRef","interactiveRef","interactive","error","setError","useState","loading","setLoading","useEffect","host","source","content","cancelled","model","abort","scene","camera","renderer","directional","controls","OrbitControls","drawing","createDemandRender","intersecting","updateVisibility","visibilityObserver","entries","entry","resize","width","height","observer","response","root","box","center","sphere","halfFovY","halfFovX","distance","nextError","event"],"sources":["../../../../../src/components/pro/Flow/nodes/Model3DView.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport * as THREE from 'three';\nimport { OrbitControls } from 'three/addons/controls/OrbitControls.js';\nimport { ThreeMFLoader } from 'three/addons/loaders/3MFLoader.js';\nimport { OBJLoader } from 'three/addons/loaders/OBJLoader.js';\nimport { STLLoader } from 'three/addons/loaders/STLLoader.js';\nimport type { FlowModelFormat } from '../types';\nimport { createDemandRender } from './demandRender';\n\nfunction disposeObject(root: any) {\n const materials = new Set<any>();\n const textures = new Set<any>();\n root.traverse((object: any) => {\n if (!(object instanceof THREE.Mesh)) return;\n object.geometry?.dispose();\n const list = Array.isArray(object.material) ? object.material : [object.material];\n for (const material of list) {\n if (!material || materials.has(material)) continue;\n materials.add(material);\n for (const value of Object.values(material)) {\n if (value instanceof THREE.Texture) textures.add(value);\n }\n }\n });\n for (const texture of textures) texture.dispose();\n for (const material of materials) material.dispose();\n}\n\nfunction parseModel(format: FlowModelFormat, data: ArrayBuffer): any {\n if (format === 'stl') {\n const geometry = new STLLoader().parse(data);\n if (!geometry.getAttribute('normal')) geometry.computeVertexNormals();\n return new THREE.Mesh(\n geometry,\n new THREE.MeshStandardMaterial({\n color: 0xb8c2cc,\n metalness: 0.05,\n roughness: 0.72,\n side: THREE.DoubleSide,\n }),\n );\n }\n if (format === 'obj') {\n return new OBJLoader().parse(new TextDecoder().decode(data));\n }\n return new ThreeMFLoader().parse(data);\n}\n\nexport function Model3DView({\n content,\n format,\n interactive,\n}: {\n content: string;\n format: FlowModelFormat;\n interactive: boolean;\n}) {\n const hostRef = useRef<HTMLDivElement>(null);\n const controlsRef = useRef<OrbitControls | null>(null);\n const interactiveRef = useRef(interactive);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n\n useEffect(() => {\n interactiveRef.current = interactive;\n if (controlsRef.current) controlsRef.current.enabled = interactive;\n }, [interactive]);\n\n useEffect(() => {\n const host = hostRef.current;\n const source = content.trim();\n if (!host || !source) return;\n\n let cancelled = false;\n let model: any = null;\n const abort = new AbortController();\n const scene = new THREE.Scene();\n const camera = new THREE.PerspectiveCamera(45, 1, 0.01, 10000);\n const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });\n renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));\n renderer.outputColorSpace = THREE.SRGBColorSpace;\n renderer.setClearColor(0x000000, 0);\n host.appendChild(renderer.domElement);\n\n scene.add(new THREE.HemisphereLight(0xffffff, 0x445066, 2));\n const directional = new THREE.DirectionalLight(0xffffff, 2.4);\n directional.position.set(3, 5, 4);\n scene.add(directional);\n\n const controls = new OrbitControls(camera, renderer.domElement);\n controls.enableDamping = true;\n controls.enabled = interactiveRef.current;\n controlsRef.current = controls;\n\n const drawing = createDemandRender({\n update: () => controls.update(),\n render: () => renderer.render(scene, camera),\n });\n controls.addEventListener('change', drawing.invalidate);\n // Observe the actual DOM box, including overlay transforms and clipping.\n // Pausing keeps the loaded model, camera and WebGL context intact.\n let intersecting = typeof IntersectionObserver === 'undefined';\n const updateVisibility = () => drawing.setActive(intersecting && !document.hidden);\n const visibilityObserver = typeof IntersectionObserver === 'undefined' ? null : new IntersectionObserver(entries => {\n intersecting = entries.some(entry => entry.isIntersecting && entry.intersectionRect.width > 0 && entry.intersectionRect.height > 0);\n updateVisibility();\n });\n visibilityObserver?.observe(host);\n document.addEventListener('visibilitychange', updateVisibility);\n updateVisibility();\n\n const resize = () => {\n const width = Math.max(1, host.clientWidth);\n const height = Math.max(1, host.clientHeight);\n renderer.setSize(width, height, false);\n camera.aspect = width / height;\n camera.updateProjectionMatrix();\n drawing.invalidate();\n };\n resize();\n const observer = new ResizeObserver(resize);\n observer.observe(host);\n\n setLoading(true);\n setError(null);\n fetch(source, { signal: abort.signal })\n .then(response => {\n if (!response.ok) throw new Error(`模型加载失败:HTTP ${response.status}`);\n return response.arrayBuffer();\n })\n .then(data => {\n if (data.byteLength > 50 * 1024 * 1024) throw new Error('模型超过 50 MiB,无法加载');\n const root = parseModel(format, data);\n if (cancelled) {\n disposeObject(root);\n return;\n }\n model = root;\n root.updateMatrixWorld(true);\n const box = new THREE.Box3().setFromObject(root);\n if (box.isEmpty()) throw new Error('模型不包含可显示的几何体');\n const center = box.getCenter(new THREE.Vector3());\n root.position.sub(center);\n root.updateMatrixWorld(true);\n const sphere = new THREE.Box3().setFromObject(root).getBoundingSphere(new THREE.Sphere());\n if (!Number.isFinite(sphere.radius) || sphere.radius <= 0) throw new Error('模型尺寸无效');\n scene.add(root);\n\n const halfFovY = THREE.MathUtils.degToRad(camera.fov / 2);\n const halfFovX = Math.atan(Math.tan(halfFovY) * camera.aspect);\n const distance = (sphere.radius / Math.sin(Math.min(halfFovX, halfFovY))) * 1.15;\n camera.position.copy(new THREE.Vector3(1, 0.75, 1).normalize().multiplyScalar(distance));\n camera.near = Math.max(sphere.radius / 1000, 0.001);\n camera.far = Math.max(distance + sphere.radius * 10, sphere.radius * 1000);\n camera.updateProjectionMatrix();\n controls.target.set(0, 0, 0);\n controls.minDistance = sphere.radius * 0.05;\n controls.maxDistance = sphere.radius * 100;\n drawing.invalidate();\n })\n .catch(nextError => {\n if (!cancelled && nextError?.name !== 'AbortError') setError(nextError?.message ?? '模型加载失败');\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => {\n cancelled = true;\n abort.abort();\n drawing.dispose();\n observer.disconnect();\n visibilityObserver?.disconnect();\n document.removeEventListener('visibilitychange', updateVisibility);\n controls.removeEventListener('change', drawing.invalidate);\n controls.dispose();\n controlsRef.current = null;\n if (model) disposeObject(model);\n scene.clear();\n renderer.renderLists.dispose();\n renderer.dispose();\n renderer.forceContextLoss();\n renderer.domElement.remove();\n };\n }, [content, format]);\n\n if (!content.trim()) {\n return <div className=\"flow-media-image-empty\">输入 STL、OBJ 或 3MF 模型链接</div>;\n }\n\n return (\n <div\n ref={hostRef}\n className=\"flow-media-model3d\"\n style={{ pointerEvents: interactive ? 'auto' : 'none', touchAction: interactive ? 'none' : 'auto' }}\n onPointerDown={event => { if (interactive) event.stopPropagation(); }}\n onWheel={event => { if (interactive) event.stopPropagation(); }}\n >\n {loading && <div className=\"flow-media-loading flow-media-model3d-status\">加载模型…</div>}\n {error && <div className=\"flow-media-error flow-media-model3d-status\">{error}</div>}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"NodeHandles.js","names":[],"sources":["../../../../../src/components/pro/Flow/nodes/NodeHandles.ts"],"sourcesContent":["import { Graphics, Container } from 'pixi.js';\nimport { HANDLE_SIZE } from '../constants';\nimport type { FlowNode } from '../types';\n\nexport interface HandleDef {\n id: string;\n x: number;\n y: number;\n side: 'top' | 'right' | 'bottom' | 'left';\n}\n\n/**\n * Creates 20 connection handle positions per node (5 per side).\n * Handles are invisible hit areas; shown on hover as small circles.\n * The positions divide each edge into six equal segments.\n */\nexport function getHandlePositions(width: number, height: number): HandleDef[] {\n const offsets = [1 / 6, 2 / 6, 3 / 6, 4 / 6, 5 / 6];\n const handles: HandleDef[] = [];\n\n for (const pct of offsets) {\n handles.push({ id: `t_${pct}`, x: width * pct, y: 0, side: 'top' });\n handles.push({ id: `b_${pct}`, x: width * pct, y: height, side: 'bottom' });\n handles.push({ id: `l_${pct}`, x: 0, y: height * pct, side: 'left' });\n handles.push({ id: `r_${pct}`, x: width, y: height * pct, side: 'right' });\n }\n return handles;\n}\n\nexport function createHandleGraphics(\n parent: Container,\n handles: HandleDef[],\n visible = false,\n): Graphics {\n const g = new Graphics();\n g.label = 'handles';\n g.visible = visible;\n g.eventMode = 'static';\n\n for (const h of handles) {\n g.circle(h.x, h.y, HANDLE_SIZE / 2)\n .fill({ color: 0x3b82f6, alpha: 0.9 });\n }\n\n parent.addChild(g);\n return g;\n}\n\nexport function updateHandleGraphics(\n g: Graphics,\n handles: HandleDef[],\n): void {\n g.clear();\n for (const h of handles) {\n g.circle(h.x, h.y, HANDLE_SIZE / 2)\n .fill({ color: 0x3b82f6, alpha: 0.9 });\n }\n}\n\n/**\n * Compute a handle's world-space position considering node rotation.\n */\nexport function handleWorldPos(\n h: HandleDef,\n node: FlowNode,\n): { x: number; y: number } {\n const deg = node.data.rotation ?? 0;\n const nx = node.position.x, ny = node.position.y;\n if (deg === 0) return { x: nx + h.x, y: ny + h.y };\n const rad = (deg * Math.PI) / 180;\n const cx = node.width / 2, cy = node.height / 2;\n const dx = h.x - cx, dy = h.y - cy;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n return {\n x: nx + cx + dx * cos - dy * sin,\n y: ny + cy + dx * sin + dy * cos,\n };\n}\n\n/** Find the closest handle to a world-space point */\nexport function findClosestHandle(\n handles: HandleDef[],\n nodeX: number,\n nodeY: number,\n worldX: number,\n worldY: number,\n threshold = 20,\n): HandleDef | null {\n let best: HandleDef | null = null;\n let bestDist = threshold;\n for (const h of handles) {\n const dx = (nodeX + h.x) - worldX;\n const dy = (nodeY + h.y) - worldY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < bestDist) {\n bestDist = dist;\n best = h;\n }\n }\n return best;\n}\n\n/**\n * Like findClosestHandle but accounts for node rotation.\n */\nexport function findClosestHandleWorld(\n handles: HandleDef[],\n node: FlowNode,\n worldX: number,\n worldY: number,\n threshold = 20,\n): HandleDef | null {\n const deg = node.data.rotation ?? 0;\n if (deg === 0) {\n return findClosestHandle(handles, node.position.x, node.position.y, worldX, worldY, threshold);\n }\n let best: HandleDef | null = null;\n let bestDist = threshold;\n for (const h of handles) {\n const wp = handleWorldPos(h, node);\n const dx = wp.x - worldX, dy = wp.y - worldY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < bestDist) { bestDist = dist; best = h; }\n }\n return best;\n}\n"],"mappings":";;AAgBA,SAAgB,EAAmB,GAAe,GAA6B;CAC7E,IAAM,IAAU;EAAC,IAAI;EAAG,IAAI;EAAG,IAAI;EAAG,IAAI;EAAG,IAAI;CAAC,GAC5C,IAAuB,CAAC;CAE9B,KAAK,IAAM,KAAO,GAIhB,AAHA,EAAQ,KAAK;EAAE,IAAI,KAAK;EAAO,GAAG,IAAQ;EAAK,GAAG;EAAG,MAAM;CAAM,CAAC,GAClE,EAAQ,KAAK;EAAE,IAAI,KAAK;EAAO,GAAG,IAAQ;EAAK,GAAG;EAAQ,MAAM;CAAS,CAAC,GAC1E,EAAQ,KAAK;EAAE,IAAI,KAAK;EAAO,GAAG;EAAG,GAAG,IAAS;EAAK,MAAM;CAAO,CAAC,GACpE,EAAQ,KAAK;EAAE,IAAI,KAAK;EAAO,GAAG;EAAO,GAAG,IAAS;EAAK,MAAM;CAAQ,CAAC;CAE3E,OAAO;AACT;AAEA,SAAgB,EACd,GACA,GACA,IAAU,IACA;CACV,IAAM,IAAI,IAAI,EAAS;CAGvB,AAFA,EAAE,QAAQ,WACV,EAAE,UAAU,GACZ,EAAE,YAAY;CAEd,KAAK,IAAM,KAAK,GACd,EAAE,OAAO,EAAE,GAAG,EAAE,GAAA,CAAkB,CAAC,CAChC,KAAK;EAAE,OAAO;EAAU,OAAO;CAAI,CAAC;CAIzC,OADA,EAAO,SAAS,CAAC,GACV;AACT;AAEA,SAAgB,EACd,GACA,GACM;CACN,EAAE,MAAM;CACR,KAAK,IAAM,KAAK,GACd,EAAE,OAAO,EAAE,GAAG,EAAE,GAAA,CAAkB,CAAC,CAChC,KAAK;EAAE,OAAO;EAAU,OAAO;CAAI,CAAC;AAE3C;AAKA,SAAgB,EACd,GACA,GAC0B;CAC1B,IAAM,IAAM,EAAK,KAAK,YAAY,GAC5B,IAAK,EAAK,SAAS,GAAG,IAAK,EAAK,SAAS;CAC/C,IAAI,MAAQ,GAAG,OAAO;EAAE,GAAG,IAAK,EAAE;EAAG,GAAG,IAAK,EAAE;CAAE;CACjD,IAAM,IAAO,IAAM,KAAK,KAAM,KACxB,IAAK,EAAK,QAAQ,GAAG,IAAK,EAAK,SAAS,GACxC,IAAK,EAAE,IAAI,GAAI,IAAK,EAAE,IAAI,GAC1B,IAAM,KAAK,IAAI,CAAG,GAAG,IAAM,KAAK,IAAI,CAAG;CAC7C,OAAO;EACL,GAAG,IAAK,IAAK,IAAK,IAAM,IAAK;EAC7B,GAAG,IAAK,IAAK,IAAK,IAAM,IAAK;CAC/B;AACF;AAGA,SAAgB,EACd,GACA,GACA,GACA,GACA,GACA,IAAY,IACM;CAClB,IAAI,IAAyB,MACzB,IAAW;CACf,KAAK,IAAM,KAAK,GAAS;EACvB,IAAM,IAAM,IAAQ,EAAE,IAAK,GACrB,IAAM,IAAQ,EAAE,IAAK,GACrB,IAAO,KAAK,KAAK,IAAK,IAAK,IAAK,CAAE;EACxC,AAAI,IAAO,MACT,IAAW,GACX,IAAO;CAEX;CACA,OAAO;AACT;AAKA,SAAgB,EACd,GACA,GACA,GACA,GACA,IAAY,IACM;CAElB,KADY,EAAK,KAAK,YAAY,OACtB,GACV,OAAO,EAAkB,GAAS,EAAK,SAAS,GAAG,EAAK,SAAS,GAAG,GAAQ,GAAQ,CAAS;CAE/F,IAAI,IAAyB,MACzB,IAAW;CACf,KAAK,IAAM,KAAK,GAAS;EACvB,IAAM,IAAK,EAAe,GAAG,CAAI,GAC3B,IAAK,EAAG,IAAI,GAAQ,IAAK,EAAG,IAAI,GAChC,IAAO,KAAK,KAAK,IAAK,IAAK,IAAK,CAAE;EACxC,AAAI,IAAO,MAAY,IAAW,GAAM,IAAO;CACjD;CACA,OAAO;AACT"}
1
+ {"version":3,"file":"NodeHandles.js","names":["getHandlePositions","offsets","handles","pct","width","height","createHandleGraphics","g","Graphics","visible","h","parent","updateHandleGraphics","handleWorldPos","deg","node","nx","ny","rad","cx","cy","dx","dy","cos","sin","findClosestHandle","best","bestDist","threshold","nodeX","worldX","nodeY","worldY","dist","findClosestHandleWorld","wp"],"sources":["../../../../../src/components/pro/Flow/nodes/NodeHandles.ts"],"sourcesContent":["import { Graphics, Container } from 'pixi.js';\nimport { HANDLE_SIZE } from '../constants';\nimport type { FlowNode } from '../types';\n\nexport interface HandleDef {\n id: string;\n x: number;\n y: number;\n side: 'top' | 'right' | 'bottom' | 'left';\n}\n\n/**\n * Creates 20 connection handle positions per node (5 per side).\n * Handles are invisible hit areas; shown on hover as small circles.\n * The positions divide each edge into six equal segments.\n */\nexport function getHandlePositions(width: number, height: number): HandleDef[] {\n const offsets = [1 / 6, 2 / 6, 3 / 6, 4 / 6, 5 / 6];\n const handles: HandleDef[] = [];\n\n for (const pct of offsets) {\n handles.push({ id: `t_${pct}`, x: width * pct, y: 0, side: 'top' });\n handles.push({ id: `b_${pct}`, x: width * pct, y: height, side: 'bottom' });\n handles.push({ id: `l_${pct}`, x: 0, y: height * pct, side: 'left' });\n handles.push({ id: `r_${pct}`, x: width, y: height * pct, side: 'right' });\n }\n return handles;\n}\n\nexport function createHandleGraphics(\n parent: Container,\n handles: HandleDef[],\n visible = false,\n): Graphics {\n const g = new Graphics();\n g.label = 'handles';\n g.visible = visible;\n g.eventMode = 'static';\n\n for (const h of handles) {\n g.circle(h.x, h.y, HANDLE_SIZE / 2)\n .fill({ color: 0x3b82f6, alpha: 0.9 });\n }\n\n parent.addChild(g);\n return g;\n}\n\nexport function updateHandleGraphics(\n g: Graphics,\n handles: HandleDef[],\n): void {\n g.clear();\n for (const h of handles) {\n g.circle(h.x, h.y, HANDLE_SIZE / 2)\n .fill({ color: 0x3b82f6, alpha: 0.9 });\n }\n}\n\n/**\n * Compute a handle's world-space position considering node rotation.\n */\nexport function handleWorldPos(\n h: HandleDef,\n node: FlowNode,\n): { x: number; y: number } {\n const deg = node.data.rotation ?? 0;\n const nx = node.position.x, ny = node.position.y;\n if (deg === 0) return { x: nx + h.x, y: ny + h.y };\n const rad = (deg * Math.PI) / 180;\n const cx = node.width / 2, cy = node.height / 2;\n const dx = h.x - cx, dy = h.y - cy;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n return {\n x: nx + cx + dx * cos - dy * sin,\n y: ny + cy + dx * sin + dy * cos,\n };\n}\n\n/** Find the closest handle to a world-space point */\nexport function findClosestHandle(\n handles: HandleDef[],\n nodeX: number,\n nodeY: number,\n worldX: number,\n worldY: number,\n threshold = 20,\n): HandleDef | null {\n let best: HandleDef | null = null;\n let bestDist = threshold;\n for (const h of handles) {\n const dx = (nodeX + h.x) - worldX;\n const dy = (nodeY + h.y) - worldY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < bestDist) {\n bestDist = dist;\n best = h;\n }\n }\n return best;\n}\n\n/**\n * Like findClosestHandle but accounts for node rotation.\n */\nexport function findClosestHandleWorld(\n handles: HandleDef[],\n node: FlowNode,\n worldX: number,\n worldY: number,\n threshold = 20,\n): HandleDef | null {\n const deg = node.data.rotation ?? 0;\n if (deg === 0) {\n return findClosestHandle(handles, node.position.x, node.position.y, worldX, worldY, threshold);\n }\n let best: HandleDef | null = null;\n let bestDist = threshold;\n for (const h of handles) {\n const wp = handleWorldPos(h, node);\n const dx = wp.x - worldX, dy = wp.y - worldY;\n const dist = Math.sqrt(dx * dx + dy * dy);\n if (dist < bestDist) { bestDist = dist; best = h; }\n }\n return best;\n}\n"],"mappings":"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"}