@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,192 @@
1
+ "use client";
2
+
3
+ /**
4
+ * Terminal schematic — a fully drawn monospace flow.
5
+ *
6
+ * Structure is on screen from the first paint: 1px boxes, dotted orthogonal
7
+ * joins, a loop back, a legend, a numbered list, and a receipt. Motion is
8
+ * telemetry only (a mark on the trunk, a cluster on the live bus, status
9
+ * words, a snapping meter, a scrolling receipt). Nothing draws on.
10
+ *
11
+ * Styles: `@digithings-ai/ui/styles/diagrams.css` (the `.tschem` block).
12
+ */
13
+
14
+ import { useEffect, useState } from "react";
15
+
16
+ import { useMotionSafe } from "../../motion/primitives";
17
+
18
+ export type SchematicTone = "main" | "model" | "side" | "fallback" | "pending";
19
+
20
+ export type SchematicNode = {
21
+ label: string;
22
+ tone: SchematicTone;
23
+ };
24
+
25
+ /** One row. More than one node means those steps run together. */
26
+ export type SchematicRow = {
27
+ nodes: readonly SchematicNode[];
28
+ };
29
+
30
+ export type SchematicLegend = {
31
+ tone: SchematicTone | "ok";
32
+ label: string;
33
+ };
34
+
35
+ export type TerminalSchematicProps = {
36
+ title: string;
37
+ /** Accessible name for the whole picture. */
38
+ label: string;
39
+ rows: readonly SchematicRow[];
40
+ /** Why the flow returns to the top. */
41
+ loop: string;
42
+ notes: readonly string[];
43
+ /** Status lines for the receipt. Presentational, not a transcript. */
44
+ receipt: readonly string[];
45
+ legend: readonly SchematicLegend[];
46
+ };
47
+
48
+ type BoxStatus = "running" | "ok" | "idle" | "pending" | "hold";
49
+
50
+ function rowPending(row: SchematicRow): boolean {
51
+ return row.nodes.length > 0 && row.nodes.every((node) => node.tone === "pending");
52
+ }
53
+
54
+ function boxStatus(tone: SchematicTone, live: boolean, shipped: boolean): BoxStatus {
55
+ if (tone === "pending") return "pending";
56
+ if (tone === "fallback") return live ? "hold" : "idle";
57
+ if (!shipped) return "idle";
58
+ return live ? "running" : "ok";
59
+ }
60
+
61
+ /**
62
+ * Dark terminal picture of one flow. Counters and the receipt are motion
63
+ * for the picture — they are not a recorded run.
64
+ */
65
+ export function TerminalSchematic({
66
+ title,
67
+ label,
68
+ rows,
69
+ loop,
70
+ notes,
71
+ receipt,
72
+ legend,
73
+ }: TerminalSchematicProps) {
74
+ const safe = useMotionSafe();
75
+ const cycle = rows.flatMap((row, index) => (rowPending(row) ? [] : [index]));
76
+ const [phase, setPhase] = useState(0);
77
+
78
+ useEffect(() => {
79
+ if (!safe || cycle.length === 0) return;
80
+ const timer = window.setInterval(() => {
81
+ setPhase((current) => (current + 1) % cycle.length);
82
+ }, 1400);
83
+ return () => window.clearInterval(timer);
84
+ }, [safe, cycle.length]);
85
+
86
+ const cursor = cycle.length > 0 ? cycle[phase % cycle.length] : -1;
87
+ const liveRow = cursor >= 0 ? rows[cursor] : undefined;
88
+ const threads = liveRow && liveRow.nodes.length > 1 ? liveRow.nodes.length : 1;
89
+ const hops = String(cycle.length === 0 ? 0 : phase + 1).padStart(2, "0");
90
+ const phrase = liveRow
91
+ ? `${liveRow.nodes.map((node) => node.label).join(" · ")} · running`
92
+ : "idle";
93
+ const filled = cycle.length === 0 ? 0 : ((phase + 1) / cycle.length) * 100;
94
+ const log = receipt.length > 0 ? [...receipt, ...receipt] : [];
95
+
96
+ return (
97
+ <figure className="tschem" data-motion={safe ? "on" : "off"} aria-label={label}>
98
+ <header className="tschem__title">{title}</header>
99
+ <div className="tschem__body">
100
+ <ul className="tschem__legend" aria-label="Legend">
101
+ {legend.map((item) => (
102
+ <li key={item.label}>
103
+ <span className="tschem__swatch" data-tone={item.tone} aria-hidden="true" />
104
+ {item.label}
105
+ </li>
106
+ ))}
107
+ </ul>
108
+ <div className="tschem__stack">
109
+ <span className="tschem__drop" aria-hidden="true">
110
+ ▾
111
+ </span>
112
+ <ol className="tschem__rows">
113
+ {rows.map((row, index) => {
114
+ const live = index === cursor;
115
+ const shipped = !rowPending(row);
116
+ const parallel = row.nodes.length > 1;
117
+ return (
118
+ <li key={row.nodes.map((node) => node.label).join("|")} className="tschem__step">
119
+ {index > 0 ? (
120
+ <span className="tschem__join" aria-hidden="true" />
121
+ ) : null}
122
+ <div className="tschem__row" data-live={live ? "true" : "false"}>
123
+ {parallel ? (
124
+ <div className="tschem__bus">
125
+ <span className="tschem__par">in parallel</span>
126
+ <span className="tschem__cluster" aria-hidden="true">
127
+ ···
128
+ </span>
129
+ </div>
130
+ ) : null}
131
+ <div className="tschem__nodes">
132
+ {row.nodes.map((node) => {
133
+ const status = boxStatus(node.tone, live, shipped);
134
+ return (
135
+ <div
136
+ key={node.label}
137
+ className="tschem__box"
138
+ data-tone={node.tone}
139
+ data-status={status}
140
+ >
141
+ <span className="tschem__name">{node.label}</span>
142
+ <span className="tschem__state">{status}</span>
143
+ </div>
144
+ );
145
+ })}
146
+ </div>
147
+ </div>
148
+ </li>
149
+ );
150
+ })}
151
+ </ol>
152
+ <p className="tschem__loop">
153
+ <span aria-hidden="true">↩ </span>
154
+ {loop}
155
+ </p>
156
+ </div>
157
+ <ol className="tschem__notes" aria-label="Steps">
158
+ {notes.map((note, index) => (
159
+ <li key={note}>
160
+ <span className="tschem__num">{String(index + 1).padStart(2, "0")}</span>
161
+ <span>{note}</span>
162
+ </li>
163
+ ))}
164
+ </ol>
165
+ </div>
166
+ {log.length > 0 ? (
167
+ <div className="tschem__receipt" aria-label="Receipt">
168
+ <div className="tschem__receipt-track">
169
+ {log.map((line, index) => (
170
+ <span key={`${line}-${index}`} aria-hidden={index >= receipt.length ? true : undefined}>
171
+ {line}
172
+ </span>
173
+ ))}
174
+ </div>
175
+ </div>
176
+ ) : null}
177
+ <footer className="tschem__foot">
178
+ <span>
179
+ hops <b>{hops}</b>
180
+ </span>
181
+ <span className="tschem__meter" aria-hidden="true">
182
+ <span style={{ width: `${filled}%` }} />
183
+ </span>
184
+ <span>
185
+ threads <b>{threads}</b>
186
+ </span>
187
+ <span className="tschem__phrase">{phrase}</span>
188
+ <span>not a live run</span>
189
+ </footer>
190
+ </figure>
191
+ );
192
+ }
@@ -0,0 +1,384 @@
1
+ /**
2
+ * Architecture SVG — the box-and-connector renderer.
3
+ *
4
+ * WHY NOT MERMAID'S `architecture-beta`. Probed in the browser (round 12): the
5
+ * beta grammar draws NO service box. Every service is an 80x80 icon plate with
6
+ * its label drawn over the plate's bottom edge, and mermaid breaks the label
7
+ * into `<tspan>` rows before it reaches the DOM — so `retrieval` arrived as
8
+ * `retri / eva / l`, a two-word label wrapped onto the plate, and the whole
9
+ * drawing read as floating glyphs with text over them. Nothing in CSS can
10
+ * repair that, because the split has already happened upstream. `toMermaid`
11
+ * stays (it is the model/doc export and the chat surface's own path) but the
12
+ * visual component draws its own SVG: a box with the label inside it, one small
13
+ * kind glyph, orthogonal hairline connectors, and a boundary whose title sits
14
+ * above its rule instead of on it.
15
+ *
16
+ * POSITIONING IS DECLARED, NOT SOLVED. A spec that carries `col`/`row` on every
17
+ * service (and optionally a rect on a group) is drawn on a fixed grid — no
18
+ * force-directed layout to fight and a stable coordinate frame for the camera
19
+ * walk. A spec without positions falls back to the mermaid render.
20
+ *
21
+ * IDS ARE THE TOUR'S HANDLE. Each box is `arch-service-<id>` and each boundary
22
+ * `arch-group-<id>`, which is exactly what `ArchitectureTour` resolves inside
23
+ * the drawn SVG, so the swap/glow/camera code needed no change when the
24
+ * renderer did.
25
+ */
26
+
27
+ import type { ArchEdge, ArchGroup, ArchIcon, ArchService, ArchSpec } from "./ArchitectureDiagram";
28
+ import { ICONS } from "../logos";
29
+
30
+ const BOX_W = 176;
31
+ const BOX_H = 58;
32
+ const GAP_X = 84;
33
+ const GAP_Y = 62;
34
+ const GROUP_PAD = 18;
35
+ const GROUP_HEAD = 46;
36
+ const GLYPH = 22;
37
+ /** The label column: the text starts after the glyph and its gutter. */
38
+ const LABEL_X = 48;
39
+ /** Roughly how many characters fit the label column at the label's size. */
40
+ const LABEL_MAX_CHARS = 15;
41
+
42
+ /**
43
+ * Break a service label onto at most two lines so it never runs past its box.
44
+ * A box is `BOX_W` wide and the label column starts at `LABEL_X`, so the budget
45
+ * is ~15 monospace characters; anything longer splits on the first space that
46
+ * balances the two lines, and a single word that still overruns is left to the
47
+ * box's own clip rather than broken mid-word. Returns one line when it fits.
48
+ */
49
+ function wrapLabel(label: string): string[] {
50
+ if (label.length <= LABEL_MAX_CHARS) return [label];
51
+ const words = label.split(" ");
52
+ if (words.length === 1) return [label];
53
+ let best: string[] = [label];
54
+ let bestDelta = Infinity;
55
+ for (let cut = 1; cut < words.length; cut += 1) {
56
+ const line1 = words.slice(0, cut).join(" ");
57
+ const line2 = words.slice(cut).join(" ");
58
+ if (line1.length > LABEL_MAX_CHARS || line2.length > LABEL_MAX_CHARS) continue;
59
+ const delta = Math.abs(line1.length - line2.length);
60
+ if (delta < bestDelta) {
61
+ bestDelta = delta;
62
+ best = [line1, line2];
63
+ }
64
+ }
65
+ return best;
66
+ }
67
+
68
+ /** A laid-out service: a spec service that carries a grid slot. */
69
+ export type PlacedService = ArchService & { col: number; row: number };
70
+ type Rect = { x: number; y: number; w: number; h: number };
71
+
72
+ export function hasLayout(spec: ArchSpec): spec is ArchSpec & { services: PlacedService[] } {
73
+ return spec.services.length > 0 && spec.services.every((s) => s.col != null && s.row != null);
74
+ }
75
+
76
+ /** The grid's gutters. Boxes keep their size; only the space between them flexes. */
77
+ type Gaps = { x: number; y: number };
78
+ const DEFAULT_GAPS: Gaps = { x: GAP_X, y: GAP_Y };
79
+ /** How far a gutter may stretch to fill its frame before the drawing letterboxes instead. */
80
+ const MAX_GAP_STRETCH = 3;
81
+
82
+ const gx = (col: number, g: Gaps): number => col * (BOX_W + g.x);
83
+ /** Extra lane so a box above a boundary sits clear of its caption rule. */
84
+ const ROW_LANE_EXTRA = 34;
85
+ const gy = (row: number, g: Gaps): number =>
86
+ row * (BOX_H + g.y) + (row >= 1 ? ROW_LANE_EXTRA : 0);
87
+
88
+ function boxRect(service: PlacedService, g: Gaps): Rect {
89
+ return { x: gx(service.col, g), y: gy(service.row, g), w: BOX_W, h: BOX_H };
90
+ }
91
+
92
+ function groupRect(group: ArchGroup, services: PlacedService[], g: Gaps): Rect | null {
93
+ if (group.col != null && group.row != null && group.cols != null && group.rows != null) {
94
+ return {
95
+ x: gx(group.col, g) - GROUP_PAD,
96
+ y: gy(group.row, g) - GROUP_PAD - (GROUP_HEAD - GROUP_PAD),
97
+ w: (group.cols - 1) * (BOX_W + g.x) + BOX_W + GROUP_PAD * 2,
98
+ h: (group.rows - 1) * (BOX_H + g.y) + BOX_H + GROUP_PAD * 2,
99
+ };
100
+ }
101
+ const members = services.filter((s) => s.group === group.id).map((s) => boxRect(s, g));
102
+ if (members.length === 0) return null;
103
+ const xs = members.map((r) => r.x);
104
+ const ys = members.map((r) => r.y);
105
+ const xe = members.map((r) => r.x + r.w);
106
+ const ye = members.map((r) => r.y + r.h);
107
+ return {
108
+ x: Math.min(...xs) - GROUP_PAD,
109
+ y: Math.min(...ys) - GROUP_HEAD,
110
+ w: Math.max(...xe) - Math.min(...xs) + GROUP_PAD * 2,
111
+ h: Math.max(...ye) - Math.min(...ys) + GROUP_HEAD + GROUP_PAD,
112
+ };
113
+ }
114
+
115
+ type Routed = { d: string; lx: number; ly: number };
116
+
117
+ /**
118
+ * Orthogonal connector between two boxes.
119
+ *
120
+ * The label is placed on the LONGEST run of the path and offset perpendicular
121
+ * to it, which is the only position guaranteed clear of both boxes: the elbow
122
+ * band between two rows/columns is often thinner than the label itself, so
123
+ * "midpoint of the elbow" kept landing on a box edge. `sx`/`sy` name the first
124
+ * segment so the caller can offset correctly.
125
+ */
126
+ function route(a: Rect, b: Rect): Routed {
127
+ const acx = a.x + a.w / 2;
128
+ const acy = a.y + a.h / 2;
129
+ const bcx = b.x + b.w / 2;
130
+ const bcy = b.y + b.h / 2;
131
+ const OFF = 7;
132
+
133
+ // A straight horizontal neighbour: one line, label above it in the gutter.
134
+ if (Math.abs(acy - bcy) < 1 && Math.abs(bcx - acx) >= a.w / 2 + b.w / 2) {
135
+ const rightward = bcx >= acx;
136
+ const sx = rightward ? a.x + a.w : a.x;
137
+ const tx = rightward ? b.x : b.x + b.w;
138
+ return { d: `M${sx} ${acy} H${tx}`, lx: (sx + tx) / 2, ly: acy - OFF };
139
+ }
140
+
141
+ if (Math.abs(bcx - acx) >= Math.abs(bcy - acy)) {
142
+ const rightward = bcx >= acx;
143
+ const sx = rightward ? a.x + a.w : a.x;
144
+ const tx = rightward ? b.x : b.x + b.w;
145
+ const mx = (sx + tx) / 2;
146
+ return {
147
+ d: `M${sx} ${acy} H${mx} V${bcy} H${tx}`,
148
+ // The elbow: gutter centre-x, band centre-y. Clear of both boxes.
149
+ lx: mx,
150
+ ly: (acy + bcy) / 2,
151
+ };
152
+ }
153
+
154
+ const downward = bcy >= acy;
155
+ const sy = downward ? a.y + a.h : a.y;
156
+ const ty = downward ? b.y : b.y + b.h;
157
+ const my = (sy + ty) / 2;
158
+ return {
159
+ d: `M${acx} ${sy} V${my} H${bcx} V${ty}`,
160
+ lx: acx,
161
+ ly: my - OFF,
162
+ };
163
+ }
164
+
165
+ /** A 22px monoline kind glyph, drawn in a local 20x20 box. A named `logo` slug
166
+ * from the kit registry wins when it resolves (simple-icons paths are 24x24
167
+ * fill shapes, drawn in currentColor like everything else on the box);
168
+ * anything else falls through to the kind glyph, so unmarked vendors degrade
169
+ * to a generic plate instead of an empty one. */
170
+ function Glyph({ kind, logo }: { kind?: ArchIcon; logo?: string }) {
171
+ const mark = logo ? ICONS[logo] : undefined;
172
+ if (mark) {
173
+ /* simple-icons paths live in a 24x24 box; scale into the local 20x20 so
174
+ a brand mark fills exactly the frame the kind glyphs use. */
175
+ return (
176
+ <g transform={`scale(${20 / 24})`}>
177
+ <path d={mark.path} fill="currentColor" stroke="none" />
178
+ </g>
179
+ );
180
+ }
181
+ const common = { fill: "none", stroke: "currentColor", strokeWidth: 1.4, strokeLinecap: "round" as const };
182
+ switch (kind) {
183
+ case "database":
184
+ return (
185
+ <g {...common}>
186
+ <ellipse cx={10} cy={5.5} rx={6} ry={2.4} />
187
+ <path d="M4 5.5v9c0 1.3 2.7 2.4 6 2.4s6-1.1 6-2.4v-9" />
188
+ </g>
189
+ );
190
+ case "disk":
191
+ return (
192
+ <g {...common}>
193
+ <rect x={4} y={3.5} width={12} height={13} />
194
+ <path d="M7 3.5v6h6v-6" />
195
+ <path d="M7 16.5v-4h6v4" />
196
+ </g>
197
+ );
198
+ case "cloud":
199
+ return (
200
+ <g {...common}>
201
+ <path d="M6 14.5h9a3.2 3.2 0 0 0 .3-6.4 4.6 4.6 0 0 0-8.9-1.1A3.4 3.4 0 0 0 6 14.5Z" />
202
+ </g>
203
+ );
204
+ case "server":
205
+ return (
206
+ <g {...common}>
207
+ <rect x={3.5} y={4} width={13} height={5} />
208
+ <rect x={3.5} y={11} width={13} height={5} />
209
+ <path d="M6.2 6.5h.01M6.2 13.5h.01" />
210
+ </g>
211
+ );
212
+ default:
213
+ return (
214
+ <g {...common}>
215
+ <circle cx={10} cy={10} r={6.2} />
216
+ <path d="M3.8 10h12.4" />
217
+ <ellipse cx={10} cy={10} rx={3} ry={6.2} />
218
+ </g>
219
+ );
220
+ }
221
+ }
222
+
223
+ export type ArchitectureSvgProps = {
224
+ spec: ArchSpec;
225
+ /** Service and group ids to mark as the current step. */
226
+ lit?: readonly string[];
227
+ /** Frame width / height to stretch the gutters toward; unset keeps the default grid. */
228
+ aspect?: number;
229
+ className?: string;
230
+ };
231
+
232
+ const VIEW_PAD = 26;
233
+
234
+ function layout(spec: ArchSpec, services: PlacedService[], g: Gaps) {
235
+ const rects = new Map(services.map((s) => [s.id, boxRect(s, g)]));
236
+ const groups = (spec.groups ?? [])
237
+ .map((group) => ({ group, rect: groupRect(group, services, g) }))
238
+ .filter((x): x is { group: ArchGroup; rect: Rect } => x.rect !== null);
239
+ const boxes = [...rects.values()];
240
+ const minX = Math.min(...boxes.map((r) => r.x), ...groups.map((x) => x.rect.x));
241
+ const maxX = Math.max(...boxes.map((r) => r.x + r.w), ...groups.map((x) => x.rect.x + x.rect.w));
242
+ const minY = Math.min(...boxes.map((r) => r.y), ...groups.map((x) => x.rect.y - 24));
243
+ const maxY = Math.max(...boxes.map((r) => r.y + r.h), ...groups.map((x) => x.rect.y + x.rect.h));
244
+ const view = {
245
+ x: minX - VIEW_PAD,
246
+ y: minY - VIEW_PAD,
247
+ w: maxX - minX + VIEW_PAD * 2,
248
+ h: maxY - minY + VIEW_PAD * 2,
249
+ };
250
+ return { rects, groups, view };
251
+ }
252
+
253
+ /**
254
+ * Gutters that bring the drawing to `aspect` (width / height), so a frame of
255
+ * that shape is filled rather than letterboxed. Only the short axis stretches,
256
+ * up to `MAX_GAP_STRETCH`; box size, and so label size, never changes. The
257
+ * extent is linear in each gutter, so one probe layout per axis gives the
258
+ * exact slope.
259
+ */
260
+ function fitGaps(spec: ArchSpec, services: PlacedService[], aspect: number): Gaps {
261
+ const base = layout(spec, services, DEFAULT_GAPS).view;
262
+ const current = base.w / base.h;
263
+ if (Math.abs(current - aspect) < 0.01) return DEFAULT_GAPS;
264
+ if (current < aspect) {
265
+ const slope = layout(spec, services, { ...DEFAULT_GAPS, x: GAP_X + 1 }).view.w - base.w;
266
+ if (slope <= 0) return DEFAULT_GAPS;
267
+ const x = GAP_X + (aspect * base.h - base.w) / slope;
268
+ return { ...DEFAULT_GAPS, x: Math.min(x, GAP_X * MAX_GAP_STRETCH) };
269
+ }
270
+ const slope = layout(spec, services, { ...DEFAULT_GAPS, y: GAP_Y + 1 }).view.h - base.h;
271
+ if (slope <= 0) return DEFAULT_GAPS;
272
+ const y = GAP_Y + (base.w / aspect - base.h) / slope;
273
+ return { ...DEFAULT_GAPS, y: Math.min(y, GAP_Y * MAX_GAP_STRETCH) };
274
+ }
275
+
276
+ export function ArchitectureSvg({ spec, lit, aspect, className }: ArchitectureSvgProps) {
277
+ if (!hasLayout(spec)) return null;
278
+ const services: PlacedService[] = spec.services;
279
+ const on = new Set(lit ?? []);
280
+ const byId = new Map(services.map((s) => [s.id, s]));
281
+ const gaps = aspect && aspect > 0 ? fitGaps(spec, services, aspect) : DEFAULT_GAPS;
282
+ const { rects, groups, view } = layout(spec, services, gaps);
283
+ const edges: Array<{ edge: ArchEdge; routed: Routed }> = [];
284
+ for (const edge of spec.edges) {
285
+ const a = rects.get(edge.from);
286
+ const b = rects.get(edge.to);
287
+ if (a && b && byId.has(edge.from) && byId.has(edge.to)) {
288
+ edges.push({ edge, routed: route(a, b) });
289
+ }
290
+ }
291
+
292
+ const viewBox = `${view.x} ${view.y} ${view.w} ${view.h}`;
293
+
294
+ const uid = spec.title.replace(/[^a-zA-Z0-9]/g, "");
295
+ const markerId = `arch-arrow-${uid}`;
296
+
297
+ /* Build order for the `.arch-build` entrance: boxes in reading order (row,
298
+ then column), each connector only once both of its ends are drawn. */
299
+ const order = new Map(
300
+ [...services]
301
+ .sort((a, b) => a.row - b.row || a.col - b.col)
302
+ .map((s, i) => [s.id, i] as const),
303
+ );
304
+ const buildVar = (i: number) => ({ ["--arch-i" as string]: i });
305
+
306
+ return (
307
+ <svg
308
+ className={["arch-svg", className ?? ""].filter(Boolean).join(" ")}
309
+ viewBox={viewBox}
310
+ role="img"
311
+ aria-label={`${spec.title}. ${spec.description}`}
312
+ preserveAspectRatio="xMidYMid meet"
313
+ >
314
+ <defs>
315
+ <marker id={markerId} viewBox="0 0 8 8" refX={7} refY={4} markerWidth={9} markerHeight={9} orient="auto">
316
+ <path className="arch-arrow" d="M0 0.6 L7 4 L0 7.4" />
317
+ </marker>
318
+ </defs>
319
+
320
+ {groups.map(({ group, rect }, gi) => (
321
+ <g
322
+ key={group.id}
323
+ id={`arch-group-${group.id}`}
324
+ className={`arch-group${on.has(group.id) ? " is-on" : ""}`}
325
+ style={buildVar(gi)}
326
+ >
327
+ <rect className="arch-group__box" x={rect.x} y={rect.y} width={rect.w} height={rect.h} />
328
+ <text className="arch-group__label" x={rect.x} y={rect.y + 24}>
329
+ {group.label}
330
+ </text>
331
+ </g>
332
+ ))}
333
+
334
+ {edges.map(({ edge, routed }) => (
335
+ <g
336
+ key={`${edge.from}-${edge.to}`}
337
+ className={`arch-edge${on.has(edge.from) && on.has(edge.to) ? " is-on" : ""}`}
338
+ style={buildVar(Math.max(order.get(edge.from) ?? 0, order.get(edge.to) ?? 0))}
339
+ >
340
+ <path
341
+ className="arch-edge__line"
342
+ d={routed.d}
343
+ pathLength={1}
344
+ markerEnd={edge.arrow === "from" || edge.arrow === "none" ? undefined : `url(#${markerId})`}
345
+ markerStart={edge.arrow === "from" ? `url(#${markerId})` : undefined}
346
+ />
347
+ {edge.label ? (
348
+ <text className="arch-edge__label" x={routed.lx} y={routed.ly - 4}>
349
+ {edge.label}
350
+ </text>
351
+ ) : null}
352
+ </g>
353
+ ))}
354
+
355
+ {services.map((service) => {
356
+ const r = rects.get(service.id) as Rect;
357
+ return (
358
+ <g
359
+ key={service.id}
360
+ id={`arch-service-${service.id}`}
361
+ className={`arch-node${on.has(service.id) ? " is-on" : ""}`}
362
+ style={buildVar(order.get(service.id) ?? 0)}
363
+ >
364
+ <rect className="arch-node__box" x={r.x} y={r.y} width={r.w} height={r.h} pathLength={1} />
365
+ <g className="arch-node__glyph" transform={`translate(${r.x + 14} ${r.y + (BOX_H - GLYPH) / 2}) scale(${GLYPH / 20})`}>
366
+ <Glyph kind={service.icon} logo={service.logo} />
367
+ </g>
368
+ <text className="arch-node__label" x={r.x + LABEL_X} y={r.y + BOX_H / 2} dominantBaseline="middle">
369
+ {(() => {
370
+ const lines = wrapLabel(service.label);
371
+ if (lines.length === 1) return lines[0];
372
+ return lines.map((line, i) => (
373
+ <tspan key={line} x={r.x + LABEL_X} dy={i === 0 ? -6 : 13}>
374
+ {line}
375
+ </tspan>
376
+ ));
377
+ })()}
378
+ </text>
379
+ </g>
380
+ );
381
+ })}
382
+ </svg>
383
+ );
384
+ }
@@ -0,0 +1,30 @@
1
+ export {
2
+ ArchitectureDiagram,
3
+ toMermaid,
4
+ type ArchitectureDiagramProps,
5
+ type ArchAlign,
6
+ type ArchEdge,
7
+ type ArchGroup,
8
+ type ArchIcon,
9
+ type ArchJunction,
10
+ type ArchService,
11
+ type ArchSide,
12
+ type ArchSpec,
13
+ } from "./ArchitectureDiagram";
14
+ export { ArchitectureSvg, type ArchitectureSvgProps } from "./architecture-svg";
15
+ export {
16
+ ArchitectureTour,
17
+ type ArchitectureTourProps,
18
+ type TourStep,
19
+ type TourVariant,
20
+ } from "./ArchitectureTour";
21
+ export { camTransform, fitCamera, type CamFrame } from "./tour-camera";
22
+ export {
23
+ TerminalSchematic,
24
+ type SchematicLegend,
25
+ type SchematicNode,
26
+ type SchematicRow,
27
+ type SchematicTone,
28
+ type TerminalSchematicProps,
29
+ } from "./TerminalSchematic";
30
+ export { THEME_TOKENS, tokenThemeVariables } from "./mermaid-theme";