@digithings-ai/ui 0.0.0-stage → 0.1.0

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 (424) hide show
  1. package/README.md +48 -2
  2. package/package.json +143 -4
  3. package/src/components/NavShell.tsx +776 -0
  4. package/src/components/SocialRow.tsx +87 -0
  5. package/src/components/Spinner.tsx +27 -0
  6. package/src/components/StackLogo.tsx +40 -0
  7. package/src/components/Terminal.tsx +110 -0
  8. package/src/components/TerminalManifest.tsx +212 -0
  9. package/src/components/ThemeProvider.tsx +271 -0
  10. package/src/components/account/AuthCard.tsx +309 -0
  11. package/src/components/assistant-ui/elements/mermaid-diagram.aui.tsx +63 -0
  12. package/src/components/assistant-ui/elements/mermaid-diagram.tsx +340 -0
  13. package/src/components/brand/BrandWordmark.tsx +32 -0
  14. package/src/components/changelog/ReleaseRail.tsx +81 -0
  15. package/src/components/changelog/index.ts +1 -0
  16. package/src/components/chat/ChatCodeBlock.tsx +67 -0
  17. package/src/components/chat/ChatMarkdown.tsx +66 -0
  18. package/src/components/chat/ChatMarkdownSource.tsx +203 -0
  19. package/src/components/chat/ChatMermaidBlock.tsx +202 -0
  20. package/src/components/chat/ChatMessage.tsx +77 -0
  21. package/src/components/chat/ChatPlayback.tsx +422 -0
  22. package/src/components/chat/ChatStreamCursor.tsx +25 -0
  23. package/src/components/chat/ChatThinking.tsx +113 -0
  24. package/src/components/chat/ChatToolCall.tsx +190 -0
  25. package/src/components/chat/ChatTranscript.tsx +60 -0
  26. package/src/components/chat/ChatWidgetFrame.tsx +107 -0
  27. package/src/components/chat/DigichatBootLoader.tsx +683 -0
  28. package/src/components/chat/DigichatLauncher.tsx +361 -0
  29. package/src/components/chat/DigichatThread.tsx +118 -0
  30. package/src/components/chat/DigichatThreadList.tsx +54 -0
  31. package/src/components/chat/DigichatWordmark.tsx +24 -0
  32. package/src/components/chat/DotMatrix.tsx +650 -0
  33. package/src/components/chat/boot-lab.tsx +766 -0
  34. package/src/components/chat/boot-signal.ts +144 -0
  35. package/src/components/chat/chat-surfaces.ts +52 -0
  36. package/src/components/chat/connection-status.ts +40 -0
  37. package/src/components/chat/digichat-wordmark.ts +355 -0
  38. package/src/components/chat/disclosure-chevron.tsx +49 -0
  39. package/src/components/chat/followable-href.ts +9 -0
  40. package/src/components/chat/gallery-thread/action-icons.tsx +25 -0
  41. package/src/components/chat/gallery-thread/attachment.aui.tsx +262 -0
  42. package/src/components/chat/gallery-thread/block-caret.tsx +439 -0
  43. package/src/components/chat/gallery-thread/cn.ts +1 -0
  44. package/src/components/chat/gallery-thread/composer-keyboard.ts +106 -0
  45. package/src/components/chat/gallery-thread/composer-trigger-popover.aui.tsx +235 -0
  46. package/src/components/chat/gallery-thread/css.d.ts +6 -0
  47. package/src/components/chat/gallery-thread/file.tsx +238 -0
  48. package/src/components/chat/gallery-thread/follow-up-suggestions.aui.tsx +92 -0
  49. package/src/components/chat/gallery-thread/format-json-dump.ts +112 -0
  50. package/src/components/chat/gallery-thread/hooks/use-attachment-src.ts +46 -0
  51. package/src/components/chat/gallery-thread/hooks/use-copy-to-clipboard.ts +9 -0
  52. package/src/components/chat/gallery-thread/image.tsx +519 -0
  53. package/src/components/chat/gallery-thread/markdown-text.tsx +278 -0
  54. package/src/components/chat/gallery-thread/message-error.aui.tsx +105 -0
  55. package/src/components/chat/gallery-thread/message-timing.aui.tsx +143 -0
  56. package/src/components/chat/gallery-thread/private-work-step.tsx +188 -0
  57. package/src/components/chat/gallery-thread/reasoning.tsx +332 -0
  58. package/src/components/chat/gallery-thread/scroll-mode.ts +174 -0
  59. package/src/components/chat/gallery-thread/source.tsx +76 -0
  60. package/src/components/chat/gallery-thread/thread.aui.tsx +1619 -0
  61. package/src/components/chat/gallery-thread/tooltip-icon-button.tsx +53 -0
  62. package/src/components/chat/gallery-thread/typed-welcome-copy.tsx +18 -0
  63. package/src/components/chat/gallery-thread/ui/tooltip.tsx +22 -0
  64. package/src/components/chat/gallery-thread/work-chain-summary.tsx +48 -0
  65. package/src/components/chat/gallery-thread/work-chain.tsx +110 -0
  66. package/src/components/chat/gallery-thread/work-status.ts +66 -0
  67. package/src/components/chat/overlay-scrollbar.tsx +86 -0
  68. package/src/components/chat/sanitize-mermaid-svg.ts +38 -0
  69. package/src/components/chat/skins/SOURCE.md +36 -0
  70. package/src/components/chat/skins/base/attachment.aui.tsx +287 -0
  71. package/src/components/chat/skins/base/aui-default/README.md +45 -0
  72. package/src/components/chat/skins/base/aui-default/collapsible-root.tsx +19 -0
  73. package/src/components/chat/skins/base/aui-default/collapsible.tsx +21 -0
  74. package/src/components/chat/skins/base/aui-default/reasoning.aui.tsx +120 -0
  75. package/src/components/chat/skins/base/aui-default/reasoning.tsx +331 -0
  76. package/src/components/chat/skins/base/aui-default/surfaces.ts +7 -0
  77. package/src/components/chat/skins/base/aui-default/tool-fallback.aui.tsx +772 -0
  78. package/src/components/chat/skins/base/aui-default/tool-group.aui.tsx +241 -0
  79. package/src/components/chat/skins/base/docs-model-options.ts +6 -0
  80. package/src/components/chat/skins/base/elements/assistant-trace.aui.tsx +169 -0
  81. package/src/components/chat/skins/base/elements/composer-trigger-popover.aui.tsx +271 -0
  82. package/src/components/chat/skins/base/elements/directive-text.aui.tsx +29 -0
  83. package/src/components/chat/skins/base/elements/directive-text.tsx +76 -0
  84. package/src/components/chat/skins/base/elements/message-timing.aui.tsx +104 -0
  85. package/src/components/chat/skins/base/elements/model-selector.aui.tsx +140 -0
  86. package/src/components/chat/skins/base/elements/model-selector.tsx +720 -0
  87. package/src/components/chat/skins/base/elements/quote.aui.tsx +290 -0
  88. package/src/components/chat/skins/base/elements/work-chain.tsx +100 -0
  89. package/src/components/chat/skins/base/markdown-text.tsx +294 -0
  90. package/src/components/chat/skins/base/model.ts +1 -0
  91. package/src/components/chat/skins/base/thread.tsx +1050 -0
  92. package/src/components/chat/skins/base/tooltip-icon-button.tsx +56 -0
  93. package/src/components/chat/skins/base/ui/avatar.tsx +115 -0
  94. package/src/components/chat/skins/base/ui/badge.tsx +51 -0
  95. package/src/components/chat/skins/base/ui/button.tsx +67 -0
  96. package/src/components/chat/skins/base/ui/command.tsx +185 -0
  97. package/src/components/chat/skins/base/ui/dialog.tsx +168 -0
  98. package/src/components/chat/skins/base/ui/dot-matrix.tsx +267 -0
  99. package/src/components/chat/skins/base/ui/popover.tsx +97 -0
  100. package/src/components/chat/skins/base/ui/skeleton.tsx +20 -0
  101. package/src/components/chat/skins/base/ui/textarea.tsx +24 -0
  102. package/src/components/chat/skins/base/ui/tooltip.tsx +73 -0
  103. package/src/components/chat/skins/base-assistant-ui/config-provider.tsx +90 -0
  104. package/src/components/chat/skins/base-assistant-ui/defaults.ts +419 -0
  105. package/src/components/chat/skins/base-assistant-ui/index.tsx +44 -0
  106. package/src/components/chat/skins/chatgpt.tsx +448 -0
  107. package/src/components/chat/skins/claude.tsx +380 -0
  108. package/src/components/chat/skins/digichat-composer-toolbar.tsx +151 -0
  109. package/src/components/chat/skins/digichat-context-meter-shares.ts +158 -0
  110. package/src/components/chat/skins/digichat-context-meter.tsx +243 -0
  111. package/src/components/chat/skins/digichat-meter-tone.ts +26 -0
  112. package/src/components/chat/skins/digichat-usage-meter.tsx +103 -0
  113. package/src/components/chat/skins/digichat.tsx +144 -0
  114. package/src/components/chat/skins/expo-react-native.tsx +29 -0
  115. package/src/components/chat/skins/gemini.tsx +322 -0
  116. package/src/components/chat/skins/grok-icon.tsx +34 -0
  117. package/src/components/chat/skins/grok.tsx +369 -0
  118. package/src/components/chat/skins/index.ts +46 -0
  119. package/src/components/chat/skins/perplexity.tsx +462 -0
  120. package/src/components/chat/skins/product-page-assistant/assistant-modal.tsx +73 -0
  121. package/src/components/chat/skins/product-page-assistant/index.tsx +19 -0
  122. package/src/components/chat/skins/product-page-assistant/product-dashboard.tsx +164 -0
  123. package/src/components/chat/skins/react-ink.tsx +97 -0
  124. package/src/components/chat/skins/thread-skin-host-contract.ts +102 -0
  125. package/src/components/chat/skins/thread-skin-view.tsx +156 -0
  126. package/src/components/chat/skins/thread-skins.ts +143 -0
  127. package/src/components/chat/skins/tooltip-icon-button.tsx +35 -0
  128. package/src/components/chat/skins/ui/dropdown-menu.tsx +272 -0
  129. package/src/components/chat/skins/webpage-assistant/assistant-config.ts +238 -0
  130. package/src/components/chat/skins/webpage-assistant/assistant-modal.tsx +78 -0
  131. package/src/components/chat/skins/webpage-assistant/config-provider.tsx +132 -0
  132. package/src/components/chat/skins/webpage-assistant/docs-app.tsx +106 -0
  133. package/src/components/chat/skins/webpage-assistant/docs-article.tsx +109 -0
  134. package/src/components/chat/skins/webpage-assistant/docs-assistant.tsx +73 -0
  135. package/src/components/chat/skins/webpage-assistant/docs-nav.tsx +81 -0
  136. package/src/components/chat/skins/webpage-assistant/host-ui.ts +79 -0
  137. package/src/components/chat/skins/webpage-assistant/index.tsx +12 -0
  138. package/src/components/chat/skins/webpage-assistant/markdown-page.tsx +11 -0
  139. package/src/components/chat/skins/webpage-assistant/pages.ts +9 -0
  140. package/src/components/chat/skins/webpage-assistant/types.ts +178 -0
  141. package/src/components/chat/skins/webpage-assistant/use-mobile.ts +19 -0
  142. package/src/components/chat/stock/SOURCE.md +90 -0
  143. package/src/components/chat/stock/artifacts-panel.tsx +305 -0
  144. package/src/components/chat/stock/attachment.aui.tsx +280 -0
  145. package/src/components/chat/stock/chat-notice.tsx +143 -0
  146. package/src/components/chat/stock/chat-private-mode.tsx +64 -0
  147. package/src/components/chat/stock/deploy-ui-context.tsx +89 -0
  148. package/src/components/chat/stock/embed-chat-prefs.tsx +471 -0
  149. package/src/components/chat/stock/file.tsx +265 -0
  150. package/src/components/chat/stock/follow-up-suggestions.aui.tsx +83 -0
  151. package/src/components/chat/stock/image.tsx +531 -0
  152. package/src/components/chat/stock/index.ts +129 -0
  153. package/src/components/chat/stock/json-view.tsx +140 -0
  154. package/src/components/chat/stock/markdown-text.tsx +319 -0
  155. package/src/components/chat/stock/message-error.aui.tsx +96 -0
  156. package/src/components/chat/stock/message-export-menu.tsx +156 -0
  157. package/src/components/chat/stock/palette-row-preview.tsx +26 -0
  158. package/src/components/chat/stock/reasoning.aui.tsx +120 -0
  159. package/src/components/chat/stock/reasoning.tsx +335 -0
  160. package/src/components/chat/stock/skin-chrome.tsx +81 -0
  161. package/src/components/chat/stock/skin-credit.tsx +63 -0
  162. package/src/components/chat/stock/skin-palette-bridge.tsx +235 -0
  163. package/src/components/chat/stock/skin-palette-context.ts +16 -0
  164. package/src/components/chat/stock/skin-runtime.tsx +52 -0
  165. package/src/components/chat/stock/skin-slash-palette.tsx +393 -0
  166. package/src/components/chat/stock/skin-types.ts +217 -0
  167. package/src/components/chat/stock/stock-chat-prefs-host.tsx +501 -0
  168. package/src/components/chat/stock/stock-send-gate.tsx +94 -0
  169. package/src/components/chat/stock/stock-shape.tsx +39 -0
  170. package/src/components/chat/stock/thread.aui.tsx +645 -0
  171. package/src/components/chat/stock/tool-display.ts +6 -0
  172. package/src/components/chat/stock/tool-fallback.aui.tsx +866 -0
  173. package/src/components/chat/stock/tool-group.aui.tsx +244 -0
  174. package/src/components/chat/stock/tool-surface.ts +120 -0
  175. package/src/components/chat/stock/tooltip-icon-button.tsx +49 -0
  176. package/src/components/chat/stock/ui/avatar.tsx +108 -0
  177. package/src/components/chat/stock/ui/button.tsx +81 -0
  178. package/src/components/chat/stock/ui/collapsible.tsx +21 -0
  179. package/src/components/chat/stock/ui/dialog.tsx +163 -0
  180. package/src/components/chat/stock/ui/skeleton.tsx +13 -0
  181. package/src/components/chat/stock/ui/textarea.tsx +20 -0
  182. package/src/components/chat/stock/ui/tooltip.tsx +68 -0
  183. package/src/components/chat/stock/use-attachment-src.ts +42 -0
  184. package/src/components/chat/stock/use-copy-to-clipboard.ts +29 -0
  185. package/src/components/chat/strip-model-boilerplate.ts +42 -0
  186. package/src/components/chat/suggestion-cycle.tsx +230 -0
  187. package/src/components/chat/suggestion-scroll-row.tsx +81 -0
  188. package/src/components/chat/trace-grouping/chain-group-by.ts +44 -0
  189. package/src/components/chat/trace-grouping/chain-state.ts +141 -0
  190. package/src/components/chat/trace-grouping/index.ts +32 -0
  191. package/src/components/chat/trace-grouping/tool-row.ts +74 -0
  192. package/src/components/chat/trace-grouping/use-deploy-work-disclosure.ts +35 -0
  193. package/src/components/chat/trace-grouping/use-work-chain.ts +103 -0
  194. package/src/components/chat/trace-i18n/core.ts +48 -0
  195. package/src/components/chat/trace-i18n/index.tsx +23 -0
  196. package/src/components/chat/trace-i18n/locales/en.ts +24 -0
  197. package/src/components/chat/trace-i18n/locales/fr.ts +28 -0
  198. package/src/components/chat/trace-i18n/types.ts +35 -0
  199. package/src/components/chat/trace-spacing.ts +249 -0
  200. package/src/components/chat/transcript/activity-view.ts +375 -0
  201. package/src/components/chat/transcript/chat-export.ts +133 -0
  202. package/src/components/chat/transcript/index.ts +10 -0
  203. package/src/components/chat/transcript/save-file.ts +209 -0
  204. package/src/components/chat/transcript/transcript-markdown.ts +428 -0
  205. package/src/components/chat/transcript/types.ts +81 -0
  206. package/src/components/chat/turn-outcome.ts +52 -0
  207. package/src/components/chat/use-warmup-phase.ts +18 -0
  208. package/src/components/chat/work-status-lead.tsx +49 -0
  209. package/src/components/chrome.tsx +264 -0
  210. package/src/components/command-palette/CommandPalette.tsx +404 -0
  211. package/src/components/command-palette/index.ts +6 -0
  212. package/src/components/contact/ContactMailto.tsx +112 -0
  213. package/src/components/contact/index.ts +5 -0
  214. package/src/components/conviction/ConvictionMeter.tsx +40 -0
  215. package/src/components/conviction/SignedConvictionBadge.tsx +26 -0
  216. package/src/components/conviction/index.ts +7 -0
  217. package/src/components/data-layout/BentoGrid.tsx +52 -0
  218. package/src/components/data-layout/CardRail.tsx +150 -0
  219. package/src/components/data-layout/DotMatrixStat.tsx +65 -0
  220. package/src/components/data-layout/FeatureCell.tsx +80 -0
  221. package/src/components/data-layout/MediaFrame.tsx +125 -0
  222. package/src/components/data-layout/ModuleGrid.tsx +735 -0
  223. package/src/components/data-layout/Odometer.tsx +149 -0
  224. package/src/components/data-layout/ProductFrame.tsx +79 -0
  225. package/src/components/data-layout/TestimonialWall.tsx +139 -0
  226. package/src/components/data-layout/index.ts +19 -0
  227. package/src/components/data-layout/treemap.ts +368 -0
  228. package/src/components/deck/DeckStack.tsx +243 -0
  229. package/src/components/desk/DataTable.tsx +373 -0
  230. package/src/components/desk/KpiGrid.tsx +80 -0
  231. package/src/components/desk/Sparkline.tsx +63 -0
  232. package/src/components/desk/StateBlock.tsx +132 -0
  233. package/src/components/desk/index.ts +18 -0
  234. package/src/components/diagrams/ArchitectureDiagram.tsx +350 -0
  235. package/src/components/diagrams/ArchitectureTour.tsx +912 -0
  236. package/src/components/diagrams/TerminalSchematic.tsx +192 -0
  237. package/src/components/diagrams/architecture-svg.tsx +384 -0
  238. package/src/components/diagrams/index.ts +30 -0
  239. package/src/components/diagrams/mermaid-theme.ts +115 -0
  240. package/src/components/diagrams/tour-camera.ts +171 -0
  241. package/src/components/docs/CodeTabs.tsx +90 -0
  242. package/src/components/docs/CopyCommand.tsx +151 -0
  243. package/src/components/docs/DocsLayout.tsx +197 -0
  244. package/src/components/docs/DocsSearch.tsx +97 -0
  245. package/src/components/docs/Endpoint.tsx +135 -0
  246. package/src/components/document/DocumentFrame.tsx +43 -0
  247. package/src/components/document/GlyphList.tsx +51 -0
  248. package/src/components/document/PageTitle.tsx +44 -0
  249. package/src/components/document/Prose.tsx +38 -0
  250. package/src/components/document/Section.tsx +55 -0
  251. package/src/components/document/index.ts +13 -0
  252. package/src/components/effects-chrome/AnnouncementBar.tsx +88 -0
  253. package/src/components/effects-chrome/HorizontalScrollTrack.tsx +461 -0
  254. package/src/components/effects-chrome/Pipeline.tsx +226 -0
  255. package/src/components/effects-chrome/RotatingPrompts.tsx +116 -0
  256. package/src/components/effects-chrome/StackingPanels.tsx +101 -0
  257. package/src/components/effects-chrome/TabStrip.tsx +232 -0
  258. package/src/components/effects-chrome/ToastStack.tsx +201 -0
  259. package/src/components/effects-chrome/horizontal-track-core.ts +70 -0
  260. package/src/components/effects-chrome/index.ts +35 -0
  261. package/src/components/emblems.tsx +188 -0
  262. package/src/components/faviconTheme.ts +23 -0
  263. package/src/components/figure/Figure.tsx +38 -0
  264. package/src/components/figure/index.ts +2 -0
  265. package/src/components/finance-charts/DrawdownPlot.tsx +76 -0
  266. package/src/components/finance-charts/EquityCurve.tsx +71 -0
  267. package/src/components/finance-charts/PriceChart.tsx +119 -0
  268. package/src/components/finance-charts/chart-host.tsx +236 -0
  269. package/src/components/finance-charts/chart-scale.ts +93 -0
  270. package/src/components/finance-charts/demo-data.ts +88 -0
  271. package/src/components/finance-charts/index.ts +46 -0
  272. package/src/components/finance-charts/lw-chart.tsx +292 -0
  273. package/src/components/finance-composites/MarketBar.tsx +243 -0
  274. package/src/components/finance-composites/OrderBook.tsx +133 -0
  275. package/src/components/finance-composites/PerformanceDashboard.tsx +185 -0
  276. package/src/components/finance-composites/SortableTable.tsx +144 -0
  277. package/src/components/finance-composites/StockTicker.tsx +65 -0
  278. package/src/components/finance-composites/SyncedTearsheet.tsx +226 -0
  279. package/src/components/finance-composites/index.ts +28 -0
  280. package/src/components/finance-tearsheet/KpiStrip.tsx +49 -0
  281. package/src/components/finance-tearsheet/LiveBadge.tsx +29 -0
  282. package/src/components/finance-tearsheet/ReturnsMatrix.tsx +321 -0
  283. package/src/components/finance-tearsheet/StrategyTearsheet.tsx +99 -0
  284. package/src/components/finance-tearsheet/TearsheetCard.tsx +54 -0
  285. package/src/components/finance-tearsheet/TradeLogTable.tsx +73 -0
  286. package/src/components/finance-tearsheet/charts.tsx +2624 -0
  287. package/src/components/finance-tearsheet/demo-data.ts +177 -0
  288. package/src/components/finance-tearsheet/format.ts +41 -0
  289. package/src/components/finance-tearsheet/index.ts +120 -0
  290. package/src/components/finance-tearsheet/print.ts +52 -0
  291. package/src/components/finance-tearsheet/risk-bands.ts +48 -0
  292. package/src/components/finance-tearsheet/stats.ts +35 -0
  293. package/src/components/finance-tearsheet/strategy-sheet-model.ts +238 -0
  294. package/src/components/finance-tearsheet/types.ts +58 -0
  295. package/src/components/footer/FooterCells.tsx +109 -0
  296. package/src/components/footer/index.ts +6 -0
  297. package/src/components/graph.tsx +158 -0
  298. package/src/components/icons.tsx +98 -0
  299. package/src/components/landing/PixelWordmark.tsx +36 -0
  300. package/src/components/logos.ts +39 -0
  301. package/src/components/marquee/Marquee.tsx +204 -0
  302. package/src/components/metrics/PerfMetrics.tsx +68 -0
  303. package/src/components/metrics/StatCounter.tsx +104 -0
  304. package/src/components/page-geometry.tsx +177 -0
  305. package/src/components/pricing/Pricing.tsx +174 -0
  306. package/src/components/pricing/PricingMatrix.tsx +219 -0
  307. package/src/components/prose/index.ts +2 -0
  308. package/src/components/prose/prose.tsx +86 -0
  309. package/src/components/repo-activity/RepoActivity.tsx +599 -0
  310. package/src/components/repo-activity/RepoHeatmap.tsx +225 -0
  311. package/src/components/repo-activity/demo.ts +201 -0
  312. package/src/components/repo-activity/fetch.ts +211 -0
  313. package/src/components/repo-activity/heatmap.ts +123 -0
  314. package/src/components/repo-activity/index.ts +28 -0
  315. package/src/components/repo-activity/types.ts +99 -0
  316. package/src/components/stages/NumberedStages.tsx +116 -0
  317. package/src/components/symbols/marks.tsx +116 -0
  318. package/src/components/symbols/terminal-lockup.tsx +136 -0
  319. package/src/components/symbols/terminal-marks.tsx +226 -0
  320. package/src/components/terminal/ChatResponseLoader.tsx +67 -0
  321. package/src/components/terminal/ContainerBootLoader.tsx +82 -0
  322. package/src/components/terminal/TerminalStepCaret.tsx +202 -0
  323. package/src/components/themeInit.ts +24 -0
  324. package/src/components/typography/MotionReveal.tsx +108 -0
  325. package/src/components/typography/TypewriterReveal.tsx +101 -0
  326. package/src/components/typography/WordReveal.tsx +143 -0
  327. package/src/data/modules.ts +378 -0
  328. package/src/data/subsystems.ts +101 -0
  329. package/src/index.ts +587 -0
  330. package/src/lib/base-path.ts +60 -0
  331. package/src/lib/cx.ts +25 -0
  332. package/src/lib/gloomberb.ts +69 -0
  333. package/src/lib/record.ts +19 -0
  334. package/src/lib/stub-payload.ts +183 -0
  335. package/src/lib/useBodyScrollLock.ts +44 -0
  336. package/src/lib/utils.ts +6 -0
  337. package/src/motion/primitives.tsx +105 -0
  338. package/src/motion/scroll-glide.ts +62 -0
  339. package/src/motion/scrolly-core.ts +38 -0
  340. package/src/motion/scrolly.tsx +95 -0
  341. package/src/navigation/HashScrollManager.tsx +167 -0
  342. package/src/navigation/hashScroll.ts +78 -0
  343. package/src/replay/browser.ts +280 -0
  344. package/src/replay/chat-export-run.ts +121 -0
  345. package/src/replay/export-format.ts +25 -0
  346. package/src/replay/export-mount.ts +32 -0
  347. package/src/replay/filename.ts +54 -0
  348. package/src/replay/index.ts +21 -0
  349. package/src/replay/redact-dom.ts +178 -0
  350. package/src/replay/redact.ts +113 -0
  351. package/src/replay/snapshot.ts +659 -0
  352. package/src/styles/account-auth.css +339 -0
  353. package/src/styles/brand-wordmark.css +11 -0
  354. package/src/styles/card-rail.css +120 -0
  355. package/src/styles/chat-aui.css +1143 -0
  356. package/src/styles/chat-core.css +469 -0
  357. package/src/styles/chat-digichat.css +2531 -0
  358. package/src/styles/chat-math.css +70 -0
  359. package/src/styles/chat-skin-palette.css +138 -0
  360. package/src/styles/chat-stock-menu.css +37 -0
  361. package/src/styles/chat-widgets.css +190 -0
  362. package/src/styles/command-palette.css +372 -0
  363. package/src/styles/controls-core.css +2261 -0
  364. package/src/styles/controls-overlay.css +603 -0
  365. package/src/styles/data-layout.css +288 -0
  366. package/src/styles/deck.css +141 -0
  367. package/src/styles/diagrams.css +1860 -0
  368. package/src/styles/digichat-app-theme.css +250 -0
  369. package/src/styles/digichat-boot-loader.css +487 -0
  370. package/src/styles/digichat-launcher.css +377 -0
  371. package/src/styles/docs.css +165 -0
  372. package/src/styles/effects-chrome.css +888 -0
  373. package/src/styles/finance-composites.css +214 -0
  374. package/src/styles/finance-tearsheet-overlay.css +90 -0
  375. package/src/styles/finance-tearsheet.css +945 -0
  376. package/src/styles/marquee.css +168 -0
  377. package/src/styles/metrics.css +82 -0
  378. package/src/styles/nav-shell.css +551 -0
  379. package/src/styles/pricing.css +79 -0
  380. package/src/styles/repo-activity.css +575 -0
  381. package/src/styles/stages.css +69 -0
  382. package/src/styles/terminal-loaders.css +122 -0
  383. package/src/styles/terminal-manifest.css +228 -0
  384. package/src/styles/web-theme.css +1007 -0
  385. package/src/styles/word-reveal.css +204 -0
  386. package/src/theme/apply-theme.ts +214 -0
  387. package/src/theme/index.ts +27 -0
  388. package/src/theme/palette-registry.ts +855 -0
  389. package/src/theme/tui-prefs.ts +64 -0
  390. package/src/ui/alert.tsx +78 -0
  391. package/src/ui/avatar.tsx +104 -0
  392. package/src/ui/badge.tsx +75 -0
  393. package/src/ui/breadcrumb.tsx +61 -0
  394. package/src/ui/button.tsx +67 -0
  395. package/src/ui/card.tsx +139 -0
  396. package/src/ui/checkbox.tsx +27 -0
  397. package/src/ui/collapsible.tsx +32 -0
  398. package/src/ui/date-pager.tsx +325 -0
  399. package/src/ui/dialog.tsx +157 -0
  400. package/src/ui/dropdown-menu.tsx +267 -0
  401. package/src/ui/empty-state.tsx +165 -0
  402. package/src/ui/field.tsx +104 -0
  403. package/src/ui/form.tsx +36 -0
  404. package/src/ui/icon-button.tsx +36 -0
  405. package/src/ui/index.ts +34 -0
  406. package/src/ui/input.tsx +33 -0
  407. package/src/ui/kbd.tsx +30 -0
  408. package/src/ui/label.tsx +32 -0
  409. package/src/ui/pager.tsx +119 -0
  410. package/src/ui/pagination.tsx +126 -0
  411. package/src/ui/radio-group.tsx +51 -0
  412. package/src/ui/search-bar.tsx +85 -0
  413. package/src/ui/segmented-control.tsx +76 -0
  414. package/src/ui/select.tsx +257 -0
  415. package/src/ui/separator.tsx +24 -0
  416. package/src/ui/sheet.tsx +141 -0
  417. package/src/ui/skeleton.tsx +76 -0
  418. package/src/ui/slider.tsx +76 -0
  419. package/src/ui/switch.tsx +31 -0
  420. package/src/ui/table.tsx +179 -0
  421. package/src/ui/tabs.tsx +89 -0
  422. package/src/ui/tags-input.tsx +168 -0
  423. package/src/ui/textarea.tsx +17 -0
  424. package/src/ui/tooltip.tsx +71 -0
