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/Tooltip/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../utils/cn';\n\nexport type TooltipProps = {\n /** Tooltip text content. */\n content: React.ReactNode;\n /** The element the tooltip is attached to. */\n children: React.ReactNode;\n /** Placement relative to the target. */\n placement?: 'top' | 'bottom' | 'left' | 'right';\n /** Color variant (daisyUI). */\n variant?: 'default' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error';\n /** Always show the tooltip (useful for demos / onboarding). */\n open?: boolean;\n /** Extra class names applied to the wrapper. */\n className?: string;\n /** Inline styles applied to the wrapper. */\n style?: React.CSSProperties;\n};\n\nconst PLACEMENT_CLASS: Record<NonNullable<TooltipProps['placement']>, string> = {\n top: 'tooltip-top',\n bottom: 'tooltip-bottom',\n left: 'tooltip-left',\n right: 'tooltip-right',\n};\n\nconst VARIANT_CLASS: Record<NonNullable<TooltipProps['variant']>, string> = {\n default: '',\n primary: 'tooltip-primary',\n secondary: 'tooltip-secondary',\n accent: 'tooltip-accent',\n info: 'tooltip-info',\n success: 'tooltip-success',\n warning: 'tooltip-warning',\n error: 'tooltip-error',\n};\n\n/**\n * Tooltip —— 悬浮提示。基于 daisyUI `tooltip`,纯 CSS 实现,支持四向定位与色调变体。\n * 提示文本通过 `data-tip` 渲染,可访问性良好且无需 JS。\n */\nconst Tooltip: React.FC<TooltipProps> = ({\n content,\n children,\n placement = 'top',\n variant = 'default',\n open = false,\n className = '',\n style,\n}) => {\n const wrapperClasses = cn(\n 'tooltip',\n PLACEMENT_CLASS[placement],\n VARIANT_CLASS[variant],\n open && 'tooltip-open',\n className,\n );\n\n return (\n <span\n className={wrapperClasses}\n style={style}\n data-tip={typeof content === 'string' ? content : undefined}\n >\n {typeof content !== 'string' && (\n <span className=\"tooltip-content\">{content}</span>\n )}\n {children}\n </span>\n );\n};\n\nexport default Tooltip;\n"],"mappings":";;;;AAoBA,IAAM,IAA0E;CAC9E,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;AACT,GAEM,IAAsE;CAC1E,SAAS;CACT,SAAS;CACT,WAAW;CACX,QAAQ;CACR,MAAM;CACN,SAAS;CACT,SAAS;CACT,OAAO;AACT,GAMM,KAAmC,EACvC,YACA,aACA,eAAY,OACZ,aAAU,WACV,UAAO,IACP,eAAY,IACZ,eACI;CACJ,IAAM,IAAiB,EACrB,WACA,EAAgB,IAChB,EAAc,IACd,KAAQ,gBACR,CACF;CAEA,OACE,kBAAC,QAAD;EACE,WAAW;EACJ;EACP,YAAU,OAAO,KAAY,WAAW,IAAU,KAAA;EAHpD,UAAA,CAKG,OAAO,KAAY,YAClB,kBAAC,QAAD;GAAM,WAAU;GAAmB,UAAA;EAAc,CAAA,GAElD,CACG;;AAEV"}
1
+ {"version":3,"file":"index.js","names":["PLACEMENT_CLASS","VARIANT_CLASS","Tooltip","wrapperClasses","cn","placement","variant","open","className","content","children"],"sources":["../../../src/components/Tooltip/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../utils/cn';\n\nexport type TooltipProps = {\n /** Tooltip text content. */\n content: React.ReactNode;\n /** The element the tooltip is attached to. */\n children: React.ReactNode;\n /** Placement relative to the target. */\n placement?: 'top' | 'bottom' | 'left' | 'right';\n /** Color variant (daisyUI). */\n variant?: 'default' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error';\n /** Always show the tooltip (useful for demos / onboarding). */\n open?: boolean;\n /** Extra class names applied to the wrapper. */\n className?: string;\n /** Inline styles applied to the wrapper. */\n style?: React.CSSProperties;\n};\n\nconst PLACEMENT_CLASS: Record<NonNullable<TooltipProps['placement']>, string> = {\n top: 'tooltip-top',\n bottom: 'tooltip-bottom',\n left: 'tooltip-left',\n right: 'tooltip-right',\n};\n\nconst VARIANT_CLASS: Record<NonNullable<TooltipProps['variant']>, string> = {\n default: '',\n primary: 'tooltip-primary',\n secondary: 'tooltip-secondary',\n accent: 'tooltip-accent',\n info: 'tooltip-info',\n success: 'tooltip-success',\n warning: 'tooltip-warning',\n error: 'tooltip-error',\n};\n\n/**\n * Tooltip —— 悬浮提示。基于 daisyUI `tooltip`,纯 CSS 实现,支持四向定位与色调变体。\n * 提示文本通过 `data-tip` 渲染,可访问性良好且无需 JS。\n */\nconst Tooltip: React.FC<TooltipProps> = ({\n content,\n children,\n placement = 'top',\n variant = 'default',\n open = false,\n className = '',\n style,\n}) => {\n const wrapperClasses = cn(\n 'tooltip',\n PLACEMENT_CLASS[placement],\n VARIANT_CLASS[variant],\n open && 'tooltip-open',\n className,\n );\n\n return (\n <span\n className={wrapperClasses}\n style={style}\n data-tip={typeof content === 'string' ? content : undefined}\n >\n {typeof content !== 'string' && (\n <span className=\"tooltip-content\">{content}</span>\n )}\n {children}\n </span>\n );\n};\n\nexport default Tooltip;\n"],"mappings":";;;;AAoBA,IAAMA,IAA0E;CAC9E,KAAK;CACL,QAAQ;CACR,MAAM;CACN,OAAO;AACT,GAEMC,IAAsE;CAC1E,SAAS;CACT,SAAS;CACT,WAAW;CACX,QAAQ;CACR,MAAM;CACN,SAAS;CACT,SAAS;CACT,OAAO;AACT,GAMMC,KAAmC,EACvC,YACA,aACA,eAAY,OACZ,aAAU,WACV,UAAO,IACP,eAAY,IACZ,eACI;CACJ,IAAMC,IAAiBC,EACrB,WACAJ,EAAgBK,IAChBJ,EAAcK,IACdC,KAAQ,gBACRC,CACF;CAEA,OACE,kBAAC,QAAD;EACE,WAAWL;EACJ;EACP,YAAU,OAAOM,KAAY,WAAWA,IAAU,KAAA;EAHpD,UAAA,CAKG,OAAOA,KAAY,YAClB,kBAAC,QAAD;GAAM,WAAU;GAAmB,UAAAA;EAAc,CAAA,GAElDC,CACG;;AAEV"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tree.js","names":[],"sources":["../../../src/components/Tree/Tree.tsx"],"sourcesContent":["import React, { useState, useCallback, useMemo } from 'react';\nimport { generateTreeActiveStyles } from '../../styles/themeStyles';\n\n// ============= 类型定义 =============\n\nexport interface TreeNode {\n id: string | number;\n label: string;\n children?: TreeNode[];\n icon?: React.ReactNode;\n disabled?: boolean;\n meta?: Record<string, any>;\n}\n\nexport interface TreeProps {\n /** 树形数据 */\n data: TreeNode[];\n\n /** 节点点击回调 */\n onNodeClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点双击回调 */\n onNodeDoubleClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点展开/折叠回调 */\n onNodeToggle?: (nodeId: string | number, expanded: boolean) => void;\n\n /** 当前激活的节点 ID */\n activeNodeId?: string | number;\n\n /** 默认展开的节点 ID 列表 */\n defaultExpandedIds?: (string | number)[];\n\n /** 是否显示搜索框 */\n showSearch?: boolean;\n\n /** 搜索占位符 */\n searchPlaceholder?: string;\n\n /** 是否显示展开/折叠全部按钮 */\n showExpandAll?: boolean;\n\n /** 展开全部按钮文本 */\n expandAllText?: string;\n\n /** 折叠全部按钮文本 */\n collapseAllText?: string;\n\n /** 是否显示节点图标 */\n showIcon?: boolean;\n\n /** 默认图标 */\n defaultIcon?: React.ReactNode;\n\n /** 展开图标 */\n expandIcon?: React.ReactNode;\n\n /** 折叠图标 */\n collapseIcon?: React.ReactNode;\n\n /** 是否显示连接线 */\n showLine?: boolean;\n\n /** 最大高度 */\n maxHeight?: string;\n\n /** 自定义类名 */\n className?: string;\n\n /** 标题 */\n title?: string;\n\n /** 标题图标 */\n titleIcon?: React.ReactNode;\n\n /** 是否显示节点数量 */\n showCount?: boolean;\n\n /** 空状态文本 */\n emptyText?: string;\n\n /** 搜索无结果文本 */\n noResultsText?: string;\n\n /** 缩进宽度(像素) */\n indent?: number;\n\n /** 展开按钮位置:left(左侧)或 right(右侧) */\n togglePosition?: 'left' | 'right';\n\n /** 是否可拖拽(暂不实现) */\n draggable?: boolean;\n\n /** 是否可选择(暂不实现) */\n checkable?: boolean;\n\n /** Custom label content; depth is zero-based. The string label remains the search text and native title. */\n renderLabel?: (node: TreeNode, depth: number) => React.ReactNode;\n\n /** 自定义渲染节点 */\n renderNode?: (node: TreeNode, defaultRender: React.ReactNode) => React.ReactNode;\n}\n\n// ============= Tree 组件 =============\n\nconst Tree: React.FC<TreeProps> = ({\n data,\n onNodeClick,\n onNodeDoubleClick,\n onNodeToggle,\n activeNodeId,\n defaultExpandedIds = [],\n showSearch = true,\n searchPlaceholder = 'Search...',\n showExpandAll = true,\n expandAllText = 'Expand All',\n collapseAllText = 'Collapse All',\n showIcon = true,\n defaultIcon,\n expandIcon,\n collapseIcon,\n showLine = false,\n maxHeight = '600px',\n className = '',\n title,\n titleIcon,\n showCount = true,\n emptyText = 'No data',\n noResultsText = 'No results found',\n indent = 16,\n togglePosition = 'left',\n renderLabel,\n renderNode,\n}) => {\n const [searchQuery, setSearchQuery] = useState('');\n const [expandedIds, setExpandedIds] = useState<Set<string | number>>(\n new Set(defaultExpandedIds)\n );\n\n // 当 defaultExpandedIds 变化时,同步更新 expandedIds(用于异步加载的数据)\n React.useEffect(() => {\n if (defaultExpandedIds.length > 0) {\n setExpandedIds(prev => {\n const newSet = new Set(prev);\n defaultExpandedIds.forEach(id => newSet.add(id));\n return newSet;\n });\n }\n }, [defaultExpandedIds]);\n\n // 默认展开/折叠图标\n const defaultExpandIconEl = expandIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n );\n\n const defaultCollapseIconEl = collapseIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n );\n\n // 默认节点图标\n const defaultIconEl = defaultIcon || (\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n );\n\n // 统计节点总数\n const countNodes = useCallback((nodes: TreeNode[]): number => {\n return nodes.reduce((count, node) => {\n return count + 1 + (node.children ? countNodes(node.children) : 0);\n }, 0);\n }, []);\n\n const totalCount = useMemo(() => countNodes(data), [data, countNodes]);\n\n // 过滤节点(支持搜索)\n const filterNodes = useCallback((nodes: TreeNode[], query: string): TreeNode[] => {\n if (!query) return nodes;\n\n const lowerQuery = query.toLowerCase();\n const filtered: TreeNode[] = [];\n\n for (const node of nodes) {\n const matches = node.label.toLowerCase().includes(lowerQuery);\n const filteredChildren = node.children ? filterNodes(node.children, query) : [];\n\n if (matches || filteredChildren.length > 0) {\n filtered.push({\n ...node,\n children: filteredChildren.length > 0 ? filteredChildren : node.children,\n });\n }\n }\n\n return filtered;\n }, []);\n\n const filteredData = useMemo(\n () => filterNodes(data, searchQuery),\n [data, searchQuery, filterNodes]\n );\n\n // 切换节点展开/折叠\n const toggleNode = useCallback(\n (nodeId: string | number) => {\n const newExpanded = new Set(expandedIds);\n if (newExpanded.has(nodeId)) {\n newExpanded.delete(nodeId);\n onNodeToggle?.(nodeId, false);\n } else {\n newExpanded.add(nodeId);\n onNodeToggle?.(nodeId, true);\n }\n setExpandedIds(newExpanded);\n },\n [expandedIds, onNodeToggle]\n );\n\n // 展开所有节点\n const expandAll = useCallback(() => {\n const allIds = new Set<string | number>();\n const collectIds = (nodes: TreeNode[]) => {\n nodes.forEach((node) => {\n if (node.children && node.children.length > 0) {\n allIds.add(node.id);\n collectIds(node.children);\n }\n });\n };\n collectIds(data);\n setExpandedIds(allIds);\n }, [data]);\n\n // 折叠所有节点\n const collapseAll = useCallback(() => {\n setExpandedIds(new Set());\n }, []);\n\n // 渲染单个节点\n const renderTreeNode = useCallback(\n (node: TreeNode, depth: number = 0, path: (string | number)[] = []) => {\n const hasChildren = node.children && node.children.length > 0;\n const isExpanded = expandedIds.has(node.id);\n const isActive = activeNodeId === node.id;\n const currentPath = [...path, node.id];\n\n const nodeContent = (\n <div\n key={node.id}\n data-node-id={node.id}\n data-depth={depth}\n data-level={depth + 1}\n className={`tree-node ${isActive ? 'tree-node-active' : ''} ${node.disabled ? 'tree-node-disabled' : ''\n }`}\n style={{\n paddingLeft: `${depth * indent}px`,\n }}\n >\n <div\n className={`tree-node-content flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer transition-colors ${isActive ? 'tree-node-content-active' : 'tree-node-content-inactive'\n } ${node.disabled ? 'opacity-50 cursor-not-allowed' : ''}`}\n onClick={() => {\n if (!node.disabled) {\n onNodeClick?.(node, currentPath);\n }\n }}\n onDoubleClick={() => {\n if (!node.disabled) {\n onNodeDoubleClick?.(node, currentPath);\n }\n }}\n >\n {/* 左侧展开按钮 */}\n {togglePosition === 'left' && (\n <>\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.label}`}\n aria-expanded={isExpanded}\n className={`tree-node-toggle btn btn-xs btn-ghost btn-circle ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n ) : (\n <span className=\"tree-node-toggle-placeholder\" style={{ width: '1.5rem', height: '1.5rem', flexShrink: 0 }}></span>\n )}\n </>\n )}\n\n {/* 节点图标 */}\n {showIcon && (\n <span className=\"tree-node-icon\">{node.icon || defaultIconEl}</span>\n )}\n\n {/* 节点标签 */}\n <span className=\"tree-node-label text-sm truncate flex-1\" title={node.label}>\n {renderLabel ? renderLabel(node, depth) : node.label}\n </span>\n\n {/* 子节点数量(优先使用 meta.count,否则回退到子节点个数) */}\n {node.meta?.count !== undefined && node.meta?.count !== null ? (\n <span className=\"tree-node-count text-xs opacity-60\">\n {node.meta.count}\n </span>\n ) : hasChildren && showCount ? (\n <span className=\"tree-node-count text-xs opacity-60\">\n ({node.children!.length})\n </span>\n ) : null}\n\n {/* 右侧展开按钮 */}\n {togglePosition === 'right' && hasChildren && (\n <button\n type=\"button\"\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.label}`}\n aria-expanded={isExpanded}\n className={`tree-node-toggle tree-node-toggle-right btn btn-xs btn-ghost ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n )}\n </div>\n\n {/* 子节点 */}\n {hasChildren && (\n <div\n className={`tree-node-children ${isExpanded ? 'tree-node-children-expanded' : 'tree-node-children-collapsed'}`}\n >\n {node.children!.map((child) => renderTreeNode(child, depth + 1, currentPath))}\n </div>\n )}\n </div>\n );\n\n // 自定义渲染\n if (renderNode) {\n return renderNode(node, nodeContent);\n }\n\n return nodeContent;\n },\n [\n expandedIds,\n activeNodeId,\n indent,\n showIcon,\n showCount,\n togglePosition,\n defaultExpandIconEl,\n defaultCollapseIconEl,\n defaultIconEl,\n onNodeClick,\n onNodeDoubleClick,\n toggleNode,\n renderLabel,\n renderNode,\n ]\n );\n\n return (\n <div className={`tree-component bg-base-100 border border-base-300 rounded-lg p-2 ${className}`}>\n {/* 标题 */}\n {title && (\n <div className=\"tree-header flex items-center gap-2 px-2 py-1 mb-2 border-b border-base-300\">\n {titleIcon}\n <span className=\"font-semibold\">{title}</span>\n {showCount && (\n <span className=\"text-xs opacity-60 ml-auto\">({totalCount})</span>\n )}\n </div>\n )}\n\n {/* 搜索框 */}\n {showSearch && (\n <input\n type=\"text\"\n placeholder={searchPlaceholder}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"tree-search input input-sm input-bordered w-full mb-2\"\n />\n )}\n\n {/* 操作按钮 */}\n {showExpandAll && (\n <div className=\"tree-actions flex gap-1 mb-2\">\n <button className=\"btn btn-xs btn-ghost\" onClick={expandAll}>\n {expandAllText}\n </button>\n <button className=\"btn btn-xs btn-ghost\" onClick={collapseAll}>\n {collapseAllText}\n </button>\n </div>\n )}\n\n {/* 树形列表 */}\n <div\n className=\"tree-content overflow-y-auto\"\n style={{ maxHeight }}\n >\n {filteredData.length === 0 ? (\n <div className=\"tree-empty text-center text-sm opacity-60 py-4\">\n {searchQuery ? noResultsText : emptyText}\n </div>\n ) : (\n <div className={`tree-nodes ${showLine ? 'tree-show-line' : ''}`}>\n {filteredData.map((node) => renderTreeNode(node))}\n </div>\n )}\n </div>\n\n <style>{`\n .tree-node {\n user-select: none;\n }\n \n /* 子节点容器基础样式 */\n .tree-node-children {\n margin-top: 2px;\n overflow: hidden;\n transform-origin: top;\n box-sizing: border-box;\n }\n \n /* 折叠状态 - 初始隐藏 */\n .tree-node-children-collapsed {\n max-height: 0;\n opacity: 0;\n transform: scaleY(0.8);\n border-left: none !important;\n }\n \n /* 展开状态 - 显示内容 */\n .tree-node-children-expanded {\n max-height: 5000px;\n opacity: 1;\n transform: scaleY(1);\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n /* 不对 border 做动画 */\n box-sizing: border-box;\n }\n \n /* 连接线样式 - 在展开状态显示,使用多重选择器提高优先级 */\n .tree-component .tree-show-line .tree-node-children-expanded,\n .tree-show-line .tree-node-children.tree-node-children-expanded {\n border-left: 1px solid var(--fallback-bc, oklch(var(--bc) / 0.2)) !important;\n margin-left: 8px !important;\n padding-left: 8px !important;\n position: relative;\n }\n \n /* 左侧连接线圆点装饰 */\n .tree-show-line .tree-node-children-expanded::before {\n content: '';\n position: absolute;\n left: -3px;\n top: 0;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background-color: var(--fallback-bc, oklch(var(--bc) / 0.3));\n }\n \n /* 折叠过渡 */\n .tree-node-children-collapsed {\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 展开/折叠按钮图标旋转动画 */\n .tree-node-toggle {\n z-index: 2;\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n .tree-node-toggle svg {\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 折叠状态的图标 - 向右 */\n .tree-node-toggle:not(.tree-node-toggle-expanded) svg {\n transform: rotate(0deg);\n }\n \n /* 展开状态的图标 - 向下(已经是向下的,所以不需要额外旋转) */\n .tree-node-toggle-expanded svg {\n transform: rotate(0deg);\n }\n \n .tree-component {\n position: relative;\n z-index: 1;\n }\n \n .tree-node-disabled {\n cursor: not-allowed;\n }\n \n .tree-node-disabled .tree-node-content {\n pointer-events: none;\n }\n \n /* 节点内容悬停效果 */\n .tree-node-content {\n transition: background-color 0.15s ease;\n }\n \n /* 优化性能 - 告诉浏览器这些属性会变化 */\n .tree-node-children {\n will-change: max-height, opacity, transform;\n }\n \n /* 动画完成后移除 will-change 以节省资源 */\n .tree-node-children-expanded,\n .tree-node-children-collapsed {\n animation: remove-will-change 0.3s forwards;\n }\n \n @keyframes remove-will-change {\n to {\n will-change: auto;\n }\n }\n \n /* 活跃节点基础样式 */\n .tree-node-content-active {\n font-weight: 600 !important;\n padding-left: calc(0.5rem - 4px) !important;\n border-radius: 0.375rem !important;\n }\n \n /* 主题活跃状态样式 - 从共用配置生成 */\n ${generateTreeActiveStyles()}\n \n /* 非活跃节点的悬停状态 */\n .tree-node-content-inactive:hover {\n background-color: oklch(var(--b2));\n }\n `}</style>\n </div>\n );\n};\n\nexport default Tree;\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"Tree.js","names":["_Fragment","React","Tree","searchQuery","setSearchQuery","useState","expandedIds","setExpandedIds","defaultExpandedIds","newSet","prev","id","defaultExpandIconEl","expandIcon","defaultCollapseIconEl","collapseIcon","defaultIconEl","defaultIcon","countNodes","useCallback","nodes","count","node","totalCount","useMemo","data","filterNodes","query","lowerQuery","filtered","matches","filteredChildren","filteredData","toggleNode","newExpanded","nodeId","onNodeToggle","expandAll","allIds","collectIds","collapseAll","renderTreeNode","hasChildren","isExpanded","isActive","activeNodeId","currentPath","path","nodeContent","depth","indent","onNodeClick","onNodeDoubleClick","togglePosition","Fragment","e","showIcon","renderLabel","showCount","child","renderNode","className","title","titleIcon","showSearch","searchPlaceholder","showExpandAll","expandAllText","collapseAllText","noResultsText","emptyText","showLine","generateTreeActiveStyles"],"sources":["../../../src/components/Tree/Tree.tsx"],"sourcesContent":["import React, { useState, useCallback, useMemo } from 'react';\nimport { generateTreeActiveStyles } from '../../styles/themeStyles';\n\n// ============= 类型定义 =============\n\nexport interface TreeNode {\n id: string | number;\n label: string;\n children?: TreeNode[];\n icon?: React.ReactNode;\n disabled?: boolean;\n meta?: Record<string, any>;\n}\n\nexport interface TreeProps {\n /** 树形数据 */\n data: TreeNode[];\n\n /** 节点点击回调 */\n onNodeClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点双击回调 */\n onNodeDoubleClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点展开/折叠回调 */\n onNodeToggle?: (nodeId: string | number, expanded: boolean) => void;\n\n /** 当前激活的节点 ID */\n activeNodeId?: string | number;\n\n /** 默认展开的节点 ID 列表 */\n defaultExpandedIds?: (string | number)[];\n\n /** 是否显示搜索框 */\n showSearch?: boolean;\n\n /** 搜索占位符 */\n searchPlaceholder?: string;\n\n /** 是否显示展开/折叠全部按钮 */\n showExpandAll?: boolean;\n\n /** 展开全部按钮文本 */\n expandAllText?: string;\n\n /** 折叠全部按钮文本 */\n collapseAllText?: string;\n\n /** 是否显示节点图标 */\n showIcon?: boolean;\n\n /** 默认图标 */\n defaultIcon?: React.ReactNode;\n\n /** 展开图标 */\n expandIcon?: React.ReactNode;\n\n /** 折叠图标 */\n collapseIcon?: React.ReactNode;\n\n /** 是否显示连接线 */\n showLine?: boolean;\n\n /** 最大高度 */\n maxHeight?: string;\n\n /** 自定义类名 */\n className?: string;\n\n /** 标题 */\n title?: string;\n\n /** 标题图标 */\n titleIcon?: React.ReactNode;\n\n /** 是否显示节点数量 */\n showCount?: boolean;\n\n /** 空状态文本 */\n emptyText?: string;\n\n /** 搜索无结果文本 */\n noResultsText?: string;\n\n /** 缩进宽度(像素) */\n indent?: number;\n\n /** 展开按钮位置:left(左侧)或 right(右侧) */\n togglePosition?: 'left' | 'right';\n\n /** 是否可拖拽(暂不实现) */\n draggable?: boolean;\n\n /** 是否可选择(暂不实现) */\n checkable?: boolean;\n\n /** Custom label content; depth is zero-based. The string label remains the search text and native title. */\n renderLabel?: (node: TreeNode, depth: number) => React.ReactNode;\n\n /** 自定义渲染节点 */\n renderNode?: (node: TreeNode, defaultRender: React.ReactNode) => React.ReactNode;\n}\n\n// ============= Tree 组件 =============\n\nconst Tree: React.FC<TreeProps> = ({\n data,\n onNodeClick,\n onNodeDoubleClick,\n onNodeToggle,\n activeNodeId,\n defaultExpandedIds = [],\n showSearch = true,\n searchPlaceholder = 'Search...',\n showExpandAll = true,\n expandAllText = 'Expand All',\n collapseAllText = 'Collapse All',\n showIcon = true,\n defaultIcon,\n expandIcon,\n collapseIcon,\n showLine = false,\n maxHeight = '600px',\n className = '',\n title,\n titleIcon,\n showCount = true,\n emptyText = 'No data',\n noResultsText = 'No results found',\n indent = 16,\n togglePosition = 'left',\n renderLabel,\n renderNode,\n}) => {\n const [searchQuery, setSearchQuery] = useState('');\n const [expandedIds, setExpandedIds] = useState<Set<string | number>>(\n new Set(defaultExpandedIds)\n );\n\n // 当 defaultExpandedIds 变化时,同步更新 expandedIds(用于异步加载的数据)\n React.useEffect(() => {\n if (defaultExpandedIds.length > 0) {\n setExpandedIds(prev => {\n const newSet = new Set(prev);\n defaultExpandedIds.forEach(id => newSet.add(id));\n return newSet;\n });\n }\n }, [defaultExpandedIds]);\n\n // 默认展开/折叠图标\n const defaultExpandIconEl = expandIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n );\n\n const defaultCollapseIconEl = collapseIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n );\n\n // 默认节点图标\n const defaultIconEl = defaultIcon || (\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n );\n\n // 统计节点总数\n const countNodes = useCallback((nodes: TreeNode[]): number => {\n return nodes.reduce((count, node) => {\n return count + 1 + (node.children ? countNodes(node.children) : 0);\n }, 0);\n }, []);\n\n const totalCount = useMemo(() => countNodes(data), [data, countNodes]);\n\n // 过滤节点(支持搜索)\n const filterNodes = useCallback((nodes: TreeNode[], query: string): TreeNode[] => {\n if (!query) return nodes;\n\n const lowerQuery = query.toLowerCase();\n const filtered: TreeNode[] = [];\n\n for (const node of nodes) {\n const matches = node.label.toLowerCase().includes(lowerQuery);\n const filteredChildren = node.children ? filterNodes(node.children, query) : [];\n\n if (matches || filteredChildren.length > 0) {\n filtered.push({\n ...node,\n children: filteredChildren.length > 0 ? filteredChildren : node.children,\n });\n }\n }\n\n return filtered;\n }, []);\n\n const filteredData = useMemo(\n () => filterNodes(data, searchQuery),\n [data, searchQuery, filterNodes]\n );\n\n // 切换节点展开/折叠\n const toggleNode = useCallback(\n (nodeId: string | number) => {\n const newExpanded = new Set(expandedIds);\n if (newExpanded.has(nodeId)) {\n newExpanded.delete(nodeId);\n onNodeToggle?.(nodeId, false);\n } else {\n newExpanded.add(nodeId);\n onNodeToggle?.(nodeId, true);\n }\n setExpandedIds(newExpanded);\n },\n [expandedIds, onNodeToggle]\n );\n\n // 展开所有节点\n const expandAll = useCallback(() => {\n const allIds = new Set<string | number>();\n const collectIds = (nodes: TreeNode[]) => {\n nodes.forEach((node) => {\n if (node.children && node.children.length > 0) {\n allIds.add(node.id);\n collectIds(node.children);\n }\n });\n };\n collectIds(data);\n setExpandedIds(allIds);\n }, [data]);\n\n // 折叠所有节点\n const collapseAll = useCallback(() => {\n setExpandedIds(new Set());\n }, []);\n\n // 渲染单个节点\n const renderTreeNode = useCallback(\n (node: TreeNode, depth: number = 0, path: (string | number)[] = []) => {\n const hasChildren = node.children && node.children.length > 0;\n const isExpanded = expandedIds.has(node.id);\n const isActive = activeNodeId === node.id;\n const currentPath = [...path, node.id];\n\n const nodeContent = (\n <div\n key={node.id}\n data-node-id={node.id}\n data-depth={depth}\n data-level={depth + 1}\n className={`tree-node ${isActive ? 'tree-node-active' : ''} ${node.disabled ? 'tree-node-disabled' : ''\n }`}\n style={{\n paddingLeft: `${depth * indent}px`,\n }}\n >\n <div\n className={`tree-node-content flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer transition-colors ${isActive ? 'tree-node-content-active' : 'tree-node-content-inactive'\n } ${node.disabled ? 'opacity-50 cursor-not-allowed' : ''}`}\n onClick={() => {\n if (!node.disabled) {\n onNodeClick?.(node, currentPath);\n }\n }}\n onDoubleClick={() => {\n if (!node.disabled) {\n onNodeDoubleClick?.(node, currentPath);\n }\n }}\n >\n {/* 左侧展开按钮 */}\n {togglePosition === 'left' && (\n <>\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.label}`}\n aria-expanded={isExpanded}\n className={`tree-node-toggle btn btn-xs btn-ghost btn-circle ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n ) : (\n <span className=\"tree-node-toggle-placeholder\" style={{ width: '1.5rem', height: '1.5rem', flexShrink: 0 }}></span>\n )}\n </>\n )}\n\n {/* 节点图标 */}\n {showIcon && (\n <span className=\"tree-node-icon\">{node.icon || defaultIconEl}</span>\n )}\n\n {/* 节点标签 */}\n <span className=\"tree-node-label text-sm truncate flex-1\" title={node.label}>\n {renderLabel ? renderLabel(node, depth) : node.label}\n </span>\n\n {/* 子节点数量(优先使用 meta.count,否则回退到子节点个数) */}\n {node.meta?.count !== undefined && node.meta?.count !== null ? (\n <span className=\"tree-node-count text-xs opacity-60\">\n {node.meta.count}\n </span>\n ) : hasChildren && showCount ? (\n <span className=\"tree-node-count text-xs opacity-60\">\n ({node.children!.length})\n </span>\n ) : null}\n\n {/* 右侧展开按钮 */}\n {togglePosition === 'right' && hasChildren && (\n <button\n type=\"button\"\n aria-label={`${isExpanded ? 'Collapse' : 'Expand'} ${node.label}`}\n aria-expanded={isExpanded}\n className={`tree-node-toggle tree-node-toggle-right btn btn-xs btn-ghost ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n )}\n </div>\n\n {/* 子节点 */}\n {hasChildren && (\n <div\n className={`tree-node-children ${isExpanded ? 'tree-node-children-expanded' : 'tree-node-children-collapsed'}`}\n >\n {node.children!.map((child) => renderTreeNode(child, depth + 1, currentPath))}\n </div>\n )}\n </div>\n );\n\n // 自定义渲染\n if (renderNode) {\n return renderNode(node, nodeContent);\n }\n\n return nodeContent;\n },\n [\n expandedIds,\n activeNodeId,\n indent,\n showIcon,\n showCount,\n togglePosition,\n defaultExpandIconEl,\n defaultCollapseIconEl,\n defaultIconEl,\n onNodeClick,\n onNodeDoubleClick,\n toggleNode,\n renderLabel,\n renderNode,\n ]\n );\n\n return (\n <div className={`tree-component bg-base-100 border border-base-300 rounded-lg p-2 ${className}`}>\n {/* 标题 */}\n {title && (\n <div className=\"tree-header flex items-center gap-2 px-2 py-1 mb-2 border-b border-base-300\">\n {titleIcon}\n <span className=\"font-semibold\">{title}</span>\n {showCount && (\n <span className=\"text-xs opacity-60 ml-auto\">({totalCount})</span>\n )}\n </div>\n )}\n\n {/* 搜索框 */}\n {showSearch && (\n <input\n type=\"text\"\n placeholder={searchPlaceholder}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"tree-search input input-sm input-bordered w-full mb-2\"\n />\n )}\n\n {/* 操作按钮 */}\n {showExpandAll && (\n <div className=\"tree-actions flex gap-1 mb-2\">\n <button className=\"btn btn-xs btn-ghost\" onClick={expandAll}>\n {expandAllText}\n </button>\n <button className=\"btn btn-xs btn-ghost\" onClick={collapseAll}>\n {collapseAllText}\n </button>\n </div>\n )}\n\n {/* 树形列表 */}\n <div\n className=\"tree-content overflow-y-auto\"\n style={{ maxHeight }}\n >\n {filteredData.length === 0 ? (\n <div className=\"tree-empty text-center text-sm opacity-60 py-4\">\n {searchQuery ? noResultsText : emptyText}\n </div>\n ) : (\n <div className={`tree-nodes ${showLine ? 'tree-show-line' : ''}`}>\n {filteredData.map((node) => renderTreeNode(node))}\n </div>\n )}\n </div>\n\n <style>{`\n .tree-node {\n user-select: none;\n }\n \n /* 子节点容器基础样式 */\n .tree-node-children {\n margin-top: 2px;\n overflow: hidden;\n transform-origin: top;\n box-sizing: border-box;\n }\n \n /* 折叠状态 - 初始隐藏 */\n .tree-node-children-collapsed {\n max-height: 0;\n opacity: 0;\n transform: scaleY(0.8);\n border-left: none !important;\n }\n \n /* 展开状态 - 显示内容 */\n .tree-node-children-expanded {\n max-height: 5000px;\n opacity: 1;\n transform: scaleY(1);\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n /* 不对 border 做动画 */\n box-sizing: border-box;\n }\n \n /* 连接线样式 - 在展开状态显示,使用多重选择器提高优先级 */\n .tree-component .tree-show-line .tree-node-children-expanded,\n .tree-show-line .tree-node-children.tree-node-children-expanded {\n border-left: 1px solid var(--fallback-bc, oklch(var(--bc) / 0.2)) !important;\n margin-left: 8px !important;\n padding-left: 8px !important;\n position: relative;\n }\n \n /* 左侧连接线圆点装饰 */\n .tree-show-line .tree-node-children-expanded::before {\n content: '';\n position: absolute;\n left: -3px;\n top: 0;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background-color: var(--fallback-bc, oklch(var(--bc) / 0.3));\n }\n \n /* 折叠过渡 */\n .tree-node-children-collapsed {\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 展开/折叠按钮图标旋转动画 */\n .tree-node-toggle {\n z-index: 2;\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n .tree-node-toggle svg {\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 折叠状态的图标 - 向右 */\n .tree-node-toggle:not(.tree-node-toggle-expanded) svg {\n transform: rotate(0deg);\n }\n \n /* 展开状态的图标 - 向下(已经是向下的,所以不需要额外旋转) */\n .tree-node-toggle-expanded svg {\n transform: rotate(0deg);\n }\n \n .tree-component {\n position: relative;\n z-index: 1;\n }\n \n .tree-node-disabled {\n cursor: not-allowed;\n }\n \n .tree-node-disabled .tree-node-content {\n pointer-events: none;\n }\n \n /* 节点内容悬停效果 */\n .tree-node-content {\n transition: background-color 0.15s ease;\n }\n \n /* 优化性能 - 告诉浏览器这些属性会变化 */\n .tree-node-children {\n will-change: max-height, opacity, transform;\n }\n \n /* 动画完成后移除 will-change 以节省资源 */\n .tree-node-children-expanded,\n .tree-node-children-collapsed {\n animation: remove-will-change 0.3s forwards;\n }\n \n @keyframes remove-will-change {\n to {\n will-change: auto;\n }\n }\n \n /* 活跃节点基础样式 */\n .tree-node-content-active {\n font-weight: 600 !important;\n padding-left: calc(0.5rem - 4px) !important;\n border-radius: 0.375rem !important;\n }\n \n /* 主题活跃状态样式 - 从共用配置生成 */\n ${generateTreeActiveStyles()}\n \n /* 非活跃节点的悬停状态 */\n .tree-node-content-inactive:hover {\n background-color: oklch(var(--b2));\n }\n `}</style>\n </div>\n );\n};\n\nexport default Tree;\n\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/AgentChat/index.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { formatDuration } from '../shared';\nimport LoadingState from '../LoadingState';\nimport './AgentChat.css';\n\nexport type AgentChatReasoningStep = {\n /** Tools used in this step, rendered as chips: `Sales History · Flavor Data`. */\n tools?: string[];\n /** Rendered as `for 4s` after the chips. */\n durationMs?: number;\n /** Plain-language result of the step. */\n summary?: React.ReactNode;\n};\n\nexport type AgentChatMessage = {\n id: string;\n role: 'user' | 'assistant';\n content?: React.ReactNode | string;\n /** Assistant-only: each step renders as a chips-and-duration line followed by its summary. */\n reasoning?: AgentChatReasoningStep[];\n /** Epoch milliseconds. */\n createdAt?: number;\n};\n\nexport type ChatThread = {\n id: string;\n label: string;\n messages: AgentChatMessage[];\n};\n\nexport type AgentChatLabels = {\n send?: string;\n thinking?: string;\n threads?: string;\n messages?: string;\n};\n\nexport type AgentChatProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n threads: ChatThread[];\n /** Controlled active thread id. */\n activeThread?: string;\n defaultActiveThread?: string;\n onActiveThreadChange?: (threadId: string) => void;\n /** Called with the trimmed composer text and the active thread id. */\n onSend?: (text: string, threadId: string) => void;\n /** Shows a thinking indicator under the last message and disables sending. */\n busy?: boolean;\n placeholder?: string;\n /** Total panel height; number = px. */\n height?: string | number;\n /** Replace the default message renderer. */\n renderMessage?: (message: AgentChatMessage) => React.ReactNode;\n /** Shown when the active thread has no messages. */\n emptyState?: React.ReactNode;\n labels?: AgentChatLabels;\n};\n\nconst DEFAULT_LABELS: Required<AgentChatLabels> = {\n send: 'Send',\n thinking: 'Thinking',\n threads: 'Threads',\n messages: 'Messages',\n};\n\nconst resizeComposer = (el: HTMLTextAreaElement) => {\n el.style.height = 'auto';\n el.style.height = `${Math.min(el.scrollHeight, 160)}px`;\n};\n\nconst SendIcon: 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=\"m5 12 7-7 7 7\" />\n <path d=\"M12 19V5\" />\n </svg>\n);\n\nconst Reasoning: React.FC<{ steps: AgentChatReasoningStep[] }> = ({ steps }) => (\n <ol className=\"dishui-ai-agent-chat__reasoning\">\n {steps.map(step => (\n <li key={`${step.durationMs ?? ''}-${step.tools?.join('-') ?? ''}-${String(step.summary ?? '')}`} className=\"dishui-ai-agent-chat__step\">\n {(step.tools?.length || step.durationMs !== undefined) && (\n <div className=\"dishui-ai-agent-chat__tools\">\n {step.tools?.map((tool, j) => (\n <React.Fragment key={tool}>\n {j > 0 && <span className=\"dishui-ai-agent-chat__sep\" aria-hidden=\"true\">·</span>}\n <span className=\"dishui-ai-agent-chat__chip\">{tool}</span>\n </React.Fragment>\n ))}\n {step.durationMs !== undefined && (\n <>\n {!!step.tools?.length && <span className=\"dishui-ai-agent-chat__sep\" aria-hidden=\"true\">·</span>}\n <span className=\"dishui-ai-agent-chat__duration\">for {formatDuration(step.durationMs)}</span>\n </>\n )}\n </div>\n )}\n {step.summary !== undefined && <div className=\"dishui-ai-agent-chat__summary\">{step.summary}</div>}\n </li>\n ))}\n </ol>\n);\n\nconst DefaultMessage: React.FC<{ message: AgentChatMessage }> = ({ message }) => (\n <div className={cn('dishui-ai-agent-chat__message', `dishui-ai-agent-chat__message--${message.role}`)}>\n {message.role === 'assistant' && message.reasoning?.length ? <Reasoning steps={message.reasoning} /> : null}\n {message.content !== undefined && message.content !== null && (\n <div className=\"dishui-ai-agent-chat__content\">{message.content}</div>\n )}\n </div>\n);\n\n/**\n * Tabbed chat panel: a `tablist` of threads, a scrollable log where user\n * turns sit right in a muted bubble and assistant turns sit left as plain\n * text with their reasoning lines, and a composer that auto-grows.\n */\nexport default function AgentChat({\n threads,\n activeThread: activeProp,\n defaultActiveThread,\n onActiveThreadChange,\n onSend,\n busy = false,\n placeholder = 'Ask the agent…',\n height = 480,\n renderMessage,\n emptyState,\n labels,\n className,\n style,\n ...rest\n}: AgentChatProps) {\n const baseId = useId();\n const text = { ...DEFAULT_LABELS, ...labels };\n\n const [internalActive, setInternalActive] = useState<string | undefined>(defaultActiveThread ?? threads[0]?.id);\n const activeId = activeProp ?? internalActive;\n const thread = threads.find(t => t.id === activeId) ?? threads[0];\n const activate = useCallback((id: string) => {\n setInternalActive(id);\n onActiveThreadChange?.(id);\n }, [onActiveThreadChange]);\n\n const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});\n const onTabKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>, index: number) => {\n let next: number | undefined;\n if (event.key === 'ArrowRight') next = (index + 1) % threads.length;\n else if (event.key === 'ArrowLeft') next = (index - 1 + threads.length) % threads.length;\n else if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = threads.length - 1;\n if (next === undefined) return;\n event.preventDefault();\n const target = threads[next];\n activate(target.id);\n tabRefs.current[target.id]?.focus();\n };\n\n const logRef = useRef<HTMLDivElement>(null);\n const messageCount = thread?.messages.length ?? 0;\n // The effect intentionally follows message/busy transitions to keep the log pinned.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n const el = logRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n // Message count and busy state intentionally retrigger the imperative scroll.\n void messageCount;\n void busy;\n }, [messageCount, busy]);\n\n const [draft, setDraft] = useState('');\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const canSend = !busy && draft.trim().length > 0 && !!thread;\n const send = () => {\n if (!canSend || !thread) return;\n onSend?.(draft.trim(), thread.id);\n setDraft('');\n const el = textareaRef.current;\n if (el) el.style.height = 'auto';\n };\n const onComposerKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault();\n send();\n }\n };\n\n const panelId = `${baseId}-panel`;\n const tabId = (id: string) => `${baseId}-tab-${id}`;\n\n return (\n <div\n {...rest}\n className={cn('dishui-ai-agent-chat', className)}\n style={{ ...style, height: typeof height === 'number' ? `${height}px` : height }}\n >\n {threads.length > 1 && (\n <div className=\"dishui-ai-agent-chat__tabs\" role=\"tablist\" aria-label={text.threads}>\n {threads.map((t, i) => {\n const selected = t.id === thread?.id;\n return (\n <button\n key={t.id}\n ref={el => { tabRefs.current[t.id] = el; }}\n id={tabId(t.id)}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n aria-controls={panelId}\n tabIndex={selected ? 0 : -1}\n className={cn('dishui-ai-agent-chat__tab', selected && 'dishui-ai-agent-chat__tab--active')}\n onClick={() => activate(t.id)}\n onKeyDown={e => onTabKeyDown(e, i)}\n >\n {t.label}\n </button>\n );\n })}\n </div>\n )}\n\n <div\n ref={logRef}\n id={panelId}\n role=\"tabpanel\"\n aria-labelledby={thread && threads.length > 1 ? tabId(thread.id) : undefined}\n className=\"dishui-ai-agent-chat__log\"\n >\n <div role=\"log\" aria-live=\"polite\" aria-label={text.messages} className=\"dishui-ai-agent-chat__messages\">\n {messageCount === 0 && !busy && emptyState !== undefined && (\n <div className=\"dishui-ai-agent-chat__empty\">{emptyState}</div>\n )}\n {thread?.messages.map(message => (\n <React.Fragment key={message.id}>\n {renderMessage ? renderMessage(message) : <DefaultMessage message={message} />}\n </React.Fragment>\n ))}\n {busy && (\n <div className=\"dishui-ai-agent-chat__message dishui-ai-agent-chat__message--assistant\">\n <LoadingState variant=\"dots\" size=\"sm\" label={text.thinking} showElapsed={false} />\n </div>\n )}\n </div>\n </div>\n\n <form\n className=\"dishui-ai-agent-chat__composer\"\n onSubmit={e => { e.preventDefault(); send(); }}\n >\n <textarea\n ref={textareaRef}\n className=\"dishui-ai-agent-chat__input\"\n rows={1}\n value={draft}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={!thread}\n onChange={e => { setDraft(e.target.value); resizeComposer(e.target); }}\n onKeyDown={onComposerKeyDown}\n />\n <button\n type=\"submit\"\n className=\"dishui-ai-agent-chat__send\"\n disabled={!canSend}\n aria-label={text.send}\n title={text.send}\n >\n <SendIcon />\n </button>\n </form>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_Fragment","LoadingState","React","DEFAULT_LABELS","resizeComposer","el","SendIcon","Reasoning","steps","step","j","tool","Fragment","formatDuration","DefaultMessage","cn","message","AgentChat","activeProp","rest","baseId","useId","text","labels","internalActive","setInternalActive","useState","defaultActiveThread","threads","activeId","thread","t","activate","useCallback","id","onActiveThreadChange","tabRefs","useRef","onTabKeyDown","next","event","index","target","logRef","messageCount","busy","draft","setDraft","textareaRef","canSend","send","onSend","onComposerKeyDown","panelId","tabId","className","style","height","selected","i","emptyState","renderMessage","placeholder"],"sources":["../../../../src/components/ai/AgentChat/index.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport { formatDuration } from '../shared';\nimport LoadingState from '../LoadingState';\nimport './AgentChat.css';\n\nexport type AgentChatReasoningStep = {\n /** Tools used in this step, rendered as chips: `Sales History · Flavor Data`. */\n tools?: string[];\n /** Rendered as `for 4s` after the chips. */\n durationMs?: number;\n /** Plain-language result of the step. */\n summary?: React.ReactNode;\n};\n\nexport type AgentChatMessage = {\n id: string;\n role: 'user' | 'assistant';\n content?: React.ReactNode | string;\n /** Assistant-only: each step renders as a chips-and-duration line followed by its summary. */\n reasoning?: AgentChatReasoningStep[];\n /** Epoch milliseconds. */\n createdAt?: number;\n};\n\nexport type ChatThread = {\n id: string;\n label: string;\n messages: AgentChatMessage[];\n};\n\nexport type AgentChatLabels = {\n send?: string;\n thinking?: string;\n threads?: string;\n messages?: string;\n};\n\nexport type AgentChatProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n threads: ChatThread[];\n /** Controlled active thread id. */\n activeThread?: string;\n defaultActiveThread?: string;\n onActiveThreadChange?: (threadId: string) => void;\n /** Called with the trimmed composer text and the active thread id. */\n onSend?: (text: string, threadId: string) => void;\n /** Shows a thinking indicator under the last message and disables sending. */\n busy?: boolean;\n placeholder?: string;\n /** Total panel height; number = px. */\n height?: string | number;\n /** Replace the default message renderer. */\n renderMessage?: (message: AgentChatMessage) => React.ReactNode;\n /** Shown when the active thread has no messages. */\n emptyState?: React.ReactNode;\n labels?: AgentChatLabels;\n};\n\nconst DEFAULT_LABELS: Required<AgentChatLabels> = {\n send: 'Send',\n thinking: 'Thinking',\n threads: 'Threads',\n messages: 'Messages',\n};\n\nconst resizeComposer = (el: HTMLTextAreaElement) => {\n el.style.height = 'auto';\n el.style.height = `${Math.min(el.scrollHeight, 160)}px`;\n};\n\nconst SendIcon: 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=\"m5 12 7-7 7 7\" />\n <path d=\"M12 19V5\" />\n </svg>\n);\n\nconst Reasoning: React.FC<{ steps: AgentChatReasoningStep[] }> = ({ steps }) => (\n <ol className=\"dishui-ai-agent-chat__reasoning\">\n {steps.map(step => (\n <li key={`${step.durationMs ?? ''}-${step.tools?.join('-') ?? ''}-${String(step.summary ?? '')}`} className=\"dishui-ai-agent-chat__step\">\n {(step.tools?.length || step.durationMs !== undefined) && (\n <div className=\"dishui-ai-agent-chat__tools\">\n {step.tools?.map((tool, j) => (\n <React.Fragment key={tool}>\n {j > 0 && <span className=\"dishui-ai-agent-chat__sep\" aria-hidden=\"true\">·</span>}\n <span className=\"dishui-ai-agent-chat__chip\">{tool}</span>\n </React.Fragment>\n ))}\n {step.durationMs !== undefined && (\n <>\n {!!step.tools?.length && <span className=\"dishui-ai-agent-chat__sep\" aria-hidden=\"true\">·</span>}\n <span className=\"dishui-ai-agent-chat__duration\">for {formatDuration(step.durationMs)}</span>\n </>\n )}\n </div>\n )}\n {step.summary !== undefined && <div className=\"dishui-ai-agent-chat__summary\">{step.summary}</div>}\n </li>\n ))}\n </ol>\n);\n\nconst DefaultMessage: React.FC<{ message: AgentChatMessage }> = ({ message }) => (\n <div className={cn('dishui-ai-agent-chat__message', `dishui-ai-agent-chat__message--${message.role}`)}>\n {message.role === 'assistant' && message.reasoning?.length ? <Reasoning steps={message.reasoning} /> : null}\n {message.content !== undefined && message.content !== null && (\n <div className=\"dishui-ai-agent-chat__content\">{message.content}</div>\n )}\n </div>\n);\n\n/**\n * Tabbed chat panel: a `tablist` of threads, a scrollable log where user\n * turns sit right in a muted bubble and assistant turns sit left as plain\n * text with their reasoning lines, and a composer that auto-grows.\n */\nexport default function AgentChat({\n threads,\n activeThread: activeProp,\n defaultActiveThread,\n onActiveThreadChange,\n onSend,\n busy = false,\n placeholder = 'Ask the agent…',\n height = 480,\n renderMessage,\n emptyState,\n labels,\n className,\n style,\n ...rest\n}: AgentChatProps) {\n const baseId = useId();\n const text = { ...DEFAULT_LABELS, ...labels };\n\n const [internalActive, setInternalActive] = useState<string | undefined>(defaultActiveThread ?? threads[0]?.id);\n const activeId = activeProp ?? internalActive;\n const thread = threads.find(t => t.id === activeId) ?? threads[0];\n const activate = useCallback((id: string) => {\n setInternalActive(id);\n onActiveThreadChange?.(id);\n }, [onActiveThreadChange]);\n\n const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});\n const onTabKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>, index: number) => {\n let next: number | undefined;\n if (event.key === 'ArrowRight') next = (index + 1) % threads.length;\n else if (event.key === 'ArrowLeft') next = (index - 1 + threads.length) % threads.length;\n else if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = threads.length - 1;\n if (next === undefined) return;\n event.preventDefault();\n const target = threads[next];\n activate(target.id);\n tabRefs.current[target.id]?.focus();\n };\n\n const logRef = useRef<HTMLDivElement>(null);\n const messageCount = thread?.messages.length ?? 0;\n // The effect intentionally follows message/busy transitions to keep the log pinned.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n const el = logRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n // Message count and busy state intentionally retrigger the imperative scroll.\n void messageCount;\n void busy;\n }, [messageCount, busy]);\n\n const [draft, setDraft] = useState('');\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const canSend = !busy && draft.trim().length > 0 && !!thread;\n const send = () => {\n if (!canSend || !thread) return;\n onSend?.(draft.trim(), thread.id);\n setDraft('');\n const el = textareaRef.current;\n if (el) el.style.height = 'auto';\n };\n const onComposerKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent.isComposing) {\n event.preventDefault();\n send();\n }\n };\n\n const panelId = `${baseId}-panel`;\n const tabId = (id: string) => `${baseId}-tab-${id}`;\n\n return (\n <div\n {...rest}\n className={cn('dishui-ai-agent-chat', className)}\n style={{ ...style, height: typeof height === 'number' ? `${height}px` : height }}\n >\n {threads.length > 1 && (\n <div className=\"dishui-ai-agent-chat__tabs\" role=\"tablist\" aria-label={text.threads}>\n {threads.map((t, i) => {\n const selected = t.id === thread?.id;\n return (\n <button\n key={t.id}\n ref={el => { tabRefs.current[t.id] = el; }}\n id={tabId(t.id)}\n type=\"button\"\n role=\"tab\"\n aria-selected={selected}\n aria-controls={panelId}\n tabIndex={selected ? 0 : -1}\n className={cn('dishui-ai-agent-chat__tab', selected && 'dishui-ai-agent-chat__tab--active')}\n onClick={() => activate(t.id)}\n onKeyDown={e => onTabKeyDown(e, i)}\n >\n {t.label}\n </button>\n );\n })}\n </div>\n )}\n\n <div\n ref={logRef}\n id={panelId}\n role=\"tabpanel\"\n aria-labelledby={thread && threads.length > 1 ? tabId(thread.id) : undefined}\n className=\"dishui-ai-agent-chat__log\"\n >\n <div role=\"log\" aria-live=\"polite\" aria-label={text.messages} className=\"dishui-ai-agent-chat__messages\">\n {messageCount === 0 && !busy && emptyState !== undefined && (\n <div className=\"dishui-ai-agent-chat__empty\">{emptyState}</div>\n )}\n {thread?.messages.map(message => (\n <React.Fragment key={message.id}>\n {renderMessage ? renderMessage(message) : <DefaultMessage message={message} />}\n </React.Fragment>\n ))}\n {busy && (\n <div className=\"dishui-ai-agent-chat__message dishui-ai-agent-chat__message--assistant\">\n <LoadingState variant=\"dots\" size=\"sm\" label={text.thinking} showElapsed={false} />\n </div>\n )}\n </div>\n </div>\n\n <form\n className=\"dishui-ai-agent-chat__composer\"\n onSubmit={e => { e.preventDefault(); send(); }}\n >\n <textarea\n ref={textareaRef}\n className=\"dishui-ai-agent-chat__input\"\n rows={1}\n value={draft}\n placeholder={placeholder}\n aria-label={placeholder}\n disabled={!thread}\n onChange={e => { setDraft(e.target.value); resizeComposer(e.target); }}\n onKeyDown={onComposerKeyDown}\n />\n <button\n type=\"submit\"\n className=\"dishui-ai-agent-chat__send\"\n disabled={!canSend}\n aria-label={text.send}\n title={text.send}\n >\n <SendIcon />\n </button>\n </form>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/AgentRunCard/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport { clamp } from '../shared';\nimport './AgentRunCard.css';\n\nexport type AgentRunStatus = 'queued' | 'running' | 'waiting' | 'done' | 'failed';\n\nexport type AgentRunMeta = {\n label?: React.ReactNode;\n value: React.ReactNode;\n};\n\nexport type AgentRunCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onSelect'> & {\n /** Agent name (e.g. `Sol`). */\n name: React.ReactNode;\n /** Model or engine label shown beside the name (e.g. `Opus 5`). */\n model?: React.ReactNode;\n /** Avatar slot, typically an `Avatar` with the agent's initials. */\n avatar?: React.ReactNode;\n /** Run status; drives the trailing badge tone and progress colour. */\n status?: AgentRunStatus;\n /** Explicit status label; defaults to a capitalised form of `status`. */\n statusLabel?: React.ReactNode;\n /** The task the agent is working on (single truncating line). */\n task?: React.ReactNode;\n /** Current activity line, prefixed by a status dot. */\n activity?: React.ReactNode;\n /** Progress from 0 to 1. When omitted, the progress row is hidden. */\n progress?: number;\n /** Compact meta values shown in a row (e.g. steps, elapsed, tokens). */\n meta?: AgentRunMeta[];\n /** Monospace footer, typically a branch or path. */\n footer?: React.ReactNode;\n /** Selected state (raised border). */\n selected?: boolean;\n /** Click handler turns the card into a button for keyboard users. */\n onSelect?: () => void;\n};\n\nconst STATUS_LABEL: Record<AgentRunStatus, string> = {\n queued: 'Queued',\n running: 'Running',\n waiting: 'Waiting',\n done: 'Done',\n failed: 'Failed',\n};\n\nconst EMPTY_META: AgentRunMeta[] = [];\n\n/**\n * Agent run card: avatar + name + model, a status badge, the task, a current\n * activity line, an optional progress bar with percentage, a compact meta row\n * (steps / elapsed / tokens) and a monospace footer (branch or path).\n */\nexport default function AgentRunCard({\n name,\n model,\n avatar,\n status = 'queued',\n statusLabel,\n task,\n activity,\n progress,\n meta = EMPTY_META,\n footer,\n selected = false,\n onSelect,\n className,\n ...rest\n}: AgentRunCardProps) {\n const interactive = !!onSelect;\n const hasProgress = typeof progress === 'number' && Number.isFinite(progress);\n const pct = hasProgress ? Math.round(clamp(progress as number, 0, 1) * 100) : 0;\n const live = status === 'running';\n const label = statusLabel ?? STATUS_LABEL[status];\n\n return (\n <div\n {...rest}\n className={cn(\n 'dishui-ai-run-card',\n `dishui-ai-run-card--${status}`,\n selected && 'dishui-ai-run-card--selected',\n interactive && 'dishui-ai-run-card--interactive',\n className,\n )}\n role={interactive ? 'button' : undefined}\n tabIndex={interactive ? 0 : undefined}\n aria-pressed={interactive ? selected : undefined}\n onClick={interactive ? onSelect : rest.onClick}\n onKeyDown={interactive ? (event) => {\n if (event.target !== event.currentTarget) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n if (!event.repeat) onSelect?.();\n }\n } : undefined}\n >\n <header className=\"dishui-ai-run-card__header\">\n {avatar !== null && avatar !== undefined && <span className=\"dishui-ai-run-card__avatar\">{avatar}</span>}\n <span className=\"dishui-ai-run-card__identity\">\n <span className=\"dishui-ai-run-card__name\">{name}</span>\n {model !== null && model !== undefined && <span className=\"dishui-ai-run-card__model\">{model}</span>}\n </span>\n <span\n className={cn('dishui-ai-run-card__status', `dishui-ai-run-card__status--${status}`)}\n role=\"status\"\n aria-live=\"polite\"\n >\n <span className={cn('dishui-ai-run-card__dot', live && 'dishui-ai-run-card__dot--live')} aria-hidden=\"true\" />\n {label}\n </span>\n </header>\n\n {task !== null && task !== undefined && <div className=\"dishui-ai-run-card__task\">{task}</div>}\n\n {activity !== null && activity !== undefined && (\n <div className=\"dishui-ai-run-card__activity\">\n <span className=\"dishui-ai-run-card__activity-dot\" aria-hidden=\"true\" />\n <span className=\"dishui-ai-run-card__activity-text\">{activity}</span>\n </div>\n )}\n\n {hasProgress && (\n <div className=\"dishui-ai-run-card__progress\">\n <span\n className=\"dishui-ai-run-card__track\"\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={pct}\n >\n <span className=\"dishui-ai-run-card__fill\" style={{ width: `${pct}%` }} />\n </span>\n <span className=\"dishui-ai-run-card__pct\">{pct}%</span>\n </div>\n )}\n\n {meta.length > 0 && (\n <dl className=\"dishui-ai-run-card__meta\">\n {meta.map((item, index) => (\n <div key={item.label !== null && item.label !== undefined ? `${String(item.label)}-${index}` : `meta-${index}`}>\n {item.label !== null && item.label !== undefined && <dt>{item.label}</dt>}\n <dd>{item.value}</dd>\n </div>\n ))}\n </dl>\n )}\n\n {footer !== null && footer !== undefined && <div className=\"dishui-ai-run-card__footer\">{footer}</div>}\n </div>\n );\n}\n"],"mappings":";;;;;;AAuCA,IAAM,IAA+C;CACnD,QAAQ;CACR,SAAS;CACT,SAAS;CACT,MAAM;CACN,QAAQ;AACV,GAEM,IAA6B,CAAC;AAOpC,SAAwB,EAAa,EACnC,SACA,UACA,WACA,YAAS,UACT,gBACA,SACA,aACA,aACA,UAAO,GACP,WACA,cAAW,IACX,aACA,cACA,GAAG,KACiB;CACpB,IAAM,IAAc,CAAC,CAAC,GAChB,IAAc,OAAO,KAAa,YAAY,OAAO,SAAS,CAAQ,GACtE,IAAM,IAAc,KAAK,MAAM,EAAM,GAAoB,GAAG,CAAC,IAAI,GAAG,IAAI,GACxE,IAAO,MAAW,WAClB,IAAQ,KAAe,EAAa;CAE1C,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,EACT,sBACA,uBAAuB,KACvB,KAAY,gCACZ,KAAe,mCACf,CACF;EACA,MAAM,IAAc,WAAW,KAAA;EAC/B,UAAU,IAAc,IAAI,KAAA;EAC5B,gBAAc,IAAc,IAAW,KAAA;EACvC,SAAS,IAAc,IAAW,EAAK;EACvC,WAAW,KAAe,MAAU;GAC9B,EAAM,WAAW,EAAM,kBACvB,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,eAAe,GAChB,EAAM,UAAQ,IAAW;EAElC,IAAI,KAAA;EAnBN,UAAA;GAqBE,kBAAC,UAAD;IAAQ,WAAU;IAAlB,UAAA;KACG,KAAW,QAAgC,kBAAC,QAAD;MAAM,WAAU;MAA8B,UAAA;KAAa,CAAA;KACvG,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA,CACE,kBAAC,QAAD;OAAM,WAAU;OAA4B,UAAA;MAAW,CAAA,GACtD,KAAU,QAA+B,kBAAC,QAAD;OAAM,WAAU;OAA6B,UAAA;MAAY,CAAA,CAC/F;;KACN,kBAAC,QAAD;MACE,WAAW,EAAG,8BAA8B,+BAA+B,GAAQ;MACnF,MAAK;MACL,aAAU;MAHZ,UAAA,CAKE,kBAAC,QAAD;OAAM,WAAW,EAAG,2BAA2B,KAAQ,+BAA+B;OAAG,eAAY;MAAQ,CAAA,GAC5G,CACG;;IACA;;GAEP,KAAS,QAA8B,kBAAC,OAAD;IAAK,WAAU;IAA4B,UAAA;GAAU,CAAA;GAE5F,KAAa,QACZ,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KAAM,WAAU;KAAmC,eAAY;IAAQ,CAAA,GACvE,kBAAC,QAAD;KAAM,WAAU;KAAqC,UAAA;IAAe,CAAA,CACjE;;GAGN,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,QAAD;KACE,WAAU;KACV,MAAK;KACL,iBAAe;KACf,iBAAe;KACf,iBAAe;KAEf,UAAA,kBAAC,QAAD;MAAM,WAAU;MAA2B,OAAO,EAAE,OAAO,GAAG,EAAI,GAAG;KAAI,CAAA;IACrE,CAAA,GACN,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CAA2C,GAAI,GAAO;IACnD,CAAA,CAAA;;GAGN,EAAK,SAAS,KACb,kBAAC,MAAD;IAAI,WAAU;IACX,UAAA,EAAK,KAAK,GAAM,MACf,kBAAC,OAAD,EAAA,UAAA,CACG,EAAK,UAAU,QAAQ,EAAK,UAAU,KAAA,KAAa,kBAAC,MAAD,EAAA,UAAK,EAAK,MAAU,CAAA,GACxE,kBAAC,MAAD,EAAA,UAAK,EAAK,MAAU,CAAA,CACjB,EAAA,GAHK,EAAK,UAAU,QAAQ,EAAK,UAAU,KAAA,IAAY,GAAG,OAAO,EAAK,KAAK,EAAE,GAAG,MAAU,QAAQ,GAGlG,CACN;GACC,CAAA;GAGL,KAAW,QAAgC,kBAAC,OAAD;IAAK,WAAU;IAA8B,UAAA;GAAY,CAAA;EAClG;;AAET"}
1
+ {"version":3,"file":"index.js","names":["STATUS_LABEL","EMPTY_META","AgentRunCard","rest","interactive","onSelect","hasProgress","progress","pct","clamp","live","status","label","statusLabel","cn","selected","className","event","avatar","name","model","task","activity","meta","item","index","footer"],"sources":["../../../../src/components/ai/AgentRunCard/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport { clamp } from '../shared';\nimport './AgentRunCard.css';\n\nexport type AgentRunStatus = 'queued' | 'running' | 'waiting' | 'done' | 'failed';\n\nexport type AgentRunMeta = {\n label?: React.ReactNode;\n value: React.ReactNode;\n};\n\nexport type AgentRunCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onSelect'> & {\n /** Agent name (e.g. `Sol`). */\n name: React.ReactNode;\n /** Model or engine label shown beside the name (e.g. `Opus 5`). */\n model?: React.ReactNode;\n /** Avatar slot, typically an `Avatar` with the agent's initials. */\n avatar?: React.ReactNode;\n /** Run status; drives the trailing badge tone and progress colour. */\n status?: AgentRunStatus;\n /** Explicit status label; defaults to a capitalised form of `status`. */\n statusLabel?: React.ReactNode;\n /** The task the agent is working on (single truncating line). */\n task?: React.ReactNode;\n /** Current activity line, prefixed by a status dot. */\n activity?: React.ReactNode;\n /** Progress from 0 to 1. When omitted, the progress row is hidden. */\n progress?: number;\n /** Compact meta values shown in a row (e.g. steps, elapsed, tokens). */\n meta?: AgentRunMeta[];\n /** Monospace footer, typically a branch or path. */\n footer?: React.ReactNode;\n /** Selected state (raised border). */\n selected?: boolean;\n /** Click handler turns the card into a button for keyboard users. */\n onSelect?: () => void;\n};\n\nconst STATUS_LABEL: Record<AgentRunStatus, string> = {\n queued: 'Queued',\n running: 'Running',\n waiting: 'Waiting',\n done: 'Done',\n failed: 'Failed',\n};\n\nconst EMPTY_META: AgentRunMeta[] = [];\n\n/**\n * Agent run card: avatar + name + model, a status badge, the task, a current\n * activity line, an optional progress bar with percentage, a compact meta row\n * (steps / elapsed / tokens) and a monospace footer (branch or path).\n */\nexport default function AgentRunCard({\n name,\n model,\n avatar,\n status = 'queued',\n statusLabel,\n task,\n activity,\n progress,\n meta = EMPTY_META,\n footer,\n selected = false,\n onSelect,\n className,\n ...rest\n}: AgentRunCardProps) {\n const interactive = !!onSelect;\n const hasProgress = typeof progress === 'number' && Number.isFinite(progress);\n const pct = hasProgress ? Math.round(clamp(progress as number, 0, 1) * 100) : 0;\n const live = status === 'running';\n const label = statusLabel ?? STATUS_LABEL[status];\n\n return (\n <div\n {...rest}\n className={cn(\n 'dishui-ai-run-card',\n `dishui-ai-run-card--${status}`,\n selected && 'dishui-ai-run-card--selected',\n interactive && 'dishui-ai-run-card--interactive',\n className,\n )}\n role={interactive ? 'button' : undefined}\n tabIndex={interactive ? 0 : undefined}\n aria-pressed={interactive ? selected : undefined}\n onClick={interactive ? onSelect : rest.onClick}\n onKeyDown={interactive ? (event) => {\n if (event.target !== event.currentTarget) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n if (!event.repeat) onSelect?.();\n }\n } : undefined}\n >\n <header className=\"dishui-ai-run-card__header\">\n {avatar !== null && avatar !== undefined && <span className=\"dishui-ai-run-card__avatar\">{avatar}</span>}\n <span className=\"dishui-ai-run-card__identity\">\n <span className=\"dishui-ai-run-card__name\">{name}</span>\n {model !== null && model !== undefined && <span className=\"dishui-ai-run-card__model\">{model}</span>}\n </span>\n <span\n className={cn('dishui-ai-run-card__status', `dishui-ai-run-card__status--${status}`)}\n role=\"status\"\n aria-live=\"polite\"\n >\n <span className={cn('dishui-ai-run-card__dot', live && 'dishui-ai-run-card__dot--live')} aria-hidden=\"true\" />\n {label}\n </span>\n </header>\n\n {task !== null && task !== undefined && <div className=\"dishui-ai-run-card__task\">{task}</div>}\n\n {activity !== null && activity !== undefined && (\n <div className=\"dishui-ai-run-card__activity\">\n <span className=\"dishui-ai-run-card__activity-dot\" aria-hidden=\"true\" />\n <span className=\"dishui-ai-run-card__activity-text\">{activity}</span>\n </div>\n )}\n\n {hasProgress && (\n <div className=\"dishui-ai-run-card__progress\">\n <span\n className=\"dishui-ai-run-card__track\"\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={pct}\n >\n <span className=\"dishui-ai-run-card__fill\" style={{ width: `${pct}%` }} />\n </span>\n <span className=\"dishui-ai-run-card__pct\">{pct}%</span>\n </div>\n )}\n\n {meta.length > 0 && (\n <dl className=\"dishui-ai-run-card__meta\">\n {meta.map((item, index) => (\n <div key={item.label !== null && item.label !== undefined ? `${String(item.label)}-${index}` : `meta-${index}`}>\n {item.label !== null && item.label !== undefined && <dt>{item.label}</dt>}\n <dd>{item.value}</dd>\n </div>\n ))}\n </dl>\n )}\n\n {footer !== null && footer !== undefined && <div className=\"dishui-ai-run-card__footer\">{footer}</div>}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/AgentScreen/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport { formatElapsed } from '../shared';\nimport Resizable from '../../Resizable';\nimport './AgentScreen.css';\n\nexport type AgentScreenStatus = 'idle' | 'loading' | 'working' | 'paused' | 'recording';\n\nexport type AgentScreenLabels = {\n open?: string;\n teach?: string;\n record?: string;\n stopRecording?: string;\n pause?: string;\n resume?: string;\n status?: Partial<Record<AgentScreenStatus, string>>;\n};\n\nexport type AgentScreenProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title'> & {\n status: AgentScreenStatus;\n title?: React.ReactNode;\n /** Shown in a faux address bar and opened by the default Open action. */\n url?: string;\n /** Screen content (`<img>`, `<iframe>`, any node). Absent → skeleton blocks. */\n children?: React.ReactNode;\n /** Defaults to opening `url` in a new tab when `url` is given. */\n onOpen?: () => void;\n onTeach?: () => void;\n /** Toggles recording; the label flips to Stop while `status === 'recording'`. */\n onRecord?: () => void;\n onPause?: () => void;\n onResume?: () => void;\n elapsedMs?: number;\n /** CSS `aspect-ratio` of the screen area. */\n aspectRatio?: string;\n /** Optional secondary panel shown beside or below the screen. */\n secondary?: React.ReactNode;\n /** Split direction when `secondary` is present. */\n split?: 'horizontal' | 'vertical';\n /** Initial panel percentages; must sum to 100. */\n defaultSplitSizes?: [number, number];\n /** Controlled panel percentages; must sum to 100. */\n splitSizes?: [number, number];\n onSplitSizesChange?: (sizes: number[]) => void;\n onSplitSizesCommit?: (sizes: number[]) => void;\n /** Minimum percentage for the primary screen and secondary panel. */\n minPanelSizes?: [number, number];\n /** Resize handle presentation from the shared Resizable component. */\n resizeHandleVariant?: 'line' | 'pill';\n labels?: AgentScreenLabels;\n};\n\nconst DEFAULT_SPLIT_SIZES: [number, number] = [68, 32];\nconst DEFAULT_MIN_PANEL_SIZES: [number, number] = [30, 20];\n\nconst DEFAULT_LABELS = {\n open: 'Open',\n teach: 'Teach a task',\n record: 'Record',\n stopRecording: 'Stop recording',\n pause: 'Pause',\n resume: 'Resume',\n};\n\nconst STATUS_LABEL: Record<AgentScreenStatus, string> = {\n idle: 'Idle',\n loading: 'Loading',\n working: 'Working',\n paused: 'Paused',\n recording: 'Recording',\n};\n\nconst STATUS_TONE: Record<AgentScreenStatus, string> = {\n idle: 'neutral',\n loading: 'neutral',\n working: 'info',\n paused: 'warning',\n recording: 'danger',\n};\n\nconst Icon: React.FC<{ children: React.ReactNode }> = ({ children }) => (\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 {children}\n </svg>\n);\n\nconst ExternalIcon: React.FC = () => (\n <Icon>\n <path d=\"M15 3h6v6\" />\n <path d=\"M10 14 21 3\" />\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n </Icon>\n);\nconst TeachIcon: React.FC = () => (\n <Icon>\n <path d=\"M12 20h9\" />\n <path d=\"M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z\" />\n </Icon>\n);\nconst RecordIcon: React.FC = () => (\n <Icon>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" fill=\"currentColor\" stroke=\"none\" />\n </Icon>\n);\nconst StopIcon: React.FC = () => (\n <Icon>\n <rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"1.5\" />\n </Icon>\n);\nconst PauseIcon: React.FC = () => (\n <Icon>\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n </Icon>\n);\nconst PlayIcon: React.FC = () => (\n <Icon>\n <path d=\"m7 5 12 7-12 7Z\" />\n </Icon>\n);\n\nconst Placeholder: React.FC = () => (\n <div className=\"dishui-ai-agent-screen__placeholder\" aria-hidden=\"true\">\n <span className=\"dishui-ai-agent-screen__block dishui-ai-agent-screen__block--wide\" />\n <span className=\"dishui-ai-agent-screen__block\" />\n <span className=\"dishui-ai-agent-screen__block\" />\n <span className=\"dishui-ai-agent-screen__block dishui-ai-agent-screen__block--tall\" />\n <span className=\"dishui-ai-agent-screen__block dishui-ai-agent-screen__block--wide\" />\n <span className=\"dishui-ai-agent-screen__block\" />\n </div>\n);\n\nconst ScreenSurface = ({\n status,\n statusLabel,\n recording,\n children,\n}: {\n status: AgentScreenStatus;\n statusLabel: string;\n recording: boolean;\n children?: React.ReactNode;\n}) => (\n <div className=\"dishui-ai-agent-screen__screen\">\n {children ?? <Placeholder />}\n {status === 'loading' && (\n <div className=\"dishui-ai-agent-screen__loading\" role=\"status\" aria-live=\"polite\">\n <span className=\"dishui-ai-agent-screen__spinner\" aria-hidden=\"true\"><span /><span /><span /></span>\n <span>{statusLabel}</span>\n </div>\n )}\n {recording && (\n <span className=\"dishui-ai-agent-screen__rec\">\n <span className=\"dishui-ai-agent-screen__rec-dot\" aria-hidden=\"true\" />\n REC\n </span>\n )}\n </div>\n);\n\n/**\n * Window chrome around an agent's screen: title, text + dot status badge,\n * elapsed time, optional address bar, the screen surface and a footer\n * toolbar with Open / Teach a task / Record / Pause.\n */\nexport default function AgentScreen({\n status,\n title = \"Agent's screen\",\n url,\n children,\n onOpen,\n onTeach,\n onRecord,\n onPause,\n onResume,\n elapsedMs,\n aspectRatio = '16 / 10',\n secondary,\n split = 'horizontal',\n defaultSplitSizes = DEFAULT_SPLIT_SIZES,\n splitSizes,\n onSplitSizesChange,\n onSplitSizesCommit,\n minPanelSizes = DEFAULT_MIN_PANEL_SIZES,\n resizeHandleVariant = 'pill',\n labels,\n className,\n ...rest\n}: AgentScreenProps) {\n const text = { ...DEFAULT_LABELS, ...labels };\n const statusLabel = labels?.status?.[status] ?? STATUS_LABEL[status];\n const recording = status === 'recording';\n const live = status === 'working' || recording;\n\n const handleOpen = () => {\n if (onOpen) onOpen();\n else if (url) window.open(url, '_blank', 'noopener,noreferrer');\n };\n const showOpen = !!onOpen || !!url;\n const showPause = status === 'paused' ? !!onResume : !!onPause && (status === 'working' || recording);\n const showFooter = showOpen || !!onTeach || !!onRecord || showPause;\n\n return (\n <div {...rest} className={cn('dishui-ai-agent-screen', `dishui-ai-agent-screen--${status}`, className)}>\n <div className=\"dishui-ai-agent-screen__chrome\">\n <span className=\"dishui-ai-agent-screen__dots\" aria-hidden=\"true\">\n <span /><span /><span />\n </span>\n <span className=\"dishui-ai-agent-screen__title\">{title}</span>\n <span className={cn('dishui-ai-agent-screen__status', `dishui-ai-agent-screen__status--${STATUS_TONE[status]}`)} role=\"status\" aria-live=\"polite\">\n <span className={cn('dishui-ai-agent-screen__indicator', live && 'dishui-ai-agent-screen__indicator--live')} aria-hidden=\"true\" />\n {statusLabel}\n </span>\n {elapsedMs !== undefined && <span className=\"dishui-ai-agent-screen__elapsed\">{formatElapsed(elapsedMs)}</span>}\n </div>\n\n {url && (\n <div className=\"dishui-ai-agent-screen__address\" title={url}>\n <span className=\"dishui-ai-agent-screen__url\">{url}</span>\n </div>\n )}\n\n <div className=\"dishui-ai-agent-screen__viewport\" style={{ aspectRatio }}>\n {secondary ? (\n <Resizable\n orientation={split}\n defaultSizes={defaultSplitSizes}\n sizes={splitSizes}\n onSizesChange={onSplitSizesChange}\n onSizesCommit={onSplitSizesCommit}\n className=\"dishui-ai-agent-screen__split\"\n >\n <Resizable.Panel minSize={minPanelSizes[0]} className=\"dishui-ai-agent-screen__panel\">\n <ScreenSurface status={status} statusLabel={statusLabel} recording={recording}>{children}</ScreenSurface>\n </Resizable.Panel>\n <Resizable.Handle variant={resizeHandleVariant} aria-label=\"Resize agent screen panels\" />\n <Resizable.Panel minSize={minPanelSizes[1]} className=\"dishui-ai-agent-screen__panel dishui-ai-agent-screen__panel--secondary\">\n {secondary}\n </Resizable.Panel>\n </Resizable>\n ) : (\n <ScreenSurface status={status} statusLabel={statusLabel} recording={recording}>{children}</ScreenSurface>\n )}\n </div>\n\n {showFooter && (\n <div className=\"dishui-ai-agent-screen__footer\">\n {showOpen && (\n <button type=\"button\" className=\"dishui-ai-agent-screen__action\" onClick={handleOpen}>\n <ExternalIcon />\n {text.open}\n </button>\n )}\n {onTeach && (\n <button type=\"button\" className=\"dishui-ai-agent-screen__action\" onClick={onTeach}>\n <TeachIcon />\n {text.teach}\n </button>\n )}\n <span className=\"dishui-ai-agent-screen__spacer\" />\n {showPause && (\n <button\n type=\"button\"\n className=\"dishui-ai-agent-screen__action\"\n onClick={status === 'paused' ? onResume : onPause}\n >\n {status === 'paused' ? <PlayIcon /> : <PauseIcon />}\n {status === 'paused' ? text.resume : text.pause}\n </button>\n )}\n {onRecord && (\n <button\n type=\"button\"\n className={cn('dishui-ai-agent-screen__action', recording && 'dishui-ai-agent-screen__action--recording')}\n aria-pressed={recording}\n onClick={onRecord}\n >\n {recording ? <StopIcon /> : <RecordIcon />}\n {recording ? text.stopRecording : text.record}\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["DEFAULT_SPLIT_SIZES","DEFAULT_MIN_PANEL_SIZES","DEFAULT_LABELS","STATUS_LABEL","STATUS_TONE","Icon","ExternalIcon","TeachIcon","RecordIcon","StopIcon","PauseIcon","PlayIcon","Placeholder","ScreenSurface","children","status","statusLabel","recording","AgentScreen","rest","text","labels","live","handleOpen","onOpen","url","showOpen","showPause","onResume","onPause","showFooter","onTeach","onRecord","cn","className","title","elapsedMs","formatElapsed","secondary","Resizable","split","defaultSplitSizes","splitSizes","onSplitSizesChange","onSplitSizesCommit","minPanelSizes","resizeHandleVariant","jsx"],"sources":["../../../../src/components/ai/AgentScreen/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport { formatElapsed } from '../shared';\nimport Resizable from '../../Resizable';\nimport './AgentScreen.css';\n\nexport type AgentScreenStatus = 'idle' | 'loading' | 'working' | 'paused' | 'recording';\n\nexport type AgentScreenLabels = {\n open?: string;\n teach?: string;\n record?: string;\n stopRecording?: string;\n pause?: string;\n resume?: string;\n status?: Partial<Record<AgentScreenStatus, string>>;\n};\n\nexport type AgentScreenProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title'> & {\n status: AgentScreenStatus;\n title?: React.ReactNode;\n /** Shown in a faux address bar and opened by the default Open action. */\n url?: string;\n /** Screen content (`<img>`, `<iframe>`, any node). Absent → skeleton blocks. */\n children?: React.ReactNode;\n /** Defaults to opening `url` in a new tab when `url` is given. */\n onOpen?: () => void;\n onTeach?: () => void;\n /** Toggles recording; the label flips to Stop while `status === 'recording'`. */\n onRecord?: () => void;\n onPause?: () => void;\n onResume?: () => void;\n elapsedMs?: number;\n /** CSS `aspect-ratio` of the screen area. */\n aspectRatio?: string;\n /** Optional secondary panel shown beside or below the screen. */\n secondary?: React.ReactNode;\n /** Split direction when `secondary` is present. */\n split?: 'horizontal' | 'vertical';\n /** Initial panel percentages; must sum to 100. */\n defaultSplitSizes?: [number, number];\n /** Controlled panel percentages; must sum to 100. */\n splitSizes?: [number, number];\n onSplitSizesChange?: (sizes: number[]) => void;\n onSplitSizesCommit?: (sizes: number[]) => void;\n /** Minimum percentage for the primary screen and secondary panel. */\n minPanelSizes?: [number, number];\n /** Resize handle presentation from the shared Resizable component. */\n resizeHandleVariant?: 'line' | 'pill';\n labels?: AgentScreenLabels;\n};\n\nconst DEFAULT_SPLIT_SIZES: [number, number] = [68, 32];\nconst DEFAULT_MIN_PANEL_SIZES: [number, number] = [30, 20];\n\nconst DEFAULT_LABELS = {\n open: 'Open',\n teach: 'Teach a task',\n record: 'Record',\n stopRecording: 'Stop recording',\n pause: 'Pause',\n resume: 'Resume',\n};\n\nconst STATUS_LABEL: Record<AgentScreenStatus, string> = {\n idle: 'Idle',\n loading: 'Loading',\n working: 'Working',\n paused: 'Paused',\n recording: 'Recording',\n};\n\nconst STATUS_TONE: Record<AgentScreenStatus, string> = {\n idle: 'neutral',\n loading: 'neutral',\n working: 'info',\n paused: 'warning',\n recording: 'danger',\n};\n\nconst Icon: React.FC<{ children: React.ReactNode }> = ({ children }) => (\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 {children}\n </svg>\n);\n\nconst ExternalIcon: React.FC = () => (\n <Icon>\n <path d=\"M15 3h6v6\" />\n <path d=\"M10 14 21 3\" />\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n </Icon>\n);\nconst TeachIcon: React.FC = () => (\n <Icon>\n <path d=\"M12 20h9\" />\n <path d=\"M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4Z\" />\n </Icon>\n);\nconst RecordIcon: React.FC = () => (\n <Icon>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" fill=\"currentColor\" stroke=\"none\" />\n </Icon>\n);\nconst StopIcon: React.FC = () => (\n <Icon>\n <rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"1.5\" />\n </Icon>\n);\nconst PauseIcon: React.FC = () => (\n <Icon>\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" />\n </Icon>\n);\nconst PlayIcon: React.FC = () => (\n <Icon>\n <path d=\"m7 5 12 7-12 7Z\" />\n </Icon>\n);\n\nconst Placeholder: React.FC = () => (\n <div className=\"dishui-ai-agent-screen__placeholder\" aria-hidden=\"true\">\n <span className=\"dishui-ai-agent-screen__block dishui-ai-agent-screen__block--wide\" />\n <span className=\"dishui-ai-agent-screen__block\" />\n <span className=\"dishui-ai-agent-screen__block\" />\n <span className=\"dishui-ai-agent-screen__block dishui-ai-agent-screen__block--tall\" />\n <span className=\"dishui-ai-agent-screen__block dishui-ai-agent-screen__block--wide\" />\n <span className=\"dishui-ai-agent-screen__block\" />\n </div>\n);\n\nconst ScreenSurface = ({\n status,\n statusLabel,\n recording,\n children,\n}: {\n status: AgentScreenStatus;\n statusLabel: string;\n recording: boolean;\n children?: React.ReactNode;\n}) => (\n <div className=\"dishui-ai-agent-screen__screen\">\n {children ?? <Placeholder />}\n {status === 'loading' && (\n <div className=\"dishui-ai-agent-screen__loading\" role=\"status\" aria-live=\"polite\">\n <span className=\"dishui-ai-agent-screen__spinner\" aria-hidden=\"true\"><span /><span /><span /></span>\n <span>{statusLabel}</span>\n </div>\n )}\n {recording && (\n <span className=\"dishui-ai-agent-screen__rec\">\n <span className=\"dishui-ai-agent-screen__rec-dot\" aria-hidden=\"true\" />\n REC\n </span>\n )}\n </div>\n);\n\n/**\n * Window chrome around an agent's screen: title, text + dot status badge,\n * elapsed time, optional address bar, the screen surface and a footer\n * toolbar with Open / Teach a task / Record / Pause.\n */\nexport default function AgentScreen({\n status,\n title = \"Agent's screen\",\n url,\n children,\n onOpen,\n onTeach,\n onRecord,\n onPause,\n onResume,\n elapsedMs,\n aspectRatio = '16 / 10',\n secondary,\n split = 'horizontal',\n defaultSplitSizes = DEFAULT_SPLIT_SIZES,\n splitSizes,\n onSplitSizesChange,\n onSplitSizesCommit,\n minPanelSizes = DEFAULT_MIN_PANEL_SIZES,\n resizeHandleVariant = 'pill',\n labels,\n className,\n ...rest\n}: AgentScreenProps) {\n const text = { ...DEFAULT_LABELS, ...labels };\n const statusLabel = labels?.status?.[status] ?? STATUS_LABEL[status];\n const recording = status === 'recording';\n const live = status === 'working' || recording;\n\n const handleOpen = () => {\n if (onOpen) onOpen();\n else if (url) window.open(url, '_blank', 'noopener,noreferrer');\n };\n const showOpen = !!onOpen || !!url;\n const showPause = status === 'paused' ? !!onResume : !!onPause && (status === 'working' || recording);\n const showFooter = showOpen || !!onTeach || !!onRecord || showPause;\n\n return (\n <div {...rest} className={cn('dishui-ai-agent-screen', `dishui-ai-agent-screen--${status}`, className)}>\n <div className=\"dishui-ai-agent-screen__chrome\">\n <span className=\"dishui-ai-agent-screen__dots\" aria-hidden=\"true\">\n <span /><span /><span />\n </span>\n <span className=\"dishui-ai-agent-screen__title\">{title}</span>\n <span className={cn('dishui-ai-agent-screen__status', `dishui-ai-agent-screen__status--${STATUS_TONE[status]}`)} role=\"status\" aria-live=\"polite\">\n <span className={cn('dishui-ai-agent-screen__indicator', live && 'dishui-ai-agent-screen__indicator--live')} aria-hidden=\"true\" />\n {statusLabel}\n </span>\n {elapsedMs !== undefined && <span className=\"dishui-ai-agent-screen__elapsed\">{formatElapsed(elapsedMs)}</span>}\n </div>\n\n {url && (\n <div className=\"dishui-ai-agent-screen__address\" title={url}>\n <span className=\"dishui-ai-agent-screen__url\">{url}</span>\n </div>\n )}\n\n <div className=\"dishui-ai-agent-screen__viewport\" style={{ aspectRatio }}>\n {secondary ? (\n <Resizable\n orientation={split}\n defaultSizes={defaultSplitSizes}\n sizes={splitSizes}\n onSizesChange={onSplitSizesChange}\n onSizesCommit={onSplitSizesCommit}\n className=\"dishui-ai-agent-screen__split\"\n >\n <Resizable.Panel minSize={minPanelSizes[0]} className=\"dishui-ai-agent-screen__panel\">\n <ScreenSurface status={status} statusLabel={statusLabel} recording={recording}>{children}</ScreenSurface>\n </Resizable.Panel>\n <Resizable.Handle variant={resizeHandleVariant} aria-label=\"Resize agent screen panels\" />\n <Resizable.Panel minSize={minPanelSizes[1]} className=\"dishui-ai-agent-screen__panel dishui-ai-agent-screen__panel--secondary\">\n {secondary}\n </Resizable.Panel>\n </Resizable>\n ) : (\n <ScreenSurface status={status} statusLabel={statusLabel} recording={recording}>{children}</ScreenSurface>\n )}\n </div>\n\n {showFooter && (\n <div className=\"dishui-ai-agent-screen__footer\">\n {showOpen && (\n <button type=\"button\" className=\"dishui-ai-agent-screen__action\" onClick={handleOpen}>\n <ExternalIcon />\n {text.open}\n </button>\n )}\n {onTeach && (\n <button type=\"button\" className=\"dishui-ai-agent-screen__action\" onClick={onTeach}>\n <TeachIcon />\n {text.teach}\n </button>\n )}\n <span className=\"dishui-ai-agent-screen__spacer\" />\n {showPause && (\n <button\n type=\"button\"\n className=\"dishui-ai-agent-screen__action\"\n onClick={status === 'paused' ? onResume : onPause}\n >\n {status === 'paused' ? <PlayIcon /> : <PauseIcon />}\n {status === 'paused' ? text.resume : text.pause}\n </button>\n )}\n {onRecord && (\n <button\n type=\"button\"\n className={cn('dishui-ai-agent-screen__action', recording && 'dishui-ai-agent-screen__action--recording')}\n aria-pressed={recording}\n onClick={onRecord}\n >\n {recording ? <StopIcon /> : <RecordIcon />}\n {recording ? text.stopRecording : text.record}\n </button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/ApprovalCard/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport Button from '../../Button';\nimport './ApprovalCard.css';\n\nconst EMPTY_OPTIONS: ApprovalOption[] = [];\n\nexport type ApprovalOption = { id: string; label: React.ReactNode; description?: React.ReactNode; disabled?: boolean; disabledReason?: string };\nexport type ApprovalCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onChange'> & {\n title: React.ReactNode; description?: React.ReactNode; options?: ApprovalOption[];\n value?: string; defaultValue?: string; onChange?: (value: string) => void;\n onApprove?: (value?: string) => void; onReject?: () => void; busy?: boolean; disabled?: boolean;\n labels?: { approve?: string; reject?: string; required?: string };\n};\n\nexport default function ApprovalCard({ title, description, options = EMPTY_OPTIONS, value, defaultValue, onChange, onApprove, onReject, busy = false, disabled = false, labels, className, ...rest }: ApprovalCardProps) {\n const uid = useId();\n const [internal, setInternal] = useState(defaultValue);\n const selected = value ?? internal;\n const required = options.length > 0 && !selected;\n const choose = (id: string) => { if (value === undefined) setInternal(id); onChange?.(id); };\n return <section {...rest} className={cn('dishui-ai-approval-card', className)} aria-labelledby={`${uid}-title`}>\n <div className=\"dishui-ai-approval-card__head\"><span className=\"dishui-ai-approval-card__badge\">Approval required</span><h3 id={`${uid}-title`}>{title}</h3>{description && <div className=\"dishui-ai-approval-card__description\">{description}</div>}</div>\n {options.length > 0 && <div className=\"dishui-ai-approval-card__options\" role=\"radiogroup\" aria-label=\"Approval options\">{options.map(option => <button key={option.id} type=\"button\" role=\"radio\" aria-checked={selected === option.id} disabled={disabled || busy || option.disabled} title={option.disabledReason} className={cn('dishui-ai-approval-card__option', selected === option.id && 'dishui-ai-approval-card__option--selected')} onClick={() => choose(option.id)}><span className=\"dishui-ai-approval-card__radio\" aria-hidden=\"true\"/><span><strong>{option.label}</strong>{option.description && <small>{option.description}</small>}{option.disabled && option.disabledReason && <small>{option.disabledReason}</small>}</span></button>)}</div>}\n <div className=\"dishui-ai-approval-card__actions\">{required && <span role=\"status\">{labels?.required ?? 'Choose an option to continue'}</span>}<span className=\"dishui-ai-approval-card__spacer\"/>{onReject && <Button type=\"button\" size=\"sm\" variant=\"secondary\" disabled={disabled || busy} onClick={onReject}>{labels?.reject ?? 'Reject'}</Button>}{onApprove && <Button type=\"button\" size=\"sm\" variant=\"primary\" disabled={disabled || busy || required} aria-busy={busy || undefined} onClick={() => onApprove(selected)}>{labels?.approve ?? 'Approve'}</Button>}</div>\n </section>;\n}\n"],"mappings":";;;;;;AAKA,IAAM,IAAkC,CAAC;AAUzC,SAAwB,EAAa,EAAE,UAAO,gBAAa,aAAU,GAAe,UAAO,iBAAc,aAAU,cAAW,aAAU,UAAO,IAAO,cAAW,IAAO,WAAQ,cAAW,GAAG,KAA2B;CACvN,IAAM,IAAM,EAAM,GACZ,CAAC,GAAU,KAAe,EAAS,CAAY,GAC/C,IAAW,KAAS,GACpB,IAAW,EAAQ,SAAS,KAAK,CAAC,GAClC,KAAU,MAAe;EAA4C,AAAtC,MAAU,KAAA,KAAW,EAAY,CAAE,GAAG,IAAW,CAAE;CAAG;CAC3F,OAAO,kBAAC,WAAD;EAAS,GAAI;EAAM,WAAW,EAAG,2BAA2B,CAAS;EAAG,mBAAiB,GAAG,EAAI;EAAhG,UAAA;GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KAA+C,kBAAC,QAAD;MAAM,WAAU;MAAiC,UAAA;KAAuB,CAAA;KAAC,kBAAC,MAAD;MAAI,IAAI,GAAG,EAAI;MAAU,UAAA;KAAU,CAAA;KAAE,KAAe,kBAAC,OAAD;MAAK,WAAU;MAAwC,UAAA;KAAiB,CAAA;IAAO;;GAC1P,EAAQ,SAAS,KAAK,kBAAC,OAAD;IAAK,WAAU;IAAmC,MAAK;IAAa,cAAW;IAAoB,UAAA,EAAQ,KAAI,MAAU,kBAAC,UAAD;KAAwB,MAAK;KAAS,MAAK;KAAQ,gBAAc,MAAa,EAAO;KAAI,UAAU,KAAY,KAAQ,EAAO;KAAU,OAAO,EAAO;KAAgB,WAAW,EAAG,mCAAmC,MAAa,EAAO,MAAM,2CAA2C;KAAG,eAAe,EAAO,EAAO,EAAE;KAA9T,UAAA,CAAiU,kBAAC,QAAD;MAAM,WAAU;MAAiC,eAAY;KAAO,CAAA,GAAC,kBAAC,QAAD,EAAA,UAAA;MAAM,kBAAC,UAAD,EAAA,UAAS,EAAO,MAAc,CAAA;MAAE,EAAO,eAAe,kBAAC,SAAD,EAAA,UAAQ,EAAO,YAAmB,CAAA;MAAG,EAAO,YAAY,EAAO,kBAAkB,kBAAC,SAAD,EAAA,UAAQ,EAAO,eAAsB,CAAA;KAAQ,EAAA,CAAA,CAAS;IAA5jB,GAAA,EAAO,EAAqjB,CAAC;GAAO,CAAA;GACjuB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KAAmD,KAAY,kBAAC,QAAD;MAAM,MAAK;MAAU,UAAA,GAAQ,YAAY;KAAqC,CAAA;KAAE,kBAAC,QAAD,EAAM,WAAU,kCAAkC,CAAA;KAAE,KAAY,kBAAC,GAAD;MAAQ,MAAK;MAAS,MAAK;MAAK,SAAQ;MAAY,UAAU,KAAY;MAAM,SAAS;MAAW,UAAA,GAAQ,UAAU;KAAiB,CAAA;KAAG,KAAa,kBAAC,GAAD;MAAQ,MAAK;MAAS,MAAK;MAAK,SAAQ;MAAU,UAAU,KAAY,KAAQ;MAAU,aAAW,KAAQ,KAAA;MAAW,eAAe,EAAU,CAAQ;MAAI,UAAA,GAAQ,WAAW;KAAkB,CAAA;IAAO;;EACxiB;;AACX"}
1
+ {"version":3,"file":"index.js","names":["Button","ButtonWithCompounds","EMPTY_OPTIONS","ApprovalCard","rest","uid","useId","internal","setInternal","useState","defaultValue","selected","value","required","options","choose","id","onChange","cn","className","title","description","option","disabled","busy","labels","onReject","onApprove"],"sources":["../../../../src/components/ai/ApprovalCard/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport Button from '../../Button';\nimport './ApprovalCard.css';\n\nconst EMPTY_OPTIONS: ApprovalOption[] = [];\n\nexport type ApprovalOption = { id: string; label: React.ReactNode; description?: React.ReactNode; disabled?: boolean; disabledReason?: string };\nexport type ApprovalCardProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title' | 'onChange'> & {\n title: React.ReactNode; description?: React.ReactNode; options?: ApprovalOption[];\n value?: string; defaultValue?: string; onChange?: (value: string) => void;\n onApprove?: (value?: string) => void; onReject?: () => void; busy?: boolean; disabled?: boolean;\n labels?: { approve?: string; reject?: string; required?: string };\n};\n\nexport default function ApprovalCard({ title, description, options = EMPTY_OPTIONS, value, defaultValue, onChange, onApprove, onReject, busy = false, disabled = false, labels, className, ...rest }: ApprovalCardProps) {\n const uid = useId();\n const [internal, setInternal] = useState(defaultValue);\n const selected = value ?? internal;\n const required = options.length > 0 && !selected;\n const choose = (id: string) => { if (value === undefined) setInternal(id); onChange?.(id); };\n return <section {...rest} className={cn('dishui-ai-approval-card', className)} aria-labelledby={`${uid}-title`}>\n <div className=\"dishui-ai-approval-card__head\"><span className=\"dishui-ai-approval-card__badge\">Approval required</span><h3 id={`${uid}-title`}>{title}</h3>{description && <div className=\"dishui-ai-approval-card__description\">{description}</div>}</div>\n {options.length > 0 && <div className=\"dishui-ai-approval-card__options\" role=\"radiogroup\" aria-label=\"Approval options\">{options.map(option => <button key={option.id} type=\"button\" role=\"radio\" aria-checked={selected === option.id} disabled={disabled || busy || option.disabled} title={option.disabledReason} className={cn('dishui-ai-approval-card__option', selected === option.id && 'dishui-ai-approval-card__option--selected')} onClick={() => choose(option.id)}><span className=\"dishui-ai-approval-card__radio\" aria-hidden=\"true\"/><span><strong>{option.label}</strong>{option.description && <small>{option.description}</small>}{option.disabled && option.disabledReason && <small>{option.disabledReason}</small>}</span></button>)}</div>}\n <div className=\"dishui-ai-approval-card__actions\">{required && <span role=\"status\">{labels?.required ?? 'Choose an option to continue'}</span>}<span className=\"dishui-ai-approval-card__spacer\"/>{onReject && <Button type=\"button\" size=\"sm\" variant=\"secondary\" disabled={disabled || busy} onClick={onReject}>{labels?.reject ?? 'Reject'}</Button>}{onApprove && <Button type=\"button\" size=\"sm\" variant=\"primary\" disabled={disabled || busy || required} aria-busy={busy || undefined} onClick={() => onApprove(selected)}>{labels?.approve ?? 'Approve'}</Button>}</div>\n </section>;\n}\n"],"mappings":";;;;;;AAKA,IAAME,IAAkC,CAAC;AAUzC,SAAwBC,EAAa,EAAE,UAAO,gBAAa,aAAUD,GAAe,UAAO,iBAAc,aAAU,cAAW,aAAU,UAAO,IAAO,cAAW,IAAO,WAAQ,cAAW,GAAGE,KAA2B;CACvN,IAAMC,IAAMC,EAAM,GACZ,CAACC,GAAUC,KAAeC,EAASC,CAAY,GAC/CC,IAAWC,KAASL,GACpBM,IAAWC,EAAQ,SAAS,KAAK,CAACH,GAClCI,KAAU,MAAe;EAA4C,AAAtCH,MAAU,KAAA,KAAWJ,EAAYQ,CAAE,GAAGC,IAAWD,CAAE;CAAG;CAC3F,OAAO,kBAAC,WAAD;EAAS,GAAIZ;EAAM,WAAWc,EAAG,2BAA2BC,CAAS;EAAG,mBAAiB,GAAGd,EAAI;EAAhG,UAAA;GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KAA+C,kBAAC,QAAD;MAAM,WAAU;MAAiC,UAAA;KAAuB,CAAA;KAAC,kBAAC,MAAD;MAAI,IAAI,GAAGA,EAAI;MAAU,UAAAe;KAAU,CAAA;KAAEC,KAAe,kBAAC,OAAD;MAAK,WAAU;MAAwC,UAAAA;KAAiB,CAAA;IAAO;;GAC1PP,EAAQ,SAAS,KAAK,kBAAC,OAAD;IAAK,WAAU;IAAmC,MAAK;IAAa,cAAW;IAAoB,UAAAA,EAAQ,KAAI,MAAU,kBAAC,UAAD;KAAwB,MAAK;KAAS,MAAK;KAAQ,gBAAcH,MAAaW,EAAO;KAAI,UAAUC,KAAYC,KAAQF,EAAO;KAAU,OAAOA,EAAO;KAAgB,WAAWJ,EAAG,mCAAmCP,MAAaW,EAAO,MAAM,2CAA2C;KAAG,eAAeP,EAAOO,EAAO,EAAE;KAA9T,UAAA,CAAiU,kBAAC,QAAD;MAAM,WAAU;MAAiC,eAAY;KAAO,CAAA,GAAC,kBAAC,QAAD,EAAA,UAAA;MAAM,kBAAC,UAAD,EAAA,UAASA,EAAO,MAAc,CAAA;MAAEA,EAAO,eAAe,kBAAC,SAAD,EAAA,UAAQA,EAAO,YAAmB,CAAA;MAAGA,EAAO,YAAYA,EAAO,kBAAkB,kBAAC,SAAD,EAAA,UAAQA,EAAO,eAAsB,CAAA;KAAQ,EAAA,CAAA,CAAS;IAA5jB,GAAAA,EAAO,EAAqjB,CAAC;GAAO,CAAA;GACjuB,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KAAmDT,KAAY,kBAAC,QAAD;MAAM,MAAK;MAAU,UAAAY,GAAQ,YAAY;KAAqC,CAAA;KAAE,kBAAC,QAAD,EAAM,WAAU,kCAAkC,CAAA;KAAEC,KAAY,kBAAC1B,GAAD;MAAQ,MAAK;MAAS,MAAK;MAAK,SAAQ;MAAY,UAAUuB,KAAYC;MAAM,SAASE;MAAW,UAAAD,GAAQ,UAAU;KAAiB,CAAA;KAAGE,KAAa,kBAAC3B,GAAD;MAAQ,MAAK;MAAS,MAAK;MAAK,SAAQ;MAAU,UAAUuB,KAAYC,KAAQX;MAAU,aAAWW,KAAQ,KAAA;MAAW,eAAeG,EAAUhB,CAAQ;MAAI,UAAAc,GAAQ,WAAW;KAAkB,CAAA;IAAO;;EACxiB;;AACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/CodeView/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { cn } from '../../../utils/cn';\nimport './CodeView.css';\n\nexport type CodeViewLabels = {\n copy?: string;\n copied?: string;\n copyFailed?: string;\n expand?: string;\n collapse?: string;\n};\n\nexport type CodeViewProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n code: string;\n /** Prism language name, for example `typescript`, `tsx`, `python` or `json`. */\n language?: string;\n title?: React.ReactNode;\n /** Show a non-selectable line-number gutter. */\n showLineNumbers?: boolean;\n /** Starting value for the first visible line number. */\n startingLineNumber?: number;\n /** Wrap long source lines instead of scrolling horizontally. */\n wrap?: boolean;\n defaultCollapsed?: boolean;\n collapsible?: boolean;\n maxHeight?: string | number;\n onCopy?: (code: string) => void | Promise<void>;\n labels?: CodeViewLabels;\n};\n\nconst syntaxTheme: Record<string, React.CSSProperties> = {\n 'code[class*=\"language-\"]': {\n color: 'var(--dishui-text-primary)',\n background: 'transparent',\n fontFamily: 'var(--dishui-font-mono)',\n fontSize: 'var(--dishui-text-body-sm)',\n lineHeight: 1.65,\n textAlign: 'left',\n whiteSpace: 'pre',\n wordSpacing: 'normal',\n wordBreak: 'normal',\n overflowWrap: 'normal',\n tabSize: 2,\n },\n 'pre[class*=\"language-\"]': {\n color: 'var(--dishui-text-primary)',\n background: 'var(--dishui-surface-canvas)',\n fontFamily: 'var(--dishui-font-mono)',\n fontSize: 'var(--dishui-text-body-sm)',\n lineHeight: 1.65,\n textAlign: 'left',\n whiteSpace: 'pre',\n wordSpacing: 'normal',\n wordBreak: 'normal',\n overflowWrap: 'normal',\n tabSize: 2,\n },\n comment: { color: 'var(--dishui-text-tertiary)', fontStyle: 'italic' },\n prolog: { color: 'var(--dishui-text-tertiary)' },\n doctype: { color: 'var(--dishui-text-tertiary)' },\n cdata: { color: 'var(--dishui-text-tertiary)' },\n punctuation: { color: 'var(--dishui-text-secondary)' },\n property: { color: 'var(--dishui-status-danger-fg)' },\n tag: { color: 'var(--dishui-status-danger-fg)' },\n boolean: { color: 'var(--dishui-status-alt-fg)' },\n number: { color: 'var(--dishui-status-alt-fg)' },\n constant: { color: 'var(--dishui-status-alt-fg)' },\n symbol: { color: 'var(--dishui-status-alt-fg)' },\n deleted: { color: 'var(--dishui-status-danger-fg)' },\n selector: { color: 'var(--dishui-status-success-fg)' },\n 'attr-name': { color: 'var(--dishui-status-warning-fg)' },\n string: { color: 'var(--dishui-status-success-fg)' },\n char: { color: 'var(--dishui-status-success-fg)' },\n builtin: { color: 'var(--dishui-status-info-fg)' },\n inserted: { color: 'var(--dishui-status-success-fg)' },\n operator: { color: 'var(--dishui-status-info-fg)' },\n entity: { color: 'var(--dishui-status-warning-fg)' },\n url: { color: 'var(--dishui-status-info-fg)' },\n atrule: { color: 'var(--dishui-status-alt-fg)' },\n 'attr-value': { color: 'var(--dishui-status-success-fg)' },\n keyword: { color: 'var(--dishui-status-alt-fg)', fontWeight: 600 },\n function: { color: 'var(--dishui-status-info-fg)' },\n 'class-name': { color: 'var(--dishui-status-warning-fg)' },\n regex: { color: 'var(--dishui-status-warning-fg)' },\n important: { color: 'var(--dishui-status-danger-fg)', fontWeight: 600 },\n variable: { color: 'var(--dishui-text-primary)' },\n};\n\n/**\n * Read-only highlighted source view. It follows CodeEditor's read-only visual\n * contract while remaining focused on display, copy, collapse and line numbers.\n */\nexport default function CodeView({\n code,\n language = 'text',\n title,\n showLineNumbers = true,\n startingLineNumber = 1,\n wrap = false,\n defaultCollapsed = false,\n collapsible = false,\n maxHeight,\n onCopy,\n labels,\n className,\n ...rest\n}: CodeViewProps) {\n const id = useId();\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n const [copyState, setCopyState] = useState<'idle' | 'copied' | 'failed'>('idle');\n\n const copy = async () => {\n try {\n if (onCopy) await onCopy(code);\n else await navigator.clipboard.writeText(code);\n setCopyState('copied');\n } catch {\n setCopyState('failed');\n }\n };\n\n return (\n <div {...rest} className={cn('dishui-ai-code-view', wrap && 'dishui-ai-code-view--wrap', className)}>\n <div className=\"dishui-ai-code-view__header\">\n <span className=\"dishui-ai-code-view__title\">{title ?? language}</span>\n <span className=\"dishui-ai-code-view__language\">{language}</span>\n <span role=\"status\" className=\"dishui-ai-code-view__copy-state\">\n {copyState === 'copied' ? labels?.copied ?? 'Copied' : copyState === 'failed' ? labels?.copyFailed ?? 'Copy failed' : ''}\n </span>\n {collapsible && (\n <button type=\"button\" aria-expanded={!collapsed} aria-controls={id} onClick={() => setCollapsed(value => !value)}>\n {collapsed ? labels?.expand ?? 'Expand' : labels?.collapse ?? 'Collapse'}\n </button>\n )}\n <button type=\"button\" onClick={() => void copy()}>{labels?.copy ?? 'Copy'}</button>\n </div>\n <div id={id} hidden={collapsed} className=\"dishui-ai-code-view__scroll\" style={{ maxHeight }}>\n <SyntaxHighlighter\n language={language}\n style={syntaxTheme}\n showLineNumbers={showLineNumbers}\n startingLineNumber={startingLineNumber}\n wrapLines\n wrapLongLines={wrap}\n lineNumberStyle={{\n minWidth: '3.5em',\n paddingInlineEnd: '12px',\n marginInlineEnd: '12px',\n borderInlineEnd: '1px solid var(--dishui-border-hairline)',\n color: 'var(--dishui-text-tertiary)',\n fontVariantNumeric: 'tabular-nums',\n userSelect: 'none',\n }}\n customStyle={{ margin: 0, padding: '12px 14px', background: 'var(--dishui-surface-canvas)', overflow: 'visible' }}\n codeTagProps={{ 'aria-label': `${language} code` }}\n >\n {code}\n </SyntaxHighlighter>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["SyntaxHighlighter","syntaxTheme","CodeView","rest","id","useId","collapsed","setCollapsed","useState","defaultCollapsed","copyState","setCopyState","copy","onCopy","code","cn","wrap","className","title","language","labels","collapsible","value","Prism"],"sources":["../../../../src/components/ai/CodeView/index.tsx"],"sourcesContent":["import React, { useId, useState } from 'react';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { cn } from '../../../utils/cn';\nimport './CodeView.css';\n\nexport type CodeViewLabels = {\n copy?: string;\n copied?: string;\n copyFailed?: string;\n expand?: string;\n collapse?: string;\n};\n\nexport type CodeViewProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {\n code: string;\n /** Prism language name, for example `typescript`, `tsx`, `python` or `json`. */\n language?: string;\n title?: React.ReactNode;\n /** Show a non-selectable line-number gutter. */\n showLineNumbers?: boolean;\n /** Starting value for the first visible line number. */\n startingLineNumber?: number;\n /** Wrap long source lines instead of scrolling horizontally. */\n wrap?: boolean;\n defaultCollapsed?: boolean;\n collapsible?: boolean;\n maxHeight?: string | number;\n onCopy?: (code: string) => void | Promise<void>;\n labels?: CodeViewLabels;\n};\n\nconst syntaxTheme: Record<string, React.CSSProperties> = {\n 'code[class*=\"language-\"]': {\n color: 'var(--dishui-text-primary)',\n background: 'transparent',\n fontFamily: 'var(--dishui-font-mono)',\n fontSize: 'var(--dishui-text-body-sm)',\n lineHeight: 1.65,\n textAlign: 'left',\n whiteSpace: 'pre',\n wordSpacing: 'normal',\n wordBreak: 'normal',\n overflowWrap: 'normal',\n tabSize: 2,\n },\n 'pre[class*=\"language-\"]': {\n color: 'var(--dishui-text-primary)',\n background: 'var(--dishui-surface-canvas)',\n fontFamily: 'var(--dishui-font-mono)',\n fontSize: 'var(--dishui-text-body-sm)',\n lineHeight: 1.65,\n textAlign: 'left',\n whiteSpace: 'pre',\n wordSpacing: 'normal',\n wordBreak: 'normal',\n overflowWrap: 'normal',\n tabSize: 2,\n },\n comment: { color: 'var(--dishui-text-tertiary)', fontStyle: 'italic' },\n prolog: { color: 'var(--dishui-text-tertiary)' },\n doctype: { color: 'var(--dishui-text-tertiary)' },\n cdata: { color: 'var(--dishui-text-tertiary)' },\n punctuation: { color: 'var(--dishui-text-secondary)' },\n property: { color: 'var(--dishui-status-danger-fg)' },\n tag: { color: 'var(--dishui-status-danger-fg)' },\n boolean: { color: 'var(--dishui-status-alt-fg)' },\n number: { color: 'var(--dishui-status-alt-fg)' },\n constant: { color: 'var(--dishui-status-alt-fg)' },\n symbol: { color: 'var(--dishui-status-alt-fg)' },\n deleted: { color: 'var(--dishui-status-danger-fg)' },\n selector: { color: 'var(--dishui-status-success-fg)' },\n 'attr-name': { color: 'var(--dishui-status-warning-fg)' },\n string: { color: 'var(--dishui-status-success-fg)' },\n char: { color: 'var(--dishui-status-success-fg)' },\n builtin: { color: 'var(--dishui-status-info-fg)' },\n inserted: { color: 'var(--dishui-status-success-fg)' },\n operator: { color: 'var(--dishui-status-info-fg)' },\n entity: { color: 'var(--dishui-status-warning-fg)' },\n url: { color: 'var(--dishui-status-info-fg)' },\n atrule: { color: 'var(--dishui-status-alt-fg)' },\n 'attr-value': { color: 'var(--dishui-status-success-fg)' },\n keyword: { color: 'var(--dishui-status-alt-fg)', fontWeight: 600 },\n function: { color: 'var(--dishui-status-info-fg)' },\n 'class-name': { color: 'var(--dishui-status-warning-fg)' },\n regex: { color: 'var(--dishui-status-warning-fg)' },\n important: { color: 'var(--dishui-status-danger-fg)', fontWeight: 600 },\n variable: { color: 'var(--dishui-text-primary)' },\n};\n\n/**\n * Read-only highlighted source view. It follows CodeEditor's read-only visual\n * contract while remaining focused on display, copy, collapse and line numbers.\n */\nexport default function CodeView({\n code,\n language = 'text',\n title,\n showLineNumbers = true,\n startingLineNumber = 1,\n wrap = false,\n defaultCollapsed = false,\n collapsible = false,\n maxHeight,\n onCopy,\n labels,\n className,\n ...rest\n}: CodeViewProps) {\n const id = useId();\n const [collapsed, setCollapsed] = useState(defaultCollapsed);\n const [copyState, setCopyState] = useState<'idle' | 'copied' | 'failed'>('idle');\n\n const copy = async () => {\n try {\n if (onCopy) await onCopy(code);\n else await navigator.clipboard.writeText(code);\n setCopyState('copied');\n } catch {\n setCopyState('failed');\n }\n };\n\n return (\n <div {...rest} className={cn('dishui-ai-code-view', wrap && 'dishui-ai-code-view--wrap', className)}>\n <div className=\"dishui-ai-code-view__header\">\n <span className=\"dishui-ai-code-view__title\">{title ?? language}</span>\n <span className=\"dishui-ai-code-view__language\">{language}</span>\n <span role=\"status\" className=\"dishui-ai-code-view__copy-state\">\n {copyState === 'copied' ? labels?.copied ?? 'Copied' : copyState === 'failed' ? labels?.copyFailed ?? 'Copy failed' : ''}\n </span>\n {collapsible && (\n <button type=\"button\" aria-expanded={!collapsed} aria-controls={id} onClick={() => setCollapsed(value => !value)}>\n {collapsed ? labels?.expand ?? 'Expand' : labels?.collapse ?? 'Collapse'}\n </button>\n )}\n <button type=\"button\" onClick={() => void copy()}>{labels?.copy ?? 'Copy'}</button>\n </div>\n <div id={id} hidden={collapsed} className=\"dishui-ai-code-view__scroll\" style={{ maxHeight }}>\n <SyntaxHighlighter\n language={language}\n style={syntaxTheme}\n showLineNumbers={showLineNumbers}\n startingLineNumber={startingLineNumber}\n wrapLines\n wrapLongLines={wrap}\n lineNumberStyle={{\n minWidth: '3.5em',\n paddingInlineEnd: '12px',\n marginInlineEnd: '12px',\n borderInlineEnd: '1px solid var(--dishui-border-hairline)',\n color: 'var(--dishui-text-tertiary)',\n fontVariantNumeric: 'tabular-nums',\n userSelect: 'none',\n }}\n customStyle={{ margin: 0, padding: '12px 14px', background: 'var(--dishui-surface-canvas)', overflow: 'visible' }}\n codeTagProps={{ 'aria-label': `${language} code` }}\n >\n {code}\n </SyntaxHighlighter>\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/CommandSearch/index.tsx"],"sourcesContent":["import React, { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './CommandSearch.css';\n\nexport type CommandSearchItem = {\n id: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n group?: string;\n keywords?: string[];\n shortcut?: string;\n onSelect?: () => void;\n};\n\nexport type CommandSearchProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onSubmit' | 'children'> & {\n items: CommandSearchItem[];\n query?: string;\n defaultQuery?: string;\n onQueryChange?: (query: string) => void;\n onSelect?: (item: CommandSearchItem) => void;\n /** Enter with nothing highlighted, or on an empty result set. */\n onSubmit?: (query: string) => void;\n placeholder?: string;\n /** Custom predicate; default is a case-insensitive match on label / description / keywords. */\n filter?: (item: CommandSearchItem, query: string) => boolean;\n /** Wrap matched substrings in `<mark>`. */\n highlightMatches?: boolean;\n emptyState?: React.ReactNode | ((query: string) => React.ReactNode);\n maxVisible?: number;\n autoFocus?: boolean;\n /** Renders as an in-page panel (not a modal). */\n inline?: boolean;\n /** Show a small indeterminate indicator in the input. */\n loading?: boolean;\n /** Accessible name for the input. */\n label?: string;\n};\n\nconst SearchIcon = () => (\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 <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n);\nconst ArrowRight = () => (\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=\"M5 12h14\" />\n <path d=\"m12 5 7 7-7 7\" />\n </svg>\n);\n\nfunction defaultFilter(item: CommandSearchItem, query: string): boolean {\n const q = query.trim().toLowerCase();\n if (!q) return true;\n const hay = [item.label, item.description ?? '', ...(item.keywords ?? [])].join(' ').toLowerCase();\n return hay.includes(q);\n}\n\nfunction highlight(text: string, query: string): React.ReactNode {\n const q = query.trim();\n if (!q) return text;\n const idx = text.toLowerCase().indexOf(q.toLowerCase());\n if (idx < 0) return text;\n return (\n <>\n {text.slice(0, idx)}\n <mark className=\"dishui-ai-command-search__mark\">{text.slice(idx, idx + q.length)}</mark>\n {text.slice(idx + q.length)}\n </>\n );\n}\n\n/**\n * Command search: an input over a filtered, grouped listbox with keyboard\n * navigation and an empty state that hands the query to the agent.\n */\nexport default function CommandSearch({\n items,\n query,\n defaultQuery = '',\n onQueryChange,\n onSelect,\n onSubmit,\n placeholder = 'Search or ask…',\n filter = defaultFilter,\n highlightMatches = true,\n emptyState,\n maxVisible,\n autoFocus,\n inline = true,\n loading = false,\n label = 'Search',\n className,\n ...rest\n}: CommandSearchProps) {\n const uid = useId();\n const listId = `${uid}-list`;\n const inputRef = useRef<HTMLInputElement>(null);\n\n const [internalQuery, setInternalQuery] = useState(defaultQuery);\n const q = query ?? internalQuery;\n const [highlighted, setHighlighted] = useState<number>(-1);\n const setQuery = (next: string) => {\n if (query === undefined) setInternalQuery(next);\n onQueryChange?.(next);\n setHighlighted(-1);\n };\n\n const visible = useMemo(() => {\n const matched = items.filter(item => filter(item, q));\n return maxVisible !== undefined ? matched.slice(0, maxVisible) : matched;\n }, [items, filter, q, maxVisible]);\n\n // -1 means \"nothing highlighted\"; clamp in case the result set shrank.\n const activeIndex = highlighted < visible.length ? highlighted : -1;\n\n // Keep the highlighted option in view.\n useEffect(() => {\n if (activeIndex < 0) return;\n const el = document.getElementById(`${uid}-opt-${activeIndex}`);\n el?.scrollIntoView({ block: 'nearest' });\n }, [activeIndex, uid]);\n\n const select = (item: CommandSearchItem) => {\n item.onSelect?.();\n onSelect?.(item);\n };\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n const n = visible.length;\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (n) setHighlighted(i => (i + 1) % n);\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (n) setHighlighted(i => (i <= 0 ? n - 1 : i - 1));\n break;\n case 'Home':\n if (n) { e.preventDefault(); setHighlighted(0); }\n break;\n case 'End':\n if (n) { e.preventDefault(); setHighlighted(n - 1); }\n break;\n case 'Enter':\n e.preventDefault();\n if (activeIndex >= 0 && visible[activeIndex]) select(visible[activeIndex]);\n else onSubmit?.(q);\n break;\n case 'Escape':\n if (q) { e.preventDefault(); setQuery(''); }\n setHighlighted(-1);\n break;\n default:\n }\n };\n\n // Group while preserving first-seen order.\n const groups = useMemo(() => {\n const order: string[] = [];\n const map = new Map<string, { item: CommandSearchItem; index: number }[]>();\n visible.forEach((item, index) => {\n const key = item.group ?? '';\n if (!map.has(key)) { map.set(key, []); order.push(key); }\n map.get(key)!.push({ item, index });\n });\n return order.map(key => ({ key, entries: map.get(key)! }));\n }, [visible]);\n\n const empty = visible.length === 0;\n const activeId = activeIndex >= 0 ? `${uid}-opt-${activeIndex}` : undefined;\n\n return (\n <div {...rest} className={cn('dishui-ai-command-search', inline && 'dishui-ai-command-search--inline', className)}>\n <div className={cn('dishui-ai-command-search__field', loading && 'dishui-ai-command-search__field--loading')}>\n <span className=\"dishui-ai-command-search__glyph\" aria-hidden=\"true\"><SearchIcon /></span>\n <input\n ref={inputRef}\n className=\"dishui-ai-command-search__input\"\n type=\"text\"\n role=\"combobox\"\n aria-label={label}\n aria-expanded={!empty}\n aria-controls={listId}\n aria-activedescendant={activeId}\n aria-autocomplete=\"list\"\n aria-busy={loading || undefined}\n autoComplete=\"off\"\n spellCheck={false}\n autoFocus={autoFocus}\n placeholder={placeholder}\n value={q}\n onChange={e => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {loading && <span className=\"dishui-ai-command-search__spinner\" role=\"status\" aria-label=\"Searching\" />}\n {q && !loading && (\n <button\n type=\"button\"\n className=\"dishui-ai-command-search__clear\"\n aria-label=\"Clear search\"\n onClick={() => { setQuery(''); inputRef.current?.focus(); }}\n >\n ×\n </button>\n )}\n </div>\n\n <ul id={listId} role=\"listbox\" aria-label={label} className=\"dishui-ai-command-search__list\">\n {groups.map(group => (\n <React.Fragment key={group.key || '__default'}>\n {group.key && (\n <li role=\"presentation\" className=\"dishui-ai-command-search__group\">{group.key}</li>\n )}\n {group.entries.map(({ item, index }) => {\n const isActive = index === activeIndex;\n return (\n <li\n key={item.id}\n id={`${uid}-opt-${index}`}\n role=\"option\"\n aria-selected={isActive}\n className={cn('dishui-ai-command-search__option', isActive && 'dishui-ai-command-search__option--active')}\n onMouseMove={() => { if (!isActive) setHighlighted(index); }}\n onMouseDown={e => e.preventDefault()}\n onClick={() => select(item)}\n >\n <span className=\"dishui-ai-command-search__icon\" aria-hidden=\"true\">{item.icon ?? <ArrowRight />}</span>\n <span className=\"dishui-ai-command-search__text\">\n <span className=\"dishui-ai-command-search__label\">{highlightMatches ? highlight(item.label, q) : item.label}</span>\n {item.description && (\n <span className=\"dishui-ai-command-search__description\">\n {highlightMatches ? highlight(item.description, q) : item.description}\n </span>\n )}\n </span>\n {item.shortcut && <kbd className=\"dishui-ai-command-search__shortcut\">{item.shortcut}</kbd>}\n </li>\n );\n })}\n </React.Fragment>\n ))}\n </ul>\n\n {empty && (\n <div className=\"dishui-ai-command-search__empty\" role=\"status\">\n {typeof emptyState === 'function' ? emptyState(q) : emptyState ?? (\n <>\n <p className=\"dishui-ai-command-search__empty-title\">\n {q.trim() ? <>No results for “{q.trim()}”</> : 'Nothing to show'}\n </p>\n <p className=\"dishui-ai-command-search__empty-hint\">\n {onSubmit ? 'Try a different phrase or press Enter to ask the agent' : 'Try a different phrase'}\n </p>\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_Fragment","React","SearchIcon","ArrowRight","defaultFilter","q","query","item","highlight","text","idx","Fragment","CommandSearch","rest","uid","useId","listId","inputRef","useRef","internalQuery","setInternalQuery","useState","defaultQuery","highlighted","setHighlighted","setQuery","next","onQueryChange","visible","useMemo","matched","items","filter","maxVisible","activeIndex","select","onSelect","onKeyDown","n","i","onSubmit","groups","order","map","key","empty","activeId","cn","inline","className","loading","label","group","isActive","index","highlightMatches","emptyState"],"sources":["../../../../src/components/ai/CommandSearch/index.tsx"],"sourcesContent":["import React, { useEffect, useId, useMemo, useRef, useState } from 'react';\nimport { cn } from '../../../utils/cn';\nimport './CommandSearch.css';\n\nexport type CommandSearchItem = {\n id: string;\n label: string;\n description?: string;\n icon?: React.ReactNode;\n group?: string;\n keywords?: string[];\n shortcut?: string;\n onSelect?: () => void;\n};\n\nexport type CommandSearchProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onSubmit' | 'children'> & {\n items: CommandSearchItem[];\n query?: string;\n defaultQuery?: string;\n onQueryChange?: (query: string) => void;\n onSelect?: (item: CommandSearchItem) => void;\n /** Enter with nothing highlighted, or on an empty result set. */\n onSubmit?: (query: string) => void;\n placeholder?: string;\n /** Custom predicate; default is a case-insensitive match on label / description / keywords. */\n filter?: (item: CommandSearchItem, query: string) => boolean;\n /** Wrap matched substrings in `<mark>`. */\n highlightMatches?: boolean;\n emptyState?: React.ReactNode | ((query: string) => React.ReactNode);\n maxVisible?: number;\n autoFocus?: boolean;\n /** Renders as an in-page panel (not a modal). */\n inline?: boolean;\n /** Show a small indeterminate indicator in the input. */\n loading?: boolean;\n /** Accessible name for the input. */\n label?: string;\n};\n\nconst SearchIcon = () => (\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 <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n);\nconst ArrowRight = () => (\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=\"M5 12h14\" />\n <path d=\"m12 5 7 7-7 7\" />\n </svg>\n);\n\nfunction defaultFilter(item: CommandSearchItem, query: string): boolean {\n const q = query.trim().toLowerCase();\n if (!q) return true;\n const hay = [item.label, item.description ?? '', ...(item.keywords ?? [])].join(' ').toLowerCase();\n return hay.includes(q);\n}\n\nfunction highlight(text: string, query: string): React.ReactNode {\n const q = query.trim();\n if (!q) return text;\n const idx = text.toLowerCase().indexOf(q.toLowerCase());\n if (idx < 0) return text;\n return (\n <>\n {text.slice(0, idx)}\n <mark className=\"dishui-ai-command-search__mark\">{text.slice(idx, idx + q.length)}</mark>\n {text.slice(idx + q.length)}\n </>\n );\n}\n\n/**\n * Command search: an input over a filtered, grouped listbox with keyboard\n * navigation and an empty state that hands the query to the agent.\n */\nexport default function CommandSearch({\n items,\n query,\n defaultQuery = '',\n onQueryChange,\n onSelect,\n onSubmit,\n placeholder = 'Search or ask…',\n filter = defaultFilter,\n highlightMatches = true,\n emptyState,\n maxVisible,\n autoFocus,\n inline = true,\n loading = false,\n label = 'Search',\n className,\n ...rest\n}: CommandSearchProps) {\n const uid = useId();\n const listId = `${uid}-list`;\n const inputRef = useRef<HTMLInputElement>(null);\n\n const [internalQuery, setInternalQuery] = useState(defaultQuery);\n const q = query ?? internalQuery;\n const [highlighted, setHighlighted] = useState<number>(-1);\n const setQuery = (next: string) => {\n if (query === undefined) setInternalQuery(next);\n onQueryChange?.(next);\n setHighlighted(-1);\n };\n\n const visible = useMemo(() => {\n const matched = items.filter(item => filter(item, q));\n return maxVisible !== undefined ? matched.slice(0, maxVisible) : matched;\n }, [items, filter, q, maxVisible]);\n\n // -1 means \"nothing highlighted\"; clamp in case the result set shrank.\n const activeIndex = highlighted < visible.length ? highlighted : -1;\n\n // Keep the highlighted option in view.\n useEffect(() => {\n if (activeIndex < 0) return;\n const el = document.getElementById(`${uid}-opt-${activeIndex}`);\n el?.scrollIntoView({ block: 'nearest' });\n }, [activeIndex, uid]);\n\n const select = (item: CommandSearchItem) => {\n item.onSelect?.();\n onSelect?.(item);\n };\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n const n = visible.length;\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (n) setHighlighted(i => (i + 1) % n);\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (n) setHighlighted(i => (i <= 0 ? n - 1 : i - 1));\n break;\n case 'Home':\n if (n) { e.preventDefault(); setHighlighted(0); }\n break;\n case 'End':\n if (n) { e.preventDefault(); setHighlighted(n - 1); }\n break;\n case 'Enter':\n e.preventDefault();\n if (activeIndex >= 0 && visible[activeIndex]) select(visible[activeIndex]);\n else onSubmit?.(q);\n break;\n case 'Escape':\n if (q) { e.preventDefault(); setQuery(''); }\n setHighlighted(-1);\n break;\n default:\n }\n };\n\n // Group while preserving first-seen order.\n const groups = useMemo(() => {\n const order: string[] = [];\n const map = new Map<string, { item: CommandSearchItem; index: number }[]>();\n visible.forEach((item, index) => {\n const key = item.group ?? '';\n if (!map.has(key)) { map.set(key, []); order.push(key); }\n map.get(key)!.push({ item, index });\n });\n return order.map(key => ({ key, entries: map.get(key)! }));\n }, [visible]);\n\n const empty = visible.length === 0;\n const activeId = activeIndex >= 0 ? `${uid}-opt-${activeIndex}` : undefined;\n\n return (\n <div {...rest} className={cn('dishui-ai-command-search', inline && 'dishui-ai-command-search--inline', className)}>\n <div className={cn('dishui-ai-command-search__field', loading && 'dishui-ai-command-search__field--loading')}>\n <span className=\"dishui-ai-command-search__glyph\" aria-hidden=\"true\"><SearchIcon /></span>\n <input\n ref={inputRef}\n className=\"dishui-ai-command-search__input\"\n type=\"text\"\n role=\"combobox\"\n aria-label={label}\n aria-expanded={!empty}\n aria-controls={listId}\n aria-activedescendant={activeId}\n aria-autocomplete=\"list\"\n aria-busy={loading || undefined}\n autoComplete=\"off\"\n spellCheck={false}\n autoFocus={autoFocus}\n placeholder={placeholder}\n value={q}\n onChange={e => setQuery(e.target.value)}\n onKeyDown={onKeyDown}\n />\n {loading && <span className=\"dishui-ai-command-search__spinner\" role=\"status\" aria-label=\"Searching\" />}\n {q && !loading && (\n <button\n type=\"button\"\n className=\"dishui-ai-command-search__clear\"\n aria-label=\"Clear search\"\n onClick={() => { setQuery(''); inputRef.current?.focus(); }}\n >\n ×\n </button>\n )}\n </div>\n\n <ul id={listId} role=\"listbox\" aria-label={label} className=\"dishui-ai-command-search__list\">\n {groups.map(group => (\n <React.Fragment key={group.key || '__default'}>\n {group.key && (\n <li role=\"presentation\" className=\"dishui-ai-command-search__group\">{group.key}</li>\n )}\n {group.entries.map(({ item, index }) => {\n const isActive = index === activeIndex;\n return (\n <li\n key={item.id}\n id={`${uid}-opt-${index}`}\n role=\"option\"\n aria-selected={isActive}\n className={cn('dishui-ai-command-search__option', isActive && 'dishui-ai-command-search__option--active')}\n onMouseMove={() => { if (!isActive) setHighlighted(index); }}\n onMouseDown={e => e.preventDefault()}\n onClick={() => select(item)}\n >\n <span className=\"dishui-ai-command-search__icon\" aria-hidden=\"true\">{item.icon ?? <ArrowRight />}</span>\n <span className=\"dishui-ai-command-search__text\">\n <span className=\"dishui-ai-command-search__label\">{highlightMatches ? highlight(item.label, q) : item.label}</span>\n {item.description && (\n <span className=\"dishui-ai-command-search__description\">\n {highlightMatches ? highlight(item.description, q) : item.description}\n </span>\n )}\n </span>\n {item.shortcut && <kbd className=\"dishui-ai-command-search__shortcut\">{item.shortcut}</kbd>}\n </li>\n );\n })}\n </React.Fragment>\n ))}\n </ul>\n\n {empty && (\n <div className=\"dishui-ai-command-search__empty\" role=\"status\">\n {typeof emptyState === 'function' ? emptyState(q) : emptyState ?? (\n <>\n <p className=\"dishui-ai-command-search__empty-title\">\n {q.trim() ? <>No results for “{q.trim()}”</> : 'Nothing to show'}\n </p>\n <p className=\"dishui-ai-command-search__empty-hint\">\n {onSubmit ? 'Try a different phrase or press Enter to ask the agent' : 'Try a different phrase'}\n </p>\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/ai/ContextCards/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport './ContextCards.css';\n\nexport type ContextSourceKind = 'pdf' | 'csv' | 'doc' | 'web' | 'db' | 'code' | (string & {});\n\nexport type ContextSource = {\n kind: ContextSourceKind;\n name: string;\n url?: string;\n page?: number;\n};\n\nexport type ContextChunk = {\n id: string;\n title: React.ReactNode;\n excerpt: string;\n /** Defaults to `excerpt.length`. */\n characters?: number;\n /** Relevance 0–1, shown as a percentage. */\n score?: number;\n source: ContextSource;\n};\n\nexport type ContextCardsLabels = {\n characters?: string;\n page?: string;\n};\n\nexport type ContextCardsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title' | 'onSelect'> & {\n chunks: ContextChunk[];\n /** Total count when only a subset is passed; defaults to `chunks.length`. */\n total?: number;\n title?: React.ReactNode;\n /** Grid columns on wide containers; collapses to 1 below 560px. */\n columns?: 1 | 2;\n /** Makes each card a button. */\n onSelect?: (chunk: ContextChunk) => void;\n selectedId?: string;\n /** Excerpt line clamp. */\n maxExcerptLines?: number;\n emptyText?: React.ReactNode;\n labels?: ContextCardsLabels;\n};\n\nconst DEFAULT_LABELS: Required<ContextCardsLabels> = { characters: 'characters', page: 'p.' };\n\nconst numberFormat = new Intl.NumberFormat('en-US');\n\n/**\n * Retrieved knowledge chunks with their sources: a header count, then\n * cards with title, character count, clamped excerpt and a source pill.\n */\nexport default function ContextCards({\n chunks,\n total,\n title = 'All chunks',\n columns = 2,\n onSelect,\n selectedId,\n maxExcerptLines = 3,\n emptyText = 'No context retrieved',\n labels,\n className,\n ...rest\n}: ContextCardsProps) {\n const text = { ...DEFAULT_LABELS, ...labels };\n const count = total ?? chunks.length;\n const excerptStyle: React.CSSProperties = { WebkitLineClamp: maxExcerptLines, lineClamp: maxExcerptLines };\n\n return (\n <div {...rest} className={cn('dishui-ai-context-cards', `dishui-ai-context-cards--cols-${columns}`, className)}>\n <div className=\"dishui-ai-context-cards__header\">\n <span className=\"dishui-ai-context-cards__title\">{title}</span>\n <span className=\"dishui-ai-context-cards__count\">{numberFormat.format(count)}</span>\n </div>\n\n {chunks.length === 0 ? (\n <div className=\"dishui-ai-context-cards__empty\">{emptyText}</div>\n ) : (\n <ul className=\"dishui-ai-context-cards__grid\">\n {chunks.map(chunk => {\n const characters = chunk.characters ?? chunk.excerpt.length;\n const selected = chunk.id === selectedId;\n const inner = (\n <>\n <div className=\"dishui-ai-context-cards__card-header\">\n <span className=\"dishui-ai-context-cards__card-title\">{chunk.title}</span>\n <span className=\"dishui-ai-context-cards__chars\">\n {numberFormat.format(characters)} {text.characters}\n </span>\n {chunk.score !== undefined && (\n <span className=\"dishui-ai-context-cards__score\">{Math.round(chunk.score * 100)}%</span>\n )}\n </div>\n <p className=\"dishui-ai-context-cards__excerpt\" style={excerptStyle}>{chunk.excerpt}</p>\n <span className=\"dishui-ai-context-cards__source\">\n <span className=\"dishui-ai-context-cards__kind\">{chunk.source.kind}</span>\n <span className=\"dishui-ai-context-cards__source-name\" title={chunk.source.name}>\n {chunk.source.name}\n </span>\n {chunk.source.page !== undefined && (\n <span className=\"dishui-ai-context-cards__page\">{text.page} {chunk.source.page}</span>\n )}\n </span>\n </>\n );\n const cardClass = cn(\n 'dishui-ai-context-cards__card',\n onSelect && 'dishui-ai-context-cards__card--interactive',\n selected && 'dishui-ai-context-cards__card--selected',\n );\n return (\n <li key={chunk.id} className=\"dishui-ai-context-cards__item\">\n {onSelect ? (\n <button type=\"button\" className={cardClass} aria-pressed={selected} onClick={() => onSelect(chunk)}>\n {inner}\n </button>\n ) : (\n <div className={cardClass}>{inner}</div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AA6CA,IAAM,IAA+C;CAAE,YAAY;CAAc,MAAM;AAAK,GAEtF,IAAe,IAAI,KAAK,aAAa,OAAO;AAMlD,SAAwB,EAAa,EACnC,WACA,UACA,WAAQ,cACR,aAAU,GACV,aACA,eACA,qBAAkB,GAClB,eAAY,wBACZ,WACA,cACA,GAAG,KACiB;CACpB,IAAM,IAAO;EAAE,GAAG;EAAgB,GAAG;CAAO,GACtC,IAAQ,KAAS,EAAO,QACxB,IAAoC;EAAE,iBAAiB;EAAiB,WAAW;CAAgB;CAEzG,OACE,kBAAC,OAAD;EAAK,GAAI;EAAM,WAAW,EAAG,2BAA2B,iCAAiC,KAAW,CAAS;EAA7G,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,QAAD;IAAM,WAAU;IAAkC,UAAA;GAAY,CAAA,GAC9D,kBAAC,QAAD;IAAM,WAAU;IAAkC,UAAA,EAAa,OAAO,CAAK;GAAQ,CAAA,CAChF;EAEJ,CAAA,GAAA,EAAO,WAAW,IACjB,kBAAC,OAAD;GAAK,WAAU;GAAkC,UAAA;EAAe,CAAA,IAEhE,kBAAC,MAAD;GAAI,WAAU;GACX,UAAA,EAAO,KAAI,MAAS;IACnB,IAAM,IAAa,EAAM,cAAc,EAAM,QAAQ,QAC/C,IAAW,EAAM,OAAO,GACxB,IACJ,kBAAA,GAAA,EAAA,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAAuC,UAAA,EAAM;OAAY,CAAA;OACzE,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SACG,EAAa,OAAO,CAAU;SAAE;SAAE,EAAK;QACpC;;OACL,EAAM,UAAU,KAAA,KACf,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA,CAAkD,KAAK,MAAM,EAAM,QAAQ,GAAG,GAAE,GAAO;;MAEtF;;KACL,kBAAC,KAAD;MAAG,WAAU;MAAmC,OAAO;MAAe,UAAA,EAAM;KAAW,CAAA;KACvF,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAAiC,UAAA,EAAM,OAAO;OAAW,CAAA;OACzE,kBAAC,QAAD;QAAM,WAAU;QAAuC,OAAO,EAAM,OAAO;QACxE,UAAA,EAAM,OAAO;OACV,CAAA;OACL,EAAM,OAAO,SAAS,KAAA,KACrB,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SAAiD,EAAK;SAAK;SAAE,EAAM,OAAO;QAAW;;MAEnF;;IACN,EAAA,CAAA,GAEE,IAAY,EAChB,iCACA,KAAY,8CACZ,KAAY,yCACd;IACA,OACE,kBAAC,MAAD;KAAmB,WAAU;KAC1B,UAAA,IACC,kBAAC,UAAD;MAAQ,MAAK;MAAS,WAAW;MAAW,gBAAc;MAAU,eAAe,EAAS,CAAK;MAC9F,UAAA;KACK,CAAA,IAER,kBAAC,OAAD;MAAK,WAAW;MAAY,UAAA;KAAW,CAAA;IAEvC,GARK,EAAM,EAQX;GAER,CAAC;EACC,CAAA,CAEH;;AAET"}
1
+ {"version":3,"file":"index.js","names":["_Fragment","DEFAULT_LABELS","numberFormat","ContextCards","rest","text","labels","count","total","chunks","excerptStyle","maxExcerptLines","cn","columns","className","title","emptyText","characters","chunk","selected","selectedId","inner","Fragment","cardClass","onSelect"],"sources":["../../../../src/components/ai/ContextCards/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../../utils/cn';\nimport './ContextCards.css';\n\nexport type ContextSourceKind = 'pdf' | 'csv' | 'doc' | 'web' | 'db' | 'code' | (string & {});\n\nexport type ContextSource = {\n kind: ContextSourceKind;\n name: string;\n url?: string;\n page?: number;\n};\n\nexport type ContextChunk = {\n id: string;\n title: React.ReactNode;\n excerpt: string;\n /** Defaults to `excerpt.length`. */\n characters?: number;\n /** Relevance 0–1, shown as a percentage. */\n score?: number;\n source: ContextSource;\n};\n\nexport type ContextCardsLabels = {\n characters?: string;\n page?: string;\n};\n\nexport type ContextCardsProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title' | 'onSelect'> & {\n chunks: ContextChunk[];\n /** Total count when only a subset is passed; defaults to `chunks.length`. */\n total?: number;\n title?: React.ReactNode;\n /** Grid columns on wide containers; collapses to 1 below 560px. */\n columns?: 1 | 2;\n /** Makes each card a button. */\n onSelect?: (chunk: ContextChunk) => void;\n selectedId?: string;\n /** Excerpt line clamp. */\n maxExcerptLines?: number;\n emptyText?: React.ReactNode;\n labels?: ContextCardsLabels;\n};\n\nconst DEFAULT_LABELS: Required<ContextCardsLabels> = { characters: 'characters', page: 'p.' };\n\nconst numberFormat = new Intl.NumberFormat('en-US');\n\n/**\n * Retrieved knowledge chunks with their sources: a header count, then\n * cards with title, character count, clamped excerpt and a source pill.\n */\nexport default function ContextCards({\n chunks,\n total,\n title = 'All chunks',\n columns = 2,\n onSelect,\n selectedId,\n maxExcerptLines = 3,\n emptyText = 'No context retrieved',\n labels,\n className,\n ...rest\n}: ContextCardsProps) {\n const text = { ...DEFAULT_LABELS, ...labels };\n const count = total ?? chunks.length;\n const excerptStyle: React.CSSProperties = { WebkitLineClamp: maxExcerptLines, lineClamp: maxExcerptLines };\n\n return (\n <div {...rest} className={cn('dishui-ai-context-cards', `dishui-ai-context-cards--cols-${columns}`, className)}>\n <div className=\"dishui-ai-context-cards__header\">\n <span className=\"dishui-ai-context-cards__title\">{title}</span>\n <span className=\"dishui-ai-context-cards__count\">{numberFormat.format(count)}</span>\n </div>\n\n {chunks.length === 0 ? (\n <div className=\"dishui-ai-context-cards__empty\">{emptyText}</div>\n ) : (\n <ul className=\"dishui-ai-context-cards__grid\">\n {chunks.map(chunk => {\n const characters = chunk.characters ?? chunk.excerpt.length;\n const selected = chunk.id === selectedId;\n const inner = (\n <>\n <div className=\"dishui-ai-context-cards__card-header\">\n <span className=\"dishui-ai-context-cards__card-title\">{chunk.title}</span>\n <span className=\"dishui-ai-context-cards__chars\">\n {numberFormat.format(characters)} {text.characters}\n </span>\n {chunk.score !== undefined && (\n <span className=\"dishui-ai-context-cards__score\">{Math.round(chunk.score * 100)}%</span>\n )}\n </div>\n <p className=\"dishui-ai-context-cards__excerpt\" style={excerptStyle}>{chunk.excerpt}</p>\n <span className=\"dishui-ai-context-cards__source\">\n <span className=\"dishui-ai-context-cards__kind\">{chunk.source.kind}</span>\n <span className=\"dishui-ai-context-cards__source-name\" title={chunk.source.name}>\n {chunk.source.name}\n </span>\n {chunk.source.page !== undefined && (\n <span className=\"dishui-ai-context-cards__page\">{text.page} {chunk.source.page}</span>\n )}\n </span>\n </>\n );\n const cardClass = cn(\n 'dishui-ai-context-cards__card',\n onSelect && 'dishui-ai-context-cards__card--interactive',\n selected && 'dishui-ai-context-cards__card--selected',\n );\n return (\n <li key={chunk.id} className=\"dishui-ai-context-cards__item\">\n {onSelect ? (\n <button type=\"button\" className={cardClass} aria-pressed={selected} onClick={() => onSelect(chunk)}>\n {inner}\n </button>\n ) : (\n <div className={cardClass}>{inner}</div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AA6CA,IAAMC,IAA+C;CAAE,YAAY;CAAc,MAAM;AAAK,GAEtFC,IAAe,IAAI,KAAK,aAAa,OAAO;AAMlD,SAAwBC,EAAa,EACnC,WACA,UACA,WAAQ,cACR,aAAU,GACV,aACA,eACA,qBAAkB,GAClB,eAAY,wBACZ,WACA,cACA,GAAGC,KACiB;CACpB,IAAMC,IAAO;EAAE,GAAGJ;EAAgB,GAAGK;CAAO,GACtCC,IAAQC,KAASC,EAAO,QACxBC,IAAoC;EAAE,iBAAiBC;EAAiB,WAAWA;CAAgB;CAEzG,OACE,kBAAC,OAAD;EAAK,GAAIP;EAAM,WAAWQ,EAAG,2BAA2B,iCAAiCC,KAAWC,CAAS;EAA7G,UAAA,CACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,QAAD;IAAM,WAAU;IAAkC,UAAAC;GAAY,CAAA,GAC9D,kBAAC,QAAD;IAAM,WAAU;IAAkC,UAAAb,EAAa,OAAOK,CAAK;GAAQ,CAAA,CAChF;EAEJ,CAAA,GAAAE,EAAO,WAAW,IACjB,kBAAC,OAAD;GAAK,WAAU;GAAkC,UAAAO;EAAe,CAAA,IAEhE,kBAAC,MAAD;GAAI,WAAU;GACX,UAAAP,EAAO,KAAI,MAAS;IACnB,IAAMQ,IAAaC,EAAM,cAAcA,EAAM,QAAQ,QAC/CC,IAAWD,EAAM,OAAOE,GACxBC,IACJ,kBAAArB,GAAA,EAAA,UAAA;KACE,kBAAC,OAAD;MAAK,WAAU;MAAf,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAAuC,UAAAkB,EAAM;OAAY,CAAA;OACzE,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SACGhB,EAAa,OAAOe,CAAU;SAAE;SAAEZ,EAAK;QACpC;;OACLa,EAAM,UAAU,KAAA,KACf,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA,CAAkD,KAAK,MAAMA,EAAM,QAAQ,GAAG,GAAE,GAAO;;MAEtF;;KACL,kBAAC,KAAD;MAAG,WAAU;MAAmC,OAAOR;MAAe,UAAAQ,EAAM;KAAW,CAAA;KACvF,kBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACE,kBAAC,QAAD;QAAM,WAAU;QAAiC,UAAAA,EAAM,OAAO;OAAW,CAAA;OACzE,kBAAC,QAAD;QAAM,WAAU;QAAuC,OAAOA,EAAM,OAAO;QACxE,UAAAA,EAAM,OAAO;OACV,CAAA;OACLA,EAAM,OAAO,SAAS,KAAA,KACrB,kBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SAAiDb,EAAK;SAAK;SAAEa,EAAM,OAAO;QAAW;;MAEnF;;IACN,EAAA,CAAA,GAEEK,IAAYX,EAChB,iCACAY,KAAY,8CACZL,KAAY,yCACd;IACA,OACE,kBAAC,MAAD;KAAmB,WAAU;KAC1B,UAAAK,IACC,kBAAC,UAAD;MAAQ,MAAK;MAAS,WAAWD;MAAW,gBAAcJ;MAAU,eAAeK,EAASN,CAAK;MAC9F,UAAAG;KACK,CAAA,IAER,kBAAC,OAAD;MAAK,WAAWE;MAAY,UAAAF;KAAW,CAAA;IAEvC,GARKH,EAAM,EAQX;GAER,CAAC;EACC,CAAA,CAEH;;AAET"}