@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,720 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
createContext,
|
|
10
|
+
useContext,
|
|
11
|
+
type ComponentPropsWithoutRef,
|
|
12
|
+
type ReactNode,
|
|
13
|
+
} from "react";
|
|
14
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
15
|
+
import { CheckIcon, ChevronDownIcon } from "lucide-react";
|
|
16
|
+
import { cn } from "../../../../../lib/utils";
|
|
17
|
+
import {
|
|
18
|
+
Popover,
|
|
19
|
+
PopoverContent,
|
|
20
|
+
PopoverTrigger,
|
|
21
|
+
} from "../ui/popover";
|
|
22
|
+
import {
|
|
23
|
+
Command,
|
|
24
|
+
CommandEmpty,
|
|
25
|
+
CommandGroup,
|
|
26
|
+
CommandInput,
|
|
27
|
+
CommandItem,
|
|
28
|
+
CommandList,
|
|
29
|
+
CommandSeparator,
|
|
30
|
+
} from "../ui/command";
|
|
31
|
+
import { RadioGroup } from "@base-ui/react/radio-group";
|
|
32
|
+
import { Radio } from "@base-ui/react/radio";
|
|
33
|
+
|
|
34
|
+
export type ModelSelectorEffortOption = {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const DEFAULT_EFFORT_OPTIONS: readonly ModelSelectorEffortOption[] = [
|
|
40
|
+
{ id: "low", name: "Low" },
|
|
41
|
+
{ id: "medium", name: "Med" },
|
|
42
|
+
{ id: "high", name: "High" },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export type ModelOption = {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
icon?: ReactNode;
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
/** Extra terms matched by ModelSelector.Search, in addition to id and name. */
|
|
52
|
+
keywords?: readonly string[];
|
|
53
|
+
/**
|
|
54
|
+
* Reasoning effort levels the model supports. Pass `true` for the default
|
|
55
|
+
* low/medium/high levels, or a custom list. Omit for models without
|
|
56
|
+
* configurable reasoning.
|
|
57
|
+
*/
|
|
58
|
+
efforts?: boolean | readonly ModelSelectorEffortOption[];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function getModelEfforts(
|
|
62
|
+
model: ModelOption | undefined,
|
|
63
|
+
): readonly ModelSelectorEffortOption[] | undefined {
|
|
64
|
+
if (!model?.efforts) return undefined;
|
|
65
|
+
return model.efforts === true ? DEFAULT_EFFORT_OPTIONS : model.efforts;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function resolveEffort(
|
|
69
|
+
efforts: readonly ModelSelectorEffortOption[] | undefined,
|
|
70
|
+
effort: string | undefined,
|
|
71
|
+
): string | undefined {
|
|
72
|
+
if (effort === undefined) return undefined;
|
|
73
|
+
return efforts?.some((e) => e.id === effort) ? effort : undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns the effort id if the given model supports it, otherwise undefined.
|
|
78
|
+
* Effort selection is kept sticky across model switches; this resolves what
|
|
79
|
+
* actually applies to the current model.
|
|
80
|
+
*/
|
|
81
|
+
export function resolveModelEffort(
|
|
82
|
+
models: readonly ModelOption[],
|
|
83
|
+
modelId: string | undefined,
|
|
84
|
+
effort: string | undefined,
|
|
85
|
+
): string | undefined {
|
|
86
|
+
return resolveEffort(
|
|
87
|
+
getModelEfforts(models.find((m) => m.id === modelId)),
|
|
88
|
+
effort,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function useControllableState<T>({
|
|
93
|
+
prop,
|
|
94
|
+
defaultProp,
|
|
95
|
+
onChange,
|
|
96
|
+
}: {
|
|
97
|
+
prop: T | undefined;
|
|
98
|
+
defaultProp: T | undefined;
|
|
99
|
+
onChange: ((next: T) => void) | undefined;
|
|
100
|
+
}) {
|
|
101
|
+
const [internal, setInternal] = useState(defaultProp);
|
|
102
|
+
const isControlled = prop !== undefined;
|
|
103
|
+
const value = isControlled ? prop : internal;
|
|
104
|
+
// Read onChange through a ref so inline callbacks don't recreate the setter
|
|
105
|
+
// (and with it the memoized context value) every render.
|
|
106
|
+
const onChangeRef = useRef(onChange);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
onChangeRef.current = onChange;
|
|
109
|
+
});
|
|
110
|
+
const setValue = useCallback(
|
|
111
|
+
(next: T) => {
|
|
112
|
+
if (!isControlled) setInternal(next);
|
|
113
|
+
onChangeRef.current?.(next);
|
|
114
|
+
},
|
|
115
|
+
[isControlled],
|
|
116
|
+
);
|
|
117
|
+
return [value, setValue] as const;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
type ModelSelectorContextValue = {
|
|
121
|
+
models: readonly ModelOption[];
|
|
122
|
+
value: string | undefined;
|
|
123
|
+
setValue: (value: string) => void;
|
|
124
|
+
/** The model matching `value`, derived once for all sub-components. */
|
|
125
|
+
selectedModel: ModelOption | undefined;
|
|
126
|
+
/** The selected model's effort levels, undefined when not configurable. */
|
|
127
|
+
efforts: readonly ModelSelectorEffortOption[] | undefined;
|
|
128
|
+
/** Effort resolved against the selected model's supported levels. */
|
|
129
|
+
effort: string | undefined;
|
|
130
|
+
setEffort: (effort: string) => void;
|
|
131
|
+
setOpen: (open: boolean) => void;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const ModelSelectorContext = createContext<ModelSelectorContextValue | null>(
|
|
135
|
+
null,
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
export function useModelSelectorContext() {
|
|
139
|
+
const ctx = useContext(ModelSelectorContext);
|
|
140
|
+
if (!ctx) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
"ModelSelector sub-components must be used within ModelSelector.Root",
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return ctx;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The selected model's effort levels and the active selection. Use it to build
|
|
150
|
+
* a custom effort UI inside ModelSelector.Content (e.g. a slider or a shadcn
|
|
151
|
+
* DropdownMenu) when the built-in ModelSelector.Effort layout doesn't fit.
|
|
152
|
+
* `efforts` is undefined for models without configurable reasoning.
|
|
153
|
+
*/
|
|
154
|
+
export function useModelSelectorEfforts(): {
|
|
155
|
+
efforts: readonly ModelSelectorEffortOption[] | undefined;
|
|
156
|
+
effort: string | undefined;
|
|
157
|
+
setEffort: (effort: string) => void;
|
|
158
|
+
} {
|
|
159
|
+
const { efforts, effort, setEffort } = useModelSelectorContext();
|
|
160
|
+
return { efforts, effort, setEffort };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export type ModelSelectorRootProps = {
|
|
164
|
+
models: readonly ModelOption[];
|
|
165
|
+
value?: string;
|
|
166
|
+
defaultValue?: string;
|
|
167
|
+
onValueChange?: (value: string) => void;
|
|
168
|
+
effort?: string;
|
|
169
|
+
defaultEffort?: string;
|
|
170
|
+
onEffortChange?: (effort: string) => void;
|
|
171
|
+
open?: boolean;
|
|
172
|
+
defaultOpen?: boolean;
|
|
173
|
+
onOpenChange?: (open: boolean) => void;
|
|
174
|
+
children: ReactNode;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
function ModelSelectorRoot({
|
|
178
|
+
models,
|
|
179
|
+
value: valueProp,
|
|
180
|
+
defaultValue,
|
|
181
|
+
onValueChange,
|
|
182
|
+
effort: effortProp,
|
|
183
|
+
defaultEffort,
|
|
184
|
+
onEffortChange,
|
|
185
|
+
open: openProp,
|
|
186
|
+
defaultOpen,
|
|
187
|
+
onOpenChange,
|
|
188
|
+
children,
|
|
189
|
+
}: ModelSelectorRootProps) {
|
|
190
|
+
const [value, setValue] = useControllableState({
|
|
191
|
+
prop: valueProp,
|
|
192
|
+
defaultProp: defaultValue ?? models[0]?.id,
|
|
193
|
+
onChange: onValueChange,
|
|
194
|
+
});
|
|
195
|
+
const [effort, setEffort] = useControllableState({
|
|
196
|
+
prop: effortProp,
|
|
197
|
+
defaultProp: defaultEffort,
|
|
198
|
+
onChange: onEffortChange,
|
|
199
|
+
});
|
|
200
|
+
const [open, setOpen] = useControllableState({
|
|
201
|
+
prop: openProp,
|
|
202
|
+
defaultProp: defaultOpen ?? false,
|
|
203
|
+
onChange: onOpenChange,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const selectedModel = models.find((m) => m.id === value);
|
|
207
|
+
const efforts = getModelEfforts(selectedModel);
|
|
208
|
+
const activeEffort = resolveEffort(efforts, effort);
|
|
209
|
+
const contextValue = useMemo(
|
|
210
|
+
() => ({
|
|
211
|
+
models,
|
|
212
|
+
value,
|
|
213
|
+
setValue,
|
|
214
|
+
selectedModel,
|
|
215
|
+
efforts,
|
|
216
|
+
effort: activeEffort,
|
|
217
|
+
setEffort,
|
|
218
|
+
setOpen,
|
|
219
|
+
}),
|
|
220
|
+
[
|
|
221
|
+
models,
|
|
222
|
+
value,
|
|
223
|
+
setValue,
|
|
224
|
+
selectedModel,
|
|
225
|
+
efforts,
|
|
226
|
+
activeEffort,
|
|
227
|
+
setEffort,
|
|
228
|
+
setOpen,
|
|
229
|
+
],
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<ModelSelectorContext.Provider value={contextValue}>
|
|
234
|
+
<Popover open={open ?? false} onOpenChange={setOpen}>
|
|
235
|
+
{children}
|
|
236
|
+
</Popover>
|
|
237
|
+
</ModelSelectorContext.Provider>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export const modelSelectorTriggerVariants = cva(
|
|
242
|
+
"focus-visible:ring-ring/50 flex w-fit items-center justify-between gap-2 overflow-hidden rounded-md text-sm whitespace-nowrap transition-colors outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
|
|
243
|
+
{
|
|
244
|
+
variants: {
|
|
245
|
+
variant: {
|
|
246
|
+
outline:
|
|
247
|
+
"border-input hover:bg-muted hover:text-foreground border bg-transparent",
|
|
248
|
+
ghost: "hover:bg-muted hover:text-foreground",
|
|
249
|
+
muted: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
250
|
+
},
|
|
251
|
+
size: {
|
|
252
|
+
default: "h-9 px-3 py-2",
|
|
253
|
+
sm: "h-8 px-2.5 py-1.5 text-xs",
|
|
254
|
+
lg: "h-10 px-4 py-2.5",
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
defaultVariants: {
|
|
258
|
+
variant: "outline",
|
|
259
|
+
size: "default",
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
export type ModelSelectorTriggerProps = ComponentPropsWithoutRef<
|
|
265
|
+
typeof PopoverTrigger
|
|
266
|
+
> &
|
|
267
|
+
VariantProps<typeof modelSelectorTriggerVariants>;
|
|
268
|
+
|
|
269
|
+
function ModelSelectorTrigger({
|
|
270
|
+
className,
|
|
271
|
+
variant,
|
|
272
|
+
size,
|
|
273
|
+
children,
|
|
274
|
+
onKeyDown,
|
|
275
|
+
...props
|
|
276
|
+
}: ModelSelectorTriggerProps) {
|
|
277
|
+
const { setOpen } = useModelSelectorContext();
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
<PopoverTrigger
|
|
281
|
+
data-slot="model-selector-trigger"
|
|
282
|
+
data-variant={variant ?? "outline"}
|
|
283
|
+
data-size={size ?? "default"}
|
|
284
|
+
role="combobox"
|
|
285
|
+
aria-haspopup="listbox"
|
|
286
|
+
className={cn(modelSelectorTriggerVariants({ variant, size }), className)}
|
|
287
|
+
onKeyDown={(e) => {
|
|
288
|
+
onKeyDown?.(e);
|
|
289
|
+
if (e.defaultPrevented) return;
|
|
290
|
+
// ARIA combobox: arrows open the listbox from a focused trigger.
|
|
291
|
+
// Popover leaves this to the consumer.
|
|
292
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
293
|
+
e.preventDefault();
|
|
294
|
+
setOpen(true);
|
|
295
|
+
}
|
|
296
|
+
}}
|
|
297
|
+
{...props}
|
|
298
|
+
>
|
|
299
|
+
{children ?? <ModelSelectorValue />}
|
|
300
|
+
<ChevronDownIcon className="size-4 opacity-50" />
|
|
301
|
+
</PopoverTrigger>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export type ModelSelectorValueProps = {
|
|
306
|
+
placeholder?: ReactNode;
|
|
307
|
+
/** Show the active effort level next to the model name. */
|
|
308
|
+
showEffort?: boolean;
|
|
309
|
+
className?: string;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
function ModelIcon({
|
|
313
|
+
children,
|
|
314
|
+
className,
|
|
315
|
+
}: {
|
|
316
|
+
children: ReactNode;
|
|
317
|
+
className?: string;
|
|
318
|
+
}) {
|
|
319
|
+
return (
|
|
320
|
+
<span
|
|
321
|
+
className={cn(
|
|
322
|
+
"flex size-3.5 shrink-0 items-center justify-center [&_svg]:size-3.5",
|
|
323
|
+
className,
|
|
324
|
+
)}
|
|
325
|
+
>
|
|
326
|
+
{children}
|
|
327
|
+
</span>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function ModelSelectorValue({
|
|
332
|
+
placeholder = "Select model",
|
|
333
|
+
showEffort = true,
|
|
334
|
+
className,
|
|
335
|
+
}: ModelSelectorValueProps) {
|
|
336
|
+
const { selectedModel, efforts, effort } = useModelSelectorContext();
|
|
337
|
+
|
|
338
|
+
if (!selectedModel) {
|
|
339
|
+
return (
|
|
340
|
+
<span
|
|
341
|
+
data-slot="model-selector-value"
|
|
342
|
+
className={cn("text-muted-foreground", className)}
|
|
343
|
+
>
|
|
344
|
+
{placeholder}
|
|
345
|
+
</span>
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const effortName =
|
|
350
|
+
showEffort && effort !== undefined
|
|
351
|
+
? efforts?.find((e) => e.id === effort)?.name
|
|
352
|
+
: undefined;
|
|
353
|
+
|
|
354
|
+
return (
|
|
355
|
+
<span
|
|
356
|
+
data-slot="model-selector-value"
|
|
357
|
+
className={cn("flex min-w-0 items-center gap-2", className)}
|
|
358
|
+
>
|
|
359
|
+
{selectedModel.icon && <ModelIcon>{selectedModel.icon}</ModelIcon>}
|
|
360
|
+
<span className="truncate font-medium">{selectedModel.name}</span>
|
|
361
|
+
{effortName && (
|
|
362
|
+
<span className="text-muted-foreground min-w-7.5 truncate text-center">
|
|
363
|
+
{effortName}
|
|
364
|
+
</span>
|
|
365
|
+
)}
|
|
366
|
+
</span>
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export type ModelSelectorContentProps = Omit<
|
|
371
|
+
ComponentPropsWithoutRef<typeof PopoverContent>,
|
|
372
|
+
"side"
|
|
373
|
+
> & {
|
|
374
|
+
/**
|
|
375
|
+
* Preferred side for the initial placement. Once the popover is open, the
|
|
376
|
+
* rendered side takes over until it closes, so the popup does not jump
|
|
377
|
+
* between sides while filtering resizes the list.
|
|
378
|
+
*/
|
|
379
|
+
side?: ComponentPropsWithoutRef<typeof PopoverContent>["side"];
|
|
380
|
+
searchable?: boolean;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
// Base UI's Popover re-evaluates collision flipping whenever the popup
|
|
384
|
+
// resizes, so filtering the list down flips the popup back to the preferred
|
|
385
|
+
// side mid-interaction. Base UI only exposes its lazy-flip behavior on the
|
|
386
|
+
// Combobox positioner, so mirror it here: feed the rendered side back as the
|
|
387
|
+
// preferred side, making the popup keep its side until it no longer fits.
|
|
388
|
+
function useLazyFlipSide(): {
|
|
389
|
+
side: ModelSelectorContentProps["side"];
|
|
390
|
+
popupRef: (node: HTMLDivElement | null) => void;
|
|
391
|
+
} {
|
|
392
|
+
const [side, setSide] = useState<ModelSelectorContentProps["side"]>();
|
|
393
|
+
const observerRef = useRef<MutationObserver | null>(null);
|
|
394
|
+
const popupRef = useCallback((node: HTMLDivElement | null) => {
|
|
395
|
+
observerRef.current?.disconnect();
|
|
396
|
+
observerRef.current = null;
|
|
397
|
+
if (!node) {
|
|
398
|
+
setSide(undefined);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const sync = () => {
|
|
402
|
+
const rendered = node.getAttribute("data-side");
|
|
403
|
+
if (rendered) setSide(rendered as ModelSelectorContentProps["side"]);
|
|
404
|
+
};
|
|
405
|
+
sync();
|
|
406
|
+
const observer = new MutationObserver(sync);
|
|
407
|
+
observer.observe(node, {
|
|
408
|
+
attributes: true,
|
|
409
|
+
attributeFilter: ["data-side"],
|
|
410
|
+
});
|
|
411
|
+
observerRef.current = observer;
|
|
412
|
+
}, []);
|
|
413
|
+
return { side, popupRef };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Hidden input that anchors cmdk's keyboard navigation, keeping the list
|
|
418
|
+
* keyboard-operable without a visible search box. ModelSelectorContent renders
|
|
419
|
+
* one automatically when unfiltered.
|
|
420
|
+
*/
|
|
421
|
+
function ModelSelectorFocusAnchor() {
|
|
422
|
+
return (
|
|
423
|
+
<div className="sr-only">
|
|
424
|
+
<CommandInput readOnly aria-label="Model" />
|
|
425
|
+
</div>
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function ModelSelectorContent({
|
|
430
|
+
className,
|
|
431
|
+
align = "start",
|
|
432
|
+
side,
|
|
433
|
+
sideOffset = 6,
|
|
434
|
+
searchable,
|
|
435
|
+
children,
|
|
436
|
+
...props
|
|
437
|
+
}: ModelSelectorContentProps) {
|
|
438
|
+
const { value } = useModelSelectorContext();
|
|
439
|
+
const { side: renderedSide, popupRef } = useLazyFlipSide();
|
|
440
|
+
const unfiltered =
|
|
441
|
+
searchable === false || (!searchable && children === undefined);
|
|
442
|
+
|
|
443
|
+
return (
|
|
444
|
+
<PopoverContent
|
|
445
|
+
ref={popupRef}
|
|
446
|
+
data-slot="model-selector-content"
|
|
447
|
+
align={align}
|
|
448
|
+
side={renderedSide ?? side ?? "bottom"}
|
|
449
|
+
sideOffset={sideOffset}
|
|
450
|
+
className={cn(
|
|
451
|
+
"bg-popover w-72 min-w-(--anchor-width) overflow-hidden rounded-xl p-0",
|
|
452
|
+
className,
|
|
453
|
+
)}
|
|
454
|
+
{...props}
|
|
455
|
+
>
|
|
456
|
+
<Command
|
|
457
|
+
className="bg-transparent"
|
|
458
|
+
shouldFilter={!unfiltered}
|
|
459
|
+
{...(value !== undefined ? { defaultValue: value } : {})}
|
|
460
|
+
>
|
|
461
|
+
{unfiltered && <ModelSelectorFocusAnchor />}
|
|
462
|
+
{children ?? (
|
|
463
|
+
<>
|
|
464
|
+
{searchable && <ModelSelectorSearch />}
|
|
465
|
+
<ModelSelectorList />
|
|
466
|
+
<ModelSelectorEffort />
|
|
467
|
+
</>
|
|
468
|
+
)}
|
|
469
|
+
</Command>
|
|
470
|
+
</PopoverContent>
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export type ModelSelectorSearchProps = ComponentPropsWithoutRef<
|
|
475
|
+
typeof CommandInput
|
|
476
|
+
>;
|
|
477
|
+
|
|
478
|
+
function ModelSelectorSearch({
|
|
479
|
+
placeholder = "Search models...",
|
|
480
|
+
...props
|
|
481
|
+
}: ModelSelectorSearchProps) {
|
|
482
|
+
return (
|
|
483
|
+
<CommandInput
|
|
484
|
+
data-slot="model-selector-search"
|
|
485
|
+
placeholder={placeholder}
|
|
486
|
+
{...props}
|
|
487
|
+
/>
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export type ModelSelectorListProps = ComponentPropsWithoutRef<
|
|
492
|
+
typeof CommandList
|
|
493
|
+
>;
|
|
494
|
+
|
|
495
|
+
function ModelSelectorList({
|
|
496
|
+
className,
|
|
497
|
+
children,
|
|
498
|
+
...props
|
|
499
|
+
}: ModelSelectorListProps) {
|
|
500
|
+
const { models } = useModelSelectorContext();
|
|
501
|
+
|
|
502
|
+
return (
|
|
503
|
+
<CommandList
|
|
504
|
+
data-slot="model-selector-list"
|
|
505
|
+
className={cn(
|
|
506
|
+
"[-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
507
|
+
className,
|
|
508
|
+
)}
|
|
509
|
+
{...props}
|
|
510
|
+
>
|
|
511
|
+
{children ?? (
|
|
512
|
+
<>
|
|
513
|
+
<ModelSelectorEmpty />
|
|
514
|
+
<CommandGroup>
|
|
515
|
+
{models.map((model) => (
|
|
516
|
+
<ModelSelectorItem key={model.id} model={model} />
|
|
517
|
+
))}
|
|
518
|
+
</CommandGroup>
|
|
519
|
+
</>
|
|
520
|
+
)}
|
|
521
|
+
</CommandList>
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export type ModelSelectorEmptyProps = ComponentPropsWithoutRef<
|
|
526
|
+
typeof CommandEmpty
|
|
527
|
+
>;
|
|
528
|
+
|
|
529
|
+
function ModelSelectorEmpty({ children, ...props }: ModelSelectorEmptyProps) {
|
|
530
|
+
return (
|
|
531
|
+
<CommandEmpty data-slot="model-selector-empty" {...props}>
|
|
532
|
+
{children ?? "No models found."}
|
|
533
|
+
</CommandEmpty>
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export type ModelSelectorGroupProps = ComponentPropsWithoutRef<
|
|
538
|
+
typeof CommandGroup
|
|
539
|
+
>;
|
|
540
|
+
|
|
541
|
+
function ModelSelectorGroup(props: ModelSelectorGroupProps) {
|
|
542
|
+
return <CommandGroup data-slot="model-selector-group" {...props} />;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
export type ModelSelectorSeparatorProps = ComponentPropsWithoutRef<
|
|
546
|
+
typeof CommandSeparator
|
|
547
|
+
>;
|
|
548
|
+
|
|
549
|
+
function ModelSelectorSeparator(props: ModelSelectorSeparatorProps) {
|
|
550
|
+
return <CommandSeparator data-slot="model-selector-separator" {...props} />;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
export type ModelSelectorItemProps = Omit<
|
|
554
|
+
ComponentPropsWithoutRef<typeof CommandItem>,
|
|
555
|
+
"value"
|
|
556
|
+
> & {
|
|
557
|
+
model: ModelOption;
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
function ModelSelectorItem({
|
|
561
|
+
model,
|
|
562
|
+
className,
|
|
563
|
+
children,
|
|
564
|
+
onSelect,
|
|
565
|
+
...props
|
|
566
|
+
}: ModelSelectorItemProps) {
|
|
567
|
+
const { value, setValue, setOpen } = useModelSelectorContext();
|
|
568
|
+
const isSelected = value === model.id;
|
|
569
|
+
|
|
570
|
+
return (
|
|
571
|
+
<CommandItem
|
|
572
|
+
data-slot="model-selector-item"
|
|
573
|
+
value={model.id}
|
|
574
|
+
keywords={[model.name, ...(model.keywords ?? [])]}
|
|
575
|
+
{...(model.disabled ? { disabled: true } : undefined)}
|
|
576
|
+
onSelect={(selectedValue) => {
|
|
577
|
+
setValue(model.id);
|
|
578
|
+
setOpen(false);
|
|
579
|
+
onSelect?.(selectedValue);
|
|
580
|
+
}}
|
|
581
|
+
className={cn(
|
|
582
|
+
"relative items-start gap-2 rounded-lg py-2 ps-3 pe-9 [&_svg:not([class*='size-'])]:size-3.5",
|
|
583
|
+
className,
|
|
584
|
+
)}
|
|
585
|
+
{...props}
|
|
586
|
+
>
|
|
587
|
+
{children ?? (
|
|
588
|
+
<>
|
|
589
|
+
{model.icon && (
|
|
590
|
+
<ModelIcon className="mt-[3px]">{model.icon}</ModelIcon>
|
|
591
|
+
)}
|
|
592
|
+
<span className="flex min-w-0 flex-col">
|
|
593
|
+
<span className="truncate font-medium">{model.name}</span>
|
|
594
|
+
{model.description && (
|
|
595
|
+
<span className="text-muted-foreground truncate text-xs">
|
|
596
|
+
{model.description}
|
|
597
|
+
</span>
|
|
598
|
+
)}
|
|
599
|
+
</span>
|
|
600
|
+
</>
|
|
601
|
+
)}
|
|
602
|
+
{isSelected && (
|
|
603
|
+
<span className="absolute end-3 top-2.5 flex size-4 items-center justify-center">
|
|
604
|
+
<CheckIcon className="size-4" />
|
|
605
|
+
</span>
|
|
606
|
+
)}
|
|
607
|
+
</CommandItem>
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
export type ModelSelectorEffortProps = ComponentPropsWithoutRef<"div"> & {
|
|
612
|
+
label?: ReactNode;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
function ModelSelectorEffort({
|
|
616
|
+
label = "Thinking",
|
|
617
|
+
className,
|
|
618
|
+
onKeyDown,
|
|
619
|
+
onKeyDownCapture,
|
|
620
|
+
...props
|
|
621
|
+
}: ModelSelectorEffortProps) {
|
|
622
|
+
const { efforts, effort, setEffort } = useModelSelectorEfforts();
|
|
623
|
+
|
|
624
|
+
if (!efforts?.length) return null;
|
|
625
|
+
|
|
626
|
+
return (
|
|
627
|
+
<div
|
|
628
|
+
data-slot="model-selector-effort"
|
|
629
|
+
className={cn(
|
|
630
|
+
"flex cursor-default items-center justify-between gap-3 border-t px-3 py-2",
|
|
631
|
+
className,
|
|
632
|
+
)}
|
|
633
|
+
onKeyDownCapture={(e) => {
|
|
634
|
+
onKeyDownCapture?.(e);
|
|
635
|
+
if (e.defaultPrevented) return;
|
|
636
|
+
if (e.key !== "ArrowUp" && e.key !== "ArrowDown") return;
|
|
637
|
+
// Base UI's RadioGroup composite claims vertical arrows for roving
|
|
638
|
+
// focus (orientation "both", not configurable), so intercept them in
|
|
639
|
+
// capture and hand the keypress to cmdk: the model list owns vertical
|
|
640
|
+
// navigation, and cmdk's Enter is inert while a radio has focus.
|
|
641
|
+
onKeyDown?.(e);
|
|
642
|
+
if (e.defaultPrevented) return;
|
|
643
|
+
const input = e.currentTarget
|
|
644
|
+
.closest("[cmdk-root]")
|
|
645
|
+
?.querySelector<HTMLInputElement>("[cmdk-input]");
|
|
646
|
+
if (!input) return;
|
|
647
|
+
e.preventDefault();
|
|
648
|
+
e.stopPropagation();
|
|
649
|
+
input.focus();
|
|
650
|
+
input.dispatchEvent(new KeyboardEvent("keydown", e.nativeEvent));
|
|
651
|
+
}}
|
|
652
|
+
onKeyDown={(e) => {
|
|
653
|
+
if (e.key === "ArrowUp" || e.key === "ArrowDown") return;
|
|
654
|
+
onKeyDown?.(e);
|
|
655
|
+
if (e.defaultPrevented) return;
|
|
656
|
+
// Base UI's radio composite ignores Home/End and cmdk's Command
|
|
657
|
+
// root would claim them to jump the model list; move radio focus
|
|
658
|
+
// here so only the radiogroup reacts.
|
|
659
|
+
if (e.key === "Home" || e.key === "End") {
|
|
660
|
+
e.preventDefault();
|
|
661
|
+
e.stopPropagation();
|
|
662
|
+
const radios = Array.from(
|
|
663
|
+
e.currentTarget.querySelectorAll<HTMLElement>(
|
|
664
|
+
'[role="radio"]:not([data-disabled])',
|
|
665
|
+
),
|
|
666
|
+
);
|
|
667
|
+
(e.key === "Home" ? radios[0] : radios[radios.length - 1])?.focus();
|
|
668
|
+
}
|
|
669
|
+
}}
|
|
670
|
+
{...props}
|
|
671
|
+
>
|
|
672
|
+
<span className="text-muted-foreground text-xs">{label}</span>
|
|
673
|
+
<RadioGroup
|
|
674
|
+
value={effort ?? ""}
|
|
675
|
+
onValueChange={setEffort}
|
|
676
|
+
aria-label={typeof label === "string" ? label : "Reasoning effort"}
|
|
677
|
+
className="flex items-center gap-0.5"
|
|
678
|
+
>
|
|
679
|
+
{efforts.map((option) => (
|
|
680
|
+
<Radio.Root
|
|
681
|
+
key={option.id}
|
|
682
|
+
value={option.id}
|
|
683
|
+
className={cn(
|
|
684
|
+
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset text-muted-foreground hover:bg-muted hover:text-foreground cursor-pointer rounded-md px-2 py-1 text-xs transition-colors outline-none",
|
|
685
|
+
"data-checked:bg-muted data-checked:text-foreground data-checked:font-medium",
|
|
686
|
+
)}
|
|
687
|
+
>
|
|
688
|
+
{option.name}
|
|
689
|
+
</Radio.Root>
|
|
690
|
+
))}
|
|
691
|
+
</RadioGroup>
|
|
692
|
+
</div>
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
export type ModelSelectorProps = Omit<ModelSelectorRootProps, "children"> &
|
|
697
|
+
VariantProps<typeof modelSelectorTriggerVariants> & {
|
|
698
|
+
/** Render a search input above the model list. */
|
|
699
|
+
searchable?: boolean;
|
|
700
|
+
/** Alignment of the dropdown relative to the trigger. Use `"end"` when the
|
|
701
|
+
* trigger sits at the right edge of its container. */
|
|
702
|
+
align?: ModelSelectorContentProps["align"];
|
|
703
|
+
className?: string;
|
|
704
|
+
contentClassName?: string;
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
export {
|
|
708
|
+
ModelSelectorRoot,
|
|
709
|
+
ModelSelectorTrigger,
|
|
710
|
+
ModelSelectorValue,
|
|
711
|
+
ModelSelectorContent,
|
|
712
|
+
ModelSelectorSearch,
|
|
713
|
+
ModelSelectorFocusAnchor,
|
|
714
|
+
ModelSelectorList,
|
|
715
|
+
ModelSelectorEmpty,
|
|
716
|
+
ModelSelectorGroup,
|
|
717
|
+
ModelSelectorSeparator,
|
|
718
|
+
ModelSelectorItem,
|
|
719
|
+
ModelSelectorEffort,
|
|
720
|
+
};
|