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