@butlerw/vellum 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/LICENSE +21 -0
- package/README.md +411 -0
- package/__fixtures__/responses/code-generation.json +42 -0
- package/__fixtures__/responses/error-response.json +20 -0
- package/__fixtures__/responses/hello-world.json +32 -0
- package/dist/auth-6MCXESOH.js +26 -0
- package/dist/chunk-SECXJGWA.js +597 -0
- package/dist/index.js +34023 -0
- package/package.json +67 -0
- package/src/__tests__/commands.e2e.test.ts +728 -0
- package/src/__tests__/credentials.test.ts +713 -0
- package/src/__tests__/mode-e2e.test.ts +391 -0
- package/src/__tests__/tui-integration.test.tsx +1271 -0
- package/src/agents/__tests__/task-persistence.test.ts +235 -0
- package/src/agents/commands/delegate.ts +240 -0
- package/src/agents/commands/index.ts +10 -0
- package/src/agents/commands/resume.ts +335 -0
- package/src/agents/index.ts +29 -0
- package/src/agents/task-persistence.ts +272 -0
- package/src/agents/task-resumption.ts +242 -0
- package/src/app.tsx +4737 -0
- package/src/commands/__tests__/.gitkeep +1 -0
- package/src/commands/__tests__/agents.test.ts +606 -0
- package/src/commands/__tests__/auth.test.ts +626 -0
- package/src/commands/__tests__/autocomplete.test.ts +683 -0
- package/src/commands/__tests__/batch.test.ts +287 -0
- package/src/commands/__tests__/chain-pipe-parser.test.ts +654 -0
- package/src/commands/__tests__/completion.test.ts +238 -0
- package/src/commands/__tests__/core.test.ts +363 -0
- package/src/commands/__tests__/executor.test.ts +496 -0
- package/src/commands/__tests__/exit-codes.test.ts +220 -0
- package/src/commands/__tests__/init.test.ts +243 -0
- package/src/commands/__tests__/language.test.ts +353 -0
- package/src/commands/__tests__/mode-cli.test.ts +667 -0
- package/src/commands/__tests__/model.test.ts +277 -0
- package/src/commands/__tests__/parser.test.ts +493 -0
- package/src/commands/__tests__/performance.bench.ts +380 -0
- package/src/commands/__tests__/registry.test.ts +534 -0
- package/src/commands/__tests__/resume.test.ts +449 -0
- package/src/commands/__tests__/security.test.ts +845 -0
- package/src/commands/__tests__/stream-json.test.ts +372 -0
- package/src/commands/__tests__/user-commands.test.ts +597 -0
- package/src/commands/adapters.ts +267 -0
- package/src/commands/agent.ts +395 -0
- package/src/commands/agents/generate.ts +506 -0
- package/src/commands/agents/index.ts +272 -0
- package/src/commands/agents/show.ts +271 -0
- package/src/commands/agents/validate.ts +387 -0
- package/src/commands/auth.ts +883 -0
- package/src/commands/autocomplete.ts +480 -0
- package/src/commands/batch/command.ts +388 -0
- package/src/commands/batch/executor.ts +361 -0
- package/src/commands/batch/index.ts +12 -0
- package/src/commands/commit.ts +235 -0
- package/src/commands/completion/index.ts +371 -0
- package/src/commands/condense.ts +191 -0
- package/src/commands/config.ts +344 -0
- package/src/commands/context-provider.ts +173 -0
- package/src/commands/copy.ts +329 -0
- package/src/commands/core/clear.ts +38 -0
- package/src/commands/core/exit.ts +43 -0
- package/src/commands/core/help.ts +354 -0
- package/src/commands/core/index.ts +15 -0
- package/src/commands/cost.ts +179 -0
- package/src/commands/credentials.tsx +618 -0
- package/src/commands/custom-agents/__tests__/custom-agents.test.ts +709 -0
- package/src/commands/custom-agents/create.ts +377 -0
- package/src/commands/custom-agents/export.ts +135 -0
- package/src/commands/custom-agents/import.ts +199 -0
- package/src/commands/custom-agents/index.ts +372 -0
- package/src/commands/custom-agents/info.ts +318 -0
- package/src/commands/custom-agents/list.ts +267 -0
- package/src/commands/custom-agents/validate.ts +388 -0
- package/src/commands/diff-mode.ts +241 -0
- package/src/commands/env.ts +53 -0
- package/src/commands/executor.ts +579 -0
- package/src/commands/exit-codes.ts +202 -0
- package/src/commands/index.ts +701 -0
- package/src/commands/init/index.ts +15 -0
- package/src/commands/init/prompts.ts +366 -0
- package/src/commands/init/templates/commands-readme.md +80 -0
- package/src/commands/init/templates/example-command.md +79 -0
- package/src/commands/init/templates/example-skill.md +168 -0
- package/src/commands/init/templates/example-workflow.md +101 -0
- package/src/commands/init/templates/prompts-readme.md +52 -0
- package/src/commands/init/templates/rules-readme.md +63 -0
- package/src/commands/init/templates/skills-readme.md +83 -0
- package/src/commands/init/templates/workflows-readme.md +94 -0
- package/src/commands/init.ts +391 -0
- package/src/commands/install.ts +90 -0
- package/src/commands/language.ts +191 -0
- package/src/commands/loaders/.gitkeep +1 -0
- package/src/commands/lsp.ts +199 -0
- package/src/commands/markdown-commands.ts +253 -0
- package/src/commands/mcp.ts +588 -0
- package/src/commands/memory/export.ts +341 -0
- package/src/commands/memory/index.ts +148 -0
- package/src/commands/memory/list.ts +261 -0
- package/src/commands/memory/search.ts +346 -0
- package/src/commands/memory/utils.ts +15 -0
- package/src/commands/metrics.ts +75 -0
- package/src/commands/migrate/index.ts +16 -0
- package/src/commands/migrate/prompts.ts +477 -0
- package/src/commands/mode.ts +331 -0
- package/src/commands/model.ts +298 -0
- package/src/commands/onboard.ts +205 -0
- package/src/commands/open.ts +169 -0
- package/src/commands/output/stream-json.ts +373 -0
- package/src/commands/parser/chain-parser.ts +370 -0
- package/src/commands/parser/index.ts +29 -0
- package/src/commands/parser/pipe-parser.ts +480 -0
- package/src/commands/parser.ts +588 -0
- package/src/commands/persistence.ts +355 -0
- package/src/commands/progress.ts +18 -0
- package/src/commands/prompt/index.ts +17 -0
- package/src/commands/prompt/validate.ts +621 -0
- package/src/commands/prompt-priority.ts +401 -0
- package/src/commands/registry.ts +374 -0
- package/src/commands/sandbox/index.ts +131 -0
- package/src/commands/security/index.ts +21 -0
- package/src/commands/security/input-sanitizer.ts +168 -0
- package/src/commands/security/permission-checker.ts +456 -0
- package/src/commands/security/sensitive-data.ts +350 -0
- package/src/commands/session/delete.ts +38 -0
- package/src/commands/session/export.ts +39 -0
- package/src/commands/session/index.ts +26 -0
- package/src/commands/session/list.ts +26 -0
- package/src/commands/session/resume.ts +562 -0
- package/src/commands/session/search.ts +434 -0
- package/src/commands/session/show.ts +26 -0
- package/src/commands/settings.ts +368 -0
- package/src/commands/setup.ts +23 -0
- package/src/commands/shell/index.ts +16 -0
- package/src/commands/shell/setup.ts +422 -0
- package/src/commands/shell-init.ts +50 -0
- package/src/commands/shell-integration/index.ts +194 -0
- package/src/commands/skill.ts +1220 -0
- package/src/commands/spec.ts +558 -0
- package/src/commands/status.ts +246 -0
- package/src/commands/theme.ts +211 -0
- package/src/commands/think.ts +551 -0
- package/src/commands/trust.ts +211 -0
- package/src/commands/tutorial.ts +522 -0
- package/src/commands/types.ts +512 -0
- package/src/commands/update.ts +274 -0
- package/src/commands/usage.ts +213 -0
- package/src/commands/user-commands.ts +630 -0
- package/src/commands/utils.ts +142 -0
- package/src/commands/vim.ts +152 -0
- package/src/commands/workflow.ts +257 -0
- package/src/components/header.tsx +25 -0
- package/src/components/input.tsx +25 -0
- package/src/components/message-list.tsx +32 -0
- package/src/components/status-bar.tsx +23 -0
- package/src/index.tsx +614 -0
- package/src/onboarding/__tests__/tutorial.test.ts +740 -0
- package/src/onboarding/index.ts +69 -0
- package/src/onboarding/tips/index.ts +9 -0
- package/src/onboarding/tips/tip-engine.ts +459 -0
- package/src/onboarding/tutorial/index.ts +88 -0
- package/src/onboarding/tutorial/lessons/basics.ts +151 -0
- package/src/onboarding/tutorial/lessons/index.ts +151 -0
- package/src/onboarding/tutorial/lessons/modes.ts +230 -0
- package/src/onboarding/tutorial/lessons/tools.ts +172 -0
- package/src/onboarding/tutorial/progress-tracker.ts +350 -0
- package/src/onboarding/tutorial/storage.ts +249 -0
- package/src/onboarding/tutorial/tutorial-system.ts +462 -0
- package/src/onboarding/tutorial/types.ts +310 -0
- package/src/orchestrator-singleton.ts +129 -0
- package/src/shutdown.ts +33 -0
- package/src/test/e2e/assertions.ts +267 -0
- package/src/test/e2e/fixtures.ts +204 -0
- package/src/test/e2e/harness.ts +575 -0
- package/src/test/e2e/index.ts +57 -0
- package/src/test/e2e/types.ts +228 -0
- package/src/test/fixtures/__tests__/fake-response-loader.test.ts +314 -0
- package/src/test/fixtures/fake-response-loader.ts +314 -0
- package/src/test/fixtures/index.ts +20 -0
- package/src/tui/__tests__/mcp-panel.test.tsx +82 -0
- package/src/tui/__tests__/mcp-wiring.test.tsx +78 -0
- package/src/tui/__tests__/mode-components.test.tsx +395 -0
- package/src/tui/__tests__/permission-ask-flow.test.tsx +138 -0
- package/src/tui/__tests__/sidebar-panel-data.test.tsx +148 -0
- package/src/tui/__tests__/tools-panel-hotkeys.test.tsx +41 -0
- package/src/tui/adapters/agent-adapter.ts +1008 -0
- package/src/tui/adapters/index.ts +48 -0
- package/src/tui/adapters/message-adapter.ts +315 -0
- package/src/tui/adapters/persistence-bridge.ts +331 -0
- package/src/tui/adapters/session-adapter.ts +419 -0
- package/src/tui/buffered-stdout.ts +223 -0
- package/src/tui/components/AgentProgress.tsx +424 -0
- package/src/tui/components/Banner/AsciiArt.ts +160 -0
- package/src/tui/components/Banner/Banner.tsx +355 -0
- package/src/tui/components/Banner/ShimmerContext.tsx +131 -0
- package/src/tui/components/Banner/ShimmerText.tsx +193 -0
- package/src/tui/components/Banner/TypeWriterGradient.tsx +321 -0
- package/src/tui/components/Banner/index.ts +61 -0
- package/src/tui/components/Banner/useShimmer.ts +241 -0
- package/src/tui/components/ChatView.tsx +11 -0
- package/src/tui/components/Checkpoint/CheckpointDiffView.tsx +371 -0
- package/src/tui/components/Checkpoint/SnapshotCheckpointPanel.tsx +440 -0
- package/src/tui/components/Checkpoint/index.ts +19 -0
- package/src/tui/components/CostDisplay.tsx +226 -0
- package/src/tui/components/InitErrorBanner.tsx +122 -0
- package/src/tui/components/Input/Autocomplete.tsx +603 -0
- package/src/tui/components/Input/EnhancedCommandInput.tsx +471 -0
- package/src/tui/components/Input/HighlightedText.tsx +236 -0
- package/src/tui/components/Input/MentionAutocomplete.tsx +375 -0
- package/src/tui/components/Input/TextInput.tsx +1002 -0
- package/src/tui/components/Input/__tests__/Autocomplete.test.tsx +374 -0
- package/src/tui/components/Input/__tests__/TextInput.test.tsx +241 -0
- package/src/tui/components/Input/__tests__/highlight.test.ts +219 -0
- package/src/tui/components/Input/__tests__/slash-command-utils.test.ts +104 -0
- package/src/tui/components/Input/highlight.ts +362 -0
- package/src/tui/components/Input/index.ts +36 -0
- package/src/tui/components/Input/slash-command-utils.ts +135 -0
- package/src/tui/components/Layout.tsx +432 -0
- package/src/tui/components/McpPanel.tsx +137 -0
- package/src/tui/components/MemoryPanel.tsx +448 -0
- package/src/tui/components/Messages/CodeBlock.tsx +527 -0
- package/src/tui/components/Messages/DiffView.tsx +679 -0
- package/src/tui/components/Messages/ImageReference.tsx +89 -0
- package/src/tui/components/Messages/MarkdownBlock.tsx +228 -0
- package/src/tui/components/Messages/MarkdownRenderer.tsx +498 -0
- package/src/tui/components/Messages/MessageBubble.tsx +270 -0
- package/src/tui/components/Messages/MessageList.tsx +1719 -0
- package/src/tui/components/Messages/StreamingText.tsx +216 -0
- package/src/tui/components/Messages/ThinkingBlock.tsx +408 -0
- package/src/tui/components/Messages/ToolResultPreview.tsx +243 -0
- package/src/tui/components/Messages/__tests__/CodeBlock.test.tsx +296 -0
- package/src/tui/components/Messages/__tests__/DiffView.test.tsx +239 -0
- package/src/tui/components/Messages/__tests__/MarkdownRenderer.test.tsx +303 -0
- package/src/tui/components/Messages/__tests__/MessageBubble.test.tsx +268 -0
- package/src/tui/components/Messages/__tests__/MessageList.test.tsx +324 -0
- package/src/tui/components/Messages/__tests__/StreamingText.test.tsx +215 -0
- package/src/tui/components/Messages/index.ts +25 -0
- package/src/tui/components/ModeIndicator.tsx +177 -0
- package/src/tui/components/ModeSelector.tsx +216 -0
- package/src/tui/components/ModelSelector.tsx +339 -0
- package/src/tui/components/OnboardingWizard.tsx +670 -0
- package/src/tui/components/PhaseProgressIndicator.tsx +270 -0
- package/src/tui/components/RateLimitIndicator.tsx +82 -0
- package/src/tui/components/ScreenReaderLayout.tsx +295 -0
- package/src/tui/components/SettingsPanel.tsx +643 -0
- package/src/tui/components/Sidebar/SystemStatusPanel.tsx +284 -0
- package/src/tui/components/Sidebar/index.ts +9 -0
- package/src/tui/components/Status/ModelStatusBar.tsx +270 -0
- package/src/tui/components/Status/index.ts +12 -0
- package/src/tui/components/StatusBar/AgentModeIndicator.tsx +257 -0
- package/src/tui/components/StatusBar/ContextProgress.tsx +167 -0
- package/src/tui/components/StatusBar/FileChangesIndicator.tsx +62 -0
- package/src/tui/components/StatusBar/GitIndicator.tsx +89 -0
- package/src/tui/components/StatusBar/HeaderBar.tsx +126 -0
- package/src/tui/components/StatusBar/ModelIndicator.tsx +157 -0
- package/src/tui/components/StatusBar/PersistenceStatusIndicator.tsx +210 -0
- package/src/tui/components/StatusBar/ResilienceIndicator.tsx +106 -0
- package/src/tui/components/StatusBar/SandboxIndicator.tsx +167 -0
- package/src/tui/components/StatusBar/StatusBar.tsx +368 -0
- package/src/tui/components/StatusBar/ThinkingModeIndicator.tsx +170 -0
- package/src/tui/components/StatusBar/TokenBreakdown.tsx +246 -0
- package/src/tui/components/StatusBar/TokenCounter.tsx +135 -0
- package/src/tui/components/StatusBar/TrustModeIndicator.tsx +130 -0
- package/src/tui/components/StatusBar/WorkspaceIndicator.tsx +86 -0
- package/src/tui/components/StatusBar/__tests__/AgentModeIndicator.test.tsx +193 -0
- package/src/tui/components/StatusBar/__tests__/StatusBar.test.tsx +729 -0
- package/src/tui/components/StatusBar/index.ts +60 -0
- package/src/tui/components/TipBanner.tsx +115 -0
- package/src/tui/components/TodoItem.tsx +208 -0
- package/src/tui/components/TodoPanel.tsx +455 -0
- package/src/tui/components/Tools/ApprovalQueue.tsx +407 -0
- package/src/tui/components/Tools/OptionSelector.tsx +160 -0
- package/src/tui/components/Tools/PermissionDialog.tsx +286 -0
- package/src/tui/components/Tools/ToolParams.tsx +483 -0
- package/src/tui/components/Tools/ToolsPanel.tsx +178 -0
- package/src/tui/components/Tools/__tests__/PermissionDialog.test.tsx +510 -0
- package/src/tui/components/Tools/__tests__/ToolParams.test.tsx +432 -0
- package/src/tui/components/Tools/index.ts +21 -0
- package/src/tui/components/TrustPrompt.tsx +279 -0
- package/src/tui/components/UpdateBanner.tsx +166 -0
- package/src/tui/components/VimModeIndicator.tsx +112 -0
- package/src/tui/components/backtrack/BacktrackControls.tsx +402 -0
- package/src/tui/components/backtrack/index.ts +13 -0
- package/src/tui/components/common/AutoApprovalStatus.tsx +251 -0
- package/src/tui/components/common/CostWarning.tsx +294 -0
- package/src/tui/components/common/DynamicShortcutHints.tsx +209 -0
- package/src/tui/components/common/EnhancedLoadingIndicator.tsx +305 -0
- package/src/tui/components/common/ErrorBoundary.tsx +140 -0
- package/src/tui/components/common/GradientText.tsx +224 -0
- package/src/tui/components/common/HotkeyHelpModal.tsx +193 -0
- package/src/tui/components/common/HotkeyHints.tsx +70 -0
- package/src/tui/components/common/MaxSizedBox.tsx +354 -0
- package/src/tui/components/common/NewMessagesBadge.tsx +65 -0
- package/src/tui/components/common/ProtectedFileLegend.tsx +89 -0
- package/src/tui/components/common/ScrollIndicator.tsx +160 -0
- package/src/tui/components/common/Spinner.tsx +342 -0
- package/src/tui/components/common/StreamingIndicator.tsx +316 -0
- package/src/tui/components/common/VirtualizedList/VirtualizedList.tsx +428 -0
- package/src/tui/components/common/VirtualizedList/hooks/index.ts +19 -0
- package/src/tui/components/common/VirtualizedList/hooks/useBatchedScroll.ts +64 -0
- package/src/tui/components/common/VirtualizedList/hooks/useScrollAnchor.ts +290 -0
- package/src/tui/components/common/VirtualizedList/hooks/useVirtualization.ts +340 -0
- package/src/tui/components/common/VirtualizedList/index.ts +30 -0
- package/src/tui/components/common/VirtualizedList/types.ts +107 -0
- package/src/tui/components/common/__tests__/NewMessagesBadge.test.tsx +74 -0
- package/src/tui/components/common/__tests__/ScrollIndicator.test.tsx +193 -0
- package/src/tui/components/common/index.ts +110 -0
- package/src/tui/components/index.ts +79 -0
- package/src/tui/components/session/CheckpointPanel.tsx +323 -0
- package/src/tui/components/session/RollbackDialog.tsx +169 -0
- package/src/tui/components/session/SessionItem.tsx +136 -0
- package/src/tui/components/session/SessionListPanel.tsx +252 -0
- package/src/tui/components/session/SessionPicker.tsx +449 -0
- package/src/tui/components/session/SessionPreview.tsx +240 -0
- package/src/tui/components/session/__tests__/session.test.tsx +408 -0
- package/src/tui/components/session/index.ts +28 -0
- package/src/tui/components/session/types.ts +116 -0
- package/src/tui/components/theme/__tests__/tokens.test.ts +471 -0
- package/src/tui/components/theme/index.ts +227 -0
- package/src/tui/components/theme/tokens.ts +484 -0
- package/src/tui/config/defaults.ts +134 -0
- package/src/tui/config/index.ts +17 -0
- package/src/tui/context/AnimationContext.tsx +284 -0
- package/src/tui/context/AppContext.tsx +349 -0
- package/src/tui/context/BracketedPasteContext.tsx +372 -0
- package/src/tui/context/LspContext.tsx +192 -0
- package/src/tui/context/McpContext.tsx +325 -0
- package/src/tui/context/MessagesContext.tsx +870 -0
- package/src/tui/context/OverflowContext.tsx +213 -0
- package/src/tui/context/RateLimitContext.tsx +108 -0
- package/src/tui/context/ResilienceContext.tsx +275 -0
- package/src/tui/context/RootProvider.tsx +136 -0
- package/src/tui/context/ScrollContext.tsx +331 -0
- package/src/tui/context/ToolsContext.tsx +702 -0
- package/src/tui/context/__tests__/BracketedPasteContext.test.tsx +416 -0
- package/src/tui/context/index.ts +140 -0
- package/src/tui/enterprise-integration.ts +282 -0
- package/src/tui/hooks/__tests__/useBacktrack.test.tsx +138 -0
- package/src/tui/hooks/__tests__/useBracketedPaste.test.tsx +222 -0
- package/src/tui/hooks/__tests__/useCopyMode.test.tsx +336 -0
- package/src/tui/hooks/__tests__/useHotkeys.ctrl-input.test.tsx +96 -0
- package/src/tui/hooks/__tests__/useHotkeys.test.tsx +454 -0
- package/src/tui/hooks/__tests__/useInputHistory.test.tsx +660 -0
- package/src/tui/hooks/__tests__/useLineBuffer.test.ts +295 -0
- package/src/tui/hooks/__tests__/useModeController.test.ts +137 -0
- package/src/tui/hooks/__tests__/useModeShortcuts.test.tsx +142 -0
- package/src/tui/hooks/__tests__/useScrollController.test.ts +464 -0
- package/src/tui/hooks/__tests__/useVim.test.tsx +531 -0
- package/src/tui/hooks/index.ts +252 -0
- package/src/tui/hooks/useAgentLoop.ts +712 -0
- package/src/tui/hooks/useAlternateBuffer.ts +398 -0
- package/src/tui/hooks/useAnimatedScrollbar.ts +241 -0
- package/src/tui/hooks/useBacktrack.ts +443 -0
- package/src/tui/hooks/useBracketedPaste.ts +104 -0
- package/src/tui/hooks/useCollapsible.ts +240 -0
- package/src/tui/hooks/useCopyMode.ts +382 -0
- package/src/tui/hooks/useCostSummary.ts +75 -0
- package/src/tui/hooks/useDesktopNotification.ts +414 -0
- package/src/tui/hooks/useDiffMode.ts +44 -0
- package/src/tui/hooks/useFileChangeStats.ts +110 -0
- package/src/tui/hooks/useFileSuggestions.ts +284 -0
- package/src/tui/hooks/useFlickerDetector.ts +250 -0
- package/src/tui/hooks/useGitStatus.ts +200 -0
- package/src/tui/hooks/useHotkeys.ts +579 -0
- package/src/tui/hooks/useImagePaste.ts +114 -0
- package/src/tui/hooks/useInputHighlight.ts +145 -0
- package/src/tui/hooks/useInputHistory.ts +246 -0
- package/src/tui/hooks/useKeyboardScroll.ts +209 -0
- package/src/tui/hooks/useLineBuffer.ts +356 -0
- package/src/tui/hooks/useMentionAutocomplete.ts +235 -0
- package/src/tui/hooks/useModeController.ts +167 -0
- package/src/tui/hooks/useModeShortcuts.ts +196 -0
- package/src/tui/hooks/usePermissionHandler.ts +146 -0
- package/src/tui/hooks/usePersistence.ts +480 -0
- package/src/tui/hooks/usePersistenceShortcuts.ts +225 -0
- package/src/tui/hooks/usePlaceholderRotation.ts +143 -0
- package/src/tui/hooks/useProviderStatus.ts +270 -0
- package/src/tui/hooks/useRateLimitStatus.ts +90 -0
- package/src/tui/hooks/useScreenReader.ts +315 -0
- package/src/tui/hooks/useScrollController.ts +450 -0
- package/src/tui/hooks/useScrollEventBatcher.ts +185 -0
- package/src/tui/hooks/useSidebarPanelData.ts +115 -0
- package/src/tui/hooks/useSmoothScroll.ts +202 -0
- package/src/tui/hooks/useSnapshots.ts +300 -0
- package/src/tui/hooks/useStateAndRef.ts +50 -0
- package/src/tui/hooks/useTerminalSize.ts +206 -0
- package/src/tui/hooks/useToolApprovalController.ts +91 -0
- package/src/tui/hooks/useVim.ts +334 -0
- package/src/tui/hooks/useWorkspace.ts +56 -0
- package/src/tui/i18n/__tests__/init.test.ts +278 -0
- package/src/tui/i18n/__tests__/language-config.test.ts +199 -0
- package/src/tui/i18n/__tests__/locale-detection.test.ts +250 -0
- package/src/tui/i18n/__tests__/settings-integration.test.ts +262 -0
- package/src/tui/i18n/index.ts +72 -0
- package/src/tui/i18n/init.ts +131 -0
- package/src/tui/i18n/language-config.ts +106 -0
- package/src/tui/i18n/locale-detection.ts +173 -0
- package/src/tui/i18n/settings-integration.ts +557 -0
- package/src/tui/i18n/tui-namespace.ts +538 -0
- package/src/tui/i18n/types.ts +312 -0
- package/src/tui/index.ts +43 -0
- package/src/tui/lsp-integration.ts +409 -0
- package/src/tui/metrics-integration.ts +366 -0
- package/src/tui/plugins.ts +383 -0
- package/src/tui/resilience.ts +342 -0
- package/src/tui/sandbox-integration.ts +317 -0
- package/src/tui/services/clipboard.ts +348 -0
- package/src/tui/services/fuzzy-search.ts +441 -0
- package/src/tui/services/index.ts +72 -0
- package/src/tui/services/markdown-renderer.ts +565 -0
- package/src/tui/services/open-external.ts +247 -0
- package/src/tui/services/syntax-highlighter.ts +483 -0
- package/src/tui/slash-commands.ts +12 -0
- package/src/tui/theme/index.ts +15 -0
- package/src/tui/theme/provider.tsx +206 -0
- package/src/tui/tip-integration.ts +300 -0
- package/src/tui/types/__tests__/ink-extended.test.ts +121 -0
- package/src/tui/types/ink-extended.ts +87 -0
- package/src/tui/utils/__tests__/bracketedPaste.test.ts +231 -0
- package/src/tui/utils/__tests__/heightEstimator.test.ts +157 -0
- package/src/tui/utils/__tests__/text-width.test.ts +158 -0
- package/src/tui/utils/__tests__/textSanitizer.test.ts +266 -0
- package/src/tui/utils/__tests__/ui-sizing.test.ts +169 -0
- package/src/tui/utils/bracketedPaste.ts +107 -0
- package/src/tui/utils/cursor-manager.ts +131 -0
- package/src/tui/utils/detectTerminal.ts +596 -0
- package/src/tui/utils/findLastSafeSplitPoint.ts +92 -0
- package/src/tui/utils/heightEstimator.ts +198 -0
- package/src/tui/utils/index.ts +91 -0
- package/src/tui/utils/isNarrowWidth.ts +52 -0
- package/src/tui/utils/stdoutGuard.ts +90 -0
- package/src/tui/utils/synchronized-update.ts +70 -0
- package/src/tui/utils/text-width.ts +225 -0
- package/src/tui/utils/textSanitizer.ts +225 -0
- package/src/tui/utils/textUtils.ts +114 -0
- package/src/tui/utils/ui-sizing.ts +192 -0
- package/src/tui-blessed/app.ts +160 -0
- package/src/tui-blessed/index.ts +2 -0
- package/src/tui-blessed/neo-blessed.d.ts +6 -0
- package/src/tui-blessed/test.ts +21 -0
- package/src/tui-blessed/types.ts +14 -0
- package/src/utils/icons.ts +130 -0
- package/src/utils/index.ts +33 -0
- package/src/utils/resume-hint.ts +86 -0
- package/src/version.ts +1 -0
- package/tsconfig.json +8 -0
- package/vitest.config.ts +35 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root Provider Composition
|
|
3
|
+
*
|
|
4
|
+
* Composes all context providers in the correct order for the Vellum TUI.
|
|
5
|
+
* This is the single entry point for providing all application contexts.
|
|
6
|
+
*
|
|
7
|
+
* @module tui/context/RootProvider
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ToolExecutor, ToolRegistry } from "@vellum/core";
|
|
11
|
+
import type { ThemeName, ThemePreset, VellumTheme } from "@vellum/shared";
|
|
12
|
+
import type React from "react";
|
|
13
|
+
import type { ReactNode } from "react";
|
|
14
|
+
|
|
15
|
+
import { ThemeProvider } from "../theme/provider.js";
|
|
16
|
+
import { AnimationProvider } from "./AnimationContext.js";
|
|
17
|
+
import { AppProvider, type AppState } from "./AppContext.js";
|
|
18
|
+
import { BracketedPasteProvider } from "./BracketedPasteContext.js";
|
|
19
|
+
import { LspProvider } from "./LspContext.js";
|
|
20
|
+
import { McpProvider } from "./McpContext.js";
|
|
21
|
+
import { type Message, MessagesProvider } from "./MessagesContext.js";
|
|
22
|
+
import { OverflowProvider } from "./OverflowContext.js";
|
|
23
|
+
import { ResilienceProvider } from "./ResilienceContext.js";
|
|
24
|
+
import { ScrollProvider } from "./ScrollContext.js";
|
|
25
|
+
import { ToolsProvider } from "./ToolsContext.js";
|
|
26
|
+
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// Types
|
|
29
|
+
// =============================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Props for the RootProvider component
|
|
33
|
+
*/
|
|
34
|
+
export interface RootProviderProps {
|
|
35
|
+
/**
|
|
36
|
+
* Children to render within all contexts
|
|
37
|
+
*/
|
|
38
|
+
readonly children: ReactNode;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Theme configuration - can be a theme name, preset, or VellumTheme object
|
|
42
|
+
*
|
|
43
|
+
* @default "dark"
|
|
44
|
+
*/
|
|
45
|
+
readonly theme?: ThemeName | ThemePreset | VellumTheme;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initial application state overrides
|
|
49
|
+
*
|
|
50
|
+
* Partial state that will be merged with the default initial state
|
|
51
|
+
*/
|
|
52
|
+
readonly initialAppState?: Partial<AppState>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Initial messages to populate the conversation
|
|
56
|
+
*/
|
|
57
|
+
readonly initialMessages?: readonly Message[];
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Optional tool registry for MCP tool registration
|
|
61
|
+
*/
|
|
62
|
+
readonly toolRegistry?: ToolRegistry;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Optional tool executor for MCP tool execution
|
|
66
|
+
*/
|
|
67
|
+
readonly toolExecutor?: ToolExecutor;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// Component
|
|
72
|
+
// =============================================================================
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Root provider component that composes all context providers
|
|
76
|
+
*
|
|
77
|
+
* Provider order (outermost to innermost):
|
|
78
|
+
* 1. ThemeProvider - Theme context for styling
|
|
79
|
+
* 2. AppProvider - Application state (mode, loading, errors)
|
|
80
|
+
* 3. MessagesProvider - Message/conversation state
|
|
81
|
+
* 4. ToolsProvider - Tool execution state
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```tsx
|
|
85
|
+
* // Basic usage with defaults
|
|
86
|
+
* <RootProvider>
|
|
87
|
+
* <App />
|
|
88
|
+
* </RootProvider>
|
|
89
|
+
*
|
|
90
|
+
* // With custom theme
|
|
91
|
+
* <RootProvider theme="dracula">
|
|
92
|
+
* <App />
|
|
93
|
+
* </RootProvider>
|
|
94
|
+
*
|
|
95
|
+
* // With initial state
|
|
96
|
+
* <RootProvider
|
|
97
|
+
* theme="dark"
|
|
98
|
+
* initialAppState={{ vimMode: true }}
|
|
99
|
+
* initialMessages={[]}
|
|
100
|
+
* >
|
|
101
|
+
* <App />
|
|
102
|
+
* </RootProvider>
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export function RootProvider({
|
|
106
|
+
children,
|
|
107
|
+
theme = "dark",
|
|
108
|
+
initialAppState,
|
|
109
|
+
initialMessages,
|
|
110
|
+
toolRegistry,
|
|
111
|
+
toolExecutor,
|
|
112
|
+
}: RootProviderProps): React.JSX.Element {
|
|
113
|
+
return (
|
|
114
|
+
<ThemeProvider theme={theme}>
|
|
115
|
+
<AnimationProvider>
|
|
116
|
+
<BracketedPasteProvider>
|
|
117
|
+
<OverflowProvider>
|
|
118
|
+
<ScrollProvider autoScrollToBottom>
|
|
119
|
+
<AppProvider initialState={initialAppState}>
|
|
120
|
+
<ResilienceProvider>
|
|
121
|
+
<McpProvider toolRegistry={toolRegistry} toolExecutor={toolExecutor}>
|
|
122
|
+
<LspProvider>
|
|
123
|
+
<MessagesProvider initialMessages={initialMessages}>
|
|
124
|
+
<ToolsProvider>{children}</ToolsProvider>
|
|
125
|
+
</MessagesProvider>
|
|
126
|
+
</LspProvider>
|
|
127
|
+
</McpProvider>
|
|
128
|
+
</ResilienceProvider>
|
|
129
|
+
</AppProvider>
|
|
130
|
+
</ScrollProvider>
|
|
131
|
+
</OverflowProvider>
|
|
132
|
+
</BracketedPasteProvider>
|
|
133
|
+
</AnimationProvider>
|
|
134
|
+
</ThemeProvider>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll Context
|
|
3
|
+
*
|
|
4
|
+
* Centralized scroll state management for the Vellum TUI.
|
|
5
|
+
* Provides a unified API for scroll position tracking and control
|
|
6
|
+
* across virtualized lists and scrollable regions.
|
|
7
|
+
*
|
|
8
|
+
* Ported from Gemini CLI for Vellum TUI.
|
|
9
|
+
*
|
|
10
|
+
* @module tui/context/ScrollContext
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import React, {
|
|
14
|
+
createContext,
|
|
15
|
+
type ReactNode,
|
|
16
|
+
useCallback,
|
|
17
|
+
useContext,
|
|
18
|
+
useMemo,
|
|
19
|
+
useRef,
|
|
20
|
+
useState,
|
|
21
|
+
} from "react";
|
|
22
|
+
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Types
|
|
25
|
+
// =============================================================================
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Current scroll state
|
|
29
|
+
*/
|
|
30
|
+
export interface ScrollState {
|
|
31
|
+
/** Current scroll position from top (in lines/rows) */
|
|
32
|
+
readonly scrollTop: number;
|
|
33
|
+
/** Maximum scroll position (totalHeight - containerHeight) */
|
|
34
|
+
readonly maxScrollTop: number;
|
|
35
|
+
/** Whether scrolled to the bottom */
|
|
36
|
+
readonly isAtBottom: boolean;
|
|
37
|
+
/** Whether scrolled to the top */
|
|
38
|
+
readonly isAtTop: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Context value providing scroll state and control functions
|
|
43
|
+
*/
|
|
44
|
+
export interface ScrollContextValue {
|
|
45
|
+
/** Current scroll state */
|
|
46
|
+
readonly state: ScrollState;
|
|
47
|
+
/**
|
|
48
|
+
* Scroll to an absolute position
|
|
49
|
+
* @param position - Target scroll position (clamped to valid range)
|
|
50
|
+
*/
|
|
51
|
+
readonly scrollTo: (position: number) => void;
|
|
52
|
+
/**
|
|
53
|
+
* Scroll to the bottom of the content
|
|
54
|
+
*/
|
|
55
|
+
readonly scrollToBottom: () => void;
|
|
56
|
+
/**
|
|
57
|
+
* Scroll to the top of the content
|
|
58
|
+
*/
|
|
59
|
+
readonly scrollToTop: () => void;
|
|
60
|
+
/**
|
|
61
|
+
* Scroll by a relative amount
|
|
62
|
+
* @param delta - Amount to scroll (positive = down, negative = up)
|
|
63
|
+
*/
|
|
64
|
+
readonly scrollBy: (delta: number) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Update the content dimensions (called by scrollable components)
|
|
67
|
+
* @param totalHeight - Total content height
|
|
68
|
+
* @param containerHeight - Visible container height
|
|
69
|
+
*/
|
|
70
|
+
readonly updateDimensions: (totalHeight: number, containerHeight: number) => void;
|
|
71
|
+
/**
|
|
72
|
+
* Register a scroll callback for external scroll events
|
|
73
|
+
* @param callback - Function called when scroll position changes externally
|
|
74
|
+
* @returns Cleanup function to unregister
|
|
75
|
+
*/
|
|
76
|
+
readonly onScrollChange: (callback: (scrollTop: number) => void) => () => void;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Props for the ScrollProvider component
|
|
81
|
+
*/
|
|
82
|
+
export interface ScrollProviderProps {
|
|
83
|
+
/** Children to render within the scroll context */
|
|
84
|
+
readonly children: ReactNode;
|
|
85
|
+
/** Initial scroll position (default: 0) */
|
|
86
|
+
readonly initialScrollTop?: number;
|
|
87
|
+
/** Whether to auto-scroll to bottom on new content (default: true) */
|
|
88
|
+
readonly autoScrollToBottom?: boolean;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// =============================================================================
|
|
92
|
+
// Context
|
|
93
|
+
// =============================================================================
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* React context for scroll state management
|
|
97
|
+
*/
|
|
98
|
+
export const ScrollContext = createContext<ScrollContextValue | null>(null);
|
|
99
|
+
|
|
100
|
+
// Set display name for debugging
|
|
101
|
+
ScrollContext.displayName = "ScrollContext";
|
|
102
|
+
|
|
103
|
+
// =============================================================================
|
|
104
|
+
// Provider Component
|
|
105
|
+
// =============================================================================
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* ScrollProvider manages centralized scroll state for the TUI.
|
|
109
|
+
*
|
|
110
|
+
* This provider enables coordinated scrolling across multiple components,
|
|
111
|
+
* such as synchronized sidebar and main content scrolling, or global
|
|
112
|
+
* keyboard-driven scroll control.
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```tsx
|
|
116
|
+
* <ScrollProvider autoScrollToBottom>
|
|
117
|
+
* <Layout>
|
|
118
|
+
* <MessageList />
|
|
119
|
+
* </Layout>
|
|
120
|
+
* </ScrollProvider>
|
|
121
|
+
*
|
|
122
|
+
* // In a child component:
|
|
123
|
+
* const { state, scrollBy, scrollToBottom } = useScroll();
|
|
124
|
+
*
|
|
125
|
+
* // Handle keyboard scroll
|
|
126
|
+
* useEffect(() => {
|
|
127
|
+
* if (keyPressed === 'j') scrollBy(1);
|
|
128
|
+
* if (keyPressed === 'k') scrollBy(-1);
|
|
129
|
+
* if (keyPressed === 'G') scrollToBottom();
|
|
130
|
+
* }, [keyPressed]);
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function ScrollProvider({
|
|
134
|
+
children,
|
|
135
|
+
initialScrollTop = 0,
|
|
136
|
+
autoScrollToBottom = true,
|
|
137
|
+
}: ScrollProviderProps): React.JSX.Element {
|
|
138
|
+
// Scroll position state
|
|
139
|
+
const [scrollTop, setScrollTop] = useState(initialScrollTop);
|
|
140
|
+
|
|
141
|
+
// Content dimensions (updated by scrollable components)
|
|
142
|
+
const [dimensions, setDimensions] = useState({
|
|
143
|
+
totalHeight: 0,
|
|
144
|
+
containerHeight: 0,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Track if user has scrolled away from bottom
|
|
148
|
+
const [userScrolledAway, setUserScrolledAway] = useState(false);
|
|
149
|
+
|
|
150
|
+
// Callback registry for external scroll listeners
|
|
151
|
+
const scrollCallbacks = useRef<Set<(scrollTop: number) => void>>(new Set());
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Calculate derived scroll state
|
|
155
|
+
*/
|
|
156
|
+
const maxScrollTop = Math.max(0, dimensions.totalHeight - dimensions.containerHeight);
|
|
157
|
+
const isAtBottom = scrollTop >= maxScrollTop - 1; // Allow 1-line tolerance
|
|
158
|
+
const isAtTop = scrollTop <= 0;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Notify all registered callbacks of scroll change
|
|
162
|
+
*/
|
|
163
|
+
const notifyScrollChange = useCallback((newScrollTop: number) => {
|
|
164
|
+
for (const callback of scrollCallbacks.current) {
|
|
165
|
+
callback(newScrollTop);
|
|
166
|
+
}
|
|
167
|
+
}, []);
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Scroll to an absolute position (clamped to valid range)
|
|
171
|
+
*/
|
|
172
|
+
const scrollTo = useCallback(
|
|
173
|
+
(position: number) => {
|
|
174
|
+
const clamped = Math.max(0, Math.min(maxScrollTop, position));
|
|
175
|
+
setScrollTop(clamped);
|
|
176
|
+
setUserScrolledAway(clamped < maxScrollTop - 1);
|
|
177
|
+
notifyScrollChange(clamped);
|
|
178
|
+
},
|
|
179
|
+
[maxScrollTop, notifyScrollChange]
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Scroll to the bottom
|
|
184
|
+
*/
|
|
185
|
+
const scrollToBottom = useCallback(() => {
|
|
186
|
+
setScrollTop(maxScrollTop);
|
|
187
|
+
setUserScrolledAway(false);
|
|
188
|
+
notifyScrollChange(maxScrollTop);
|
|
189
|
+
}, [maxScrollTop, notifyScrollChange]);
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Scroll to the top
|
|
193
|
+
*/
|
|
194
|
+
const scrollToTop = useCallback(() => {
|
|
195
|
+
setScrollTop(0);
|
|
196
|
+
setUserScrolledAway(true);
|
|
197
|
+
notifyScrollChange(0);
|
|
198
|
+
}, [notifyScrollChange]);
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Scroll by a relative amount
|
|
202
|
+
*/
|
|
203
|
+
const scrollBy = useCallback(
|
|
204
|
+
(delta: number) => {
|
|
205
|
+
setScrollTop((prev) => {
|
|
206
|
+
const newPos = Math.max(0, Math.min(maxScrollTop, prev + delta));
|
|
207
|
+
if (delta < 0) {
|
|
208
|
+
setUserScrolledAway(true);
|
|
209
|
+
} else if (newPos >= maxScrollTop - 1) {
|
|
210
|
+
setUserScrolledAway(false);
|
|
211
|
+
}
|
|
212
|
+
notifyScrollChange(newPos);
|
|
213
|
+
return newPos;
|
|
214
|
+
});
|
|
215
|
+
},
|
|
216
|
+
[maxScrollTop, notifyScrollChange]
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Update content dimensions (called by scrollable components)
|
|
221
|
+
*/
|
|
222
|
+
const updateDimensions = useCallback(
|
|
223
|
+
(totalHeight: number, containerHeight: number) => {
|
|
224
|
+
setDimensions({ totalHeight, containerHeight });
|
|
225
|
+
|
|
226
|
+
// Auto-scroll to bottom if enabled and user hasn't scrolled away
|
|
227
|
+
if (autoScrollToBottom && !userScrolledAway) {
|
|
228
|
+
const newMax = Math.max(0, totalHeight - containerHeight);
|
|
229
|
+
setScrollTop(newMax);
|
|
230
|
+
notifyScrollChange(newMax);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
[autoScrollToBottom, userScrolledAway, notifyScrollChange]
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Register a scroll change callback
|
|
238
|
+
*/
|
|
239
|
+
const onScrollChange = useCallback((callback: (scrollTop: number) => void): (() => void) => {
|
|
240
|
+
scrollCallbacks.current.add(callback);
|
|
241
|
+
return () => {
|
|
242
|
+
scrollCallbacks.current.delete(callback);
|
|
243
|
+
};
|
|
244
|
+
}, []);
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Memoized scroll state
|
|
248
|
+
*/
|
|
249
|
+
const state = useMemo<ScrollState>(
|
|
250
|
+
() => ({
|
|
251
|
+
scrollTop,
|
|
252
|
+
maxScrollTop,
|
|
253
|
+
isAtBottom,
|
|
254
|
+
isAtTop,
|
|
255
|
+
}),
|
|
256
|
+
[scrollTop, maxScrollTop, isAtBottom, isAtTop]
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Memoized context value
|
|
261
|
+
*/
|
|
262
|
+
const contextValue = useMemo<ScrollContextValue>(
|
|
263
|
+
() => ({
|
|
264
|
+
state,
|
|
265
|
+
scrollTo,
|
|
266
|
+
scrollToBottom,
|
|
267
|
+
scrollToTop,
|
|
268
|
+
scrollBy,
|
|
269
|
+
updateDimensions,
|
|
270
|
+
onScrollChange,
|
|
271
|
+
}),
|
|
272
|
+
[state, scrollTo, scrollToBottom, scrollToTop, scrollBy, updateDimensions, onScrollChange]
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
return <ScrollContext.Provider value={contextValue}>{children}</ScrollContext.Provider>;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// =============================================================================
|
|
279
|
+
// Hooks
|
|
280
|
+
// =============================================================================
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Hook to access the scroll context.
|
|
284
|
+
*
|
|
285
|
+
* @returns The scroll context value
|
|
286
|
+
* @throws Error if used outside of a ScrollProvider
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* ```tsx
|
|
290
|
+
* function ScrollIndicator() {
|
|
291
|
+
* const { state } = useScroll();
|
|
292
|
+
*
|
|
293
|
+
* return (
|
|
294
|
+
* <Text>
|
|
295
|
+
* {state.isAtTop ? '⬆ Top' : state.isAtBottom ? '⬇ Bottom' : `${state.scrollTop}/${state.maxScrollTop}`}
|
|
296
|
+
* </Text>
|
|
297
|
+
* );
|
|
298
|
+
* }
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
export function useScroll(): ScrollContextValue {
|
|
302
|
+
const context = useContext(ScrollContext);
|
|
303
|
+
|
|
304
|
+
if (context === null) {
|
|
305
|
+
throw new Error("useScroll must be used within a ScrollProvider");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return context;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Optional hook that returns null instead of throwing when used outside provider.
|
|
313
|
+
* Useful for components that may work with or without scroll context.
|
|
314
|
+
*
|
|
315
|
+
* @returns The scroll context value or null if not within a provider
|
|
316
|
+
*/
|
|
317
|
+
export function useScrollOptional(): ScrollContextValue | null {
|
|
318
|
+
return useContext(ScrollContext);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Hook that returns only the scroll state (no control functions).
|
|
323
|
+
* Useful for read-only scroll position display.
|
|
324
|
+
*
|
|
325
|
+
* @returns The current scroll state
|
|
326
|
+
* @throws Error if used outside of a ScrollProvider
|
|
327
|
+
*/
|
|
328
|
+
export function useScrollState(): ScrollState {
|
|
329
|
+
const { state } = useScroll();
|
|
330
|
+
return state;
|
|
331
|
+
}
|