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":"index.js","names":[],"sources":["../../../../src/components/ai/StreamingText/index.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './StreamingText.css';\n\nexport type StreamingSource = {\n id: string;\n title: string;\n domain?: string;\n url?: string;\n favicon?: React.ReactNode;\n};\n\nexport type StreamingAction = {\n id: string;\n label: string;\n icon?: React.ReactNode;\n onClick?: () => void;\n};\n\nexport type StreamingFeedback = 'up' | 'down';\n\nexport type StreamingTextProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n /** Full or partial answer text. `\\n\\n` starts a new paragraph. */\n text: string;\n /** Shows the caret and hides actions / follow-ups until the answer is complete. */\n streaming?: boolean;\n /** Reveal `text` progressively on the client. Remount (key) to replay. */\n typewriter?: boolean;\n /** Characters revealed per tick in typewriter mode. */\n typewriterSpeed?: number;\n sources?: StreamingSource[];\n /** Render `[n]` markers in `text` as inline chips pointing at `sources[n - 1]`. */\n citations?: boolean;\n /** Source chips shown before the “+k” overflow toggle. */\n maxVisibleSources?: number;\n /** Extra actions appended after the built-in copy / regenerate / feedback buttons. */\n actions?: StreamingAction[];\n onCopy?: (text: string) => void;\n onRegenerate?: () => void;\n onFeedback?: (kind: StreamingFeedback) => void;\n followUps?: string[];\n onFollowUp?: (question: string) => void;\n followUpsLabel?: React.ReactNode;\n};\n\nconst TYPEWRITER_TICK_MS = 30;\n\nconst svgProps = { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': true } as const;\nconst CopyIcon = () => (\n <svg {...svgProps}><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" /><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" /></svg>\n);\nconst RefreshIcon = () => (\n <svg {...svgProps}><path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" /><path d=\"M21 3v5h-5\" /><path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" /><path d=\"M8 16H3v5\" /></svg>\n);\nconst ThumbsUpIcon = () => (\n <svg {...svgProps}><path d=\"M7 10v12\" /><path d=\"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z\" /></svg>\n);\nconst ThumbsDownIcon = () => (\n <svg {...svgProps}><path d=\"M17 14V2\" /><path d=\"M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z\" /></svg>\n);\nconst ArrowIcon = () => (\n <svg {...svgProps}><path d=\"M7 17 17 7\" /><path d=\"M7 7h10v10\" /></svg>\n);\n\nconst CITATION_RE = /\\[(\\d+)\\]/g;\n\nconst initialOf = (source: StreamingSource) => (source.domain ?? source.title).trim().charAt(0).toUpperCase();\n\nfunction renderLine(line: string, sources: StreamingSource[] | undefined, citations: boolean, keyBase: string): React.ReactNode[] {\n if (!citations) return [line];\n const nodes: React.ReactNode[] = [];\n let last = 0;\n let match: RegExpExecArray | null;\n CITATION_RE.lastIndex = 0;\n while ((match = CITATION_RE.exec(line)) !== null) {\n if (match.index > last) nodes.push(line.slice(last, match.index));\n const n = Number(match[1]);\n const source = sources?.[n - 1];\n const label = source ? source.title : `Source ${n}`;\n nodes.push(\n source?.url ? (\n <a key={`${keyBase}-${match.index}`} className=\"dishui-ai-streaming__cite\" href={source.url} target=\"_blank\" rel=\"noreferrer\" title={label} aria-label={label}>{n}</a>\n ) : (\n <span key={`${keyBase}-${match.index}`} className=\"dishui-ai-streaming__cite\" title={label} aria-label={label} role=\"note\">{n}</span>\n ),\n );\n last = match.index + match[0].length;\n }\n if (last < line.length) nodes.push(line.slice(last));\n return nodes;\n}\n\n/**\n * Streamed answer: paragraphs with optional inline citations, a source bar,\n * an action row and follow-up questions. Fully controlled — it renders the\n * `text` it is given; `typewriter` only adds a client-side reveal.\n */\nexport default function StreamingText({\n text,\n streaming = false,\n typewriter = false,\n typewriterSpeed = 3,\n sources,\n citations = false,\n maxVisibleSources = 3,\n actions,\n onCopy,\n onRegenerate,\n onFeedback,\n followUps,\n onFollowUp,\n followUpsLabel = 'Follow-ups',\n className,\n ...rest\n}: StreamingTextProps) {\n const [revealed, setRevealed] = useState(0);\n const [showAllSources, setShowAllSources] = useState(false);\n\n const revealing = typewriter && revealed < text.length;\n useEffect(() => {\n if (!revealing) return;\n const id = window.setTimeout(() => {\n setRevealed(count => Math.min(text.length, count + Math.max(1, typewriterSpeed)));\n }, TYPEWRITER_TICK_MS);\n return () => window.clearTimeout(id);\n }, [revealing, text.length, typewriterSpeed]);\n\n const visibleText = typewriter ? text.slice(0, revealed) : text;\n const live = streaming || revealing;\n // Keep a trailing empty paragraph only while live so the caret has a home.\n const paragraphs = visibleText.split(/\\n{2,}/).filter((p, i, all) => p.length > 0 || (live && i === all.length - 1));\n\n const builtIns: StreamingAction[] = [];\n if (onCopy) builtIns.push({ id: 'copy', label: 'Copy', icon: <CopyIcon />, onClick: () => onCopy(text) });\n if (onRegenerate) builtIns.push({ id: 'regenerate', label: 'Regenerate', icon: <RefreshIcon />, onClick: onRegenerate });\n if (onFeedback) {\n builtIns.push({ id: 'up', label: 'Good response', icon: <ThumbsUpIcon />, onClick: () => onFeedback('up') });\n builtIns.push({ id: 'down', label: 'Bad response', icon: <ThumbsDownIcon />, onClick: () => onFeedback('down') });\n }\n const allActions = [...builtIns, ...(actions ?? [])];\n\n const sourceList = sources ?? [];\n const visibleSources = showAllSources ? sourceList : sourceList.slice(0, maxVisibleSources);\n const overflow = sourceList.length - visibleSources.length;\n\n return (\n <div {...rest} className={cn('dishui-ai-streaming', live && 'dishui-ai-streaming--live', className)}>\n <div className=\"dishui-ai-streaming__body\" aria-live={live ? 'polite' : undefined} aria-busy={live || undefined}>\n {paragraphs.map((paragraph, pi) => {\n const lines = paragraph.split('\\n');\n const isLast = pi === paragraphs.length - 1;\n return (\n <p key={paragraph} className=\"dishui-ai-streaming__paragraph\">\n {lines.map((line, li) => (\n <React.Fragment key={line}>\n {li > 0 && <br />}\n {renderLine(line, sources, citations, `${pi}-${li}`)}\n </React.Fragment>\n ))}\n {isLast && live && <span className=\"dishui-ai-streaming__caret\" aria-hidden=\"true\" />}\n </p>\n );\n })}\n </div>\n\n {sourceList.length > 0 && (\n <div className=\"dishui-ai-streaming__sources\">\n <span className=\"dishui-ai-streaming__sources-count\">\n {sourceList.length} {sourceList.length === 1 ? 'source' : 'sources'}\n </span>\n <ul className=\"dishui-ai-streaming__source-list\">\n {visibleSources.map((source, i) => {\n const inner = (\n <>\n <span className=\"dishui-ai-streaming__source-icon\" aria-hidden=\"true\">{source.favicon ?? initialOf(source)}</span>\n <span className=\"dishui-ai-streaming__source-title\">{source.title}</span>\n {source.domain && <span className=\"dishui-ai-streaming__source-domain\">{source.domain}</span>}\n </>\n );\n return (\n <li key={source.id}>\n {source.url ? (\n <a className=\"dishui-ai-streaming__source\" href={source.url} target=\"_blank\" rel=\"noreferrer\" title={`[${i + 1}] ${source.title}`}>{inner}</a>\n ) : (\n <span className=\"dishui-ai-streaming__source\" title={`[${i + 1}] ${source.title}`}>{inner}</span>\n )}\n </li>\n );\n })}\n {(overflow > 0 || showAllSources) && sourceList.length > maxVisibleSources && (\n <li>\n <button\n type=\"button\"\n className=\"dishui-ai-streaming__source dishui-ai-streaming__source--more\"\n aria-expanded={showAllSources}\n onClick={() => setShowAllSources(v => !v)}\n >\n {showAllSources ? 'Show less' : `+${overflow}`}\n </button>\n </li>\n )}\n </ul>\n </div>\n )}\n\n {!live && allActions.length > 0 && (\n <div className=\"dishui-ai-streaming__actions\" role=\"toolbar\" aria-label=\"Answer actions\">\n {allActions.map(action => (\n <button\n key={action.id}\n type=\"button\"\n className={cn('dishui-ai-streaming__action', !action.icon && 'dishui-ai-streaming__action--text')}\n aria-label={action.label}\n title={action.label}\n onClick={action.onClick}\n >\n {action.icon ?? action.label}\n </button>\n ))}\n </div>\n )}\n\n {!live && followUps && followUps.length > 0 && (\n <div className=\"dishui-ai-streaming__follow-ups\">\n <div className=\"dishui-ai-streaming__follow-ups-label\">{followUpsLabel}</div>\n <ul className=\"dishui-ai-streaming__follow-up-list\">\n {followUps.map(question => (\n <li key={question}>\n <button type=\"button\" className=\"dishui-ai-streaming__follow-up\" onClick={() => onFollowUp?.(question)}>\n <span className=\"dishui-ai-streaming__follow-up-text\">{question}</span>\n <span className=\"dishui-ai-streaming__follow-up-icon\" aria-hidden=\"true\"><ArrowIcon /></span>\n </button>\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_Fragment","React","TYPEWRITER_TICK_MS","svgProps","CopyIcon","RefreshIcon","ThumbsUpIcon","ThumbsDownIcon","ArrowIcon","CITATION_RE","initialOf","source","renderLine","citations","line","nodes","last","match","sources","label","keyBase","StreamingText","rest","revealed","setRevealed","useState","showAllSources","setShowAllSources","revealing","typewriter","text","id","count","typewriterSpeed","visibleText","live","streaming","paragraphs","p","i","all","builtIns","onCopy","onRegenerate","onFeedback","allActions","actions","sourceList","visibleSources","maxVisibleSources","overflow","cn","className","lines","paragraph","isLast","pi","li","inner","Fragment","v","action","followUps","followUpsLabel","onFollowUp","question"],"sources":["../../../../src/components/ai/StreamingText/index.tsx"],"sourcesContent":["import React, { useEffect, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './StreamingText.css';\n\nexport type StreamingSource = {\n id: string;\n title: string;\n domain?: string;\n url?: string;\n favicon?: React.ReactNode;\n};\n\nexport type StreamingAction = {\n id: string;\n label: string;\n icon?: React.ReactNode;\n onClick?: () => void;\n};\n\nexport type StreamingFeedback = 'up' | 'down';\n\nexport type StreamingTextProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n /** Full or partial answer text. `\\n\\n` starts a new paragraph. */\n text: string;\n /** Shows the caret and hides actions / follow-ups until the answer is complete. */\n streaming?: boolean;\n /** Reveal `text` progressively on the client. Remount (key) to replay. */\n typewriter?: boolean;\n /** Characters revealed per tick in typewriter mode. */\n typewriterSpeed?: number;\n sources?: StreamingSource[];\n /** Render `[n]` markers in `text` as inline chips pointing at `sources[n - 1]`. */\n citations?: boolean;\n /** Source chips shown before the “+k” overflow toggle. */\n maxVisibleSources?: number;\n /** Extra actions appended after the built-in copy / regenerate / feedback buttons. */\n actions?: StreamingAction[];\n onCopy?: (text: string) => void;\n onRegenerate?: () => void;\n onFeedback?: (kind: StreamingFeedback) => void;\n followUps?: string[];\n onFollowUp?: (question: string) => void;\n followUpsLabel?: React.ReactNode;\n};\n\nconst TYPEWRITER_TICK_MS = 30;\n\nconst svgProps = { width: 16, height: 16, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 2, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': true } as const;\nconst CopyIcon = () => (\n <svg {...svgProps}><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" /><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" /></svg>\n);\nconst RefreshIcon = () => (\n <svg {...svgProps}><path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" /><path d=\"M21 3v5h-5\" /><path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" /><path d=\"M8 16H3v5\" /></svg>\n);\nconst ThumbsUpIcon = () => (\n <svg {...svgProps}><path d=\"M7 10v12\" /><path d=\"M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z\" /></svg>\n);\nconst ThumbsDownIcon = () => (\n <svg {...svgProps}><path d=\"M17 14V2\" /><path d=\"M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z\" /></svg>\n);\nconst ArrowIcon = () => (\n <svg {...svgProps}><path d=\"M7 17 17 7\" /><path d=\"M7 7h10v10\" /></svg>\n);\n\nconst CITATION_RE = /\\[(\\d+)\\]/g;\n\nconst initialOf = (source: StreamingSource) => (source.domain ?? source.title).trim().charAt(0).toUpperCase();\n\nfunction renderLine(line: string, sources: StreamingSource[] | undefined, citations: boolean, keyBase: string): React.ReactNode[] {\n if (!citations) return [line];\n const nodes: React.ReactNode[] = [];\n let last = 0;\n let match: RegExpExecArray | null;\n CITATION_RE.lastIndex = 0;\n while ((match = CITATION_RE.exec(line)) !== null) {\n if (match.index > last) nodes.push(line.slice(last, match.index));\n const n = Number(match[1]);\n const source = sources?.[n - 1];\n const label = source ? source.title : `Source ${n}`;\n nodes.push(\n source?.url ? (\n <a key={`${keyBase}-${match.index}`} className=\"dishui-ai-streaming__cite\" href={source.url} target=\"_blank\" rel=\"noreferrer\" title={label} aria-label={label}>{n}</a>\n ) : (\n <span key={`${keyBase}-${match.index}`} className=\"dishui-ai-streaming__cite\" title={label} aria-label={label} role=\"note\">{n}</span>\n ),\n );\n last = match.index + match[0].length;\n }\n if (last < line.length) nodes.push(line.slice(last));\n return nodes;\n}\n\n/**\n * Streamed answer: paragraphs with optional inline citations, a source bar,\n * an action row and follow-up questions. Fully controlled — it renders the\n * `text` it is given; `typewriter` only adds a client-side reveal.\n */\nexport default function StreamingText({\n text,\n streaming = false,\n typewriter = false,\n typewriterSpeed = 3,\n sources,\n citations = false,\n maxVisibleSources = 3,\n actions,\n onCopy,\n onRegenerate,\n onFeedback,\n followUps,\n onFollowUp,\n followUpsLabel = 'Follow-ups',\n className,\n ...rest\n}: StreamingTextProps) {\n const [revealed, setRevealed] = useState(0);\n const [showAllSources, setShowAllSources] = useState(false);\n\n const revealing = typewriter && revealed < text.length;\n useEffect(() => {\n if (!revealing) return;\n const id = window.setTimeout(() => {\n setRevealed(count => Math.min(text.length, count + Math.max(1, typewriterSpeed)));\n }, TYPEWRITER_TICK_MS);\n return () => window.clearTimeout(id);\n }, [revealing, text.length, typewriterSpeed]);\n\n const visibleText = typewriter ? text.slice(0, revealed) : text;\n const live = streaming || revealing;\n // Keep a trailing empty paragraph only while live so the caret has a home.\n const paragraphs = visibleText.split(/\\n{2,}/).filter((p, i, all) => p.length > 0 || (live && i === all.length - 1));\n\n const builtIns: StreamingAction[] = [];\n if (onCopy) builtIns.push({ id: 'copy', label: 'Copy', icon: <CopyIcon />, onClick: () => onCopy(text) });\n if (onRegenerate) builtIns.push({ id: 'regenerate', label: 'Regenerate', icon: <RefreshIcon />, onClick: onRegenerate });\n if (onFeedback) {\n builtIns.push({ id: 'up', label: 'Good response', icon: <ThumbsUpIcon />, onClick: () => onFeedback('up') });\n builtIns.push({ id: 'down', label: 'Bad response', icon: <ThumbsDownIcon />, onClick: () => onFeedback('down') });\n }\n const allActions = [...builtIns, ...(actions ?? [])];\n\n const sourceList = sources ?? [];\n const visibleSources = showAllSources ? sourceList : sourceList.slice(0, maxVisibleSources);\n const overflow = sourceList.length - visibleSources.length;\n\n return (\n <div {...rest} className={cn('dishui-ai-streaming', live && 'dishui-ai-streaming--live', className)}>\n <div className=\"dishui-ai-streaming__body\" aria-live={live ? 'polite' : undefined} aria-busy={live || undefined}>\n {paragraphs.map((paragraph, pi) => {\n const lines = paragraph.split('\\n');\n const isLast = pi === paragraphs.length - 1;\n return (\n <p key={paragraph} className=\"dishui-ai-streaming__paragraph\">\n {lines.map((line, li) => (\n <React.Fragment key={line}>\n {li > 0 && <br />}\n {renderLine(line, sources, citations, `${pi}-${li}`)}\n </React.Fragment>\n ))}\n {isLast && live && <span className=\"dishui-ai-streaming__caret\" aria-hidden=\"true\" />}\n </p>\n );\n })}\n </div>\n\n {sourceList.length > 0 && (\n <div className=\"dishui-ai-streaming__sources\">\n <span className=\"dishui-ai-streaming__sources-count\">\n {sourceList.length} {sourceList.length === 1 ? 'source' : 'sources'}\n </span>\n <ul className=\"dishui-ai-streaming__source-list\">\n {visibleSources.map((source, i) => {\n const inner = (\n <>\n <span className=\"dishui-ai-streaming__source-icon\" aria-hidden=\"true\">{source.favicon ?? initialOf(source)}</span>\n <span className=\"dishui-ai-streaming__source-title\">{source.title}</span>\n {source.domain && <span className=\"dishui-ai-streaming__source-domain\">{source.domain}</span>}\n </>\n );\n return (\n <li key={source.id}>\n {source.url ? (\n <a className=\"dishui-ai-streaming__source\" href={source.url} target=\"_blank\" rel=\"noreferrer\" title={`[${i + 1}] ${source.title}`}>{inner}</a>\n ) : (\n <span className=\"dishui-ai-streaming__source\" title={`[${i + 1}] ${source.title}`}>{inner}</span>\n )}\n </li>\n );\n })}\n {(overflow > 0 || showAllSources) && sourceList.length > maxVisibleSources && (\n <li>\n <button\n type=\"button\"\n className=\"dishui-ai-streaming__source dishui-ai-streaming__source--more\"\n aria-expanded={showAllSources}\n onClick={() => setShowAllSources(v => !v)}\n >\n {showAllSources ? 'Show less' : `+${overflow}`}\n </button>\n </li>\n )}\n </ul>\n </div>\n )}\n\n {!live && allActions.length > 0 && (\n <div className=\"dishui-ai-streaming__actions\" role=\"toolbar\" aria-label=\"Answer actions\">\n {allActions.map(action => (\n <button\n key={action.id}\n type=\"button\"\n className={cn('dishui-ai-streaming__action', !action.icon && 'dishui-ai-streaming__action--text')}\n aria-label={action.label}\n title={action.label}\n onClick={action.onClick}\n >\n {action.icon ?? action.label}\n </button>\n ))}\n </div>\n )}\n\n {!live && followUps && followUps.length > 0 && (\n <div className=\"dishui-ai-streaming__follow-ups\">\n <div className=\"dishui-ai-streaming__follow-ups-label\">{followUpsLabel}</div>\n <ul className=\"dishui-ai-streaming__follow-up-list\">\n {followUps.map(question => (\n <li key={question}>\n <button type=\"button\" className=\"dishui-ai-streaming__follow-up\" onClick={() => onFollowUp?.(question)}>\n <span className=\"dishui-ai-streaming__follow-up-text\">{question}</span>\n <span className=\"dishui-ai-streaming__follow-up-icon\" aria-hidden=\"true\"><ArrowIcon /></span>\n </button>\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AA6CA,IAAME,IAAqB,IAErBC,IAAW;CAAE,OAAO;CAAI,QAAQ;CAAI,SAAS;CAAa,MAAM;CAAQ,QAAQ;CAAgB,aAAa;CAAG,eAAe;CAAS,gBAAgB;CAAS,eAAe;AAAK,GACrLC,UACJ,kBAAC,OAAD;CAAK,GAAID;CAAT,UAAA,CAAmB,kBAAC,QAAD;EAAM,OAAM;EAAK,QAAO;EAAK,GAAE;EAAI,GAAE;EAAI,IAAG;CAAK,CAAA,GAAC,kBAAC,QAAD,EAAM,GAAE,0DAA2D,CAAA,CAAM;IAE1IE,UACJ,kBAAC,OAAD;CAAK,GAAIF;CAAT,UAAA;EAAmB,kBAAC,QAAD,EAAM,GAAE,qDAAsD,CAAA;EAAC,kBAAC,QAAD,EAAM,GAAE,aAAc,CAAA;EAAC,kBAAC,QAAD,EAAM,GAAE,sDAAuD,CAAA;EAAC,kBAAC,QAAD,EAAM,GAAE,YAAa,CAAA;CAAM;IAEhMG,UACJ,kBAAC,OAAD;CAAK,GAAIH;CAAT,UAAA,CAAmB,kBAAC,QAAD,EAAM,GAAE,WAAY,CAAA,GAAC,kBAAC,QAAD,EAAM,GAAE,2JAA4J,CAAA,CAAM;IAE9MI,UACJ,kBAAC,OAAD;CAAK,GAAIJ;CAAT,UAAA,CAAmB,kBAAC,QAAD,EAAM,GAAE,WAAY,CAAA,GAAC,kBAAC,QAAD,EAAM,GAAE,0JAA2J,CAAA,CAAM;IAE7MK,UACJ,kBAAC,OAAD;CAAK,GAAIL;CAAT,UAAA,CAAmB,kBAAC,QAAD,EAAM,GAAE,aAAc,CAAA,GAAC,kBAAC,QAAD,EAAM,GAAE,aAAc,CAAA,CAAM;IAGlEM,IAAc,cAEdC,KAAa,OAA6BC,EAAO,UAAUA,EAAO,MAAA,CAAO,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY;AAE5G,SAASC,EAAW,GAAc,GAAwC,GAAoB,GAAoC;CAChI,IAAI,CAACC,GAAW,OAAO,CAACC,CAAI;CAC5B,IAAMC,IAA2B,CAAC,GAC9BC,IAAO,GACPC;CAEJ,KADA,EAAY,YAAY,IAChB,IAAQR,EAAY,KAAKK,CAAI,OAAO,OAAM;EAChD,AAAIG,EAAM,QAAQD,KAAMD,EAAM,KAAKD,EAAK,MAAME,GAAMC,EAAM,KAAK,CAAC;EAChE,IAAM,IAAI,OAAOA,EAAM,EAAE,GACnBN,IAASO,IAAU,IAAI,IACvBC,IAAQR,IAASA,EAAO,QAAQ,UAAU;EAQhD,AAPAI,EAAM,KACJJ,GAAQ,MACN,kBAAC,KAAD;GAAqC,WAAU;GAA4B,MAAMA,EAAO;GAAK,QAAO;GAAS,KAAI;GAAa,OAAOQ;GAAO,cAAYA;GAAQ,UAAA;EAAK,GAA7J,GAAGC,EAAQ,GAAGH,EAAM,OAAyI,IAErK,kBAAC,QAAD;GAAwC,WAAU;GAA4B,OAAOE;GAAO,cAAYA;GAAO,MAAK;GAAQ,UAAA;EAAQ,GAAzH,GAAGC,EAAQ,GAAGH,EAAM,OAAqG,CAExI,GACA,IAAOA,EAAM,QAAQA,EAAM,EAAE,CAAC;CAChC;CAEA,OADID,IAAOF,EAAK,UAAQC,EAAM,KAAKD,EAAK,MAAME,CAAI,CAAC,GAC5CD;AACT;AAOA,SAAwBM,EAAc,EACpC,SACA,eAAY,IACZ,gBAAa,IACb,qBAAkB,GAClB,YACA,eAAY,IACZ,uBAAoB,GACpB,YACA,WACA,iBACA,eACA,cACA,eACA,oBAAiB,cACjB,cACA,GAAGC,KACkB;CACrB,IAAM,CAACC,GAAUC,KAAeC,EAAS,CAAC,GACpC,CAACC,GAAgBC,KAAqBF,EAAS,EAAK,GAEpDG,IAAYC,KAAcN,IAAWO,EAAK;CAChD,QAAgB;EACd,IAAI,CAACF,GAAW;EAChB,IAAMG,IAAK,OAAO,iBAAiB;GACjC,GAAY,MAAS,KAAK,IAAID,EAAK,QAAQE,IAAQ,KAAK,IAAI,GAAGC,CAAe,CAAC,CAAC;EAClF,GAAG/B,CAAkB;EACrB,aAAa,OAAO,aAAa6B,CAAE;CACrC,GAAG;EAACH;EAAWE,EAAK;EAAQG;CAAe,CAAC;CAE5C,IAAMC,IAAcL,IAAaC,EAAK,MAAM,GAAGP,CAAQ,IAAIO,GACrDK,IAAOC,KAAaR,GAEpBS,IAAaH,EAAY,MAAM,QAAQ,CAAC,CAAC,QAAQ,GAAG,GAAG,MAAQI,EAAE,SAAS,KAAMH,KAAQI,MAAMC,EAAI,SAAS,CAAE,GAE7GC,IAA8B,CAAC;CAGrC,AAFIC,KAAQD,EAAS,KAAK;EAAE,IAAI;EAAQ,OAAO;EAAQ,MAAM,kBAACrC,GAAD,CAAW,CAAA;EAAG,eAAesC,EAAOZ,CAAI;CAAE,CAAC,GACpGa,KAAcF,EAAS,KAAK;EAAE,IAAI;EAAc,OAAO;EAAc,MAAM,kBAACpC,GAAD,CAAc,CAAA;EAAG,SAASsC;CAAa,CAAC,GACnHC,MACFH,EAAS,KAAK;EAAE,IAAI;EAAM,OAAO;EAAiB,MAAM,kBAACnC,GAAD,CAAe,CAAA;EAAG,eAAesC,EAAW,IAAI;CAAE,CAAC,GAC3GH,EAAS,KAAK;EAAE,IAAI;EAAQ,OAAO;EAAgB,MAAM,kBAAClC,GAAD,CAAiB,CAAA;EAAG,eAAeqC,EAAW,MAAM;CAAE,CAAC;CAElH,IAAMC,IAAa,CAAC,GAAGJ,GAAU,GAAIK,KAAW,CAAC,CAAE,GAE7CC,IAAa7B,KAAW,CAAC,GACzB8B,IAAiBtB,IAAiBqB,IAAaA,EAAW,MAAM,GAAGE,CAAiB,GACpFC,IAAWH,EAAW,SAASC,EAAe;CAEpD,OACE,kBAAC,OAAD;EAAK,GAAI1B;EAAM,WAAW6B,EAAG,uBAAuBhB,KAAQ,6BAA6BiB,CAAS;EAAlG,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IAA4B,aAAWjB,IAAO,WAAW,KAAA;IAAW,aAAWA,KAAQ,KAAA;IACnG,UAAAE,EAAW,KAAK,GAAW,MAAO;KACjC,IAAMgB,IAAQC,EAAU,MAAM,IAAI,GAC5BC,IAASC,MAAOnB,EAAW,SAAS;KAC1C,OACE,kBAAC,KAAD;MAAmB,WAAU;MAA7B,UAAA,CACGgB,EAAM,KAAK,GAAM,MAChB,kBAACpD,EAAM,UAAP,EAAA,UAAA,CACGwD,IAAK,KAAK,kBAAC,MAAD,CAAK,CAAA,GACf7C,EAAWE,GAAMI,GAASL,GAAW,GAAG2C,EAAG,GAAGC,GAAI,CACrC,EAAA,GAHK3C,CAGL,CACjB,GACAyC,KAAUpB,KAAQ,kBAAC,QAAD;OAAM,WAAU;OAA6B,eAAY;MAAQ,CAAA,CACnF;KARK,GAAAmB,CAQL;IAEP,CAAC;GACE,CAAA;GAEJP,EAAW,SAAS,KACnB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MACGA,EAAW;MAAO;MAAEA,EAAW,WAAW,IAAI,WAAW;KACtD;IACN,CAAA,GAAA,kBAAC,MAAD;KAAI,WAAU;KAAd,UAAA,CACGC,EAAe,KAAK,GAAQ,MAAM;MACjC,IAAMU,IACJ,kBAAA1D,GAAA,EAAA,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAAmC,eAAY;QAAQ,UAAAW,EAAO,WAAWD,EAAUC,CAAM;OAAQ,CAAA;OACjH,kBAAC,QAAD;QAAM,WAAU;QAAqC,UAAAA,EAAO;OAAY,CAAA;OACvEA,EAAO,UAAU,kBAAC,QAAD;QAAM,WAAU;QAAsC,UAAAA,EAAO;OAAa,CAAA;MAC5F,EAAA,CAAA;MAEJ,OACE,kBAAC,MAAD,EAAA,UACGA,EAAO,MACN,kBAAC,KAAD;OAAG,WAAU;OAA8B,MAAMA,EAAO;OAAK,QAAO;OAAS,KAAI;OAAa,OAAO,IAAI4B,IAAI,EAAE,IAAI5B,EAAO;OAAU,UAAA+C;MAAS,CAAA,IAE7I,kBAAC,QAAD;OAAM,WAAU;OAA8B,OAAO,IAAInB,IAAI,EAAE,IAAI5B,EAAO;OAAU,UAAA+C;MAAY,CAAA,EAEhG,GANK/C,EAAO,EAMZ;KAER,CAAC,IACCuC,IAAW,KAAKxB,MAAmBqB,EAAW,SAASE,KACvD,kBAAC,MAAD,EAAA,UACE,kBAAC,UAAD;MACE,MAAK;MACL,WAAU;MACV,iBAAevB;MACf,eAAeC,GAAkB,MAAK,CAACiC,CAAC;MAEvC,UAAAlC,IAAiB,cAAc,IAAIwB;KAC9B,CAAA,EACN,CAAA,CAEJ;IACD,CAAA,CAAA;;GAGN,CAACf,KAAQU,EAAW,SAAS,KAC5B,kBAAC,OAAD;IAAK,WAAU;IAA+B,MAAK;IAAU,cAAW;IACrE,UAAAA,EAAW,KAAI,MACd,kBAAC,UAAD;KAEE,MAAK;KACL,WAAWM,EAAG,+BAA+B,CAACU,EAAO,QAAQ,mCAAmC;KAChG,cAAYA,EAAO;KACnB,OAAOA,EAAO;KACd,SAASA,EAAO;KAEf,UAAAA,EAAO,QAAQA,EAAO;IACjB,GARDA,EAAO,EAQN,CACT;GACE,CAAA;GAGN,CAAC1B,KAAQ2B,KAAaA,EAAU,SAAS,KACxC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,OAAD;KAAK,WAAU;KAAyC,UAAAC;IAAoB,CAAA,GAC5E,kBAAC,MAAD;KAAI,WAAU;KACX,UAAAD,EAAU,KAAI,MACb,kBAAC,MAAD,EAAA,UACE,kBAAC,UAAD;MAAQ,MAAK;MAAS,WAAU;MAAiC,eAAeE,IAAaC,CAAQ;MAArG,UAAA,CACE,kBAAC,QAAD;OAAM,WAAU;OAAuC,UAAAA;MAAe,CAAA,GACtE,kBAAC,QAAD;OAAM,WAAU;OAAsC,eAAY;OAAO,UAAA,kBAACzD,GAAD,CAAY,CAAA;MAAO,CAAA,CACtF;KACN,CAAA,EAAA,GALKyD,CAKL,CACL;IACC,CAAA,CACD;;EAEJ;;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/TaskRows/index.tsx"],"sourcesContent":["import React, { useCallback, useId, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { AGENT_STATUS_LABEL, clamp } from '../shared';\nimport type { AgentStatus } from '../shared';\nimport './TaskRows.css';\n\nexport type AgentSubtask = {\n id: string;\n title: React.ReactNode;\n /** Right-aligned value, e.g. `12/12`, `68%`, `draft`. */\n value?: React.ReactNode;\n status?: AgentStatus;\n};\n\nexport type AgentTask = {\n id: string;\n title: React.ReactNode;\n /** Short qualifier shown after the title, e.g. `12 suppliers`. */\n meta?: React.ReactNode;\n status: AgentStatus;\n /** Determinate progress 0–100. Running tasks without it show an indeterminate bar. */\n progress?: number;\n subtasks?: AgentSubtask[];\n /** Shown under a failed task, next to the retry action. */\n error?: React.ReactNode;\n};\n\nexport type TaskRowsView = 'capsules' | 'list';\n\nexport type TaskRowsLabels = {\n capsules?: string;\n list?: string;\n retry?: string;\n view?: string;\n status?: Partial<Record<AgentStatus, string>>;\n};\n\nexport type TaskRowsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n tasks: AgentTask[];\n /** Controlled view mode. */\n view?: TaskRowsView;\n defaultView?: TaskRowsView;\n onViewChange?: (view: TaskRowsView) => void;\n /** Render the Capsules / List toggle above the tasks. */\n showViewToggle?: boolean;\n /** Controlled list of task ids whose subtasks are visible. */\n expanded?: string[];\n /** Defaults to every running or failed task. */\n defaultExpanded?: string[];\n onExpandedChange?: (expanded: string[]) => void;\n /** Enables the retry action on failed tasks. */\n onRetry?: (task: AgentTask) => void;\n emptyText?: React.ReactNode;\n labels?: TaskRowsLabels;\n};\n\nconst DEFAULT_LABELS = { capsules: 'Capsules', list: 'List', retry: 'Retry', view: 'View' };\n\nconst STATUS_TONE: Record<AgentStatus, string> = {\n pending: 'neutral',\n running: 'info',\n completed: 'success',\n failed: 'danger',\n skipped: 'neutral',\n};\n\nconst ChevronIcon: React.FC = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n);\n\nconst RetryIcon: React.FC = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M3 12a9 9 0 1 0 3-6.7\" />\n <path d=\"M3 4v5h5\" />\n </svg>\n);\n\nconst StatusPill: React.FC<{ status: AgentStatus; label: string }> = ({ status, label }) => (\n <span className={cn('dishui-ai-task-rows__status', `dishui-ai-task-rows__status--${STATUS_TONE[status]}`)}>\n {status === 'running' && <span className=\"dishui-ai-task-rows__pulse\" aria-hidden=\"true\" />}\n {label}\n </span>\n);\n\nconst defaultExpandedFor = (tasks: AgentTask[]) =>\n tasks.filter(t => t.status === 'running' || t.status === 'failed').map(t => t.id);\n\n/**\n * Live agent task status. Each task is a row (or capsule) with a text +\n * colour status pill, optional progress and expandable subtasks with\n * right-aligned tabular values.\n */\nexport default function TaskRows({\n tasks,\n view: viewProp,\n defaultView = 'capsules',\n onViewChange,\n showViewToggle = false,\n expanded: expandedProp,\n defaultExpanded,\n onExpandedChange,\n onRetry,\n emptyText = 'No tasks yet',\n labels,\n className,\n ...rest\n}: TaskRowsProps) {\n const baseId = useId();\n const text = { ...DEFAULT_LABELS, ...labels };\n\n const [internalView, setInternalView] = useState<TaskRowsView>(defaultView);\n const view = viewProp ?? internalView;\n const changeView = useCallback((next: TaskRowsView) => {\n setInternalView(next);\n onViewChange?.(next);\n }, [onViewChange]);\n\n const [internalExpanded, setInternalExpanded] = useState<string[]>(\n () => defaultExpanded ?? defaultExpandedFor(tasks),\n );\n const expanded = expandedProp ?? internalExpanded;\n const toggle = useCallback((id: string) => {\n const next = expanded.includes(id) ? expanded.filter(x => x !== id) : [...expanded, id];\n setInternalExpanded(next);\n onExpandedChange?.(next);\n }, [expanded, onExpandedChange]);\n\n const statusLabel = (status: AgentStatus) => labels?.status?.[status] ?? AGENT_STATUS_LABEL[status];\n\n return (\n <div {...rest} className={cn('dishui-ai-task-rows', `dishui-ai-task-rows--${view}`, className)}>\n {showViewToggle && (\n <div className=\"dishui-ai-task-rows__toolbar\">\n <div className=\"dishui-ai-task-rows__segmented\" role=\"group\" aria-label={text.view}>\n {(['capsules', 'list'] as TaskRowsView[]).map(v => (\n <button\n key={v}\n type=\"button\"\n className={cn('dishui-ai-task-rows__segment', v === view && 'dishui-ai-task-rows__segment--active')}\n aria-pressed={v === view}\n onClick={() => changeView(v)}\n >\n {text[v]}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {tasks.length === 0 ? (\n <div className=\"dishui-ai-task-rows__empty\">{emptyText}</div>\n ) : (\n <ul className=\"dishui-ai-task-rows__list\">\n {tasks.map(task => {\n const hasSubtasks = !!task.subtasks?.length;\n const isOpen = hasSubtasks && expanded.includes(task.id);\n const panelId = `${baseId}-${task.id}`;\n const progress = task.progress === undefined ? undefined : clamp(task.progress, 0, 100);\n const showBar = view === 'capsules' && (progress !== undefined || task.status === 'running');\n return (\n <li\n key={task.id}\n className={cn(\n 'dishui-ai-task-rows__task',\n `dishui-ai-task-rows__task--${task.status}`,\n isOpen && 'dishui-ai-task-rows__task--open',\n )}\n >\n <div className=\"dishui-ai-task-rows__row\">\n {hasSubtasks ? (\n <button\n type=\"button\"\n className=\"dishui-ai-task-rows__toggle\"\n aria-expanded={isOpen}\n aria-controls={panelId}\n onClick={() => toggle(task.id)}\n >\n <span className=\"dishui-ai-task-rows__chevron\"><ChevronIcon /></span>\n <span className=\"dishui-ai-task-rows__title\">{task.title}</span>\n {task.meta !== undefined && <span className=\"dishui-ai-task-rows__meta\">{task.meta}</span>}\n </button>\n ) : (\n <div className=\"dishui-ai-task-rows__toggle dishui-ai-task-rows__toggle--static\">\n <span className=\"dishui-ai-task-rows__chevron dishui-ai-task-rows__chevron--blank\" />\n <span className=\"dishui-ai-task-rows__title\">{task.title}</span>\n {task.meta !== undefined && <span className=\"dishui-ai-task-rows__meta\">{task.meta}</span>}\n </div>\n )}\n {progress !== undefined && task.status === 'running' && (\n <span className=\"dishui-ai-task-rows__percent\">{Math.round(progress)}%</span>\n )}\n <StatusPill status={task.status} label={statusLabel(task.status)} />\n </div>\n\n {showBar && (\n <div\n className={cn('dishui-ai-task-rows__bar', progress === undefined && 'dishui-ai-task-rows__bar--indeterminate')}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress}\n >\n <span className=\"dishui-ai-task-rows__fill\" style={progress === undefined ? undefined : { width: `${progress}%` }} />\n </div>\n )}\n\n {task.status === 'failed' && (task.error !== undefined || onRetry) && (\n <div className=\"dishui-ai-task-rows__error\" role=\"alert\">\n <span className=\"dishui-ai-task-rows__error-text\">{task.error}</span>\n {onRetry && (\n <button type=\"button\" className=\"dishui-ai-task-rows__retry\" onClick={() => onRetry(task)}>\n <RetryIcon />\n {text.retry}\n </button>\n )}\n </div>\n )}\n\n {hasSubtasks && (\n <ul id={panelId} className=\"dishui-ai-task-rows__subtasks\" hidden={!isOpen}>\n {task.subtasks!.map(sub => (\n <li\n key={sub.id}\n className={cn('dishui-ai-task-rows__subtask', sub.status && `dishui-ai-task-rows__subtask--${sub.status}`)}\n >\n <span className=\"dishui-ai-task-rows__subtitle\">{sub.title}</span>\n {sub.value !== undefined && <span className=\"dishui-ai-task-rows__value\">{sub.value}</span>}\n {sub.status && sub.status !== task.status && (\n <span className=\"dishui-ai-task-rows__substatus\">{statusLabel(sub.status)}</span>\n )}\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;AAwDA,IAAM,IAAiB;CAAE,UAAU;CAAY,MAAM;CAAQ,OAAO;CAAS,MAAM;AAAO,GAEpF,IAA2C;CAC/C,SAAS;CACT,SAAS;CACT,WAAW;CACX,QAAQ;CACR,SAAS;AACX,GAEM,UACJ,kBAAC,OAAD;CAAK,OAAM;CAAK,QAAO;CAAK,SAAQ;CAAY,MAAK;CAAO,QAAO;CAAe,aAAY;CAAI,eAAc;CAAQ,gBAAe;CAAQ,eAAY;CACzJ,UAAA,kBAAC,QAAD,EAAM,GAAE,gBAAiB,CAAA;AACtB,CAAA,GAGD,UACJ,kBAAC,OAAD;CAAK,OAAM;CAAK,QAAO;CAAK,SAAQ;CAAY,MAAK;CAAO,QAAO;CAAe,aAAY;CAAI,eAAc;CAAQ,gBAAe;CAAQ,eAAY;CAA3J,UAAA,CACE,kBAAC,QAAD,EAAM,GAAE,wBAAyB,CAAA,GACjC,kBAAC,QAAD,EAAM,GAAE,WAAY,CAAA,CACjB;IAGD,KAAgE,EAAE,WAAQ,eAC9E,kBAAC,QAAD;CAAM,WAAW,EAAG,+BAA+B,gCAAgC,EAAY,IAAS;CAAxG,UAAA,CACG,MAAW,aAAa,kBAAC,QAAD;EAAM,WAAU;EAA6B,eAAY;CAAQ,CAAA,GACzF,CACG;IAGF,KAAsB,MAC1B,EAAM,QAAO,MAAK,EAAE,WAAW,aAAa,EAAE,WAAW,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,EAAE;AAOlF,SAAwB,EAAS,EAC/B,UACA,MAAM,GACN,iBAAc,YACd,iBACA,oBAAiB,IACjB,UAAU,GACV,oBACA,qBACA,YACA,eAAY,gBACZ,WACA,cACA,GAAG,KACa;CAChB,IAAM,IAAS,EAAM,GACf,IAAO;EAAE,GAAG;EAAgB,GAAG;CAAO,GAEtC,CAAC,GAAc,KAAmB,EAAuB,CAAW,GACpE,IAAO,KAAY,GACnB,IAAa,GAAa,MAAuB;EAErD,AADA,EAAgB,CAAI,GACpB,IAAe,CAAI;CACrB,GAAG,CAAC,CAAY,CAAC,GAEX,CAAC,GAAkB,KAAuB,QACxC,KAAmB,EAAmB,CAAK,CACnD,GACM,IAAW,KAAgB,GAC3B,IAAS,GAAa,MAAe;EACzC,IAAM,IAAO,EAAS,SAAS,CAAE,IAAI,EAAS,QAAO,MAAK,MAAM,CAAE,IAAI,CAAC,GAAG,GAAU,CAAE;EAEtF,AADA,EAAoB,CAAI,GACxB,IAAmB,CAAI;CACzB,GAAG,CAAC,GAAU,CAAgB,CAAC,GAEzB,KAAe,MAAwB,GAAQ,SAAS,MAAW,EAAmB;CAE5F,OACE,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,uBAAuB,wBAAwB,KAAQ,CAAS;EAA7F,UAAA,CACG,KACC,kBAAC,OAAD;GAAK,WAAU;GACb,UAAA,kBAAC,OAAD;IAAK,WAAU;IAAiC,MAAK;IAAQ,cAAY,EAAK;IAC1E,UAAA,CAAC,YAAY,MAAM,CAAC,CAAoB,KAAI,MAC5C,kBAAC,UAAD;KAEE,MAAK;KACL,WAAW,EAAG,gCAAgC,MAAM,KAAQ,sCAAsC;KAClG,gBAAc,MAAM;KACpB,eAAe,EAAW,CAAC;KAE1B,UAAA,EAAK;IACA,GAPD,CAOC,CACT;GACE,CAAA;EACF,CAAA,GAGN,EAAM,WAAW,IAChB,kBAAC,OAAD;GAAK,WAAU;GAA8B,UAAA;EAAe,CAAA,IAE5D,kBAAC,MAAD;GAAI,WAAU;GACX,UAAA,EAAM,KAAI,MAAQ;IACjB,IAAM,IAAc,CAAC,CAAC,EAAK,UAAU,QAC/B,IAAS,KAAe,EAAS,SAAS,EAAK,EAAE,GACjD,IAAU,GAAG,EAAO,GAAG,EAAK,MAC5B,IAAW,EAAK,aAAa,KAAA,IAAY,KAAA,IAAY,EAAM,EAAK,UAAU,GAAG,GAAG,GAChF,IAAU,MAAS,eAAe,MAAa,KAAA,KAAa,EAAK,WAAW;IAClF,OACE,kBAAC,MAAD;KAEE,WAAW,EACT,6BACA,8BAA8B,EAAK,UACnC,KAAU,iCACZ;KANF,UAAA;MAQE,kBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACG,IACC,kBAAC,UAAD;SACE,MAAK;SACL,WAAU;SACV,iBAAe;SACf,iBAAe;SACf,eAAe,EAAO,EAAK,EAAE;SAL/B,UAAA;UAOE,kBAAC,QAAD;WAAM,WAAU;WAA+B,UAAA,kBAAC,GAAD,CAAc,CAAA;UAAO,CAAA;UACpE,kBAAC,QAAD;WAAM,WAAU;WAA8B,UAAA,EAAK;UAAY,CAAA;UAC9D,EAAK,SAAS,KAAA,KAAa,kBAAC,QAAD;WAAM,WAAU;WAA6B,UAAA,EAAK;UAAW,CAAA;SACnF;QAER,CAAA,IAAA,kBAAC,OAAD;SAAK,WAAU;SAAf,UAAA;UACE,kBAAC,QAAD,EAAM,WAAU,mEAAoE,CAAA;UACpF,kBAAC,QAAD;WAAM,WAAU;WAA8B,UAAA,EAAK;UAAY,CAAA;UAC9D,EAAK,SAAS,KAAA,KAAa,kBAAC,QAAD;WAAM,WAAU;WAA6B,UAAA,EAAK;UAAW,CAAA;SACtF;;QAEN,MAAa,KAAA,KAAa,EAAK,WAAW,aACzC,kBAAC,QAAD;SAAM,WAAU;SAAhB,UAAA,CAAgD,KAAK,MAAM,CAAQ,GAAE,GAAO;;QAE9E,kBAAC,GAAD;SAAY,QAAQ,EAAK;SAAQ,OAAO,EAAY,EAAK,MAAM;QAAI,CAAA;OAChE;;MAEJ,KACC,kBAAC,OAAD;OACE,WAAW,EAAG,4BAA4B,MAAa,KAAA,KAAa,yCAAyC;OAC7G,MAAK;OACL,iBAAe;OACf,iBAAe;OACf,iBAAe;OAEf,UAAA,kBAAC,QAAD;QAAM,WAAU;QAA4B,OAAO,MAAa,KAAA,IAAY,KAAA,IAAY,EAAE,OAAO,GAAG,EAAS,GAAG;OAAI,CAAA;MACjH,CAAA;MAGN,EAAK,WAAW,aAAa,EAAK,UAAU,KAAA,KAAa,MACxD,kBAAC,OAAD;OAAK,WAAU;OAA6B,MAAK;OAAjD,UAAA,CACE,kBAAC,QAAD;QAAM,WAAU;QAAmC,UAAA,EAAK;OAAY,CAAA,GACnE,KACC,kBAAC,UAAD;QAAQ,MAAK;QAAS,WAAU;QAA6B,eAAe,EAAQ,CAAI;QAAxF,UAAA,CACE,kBAAC,GAAD,CAAY,CAAA,GACX,EAAK,KACA;OAEP,CAAA,CAAA;;MAGN,KACC,kBAAC,MAAD;OAAI,IAAI;OAAS,WAAU;OAAgC,QAAQ,CAAC;OACjE,UAAA,EAAK,SAAU,KAAI,MAClB,kBAAC,MAAD;QAEE,WAAW,EAAG,gCAAgC,EAAI,UAAU,iCAAiC,EAAI,QAAQ;QAF3G,UAAA;SAIE,kBAAC,QAAD;UAAM,WAAU;UAAiC,UAAA,EAAI;SAAY,CAAA;SAChE,EAAI,UAAU,KAAA,KAAa,kBAAC,QAAD;UAAM,WAAU;UAA8B,UAAA,EAAI;SAAY,CAAA;SACzF,EAAI,UAAU,EAAI,WAAW,EAAK,UACjC,kBAAC,QAAD;UAAM,WAAU;UAAkC,UAAA,EAAY,EAAI,MAAM;SAAQ,CAAA;QAEhF;OARG,GAAA,EAAI,EAQP,CACL;MACC,CAAA;KAEJ;IAzEG,GAAA,EAAK,EAyER;GAER,CAAC;EACC,CAAA,CAEH;;AAET"}
1
+ {"version":3,"file":"index.js","names":["DEFAULT_LABELS","STATUS_TONE","ChevronIcon","RetryIcon","StatusPill","cn","status","label","defaultExpandedFor","tasks","t","TaskRows","viewProp","expandedProp","rest","baseId","useId","text","labels","internalView","setInternalView","useState","defaultView","view","changeView","useCallback","next","onViewChange","internalExpanded","setInternalExpanded","defaultExpanded","expanded","toggle","id","x","onExpandedChange","statusLabel","AGENT_STATUS_LABEL","className","showViewToggle","v","emptyText","hasSubtasks","task","isOpen","panelId","progress","clamp","showBar","onRetry","sub"],"sources":["../../../../src/components/ai/TaskRows/index.tsx"],"sourcesContent":["import React, { useCallback, useId, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { AGENT_STATUS_LABEL, clamp } from '../shared';\nimport type { AgentStatus } from '../shared';\nimport './TaskRows.css';\n\nexport type AgentSubtask = {\n id: string;\n title: React.ReactNode;\n /** Right-aligned value, e.g. `12/12`, `68%`, `draft`. */\n value?: React.ReactNode;\n status?: AgentStatus;\n};\n\nexport type AgentTask = {\n id: string;\n title: React.ReactNode;\n /** Short qualifier shown after the title, e.g. `12 suppliers`. */\n meta?: React.ReactNode;\n status: AgentStatus;\n /** Determinate progress 0–100. Running tasks without it show an indeterminate bar. */\n progress?: number;\n subtasks?: AgentSubtask[];\n /** Shown under a failed task, next to the retry action. */\n error?: React.ReactNode;\n};\n\nexport type TaskRowsView = 'capsules' | 'list';\n\nexport type TaskRowsLabels = {\n capsules?: string;\n list?: string;\n retry?: string;\n view?: string;\n status?: Partial<Record<AgentStatus, string>>;\n};\n\nexport type TaskRowsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n tasks: AgentTask[];\n /** Controlled view mode. */\n view?: TaskRowsView;\n defaultView?: TaskRowsView;\n onViewChange?: (view: TaskRowsView) => void;\n /** Render the Capsules / List toggle above the tasks. */\n showViewToggle?: boolean;\n /** Controlled list of task ids whose subtasks are visible. */\n expanded?: string[];\n /** Defaults to every running or failed task. */\n defaultExpanded?: string[];\n onExpandedChange?: (expanded: string[]) => void;\n /** Enables the retry action on failed tasks. */\n onRetry?: (task: AgentTask) => void;\n emptyText?: React.ReactNode;\n labels?: TaskRowsLabels;\n};\n\nconst DEFAULT_LABELS = { capsules: 'Capsules', list: 'List', retry: 'Retry', view: 'View' };\n\nconst STATUS_TONE: Record<AgentStatus, string> = {\n pending: 'neutral',\n running: 'info',\n completed: 'success',\n failed: 'danger',\n skipped: 'neutral',\n};\n\nconst ChevronIcon: React.FC = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n);\n\nconst RetryIcon: React.FC = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M3 12a9 9 0 1 0 3-6.7\" />\n <path d=\"M3 4v5h5\" />\n </svg>\n);\n\nconst StatusPill: React.FC<{ status: AgentStatus; label: string }> = ({ status, label }) => (\n <span className={cn('dishui-ai-task-rows__status', `dishui-ai-task-rows__status--${STATUS_TONE[status]}`)}>\n {status === 'running' && <span className=\"dishui-ai-task-rows__pulse\" aria-hidden=\"true\" />}\n {label}\n </span>\n);\n\nconst defaultExpandedFor = (tasks: AgentTask[]) =>\n tasks.filter(t => t.status === 'running' || t.status === 'failed').map(t => t.id);\n\n/**\n * Live agent task status. Each task is a row (or capsule) with a text +\n * colour status pill, optional progress and expandable subtasks with\n * right-aligned tabular values.\n */\nexport default function TaskRows({\n tasks,\n view: viewProp,\n defaultView = 'capsules',\n onViewChange,\n showViewToggle = false,\n expanded: expandedProp,\n defaultExpanded,\n onExpandedChange,\n onRetry,\n emptyText = 'No tasks yet',\n labels,\n className,\n ...rest\n}: TaskRowsProps) {\n const baseId = useId();\n const text = { ...DEFAULT_LABELS, ...labels };\n\n const [internalView, setInternalView] = useState<TaskRowsView>(defaultView);\n const view = viewProp ?? internalView;\n const changeView = useCallback((next: TaskRowsView) => {\n setInternalView(next);\n onViewChange?.(next);\n }, [onViewChange]);\n\n const [internalExpanded, setInternalExpanded] = useState<string[]>(\n () => defaultExpanded ?? defaultExpandedFor(tasks),\n );\n const expanded = expandedProp ?? internalExpanded;\n const toggle = useCallback((id: string) => {\n const next = expanded.includes(id) ? expanded.filter(x => x !== id) : [...expanded, id];\n setInternalExpanded(next);\n onExpandedChange?.(next);\n }, [expanded, onExpandedChange]);\n\n const statusLabel = (status: AgentStatus) => labels?.status?.[status] ?? AGENT_STATUS_LABEL[status];\n\n return (\n <div {...rest} className={cn('dishui-ai-task-rows', `dishui-ai-task-rows--${view}`, className)}>\n {showViewToggle && (\n <div className=\"dishui-ai-task-rows__toolbar\">\n <div className=\"dishui-ai-task-rows__segmented\" role=\"group\" aria-label={text.view}>\n {(['capsules', 'list'] as TaskRowsView[]).map(v => (\n <button\n key={v}\n type=\"button\"\n className={cn('dishui-ai-task-rows__segment', v === view && 'dishui-ai-task-rows__segment--active')}\n aria-pressed={v === view}\n onClick={() => changeView(v)}\n >\n {text[v]}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {tasks.length === 0 ? (\n <div className=\"dishui-ai-task-rows__empty\">{emptyText}</div>\n ) : (\n <ul className=\"dishui-ai-task-rows__list\">\n {tasks.map(task => {\n const hasSubtasks = !!task.subtasks?.length;\n const isOpen = hasSubtasks && expanded.includes(task.id);\n const panelId = `${baseId}-${task.id}`;\n const progress = task.progress === undefined ? undefined : clamp(task.progress, 0, 100);\n const showBar = view === 'capsules' && (progress !== undefined || task.status === 'running');\n return (\n <li\n key={task.id}\n className={cn(\n 'dishui-ai-task-rows__task',\n `dishui-ai-task-rows__task--${task.status}`,\n isOpen && 'dishui-ai-task-rows__task--open',\n )}\n >\n <div className=\"dishui-ai-task-rows__row\">\n {hasSubtasks ? (\n <button\n type=\"button\"\n className=\"dishui-ai-task-rows__toggle\"\n aria-expanded={isOpen}\n aria-controls={panelId}\n onClick={() => toggle(task.id)}\n >\n <span className=\"dishui-ai-task-rows__chevron\"><ChevronIcon /></span>\n <span className=\"dishui-ai-task-rows__title\">{task.title}</span>\n {task.meta !== undefined && <span className=\"dishui-ai-task-rows__meta\">{task.meta}</span>}\n </button>\n ) : (\n <div className=\"dishui-ai-task-rows__toggle dishui-ai-task-rows__toggle--static\">\n <span className=\"dishui-ai-task-rows__chevron dishui-ai-task-rows__chevron--blank\" />\n <span className=\"dishui-ai-task-rows__title\">{task.title}</span>\n {task.meta !== undefined && <span className=\"dishui-ai-task-rows__meta\">{task.meta}</span>}\n </div>\n )}\n {progress !== undefined && task.status === 'running' && (\n <span className=\"dishui-ai-task-rows__percent\">{Math.round(progress)}%</span>\n )}\n <StatusPill status={task.status} label={statusLabel(task.status)} />\n </div>\n\n {showBar && (\n <div\n className={cn('dishui-ai-task-rows__bar', progress === undefined && 'dishui-ai-task-rows__bar--indeterminate')}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress}\n >\n <span className=\"dishui-ai-task-rows__fill\" style={progress === undefined ? undefined : { width: `${progress}%` }} />\n </div>\n )}\n\n {task.status === 'failed' && (task.error !== undefined || onRetry) && (\n <div className=\"dishui-ai-task-rows__error\" role=\"alert\">\n <span className=\"dishui-ai-task-rows__error-text\">{task.error}</span>\n {onRetry && (\n <button type=\"button\" className=\"dishui-ai-task-rows__retry\" onClick={() => onRetry(task)}>\n <RetryIcon />\n {text.retry}\n </button>\n )}\n </div>\n )}\n\n {hasSubtasks && (\n <ul id={panelId} className=\"dishui-ai-task-rows__subtasks\" hidden={!isOpen}>\n {task.subtasks!.map(sub => (\n <li\n key={sub.id}\n className={cn('dishui-ai-task-rows__subtask', sub.status && `dishui-ai-task-rows__subtask--${sub.status}`)}\n >\n <span className=\"dishui-ai-task-rows__subtitle\">{sub.title}</span>\n {sub.value !== undefined && <span className=\"dishui-ai-task-rows__value\">{sub.value}</span>}\n {sub.status && sub.status !== task.status && (\n <span className=\"dishui-ai-task-rows__substatus\">{statusLabel(sub.status)}</span>\n )}\n </li>\n ))}\n </ul>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/Thinking/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { formatDuration, formatElapsed, AGENT_STATUS_LABEL } from '../shared';\nimport type { AgentStatus } from '../shared';\nimport './Thinking.css';\n\nexport type ThinkingStepKind = 'step' | 'reasoning' | 'search' | 'coding';\nexport type ThinkingMode = 'steps' | 'reasoning' | 'search' | 'coding' | 'auto';\nexport type ThinkingStatus = 'thinking' | 'done';\n\nexport type ThinkingSearchResult = { title: string; url?: string; domain?: string };\nexport type ThinkingCode = { language?: string; content: string; file?: string };\n\nexport type ThinkingStep = {\n id: string;\n kind: ThinkingStepKind;\n title: React.ReactNode;\n detail?: React.ReactNode;\n /** Defaults to `completed`. */\n status?: AgentStatus;\n durationMs?: number;\n /** Result chips rendered by `search` steps. */\n results?: ThinkingSearchResult[];\n /** Code block rendered by `coding` steps. */\n code?: ThinkingCode;\n};\n\nexport type ThinkingProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title'> & {\n steps: ThinkingStep[];\n /** Derived from the steps when omitted: any running step → `thinking`. */\n status?: ThinkingStatus;\n /** Total time; rendered as “Thought for 4s” once done. Falls back to the sum of step durations. */\n durationMs?: number;\n /** Overrides the default “Thinking” / “Thought for …” header text. */\n title?: React.ReactNode;\n expanded?: boolean;\n defaultExpanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** Rendering emphasis. `auto` renders each step by its own `kind`. */\n mode?: ThinkingMode;\n};\n\nconst MODE_KIND: Record<Exclude<ThinkingMode, 'auto'>, ThinkingStepKind> = {\n steps: 'step',\n reasoning: 'reasoning',\n search: 'search',\n coding: 'coding',\n};\n\nconst ChevronIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n);\nconst CheckIcon = () => (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n);\nconst XIcon = () => (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n);\n\nconst Marker: React.FC<{ status: AgentStatus }> = ({ status }) => (\n <span className={cn('dishui-ai-thinking__marker', `dishui-ai-thinking__marker--${status}`)} title={AGENT_STATUS_LABEL[status]}>\n {status === 'completed' && <CheckIcon />}\n {status === 'failed' && <XIcon />}\n <span className=\"dishui-ai-thinking__sr\">{AGENT_STATUS_LABEL[status]}</span>\n </span>\n);\n\nconst initialOf = (result: ThinkingSearchResult) => (result.domain ?? result.title).trim().charAt(0).toUpperCase();\n\nconst StepBody: React.FC<{ step: ThinkingStep; kind: ThinkingStepKind }> = ({ step, kind }) => {\n const status = step.status ?? 'completed';\n return (\n <li className={cn('dishui-ai-thinking__step', `dishui-ai-thinking__step--${kind}`, `dishui-ai-thinking__step--${status}`)}>\n <Marker status={status} />\n <div className=\"dishui-ai-thinking__content\">\n <div className=\"dishui-ai-thinking__step-row\">\n <span className=\"dishui-ai-thinking__step-title\">{step.title}</span>\n {step.durationMs !== undefined && <span className=\"dishui-ai-thinking__step-duration\">{formatElapsed(step.durationMs)}</span>}\n </div>\n {step.detail !== undefined && <div className=\"dishui-ai-thinking__detail\">{step.detail}</div>}\n {kind === 'search' && step.results && step.results.length > 0 && (\n <ul className=\"dishui-ai-thinking__results\">\n {step.results.map(result => {\n const inner = (\n <>\n <span className=\"dishui-ai-thinking__result-initial\" aria-hidden=\"true\">{initialOf(result)}</span>\n <span className=\"dishui-ai-thinking__result-title\">{result.title}</span>\n {result.domain && <span className=\"dishui-ai-thinking__result-domain\">{result.domain}</span>}\n </>\n );\n return (\n <li key={`${result.url ?? ''}-${result.domain ?? ''}-${result.title}`}>\n {result.url ? (\n <a className=\"dishui-ai-thinking__result\" href={result.url} target=\"_blank\" rel=\"noreferrer\">{inner}</a>\n ) : (\n <span className=\"dishui-ai-thinking__result\">{inner}</span>\n )}\n </li>\n );\n })}\n </ul>\n )}\n {kind === 'coding' && step.code && (\n <div className=\"dishui-ai-thinking__code\">\n <div className=\"dishui-ai-thinking__code-header\">\n <span className=\"dishui-ai-thinking__code-file\">{step.code.file ?? 'snippet'}</span>\n {step.code.language && <span className=\"dishui-ai-thinking__code-lang\">{step.code.language}</span>}\n </div>\n <pre className=\"dishui-ai-thinking__code-body\"><code>{step.code.content}</code></pre>\n </div>\n )}\n </div>\n </li>\n );\n};\n\n/**\n * Expandable reasoning trace. Collapsed by default; the header summarises the\n * currently running step while collapsed and reads “Thought for …” once done.\n */\nexport default function Thinking({\n steps,\n status: statusProp,\n durationMs,\n title,\n expanded: expandedProp,\n defaultExpanded = false,\n onExpandedChange,\n mode = 'auto',\n className,\n ...rest\n}: ThinkingProps) {\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n const controlled = expandedProp !== undefined;\n const expanded = controlled ? expandedProp : internalExpanded;\n const bodyId = useId();\n\n const running = steps.find(step => step.status === 'running');\n const status: ThinkingStatus = statusProp ?? (running ? 'thinking' : 'done');\n const thinking = status === 'thinking';\n\n const stepDurations = steps.reduce<number | undefined>(\n (sum, step) => (step.durationMs === undefined ? sum : (sum ?? 0) + step.durationMs),\n undefined,\n );\n const totalMs = durationMs ?? stepDurations;\n\n const defaultTitle = thinking ? 'Thinking' : totalMs !== undefined ? `Thought for ${formatDuration(totalMs)}` : 'Thought';\n const showDurationMeta = title !== undefined && !thinking && totalMs !== undefined;\n\n const toggle = () => {\n const next = !expanded;\n if (!controlled) setInternalExpanded(next);\n onExpandedChange?.(next);\n };\n\n return (\n <div\n {...rest}\n className={cn('dishui-ai-thinking', thinking && 'dishui-ai-thinking--thinking', expanded && 'dishui-ai-thinking--expanded', className)}\n >\n <button type=\"button\" className=\"dishui-ai-thinking__header\" aria-expanded={expanded} aria-controls={bodyId} onClick={toggle}>\n {thinking && (\n <span className=\"dishui-ai-thinking__glyph\" aria-hidden=\"true\">\n <span className=\"dishui-ai-thinking__cell\" />\n <span className=\"dishui-ai-thinking__cell\" />\n <span className=\"dishui-ai-thinking__cell\" />\n </span>\n )}\n <span className=\"dishui-ai-thinking__title\">{title ?? defaultTitle}</span>\n {!expanded && thinking && running && <span className=\"dishui-ai-thinking__summary\">{running.title}</span>}\n {!expanded && !thinking && steps.length > 0 && (\n <span className=\"dishui-ai-thinking__meta\">{steps.length} {steps.length === 1 ? 'step' : 'steps'}</span>\n )}\n {showDurationMeta && <span className=\"dishui-ai-thinking__meta\">{formatDuration(totalMs)}</span>}\n <span className=\"dishui-ai-thinking__chevron\" aria-hidden=\"true\"><ChevronIcon /></span>\n </button>\n <div id={bodyId} className=\"dishui-ai-thinking__body\" hidden={!expanded}>\n {steps.length === 0 ? (\n <p className=\"dishui-ai-thinking__empty\">No steps recorded.</p>\n ) : (\n <ol className=\"dishui-ai-thinking__trace\">\n {steps.map(step => (\n <StepBody key={step.id} step={step} kind={mode === 'auto' ? step.kind : MODE_KIND[mode]} />\n ))}\n </ol>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_Fragment","MODE_KIND","ChevronIcon","CheckIcon","XIcon","Marker","cn","status","AGENT_STATUS_LABEL","initialOf","result","StepBody","step","kind","formatElapsed","inner","Fragment","Thinking","statusProp","expandedProp","rest","internalExpanded","setInternalExpanded","useState","defaultExpanded","controlled","expanded","bodyId","useId","running","steps","thinking","stepDurations","sum","totalMs","durationMs","defaultTitle","formatDuration","showDurationMeta","title","toggle","next","onExpandedChange","className","mode"],"sources":["../../../../src/components/ai/Thinking/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { formatDuration, formatElapsed, AGENT_STATUS_LABEL } from '../shared';\nimport type { AgentStatus } from '../shared';\nimport './Thinking.css';\n\nexport type ThinkingStepKind = 'step' | 'reasoning' | 'search' | 'coding';\nexport type ThinkingMode = 'steps' | 'reasoning' | 'search' | 'coding' | 'auto';\nexport type ThinkingStatus = 'thinking' | 'done';\n\nexport type ThinkingSearchResult = { title: string; url?: string; domain?: string };\nexport type ThinkingCode = { language?: string; content: string; file?: string };\n\nexport type ThinkingStep = {\n id: string;\n kind: ThinkingStepKind;\n title: React.ReactNode;\n detail?: React.ReactNode;\n /** Defaults to `completed`. */\n status?: AgentStatus;\n durationMs?: number;\n /** Result chips rendered by `search` steps. */\n results?: ThinkingSearchResult[];\n /** Code block rendered by `coding` steps. */\n code?: ThinkingCode;\n};\n\nexport type ThinkingProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title'> & {\n steps: ThinkingStep[];\n /** Derived from the steps when omitted: any running step → `thinking`. */\n status?: ThinkingStatus;\n /** Total time; rendered as “Thought for 4s” once done. Falls back to the sum of step durations. */\n durationMs?: number;\n /** Overrides the default “Thinking” / “Thought for …” header text. */\n title?: React.ReactNode;\n expanded?: boolean;\n defaultExpanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** Rendering emphasis. `auto` renders each step by its own `kind`. */\n mode?: ThinkingMode;\n};\n\nconst MODE_KIND: Record<Exclude<ThinkingMode, 'auto'>, ThinkingStepKind> = {\n steps: 'step',\n reasoning: 'reasoning',\n search: 'search',\n coding: 'coding',\n};\n\nconst ChevronIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n);\nconst CheckIcon = () => (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n);\nconst XIcon = () => (\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n);\n\nconst Marker: React.FC<{ status: AgentStatus }> = ({ status }) => (\n <span className={cn('dishui-ai-thinking__marker', `dishui-ai-thinking__marker--${status}`)} title={AGENT_STATUS_LABEL[status]}>\n {status === 'completed' && <CheckIcon />}\n {status === 'failed' && <XIcon />}\n <span className=\"dishui-ai-thinking__sr\">{AGENT_STATUS_LABEL[status]}</span>\n </span>\n);\n\nconst initialOf = (result: ThinkingSearchResult) => (result.domain ?? result.title).trim().charAt(0).toUpperCase();\n\nconst StepBody: React.FC<{ step: ThinkingStep; kind: ThinkingStepKind }> = ({ step, kind }) => {\n const status = step.status ?? 'completed';\n return (\n <li className={cn('dishui-ai-thinking__step', `dishui-ai-thinking__step--${kind}`, `dishui-ai-thinking__step--${status}`)}>\n <Marker status={status} />\n <div className=\"dishui-ai-thinking__content\">\n <div className=\"dishui-ai-thinking__step-row\">\n <span className=\"dishui-ai-thinking__step-title\">{step.title}</span>\n {step.durationMs !== undefined && <span className=\"dishui-ai-thinking__step-duration\">{formatElapsed(step.durationMs)}</span>}\n </div>\n {step.detail !== undefined && <div className=\"dishui-ai-thinking__detail\">{step.detail}</div>}\n {kind === 'search' && step.results && step.results.length > 0 && (\n <ul className=\"dishui-ai-thinking__results\">\n {step.results.map(result => {\n const inner = (\n <>\n <span className=\"dishui-ai-thinking__result-initial\" aria-hidden=\"true\">{initialOf(result)}</span>\n <span className=\"dishui-ai-thinking__result-title\">{result.title}</span>\n {result.domain && <span className=\"dishui-ai-thinking__result-domain\">{result.domain}</span>}\n </>\n );\n return (\n <li key={`${result.url ?? ''}-${result.domain ?? ''}-${result.title}`}>\n {result.url ? (\n <a className=\"dishui-ai-thinking__result\" href={result.url} target=\"_blank\" rel=\"noreferrer\">{inner}</a>\n ) : (\n <span className=\"dishui-ai-thinking__result\">{inner}</span>\n )}\n </li>\n );\n })}\n </ul>\n )}\n {kind === 'coding' && step.code && (\n <div className=\"dishui-ai-thinking__code\">\n <div className=\"dishui-ai-thinking__code-header\">\n <span className=\"dishui-ai-thinking__code-file\">{step.code.file ?? 'snippet'}</span>\n {step.code.language && <span className=\"dishui-ai-thinking__code-lang\">{step.code.language}</span>}\n </div>\n <pre className=\"dishui-ai-thinking__code-body\"><code>{step.code.content}</code></pre>\n </div>\n )}\n </div>\n </li>\n );\n};\n\n/**\n * Expandable reasoning trace. Collapsed by default; the header summarises the\n * currently running step while collapsed and reads “Thought for …” once done.\n */\nexport default function Thinking({\n steps,\n status: statusProp,\n durationMs,\n title,\n expanded: expandedProp,\n defaultExpanded = false,\n onExpandedChange,\n mode = 'auto',\n className,\n ...rest\n}: ThinkingProps) {\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n const controlled = expandedProp !== undefined;\n const expanded = controlled ? expandedProp : internalExpanded;\n const bodyId = useId();\n\n const running = steps.find(step => step.status === 'running');\n const status: ThinkingStatus = statusProp ?? (running ? 'thinking' : 'done');\n const thinking = status === 'thinking';\n\n const stepDurations = steps.reduce<number | undefined>(\n (sum, step) => (step.durationMs === undefined ? sum : (sum ?? 0) + step.durationMs),\n undefined,\n );\n const totalMs = durationMs ?? stepDurations;\n\n const defaultTitle = thinking ? 'Thinking' : totalMs !== undefined ? `Thought for ${formatDuration(totalMs)}` : 'Thought';\n const showDurationMeta = title !== undefined && !thinking && totalMs !== undefined;\n\n const toggle = () => {\n const next = !expanded;\n if (!controlled) setInternalExpanded(next);\n onExpandedChange?.(next);\n };\n\n return (\n <div\n {...rest}\n className={cn('dishui-ai-thinking', thinking && 'dishui-ai-thinking--thinking', expanded && 'dishui-ai-thinking--expanded', className)}\n >\n <button type=\"button\" className=\"dishui-ai-thinking__header\" aria-expanded={expanded} aria-controls={bodyId} onClick={toggle}>\n {thinking && (\n <span className=\"dishui-ai-thinking__glyph\" aria-hidden=\"true\">\n <span className=\"dishui-ai-thinking__cell\" />\n <span className=\"dishui-ai-thinking__cell\" />\n <span className=\"dishui-ai-thinking__cell\" />\n </span>\n )}\n <span className=\"dishui-ai-thinking__title\">{title ?? defaultTitle}</span>\n {!expanded && thinking && running && <span className=\"dishui-ai-thinking__summary\">{running.title}</span>}\n {!expanded && !thinking && steps.length > 0 && (\n <span className=\"dishui-ai-thinking__meta\">{steps.length} {steps.length === 1 ? 'step' : 'steps'}</span>\n )}\n {showDurationMeta && <span className=\"dishui-ai-thinking__meta\">{formatDuration(totalMs)}</span>}\n <span className=\"dishui-ai-thinking__chevron\" aria-hidden=\"true\"><ChevronIcon /></span>\n </button>\n <div id={bodyId} className=\"dishui-ai-thinking__body\" hidden={!expanded}>\n {steps.length === 0 ? (\n <p className=\"dishui-ai-thinking__empty\">No steps recorded.</p>\n ) : (\n <ol className=\"dishui-ai-thinking__trace\">\n {steps.map(step => (\n <StepBody key={step.id} step={step} kind={mode === 'auto' ? step.kind : MODE_KIND[mode]} />\n ))}\n </ol>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/ToolChips/index.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport type { AgentStatus } from '../shared';\nimport { AGENT_STATUS_LABEL } from '../shared';\nimport './ToolChips.css';\n\nconst EMPTY_EXPANDED: string[] = [];\n\nexport type ToolChip = { id: string; label: React.ReactNode; status?: AgentStatus; detail?: React.ReactNode; duration?: string; onRetry?: () => void };\nexport type ToolChipsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & { tools: ToolChip[]; expanded?: string[]; defaultExpanded?: string[]; onExpandedChange?: (ids: string[]) => void; labels?: Partial<Record<AgentStatus, string>> & { retry?: string; empty?: string } };\n\nexport default function ToolChips({ tools, expanded, defaultExpanded = EMPTY_EXPANDED, onExpandedChange, labels, className, ...rest }: ToolChipsProps) {\n const [internal, setInternal] = useState(defaultExpanded);\n const open = expanded ?? internal;\n const toggle = (id: string) => { const next = open.includes(id) ? open.filter(x => x !== id) : [...open, id]; if (expanded === undefined) setInternal(next); onExpandedChange?.(next); };\n if (!tools.length) return <div {...rest} className={cn('dishui-ai-tool-chips dishui-ai-tool-chips--empty', className)}>{labels?.empty ?? 'No tools used'}</div>;\n return <div {...rest} className={cn('dishui-ai-tool-chips', className)}>{tools.map(tool => { const status = tool.status ?? 'completed'; const isOpen = open.includes(tool.id); const panelId = `tool-${tool.id}-detail`; return <div key={tool.id} className={cn('dishui-ai-tool-chips__item', `dishui-ai-tool-chips__item--${status}`)}><button type=\"button\" className=\"dishui-ai-tool-chips__chip\" aria-expanded={tool.detail ? isOpen : undefined} aria-controls={tool.detail ? panelId : undefined} onClick={() => tool.detail && toggle(tool.id)}><span className=\"dishui-ai-tool-chips__mark\" aria-hidden=\"true\">{status === 'completed' ? '✓' : status === 'failed' ? '!' : status === 'running' ? '…' : '·'}</span><span>{tool.label}</span><span className=\"dishui-ai-tool-chips__status\">{labels?.[status] ?? AGENT_STATUS_LABEL[status]}</span>{tool.duration && <span className=\"dishui-ai-tool-chips__duration\">{tool.duration}</span>}</button>{tool.detail && <div id={panelId} hidden={!isOpen} className=\"dishui-ai-tool-chips__detail\">{tool.detail}{status === 'failed' && tool.onRetry && <button type=\"button\" onClick={tool.onRetry}>{labels?.retry ?? 'Retry'}</button>}</div>}</div>; })}</div>;\n}\n"],"mappings":";;;;;;AAMA,IAAM,IAA2B,CAAC;AAKlC,SAAwB,EAAU,EAAE,UAAO,aAAU,qBAAkB,GAAgB,qBAAkB,WAAQ,cAAW,GAAG,KAAwB;CACrJ,IAAM,CAAC,GAAU,KAAe,EAAS,CAAe,GAClD,IAAO,KAAY,GACnB,KAAU,MAAe;EAAE,IAAM,IAAO,EAAK,SAAS,CAAE,IAAI,EAAK,QAAO,MAAK,MAAM,CAAE,IAAI,CAAC,GAAG,GAAM,CAAE;EAAkD,AAA3C,MAAa,KAAA,KAAW,EAAY,CAAI,GAAG,IAAmB,CAAI;CAAG;CAEvL,OADK,EAAM,SACJ,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,wBAAwB,CAAS;EAAI,UAAA,EAAM,KAAI,MAAQ;GAAE,IAAM,IAAS,EAAK,UAAU,aAAmB,IAAS,EAAK,SAAS,EAAK,EAAE,GAAS,IAAU,QAAQ,EAAK,GAAG;GAAU,OAAO,kBAAC,OAAD;IAAmB,WAAW,EAAG,8BAA8B,+BAA+B,GAAQ;IAAtG,UAAA,CAAyG,kBAAC,UAAD;KAAQ,MAAK;KAAS,WAAU;KAA6B,iBAAe,EAAK,SAAS,IAAS,KAAA;KAAW,iBAAe,EAAK,SAAS,IAAU,KAAA;KAAW,eAAe,EAAK,UAAU,EAAO,EAAK,EAAE;KAA5M,UAAA;MAA+M,kBAAC,QAAD;OAAM,WAAU;OAA6B,eAAY;OAAQ,UAAA,MAAW,cAAc,MAAM,MAAW,WAAW,MAAM,MAAW,YAAY,MAAM;MAAU,CAAA;MAAC,kBAAC,QAAD,EAAA,UAAO,EAAK,MAAY,CAAA;MAAC,kBAAC,QAAD;OAAM,WAAU;OAAgC,UAAA,IAAS,MAAW,EAAmB;MAAc,CAAA;MAAE,EAAK,YAAY,kBAAC,QAAD;OAAM,WAAU;OAAkC,UAAA,EAAK;MAAe,CAAA;KAAU;IAAE,CAAA,GAAA,EAAK,UAAU,kBAAC,OAAD;KAAK,IAAI;KAAS,QAAQ,CAAC;KAAQ,WAAU;KAA7C,UAAA,CAA6E,EAAK,QAAQ,MAAW,YAAY,EAAK,WAAW,kBAAC,UAAD;MAAQ,MAAK;MAAS,SAAS,EAAK;MAAU,UAAA,GAAQ,SAAS;KAAgB,CAAA,CAAO;IAAO,CAAA,CAAA;GAAl6B,GAAA,EAAK,EAA65B;EAAG,CAAC;CAAO,CAAA,IAD7nC,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,oDAAoD,CAAS;EAAI,UAAA,GAAQ,SAAS;CAAqB,CAAA;AAEhK"}
1
+ {"version":3,"file":"index.js","names":["EMPTY_EXPANDED","ToolChips","rest","internal","setInternal","useState","defaultExpanded","open","expanded","toggle","next","id","x","onExpandedChange","tools","cn","className","status","tool","isOpen","panelId","labels","AGENT_STATUS_LABEL"],"sources":["../../../../src/components/ai/ToolChips/index.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport type { AgentStatus } from '../shared';\nimport { AGENT_STATUS_LABEL } from '../shared';\nimport './ToolChips.css';\n\nconst EMPTY_EXPANDED: string[] = [];\n\nexport type ToolChip = { id: string; label: React.ReactNode; status?: AgentStatus; detail?: React.ReactNode; duration?: string; onRetry?: () => void };\nexport type ToolChipsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & { tools: ToolChip[]; expanded?: string[]; defaultExpanded?: string[]; onExpandedChange?: (ids: string[]) => void; labels?: Partial<Record<AgentStatus, string>> & { retry?: string; empty?: string } };\n\nexport default function ToolChips({ tools, expanded, defaultExpanded = EMPTY_EXPANDED, onExpandedChange, labels, className, ...rest }: ToolChipsProps) {\n const [internal, setInternal] = useState(defaultExpanded);\n const open = expanded ?? internal;\n const toggle = (id: string) => { const next = open.includes(id) ? open.filter(x => x !== id) : [...open, id]; if (expanded === undefined) setInternal(next); onExpandedChange?.(next); };\n if (!tools.length) return <div {...rest} className={cn('dishui-ai-tool-chips dishui-ai-tool-chips--empty', className)}>{labels?.empty ?? 'No tools used'}</div>;\n return <div {...rest} className={cn('dishui-ai-tool-chips', className)}>{tools.map(tool => { const status = tool.status ?? 'completed'; const isOpen = open.includes(tool.id); const panelId = `tool-${tool.id}-detail`; return <div key={tool.id} className={cn('dishui-ai-tool-chips__item', `dishui-ai-tool-chips__item--${status}`)}><button type=\"button\" className=\"dishui-ai-tool-chips__chip\" aria-expanded={tool.detail ? isOpen : undefined} aria-controls={tool.detail ? panelId : undefined} onClick={() => tool.detail && toggle(tool.id)}><span className=\"dishui-ai-tool-chips__mark\" aria-hidden=\"true\">{status === 'completed' ? '✓' : status === 'failed' ? '!' : status === 'running' ? '…' : '·'}</span><span>{tool.label}</span><span className=\"dishui-ai-tool-chips__status\">{labels?.[status] ?? AGENT_STATUS_LABEL[status]}</span>{tool.duration && <span className=\"dishui-ai-tool-chips__duration\">{tool.duration}</span>}</button>{tool.detail && <div id={panelId} hidden={!isOpen} className=\"dishui-ai-tool-chips__detail\">{tool.detail}{status === 'failed' && tool.onRetry && <button type=\"button\" onClick={tool.onRetry}>{labels?.retry ?? 'Retry'}</button>}</div>}</div>; })}</div>;\n}\n"],"mappings":";;;;;;AAMA,IAAMA,IAA2B,CAAC;AAKlC,SAAwBC,EAAU,EAAE,UAAO,aAAU,qBAAkBD,GAAgB,qBAAkB,WAAQ,cAAW,GAAGE,KAAwB;CACrJ,IAAM,CAACC,GAAUC,KAAeC,EAASC,CAAe,GAClDC,IAAOC,KAAYL,GACnBM,KAAU,MAAe;EAAE,IAAMC,IAAOH,EAAK,SAASI,CAAE,IAAIJ,EAAK,QAAO,MAAKK,MAAMD,CAAE,IAAI,CAAC,GAAGJ,GAAMI,CAAE;EAAkD,AAA3CH,MAAa,KAAA,KAAWJ,EAAYM,CAAI,GAAGG,IAAmBH,CAAI;CAAG;CAEvL,OADKI,EAAM,SACJ,kBAAC,OAAD;EAAK,GAAIZ;EAAM,WAAWa,EAAG,wBAAwBC,CAAS;EAAI,UAAAF,EAAM,KAAI,MAAQ;GAAE,IAAMG,IAASC,EAAK,UAAU,aAAmBC,IAASZ,EAAK,SAASW,EAAK,EAAE,GAASE,IAAU,QAAQF,EAAK,GAAG;GAAU,OAAO,kBAAC,OAAD;IAAmB,WAAWH,EAAG,8BAA8B,+BAA+BE,GAAQ;IAAtG,UAAA,CAAyG,kBAAC,UAAD;KAAQ,MAAK;KAAS,WAAU;KAA6B,iBAAeC,EAAK,SAASC,IAAS,KAAA;KAAW,iBAAeD,EAAK,SAASE,IAAU,KAAA;KAAW,eAAeF,EAAK,UAAUT,EAAOS,EAAK,EAAE;KAA5M,UAAA;MAA+M,kBAAC,QAAD;OAAM,WAAU;OAA6B,eAAY;OAAQ,UAAAD,MAAW,cAAc,MAAMA,MAAW,WAAW,MAAMA,MAAW,YAAY,MAAM;MAAU,CAAA;MAAC,kBAAC,QAAD,EAAA,UAAOC,EAAK,MAAY,CAAA;MAAC,kBAAC,QAAD;OAAM,WAAU;OAAgC,UAAAG,IAASJ,MAAWK,EAAmBL;MAAc,CAAA;MAAEC,EAAK,YAAY,kBAAC,QAAD;OAAM,WAAU;OAAkC,UAAAA,EAAK;MAAe,CAAA;KAAU;IAAE,CAAA,GAAAA,EAAK,UAAU,kBAAC,OAAD;KAAK,IAAIE;KAAS,QAAQ,CAACD;KAAQ,WAAU;KAA7C,UAAA,CAA6ED,EAAK,QAAQD,MAAW,YAAYC,EAAK,WAAW,kBAAC,UAAD;MAAQ,MAAK;MAAS,SAASA,EAAK;MAAU,UAAAG,GAAQ,SAAS;KAAgB,CAAA,CAAO;IAAO,CAAA,CAAA;GAAl6B,GAAAH,EAAK,EAA65B;EAAG,CAAC;CAAO,CAAA,IAD7nC,kBAAC,OAAD;EAAK,GAAIhB;EAAM,WAAWa,EAAG,oDAAoDC,CAAS;EAAI,UAAAK,GAAQ,SAAS;CAAqB,CAAA;AAEhK"}
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","names":[],"sources":["../../../src/components/ai/shared.ts"],"sourcesContent":["/**\n * Shared helpers for the AI-native component set (`src/components/ai`).\n * Keep this file dependency-free so every component can import it cheaply.\n */\n\n/** Format elapsed milliseconds as `0.0s`, `12s`, `1m 04s`. */\nexport function formatElapsed(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) ms = 0;\n const seconds = ms / 1000;\n if (seconds < 10) return `${seconds.toFixed(1)}s`;\n if (seconds < 60) return `${Math.floor(seconds)}s`;\n const minutes = Math.floor(seconds / 60);\n const rest = Math.floor(seconds % 60);\n return `${minutes}m ${rest.toString().padStart(2, '0')}s`;\n}\n\n/** Format a duration for prose, e.g. `for 4s`, `for 1m 04s`. */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) ms = 0;\n const seconds = Math.round(ms / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n const rest = seconds % 60;\n return `${minutes}m ${rest.toString().padStart(2, '0')}s`;\n}\n\n/** Status vocabulary shared by task rows, tool chips and thinking steps. */\nexport type AgentStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';\n\nexport const AGENT_STATUS_LABEL: Record<AgentStatus, string> = {\n pending: 'Pending',\n running: 'Running',\n completed: 'Completed',\n failed: 'Failed',\n skipped: 'Skipped',\n};\n\n/** Clamp a number into `[min, max]`. */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n"],"mappings":";AAMA,SAAgB,EAAc,GAAoB;CAChD,CAAI,CAAC,OAAO,SAAS,CAAE,KAAK,IAAK,OAAG,IAAK;CACzC,IAAM,IAAU,IAAK;CAKrB,OAJI,IAAU,KAAW,GAAG,EAAQ,QAAQ,CAAC,EAAE,KAC3C,IAAU,KAAW,GAAG,KAAK,MAAM,CAAO,EAAE,KAGzC,GAFS,KAAK,MAAM,IAAU,EAE3B,EAAQ,IADL,KAAK,MAAM,IAAU,EACZ,CAAA,CAAK,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACzD;AAGA,SAAgB,EAAe,GAAoB;CACjD,CAAI,CAAC,OAAO,SAAS,CAAE,KAAK,IAAK,OAAG,IAAK;CACzC,IAAM,IAAU,KAAK,MAAM,IAAK,GAAI;CAIpC,OAHI,IAAU,KAAW,GAAG,EAAQ,KAG7B,GAFS,KAAK,MAAM,IAAU,EAE3B,EAAQ,KADL,IAAU,GAAA,CACI,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACzD;AAKA,IAAa,IAAkD;CAC7D,SAAS;CACT,SAAS;CACT,WAAW;CACX,QAAQ;CACR,SAAS;AACX;AAGA,SAAgB,EAAM,GAAe,GAAa,GAAqB;CACrE,OAAO,KAAK,IAAI,GAAK,KAAK,IAAI,GAAK,CAAK,CAAC;AAC3C"}
1
+ {"version":3,"file":"shared.js","names":["formatElapsed","ms","seconds","formatDuration","AGENT_STATUS_LABEL","clamp","max","min","value"],"sources":["../../../src/components/ai/shared.ts"],"sourcesContent":["/**\n * Shared helpers for the AI-native component set (`src/components/ai`).\n * Keep this file dependency-free so every component can import it cheaply.\n */\n\n/** Format elapsed milliseconds as `0.0s`, `12s`, `1m 04s`. */\nexport function formatElapsed(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) ms = 0;\n const seconds = ms / 1000;\n if (seconds < 10) return `${seconds.toFixed(1)}s`;\n if (seconds < 60) return `${Math.floor(seconds)}s`;\n const minutes = Math.floor(seconds / 60);\n const rest = Math.floor(seconds % 60);\n return `${minutes}m ${rest.toString().padStart(2, '0')}s`;\n}\n\n/** Format a duration for prose, e.g. `for 4s`, `for 1m 04s`. */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) ms = 0;\n const seconds = Math.round(ms / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n const rest = seconds % 60;\n return `${minutes}m ${rest.toString().padStart(2, '0')}s`;\n}\n\n/** Status vocabulary shared by task rows, tool chips and thinking steps. */\nexport type AgentStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';\n\nexport const AGENT_STATUS_LABEL: Record<AgentStatus, string> = {\n pending: 'Pending',\n running: 'Running',\n completed: 'Completed',\n failed: 'Failed',\n skipped: 'Skipped',\n};\n\n/** Clamp a number into `[min, max]`. */\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n"],"mappings":";AAMA,SAAgBA,EAAc,GAAoB;CAChD,CAAI,CAAC,OAAO,SAASC,CAAE,KAAKA,IAAK,OAAG,IAAK;CACzC,IAAMC,IAAUD,IAAK;CAKrB,OAJIC,IAAU,KAAW,GAAGA,EAAQ,QAAQ,CAAC,EAAE,KAC3CA,IAAU,KAAW,GAAG,KAAK,MAAMA,CAAO,EAAE,KAGzC,GAFS,KAAK,MAAMA,IAAU,EAE3B,EAAQ,IADL,KAAK,MAAMA,IAAU,EACZ,CAAA,CAAK,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACzD;AAGA,SAAgBC,EAAe,GAAoB;CACjD,CAAI,CAAC,OAAO,SAASF,CAAE,KAAKA,IAAK,OAAG,IAAK;CACzC,IAAMC,IAAU,KAAK,MAAMD,IAAK,GAAI;CAIpC,OAHIC,IAAU,KAAW,GAAGA,EAAQ,KAG7B,GAFS,KAAK,MAAMA,IAAU,EAE3B,EAAQ,KADLA,IAAU,GAAA,CACI,SAAS,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AACzD;AAKA,IAAaE,IAAkD;CAC7D,SAAS;CACT,SAAS;CACT,WAAW;CACX,QAAQ;CACR,SAAS;AACX;AAGA,SAAgBC,EAAM,GAAe,GAAa,GAAqB;CACrE,OAAO,KAAK,IAAIC,GAAK,KAAK,IAAIC,GAAKC,CAAK,CAAC;AAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/pro/ArticleContextMenu/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { useClickOutside } from '../../../hooks/useClickOutside';\nimport { useContainerElement } from '../../../hooks/useContainerElement';\nimport { SelectionInfo, getSelectionInfo, getMarkdownContent } from '../../../utils/selection';\n\n// 菜单项配置\nexport interface ContextMenuItem {\n id: string;\n label: string;\n icon?: React.ReactNode;\n description?: string;\n action: (content: string, selection?: SelectionInfo) => void;\n disabled?: boolean;\n}\n\nexport type { SelectionInfo } from '../../../utils/selection';\n\nexport interface ArticleContextMenuProps {\n /**\n * 绑定的容器 ID 或 ref\n */\n targetId?: string;\n targetRef?: React.RefObject<HTMLElement | HTMLDivElement | null>;\n\n /**\n * 菜单项列表\n */\n menuItems: ContextMenuItem[];\n\n /**\n * 自定义样式类名\n */\n className?: string;\n\n /**\n * 是否启用\n * @default true\n */\n enabled?: boolean;\n}\n\nconst ArticleContextMenu: React.FC<ArticleContextMenuProps> = ({\n targetId,\n targetRef,\n menuItems,\n className = '',\n enabled = true,\n}) => {\n const [visible, setVisible] = useState(false);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [hasSelection, setHasSelection] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n const container = useContainerElement(targetId, targetRef);\n\n // 点击外部关闭菜单\n useClickOutside(menuRef, useCallback(() => setVisible(false), []), visible);\n\n\n\n // 处理右键点击\n const handleContextMenu = useCallback((e: MouseEvent) => {\n if (!enabled || !container) return;\n\n // 检查点击位置是否在容器内\n let target = e.target as Node | null;\n let isInContainer = false;\n while (target) {\n if (target === container) {\n isInContainer = true;\n break;\n }\n target = target.parentNode;\n }\n\n if (!isInContainer) return;\n\n e.preventDefault();\n\n // 检查是否有选中文本\n const selection = window.getSelection();\n const hasText = selection && selection.toString().trim() !== '';\n setHasSelection(!!hasText);\n\n // 计算菜单位置(显示在鼠标上方)\n const menuHeight = 200; // 预估菜单高度\n const menuWidth = 200; // 预估菜单宽度\n\n let x = e.clientX;\n let y = e.clientY - menuHeight - 10; // 显示在鼠标上方\n\n // 边界检查\n if (y < 0) {\n y = e.clientY + 10; // 如果上方空间不够,显示在下方\n }\n if (x + menuWidth > window.innerWidth) {\n x = window.innerWidth - menuWidth - 10;\n }\n\n setPosition({ x, y });\n setVisible(true);\n }, [enabled, container]);\n\n // 处理菜单项点击\n const handleMenuItemClick = useCallback((item: ContextMenuItem) => {\n if (item.disabled) return;\n\n const content = getMarkdownContent(container);\n const selection = getSelectionInfo(container);\n\n item.action(content, selection);\n setVisible(false);\n }, [container]);\n\n // 滚动时关闭菜单\n useEffect(() => {\n if (!visible) return;\n\n const handleScroll = () => setVisible(false);\n document.addEventListener('scroll', handleScroll, true);\n\n return () => {\n document.removeEventListener('scroll', handleScroll, true);\n };\n }, [visible]);\n\n // 监听右键事件\n useEffect(() => {\n document.addEventListener('contextmenu', handleContextMenu);\n\n return () => {\n document.removeEventListener('contextmenu', handleContextMenu);\n };\n }, [handleContextMenu]);\n\n // ESC 键关闭菜单\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setVisible(false);\n }\n };\n\n if (visible) {\n document.addEventListener('keydown', handleKeyDown);\n }\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [visible]);\n\n if (!visible) return null;\n\n return (\n <div\n ref={menuRef}\n className={`fixed z-50 bg-base-100 rounded-lg shadow-2xl border border-base-300 py-2 min-w-[200px] ${className}`}\n style={{\n left: `${position.x}px`,\n top: `${position.y}px`,\n }}\n >\n {menuItems.map((item) => {\n const isDisabled = item.disabled || (!hasSelection && item.id !== 'copy' && item.id !== 'stats');\n\n return (\n <button\n key={item.id}\n onClick={() => handleMenuItemClick(item)}\n disabled={isDisabled}\n className={`w-full px-4 py-2 text-left flex items-center gap-3 hover:bg-base-200 transition-colors ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'\n }`}\n title={item.description}\n >\n {item.icon && (\n <span className=\"flex-shrink-0 w-5 h-5 flex items-center justify-center\">\n {item.icon}\n </span>\n )}\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium\">{item.label}</div>\n {item.description && (\n <div className=\"text-xs text-base-content/60 truncate\">{item.description}</div>\n )}\n </div>\n </button>\n );\n })}\n\n {menuItems.length === 0 && (\n <div className=\"px-4 py-2 text-sm text-base-content/60 text-center\">\n 暂无可用操作\n </div>\n )}\n </div>\n );\n};\n\nexport default ArticleContextMenu;\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["ArticleContextMenu","visible","setVisible","useState","position","setPosition","hasSelection","setHasSelection","menuRef","useRef","container","useContainerElement","targetId","targetRef","useCallback","handleContextMenu","enabled","target","isInContainer","selection","hasText","x","y","handleMenuItemClick","item","content","getMarkdownContent","getSelectionInfo","useEffect","handleScroll","handleKeyDown","className","menuItems","isDisabled"],"sources":["../../../../src/components/pro/ArticleContextMenu/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { useClickOutside } from '../../../hooks/useClickOutside';\nimport { useContainerElement } from '../../../hooks/useContainerElement';\nimport { SelectionInfo, getSelectionInfo, getMarkdownContent } from '../../../utils/selection';\n\n// 菜单项配置\nexport interface ContextMenuItem {\n id: string;\n label: string;\n icon?: React.ReactNode;\n description?: string;\n action: (content: string, selection?: SelectionInfo) => void;\n disabled?: boolean;\n}\n\nexport type { SelectionInfo } from '../../../utils/selection';\n\nexport interface ArticleContextMenuProps {\n /**\n * 绑定的容器 ID 或 ref\n */\n targetId?: string;\n targetRef?: React.RefObject<HTMLElement | HTMLDivElement | null>;\n\n /**\n * 菜单项列表\n */\n menuItems: ContextMenuItem[];\n\n /**\n * 自定义样式类名\n */\n className?: string;\n\n /**\n * 是否启用\n * @default true\n */\n enabled?: boolean;\n}\n\nconst ArticleContextMenu: React.FC<ArticleContextMenuProps> = ({\n targetId,\n targetRef,\n menuItems,\n className = '',\n enabled = true,\n}) => {\n const [visible, setVisible] = useState(false);\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [hasSelection, setHasSelection] = useState(false);\n const menuRef = useRef<HTMLDivElement>(null);\n const container = useContainerElement(targetId, targetRef);\n\n // 点击外部关闭菜单\n useClickOutside(menuRef, useCallback(() => setVisible(false), []), visible);\n\n\n\n // 处理右键点击\n const handleContextMenu = useCallback((e: MouseEvent) => {\n if (!enabled || !container) return;\n\n // 检查点击位置是否在容器内\n let target = e.target as Node | null;\n let isInContainer = false;\n while (target) {\n if (target === container) {\n isInContainer = true;\n break;\n }\n target = target.parentNode;\n }\n\n if (!isInContainer) return;\n\n e.preventDefault();\n\n // 检查是否有选中文本\n const selection = window.getSelection();\n const hasText = selection && selection.toString().trim() !== '';\n setHasSelection(!!hasText);\n\n // 计算菜单位置(显示在鼠标上方)\n const menuHeight = 200; // 预估菜单高度\n const menuWidth = 200; // 预估菜单宽度\n\n let x = e.clientX;\n let y = e.clientY - menuHeight - 10; // 显示在鼠标上方\n\n // 边界检查\n if (y < 0) {\n y = e.clientY + 10; // 如果上方空间不够,显示在下方\n }\n if (x + menuWidth > window.innerWidth) {\n x = window.innerWidth - menuWidth - 10;\n }\n\n setPosition({ x, y });\n setVisible(true);\n }, [enabled, container]);\n\n // 处理菜单项点击\n const handleMenuItemClick = useCallback((item: ContextMenuItem) => {\n if (item.disabled) return;\n\n const content = getMarkdownContent(container);\n const selection = getSelectionInfo(container);\n\n item.action(content, selection);\n setVisible(false);\n }, [container]);\n\n // 滚动时关闭菜单\n useEffect(() => {\n if (!visible) return;\n\n const handleScroll = () => setVisible(false);\n document.addEventListener('scroll', handleScroll, true);\n\n return () => {\n document.removeEventListener('scroll', handleScroll, true);\n };\n }, [visible]);\n\n // 监听右键事件\n useEffect(() => {\n document.addEventListener('contextmenu', handleContextMenu);\n\n return () => {\n document.removeEventListener('contextmenu', handleContextMenu);\n };\n }, [handleContextMenu]);\n\n // ESC 键关闭菜单\n useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n setVisible(false);\n }\n };\n\n if (visible) {\n document.addEventListener('keydown', handleKeyDown);\n }\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [visible]);\n\n if (!visible) return null;\n\n return (\n <div\n ref={menuRef}\n className={`fixed z-50 bg-base-100 rounded-lg shadow-2xl border border-base-300 py-2 min-w-[200px] ${className}`}\n style={{\n left: `${position.x}px`,\n top: `${position.y}px`,\n }}\n >\n {menuItems.map((item) => {\n const isDisabled = item.disabled || (!hasSelection && item.id !== 'copy' && item.id !== 'stats');\n\n return (\n <button\n key={item.id}\n onClick={() => handleMenuItemClick(item)}\n disabled={isDisabled}\n className={`w-full px-4 py-2 text-left flex items-center gap-3 hover:bg-base-200 transition-colors ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'\n }`}\n title={item.description}\n >\n {item.icon && (\n <span className=\"flex-shrink-0 w-5 h-5 flex items-center justify-center\">\n {item.icon}\n </span>\n )}\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium\">{item.label}</div>\n {item.description && (\n <div className=\"text-xs text-base-content/60 truncate\">{item.description}</div>\n )}\n </div>\n </button>\n );\n })}\n\n {menuItems.length === 0 && (\n <div className=\"px-4 py-2 text-sm text-base-content/60 text-center\">\n 暂无可用操作\n </div>\n )}\n </div>\n );\n};\n\nexport default ArticleContextMenu;\n\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ArticleControl2.js","names":[],"sources":["../../../../src/components/pro/ArticleControl/ArticleControl.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport { Tree } from '../../Tree';\nimport type { TreeNode } from '../../Tree';\nimport { useDraggable } from '../../../hooks/useDraggable';\nimport { useContainerElement } from '../../../hooks/useContainerElement';\nimport { getSelectionInfo, getMarkdownContent } from '../../../utils/selection';\nimport type { ArticleControlProps, ArticleAction, HeadingItem } from './types';\nimport { useArticleToc } from './useArticleToc';\nimport { buildHeadingTree, getAllNodeIds } from './buildHeadingTree';\nimport './ArticleControl.css';\n\nconst ArticleControl: React.FC<ArticleControlProps> = ({\n targetId,\n targetRef,\n initialPosition = { x: window.innerWidth - 320, y: 100 },\n initialExpanded = true,\n ballSize = 56,\n panelWidth = 280,\n panelMaxHeight = 400,\n className = '',\n onHeadingClick,\n actions = [],\n}) => {\n const [isExpanded, setIsExpanded] = useState(initialExpanded);\n const controlRef = useRef<HTMLDivElement>(null);\n const tocContainerRef = useRef<HTMLDivElement>(null);\n const [hoveredAction, setHoveredAction] = useState<string | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n\n const { position, isDragging, handleMouseDown, handleTouchStart } = useDraggable({\n initialPosition,\n boundarySize: {\n width: isExpanded ? panelWidth : ballSize,\n height: isExpanded ? 60 : ballSize,\n },\n });\n\n const container = useContainerElement(targetId, targetRef);\n const { headings, activeId, prevActiveId, scrollToHeading } = useArticleToc(container);\n\n useEffect(() => {\n if (!activeId || !tocContainerRef.current || !isExpanded) return;\n requestAnimationFrame(() => {\n const activeElement = tocContainerRef.current?.querySelector(`[data-node-id=\"${activeId}\"]`);\n if (activeElement) {\n const cont = tocContainerRef.current;\n if (!cont) return;\n const elementRect = activeElement.getBoundingClientRect();\n const containerRect = cont.getBoundingClientRect();\n if (elementRect.top < containerRect.top || elementRect.bottom > containerRect.bottom) {\n activeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n }\n });\n }, [activeId, isExpanded]);\n\n const filteredHeadings = useMemo(() => {\n if (!searchQuery.trim()) return headings;\n const query = searchQuery.toLowerCase();\n return headings.filter(h => h.text.toLowerCase().includes(query));\n }, [headings, searchQuery]);\n\n const treeData = useMemo(() => buildHeadingTree(filteredHeadings), [filteredHeadings]);\n const defaultExpandedIds = useMemo(() => getAllNodeIds(treeData), [treeData]);\n\n const getContent = useCallback(() => getMarkdownContent(container, true), [container]);\n const getSelection = useCallback(() => getSelectionInfo(container), [container]);\n\n const handleActionClick = (action: ArticleAction) => {\n action.action(getContent(), getSelection());\n };\n\n const handleTreeNodeClick = (node: TreeNode) => {\n const heading = node.meta?.heading as HeadingItem;\n if (heading) {\n scrollToHeading(heading);\n onHeadingClick?.(heading);\n }\n };\n\n if (headings.length === 0) return null;\n\n return (\n <div\n ref={controlRef}\n className={`fixed z-50 ${className}`}\n style={{\n left: `${position.x}px`,\n top: `${position.y}px`,\n cursor: isDragging ? 'grabbing' : 'grab',\n touchAction: 'none',\n }}\n onMouseDown={handleMouseDown}\n onTouchStart={handleTouchStart}\n >\n {isExpanded ? (\n <div\n className=\"bg-base-100 rounded-lg shadow-2xl border border-base-300\"\n style={{ width: `${panelWidth}px` }}\n >\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-base-300 bg-base-200 rounded-t-lg\">\n <div className=\"flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5 text-primary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 6h16M4 12h16M4 18h7\" />\n </svg>\n <span className=\"font-semibold text-sm\">目录</span>\n <span className=\"text-xs text-base-content/60\">({filteredHeadings.length}/{headings.length})</span>\n </div>\n <button onClick={() => setIsExpanded(false)} className=\"btn btn-ghost btn-xs btn-circle\" title=\"收起\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"px-3 py-2 border-b border-base-300 toc-search\">\n <div className=\"relative\">\n <input\n type=\"text\"\n placeholder=\"筛选目录...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"input input-sm input-bordered w-full pl-8 text-sm\"\n onClick={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n />\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4 absolute left-2.5 top-1/2 -translate-y-1/2 opacity-50\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n {searchQuery && (\n <button\n onClick={(e) => { e.stopPropagation(); setSearchQuery(''); }}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 btn btn-ghost btn-xs btn-circle\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {actions.length > 0 && (\n <div className=\"px-2 py-2 border-b border-base-300 bg-base-100\">\n <div className=\"flex flex-wrap gap-1\">\n {actions.map((action) => (\n <div\n key={action.id}\n className=\"relative group\"\n onMouseEnter={() => setHoveredAction(action.id)}\n onMouseLeave={() => setHoveredAction(null)}\n >\n <button\n onClick={(e) => { e.stopPropagation(); handleActionClick(action); }}\n className=\"btn btn-ghost btn-xs btn-square\"\n title={action.label}\n >\n {action.icon || (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n )}\n </button>\n {hoveredAction === action.id && (action.label || action.description) && (\n <div className=\"absolute left-full ml-2 top-0 z-50 bg-base-content text-base-100 px-3 py-2 rounded shadow-lg whitespace-nowrap min-w-max\">\n {action.label && <div className=\"font-semibold text-sm\">{action.label}</div>}\n {action.description && <div className=\"text-xs opacity-80 mt-1\">{action.description}</div>}\n </div>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n <div ref={tocContainerRef} className=\"overflow-y-auto p-2 scroll-smooth\" style={{ maxHeight: `${panelMaxHeight}px` }}>\n <Tree\n data={treeData}\n activeNodeId={activeId}\n defaultExpandedIds={defaultExpandedIds}\n showSearch={false}\n showExpandAll={false}\n showIcon={true}\n showCount={false}\n showLine={true}\n indent={8}\n togglePosition=\"right\"\n maxHeight={`${panelMaxHeight}px`}\n className={`article-toc-tree ${prevActiveId !== activeId ? 'toc-transitioning' : ''}`}\n onNodeClick={handleTreeNodeClick}\n />\n </div>\n </div>\n ) : (\n <button\n onClick={() => setIsExpanded(true)}\n className=\"btn btn-circle btn-primary shadow-2xl hover:scale-110 transition-transform\"\n style={{ width: `${ballSize}px`, height: `${ballSize}px` }}\n title={`目录 (${headings.length})`}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 6h16M4 12h16M4 18h7\" />\n </svg>\n </button>\n )}\n\n {isDragging && (\n <div className=\"absolute -top-8 left-1/2 -translate-x-1/2 bg-base-content text-base-100 px-3 py-1 rounded text-xs whitespace-nowrap\">\n 拖动中...\n </div>\n )}\n </div>\n );\n};\n\nexport default ArticleControl;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ArticleControl2.js","names":["Tree","ArticleControl","isExpanded","setIsExpanded","useState","initialExpanded","controlRef","useRef","tocContainerRef","hoveredAction","setHoveredAction","searchQuery","setSearchQuery","useDraggable","panelWidth","ballSize","container","useContainerElement","targetId","targetRef","useArticleToc","activeId","activeElement","cont","elementRect","containerRect","filteredHeadings","useMemo","headings","query","h","treeData","buildHeadingTree","defaultExpandedIds","getAllNodeIds","getContent","useCallback","getMarkdownContent","getSelection","getSelectionInfo","handleActionClick","className","position","isDragging","handleMouseDown","handleTouchStart","actions","action","e","panelMaxHeight","prevActiveId","heading","node","scrollToHeading","onHeadingClick"],"sources":["../../../../src/components/pro/ArticleControl/ArticleControl.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react';\nimport { Tree } from '../../Tree';\nimport type { TreeNode } from '../../Tree';\nimport { useDraggable } from '../../../hooks/useDraggable';\nimport { useContainerElement } from '../../../hooks/useContainerElement';\nimport { getSelectionInfo, getMarkdownContent } from '../../../utils/selection';\nimport type { ArticleControlProps, ArticleAction, HeadingItem } from './types';\nimport { useArticleToc } from './useArticleToc';\nimport { buildHeadingTree, getAllNodeIds } from './buildHeadingTree';\nimport './ArticleControl.css';\n\nconst ArticleControl: React.FC<ArticleControlProps> = ({\n targetId,\n targetRef,\n initialPosition = { x: window.innerWidth - 320, y: 100 },\n initialExpanded = true,\n ballSize = 56,\n panelWidth = 280,\n panelMaxHeight = 400,\n className = '',\n onHeadingClick,\n actions = [],\n}) => {\n const [isExpanded, setIsExpanded] = useState(initialExpanded);\n const controlRef = useRef<HTMLDivElement>(null);\n const tocContainerRef = useRef<HTMLDivElement>(null);\n const [hoveredAction, setHoveredAction] = useState<string | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n\n const { position, isDragging, handleMouseDown, handleTouchStart } = useDraggable({\n initialPosition,\n boundarySize: {\n width: isExpanded ? panelWidth : ballSize,\n height: isExpanded ? 60 : ballSize,\n },\n });\n\n const container = useContainerElement(targetId, targetRef);\n const { headings, activeId, prevActiveId, scrollToHeading } = useArticleToc(container);\n\n useEffect(() => {\n if (!activeId || !tocContainerRef.current || !isExpanded) return;\n requestAnimationFrame(() => {\n const activeElement = tocContainerRef.current?.querySelector(`[data-node-id=\"${activeId}\"]`);\n if (activeElement) {\n const cont = tocContainerRef.current;\n if (!cont) return;\n const elementRect = activeElement.getBoundingClientRect();\n const containerRect = cont.getBoundingClientRect();\n if (elementRect.top < containerRect.top || elementRect.bottom > containerRect.bottom) {\n activeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n }\n });\n }, [activeId, isExpanded]);\n\n const filteredHeadings = useMemo(() => {\n if (!searchQuery.trim()) return headings;\n const query = searchQuery.toLowerCase();\n return headings.filter(h => h.text.toLowerCase().includes(query));\n }, [headings, searchQuery]);\n\n const treeData = useMemo(() => buildHeadingTree(filteredHeadings), [filteredHeadings]);\n const defaultExpandedIds = useMemo(() => getAllNodeIds(treeData), [treeData]);\n\n const getContent = useCallback(() => getMarkdownContent(container, true), [container]);\n const getSelection = useCallback(() => getSelectionInfo(container), [container]);\n\n const handleActionClick = (action: ArticleAction) => {\n action.action(getContent(), getSelection());\n };\n\n const handleTreeNodeClick = (node: TreeNode) => {\n const heading = node.meta?.heading as HeadingItem;\n if (heading) {\n scrollToHeading(heading);\n onHeadingClick?.(heading);\n }\n };\n\n if (headings.length === 0) return null;\n\n return (\n <div\n ref={controlRef}\n className={`fixed z-50 ${className}`}\n style={{\n left: `${position.x}px`,\n top: `${position.y}px`,\n cursor: isDragging ? 'grabbing' : 'grab',\n touchAction: 'none',\n }}\n onMouseDown={handleMouseDown}\n onTouchStart={handleTouchStart}\n >\n {isExpanded ? (\n <div\n className=\"bg-base-100 rounded-lg shadow-2xl border border-base-300\"\n style={{ width: `${panelWidth}px` }}\n >\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-base-300 bg-base-200 rounded-t-lg\">\n <div className=\"flex items-center gap-2\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-5 w-5 text-primary\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 6h16M4 12h16M4 18h7\" />\n </svg>\n <span className=\"font-semibold text-sm\">目录</span>\n <span className=\"text-xs text-base-content/60\">({filteredHeadings.length}/{headings.length})</span>\n </div>\n <button onClick={() => setIsExpanded(false)} className=\"btn btn-ghost btn-xs btn-circle\" title=\"收起\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </div>\n\n <div className=\"px-3 py-2 border-b border-base-300 toc-search\">\n <div className=\"relative\">\n <input\n type=\"text\"\n placeholder=\"筛选目录...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"input input-sm input-bordered w-full pl-8 text-sm\"\n onClick={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n onTouchStart={(e) => e.stopPropagation()}\n />\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4 absolute left-2.5 top-1/2 -translate-y-1/2 opacity-50\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z\" />\n </svg>\n {searchQuery && (\n <button\n onClick={(e) => { e.stopPropagation(); setSearchQuery(''); }}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 btn btn-ghost btn-xs btn-circle\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n )}\n </div>\n </div>\n\n {actions.length > 0 && (\n <div className=\"px-2 py-2 border-b border-base-300 bg-base-100\">\n <div className=\"flex flex-wrap gap-1\">\n {actions.map((action) => (\n <div\n key={action.id}\n className=\"relative group\"\n onMouseEnter={() => setHoveredAction(action.id)}\n onMouseLeave={() => setHoveredAction(null)}\n >\n <button\n onClick={(e) => { e.stopPropagation(); handleActionClick(action); }}\n className=\"btn btn-ghost btn-xs btn-square\"\n title={action.label}\n >\n {action.icon || (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-4 w-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M13 10V3L4 14h7v7l9-11h-7z\" />\n </svg>\n )}\n </button>\n {hoveredAction === action.id && (action.label || action.description) && (\n <div className=\"absolute left-full ml-2 top-0 z-50 bg-base-content text-base-100 px-3 py-2 rounded shadow-lg whitespace-nowrap min-w-max\">\n {action.label && <div className=\"font-semibold text-sm\">{action.label}</div>}\n {action.description && <div className=\"text-xs opacity-80 mt-1\">{action.description}</div>}\n </div>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n <div ref={tocContainerRef} className=\"overflow-y-auto p-2 scroll-smooth\" style={{ maxHeight: `${panelMaxHeight}px` }}>\n <Tree\n data={treeData}\n activeNodeId={activeId}\n defaultExpandedIds={defaultExpandedIds}\n showSearch={false}\n showExpandAll={false}\n showIcon={true}\n showCount={false}\n showLine={true}\n indent={8}\n togglePosition=\"right\"\n maxHeight={`${panelMaxHeight}px`}\n className={`article-toc-tree ${prevActiveId !== activeId ? 'toc-transitioning' : ''}`}\n onNodeClick={handleTreeNodeClick}\n />\n </div>\n </div>\n ) : (\n <button\n onClick={() => setIsExpanded(true)}\n className=\"btn btn-circle btn-primary shadow-2xl hover:scale-110 transition-transform\"\n style={{ width: `${ballSize}px`, height: `${ballSize}px` }}\n title={`目录 (${headings.length})`}\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M4 6h16M4 12h16M4 18h7\" />\n </svg>\n </button>\n )}\n\n {isDragging && (\n <div className=\"absolute -top-8 left-1/2 -translate-x-1/2 bg-base-content text-base-100 px-3 py-1 rounded text-xs whitespace-nowrap\">\n 拖动中...\n </div>\n )}\n </div>\n );\n};\n\nexport default ArticleControl;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"buildHeadingTree.js","names":[],"sources":["../../../../src/components/pro/ArticleControl/buildHeadingTree.ts"],"sourcesContent":["import React from 'react';\nimport type { TreeNode } from '../../Tree';\nimport type { HeadingItem } from './types';\n\nexport function buildHeadingTree(items: HeadingItem[]): TreeNode[] {\n const result: TreeNode[] = [];\n const stack: { node: TreeNode; level: number }[] = [];\n\n items.forEach((item, index) => {\n const treeNode: TreeNode = {\n id: item.id || `heading-${index}`,\n label: item.text,\n icon: React.createElement(\n 'span',\n { className: 'text-xs opacity-50' },\n item.level === 1 ? '●' : item.level === 2 ? '○' : '▪',\n ),\n meta: { heading: item },\n };\n\n while (stack.length > 0 && stack[stack.length - 1].level >= item.level) {\n stack.pop();\n }\n\n if (stack.length === 0) {\n result.push(treeNode);\n } else {\n const parent = stack[stack.length - 1].node;\n if (!parent.children) parent.children = [];\n parent.children.push(treeNode);\n }\n\n stack.push({ node: treeNode, level: item.level });\n });\n\n return result;\n}\n\nexport function getAllNodeIds(nodes: TreeNode[]): (string | number)[] {\n const ids: (string | number)[] = [];\n const traverse = (items: TreeNode[]) => {\n items.forEach(node => {\n ids.push(node.id);\n if (node.children) traverse(node.children);\n });\n };\n traverse(nodes);\n return ids;\n}\n"],"mappings":";;AAIA,SAAgB,EAAiB,GAAkC;CACjE,IAAM,IAAqB,CAAC,GACtB,IAA6C,CAAC;CA6BpD,OA3BA,EAAM,SAAS,GAAM,MAAU;EAC7B,IAAM,IAAqB;GACzB,IAAI,EAAK,MAAM,WAAW;GAC1B,OAAO,EAAK;GACZ,MAAM,EAAM,cACV,QACA,EAAE,WAAW,qBAAqB,GAClC,EAAK,UAAU,IAAI,MAAM,EAAK,UAAU,IAAI,MAAM,GACpD;GACA,MAAM,EAAE,SAAS,EAAK;EACxB;EAEA,OAAO,EAAM,SAAS,KAAK,EAAM,EAAM,SAAS,EAAE,CAAC,SAAS,EAAK,QAC/D,EAAM,IAAI;EAGZ,IAAI,EAAM,WAAW,GACnB,EAAO,KAAK,CAAQ;OACf;GACL,IAAM,IAAS,EAAM,EAAM,SAAS,EAAE,CAAC;GAEvC,AADA,AAAsB,EAAO,aAAW,CAAC,GACzC,EAAO,SAAS,KAAK,CAAQ;EAC/B;EAEA,EAAM,KAAK;GAAE,MAAM;GAAU,OAAO,EAAK;EAAM,CAAC;CAClD,CAAC,GAEM;AACT;AAEA,SAAgB,EAAc,GAAwC;CACpE,IAAM,IAA2B,CAAC,GAC5B,KAAY,MAAsB;EACtC,EAAM,SAAQ,MAAQ;GAEpB,AADA,EAAI,KAAK,EAAK,EAAE,GACZ,EAAK,YAAU,EAAS,EAAK,QAAQ;EAC3C,CAAC;CACH;CAEA,OADA,EAAS,CAAK,GACP;AACT"}
1
+ {"version":3,"file":"buildHeadingTree.js","names":["React","buildHeadingTree","result","stack","items","treeNode","item","index","parent","getAllNodeIds","ids","traverse","node","nodes"],"sources":["../../../../src/components/pro/ArticleControl/buildHeadingTree.ts"],"sourcesContent":["import React from 'react';\nimport type { TreeNode } from '../../Tree';\nimport type { HeadingItem } from './types';\n\nexport function buildHeadingTree(items: HeadingItem[]): TreeNode[] {\n const result: TreeNode[] = [];\n const stack: { node: TreeNode; level: number }[] = [];\n\n items.forEach((item, index) => {\n const treeNode: TreeNode = {\n id: item.id || `heading-${index}`,\n label: item.text,\n icon: React.createElement(\n 'span',\n { className: 'text-xs opacity-50' },\n item.level === 1 ? '●' : item.level === 2 ? '○' : '▪',\n ),\n meta: { heading: item },\n };\n\n while (stack.length > 0 && stack[stack.length - 1].level >= item.level) {\n stack.pop();\n }\n\n if (stack.length === 0) {\n result.push(treeNode);\n } else {\n const parent = stack[stack.length - 1].node;\n if (!parent.children) parent.children = [];\n parent.children.push(treeNode);\n }\n\n stack.push({ node: treeNode, level: item.level });\n });\n\n return result;\n}\n\nexport function getAllNodeIds(nodes: TreeNode[]): (string | number)[] {\n const ids: (string | number)[] = [];\n const traverse = (items: TreeNode[]) => {\n items.forEach(node => {\n ids.push(node.id);\n if (node.children) traverse(node.children);\n });\n };\n traverse(nodes);\n return ids;\n}\n"],"mappings":";;AAIA,SAAgBC,EAAiB,GAAkC;CACjE,IAAMC,IAAqB,CAAC,GACtBC,IAA6C,CAAC;CA6BpD,OA3BAC,EAAM,SAAS,GAAM,MAAU;EAC7B,IAAMC,IAAqB;GACzB,IAAIC,EAAK,MAAM,WAAWC;GAC1B,OAAOD,EAAK;GACZ,MAAMN,EAAM,cACV,QACA,EAAE,WAAW,qBAAqB,GAClCM,EAAK,UAAU,IAAI,MAAMA,EAAK,UAAU,IAAI,MAAM,GACpD;GACA,MAAM,EAAE,SAASA,EAAK;EACxB;EAEA,OAAOH,EAAM,SAAS,KAAKA,EAAMA,EAAM,SAAS,EAAE,CAAC,SAASG,EAAK,QAC/D,EAAM,IAAI;EAGZ,IAAIH,EAAM,WAAW,GACnB,EAAO,KAAKE,CAAQ;OACf;GACL,IAAMG,IAASL,EAAMA,EAAM,SAAS,EAAE,CAAC;GAEvC,AADA,AAAsBK,EAAO,aAAW,CAAC,GACzCA,EAAO,SAAS,KAAKH,CAAQ;EAC/B;EAEA,EAAM,KAAK;GAAE,MAAMA;GAAU,OAAOC,EAAK;EAAM,CAAC;CAClD,CAAC,GAEMJ;AACT;AAEA,SAAgBO,EAAc,GAAwC;CACpE,IAAMC,IAA2B,CAAC,GAC5BC,KAAY,MAAsB;EACtC,EAAM,SAAQ,MAAQ;GAEpB,AADAD,EAAI,KAAKE,EAAK,EAAE,GACZA,EAAK,YAAUD,EAASC,EAAK,QAAQ;EAC3C,CAAC;CACH;CAEA,OADAD,EAASE,CAAK,GACPH;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"useArticleToc.js","names":[],"sources":["../../../../src/components/pro/ArticleControl/useArticleToc.ts"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport type { HeadingItem } from './types';\n\nexport function useArticleToc(container: HTMLElement | null) {\n const [headings, setHeadings] = useState<HeadingItem[]>([]);\n const [activeId, setActiveId] = useState<string>('');\n const [prevActiveId, setPrevActiveId] = useState<string>('');\n const activeIdRef = useRef<string>('');\n\n useEffect(() => {\n activeIdRef.current = activeId;\n }, [activeId]);\n\n const extractHeadings = useCallback(() => {\n if (!container) return;\n\n const headingElements = container.querySelectorAll('h1, h2, h3, h4, h5, h6');\n const extracted: HeadingItem[] = [];\n\n headingElements.forEach((element) => {\n const id = element.id || element.textContent?.toLowerCase().replace(/\\s+/g, '-') || '';\n const text = element.textContent || '';\n const level = parseInt(element.tagName.substring(1));\n if (!element.id && id) element.id = id;\n extracted.push({ id, text, level });\n });\n\n setHeadings(extracted);\n }, [container]);\n\n useEffect(() => {\n if (!container) return;\n\n const findScrollContainer = (el: HTMLElement): HTMLElement | null => {\n let current: HTMLElement | null = el;\n while (current) {\n const overflow = window.getComputedStyle(current).overflowY;\n if (overflow === 'auto' || overflow === 'scroll') return current;\n current = current.parentElement;\n }\n return null;\n };\n\n const scrollContainer = findScrollContainer(container);\n const visibleHeadings = new Map<string, { ratio: number; top: number }>();\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const id = entry.target.id;\n if (entry.isIntersecting) {\n visibleHeadings.set(id, { ratio: entry.intersectionRatio, top: entry.boundingClientRect.top });\n } else {\n visibleHeadings.delete(id);\n }\n });\n\n let bestId = '';\n let bestTop = Infinity;\n\n visibleHeadings.forEach((info, id) => {\n const absTop = Math.abs(info.top - 100);\n if (absTop < bestTop) { bestTop = absTop; bestId = id; }\n });\n\n if (!bestId) {\n const headingElements = container!.querySelectorAll('h1, h2, h3, h4, h5, h6');\n let lastPassedId = '';\n headingElements.forEach((element) => {\n const rect = element.getBoundingClientRect();\n if (rect.top <= 120) lastPassedId = element.id;\n });\n if (lastPassedId) bestId = lastPassedId;\n }\n\n if (bestId && bestId !== activeIdRef.current) {\n setPrevActiveId(activeIdRef.current);\n setActiveId(bestId);\n }\n },\n {\n root: scrollContainer,\n rootMargin: '-5% 0px -70% 0px',\n threshold: [0, 0.1, 0.25, 0.5, 0.75, 1],\n },\n );\n\n const headingElements = container.querySelectorAll('h1, h2, h3, h4, h5, h6');\n headingElements.forEach((element) => { if (element.id) observer.observe(element); });\n\n const handleScroll = () => {\n const headingElements = container!.querySelectorAll('h1, h2, h3, h4, h5, h6');\n let currentId = '';\n let minDistance = Infinity;\n\n headingElements.forEach((element) => {\n const rect = element.getBoundingClientRect();\n const distance = Math.abs(rect.top - 100);\n if (rect.top <= 150 && distance < minDistance) { minDistance = distance; currentId = element.id; }\n });\n\n if (!currentId) {\n headingElements.forEach((element) => {\n const rect = element.getBoundingClientRect();\n if (rect.top <= 100) currentId = element.id;\n });\n }\n\n if (currentId && currentId !== activeIdRef.current) {\n setPrevActiveId(activeIdRef.current);\n setActiveId(currentId);\n }\n };\n\n const scrollTargets: (HTMLElement | Window)[] = [];\n if (scrollContainer) scrollTargets.push(scrollContainer);\n scrollTargets.push(window);\n scrollTargets.forEach(target => target.addEventListener('scroll', handleScroll, { passive: true }));\n setTimeout(handleScroll, 100);\n\n return () => {\n observer.disconnect();\n scrollTargets.forEach(target => target.removeEventListener('scroll', handleScroll));\n };\n }, [container, headings]);\n\n useEffect(() => {\n const timer = setTimeout(extractHeadings, 500);\n return () => clearTimeout(timer);\n }, [extractHeadings]);\n\n useEffect(() => {\n if (!container) return;\n const observer = new MutationObserver(() => extractHeadings());\n observer.observe(container, { childList: true, subtree: true });\n return () => observer.disconnect();\n }, [container, extractHeadings]);\n\n const scrollToHeading = useCallback((heading: HeadingItem) => {\n const element = document.getElementById(heading.id);\n if (element) {\n element.scrollIntoView({ behavior: 'smooth', block: 'start' });\n setActiveId(heading.id);\n }\n }, []);\n\n return { headings, activeId, prevActiveId, setActiveId, scrollToHeading };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useArticleToc.js","names":["useArticleToc","headings","setHeadings","useState","activeId","setActiveId","prevActiveId","setPrevActiveId","activeIdRef","useRef","extractHeadings","useCallback","container","headingElements","extracted","id","element","text","level","useEffect","scrollContainer","current","el","overflow","visibleHeadings","observer","entry","bestId","bestTop","absTop","info","lastPassedId","handleScroll","currentId","minDistance","rect","distance","scrollTargets","target","timer","heading"],"sources":["../../../../src/components/pro/ArticleControl/useArticleToc.ts"],"sourcesContent":["import { useState, useEffect, useRef, useCallback } from 'react';\nimport type { HeadingItem } from './types';\n\nexport function useArticleToc(container: HTMLElement | null) {\n const [headings, setHeadings] = useState<HeadingItem[]>([]);\n const [activeId, setActiveId] = useState<string>('');\n const [prevActiveId, setPrevActiveId] = useState<string>('');\n const activeIdRef = useRef<string>('');\n\n useEffect(() => {\n activeIdRef.current = activeId;\n }, [activeId]);\n\n const extractHeadings = useCallback(() => {\n if (!container) return;\n\n const headingElements = container.querySelectorAll('h1, h2, h3, h4, h5, h6');\n const extracted: HeadingItem[] = [];\n\n headingElements.forEach((element) => {\n const id = element.id || element.textContent?.toLowerCase().replace(/\\s+/g, '-') || '';\n const text = element.textContent || '';\n const level = parseInt(element.tagName.substring(1));\n if (!element.id && id) element.id = id;\n extracted.push({ id, text, level });\n });\n\n setHeadings(extracted);\n }, [container]);\n\n useEffect(() => {\n if (!container) return;\n\n const findScrollContainer = (el: HTMLElement): HTMLElement | null => {\n let current: HTMLElement | null = el;\n while (current) {\n const overflow = window.getComputedStyle(current).overflowY;\n if (overflow === 'auto' || overflow === 'scroll') return current;\n current = current.parentElement;\n }\n return null;\n };\n\n const scrollContainer = findScrollContainer(container);\n const visibleHeadings = new Map<string, { ratio: number; top: number }>();\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const id = entry.target.id;\n if (entry.isIntersecting) {\n visibleHeadings.set(id, { ratio: entry.intersectionRatio, top: entry.boundingClientRect.top });\n } else {\n visibleHeadings.delete(id);\n }\n });\n\n let bestId = '';\n let bestTop = Infinity;\n\n visibleHeadings.forEach((info, id) => {\n const absTop = Math.abs(info.top - 100);\n if (absTop < bestTop) { bestTop = absTop; bestId = id; }\n });\n\n if (!bestId) {\n const headingElements = container!.querySelectorAll('h1, h2, h3, h4, h5, h6');\n let lastPassedId = '';\n headingElements.forEach((element) => {\n const rect = element.getBoundingClientRect();\n if (rect.top <= 120) lastPassedId = element.id;\n });\n if (lastPassedId) bestId = lastPassedId;\n }\n\n if (bestId && bestId !== activeIdRef.current) {\n setPrevActiveId(activeIdRef.current);\n setActiveId(bestId);\n }\n },\n {\n root: scrollContainer,\n rootMargin: '-5% 0px -70% 0px',\n threshold: [0, 0.1, 0.25, 0.5, 0.75, 1],\n },\n );\n\n const headingElements = container.querySelectorAll('h1, h2, h3, h4, h5, h6');\n headingElements.forEach((element) => { if (element.id) observer.observe(element); });\n\n const handleScroll = () => {\n const headingElements = container!.querySelectorAll('h1, h2, h3, h4, h5, h6');\n let currentId = '';\n let minDistance = Infinity;\n\n headingElements.forEach((element) => {\n const rect = element.getBoundingClientRect();\n const distance = Math.abs(rect.top - 100);\n if (rect.top <= 150 && distance < minDistance) { minDistance = distance; currentId = element.id; }\n });\n\n if (!currentId) {\n headingElements.forEach((element) => {\n const rect = element.getBoundingClientRect();\n if (rect.top <= 100) currentId = element.id;\n });\n }\n\n if (currentId && currentId !== activeIdRef.current) {\n setPrevActiveId(activeIdRef.current);\n setActiveId(currentId);\n }\n };\n\n const scrollTargets: (HTMLElement | Window)[] = [];\n if (scrollContainer) scrollTargets.push(scrollContainer);\n scrollTargets.push(window);\n scrollTargets.forEach(target => target.addEventListener('scroll', handleScroll, { passive: true }));\n setTimeout(handleScroll, 100);\n\n return () => {\n observer.disconnect();\n scrollTargets.forEach(target => target.removeEventListener('scroll', handleScroll));\n };\n }, [container, headings]);\n\n useEffect(() => {\n const timer = setTimeout(extractHeadings, 500);\n return () => clearTimeout(timer);\n }, [extractHeadings]);\n\n useEffect(() => {\n if (!container) return;\n const observer = new MutationObserver(() => extractHeadings());\n observer.observe(container, { childList: true, subtree: true });\n return () => observer.disconnect();\n }, [container, extractHeadings]);\n\n const scrollToHeading = useCallback((heading: HeadingItem) => {\n const element = document.getElementById(heading.id);\n if (element) {\n element.scrollIntoView({ behavior: 'smooth', block: 'start' });\n setActiveId(heading.id);\n }\n }, []);\n\n return { headings, activeId, prevActiveId, setActiveId, scrollToHeading };\n}\n"],"mappings":";;AAGA,SAAgBA,EAAc,GAA+B;CAC3D,IAAM,CAACC,GAAUC,KAAeC,EAAwB,CAAC,CAAC,GACpD,CAACC,GAAUC,KAAeF,EAAiB,EAAE,GAC7C,CAACG,GAAcC,KAAmBJ,EAAiB,EAAE,GACrDK,IAAcC,EAAe,EAAE;CAErC,QAAgB;EACd,EAAY,UAAUL;CACxB,GAAG,CAACA,CAAQ,CAAC;CAEb,IAAMM,IAAkBC,QAAkB;EACxC,IAAI,CAACC,GAAW;EAEhB,IAAMC,IAAkBD,EAAU,iBAAiB,wBAAwB,GACrEE,IAA2B,CAAC;EAUlC,AARAD,EAAgB,SAAS,MAAY;GACnC,IAAME,IAAKC,EAAQ,MAAMA,EAAQ,aAAa,YAAY,CAAC,CAAC,QAAQ,QAAQ,GAAG,KAAK,IAC9EC,IAAOD,EAAQ,eAAe,IAC9BE,IAAQ,SAASF,EAAQ,QAAQ,UAAU,CAAC,CAAC;GAEnD,AADI,CAACA,EAAQ,MAAMD,MAAI,EAAQ,KAAKA,IACpCD,EAAU,KAAK;IAAE;IAAI;IAAM;GAAM,CAAC;EACpC,CAAC,GAEDZ,EAAYY,CAAS;CACvB,GAAG,CAACF,CAAS,CAAC;CAsHd,OApHAO,QAAgB;EACd,IAAI,CAACP,GAAW;EAYhB,IAAMQ,MAVuB,MAAwC;GACnE,IAAIC,IAA8BC;GAClC,OAAOD,IAAS;IACd,IAAME,IAAW,OAAO,iBAAiBF,CAAO,CAAC,CAAC;IAClD,IAAIE,MAAa,UAAUA,MAAa,UAAU,OAAOF;IACzD,IAAUA,EAAQ;GACpB;GACA,OAAO;EACT,EAEwB,CAAoBT,CAAS,GAC/CY,oBAAkB,IAAI,IAA4C,GAElEC,IAAW,IAAI,sBAClB,MAAY;GACX,EAAQ,SAAS,MAAU;IACzB,IAAMV,IAAKW,EAAM,OAAO;IACxB,AAAIA,EAAM,iBACRF,EAAgB,IAAIT,GAAI;KAAE,OAAOW,EAAM;KAAmB,KAAKA,EAAM,mBAAmB;IAAI,CAAC,IAE7FF,EAAgB,OAAOT,CAAE;GAE7B,CAAC;GAED,IAAIY,IAAS,IACTC,IAAU;GAOd,IALAJ,EAAgB,SAAS,GAAM,MAAO;IACpC,IAAMK,IAAS,KAAK,IAAIC,EAAK,MAAM,GAAG;IACtC,AAAID,IAASD,MAAW,IAAUC,GAAQ,IAASd;GACrD,CAAC,GAEG,CAACY,GAAQ;IACX,IAAMd,IAAkBD,EAAW,iBAAiB,wBAAwB,GACxEmB,IAAe;IAKnB,AAJAlB,EAAgB,SAAS,MAAY;KAEnC,AADaG,EAAQ,sBACjB,CAAA,CAAK,OAAO,QAAK,IAAeA,EAAQ;IAC9C,CAAC,GACGe,MAAc,IAASA;GAC7B;GAEA,AAAIJ,KAAUA,MAAWnB,EAAY,YACnCD,EAAgBC,EAAY,OAAO,GACnCH,EAAYsB,CAAM;EAEtB,GACA;GACE,MAAMP;GACN,YAAY;GACZ,WAAW;IAAC;IAAG;IAAK;IAAM;IAAK;IAAM;GAAC;EACxC,CACF;EAGA,EADkC,iBAAiB,wBACnD,CAAA,CAAgB,SAAS,MAAY;GAAE,AAAIJ,EAAQ,MAAIS,EAAS,QAAQT,CAAO;EAAG,CAAC;EAEnF,IAAMgB,UAAqB;GACzB,IAAMnB,IAAkBD,EAAW,iBAAiB,wBAAwB,GACxEqB,IAAY,IACZC,IAAc;GAelB,AAbArB,EAAgB,SAAS,MAAY;IACnC,IAAMsB,IAAOnB,EAAQ,sBAAsB,GACrCoB,IAAW,KAAK,IAAID,EAAK,MAAM,GAAG;IACxC,AAAIA,EAAK,OAAO,OAAOC,IAAWF,MAAe,IAAcE,GAAU,IAAYpB,EAAQ;GAC/F,CAAC,GAEIiB,KACHpB,EAAgB,SAAS,MAAY;IAEnC,AADaG,EAAQ,sBACjB,CAAA,CAAK,OAAO,QAAK,IAAYA,EAAQ;GAC3C,CAAC,GAGCiB,KAAaA,MAAczB,EAAY,YACzCD,EAAgBC,EAAY,OAAO,GACnCH,EAAY4B,CAAS;EAEzB,GAEMI,IAA0C,CAAC;EAMjD,OALIjB,KAAiBiB,EAAc,KAAKjB,CAAe,GACvDiB,EAAc,KAAK,MAAM,GACzBA,EAAc,SAAQ,MAAUC,EAAO,iBAAiB,UAAUN,GAAc,EAAE,SAAS,GAAK,CAAC,CAAC,GAClG,WAAWA,GAAc,GAAG,SAEf;GAEX,AADAP,EAAS,WAAW,GACpBY,EAAc,SAAQ,MAAUC,EAAO,oBAAoB,UAAUN,CAAY,CAAC;EACpF;CACF,GAAG,CAACpB,GAAWX,CAAQ,CAAC,GAExBkB,QAAgB;EACd,IAAMoB,IAAQ,WAAW7B,GAAiB,GAAG;EAC7C,aAAa,aAAa6B,CAAK;CACjC,GAAG,CAAC7B,CAAe,CAAC,GAEpBS,QAAgB;EACd,IAAI,CAACP,GAAW;EAChB,IAAMa,IAAW,IAAI,uBAAuBf,EAAgB,CAAC;EAE7D,OADAe,EAAS,QAAQb,GAAW;GAAE,WAAW;GAAM,SAAS;EAAK,CAAC,SACjDa,EAAS,WAAW;CACnC,GAAG,CAACb,GAAWF,CAAe,CAAC,GAUxB;EAAE;EAAU;EAAU;EAAc;EAAa,iBARhCC,GAAa,MAAyB;GAC5D,IAAMK,IAAU,SAAS,eAAewB,EAAQ,EAAE;GAClD,AAAIxB,MACFA,EAAQ,eAAe;IAAE,UAAU;IAAU,OAAO;GAAQ,CAAC,GAC7DX,EAAYmC,EAAQ,EAAE;EAE1B,GAAG,CAAC,CAEoD;CAAgB;AAC1E"}