@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,144 @@
1
+ /**
2
+ * Same-window signal that the DigiChat boot animation has settled.
3
+ * DigichatBootLoader dispatches it; surfaces that reveal copy after the boot
4
+ * (e.g. the welcome body typewriter) listen for it so their animation is not
5
+ * spent behind a boot overlay.
6
+ */
7
+ export const DIGI_CHAT_READY_EVENT = "digichat:ready";
8
+
9
+ /** Mark the boot as settled for this document (idempotent). */
10
+ export function signalDigichatReady(): void {
11
+ if (typeof document === "undefined") return;
12
+ document.documentElement.dataset.digichatReady = "1";
13
+ window.dispatchEvent(new Event(DIGI_CHAT_READY_EVENT));
14
+ }
15
+
16
+ /** Whether the boot already settled in this document. */
17
+ export function hasDigichatReady(): boolean {
18
+ return (
19
+ typeof document !== "undefined" &&
20
+ document.documentElement.dataset.digichatReady === "1"
21
+ );
22
+ }
23
+
24
+ /**
25
+ * Same-window signal that the boot overlay has left the stage (it starts
26
+ * fading). Surfaces that hold their choreography until the handoff - e.g. the
27
+ * welcome typewriter in "takeover" handoff mode - listen for it.
28
+ */
29
+ export const DIGI_CHAT_REVEALED_EVENT = "digichat:boot-revealed";
30
+
31
+ /** Mark the boot handoff as started for this document (idempotent). */
32
+ export function signalDigichatRevealed(): void {
33
+ if (typeof document === "undefined") return;
34
+ document.documentElement.dataset.digichatRevealed = "1";
35
+ window.dispatchEvent(new Event(DIGI_CHAT_REVEALED_EVENT));
36
+ }
37
+
38
+ /** Whether the boot handoff already started in this document. */
39
+ export function hasDigichatRevealed(): boolean {
40
+ return (
41
+ typeof document !== "undefined" &&
42
+ document.documentElement.dataset.digichatRevealed === "1"
43
+ );
44
+ }
45
+
46
+ /**
47
+ * Boot-step channel: the app reports real milestones as they happen
48
+ * (deployment configuration applied, chat runtime up) so the boot animation
49
+ * can complete its rows against the actual boot instead of a fixed timeline.
50
+ */
51
+ export const DIGI_CHAT_BOOT_STEP_EVENT = "digichat:boot-step";
52
+
53
+ /**
54
+ * Real boot milestones the app reports.
55
+ * `services` lands once every sleep-on-idle backend the chat needs has
56
+ * answered its warm-up probe. The iframe host reports that step.
57
+ */
58
+ export type DigichatBootStep = "config" | "runtime" | "services";
59
+
60
+ /** Report a real boot milestone for this document (idempotent per step). */
61
+ export function signalDigichatBootStep(step: DigichatBootStep): void {
62
+ if (typeof document === "undefined") return;
63
+ const root = document.documentElement;
64
+ const done = root.dataset.digichatBootSteps?.split(",") ?? [];
65
+ if (done.includes(step)) return;
66
+ root.dataset.digichatBootSteps = [...done, step].join(",");
67
+ window.dispatchEvent(
68
+ new CustomEvent(DIGI_CHAT_BOOT_STEP_EVENT, { detail: step }),
69
+ );
70
+ }
71
+
72
+ /** Boot milestones already reported in this document. */
73
+ export function digichatBootSteps(): readonly string[] {
74
+ if (typeof document === "undefined") return [];
75
+ return document.documentElement.dataset.digichatBootSteps?.split(",") ?? [];
76
+ }
77
+
78
+ /** Milliseconds since this document started loading (boot clock). */
79
+ export function digichatBootClockMs(): number {
80
+ return typeof performance === "undefined" ? 0 : performance.now();
81
+ }
82
+
83
+ /**
84
+ * Lab switch: `?handoff=` picks how the boot hands off to the chat.
85
+ * Comma-separated: `reveal` (re-run the hero entrance), `type` (welcome
86
+ * takeover), `drift` (motion match), `beat` (pause before the fade).
87
+ */
88
+ export type DigichatHandoff = {
89
+ reveal: boolean;
90
+ type: boolean;
91
+ drift: boolean;
92
+ beat: boolean;
93
+ };
94
+
95
+ /**
96
+ * Parse the `?handoff=` lab switch. The reveal hand-off ships by default;
97
+ * `?handoff=none` (or `off`) restores the hard cut, and any other comma list
98
+ * opts into exactly those modes.
99
+ */
100
+ export function resolveHandoff(): DigichatHandoff {
101
+ const off: DigichatHandoff = {
102
+ reveal: false,
103
+ type: false,
104
+ drift: false,
105
+ beat: false,
106
+ };
107
+ if (typeof window === "undefined") return off;
108
+ const raw = new URLSearchParams(window.location.search).get("handoff");
109
+ if (raw === null) return { ...off, reveal: true };
110
+ const modes = new Set(
111
+ raw
112
+ .split(",")
113
+ .map((mode) => mode.trim())
114
+ .filter(Boolean),
115
+ );
116
+ if (modes.has("none") || modes.has("off")) return off;
117
+ return {
118
+ reveal: modes.has("reveal"),
119
+ type: modes.has("type"),
120
+ drift: modes.has("drift"),
121
+ beat: modes.has("beat"),
122
+ };
123
+ }
124
+
125
+ /**
126
+ * Service warm-up phase (sleep-on-idle backends). The app sets it while it
127
+ * waits for /api/embed/warmup; the boot loader and the assistant pending row
128
+ * read it to say "Waking up services…" instead of a separate banner.
129
+ */
130
+ export type DigichatWarmupPhase = "idle" | "waking" | "ready" | "error";
131
+ export const DIGI_CHAT_WARMUP_EVENT = "digichat:warmup";
132
+
133
+ export function setDigichatWarmupPhase(phase: DigichatWarmupPhase): void {
134
+ if (typeof document === "undefined") return;
135
+ const root = document.documentElement;
136
+ if (root.dataset.digichatWarmup === phase) return;
137
+ root.dataset.digichatWarmup = phase;
138
+ window.dispatchEvent(new CustomEvent(DIGI_CHAT_WARMUP_EVENT, { detail: phase }));
139
+ }
140
+
141
+ export function getDigichatWarmupPhase(): DigichatWarmupPhase {
142
+ if (typeof document === "undefined") return "idle";
143
+ return (document.documentElement.dataset.digichatWarmup as DigichatWarmupPhase) || "idle";
144
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Surface class strings for the first-party digichat Thread — the digiweb analog
3
+ * of assistant-ui `surfaces.tsx`. Paper / field / live / mono / code sit on
4
+ * `[data-theme]` + `--term-*` + rose livery (see styles/chat-aui.css). No pills.
5
+ */
6
+
7
+ export const DIGICHAT_GLYPHS = {
8
+ user: ">",
9
+ assistant: "▸",
10
+ system: "·",
11
+ } as const;
12
+
13
+ export const digichatSurfaces = {
14
+ thread:
15
+ "digichat-thread aui-root aui-thread-root flex h-full min-h-0 flex-col bg-term-bg font-mono text-term-ink",
16
+ viewport:
17
+ "digichat-thread__viewport flex min-h-0 flex-1 flex-col gap-[0.55rem] overflow-y-auto overscroll-contain px-[0.9rem] pt-[0.75rem] pb-[0.85rem]",
18
+ footer:
19
+ "digichat-thread__footer aui-thread-viewport-footer sticky bottom-0 mt-auto flex flex-col gap-[0.4rem] bg-term-bg pt-[0.35rem] pb-[0.35rem]",
20
+ empty: "digichat-thread__empty aui-thread-empty flex flex-col gap-[0.7rem]",
21
+ welcome: "aui-thread-welcome-root flex flex-col gap-[0.45rem]",
22
+ welcomeTitle:
23
+ "aui-thread-welcome-message-inner m-0 max-w-[36rem] font-mono text-[1.05rem] font-normal leading-[1.4] tracking-[-0.02em] text-term-ink",
24
+ welcomeBody:
25
+ "aui-thread-welcome-copy m-0 max-w-[46ch] font-mono text-[0.82rem] font-normal leading-[1.45] text-term-mute",
26
+ examples: "aui-thread-welcome-suggestions flex flex-col gap-[0.1rem]",
27
+ example:
28
+ "digichat-example aui-thread-welcome-suggestion grid cursor-pointer grid-cols-[1.25rem_minmax(0,1fr)] items-baseline gap-x-[0.55rem] rounded-none border-0 bg-transparent px-0 py-[0.15rem] text-left font-mono text-[0.82rem] text-ink-soft",
29
+ exampleMark: "select-none font-mono text-[0.88rem] leading-[1.45] text-term-ink",
30
+ turn: "digichat-turn flex flex-col items-stretch gap-[0.2rem]",
31
+ composer:
32
+ "digichat-composer aui-composer-root flex flex-col gap-[0.35rem] rounded-none border border-hair bg-transparent px-[0.75rem] pt-[0.55rem] pb-[0.45rem]",
33
+ composerRow: "flex items-start gap-[0.55rem]",
34
+ composerGlyph: "shrink-0 select-none font-mono text-[0.9rem] leading-[1.5] text-ink",
35
+ composerInput:
36
+ "aui-composer-input min-h-[1.5rem] w-full resize-none border-0 bg-transparent font-mono text-[0.9rem] leading-[1.5] text-ink outline-none",
37
+ composerTray: "flex items-center justify-between gap-[0.75rem]",
38
+ action:
39
+ "digichat-action inline-flex cursor-pointer items-center rounded-none border-0 bg-transparent p-0 font-mono text-[0.66rem] tracking-[0.02em] text-ink-mute",
40
+ actionRow:
41
+ "digichat-action-row mt-[0.25rem] ml-[1.8rem] flex flex-wrap items-center gap-[0.75rem]",
42
+ send: "aui-composer-send inline-flex h-8 cursor-pointer items-center justify-center rounded-none font-mono text-[0.72rem]",
43
+ stop: "inline-flex h-8 cursor-pointer items-center justify-center rounded-none border border-hair bg-transparent px-[0.85rem] font-mono text-[0.72rem] text-ink",
44
+ scrollBtn:
45
+ "digichat-scroll-btn mx-auto cursor-pointer rounded-none border border-hair bg-surface px-[0.6rem] py-[0.2rem] font-mono text-[0.66rem] text-ink-mute",
46
+ attach: "digichat-attach inline-flex items-center gap-[0.35rem] border border-hair px-[0.45rem] py-[0.15rem] font-mono text-[0.66rem] text-ink-soft",
47
+ error: "ml-[1.8rem] mt-[0.35rem] border border-danger/40 px-[0.7rem] py-[0.4rem] font-mono text-[0.78rem] text-danger",
48
+ list: "digichat-thread-list flex w-56 shrink-0 flex-col border-r border-term-hair bg-term-bg font-mono",
49
+ listItem:
50
+ "digichat-thread-list__item block h-7 w-full truncate rounded-none border-0 bg-transparent px-[0.7rem] py-0 text-left font-mono text-[0.75rem] leading-7 text-term-ink data-[active]:bg-term-fill",
51
+ pane: "flex h-full min-h-0 flex-col rounded-none border border-term-hair bg-term-bg",
52
+ } as const;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The pre-response status line (DIG-4459).
3
+ *
4
+ * Before the agent answers, the loading row shows the animation on its own.
5
+ * It carries text only when the server actually told us something: a
6
+ * `data-connection` part with a `message` ("Waking up services…", "Waiting
7
+ * for model capacity — retrying in 8s"). A bare state such as `connecting`
8
+ * is just the wait for a response, so it gets no text, and the client never
9
+ * makes up a default line of its own.
10
+ */
11
+ type MessagePartLike = {
12
+ readonly type: string;
13
+ readonly name?: string;
14
+ readonly data?: unknown;
15
+ };
16
+
17
+ /** States that end the pre-response phase: any earlier message is stale. */
18
+ const SETTLED_STATES = new Set(["connected", "ready"]);
19
+
20
+ /**
21
+ * The status text the server sent for this turn, or null. The latest
22
+ * connection part wins; a settled state clears the line.
23
+ */
24
+ export function connectionStatusText(
25
+ parts: readonly MessagePartLike[],
26
+ ): string | null {
27
+ let text: string | null = null;
28
+ for (const part of parts) {
29
+ if (part.type !== "data" || part.name !== "connection") continue;
30
+ const data = (part.data ?? {}) as { state?: unknown; message?: unknown };
31
+ if (typeof data.state === "string" && SETTLED_STATES.has(data.state)) {
32
+ text = null;
33
+ continue;
34
+ }
35
+ const message =
36
+ typeof data.message === "string" ? data.message.trim() : "";
37
+ text = message.length > 0 ? message : null;
38
+ }
39
+ return text;
40
+ }
@@ -0,0 +1,355 @@
1
+ /**
2
+ * DIGICHAT block wordmark.
3
+ *
4
+ * Glyph cells are 7×10. A terminal cell is about twice as tall as it is wide,
5
+ * so the TUI draws with half-blocks (▀ ▄ █), the same method as
6
+ * digivoice/tui/src/hero.js. D, I, G, C, H, and T are that file's bitmaps.
7
+ * Gaps stay empty. One color mode per cell: 38;2 only when truecolor is on,
8
+ * otherwise 38;5. Never both.
9
+ *
10
+ * The settled word is the mark. The scramble plays once per session, then one
11
+ * letter flashes. It does not loop.
12
+ */
13
+
14
+ export const WORD = "DIGICHAT";
15
+ export const STEP_MS = 80;
16
+ export const SPIN_MS = 240;
17
+ export const LOCK_MS = 180;
18
+ export const HOLD_MS = 960;
19
+ export const FLASH_MS = 200;
20
+ /** SPIN + 8 * LOCK + HOLD = 2.64s. */
21
+ export const CYCLE_MS = SPIN_MS + 8 * LOCK_MS + HOLD_MS;
22
+ /** Inside the hold, after the last lock flash. */
23
+ export const SETTLED_MS = 2000;
24
+ /** Quiet stretch between single-letter flashes after the scramble. */
25
+ export const IDLE_GAP_MS = 6400;
26
+ export const WORDMARK_SESSION_KEY = "digichat:wordmark-played";
27
+ export const WORDMARK_CLOCK_HOST = "__digichatWordmarkClock";
28
+
29
+ export const POOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?#$%&*+-=/<>().,:;@";
30
+
31
+ export const SHADES = {
32
+ dim: { rgb: 95, cube: 59 },
33
+ rest: { rgb: 215, cube: 188 },
34
+ flash: { rgb: 255, cube: 231 },
35
+ } as const;
36
+
37
+ export type ShadeName = keyof typeof SHADES;
38
+ export type CellColor = { rgb: number } | { cube: number };
39
+
40
+ export type WordCell = {
41
+ ch: string;
42
+ color: CellColor | null;
43
+ };
44
+
45
+ export type SlotFrame = {
46
+ ch: string | null;
47
+ shade: ShadeName;
48
+ };
49
+
50
+ const GLYPHS: Record<string, readonly string[]> = {
51
+ A: ["..###..", ".#####.", "##...##", "##...##", "#######", "#######", "##...##", "##...##", "##...##", "##...##"],
52
+ B: ["######.", "#######", "##...##", "##...##", "######.", "######.", "##...##", "##...##", "#######", "######."],
53
+ C: [".#####.", "#######", "##.....", "##.....", "##.....", "##.....", "##.....", "##.....", "#######", ".#####."],
54
+ D: ["######.", "#######", "##...##", "##...##", "##...##", "##...##", "##...##", "##...##", "#######", "######."],
55
+ E: ["#######", "#######", "##.....", "##.....", "######.", "######.", "##.....", "##.....", "#######", "#######"],
56
+ F: ["#######", "#######", "##.....", "##.....", "######.", "######.", "##.....", "##.....", "##.....", "##....."],
57
+ G: [".#####.", "#######", "##.....", "##.....", "##..###", "##..###", "##...##", "##...##", "#######", ".#####."],
58
+ H: ["##...##", "##...##", "##...##", "##...##", "#######", "#######", "##...##", "##...##", "##...##", "##...##"],
59
+ I: ["#######", "#######", "..##...", "..##...", "..##...", "..##...", "..##...", "..##...", "#######", "#######"],
60
+ J: ["...####", "...####", ".....##", ".....##", ".....##", ".....##", "##...##", "##...##", "#######", ".#####."],
61
+ K: ["##...##", "##..##.", "##.##..", "####...", "###....", "####...", "##.##..", "##..##.", "##...##", "##...##"],
62
+ L: ["##.....", "##.....", "##.....", "##.....", "##.....", "##.....", "##.....", "##.....", "#######", "#######"],
63
+ M: ["##...##", "###.###", "##.#.##", "##.#.##", "##...##", "##...##", "##...##", "##...##", "##...##", "##...##"],
64
+ N: ["##...##", "###..##", "###..##", "##.#.##", "##.#.##", "##..###", "##..###", "##...##", "##...##", "##...##"],
65
+ O: [".#####.", "#######", "##...##", "##...##", "##...##", "##...##", "##...##", "##...##", "#######", ".#####."],
66
+ P: ["######.", "#######", "##...##", "##...##", "#######", "######.", "##.....", "##.....", "##.....", "##....."],
67
+ Q: [".#####.", "#######", "##...##", "##...##", "##...##", "##.#.##", "##..##.", "##...##", "#######", ".####.#"],
68
+ R: ["######.", "#######", "##...##", "##...##", "#######", "######.", "##.##..", "##..##.", "##...##", "##...##"],
69
+ S: [".######", "#######", "##.....", "##.....", "######.", "######.", ".....##", ".....##", "#######", "######."],
70
+ T: ["#######", "#######", "...##..", "...##..", "...##..", "...##..", "...##..", "...##..", "...##..", "...##.."],
71
+ U: ["##...##", "##...##", "##...##", "##...##", "##...##", "##...##", "##...##", "##...##", "#######", ".#####."],
72
+ V: ["##...##", "##...##", "##...##", "##...##", "##...##", "##...##", "##...##", "##...##", ".#####.", "..###.."],
73
+ W: ["##...##", "##...##", "##...##", "##...##", "##.#.##", "##.#.##", "##.#.##", "###.###", ".#####.", ".##.##."],
74
+ X: ["##...##", "##...##", ".##.##.", "..###..", "..###..", "..###..", ".##.##.", "##...##", "##...##", "##...##"],
75
+ Y: ["##...##", "##...##", "##...##", ".##.##.", "..###..", "...##..", "...##..", "...##..", "...##..", "...##.."],
76
+ Z: ["#######", "#######", ".....##", "....##.", "...##..", "..##...", ".##....", "##.....", "#######", "#######"],
77
+ "0": [".#####.", "#######", "##...##", "##..###", "##.#.##", "###..##", "##...##", "##...##", "#######", ".#####."],
78
+ "1": ["..##...", ".###...", "####...", "..##...", "..##...", "..##...", "..##...", "..##...", "#######", "#######"],
79
+ "2": [".#####.", "#######", ".....##", ".....##", ".#####.", "#####..", "##.....", "##.....", "#######", "#######"],
80
+ "3": [".#####.", "#######", ".....##", ".....##", "..####.", "..####.", ".....##", ".....##", "#######", ".#####."],
81
+ "4": ["...##..", "..###..", ".#.##..", "##.##..", "##.##..", "#######", "#######", "...##..", "...##..", "...##.."],
82
+ "5": ["#######", "#######", "##.....", "##.....", "######.", ".######", ".....##", ".....##", "#######", "######."],
83
+ "6": [".#####.", "#######", "##.....", "##.....", "######.", "#######", "##...##", "##...##", "#######", ".#####."],
84
+ "7": ["#######", "#######", ".....##", "....##.", "...##..", "..##...", "..##...", "..##...", "..##...", "..##..."],
85
+ "8": [".#####.", "#######", "##...##", "##...##", ".#####.", ".#####.", "##...##", "##...##", "#######", ".#####."],
86
+ "9": [".#####.", "#######", "##...##", "##...##", "#######", ".######", ".....##", ".....##", "#######", ".#####."],
87
+ "!": ["..##...", "..##...", "..##...", "..##...", "..##...", "..##...", ".......", "..##...", "..##...", "......."],
88
+ "?": [".#####.", "#######", "##...##", "....##.", "...##..", "..##...", ".......", "..##...", "..##...", "......."],
89
+ "#": [".##.##.", ".##.##.", "#######", "#######", ".##.##.", ".##.##.", "#######", "#######", ".##.##.", ".##.##."],
90
+ $: ["..##...", ".######", "##.##..", "##.....", ".#####.", ".....##", "..##.##", "######.", "..##...", "..##..."],
91
+ "%": ["##...##", "##..##.", "##.##..", "##.#...", "..##...", "...#.##", "..##.##", ".##..##", "##...##", "##...##"],
92
+ "&": [".##....", "###....", "##.....", ".####..", "##..##.", "##..##.", "##..##.", "##..##.", ".####.#", "..##.##"],
93
+ "*": [".......", "##...##", ".##.##.", "..###..", "#######", "..###..", ".##.##.", "##...##", ".......", "......."],
94
+ "+": [".......", "..##...", "..##...", "..##...", "#######", "#######", "..##...", "..##...", "..##...", "......."],
95
+ "-": [".......", ".......", ".......", ".......", "#######", "#######", ".......", ".......", ".......", "......."],
96
+ "=": [".......", ".......", "#######", "#######", ".......", ".......", "#######", "#######", ".......", "......."],
97
+ "/": [".....##", "....##.", "....##.", "...##..", "...##..", "..##...", "..##...", ".##....", ".##....", "##....."],
98
+ "<": ["....##.", "...##..", "..##...", ".##....", "##.....", "##.....", ".##....", "..##...", "...##..", "....##."],
99
+ ">": [".##....", "..##...", "...##..", "....##.", ".....##", ".....##", "....##.", "...##..", "..##...", ".##...."],
100
+ "(": ["...##..", "..##...", ".##....", "##.....", "##.....", "##.....", "##.....", ".##....", "..##...", "...##.."],
101
+ ")": ["..##...", "...##..", "....##.", ".....##", ".....##", ".....##", ".....##", "....##.", "...##..", "..##..."],
102
+ ".": [".......", ".......", ".......", ".......", ".......", ".......", ".......", "..##...", "..##...", "......."],
103
+ ",": [".......", ".......", ".......", ".......", ".......", ".......", "..##...", "..##...", "...##..", "..##..."],
104
+ ":": [".......", "..##...", "..##...", ".......", ".......", ".......", "..##...", "..##...", ".......", "......."],
105
+ ";": [".......", "..##...", "..##...", ".......", ".......", "..##...", "..##...", "...##..", "..##...", "......."],
106
+ "@": [".#####.", "##...##", "##.###.", "##.#.##", "##.#.##", "##.###.", "##.....", "##...##", ".#####.", "......."],
107
+ };
108
+
109
+ export function glyphOf(ch: string): readonly string[] | null {
110
+ return GLYPHS[ch] ?? null;
111
+ }
112
+
113
+ export function letterGap(cols: number, letters: number): number {
114
+ for (const gap of [2, 1, 0]) {
115
+ const width = letters * 7 + Math.max(0, letters - 1) * gap;
116
+ if (width <= Math.max(1, cols - 2)) return gap;
117
+ }
118
+ return 0;
119
+ }
120
+
121
+ export function truecolorEnabled(colorterm: string | undefined): boolean {
122
+ const value = (colorterm ?? "").toLowerCase();
123
+ return value === "truecolor" || value === "24bit";
124
+ }
125
+
126
+ function mod(tMs: number, cycle: number): number {
127
+ const t = Number.isFinite(tMs) ? Math.floor(tMs) : 0;
128
+ return ((t % cycle) + cycle) % cycle;
129
+ }
130
+
131
+ function poolChar(slot: number, step: number): string | null {
132
+ let x = Math.imul(step + 1, 0x9e3779b1) ^ Math.imul(slot + 1, 0x85ebca6b);
133
+ x = Math.imul(x ^ (x >>> 16), 0x7feb352d);
134
+ x = (x ^ (x >>> 15)) >>> 0;
135
+ for (let i = 0; i < POOL.length; i += 1) {
136
+ const ch = POOL[(x + i) % POOL.length];
137
+ if (ch && GLYPHS[ch]) return ch;
138
+ }
139
+ return null;
140
+ }
141
+
142
+ export function slotsAt(tMs: number, word = WORD): SlotFrame[] {
143
+ const letters = word.toUpperCase();
144
+ const t = mod(tMs, CYCLE_MS);
145
+ const frames: SlotFrame[] = [];
146
+ for (let slot = 0; slot < letters.length; slot += 1) {
147
+ const letter = letters[slot] ?? "";
148
+ const lockAt = SPIN_MS + slot * LOCK_MS;
149
+ if (t < lockAt) {
150
+ frames.push({ ch: poolChar(slot, Math.floor(t / STEP_MS)), shade: "dim" });
151
+ continue;
152
+ }
153
+ const known = Boolean(GLYPHS[letter]);
154
+ const shade: ShadeName = t < lockAt + FLASH_MS ? "flash" : "rest";
155
+ frames.push({ ch: known ? letter : null, shade });
156
+ }
157
+ return frames;
158
+ }
159
+
160
+ /** Settled word. One letter flashes, then the word rests. Characters never scramble. */
161
+ export function idleSlots(idleElapsed: number, word = WORD): SlotFrame[] {
162
+ const base = slotsAt(SETTLED_MS, word);
163
+ const span = IDLE_GAP_MS + FLASH_MS;
164
+ const elapsed = Number.isFinite(idleElapsed) ? Math.max(0, idleElapsed) : 0;
165
+ if (elapsed % span < IDLE_GAP_MS) return base;
166
+ const index = Math.floor(elapsed / span) % Math.max(1, base.length);
167
+ return base.map((slot, i) => (i === index ? { ch: slot.ch, shade: "flash" } : slot));
168
+ }
169
+
170
+ /**
171
+ * One scramble from t=0 when `full` is set. After CYCLE_MS, or when `full` is
172
+ * clear, only the idle flash remains.
173
+ */
174
+ export function heroSlots(elapsedMs: number, full: boolean, word = WORD): SlotFrame[] {
175
+ const elapsed = Number.isFinite(elapsedMs) ? Math.max(0, elapsedMs) : 0;
176
+ if (full && elapsed < CYCLE_MS) return slotsAt(elapsed, word);
177
+ return idleSlots(full ? elapsed - CYCLE_MS : elapsed, word);
178
+ }
179
+
180
+ export type WordmarkStore = {
181
+ getItem(key: string): string | null;
182
+ setItem(key: string, value: string): void;
183
+ };
184
+
185
+ export type WordmarkClock = { origin: number; full: boolean };
186
+
187
+ /** First call in a tab plays the scramble and records it. A later call does not. */
188
+ export function readFullPlay(store: WordmarkStore | null): boolean {
189
+ if (!store) return true;
190
+ try {
191
+ if (store.getItem(WORDMARK_SESSION_KEY) === "1") return false;
192
+ store.setItem(WORDMARK_SESSION_KEY, "1");
193
+ return true;
194
+ } catch {
195
+ return true;
196
+ }
197
+ }
198
+
199
+ export function ensureWordmarkClock(
200
+ now: number,
201
+ store: WordmarkStore | null,
202
+ current: WordmarkClock | null,
203
+ ): WordmarkClock {
204
+ if (current) return current;
205
+ return { origin: now, full: readFullPlay(store) };
206
+ }
207
+
208
+ export function wordmarkSample(now: number, clock: WordmarkClock): { elapsed: number; full: boolean } {
209
+ return { elapsed: Math.max(0, now - clock.origin), full: clock.full };
210
+ }
211
+
212
+ function colorOf(shade: ShadeName, truecolor: boolean): CellColor {
213
+ const tone = SHADES[shade];
214
+ return truecolor ? { rgb: tone.rgb } : { cube: tone.cube };
215
+ }
216
+
217
+ type Pixel = { on: boolean; shade: ShadeName | null };
218
+
219
+ function gridFor(frames: readonly SlotFrame[], gap: number): Pixel[][] {
220
+ const rows: Pixel[][] = Array.from({ length: 10 }, () => []);
221
+ let drawn = 0;
222
+ for (const frame of frames) {
223
+ const glyph = frame.ch ? GLYPHS[frame.ch] : undefined;
224
+ if (!glyph) continue;
225
+ if (drawn > 0) {
226
+ for (const row of rows) {
227
+ for (let g = 0; g < gap; g += 1) row.push({ on: false, shade: null });
228
+ }
229
+ }
230
+ for (let y = 0; y < 10; y += 1) {
231
+ const line = glyph[y] ?? ".......";
232
+ for (const mark of line) rows[y]?.push({ on: mark === "#", shade: frame.shade });
233
+ }
234
+ drawn += 1;
235
+ }
236
+ return rows;
237
+ }
238
+
239
+ const BLANK: WordCell = { ch: " ", color: null };
240
+
241
+ function linesFor(
242
+ frames: readonly SlotFrame[],
243
+ { cols = 100, truecolor = false, gap }: { cols?: number; truecolor?: boolean; gap?: number } = {},
244
+ ): { lines: WordCell[][]; gap: number; rows: number } {
245
+ const count = frames.filter((frame) => frame.ch && GLYPHS[frame.ch]).length;
246
+ const usedGap = gap ?? letterGap(cols, Math.max(1, count));
247
+ const grid = gridFor(frames, count > 1 ? usedGap : 0);
248
+ const width = grid[0]?.length ?? 0;
249
+ if (width === 0) {
250
+ return { lines: Array.from({ length: 5 }, () => [{ ...BLANK }]), gap: usedGap, rows: 5 };
251
+ }
252
+ const lines: WordCell[][] = [];
253
+ for (let y = 0; y < 10; y += 2) {
254
+ const cells: WordCell[] = [];
255
+ for (let x = 0; x < width; x += 1) {
256
+ const top = grid[y]?.[x];
257
+ const bot = grid[y + 1]?.[x];
258
+ const topOn = top?.on === true;
259
+ const botOn = bot?.on === true;
260
+ if (!topOn && !botOn) {
261
+ cells.push({ ...BLANK });
262
+ continue;
263
+ }
264
+ let ch = "▄";
265
+ let shade = bot?.shade ?? top?.shade ?? "rest";
266
+ if (topOn && botOn) {
267
+ ch = "█";
268
+ shade = top?.shade ?? shade;
269
+ } else if (topOn) {
270
+ ch = "▀";
271
+ shade = top?.shade ?? shade;
272
+ }
273
+ cells.push({ ch, color: colorOf(shade, truecolor) });
274
+ }
275
+ lines.push(cells);
276
+ }
277
+ return { lines, gap: usedGap, rows: lines.length };
278
+ }
279
+
280
+ export function wordmarkLines(
281
+ word = WORD,
282
+ { cols = 100, tMs = SETTLED_MS, truecolor = false, gap }: {
283
+ cols?: number;
284
+ tMs?: number;
285
+ truecolor?: boolean;
286
+ gap?: number;
287
+ } = {},
288
+ ): { lines: WordCell[][]; gap: number; rows: number } {
289
+ return linesFor(slotsAt(tMs, word), { cols, truecolor, gap });
290
+ }
291
+
292
+ export function heroWordmarkLines(
293
+ word = WORD,
294
+ { cols = 100, elapsed = 0, full = false, truecolor = false, gap }: {
295
+ cols?: number;
296
+ elapsed?: number;
297
+ full?: boolean;
298
+ truecolor?: boolean;
299
+ gap?: number;
300
+ } = {},
301
+ ): { lines: WordCell[][]; gap: number; rows: number } {
302
+ return linesFor(heroSlots(elapsed, full, word), { cols, truecolor, gap });
303
+ }
304
+
305
+ export type WordPixel = { x: number; y: number; shade: ShadeName };
306
+
307
+ function pixelsFor(frames: readonly SlotFrame[], gap: number): { pixels: WordPixel[]; width: number; height: number } {
308
+ const pixels: WordPixel[] = [];
309
+ let cursor = 0;
310
+ let drawn = 0;
311
+ for (const frame of frames) {
312
+ const glyph = frame.ch ? GLYPHS[frame.ch] : undefined;
313
+ if (!glyph) continue;
314
+ if (drawn > 0) cursor += gap;
315
+ for (let y = 0; y < 10; y += 1) {
316
+ const line = glyph[y] ?? "";
317
+ for (let x = 0; x < line.length; x += 1) {
318
+ if (line[x] === "#") pixels.push({ x: cursor + x, y, shade: frame.shade });
319
+ }
320
+ }
321
+ cursor += 7;
322
+ drawn += 1;
323
+ }
324
+ return { pixels, width: Math.max(cursor, 0), height: 10 };
325
+ }
326
+
327
+ export function wordmarkPixels(
328
+ tMs = SETTLED_MS,
329
+ { word = WORD, gap = 1 }: { word?: string; gap?: number } = {},
330
+ ): { pixels: WordPixel[]; width: number; height: number } {
331
+ return pixelsFor(slotsAt(tMs, word), gap);
332
+ }
333
+
334
+ export function heroWordmarkPixels(
335
+ elapsed = 0,
336
+ full = false,
337
+ { word = WORD, gap = 1 }: { word?: string; gap?: number } = {},
338
+ ): { pixels: WordPixel[]; width: number; height: number } {
339
+ return pixelsFor(heroSlots(elapsed, full, word), gap);
340
+ }
341
+
342
+ export function shadeHex(shade: ShadeName): string {
343
+ const channel = SHADES[shade].rgb.toString(16).padStart(2, "0");
344
+ return `#${channel}${channel}${channel}`;
345
+ }
346
+
347
+ /** One SGR color selector. A cell never carries both 38;5 and 38;2. */
348
+ export function cellSgr(cell: WordCell): string {
349
+ if (!cell.color) return "";
350
+ if ("rgb" in cell.color) {
351
+ const n = cell.color.rgb;
352
+ return `38;2;${n};${n};${n}`;
353
+ }
354
+ return `38;5;${cell.color.cube}`;
355
+ }
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import { DotMatrix } from "./DotMatrix";
4
+
5
+ /**
6
+ * The one caret for every collapsible row in the trace.
7
+ *
8
+ * The same square pixel chevron as the mark beside a user message
9
+ * (`DotMatrix` state `user`), in the 0.55rem box the trace caret had before.
10
+ * Closed, it points right. Open, the skin stylesheet rotates the cube svg
11
+ * 90° so it points down. The rotate is on `dot-matrix-grid` only — never
12
+ * this wrapper, the trigger, or the label. The glyph is decorative: every
13
+ * trigger it sits in is named by its visible text (DIG-4669), and the open
14
+ * state is the trigger's `aria-expanded`. The caret is a direct child of its
15
+ * trigger, and the rotation follows that trigger:
16
+ * `aria-expanded` and `data-panel-open` (Base UI) or `data-state="open"`
17
+ * (Radix). An open ancestor — the work chain's `data-open` — does not
18
+ * rotate the closed rows inside it.
19
+ */
20
+ /**
21
+ * The turn as Tailwind utilities, so it holds in every host that scans this
22
+ * package (stock skins and the baseline catalog load no chat stylesheet). The
23
+ * DigiChat sheets repeat the same rotate with their own transition.
24
+ */
25
+ export const TURN = [
26
+ "aui-disclosure-chevron",
27
+ "[&_[data-slot=dot-matrix-grid]]:transition-transform",
28
+ "motion-reduce:[&_[data-slot=dot-matrix-grid]]:transition-none",
29
+ "[[aria-expanded=true]>&_[data-slot=dot-matrix-grid]]:[transform:rotate(90deg)]",
30
+ "[[data-panel-open]>&_[data-slot=dot-matrix-grid]]:[transform:rotate(90deg)]",
31
+ ].join(" ");
32
+
33
+ export function DisclosureChevron() {
34
+ return (
35
+ <span
36
+ data-slot="disclosure-chevron"
37
+ className={TURN}
38
+ style={{
39
+ position: "relative",
40
+ display: "inline-flex",
41
+ width: "0.55rem",
42
+ height: "0.55rem",
43
+ flex: "0 0 0.55rem",
44
+ }}
45
+ >
46
+ <DotMatrix state="user" decorative className="!size-[0.55rem]" />
47
+ </span>
48
+ );
49
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Citation links (DIG-3269): a non-web source (repo://, vault path) reaches the
3
+ * renderer with its href emptied by the sanitizer, and <a href=""> would reload
4
+ * the embed itself, query string included. Only these hrefs are links.
5
+ */
6
+ export function isFollowableHref(href: string | undefined): boolean {
7
+ if (!href) return false;
8
+ return /^(https?:|mailto:|#|\/(?!\/))/i.test(href.trim());
9
+ }