@@ -0,0 +1,188 @@
1
+ "use client";
2
+
3
+ import type { FC, ReactNode } from "react";
4
+ import type { ToolCallMessagePartStatus } from "@assistant-ui/react";
5
+ import { DotMatrix } from "../DotMatrix";
6
+ import { toolRowTitle } from "../stock/tool-display";
7
+ import {
8
+ resolveToolStatus,
9
+ ToolFallbackDuration,
10
+ toolTriggerLabel,
11
+ } from "../stock/tool-fallback.aui";
12
+ import { useTurnOutcome } from "../turn-outcome";
13
+ import { cn } from "./cn";
14
+ import { EN_TRACE_T, useTraceT, type TraceT } from "../trace-i18n";
15
+
16
+ /**
17
+ * One work step in a private session, drawn exactly like the normal row —
18
+ * the same slots, classes, icon, wording and running/done state, so the skin
19
+ * styles it the same — but it is not a disclosure. There is no button, no
20
+ * chevron, no body and no hover change: in a private session the server
21
+ * never sends the arguments, results or reasoning text a body would show
22
+ * (apps/digichat/src/lib/private-stream.ts), so the row has nothing to open.
23
+ *
24
+ * `pointer-events: none` keeps the skin's `:hover` / `:active` rules off it
25
+ * and makes a click on the row land on nothing.
26
+ */
27
+ export type PrivateWorkStepProps = {
28
+ kind: "tool" | "reasoning";
29
+ /** Tool name for a tool step; ignored for reasoning. */
30
+ toolName?: string;
31
+ /** assistant-ui part status type: running | complete | incomplete | requires-action. */
32
+ statusType?: string;
33
+ /** incomplete reason: error | cancelled | … */
34
+ reason?: string;
35
+ isError?: boolean;
36
+ /** Trailing meta on a tool row (the elapsed time), same as the normal row. */
37
+ trailing?: ReactNode;
38
+ };
39
+
40
+ /** A failed call reads as failed even when its part says complete (see `resolveToolStatus`). */
41
+ function toolStatus(
42
+ statusType: string | undefined,
43
+ reason: string | undefined,
44
+ isError: boolean | undefined,
45
+ ): ToolCallMessagePartStatus | undefined {
46
+ if (isError && statusType !== "incomplete") {
47
+ return { type: "incomplete", reason: "error" } as ToolCallMessagePartStatus;
48
+ }
49
+ if (!statusType) return undefined;
50
+ return { type: statusType, ...(reason ? { reason } : {}) } as ToolCallMessagePartStatus;
51
+ }
52
+
53
+ /** The normal rows' words: "Reasoning" for a reasoning row, the upstream tool wording for a tool row. */
54
+ export function privateWorkStepLabel(
55
+ {
56
+ kind,
57
+ statusType,
58
+ reason,
59
+ isError,
60
+ }: Pick<PrivateWorkStepProps, "kind" | "statusType" | "reason" | "isError">,
61
+ tr: TraceT = EN_TRACE_T,
62
+ ): {
63
+ label: string;
64
+ state: string;
65
+ } {
66
+ const running = statusType === "running";
67
+ if (kind === "reasoning") {
68
+ return { label: tr.t("reasoning"), state: running ? "thinking" : "thought" };
69
+ }
70
+ const { label, matrixState } = toolTriggerLabel(toolStatus(statusType, reason, isError), tr);
71
+ return { label, state: matrixState };
72
+ }
73
+
74
+ const INERT = "pointer-events-none cursor-default select-none";
75
+
76
+ export const PrivateWorkStep: FC<PrivateWorkStepProps> = ({
77
+ kind,
78
+ toolName,
79
+ statusType,
80
+ reason,
81
+ isError,
82
+ trailing,
83
+ }) => {
84
+ const tr = useTraceT();
85
+ const running = statusType === "running";
86
+ if (kind === "reasoning") {
87
+ return (
88
+ <div
89
+ data-slot="aui_private-work-step"
90
+ data-kind="reasoning"
91
+ data-state={running ? "thinking" : "thought"}
92
+ className="aui-reasoning-root w-full"
93
+ >
94
+ <div
95
+ data-slot="reasoning-trigger"
96
+ data-private=""
97
+ className={cn(
98
+ "aui-reasoning-trigger text-ink-mute flex w-full items-center gap-2 py-1.5 text-sm",
99
+ INERT,
100
+ )}
101
+ >
102
+ <span
103
+ data-slot="reasoning-trigger-icon"
104
+ className="aui-reasoning-trigger-icon inline-flex size-3.5 shrink-0 items-center justify-center"
105
+ >
106
+ <DotMatrix state={running ? "thinking" : "thought"} decorative className="size-3.5" />
107
+ </span>
108
+ <span
109
+ data-slot="reasoning-trigger-label"
110
+ className={cn(
111
+ "aui-reasoning-trigger-label-wrapper min-w-0 flex-1 truncate text-start leading-none tabular-nums",
112
+ running && "shimmer motion-reduce:animate-none",
113
+ )}
114
+ >
115
+ {tr.t("reasoning")}
116
+ </span>
117
+ </div>
118
+ </div>
119
+ );
120
+ }
121
+ const { label, matrixState, isRunning, isCancelled } = toolTriggerLabel(
122
+ toolStatus(statusType, reason, isError),
123
+ tr,
124
+ );
125
+ return (
126
+ <div
127
+ data-slot="aui_private-work-step"
128
+ data-kind="tool"
129
+ data-state={matrixState}
130
+ className="aui-tool-fallback-root w-full"
131
+ >
132
+ <div
133
+ data-slot="tool-fallback-trigger"
134
+ data-private=""
135
+ className={cn(
136
+ "aui-tool-fallback-trigger text-ink-mute flex w-fit origin-left items-center gap-2 py-1.5 text-sm",
137
+ INERT,
138
+ )}
139
+ >
140
+ <DotMatrix
141
+ state={matrixState}
142
+ decorative
143
+ className="aui-tool-fallback-trigger-icon size-4 shrink-0"
144
+ />
145
+ <span
146
+ data-slot="tool-fallback-trigger-label"
147
+ className={cn(
148
+ "aui-tool-fallback-trigger-label-wrapper inline-block text-start leading-none text-ink",
149
+ isCancelled && "text-ink-mute line-through",
150
+ isRunning && "shimmer motion-reduce:animate-none",
151
+ )}
152
+ >
153
+ {label}: <b>{toolRowTitle(toolName ?? "")}</b>
154
+ </span>
155
+ {trailing}
156
+ </div>
157
+ </div>
158
+ );
159
+ };
160
+
161
+ /**
162
+ * A tool-call part in a private session, with the status rules of the normal
163
+ * row (`ToolFallback`): a failed call reads as failed, a call left waiting
164
+ * when the turn was stopped reads as cancelled, and the elapsed time trails
165
+ * the label. Never the part's custom renderer and never a body.
166
+ */
167
+ export const PrivateToolCallStep: FC<{
168
+ toolName: string;
169
+ status?: ToolCallMessagePartStatus | undefined;
170
+ isError?: boolean | undefined;
171
+ result?: unknown;
172
+ }> = ({ toolName, status, isError, result }) => {
173
+ const outcome = useTurnOutcome();
174
+ const resolved = resolveToolStatus(status, isError, result);
175
+ const effective =
176
+ outcome === "stopped" && resolved?.type === "requires-action"
177
+ ? ({ type: "incomplete", reason: "cancelled" } as const)
178
+ : resolved;
179
+ return (
180
+ <PrivateWorkStep
181
+ kind="tool"
182
+ toolName={toolName}
183
+ statusType={effective?.type}
184
+ reason={(effective as { reason?: string } | undefined)?.reason}
185
+ trailing={<ToolFallbackDuration />}
186
+ />
187
+ );
188
+ };
@@ -0,0 +1,332 @@
1
+ "use client";
2
+
3
+ import {
4
+ createContext,
5
+ useCallback,
6
+ useContext,
7
+ useEffect,
8
+ useLayoutEffect,
9
+ useRef,
10
+ useState,
11
+ } from "react";
12
+ import { cva, type VariantProps } from "class-variance-authority";
13
+ import { DisclosureChevron } from "../disclosure-chevron";
14
+ import { DotMatrix } from "../DotMatrix";
15
+ import {
16
+ Collapsible,
17
+ CollapsibleContent,
18
+ CollapsibleTrigger,
19
+ } from "../../../ui/collapsible";
20
+ import { cn } from "./cn";
21
+ import { useExportKeepMounted } from "../../../replay/export-mount";
22
+ import { useTraceT } from "../trace-i18n";
23
+
24
+ export const ANIMATION_DURATION = 200;
25
+
26
+ const ReasoningPreviewContext = createContext(false);
27
+
28
+ const reasoningVariants = cva("aui-reasoning-root w-full", {
29
+ variants: {
30
+ variant: {
31
+ outline: "rounded-none border px-3 py-2",
32
+ ghost: "",
33
+ muted: "bg-surface-2/50 rounded-none px-3 py-2",
34
+ },
35
+ },
36
+ defaultVariants: {
37
+ variant: "outline",
38
+ },
39
+ });
40
+
41
+ export type ReasoningRootProps = Omit<
42
+ React.ComponentProps<typeof Collapsible>,
43
+ "open" | "onOpenChange"
44
+ > &
45
+ VariantProps<typeof reasoningVariants> & {
46
+ open?: boolean;
47
+ onOpenChange?: (open: boolean) => void;
48
+ defaultOpen?: boolean;
49
+ /**
50
+ * Whether the reasoning is currently streaming. While `true` the
51
+ * disclosure is held open with a bottom-pinned live preview; when
52
+ * streaming ends it returns to `defaultOpen`, and the first manual
53
+ * toggle takes over the open/close state permanently. The live preview
54
+ * keeps following the newest tokens while the disclosure is open during
55
+ * streaming, even after a manual toggle, and pauses while the reader is
56
+ * scrolled up.
57
+ */
58
+ streaming?: boolean;
59
+ /** Called right before the disclosure animates, on toggle and on streaming transitions. */
60
+ onAnimationStart?: () => void;
61
+ };
62
+
63
+ function ReasoningRoot({
64
+ className,
65
+ variant,
66
+ open: controlledOpen,
67
+ onOpenChange: controlledOnOpenChange,
68
+ defaultOpen = false,
69
+ streaming,
70
+ onAnimationStart,
71
+ children,
72
+ ...props
73
+ }: ReasoningRootProps) {
74
+ const [initialOpen] = useState(defaultOpen);
75
+ const [userOpen, setUserOpen] = useState<boolean | null>(null);
76
+
77
+ const isControlled = controlledOpen !== undefined;
78
+ const isOpen = isControlled
79
+ ? controlledOpen
80
+ : (userOpen ?? (streaming || initialOpen));
81
+ const isPreview = streaming === true && isOpen;
82
+
83
+ const prevStreamingRef = useRef(streaming);
84
+ useLayoutEffect(() => {
85
+ if (prevStreamingRef.current === streaming) return;
86
+ prevStreamingRef.current = streaming;
87
+ // A streaming transition only animates the panel when the resting state
88
+ // is collapsed; with `defaultOpen` the disclosure stays open across it.
89
+ if (!isControlled && userOpen === null && !initialOpen) {
90
+ onAnimationStart?.();
91
+ }
92
+ }, [streaming, isControlled, userOpen, initialOpen, onAnimationStart]);
93
+
94
+ const handleOpenChange = useCallback(
95
+ (open: boolean) => {
96
+ onAnimationStart?.();
97
+ if (!isControlled) {
98
+ setUserOpen(open);
99
+ }
100
+ controlledOnOpenChange?.(open);
101
+ },
102
+ [onAnimationStart, isControlled, controlledOnOpenChange],
103
+ );
104
+
105
+ return (
106
+ <Collapsible
107
+ data-slot="reasoning-root"
108
+ data-variant={variant}
109
+ open={isOpen}
110
+ onOpenChange={handleOpenChange}
111
+ className={cn(
112
+ "group/reasoning-root",
113
+ reasoningVariants({ variant, className }),
114
+ )}
115
+ style={
116
+ {
117
+ "--animation-duration": `${ANIMATION_DURATION}ms`,
118
+ } as React.CSSProperties
119
+ }
120
+ {...props}
121
+ >
122
+ <ReasoningPreviewContext.Provider value={isPreview}>
123
+ {children}
124
+ </ReasoningPreviewContext.Provider>
125
+ </Collapsible>
126
+ );
127
+ }
128
+
129
+ function ReasoningFade({
130
+ side = "bottom",
131
+ className,
132
+ ...props
133
+ }: React.ComponentProps<"div"> & { side?: "top" | "bottom" }) {
134
+ if (side === "top") {
135
+ return (
136
+ <div
137
+ data-slot="reasoning-fade"
138
+ className={cn(
139
+ "aui-reasoning-fade pointer-events-none absolute inset-x-0 top-0 z-10 h-8",
140
+ "bg-[linear-gradient(to_bottom,var(--color-background),transparent)]",
141
+ "group-data-[variant=muted]/reasoning-root:bg-[linear-gradient(to_bottom,color-mix(in_oklab,var(--color-muted)_50%,var(--color-background)),transparent)]",
142
+ "fade-in-0 animate-in",
143
+ "animation-duration-(--animation-duration)",
144
+ className,
145
+ )}
146
+ {...props}
147
+ />
148
+ );
149
+ }
150
+
151
+ return (
152
+ <div
153
+ data-slot="reasoning-fade"
154
+ className={cn(
155
+ "aui-reasoning-fade pointer-events-none absolute inset-x-0 bottom-0 z-10 h-8",
156
+ "bg-[linear-gradient(to_top,var(--color-background),transparent)]",
157
+ "group-data-[variant=muted]/reasoning-root:bg-[linear-gradient(to_top,color-mix(in_oklab,var(--color-muted)_50%,var(--color-background)),transparent)]",
158
+ "fade-in-0 animate-in",
159
+ "animation-duration-(--animation-duration)",
160
+ className,
161
+ )}
162
+ {...props}
163
+ />
164
+ );
165
+ }
166
+
167
+ function ReasoningTrigger({
168
+ active,
169
+ duration,
170
+ className,
171
+ ...props
172
+ }: React.ComponentProps<typeof CollapsibleTrigger> & {
173
+ active?: boolean;
174
+ duration?: number;
175
+ }) {
176
+ const reasoningLabel = useTraceT().t("reasoning");
177
+ const durationText = duration ? ` (${duration}s)` : "";
178
+
179
+ return (
180
+ <CollapsibleTrigger
181
+ data-slot="reasoning-trigger"
182
+ className={cn(
183
+ "aui-reasoning-trigger group/trigger text-ink-mute hover:text-ink flex w-full items-center gap-2 py-1.5 text-sm transition-colors",
184
+ className,
185
+ )}
186
+ {...props}
187
+ >
188
+ <span
189
+ data-slot="reasoning-trigger-icon"
190
+ className="aui-reasoning-trigger-icon inline-flex size-3.5 shrink-0 items-center justify-center"
191
+ >
192
+ <DotMatrix
193
+ state={active ? "thinking" : "thought"}
194
+ decorative
195
+ className="size-3.5"
196
+ />
197
+ </span>
198
+ <span
199
+ data-slot="reasoning-trigger-label"
200
+ className={cn(
201
+ "aui-reasoning-trigger-label-wrapper min-w-0 flex-1 truncate text-start leading-none tabular-nums",
202
+ active && "shimmer motion-reduce:animate-none",
203
+ )}
204
+ >
205
+ {reasoningLabel}{durationText}
206
+ </span>
207
+ <DisclosureChevron />
208
+ </CollapsibleTrigger>
209
+ );
210
+ }
211
+
212
+ function ReasoningContent({
213
+ className,
214
+ children,
215
+ ...props
216
+ }: React.ComponentProps<typeof CollapsibleContent>) {
217
+ const isPreview = useContext(ReasoningPreviewContext);
218
+ const keepMounted = useExportKeepMounted();
219
+
220
+ return (
221
+ <CollapsibleContent
222
+ keepMounted={keepMounted}
223
+ data-slot="reasoning-content"
224
+ className={cn(
225
+ "aui-reasoning-content text-ink-mute relative overflow-hidden text-sm outline-none",
226
+ "group/collapsible-content ease-[cubic-bezier(0.32,0.72,0,1)] motion-reduce:animate-none",
227
+ "data-closed:animate-collapsible-up",
228
+ "data-open:animate-collapsible-down",
229
+ "data-closed:fill-mode-forwards",
230
+ "data-closed:pointer-events-none",
231
+ "[--tw-duration:var(--animation-duration)]",
232
+ className,
233
+ )}
234
+ {...props}
235
+ >
236
+ <ReasoningFade side="top" />
237
+ {children}
238
+ {isPreview ? <ReasoningFade /> : null}
239
+ </CollapsibleContent>
240
+ );
241
+ }
242
+
243
+ function ReasoningText({
244
+ className,
245
+ children,
246
+ ...props
247
+ }: React.ComponentProps<"div">) {
248
+ const isPreview = useContext(ReasoningPreviewContext);
249
+ const scrollRef = useRef<HTMLDivElement>(null);
250
+ const contentRef = useRef<HTMLDivElement>(null);
251
+
252
+ useEffect(() => {
253
+ if (!isPreview) return;
254
+ const scrollEl = scrollRef.current;
255
+ const contentEl = contentRef.current;
256
+ if (!scrollEl || !contentEl) return;
257
+
258
+ let pinned = true;
259
+ let lastScrollTop = scrollEl.scrollTop;
260
+ let lastScrollHeight = scrollEl.scrollHeight;
261
+ const isAtBottom = () =>
262
+ Math.abs(
263
+ scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight,
264
+ ) <= 1 || scrollEl.scrollHeight <= scrollEl.clientHeight;
265
+
266
+ const pin = () => {
267
+ if (!pinned) return;
268
+ scrollEl.scrollTop = scrollEl.scrollHeight;
269
+ };
270
+ // A pin's own scroll event can arrive after new content grew the scroll
271
+ // height and read as "not at bottom"; only an upward move at unchanged
272
+ // scroll height is user intent.
273
+ const onScroll = () => {
274
+ if (isAtBottom()) {
275
+ pinned = true;
276
+ } else if (
277
+ scrollEl.scrollTop < lastScrollTop &&
278
+ scrollEl.scrollHeight === lastScrollHeight
279
+ ) {
280
+ pinned = false;
281
+ }
282
+ lastScrollTop = scrollEl.scrollTop;
283
+ lastScrollHeight = scrollEl.scrollHeight;
284
+ };
285
+
286
+ pin();
287
+ scrollEl.addEventListener("scroll", onScroll);
288
+ const observer = new ResizeObserver(pin);
289
+ observer.observe(contentEl);
290
+ return () => {
291
+ scrollEl.removeEventListener("scroll", onScroll);
292
+ observer.disconnect();
293
+ };
294
+ }, [isPreview]);
295
+
296
+ return (
297
+ <div
298
+ ref={scrollRef}
299
+ data-slot="reasoning-text"
300
+ className={cn(
301
+ "aui-reasoning-text relative z-0 max-h-64 overflow-y-auto ps-6 pt-2 pb-2 leading-relaxed text-pretty",
302
+ "transform-gpu transition-[transform,opacity] ease-[cubic-bezier(0.32,0.72,0,1)]",
303
+ "motion-reduce:animate-none",
304
+ "group-data-open/collapsible-content:animate-in",
305
+ "group-data-closed/collapsible-content:animate-out",
306
+ "group-data-open/collapsible-content:fade-in-0",
307
+ "group-data-closed/collapsible-content:fade-out-0",
308
+ "group-data-open/collapsible-content:slide-in-from-top-4",
309
+ "group-data-closed/collapsible-content:slide-out-to-top-4",
310
+ "group-data-open/collapsible-content:blur-in-[2px]",
311
+ "group-data-closed/collapsible-content:blur-out-[2px]",
312
+ "group-data-open/collapsible-content:animation-duration-(--animation-duration)",
313
+ "group-data-closed/collapsible-content:animation-duration-(--animation-duration)",
314
+ className,
315
+ )}
316
+ {...props}
317
+ >
318
+ <div ref={contentRef} className="aui-reasoning-text-content">
319
+ {children}
320
+ </div>
321
+ </div>
322
+ );
323
+ }
324
+
325
+ export {
326
+ ReasoningRoot,
327
+ ReasoningTrigger,
328
+ ReasoningContent,
329
+ ReasoningText,
330
+ ReasoningFade,
331
+ reasoningVariants,
332
+ };
@@ -0,0 +1,174 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Whether the thread follows the answer, or leaves the scroll to the reader.
5
+ *
6
+ * `follow` (the default) anchors the submitted question at the top of the
7
+ * viewport and then chases the bottom of the stream, so the answer is being
8
+ * read as it is written. `free` never moves the viewport — not when a message
9
+ * is sent, not while it streams — and is for readers who scroll back through
10
+ * the transcript while a long answer arrives.
11
+ *
12
+ * `ThreadPrimitive.Viewport` can express both, but its defaults are the
13
+ * half-configured state this module replaces: `autoScroll` defaults to false
14
+ * under `turnAnchor="top"`, and while a top anchor is active during a run the
15
+ * library deliberately stops following. So `follow` is the anchor plus our own
16
+ * chase, and one value here fans out to the explicit prop set the viewport
17
+ * gets.
18
+ */
19
+
20
+ import { useEffect } from "react";
21
+
22
+ export type ScrollMode = "follow" | "free";
23
+
24
+ export const SCROLL_MODES = ["follow", "free"] as const;
25
+ export const DEFAULT_SCROLL_MODE: ScrollMode = "follow";
26
+ export const SCROLL_STORAGE_KEY = "dt-scroll";
27
+
28
+ /**
29
+ * How close to the bottom counts as "still following". A reader who scrolls
30
+ * up past this is reading something older, and the chase stops until they
31
+ * come back down.
32
+ */
33
+ const FOLLOW_BOTTOM_SLACK_PX = 24;
34
+
35
+ export function normalizeScrollMode(value: unknown): ScrollMode | undefined {
36
+ if (value === "follow" || value === "free") return value;
37
+ return undefined;
38
+ }
39
+
40
+ /**
41
+ * A stored choice beats the deployment default, which beats `follow`. An
42
+ * unknown value from either side is ignored rather than treated as a mode.
43
+ */
44
+ export function resolveScrollMode(stored: unknown, deploy: unknown): ScrollMode {
45
+ return (
46
+ normalizeScrollMode(stored) ??
47
+ normalizeScrollMode(deploy) ??
48
+ DEFAULT_SCROLL_MODE
49
+ );
50
+ }
51
+
52
+ export type ScrollViewportProps = {
53
+ turnAnchor: "top" | "bottom";
54
+ autoScroll: boolean;
55
+ scrollToBottomOnRunStart: boolean;
56
+ scrollToBottomOnInitialize: boolean;
57
+ scrollToBottomOnThreadSwitch: boolean;
58
+ };
59
+
60
+ /**
61
+ * The exact viewport prop set for a mode.
62
+ *
63
+ * `free` turns every trigger off explicitly. Leaving one to its default is
64
+ * how the mode silently starts moving again — the library defaults
65
+ * `scrollToBottomOnRunStart` and the other two to true.
66
+ */
67
+ export function scrollModeProps(mode: ScrollMode | undefined): ScrollViewportProps {
68
+ if (mode === "free") {
69
+ return {
70
+ turnAnchor: "bottom",
71
+ autoScroll: false,
72
+ scrollToBottomOnRunStart: false,
73
+ scrollToBottomOnInitialize: false,
74
+ scrollToBottomOnThreadSwitch: false,
75
+ };
76
+ }
77
+ return {
78
+ turnAnchor: "top",
79
+ autoScroll: true,
80
+ scrollToBottomOnRunStart: true,
81
+ scrollToBottomOnInitialize: true,
82
+ scrollToBottomOnThreadSwitch: true,
83
+ };
84
+ }
85
+
86
+ export function readStoredScrollMode(
87
+ storage?: { getItem(key: string): string | null } | null,
88
+ ): ScrollMode | undefined {
89
+ const store =
90
+ storage === undefined
91
+ ? typeof window === "undefined"
92
+ ? null
93
+ : window.localStorage
94
+ : storage;
95
+ if (!store) return undefined;
96
+ try {
97
+ return normalizeScrollMode(store.getItem(SCROLL_STORAGE_KEY));
98
+ } catch {
99
+ return undefined;
100
+ }
101
+ }
102
+
103
+ export function writeStoredScrollMode(mode: ScrollMode): void {
104
+ if (typeof window === "undefined") return;
105
+ try {
106
+ window.localStorage.setItem(SCROLL_STORAGE_KEY, mode);
107
+ } catch {
108
+ /* private mode or blocked storage — the session still follows the pref */
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Chase the bottom of the stream while the reader is at the bottom.
114
+ *
115
+ * The library stops following as soon as a top anchor is active and a run is
116
+ * underway, which is why a submitted question pins and the answer then grows
117
+ * below the fold. This reads as one rule: keep the newest line in view unless
118
+ * the reader has taken the scroll back.
119
+ *
120
+ * Smoothness comes from the viewport's own `scroll-behavior: smooth`; the
121
+ * assignments here are targets, not animations, so a stream that lands many
122
+ * targets a second retargets the same smooth scroll instead of stacking.
123
+ */
124
+ export function useFollowStream(
125
+ viewport: HTMLElement | null,
126
+ enabled: boolean,
127
+ /**
128
+ * Changes when a new turn starts (the message count). A send is an explicit
129
+ * intent to read the answer, so it clears a pause the reader had taken.
130
+ */
131
+ resumeKey: number = 0,
132
+ ): void {
133
+ useEffect(() => {
134
+ if (!viewport || !enabled) return;
135
+ let paused = false;
136
+ let lastTop = viewport.scrollTop;
137
+ let frame = 0;
138
+
139
+ const atBottom = () =>
140
+ viewport.scrollHeight - viewport.scrollTop - viewport.clientHeight <=
141
+ FOLLOW_BOTTOM_SLACK_PX;
142
+
143
+ const chase = () => {
144
+ frame = 0;
145
+ if (paused) return;
146
+ if (!atBottom()) viewport.scrollTop = viewport.scrollHeight;
147
+ };
148
+ const schedule = () => {
149
+ if (frame) return;
150
+ frame = requestAnimationFrame(chase);
151
+ };
152
+ const onScroll = () => {
153
+ const top = viewport.scrollTop;
154
+ if (atBottom()) paused = false;
155
+ else if (top < lastTop) paused = true;
156
+ lastTop = top;
157
+ };
158
+
159
+ const observer = new ResizeObserver(schedule);
160
+ const inner = viewport.firstElementChild;
161
+ if (inner) observer.observe(inner);
162
+ observer.observe(viewport);
163
+ viewport.addEventListener("scroll", onScroll, { passive: true });
164
+ // A question sent while the reader is parked mid-transcript pins to the
165
+ // top and then follows: sending is an explicit intent to read the answer.
166
+ schedule();
167
+
168
+ return () => {
169
+ observer.disconnect();
170
+ viewport.removeEventListener("scroll", onScroll);
171
+ if (frame) cancelAnimationFrame(frame);
172
+ };
173
+ }, [viewport, enabled, resumeKey]);
174
+ }