@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,422 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useReducer, useRef, type ReactNode } from "react";
|
|
4
|
+
import { m, useMotionSafe } from "../../motion/primitives";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
import { ChatToolCall } from "./ChatToolCall";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ChatPlayback — a props-driven, SCRIPTED chat simulation in a terminal frame.
|
|
10
|
+
* The caller supplies an ordered script; the part types the user prompts, shows
|
|
11
|
+
* tool-call rows (real names and args, supplied by the caller), and streams the
|
|
12
|
+
* assistant text. It never talks to a model or a server and it invents nothing:
|
|
13
|
+
* every word, tool name, argument and result comes from `script`, and a
|
|
14
|
+
* REQUIRED `badge` prop is rendered inside the frame chrome so the surface
|
|
15
|
+
* always says what it is ("Simulation · scripted · not connected to any MCP
|
|
16
|
+
* server").
|
|
17
|
+
*
|
|
18
|
+
* Behaviour
|
|
19
|
+
* - starts once when the frame scrolls into view (IntersectionObserver), plays
|
|
20
|
+
* once, then offers `[replay]`; `[pause]` / `[play]` and `[skip]` are visible
|
|
21
|
+
* while it runs (it auto-runs well past 5s);
|
|
22
|
+
* - the only React state is the step index, the char count and a phase, advanced
|
|
23
|
+
* on a ~30ms timer while a text step types (no per-frame state, no rAF);
|
|
24
|
+
* - reduced motion, no JS, no IntersectionObserver and server render all show
|
|
25
|
+
* the FULL transcript, statically, with no controls;
|
|
26
|
+
* - a tool `result` is shown only once its (simulated) call has settled;
|
|
27
|
+
* `masked` blanks every non-space character to `▒` so a result can be shown
|
|
28
|
+
* as "a result came back" without claiming its content;
|
|
29
|
+
* - tool rows show no duration: a latency here would be invented.
|
|
30
|
+
*
|
|
31
|
+
* A11y: the animated transcript is `aria-hidden` + `inert` (its expand buttons
|
|
32
|
+
* are decorative here) and the region is `aria-live="off"`; a plain-text
|
|
33
|
+
* `sr-only` ordered list carries the full transcript once, statically. The
|
|
34
|
+
* header, badge, status and controls sit outside the hidden region.
|
|
35
|
+
*
|
|
36
|
+
* Motion: row entrance is `m.div` (opacity + translateY only) under a
|
|
37
|
+
* `MotionProvider`, gated by `useMotionSafe`; the static branch renders none.
|
|
38
|
+
*
|
|
39
|
+
* Wiring (in the consuming app):
|
|
40
|
+
* globals.css @import "@digithings-ai/ui/styles/chat-widgets.css"; (ChatToolCall rail + running pulse)
|
|
41
|
+
* @source "<path-to>/packages/ui/src/components/chat";
|
|
42
|
+
* Chrome is utilities-only (no family sheet, no keyframes of its own).
|
|
43
|
+
*/
|
|
44
|
+
export type ChatPlaybackTable = { columns: string[]; rows: string[][] };
|
|
45
|
+
|
|
46
|
+
export type ChatPlaybackTool = {
|
|
47
|
+
/** Real tool name, e.g. `digiquant.list_strategies`. */
|
|
48
|
+
name: string;
|
|
49
|
+
/** Argument summary, rendered `(args)` — supplied by the caller, real. */
|
|
50
|
+
args?: string;
|
|
51
|
+
/** What came back: text (newlines split lines), a list of lines, or a table. Omit for no body. */
|
|
52
|
+
result?: string | string[] | ChatPlaybackTable;
|
|
53
|
+
/** Blank every non-space character of `result` to `▒` (shows the shape, not the content). */
|
|
54
|
+
masked?: boolean;
|
|
55
|
+
/** How long the call shows as running before it settles. Default 700. */
|
|
56
|
+
runMs?: number;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type ChatPlaybackStep = {
|
|
60
|
+
role: "user" | "assistant" | "tool";
|
|
61
|
+
/** Prompt or reply text (user / assistant steps). */
|
|
62
|
+
text?: string;
|
|
63
|
+
/** The call (tool steps). */
|
|
64
|
+
tool?: ChatPlaybackTool;
|
|
65
|
+
/** Pause before this step starts, in ms. Defaults per role. */
|
|
66
|
+
delayMs?: number;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export type ChatPlaybackProps = {
|
|
70
|
+
/** The scripted steps, in order. Data, not a component. */
|
|
71
|
+
script: ChatPlaybackStep[];
|
|
72
|
+
/** REQUIRED honesty badge inside the frame, e.g. "Simulation · scripted · not connected to any MCP server". */
|
|
73
|
+
badge: string;
|
|
74
|
+
/** Caller-supplied title-row label, e.g. "local mcp session". */
|
|
75
|
+
header: string;
|
|
76
|
+
/** Accessible name for the region. Default: the header. */
|
|
77
|
+
ariaLabel?: string;
|
|
78
|
+
className?: string;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
type Mode = "static" | "armed" | "playing" | "paused" | "done";
|
|
82
|
+
type Phase = "wait" | "work";
|
|
83
|
+
type State = { mode: Mode; step: number; chars: number; phase: Phase };
|
|
84
|
+
type Action =
|
|
85
|
+
| { type: "static" }
|
|
86
|
+
| { type: "arm" }
|
|
87
|
+
| { type: "play" }
|
|
88
|
+
| { type: "pause" }
|
|
89
|
+
| { type: "skip" }
|
|
90
|
+
| { type: "replay" }
|
|
91
|
+
| { type: "advance"; len: number; total: number; rate: number; tool: boolean };
|
|
92
|
+
|
|
93
|
+
const TICK_MS = 30;
|
|
94
|
+
const USER_CPS = 1; // chars per tick
|
|
95
|
+
const ASSISTANT_CPS = 2;
|
|
96
|
+
const DEFAULT_DELAY: Record<ChatPlaybackStep["role"], number> = { user: 500, tool: 450, assistant: 350 };
|
|
97
|
+
const FULL: State = { mode: "static", step: 0, chars: 0, phase: "wait" };
|
|
98
|
+
|
|
99
|
+
function reduce(s: State, a: Action): State {
|
|
100
|
+
switch (a.type) {
|
|
101
|
+
case "static":
|
|
102
|
+
return s.mode === "static" ? s : FULL;
|
|
103
|
+
case "arm":
|
|
104
|
+
return s.mode === "static" ? { mode: "armed", step: 0, chars: 0, phase: "wait" } : s;
|
|
105
|
+
case "play":
|
|
106
|
+
return s.mode === "armed" || s.mode === "paused" ? { ...s, mode: "playing" } : s;
|
|
107
|
+
case "pause":
|
|
108
|
+
return s.mode === "playing" ? { ...s, mode: "paused" } : s;
|
|
109
|
+
case "skip":
|
|
110
|
+
return s.mode === "playing" || s.mode === "paused" ? { ...s, mode: "done" } : s;
|
|
111
|
+
case "replay":
|
|
112
|
+
return s.mode === "done" ? { mode: "playing", step: 0, chars: 0, phase: "wait" } : s;
|
|
113
|
+
case "advance": {
|
|
114
|
+
if (s.mode !== "playing") return s;
|
|
115
|
+
const next = (): State =>
|
|
116
|
+
s.step + 1 >= a.total
|
|
117
|
+
? { ...s, mode: "done", step: a.total }
|
|
118
|
+
: { ...s, step: s.step + 1, chars: 0, phase: "wait" };
|
|
119
|
+
if (s.phase === "wait") return { ...s, phase: "work", chars: 0 };
|
|
120
|
+
if (a.tool) return next();
|
|
121
|
+
const chars = Math.min(a.len, s.chars + a.rate);
|
|
122
|
+
return chars >= a.len ? next() : { ...s, chars };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const maskText = (t: string) => t.replace(/\S/g, "▒");
|
|
128
|
+
|
|
129
|
+
function resultLines(tool: ChatPlaybackTool): string[] {
|
|
130
|
+
const r = tool.result;
|
|
131
|
+
if (r === undefined || (typeof r === "object" && !Array.isArray(r))) return [];
|
|
132
|
+
const lines = Array.isArray(r) ? r : r.split("\n");
|
|
133
|
+
return tool.masked ? lines.map(maskText) : lines;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function resultTable(tool: ChatPlaybackTool): ChatPlaybackTable | null {
|
|
137
|
+
const r = tool.result;
|
|
138
|
+
if (r === undefined || typeof r === "string" || Array.isArray(r)) return null;
|
|
139
|
+
return tool.masked
|
|
140
|
+
? { columns: r.columns, rows: r.rows.map((row) => row.map(maskText)) }
|
|
141
|
+
: r;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function ResultBody({ tool }: { tool: ChatPlaybackTool }): ReactNode {
|
|
145
|
+
const lines = resultLines(tool);
|
|
146
|
+
const table = resultTable(tool);
|
|
147
|
+
if (lines.length === 0 && !table) return null;
|
|
148
|
+
return (
|
|
149
|
+
<>
|
|
150
|
+
{lines.map((l, i) => (
|
|
151
|
+
<p key={i} className="my-[0.12rem] whitespace-pre-wrap break-words font-mono text-[0.74rem] leading-[1.5] text-term-mute">
|
|
152
|
+
{l}
|
|
153
|
+
</p>
|
|
154
|
+
))}
|
|
155
|
+
{table ? (
|
|
156
|
+
<div className="my-1 max-w-full overflow-x-auto">
|
|
157
|
+
<table className="border-collapse font-mono text-[0.72rem] leading-[1.4]">
|
|
158
|
+
<thead>
|
|
159
|
+
<tr>
|
|
160
|
+
{table.columns.map((c, i) => (
|
|
161
|
+
<th key={i} scope="col" className="border border-term-hair px-2 py-1 text-start font-normal text-term-ink">
|
|
162
|
+
{c}
|
|
163
|
+
</th>
|
|
164
|
+
))}
|
|
165
|
+
</tr>
|
|
166
|
+
</thead>
|
|
167
|
+
<tbody>
|
|
168
|
+
{table.rows.map((row, ri) => (
|
|
169
|
+
<tr key={ri}>
|
|
170
|
+
{row.map((cell, ci) => (
|
|
171
|
+
<td key={ci} className="whitespace-nowrap border border-term-hair px-2 py-1 text-term-mute">
|
|
172
|
+
{cell}
|
|
173
|
+
</td>
|
|
174
|
+
))}
|
|
175
|
+
</tr>
|
|
176
|
+
))}
|
|
177
|
+
</tbody>
|
|
178
|
+
</table>
|
|
179
|
+
</div>
|
|
180
|
+
) : null}
|
|
181
|
+
</>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function srLine(step: ChatPlaybackStep): string {
|
|
186
|
+
if (step.role === "user") return `You: ${step.text ?? ""}`;
|
|
187
|
+
if (step.role === "assistant") return `Assistant: ${step.text ?? ""}`;
|
|
188
|
+
const t = step.tool;
|
|
189
|
+
if (!t) return "Tool call";
|
|
190
|
+
const call = `Tool call: ${t.name}${t.args ? `(${t.args})` : ""}.`;
|
|
191
|
+
if (t.result === undefined) return call;
|
|
192
|
+
if (t.masked) return `${call} The result is withheld in this simulation.`;
|
|
193
|
+
const table = resultTable(t);
|
|
194
|
+
if (table) {
|
|
195
|
+
return `${call} Result table, columns ${table.columns.join(", ")}: ${table.rows.map((r) => r.join(" / ")).join("; ")}.`;
|
|
196
|
+
}
|
|
197
|
+
return `${call} Result: ${resultLines(t).join(" ")}`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const CTL =
|
|
201
|
+
"shrink-0 cursor-pointer bg-transparent p-0 font-[inherit] text-ink-mute transition-colors hover:text-ink focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-accent";
|
|
202
|
+
|
|
203
|
+
const STATUS_WORD: Record<Mode, string> = {
|
|
204
|
+
static: "transcript",
|
|
205
|
+
armed: "waiting for view",
|
|
206
|
+
playing: "playing",
|
|
207
|
+
paused: "paused",
|
|
208
|
+
done: "done",
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
function Caret() {
|
|
212
|
+
return (
|
|
213
|
+
<span
|
|
214
|
+
aria-hidden="true"
|
|
215
|
+
className="ms-[0.15rem] inline-block h-[0.95em] w-[0.5ch] translate-y-[0.12em] bg-accent motion-safe:animate-pulse"
|
|
216
|
+
/>
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function ChatPlayback({ script, badge, header, ariaLabel, className }: ChatPlaybackProps) {
|
|
221
|
+
const safe = useMotionSafe();
|
|
222
|
+
const [s, dispatch] = useReducer(reduce, FULL);
|
|
223
|
+
const frameRef = useRef<HTMLElement>(null);
|
|
224
|
+
const scrollRef = useRef<HTMLDivElement>(null);
|
|
225
|
+
const total = script.length;
|
|
226
|
+
|
|
227
|
+
// Arm (empty, wait for view) only when motion is allowed and IO exists;
|
|
228
|
+
// otherwise — reduced motion, no IO, SSR — the full transcript stays.
|
|
229
|
+
useEffect(() => {
|
|
230
|
+
if (!safe || total === 0 || typeof IntersectionObserver === "undefined") {
|
|
231
|
+
dispatch({ type: "static" });
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
dispatch({ type: "arm" });
|
|
235
|
+
}, [safe, total]);
|
|
236
|
+
|
|
237
|
+
useEffect(() => {
|
|
238
|
+
if (s.mode !== "armed") return;
|
|
239
|
+
const el = frameRef.current;
|
|
240
|
+
if (!el) return;
|
|
241
|
+
// CodeQL js/superfluous-trailing-arguments false positive: the DOM
|
|
242
|
+
// IntersectionObserver constructor takes (callback, options?) — both args are consumed.
|
|
243
|
+
const io = new IntersectionObserver(
|
|
244
|
+
(entries) => {
|
|
245
|
+
if (entries.some((e) => e.isIntersecting)) {
|
|
246
|
+
dispatch({ type: "play" });
|
|
247
|
+
io.disconnect();
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
{ threshold: 0.35 },
|
|
251
|
+
);
|
|
252
|
+
io.observe(el);
|
|
253
|
+
return () => io.disconnect();
|
|
254
|
+
}, [s.mode]);
|
|
255
|
+
|
|
256
|
+
// The one timer: a wait before the step, then ~30ms ticks while text types,
|
|
257
|
+
// or a single settle delay for a tool call.
|
|
258
|
+
useEffect(() => {
|
|
259
|
+
if (s.mode !== "playing") return;
|
|
260
|
+
const cur = script[s.step];
|
|
261
|
+
if (!cur) return;
|
|
262
|
+
const isTool = cur.role === "tool";
|
|
263
|
+
const len = isTool ? 0 : (cur.text ?? "").length;
|
|
264
|
+
const delay =
|
|
265
|
+
s.phase === "wait"
|
|
266
|
+
? (cur.delayMs ?? DEFAULT_DELAY[cur.role])
|
|
267
|
+
: isTool
|
|
268
|
+
? (cur.tool?.runMs ?? 700)
|
|
269
|
+
: TICK_MS;
|
|
270
|
+
const id = setTimeout(
|
|
271
|
+
() =>
|
|
272
|
+
dispatch({
|
|
273
|
+
type: "advance",
|
|
274
|
+
len,
|
|
275
|
+
total,
|
|
276
|
+
rate: cur.role === "user" ? USER_CPS : ASSISTANT_CPS,
|
|
277
|
+
tool: isTool,
|
|
278
|
+
}),
|
|
279
|
+
delay,
|
|
280
|
+
);
|
|
281
|
+
return () => clearTimeout(id);
|
|
282
|
+
}, [s, script, total]);
|
|
283
|
+
|
|
284
|
+
// Follow the newest line inside the frame only (never scrolls the page).
|
|
285
|
+
useEffect(() => {
|
|
286
|
+
const el = scrollRef.current;
|
|
287
|
+
if (el && (s.mode === "playing" || s.mode === "done")) el.scrollTop = el.scrollHeight;
|
|
288
|
+
}, [s.mode, s.step, s.chars, s.phase]);
|
|
289
|
+
|
|
290
|
+
const full = s.mode === "static" || s.mode === "done";
|
|
291
|
+
const animated = s.mode !== "static";
|
|
292
|
+
const progress = full ? 1 : total === 0 ? 0 : Math.min(1, s.step / total);
|
|
293
|
+
|
|
294
|
+
const rows: ReactNode[] = [];
|
|
295
|
+
script.forEach((step, i) => {
|
|
296
|
+
const visible = full || i < s.step || (i === s.step && s.phase === "work" && s.mode !== "armed");
|
|
297
|
+
if (!visible) return;
|
|
298
|
+
const current = !full && i === s.step;
|
|
299
|
+
const typing = current && step.role !== "tool";
|
|
300
|
+
const text = step.text ?? "";
|
|
301
|
+
const shown = current && typing ? text.slice(0, s.chars) : text;
|
|
302
|
+
|
|
303
|
+
let body: ReactNode;
|
|
304
|
+
if (step.role === "tool" && step.tool) {
|
|
305
|
+
const settled = !current;
|
|
306
|
+
const hasResult = settled && step.tool.result !== undefined;
|
|
307
|
+
body = (
|
|
308
|
+
<ChatToolCall
|
|
309
|
+
name={step.tool.name}
|
|
310
|
+
args={step.tool.args}
|
|
311
|
+
status={settled ? "ok" : "running"}
|
|
312
|
+
open={hasResult}
|
|
313
|
+
>
|
|
314
|
+
{hasResult ? <ResultBody tool={step.tool} /> : undefined}
|
|
315
|
+
</ChatToolCall>
|
|
316
|
+
);
|
|
317
|
+
} else {
|
|
318
|
+
const isUser = step.role === "user";
|
|
319
|
+
body = (
|
|
320
|
+
<p className="m-0 flex items-baseline gap-2 font-mono text-[0.78rem] leading-[1.65] text-term-ink">
|
|
321
|
+
<span className="shrink-0 tracking-[0.04em] text-term-mute" aria-hidden="true">
|
|
322
|
+
{isUser ? "[you]" : "[agent]"}
|
|
323
|
+
</span>
|
|
324
|
+
<span className="min-w-0 whitespace-pre-wrap break-words">
|
|
325
|
+
{shown}
|
|
326
|
+
{typing ? <Caret /> : null}
|
|
327
|
+
</span>
|
|
328
|
+
</p>
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
rows.push(
|
|
333
|
+
animated ? (
|
|
334
|
+
<m.div
|
|
335
|
+
key={i}
|
|
336
|
+
className="py-[0.3rem]"
|
|
337
|
+
data-motion=""
|
|
338
|
+
initial={s.mode === "done" ? false : { opacity: 0, y: 6 }}
|
|
339
|
+
animate={{ opacity: 1, y: 0 }}
|
|
340
|
+
transition={{ duration: 0.22, ease: [0.16, 1, 0.3, 1] }}
|
|
341
|
+
>
|
|
342
|
+
{body}
|
|
343
|
+
</m.div>
|
|
344
|
+
) : (
|
|
345
|
+
<div key={i} className="py-[0.3rem]">
|
|
346
|
+
{body}
|
|
347
|
+
</div>
|
|
348
|
+
),
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const label = ariaLabel ?? header;
|
|
353
|
+
|
|
354
|
+
return (
|
|
355
|
+
<section
|
|
356
|
+
ref={frameRef}
|
|
357
|
+
role="region"
|
|
358
|
+
aria-label={label}
|
|
359
|
+
aria-live="off"
|
|
360
|
+
data-slot="chat-playback"
|
|
361
|
+
data-mode={s.mode}
|
|
362
|
+
className={cn("min-w-0 border border-hair bg-surface font-mono", className)}
|
|
363
|
+
>
|
|
364
|
+
<div className="flex items-center gap-3 border-b border-hair px-3 py-2 text-[0.68rem] tracking-[0.04em] text-ink-mute">
|
|
365
|
+
<span aria-hidden="true">[chat]</span>
|
|
366
|
+
<span className="min-w-0 flex-1 truncate text-ink-soft">{header}</span>
|
|
367
|
+
{s.mode === "playing" ? (
|
|
368
|
+
<button type="button" className={CTL} onClick={() => dispatch({ type: "pause" })} aria-label="Pause playback">
|
|
369
|
+
[pause]
|
|
370
|
+
</button>
|
|
371
|
+
) : null}
|
|
372
|
+
{s.mode === "paused" || s.mode === "armed" ? (
|
|
373
|
+
<button type="button" className={CTL} onClick={() => dispatch({ type: "play" })} aria-label="Play the scripted session">
|
|
374
|
+
[play]
|
|
375
|
+
</button>
|
|
376
|
+
) : null}
|
|
377
|
+
{s.mode === "playing" || s.mode === "paused" ? (
|
|
378
|
+
<button type="button" className={CTL} onClick={() => dispatch({ type: "skip" })} aria-label="Skip to the full transcript">
|
|
379
|
+
[skip]
|
|
380
|
+
</button>
|
|
381
|
+
) : null}
|
|
382
|
+
{s.mode === "done" ? (
|
|
383
|
+
<button type="button" className={CTL} onClick={() => dispatch({ type: "replay" })} aria-label="Replay the scripted session">
|
|
384
|
+
[replay]
|
|
385
|
+
</button>
|
|
386
|
+
) : null}
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
<div className="flex items-center gap-3 border-b border-hair px-3 py-1.5 text-[0.66rem] text-ink-soft">
|
|
390
|
+
<span className="min-w-0 flex-1" data-slot="chat-playback-badge">{`◇ ${badge}`}</span>
|
|
391
|
+
<span className="shrink-0 text-ink-mute" aria-hidden="true">{`[${STATUS_WORD[s.mode]}]`}</span>
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
<div aria-hidden="true" className="relative h-px bg-hair">
|
|
395
|
+
<div
|
|
396
|
+
className="absolute inset-0 origin-left bg-ink-mute transition-transform duration-200 motion-reduce:transition-none"
|
|
397
|
+
style={{ transform: `scaleX(${progress})` }}
|
|
398
|
+
/>
|
|
399
|
+
</div>
|
|
400
|
+
|
|
401
|
+
<div
|
|
402
|
+
ref={scrollRef}
|
|
403
|
+
className="h-[24rem] overflow-y-auto overscroll-contain bg-term-bg px-3 py-3 sm:h-[26rem] sm:px-4"
|
|
404
|
+
>
|
|
405
|
+
<div aria-hidden="true" inert>
|
|
406
|
+
{rows}
|
|
407
|
+
{s.mode === "done" ? (
|
|
408
|
+
<p className="m-0 pt-2 text-[0.68rem] tracking-[0.04em] text-term-mute">
|
|
409
|
+
{"── end of scripted session ──"}
|
|
410
|
+
</p>
|
|
411
|
+
) : null}
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
<ol className="sr-only" aria-label="Full transcript">
|
|
416
|
+
{script.map((step, i) => (
|
|
417
|
+
<li key={i}>{srLine(step)}</li>
|
|
418
|
+
))}
|
|
419
|
+
</ol>
|
|
420
|
+
</section>
|
|
421
|
+
);
|
|
422
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming caret — the blinking block cursor that marks text still arriving
|
|
3
|
+
* (canon §16): the ▍ read as a glyph-metric-free 7×14 accent block, steps(1)
|
|
4
|
+
* blink, holding a steady block under reduced motion. Same mark as
|
|
5
|
+
* digichat-ui's .dt-cur and digichat's .dc-term-streaming::after — both
|
|
6
|
+
* rebuild on .chat-cursor. Accepts a ref so imperative typewriter effects
|
|
7
|
+
* can toggle its visibility without re-rendering (see the stream-transcript
|
|
8
|
+
* specimen). Keyframes + reduced-motion guard live in styles/chat-core.css.
|
|
9
|
+
*/
|
|
10
|
+
import type { Ref } from "react";
|
|
11
|
+
|
|
12
|
+
export type ChatStreamCursorProps = {
|
|
13
|
+
className?: string;
|
|
14
|
+
ref?: Ref<HTMLSpanElement>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function ChatStreamCursor({ className, ref }: ChatStreamCursorProps) {
|
|
18
|
+
return (
|
|
19
|
+
<span
|
|
20
|
+
ref={ref}
|
|
21
|
+
className={["chat-cursor", className ?? ""].filter(Boolean).join(" ")}
|
|
22
|
+
aria-hidden="true"
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* ChatThinking — the reasoning disclosure promoted from the chatbot reference
|
|
4
|
+
* family (#1418): the model's chain of thought folded into a single chip —
|
|
5
|
+
* caret · dot · label · step count — that expands into an accent-railed step
|
|
6
|
+
* list. `live` pulses the dot while a run is streaming; a finished run reads
|
|
7
|
+
* its label at rest ("Thought for 4.2s"). Steps reveal one by one when
|
|
8
|
+
* scrolled into view (`animateIn`); reduced motion renders the whole chain
|
|
9
|
+
* settled. Uncontrolled by default (`defaultOpen`) or controlled via
|
|
10
|
+
* `open`/`onOpenChange`. Pass `steps` for the railed list, or `children` for
|
|
11
|
+
* a custom body (e.g. digichat’s reasoning part —
|
|
12
|
+
* `<ChatThinking label="Reasoning"><pre>{text}</pre></ChatThinking>`).
|
|
13
|
+
* Step text inherits the surrounding transcript font. Chip background/hover,
|
|
14
|
+
* caret art, the pulse, the step rail, and the reveal transitions live in
|
|
15
|
+
* styles/chat-widgets.css (import it once app-wide; see the wiring note
|
|
16
|
+
* there).
|
|
17
|
+
*/
|
|
18
|
+
import { useRef, useState, type ReactNode } from "react";
|
|
19
|
+
import { useInView } from "motion/react";
|
|
20
|
+
import { useMotionSafe } from "../../motion/primitives";
|
|
21
|
+
|
|
22
|
+
export type ChatThinkingProps = {
|
|
23
|
+
/** Chip label, e.g. `Thought for 4.2s` or `Thinking…`. */
|
|
24
|
+
label: ReactNode;
|
|
25
|
+
/** Reasoning steps, revealed down an accent rail. */
|
|
26
|
+
steps?: string[];
|
|
27
|
+
/** Right chip segment; defaults to `${steps.length} steps`. Pass null to hide. */
|
|
28
|
+
count?: ReactNode;
|
|
29
|
+
/** Pulse the dot while the run is live (off under reduced motion). */
|
|
30
|
+
live?: boolean;
|
|
31
|
+
/** Reveal steps as they scroll into view (default true; off under reduced motion). */
|
|
32
|
+
animateIn?: boolean;
|
|
33
|
+
defaultOpen?: boolean;
|
|
34
|
+
/** Controlled open state; omit to let the chip own it. */
|
|
35
|
+
open?: boolean;
|
|
36
|
+
onOpenChange?: (open: boolean) => void;
|
|
37
|
+
/** Custom disclosure body rendered under the chip (instead of / after `steps`). */
|
|
38
|
+
children?: ReactNode;
|
|
39
|
+
className?: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function ChatThinking({
|
|
43
|
+
label,
|
|
44
|
+
steps,
|
|
45
|
+
count,
|
|
46
|
+
live = false,
|
|
47
|
+
animateIn = true,
|
|
48
|
+
defaultOpen = false,
|
|
49
|
+
open,
|
|
50
|
+
onOpenChange,
|
|
51
|
+
children,
|
|
52
|
+
className,
|
|
53
|
+
}: ChatThinkingProps) {
|
|
54
|
+
const safe = useMotionSafe();
|
|
55
|
+
const [ownOpen, setOwnOpen] = useState(defaultOpen);
|
|
56
|
+
const isOpen = open !== undefined ? open : ownOpen;
|
|
57
|
+
|
|
58
|
+
const listRef = useRef<HTMLOListElement | null>(null);
|
|
59
|
+
const inView = useInView(listRef, { amount: 0.4, once: true });
|
|
60
|
+
const animate = animateIn && safe;
|
|
61
|
+
const revealed = !animate || inView;
|
|
62
|
+
|
|
63
|
+
const toggle = () => {
|
|
64
|
+
const next = !isOpen;
|
|
65
|
+
if (open === undefined) setOwnOpen(next);
|
|
66
|
+
onOpenChange?.(next);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const shownCount = count !== undefined ? count : steps ? `${steps.length} steps` : null;
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div className={`flex flex-col items-start gap-[0.55rem]${className ? ` ${className}` : ""}`}>
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
className={`think-chip inline-flex min-h-10 cursor-pointer items-center gap-[0.5rem] rounded-none border border-hair px-[0.7rem] py-[0.35rem] font-mono text-[0.7rem] text-ink-mute${
|
|
76
|
+
isOpen ? " open" : ""
|
|
77
|
+
}`}
|
|
78
|
+
aria-expanded={isOpen}
|
|
79
|
+
onClick={toggle}
|
|
80
|
+
>
|
|
81
|
+
<span className="think-caret" aria-hidden="true" />
|
|
82
|
+
<span className={`think-dot${live && safe ? " is-live" : ""}`} aria-hidden="true" />
|
|
83
|
+
{label}
|
|
84
|
+
{shownCount != null ? (
|
|
85
|
+
<span className="ms-[0.1rem] border-s border-hair ps-[0.5rem] text-ink-mute">
|
|
86
|
+
{shownCount}
|
|
87
|
+
</span>
|
|
88
|
+
) : null}
|
|
89
|
+
</button>
|
|
90
|
+
|
|
91
|
+
{isOpen && steps?.length ? (
|
|
92
|
+
<ol
|
|
93
|
+
ref={listRef}
|
|
94
|
+
className={`think-steps m-0 ms-[0.35rem] flex list-none flex-col gap-[0.5rem] p-0 ps-[1.4rem]${
|
|
95
|
+
revealed ? " in" : ""
|
|
96
|
+
}`}
|
|
97
|
+
>
|
|
98
|
+
{steps.map((s, i) => (
|
|
99
|
+
<li
|
|
100
|
+
key={s}
|
|
101
|
+
className="relative text-[0.8rem] leading-[1.5] text-ink-mute"
|
|
102
|
+
style={animate ? { transitionDelay: `${i * 90}ms` } : undefined}
|
|
103
|
+
>
|
|
104
|
+
{s}
|
|
105
|
+
</li>
|
|
106
|
+
))}
|
|
107
|
+
</ol>
|
|
108
|
+
) : null}
|
|
109
|
+
|
|
110
|
+
{isOpen ? children : null}
|
|
111
|
+
</div>
|
|
112
|
+
);
|
|
113
|
+
}
|