@machina.ai/cell-cli 1.11.0-rc1 → 1.13.0-rc2
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/dist/package.json +16 -10
- package/dist/src/commands/extensions/disable.d.ts +1 -1
- package/dist/src/commands/extensions/disable.js +15 -7
- package/dist/src/commands/extensions/disable.js.map +1 -1
- package/dist/src/commands/extensions/enable.d.ts +1 -1
- package/dist/src/commands/extensions/enable.js +15 -7
- package/dist/src/commands/extensions/enable.js.map +1 -1
- package/dist/src/commands/extensions/install.js +14 -3
- package/dist/src/commands/extensions/install.js.map +1 -1
- package/dist/src/commands/extensions/install.test.js +39 -19
- package/dist/src/commands/extensions/install.test.js.map +1 -1
- package/dist/src/commands/extensions/link.js +14 -3
- package/dist/src/commands/extensions/link.js.map +1 -1
- package/dist/src/commands/extensions/list.js +13 -4
- package/dist/src/commands/extensions/list.js.map +1 -1
- package/dist/src/commands/extensions/uninstall.js +13 -2
- package/dist/src/commands/extensions/uninstall.js.map +1 -1
- package/dist/src/commands/extensions/update.js +18 -13
- package/dist/src/commands/extensions/update.js.map +1 -1
- package/dist/src/commands/extensions/validate.d.ts +12 -0
- package/dist/src/commands/extensions/validate.js +83 -0
- package/dist/src/commands/extensions/validate.js.map +1 -0
- package/dist/src/commands/extensions/validate.test.js +93 -0
- package/dist/src/commands/extensions/validate.test.js.map +1 -0
- package/dist/src/commands/extensions.js +3 -0
- package/dist/src/commands/extensions.js.map +1 -1
- package/dist/src/commands/mcp/add.test.js +3 -0
- package/dist/src/commands/mcp/add.test.js.map +1 -1
- package/dist/src/commands/mcp/list.js +10 -3
- package/dist/src/commands/mcp/list.js.map +1 -1
- package/dist/src/commands/mcp/list.test.js +37 -27
- package/dist/src/commands/mcp/list.test.js.map +1 -1
- package/dist/src/config/auth.js +0 -5
- package/dist/src/config/auth.js.map +1 -1
- package/dist/src/config/config.d.ts +6 -3
- package/dist/src/config/config.js +65 -80
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +235 -212
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extension-manager.d.ts +63 -0
- package/dist/src/config/extension-manager.js +450 -0
- package/dist/src/config/extension-manager.js.map +1 -0
- package/dist/src/config/extension.d.ts +4 -51
- package/dist/src/config/extension.js +1 -535
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/extension.test.js +525 -201
- package/dist/src/config/extension.test.js.map +1 -1
- package/dist/src/config/extensions/consent.d.ts +38 -0
- package/dist/src/config/extensions/consent.js +123 -0
- package/dist/src/config/extensions/consent.js.map +1 -0
- package/dist/src/config/extensions/extensionEnablement.d.ts +1 -1
- package/dist/src/config/extensions/extensionEnablement.js +4 -3
- package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
- package/dist/src/config/extensions/extensionEnablement.test.js +10 -10
- package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
- package/dist/src/config/extensions/extensionSettings.d.ts +15 -0
- package/dist/src/config/extensions/extensionSettings.js +113 -0
- package/dist/src/config/extensions/extensionSettings.js.map +1 -0
- package/dist/src/config/extensions/extensionSettings.test.d.ts +6 -0
- package/dist/src/config/extensions/extensionSettings.test.js +254 -0
- package/dist/src/config/extensions/extensionSettings.test.js.map +1 -0
- package/dist/src/config/extensions/github.d.ts +2 -2
- package/dist/src/config/extensions/github.js +5 -10
- package/dist/src/config/extensions/github.js.map +1 -1
- package/dist/src/config/extensions/github.test.js +153 -167
- package/dist/src/config/extensions/github.test.js.map +1 -1
- package/dist/src/config/extensions/github_fetch.d.ts +1 -1
- package/dist/src/config/extensions/github_fetch.js +13 -1
- package/dist/src/config/extensions/github_fetch.js.map +1 -1
- package/dist/src/config/extensions/github_fetch.test.d.ts +6 -0
- package/dist/src/config/extensions/github_fetch.test.js +169 -0
- package/dist/src/config/extensions/github_fetch.test.js.map +1 -0
- package/dist/src/config/extensions/storage.d.ts +14 -0
- package/dist/src/config/extensions/storage.js +32 -0
- package/dist/src/config/extensions/storage.js.map +1 -0
- package/dist/src/config/extensions/update.d.ts +4 -4
- package/dist/src/config/extensions/update.js +39 -39
- package/dist/src/config/extensions/update.js.map +1 -1
- package/dist/src/config/extensions/update.test.js +72 -74
- package/dist/src/config/extensions/update.test.js.map +1 -1
- package/dist/src/config/extensions/variableSchema.d.ts +0 -6
- package/dist/src/config/extensions/variableSchema.js.map +1 -1
- package/dist/src/config/extensions/variables.d.ts +4 -0
- package/dist/src/config/extensions/variables.js +6 -0
- package/dist/src/config/extensions/variables.js.map +1 -1
- package/dist/src/config/keyBindings.d.ts +3 -0
- package/dist/src/config/keyBindings.js +30 -8
- package/dist/src/config/keyBindings.js.map +1 -1
- package/dist/src/config/keyBindings.test.js +17 -0
- package/dist/src/config/keyBindings.test.js.map +1 -1
- package/dist/src/config/policies/read-only.toml +56 -0
- package/dist/src/config/policies/write.toml +63 -0
- package/dist/src/config/policies/yolo.toml +31 -0
- package/dist/src/config/policy-engine.integration.test.js +41 -38
- package/dist/src/config/policy-engine.integration.test.js.map +1 -1
- package/dist/src/config/policy.d.ts +2 -2
- package/dist/src/config/policy.js +10 -148
- package/dist/src/config/policy.js.map +1 -1
- package/dist/src/config/sandboxConfig.d.ts +1 -1
- package/dist/src/config/sandboxConfig.js +6 -3
- package/dist/src/config/sandboxConfig.js.map +1 -1
- package/dist/src/config/settings.d.ts +2 -1
- package/dist/src/config/settings.js +58 -18
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settings.test.js +128 -69
- package/dist/src/config/settings.test.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +170 -28
- package/dist/src/config/settingsSchema.js +418 -27
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/settingsSchema.test.js +42 -1
- package/dist/src/config/settingsSchema.test.js.map +1 -1
- package/dist/src/config/trustedFolders.d.ts +1 -1
- package/dist/src/config/trustedFolders.js +4 -2
- package/dist/src/config/trustedFolders.js.map +1 -1
- package/dist/src/core/initializer.js +2 -1
- package/dist/src/core/initializer.js.map +1 -1
- package/dist/src/gemini.d.ts +1 -1
- package/dist/src/gemini.js +46 -16
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +88 -30
- package/dist/src/gemini.test.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/nonInteractiveCli.d.ts +9 -1
- package/dist/src/nonInteractiveCli.js +114 -7
- package/dist/src/nonInteractiveCli.js.map +1 -1
- package/dist/src/nonInteractiveCli.test.js +355 -112
- package/dist/src/nonInteractiveCli.test.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +4 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.test.js +22 -0
- package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
- package/dist/src/services/FeedbackService.js +2 -2
- package/dist/src/services/FeedbackService.js.map +1 -1
- package/dist/src/services/McpPromptLoader.js +2 -2
- package/dist/src/services/McpPromptLoader.js.map +1 -1
- package/dist/src/services/McpPromptLoader.test.js +4 -2
- package/dist/src/services/McpPromptLoader.test.js.map +1 -1
- package/dist/src/test-utils/async.d.ts +9 -0
- package/dist/src/test-utils/async.js +29 -0
- package/dist/src/test-utils/async.js.map +1 -0
- package/dist/src/test-utils/createExtension.d.ts +3 -1
- package/dist/src/test-utils/createExtension.js +3 -3
- package/dist/src/test-utils/createExtension.js.map +1 -1
- package/dist/src/test-utils/render.d.ts +16 -2
- package/dist/src/test-utils/render.js +66 -4
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/test-utils/render.test.d.ts +6 -0
- package/dist/src/test-utils/render.test.js +79 -0
- package/dist/src/test-utils/render.test.js.map +1 -0
- package/dist/src/ui/App.test.js +1 -1
- package/dist/src/ui/App.test.js.map +1 -1
- package/dist/src/ui/AppContainer.js +181 -65
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +505 -147
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/IdeIntegrationNudge.js +1 -1
- package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
- package/dist/src/ui/auth/ApiAuthDialog.d.ts +14 -0
- package/dist/src/ui/auth/ApiAuthDialog.js +26 -0
- package/dist/src/ui/auth/ApiAuthDialog.js.map +1 -0
- package/dist/src/ui/auth/ApiAuthDialog.test.d.ts +6 -0
- package/dist/src/ui/auth/ApiAuthDialog.test.js +91 -0
- package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -0
- package/dist/src/ui/auth/AuthDialog.js +7 -3
- package/dist/src/ui/auth/AuthDialog.js.map +1 -1
- package/dist/src/ui/auth/useAuth.d.ts +2 -0
- package/dist/src/ui/auth/useAuth.js +31 -2
- package/dist/src/ui/auth/useAuth.js.map +1 -1
- package/dist/src/ui/colors.js +3 -0
- package/dist/src/ui/colors.js.map +1 -1
- package/dist/src/ui/commands/directoryCommand.js +1 -1
- package/dist/src/ui/commands/directoryCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.js +64 -11
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.test.js +72 -1
- package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +14 -14
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.test.js +4 -0
- package/dist/src/ui/commands/mcpCommand.test.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.js +1 -1
- package/dist/src/ui/commands/memoryCommand.js.map +1 -1
- package/dist/src/ui/commands/memoryCommand.test.js +3 -1
- package/dist/src/ui/commands/memoryCommand.test.js.map +1 -1
- package/dist/src/ui/commands/policiesCommand.d.ts +7 -0
- package/dist/src/ui/commands/policiesCommand.js +59 -0
- package/dist/src/ui/commands/policiesCommand.js.map +1 -0
- package/dist/src/ui/commands/policiesCommand.test.d.ts +6 -0
- package/dist/src/ui/commands/policiesCommand.test.js +83 -0
- package/dist/src/ui/commands/policiesCommand.test.js.map +1 -0
- package/dist/src/ui/components/AnsiOutput.test.js +1 -1
- package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
- package/dist/src/ui/components/AsciiArt.d.ts +3 -3
- package/dist/src/ui/components/AsciiArt.js +3 -3
- package/dist/src/ui/components/Composer.js +1 -1
- package/dist/src/ui/components/Composer.js.map +1 -1
- package/dist/src/ui/components/Composer.test.js +5 -2
- package/dist/src/ui/components/Composer.test.js.map +1 -1
- package/dist/src/ui/components/ConfigInitDisplay.js +4 -6
- package/dist/src/ui/components/ConfigInitDisplay.js.map +1 -1
- package/dist/src/ui/components/ConsentPrompt.test.js +18 -8
- package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.js +1 -1
- package/dist/src/ui/components/ConsoleSummaryDisplay.js.map +1 -1
- package/dist/src/ui/components/ContextSummaryDisplay.test.js +11 -6
- package/dist/src/ui/components/ContextSummaryDisplay.test.js.map +1 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.js +1 -1
- package/dist/src/ui/components/DetailedMessagesDisplay.js.map +1 -1
- package/dist/src/ui/components/DialogManager.js +4 -0
- package/dist/src/ui/components/DialogManager.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js +2 -1
- package/dist/src/ui/components/FolderTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/Footer.js +4 -3
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Footer.test.js +83 -0
- package/dist/src/ui/components/Footer.test.js.map +1 -1
- package/dist/src/ui/components/Header.test.js +13 -5
- package/dist/src/ui/components/Header.test.js.map +1 -1
- package/dist/src/ui/components/Help.test.js +5 -4
- package/dist/src/ui/components/Help.test.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +27 -8
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.test.js +776 -727
- package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
- package/dist/src/ui/components/LoadingIndicator.js +2 -2
- package/dist/src/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/src/ui/components/LoadingIndicator.test.js +28 -15
- package/dist/src/ui/components/LoadingIndicator.test.js.map +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.js +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js +2 -2
- package/dist/src/ui/components/LoopDetectionConfirmation.test.js.map +1 -1
- package/dist/src/ui/components/MainContent.js +15 -4
- package/dist/src/ui/components/MainContent.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.js +1 -1
- package/dist/src/ui/components/ModelDialog.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.test.js +23 -13
- package/dist/src/ui/components/ModelDialog.test.js.map +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.test.js +1 -1
- package/dist/src/ui/components/ModelStatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/Notifications.js +38 -5
- package/dist/src/ui/components/Notifications.js.map +1 -1
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +2 -2
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/PrepareLabel.test.js +14 -8
- package/dist/src/ui/components/PrepareLabel.test.js.map +1 -1
- package/dist/src/ui/components/ProQuotaDialog.test.js +14 -6
- package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
- package/dist/src/ui/components/QueuedMessageDisplay.test.js +11 -6
- package/dist/src/ui/components/QueuedMessageDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SessionSummaryDisplay.test.js +1 -1
- package/dist/src/ui/components/SessionSummaryDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.js +32 -25
- package/dist/src/ui/components/SettingsDialog.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.test.js +428 -532
- package/dist/src/ui/components/SettingsDialog.test.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.js +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.test.js +2 -2
- package/dist/src/ui/components/ShellConfirmationDialog.test.js.map +1 -1
- package/dist/src/ui/components/StatsDisplay.test.js +1 -1
- package/dist/src/ui/components/StatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.js +1 -1
- package/dist/src/ui/components/SuggestionsDisplay.js.map +1 -1
- package/dist/src/ui/components/ThemeDialog.test.js +2 -2
- package/dist/src/ui/components/ThemeDialog.test.js.map +1 -1
- package/dist/src/ui/components/ToolStatsDisplay.test.js +1 -1
- package/dist/src/ui/components/ToolStatsDisplay.test.js.map +1 -1
- package/dist/src/ui/components/messages/CompressionMessage.test.js +25 -17
- package/dist/src/ui/components/messages/CompressionMessage.test.js.map +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.js +1 -1
- package/dist/src/ui/components/messages/DiffRenderer.test.js.map +1 -1
- package/dist/src/ui/components/messages/InfoMessage.js +1 -1
- package/dist/src/ui/components/messages/InfoMessage.js.map +1 -1
- package/dist/src/ui/components/messages/Todo.js +27 -5
- package/dist/src/ui/components/messages/Todo.js.map +1 -1
- package/dist/src/ui/components/messages/Todo.test.js +20 -8
- package/dist/src/ui/components/messages/Todo.test.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js +29 -15
- package/dist/src/ui/components/messages/ToolGroupMessage.test.js.map +1 -1
- package/dist/src/ui/components/messages/WarningMessage.js +2 -2
- package/dist/src/ui/components/messages/WarningMessage.js.map +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.test.js +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
- package/dist/src/ui/components/shared/MaxSizedBox.test.js +43 -22
- package/dist/src/ui/components/shared/MaxSizedBox.test.js.map +1 -1
- package/dist/src/ui/components/shared/TextInput.d.ts +15 -0
- package/dist/src/ui/components/shared/TextInput.js +38 -0
- package/dist/src/ui/components/shared/TextInput.js.map +1 -0
- package/dist/src/ui/components/shared/TextInput.test.d.ts +6 -0
- package/dist/src/ui/components/shared/TextInput.test.js +242 -0
- package/dist/src/ui/components/shared/TextInput.test.js.map +1 -0
- package/dist/src/ui/components/shared/text-buffer.d.ts +9 -2
- package/dist/src/ui/components/shared/text-buffer.js +51 -13
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.test.js +385 -202
- package/dist/src/ui/components/shared/text-buffer.test.js.map +1 -1
- package/dist/src/ui/components/views/ChatList.test.js +7 -4
- package/dist/src/ui/components/views/ChatList.test.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.d.ts +7 -1
- package/dist/src/ui/components/views/ExtensionsList.js +9 -11
- package/dist/src/ui/components/views/ExtensionsList.js.map +1 -1
- package/dist/src/ui/components/views/ExtensionsList.test.js +43 -22
- package/dist/src/ui/components/views/ExtensionsList.test.js.map +1 -1
- package/dist/src/ui/components/views/McpStatus.test.js +23 -12
- package/dist/src/ui/components/views/McpStatus.test.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.d.ts +3 -2
- package/dist/src/ui/contexts/KeypressContext.js +610 -540
- package/dist/src/ui/contexts/KeypressContext.js.map +1 -1
- package/dist/src/ui/contexts/KeypressContext.test.js +438 -718
- package/dist/src/ui/contexts/KeypressContext.test.js.map +1 -1
- package/dist/src/ui/contexts/MouseContext.d.ts +21 -0
- package/dist/src/ui/contexts/MouseContext.js +89 -0
- package/dist/src/ui/contexts/MouseContext.js.map +1 -0
- package/dist/src/ui/contexts/MouseContext.test.d.ts +6 -0
- package/dist/src/ui/contexts/MouseContext.test.js +164 -0
- package/dist/src/ui/contexts/MouseContext.test.js.map +1 -0
- package/dist/src/ui/contexts/SessionContext.test.js +35 -17
- package/dist/src/ui/contexts/SessionContext.test.js.map +1 -1
- package/dist/src/ui/contexts/UIActionsContext.d.ts +2 -0
- package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
- package/dist/src/ui/contexts/UIStateContext.d.ts +2 -0
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.js +31 -9
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/atCommandProcessor.test.js +163 -64
- package/dist/src/ui/hooks/atCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.test.js +64 -35
- package/dist/src/ui/hooks/shellCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.test.js +193 -165
- package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/useAtCompletion.test.js +16 -5
- package/dist/src/ui/hooks/useAtCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js +10 -0
- package/dist/src/ui/hooks/useAutoAcceptIndicator.js.map +1 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js +32 -1
- package/dist/src/ui/hooks/useAutoAcceptIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useCommandCompletion.test.js +66 -64
- package/dist/src/ui/hooks/useCommandCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.test.js +26 -9
- package/dist/src/ui/hooks/useConsoleMessages.test.js.map +1 -1
- package/dist/src/ui/hooks/useEditorSettings.test.js +40 -34
- package/dist/src/ui/hooks/useEditorSettings.test.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +14 -5
- package/dist/src/ui/hooks/useExtensionUpdates.js +18 -13
- package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +49 -44
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
- package/dist/src/ui/hooks/useFlickerDetector.test.js +9 -5
- package/dist/src/ui/hooks/useFlickerDetector.test.js.map +1 -1
- package/dist/src/ui/hooks/useFocus.test.js +25 -9
- package/dist/src/ui/hooks/useFocus.test.js.map +1 -1
- package/dist/src/ui/hooks/useFolderTrust.test.js +46 -22
- package/dist/src/ui/hooks/useFolderTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +56 -19
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.test.js +260 -411
- package/dist/src/ui/hooks/useGeminiStream.test.js.map +1 -1
- package/dist/src/ui/hooks/useGitBranchName.js +4 -0
- package/dist/src/ui/hooks/useGitBranchName.js.map +1 -1
- package/dist/src/ui/hooks/useGitBranchName.test.js +46 -34
- package/dist/src/ui/hooks/useGitBranchName.test.js.map +1 -1
- package/dist/src/ui/hooks/useHistoryManager.test.js +2 -1
- package/dist/src/ui/hooks/useHistoryManager.test.js.map +1 -1
- package/dist/src/ui/hooks/useIdeTrustListener.test.js +40 -9
- package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -1
- package/dist/src/ui/hooks/useInputHistory.test.js +2 -1
- package/dist/src/ui/hooks/useInputHistory.test.js.map +1 -1
- package/dist/src/ui/hooks/useInputHistoryStore.test.js +2 -1
- package/dist/src/ui/hooks/useInputHistoryStore.test.js.map +1 -1
- package/dist/src/ui/hooks/useKeypress.test.js +103 -114
- package/dist/src/ui/hooks/useKeypress.test.js.map +1 -1
- package/dist/src/ui/hooks/useLoadingIndicator.test.js +24 -6
- package/dist/src/ui/hooks/useLoadingIndicator.test.js.map +1 -1
- package/dist/src/ui/hooks/useMemoryMonitor.test.js +10 -5
- package/dist/src/ui/hooks/useMemoryMonitor.test.js.map +1 -1
- package/dist/src/ui/hooks/useMessageQueue.test.js +62 -45
- package/dist/src/ui/hooks/useMessageQueue.test.js.map +1 -1
- package/dist/src/ui/hooks/useModelCommand.test.js +21 -11
- package/dist/src/ui/hooks/useModelCommand.test.js.map +1 -1
- package/dist/src/ui/hooks/useMouse.d.ts +17 -0
- package/dist/src/ui/hooks/useMouse.js +27 -0
- package/dist/src/ui/hooks/useMouse.js.map +1 -0
- package/dist/src/ui/hooks/useMouse.test.d.ts +6 -0
- package/dist/src/ui/hooks/useMouse.test.js +57 -0
- package/dist/src/ui/hooks/useMouse.test.js.map +1 -0
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js +2 -2
- package/dist/src/ui/hooks/usePermissionsModifyTrust.test.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.js +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.js.map +1 -1
- package/dist/src/ui/hooks/usePhraseCycler.test.js +109 -106
- package/dist/src/ui/hooks/usePhraseCycler.test.js.map +1 -1
- package/dist/src/ui/hooks/usePrivacySettings.test.js +26 -6
- package/dist/src/ui/hooks/usePrivacySettings.test.js.map +1 -1
- package/dist/src/ui/hooks/usePromptCompletion.js +2 -2
- package/dist/src/ui/hooks/usePromptCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.js +13 -14
- package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js +55 -48
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.d.ts +8 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +59 -34
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.test.d.ts +6 -0
- package/dist/src/ui/hooks/useReactToolScheduler.test.js +65 -0
- package/dist/src/ui/hooks/useReactToolScheduler.test.js.map +1 -0
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js +2 -2
- package/dist/src/ui/hooks/useReverseSearchCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.js +5 -4
- package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.test.js +272 -183
- package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
- package/dist/src/ui/hooks/useShellHistory.test.js +52 -20
- package/dist/src/ui/hooks/useShellHistory.test.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.js +18 -7
- package/dist/src/ui/hooks/useSlashCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +275 -137
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useTimer.test.js +43 -14
- package/dist/src/ui/hooks/useTimer.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +226 -242
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/hooks/vim.test.js +235 -355
- package/dist/src/ui/hooks/vim.test.js.map +1 -1
- package/dist/src/ui/keyMatchers.test.js +30 -3
- package/dist/src/ui/keyMatchers.test.js.map +1 -1
- package/dist/src/ui/state/extensions.d.ts +1 -0
- package/dist/src/ui/state/extensions.js +1 -0
- package/dist/src/ui/state/extensions.js.map +1 -1
- package/dist/src/ui/themes/ansi-light.js +1 -0
- package/dist/src/ui/themes/ansi-light.js.map +1 -1
- package/dist/src/ui/themes/ansi.js +1 -0
- package/dist/src/ui/themes/ansi.js.map +1 -1
- package/dist/src/ui/themes/atom-one-dark.js +2 -0
- package/dist/src/ui/themes/atom-one-dark.js.map +1 -1
- package/dist/src/ui/themes/ayu-light.js +2 -0
- package/dist/src/ui/themes/ayu-light.js.map +1 -1
- package/dist/src/ui/themes/ayu.js +2 -0
- package/dist/src/ui/themes/ayu.js.map +1 -1
- package/dist/src/ui/themes/color-utils.d.ts +1 -0
- package/dist/src/ui/themes/color-utils.js +6 -0
- package/dist/src/ui/themes/color-utils.js.map +1 -1
- package/dist/src/ui/themes/color-utils.test.js +13 -1
- package/dist/src/ui/themes/color-utils.test.js.map +1 -1
- package/dist/src/ui/themes/dracula.js +2 -0
- package/dist/src/ui/themes/dracula.js.map +1 -1
- package/dist/src/ui/themes/github-dark.js +2 -0
- package/dist/src/ui/themes/github-dark.js.map +1 -1
- package/dist/src/ui/themes/github-light.js +2 -0
- package/dist/src/ui/themes/github-light.js.map +1 -1
- package/dist/src/ui/themes/googlecode.js +2 -0
- package/dist/src/ui/themes/googlecode.js.map +1 -1
- package/dist/src/ui/themes/no-color.js +3 -0
- package/dist/src/ui/themes/no-color.js.map +1 -1
- package/dist/src/ui/themes/semantic-tokens.d.ts +2 -0
- package/dist/src/ui/themes/semantic-tokens.js +6 -0
- package/dist/src/ui/themes/semantic-tokens.js.map +1 -1
- package/dist/src/ui/themes/shades-of-purple.js +2 -0
- package/dist/src/ui/themes/shades-of-purple.js.map +1 -1
- package/dist/src/ui/themes/theme.d.ts +3 -0
- package/dist/src/ui/themes/theme.js +14 -3
- package/dist/src/ui/themes/theme.js.map +1 -1
- package/dist/src/ui/themes/theme.test.js +67 -1
- package/dist/src/ui/themes/theme.test.js.map +1 -1
- package/dist/src/ui/themes/xcode.js +2 -0
- package/dist/src/ui/themes/xcode.js.map +1 -1
- package/dist/src/ui/types.d.ts +3 -1
- package/dist/src/ui/types.js +2 -0
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/ui/utils/CodeColorizer.js +2 -1
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
- package/dist/src/ui/utils/InlineMarkdownRenderer.d.ts +1 -0
- package/dist/src/ui/utils/InlineMarkdownRenderer.js +11 -10
- package/dist/src/ui/utils/InlineMarkdownRenderer.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.js +11 -9
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
- package/dist/src/ui/utils/clipboardUtils.js +2 -2
- package/dist/src/ui/utils/clipboardUtils.js.map +1 -1
- package/dist/src/ui/utils/input.d.ts +17 -0
- package/dist/src/ui/utils/input.js +51 -0
- package/dist/src/ui/utils/input.js.map +1 -0
- package/dist/src/ui/utils/input.test.d.ts +6 -0
- package/dist/src/ui/utils/input.test.js +44 -0
- package/dist/src/ui/utils/input.test.js.map +1 -0
- package/dist/src/ui/utils/kittyProtocolDetector.js +13 -4
- package/dist/src/ui/utils/kittyProtocolDetector.js.map +1 -1
- package/dist/src/ui/utils/mouse.d.ts +31 -0
- package/dist/src/ui/utils/mouse.js +164 -0
- package/dist/src/ui/utils/mouse.js.map +1 -0
- package/dist/src/ui/utils/mouse.test.d.ts +6 -0
- package/dist/src/ui/utils/mouse.test.js +131 -0
- package/dist/src/ui/utils/mouse.test.js.map +1 -0
- package/dist/src/ui/utils/textOutput.d.ts +25 -0
- package/dist/src/ui/utils/textOutput.js +49 -0
- package/dist/src/ui/utils/textOutput.js.map +1 -0
- package/dist/src/ui/utils/textOutput.test.d.ts +6 -0
- package/dist/src/ui/utils/textOutput.test.js +79 -0
- package/dist/src/ui/utils/textOutput.test.js.map +1 -0
- package/dist/src/ui/utils/updateCheck.d.ts +7 -1
- package/dist/src/ui/utils/updateCheck.js +33 -29
- package/dist/src/ui/utils/updateCheck.js.map +1 -1
- package/dist/src/ui/utils/updateCheck.test.js +24 -50
- package/dist/src/ui/utils/updateCheck.test.js.map +1 -1
- package/dist/src/utils/commentJson.js +2 -2
- package/dist/src/utils/commentJson.js.map +1 -1
- package/dist/src/utils/commentJson.test.js +7 -6
- package/dist/src/utils/commentJson.test.js.map +1 -1
- package/dist/src/utils/envVarResolver.d.ts +2 -2
- package/dist/src/utils/envVarResolver.js +10 -7
- package/dist/src/utils/envVarResolver.js.map +1 -1
- package/dist/src/utils/events.d.ts +11 -2
- package/dist/src/utils/events.js +1 -0
- package/dist/src/utils/events.js.map +1 -1
- package/dist/src/utils/handleAutoUpdate.js +9 -3
- package/dist/src/utils/handleAutoUpdate.js.map +1 -1
- package/dist/src/utils/sandbox.js +16 -18
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/utils/version.js +6 -2
- package/dist/src/utils/version.js.map +1 -1
- package/dist/src/zed-integration/acp.js +2 -1
- package/dist/src/zed-integration/acp.js.map +1 -1
- package/dist/src/zed-integration/schema.d.ts +4 -4
- package/dist/src/zed-integration/zedIntegration.d.ts +2 -2
- package/dist/src/zed-integration/zedIntegration.js +12 -19
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -14
- package/dist/src/config/policy.test.js +0 -360
- package/dist/src/config/policy.test.js.map +0 -1
- package/dist/src/utils/package.d.ts +0 -12
- package/dist/src/utils/package.js +0 -24
- package/dist/src/utils/package.js.map +0 -1
- /package/dist/src/{config/policy.test.d.ts → commands/extensions/validate.test.d.ts} +0 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
/**
|
|
2
3
|
* @license
|
|
3
4
|
* Copyright 2025 Google LLC
|
|
4
5
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
6
|
*/
|
|
6
7
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
7
|
-
import {
|
|
8
|
+
import { act } from 'react';
|
|
9
|
+
import { render } from '../../test-utils/render.js';
|
|
10
|
+
import { waitFor } from '../../test-utils/async.js';
|
|
8
11
|
import { useSelectionList, } from './useSelectionList.js';
|
|
9
12
|
import { useKeypress } from './useKeypress.js';
|
|
10
13
|
vi.mock('./useKeypress.js');
|
|
@@ -31,15 +34,15 @@ describe('useSelectionList', () => {
|
|
|
31
34
|
mockOnSelect.mockClear();
|
|
32
35
|
mockOnHighlight.mockClear();
|
|
33
36
|
});
|
|
34
|
-
const pressKey = (name, sequence = name) => {
|
|
37
|
+
const pressKey = (name, sequence = name, options = {}) => {
|
|
35
38
|
act(() => {
|
|
36
39
|
if (activeKeypressHandler) {
|
|
37
40
|
const key = {
|
|
38
41
|
name,
|
|
39
42
|
sequence,
|
|
40
|
-
ctrl: false,
|
|
43
|
+
ctrl: options.ctrl ?? false,
|
|
41
44
|
meta: false,
|
|
42
|
-
shift: false,
|
|
45
|
+
shift: options.shift ?? false,
|
|
43
46
|
paste: false,
|
|
44
47
|
};
|
|
45
48
|
activeKeypressHandler(key);
|
|
@@ -49,131 +52,186 @@ describe('useSelectionList', () => {
|
|
|
49
52
|
}
|
|
50
53
|
});
|
|
51
54
|
};
|
|
55
|
+
const renderSelectionListHook = async (initialProps) => {
|
|
56
|
+
let hookResult;
|
|
57
|
+
function TestComponent(props) {
|
|
58
|
+
hookResult = useSelectionList(props);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const { rerender, unmount } = render(_jsx(TestComponent, { ...initialProps }));
|
|
62
|
+
return {
|
|
63
|
+
result: {
|
|
64
|
+
get current() {
|
|
65
|
+
return hookResult;
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
rerender: async (newProps) => {
|
|
69
|
+
rerender(_jsx(TestComponent, { ...initialProps, ...newProps }));
|
|
70
|
+
},
|
|
71
|
+
unmount: async () => {
|
|
72
|
+
unmount();
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
};
|
|
52
76
|
describe('Initialization', () => {
|
|
53
|
-
it('should initialize with the default index (0) if enabled', () => {
|
|
54
|
-
const { result } =
|
|
77
|
+
it('should initialize with the default index (0) if enabled', async () => {
|
|
78
|
+
const { result } = await renderSelectionListHook({
|
|
79
|
+
items,
|
|
80
|
+
onSelect: mockOnSelect,
|
|
81
|
+
});
|
|
55
82
|
expect(result.current.activeIndex).toBe(0);
|
|
56
83
|
});
|
|
57
|
-
it('should initialize with the provided initialIndex if enabled', () => {
|
|
58
|
-
const { result } =
|
|
84
|
+
it('should initialize with the provided initialIndex if enabled', async () => {
|
|
85
|
+
const { result } = await renderSelectionListHook({
|
|
59
86
|
items,
|
|
60
87
|
initialIndex: 2,
|
|
61
88
|
onSelect: mockOnSelect,
|
|
62
|
-
})
|
|
89
|
+
});
|
|
63
90
|
expect(result.current.activeIndex).toBe(2);
|
|
64
91
|
});
|
|
65
|
-
it('should handle an empty list gracefully', () => {
|
|
66
|
-
const { result } =
|
|
92
|
+
it('should handle an empty list gracefully', async () => {
|
|
93
|
+
const { result } = await renderSelectionListHook({
|
|
94
|
+
items: [],
|
|
95
|
+
onSelect: mockOnSelect,
|
|
96
|
+
});
|
|
67
97
|
expect(result.current.activeIndex).toBe(0);
|
|
68
98
|
});
|
|
69
|
-
it('should find the next enabled item (downwards) if initialIndex is disabled', () => {
|
|
70
|
-
const { result } =
|
|
99
|
+
it('should find the next enabled item (downwards) if initialIndex is disabled', async () => {
|
|
100
|
+
const { result } = await renderSelectionListHook({
|
|
71
101
|
items,
|
|
72
102
|
initialIndex: 1,
|
|
73
103
|
onSelect: mockOnSelect,
|
|
74
|
-
})
|
|
104
|
+
});
|
|
75
105
|
expect(result.current.activeIndex).toBe(2);
|
|
76
106
|
});
|
|
77
|
-
it('should wrap around to find the next enabled item if initialIndex is disabled', () => {
|
|
107
|
+
it('should wrap around to find the next enabled item if initialIndex is disabled', async () => {
|
|
78
108
|
const wrappingItems = [
|
|
79
109
|
{ value: 'A', key: 'A' },
|
|
80
110
|
{ value: 'B', disabled: true, key: 'B' },
|
|
81
111
|
{ value: 'C', disabled: true, key: 'C' },
|
|
82
112
|
];
|
|
83
|
-
const { result } =
|
|
113
|
+
const { result } = await renderSelectionListHook({
|
|
84
114
|
items: wrappingItems,
|
|
85
115
|
initialIndex: 2,
|
|
86
116
|
onSelect: mockOnSelect,
|
|
87
|
-
})
|
|
117
|
+
});
|
|
88
118
|
expect(result.current.activeIndex).toBe(0);
|
|
89
119
|
});
|
|
90
|
-
it('should default to 0 if initialIndex is out of bounds', () => {
|
|
91
|
-
const { result } =
|
|
120
|
+
it('should default to 0 if initialIndex is out of bounds', async () => {
|
|
121
|
+
const { result } = await renderSelectionListHook({
|
|
92
122
|
items,
|
|
93
123
|
initialIndex: 10,
|
|
94
124
|
onSelect: mockOnSelect,
|
|
95
|
-
})
|
|
125
|
+
});
|
|
96
126
|
expect(result.current.activeIndex).toBe(0);
|
|
97
|
-
const { result: resultNeg } =
|
|
127
|
+
const { result: resultNeg } = await renderSelectionListHook({
|
|
98
128
|
items,
|
|
99
129
|
initialIndex: -1,
|
|
100
130
|
onSelect: mockOnSelect,
|
|
101
|
-
})
|
|
131
|
+
});
|
|
102
132
|
expect(resultNeg.current.activeIndex).toBe(0);
|
|
103
133
|
});
|
|
104
|
-
it('should stick to the initial index if all items are disabled', () => {
|
|
134
|
+
it('should stick to the initial index if all items are disabled', async () => {
|
|
105
135
|
const allDisabled = [
|
|
106
136
|
{ value: 'A', disabled: true, key: 'A' },
|
|
107
137
|
{ value: 'B', disabled: true, key: 'B' },
|
|
108
138
|
];
|
|
109
|
-
const { result } =
|
|
139
|
+
const { result } = await renderSelectionListHook({
|
|
110
140
|
items: allDisabled,
|
|
111
141
|
initialIndex: 1,
|
|
112
142
|
onSelect: mockOnSelect,
|
|
113
|
-
})
|
|
143
|
+
});
|
|
114
144
|
expect(result.current.activeIndex).toBe(1);
|
|
115
145
|
});
|
|
116
146
|
});
|
|
117
147
|
describe('Keyboard Navigation (Up/Down/J/K)', () => {
|
|
118
|
-
it('should move down with "j" and "down" keys, skipping disabled items', () => {
|
|
119
|
-
const { result } =
|
|
148
|
+
it('should move down with "j" and "down" keys, skipping disabled items', async () => {
|
|
149
|
+
const { result } = await renderSelectionListHook({
|
|
150
|
+
items,
|
|
151
|
+
onSelect: mockOnSelect,
|
|
152
|
+
});
|
|
120
153
|
expect(result.current.activeIndex).toBe(0);
|
|
121
154
|
pressKey('j');
|
|
122
155
|
expect(result.current.activeIndex).toBe(2);
|
|
123
156
|
pressKey('down');
|
|
124
157
|
expect(result.current.activeIndex).toBe(3);
|
|
125
158
|
});
|
|
126
|
-
it('should move up with "k" and "up" keys, skipping disabled items', () => {
|
|
127
|
-
const { result } =
|
|
159
|
+
it('should move up with "k" and "up" keys, skipping disabled items', async () => {
|
|
160
|
+
const { result } = await renderSelectionListHook({
|
|
161
|
+
items,
|
|
162
|
+
initialIndex: 3,
|
|
163
|
+
onSelect: mockOnSelect,
|
|
164
|
+
});
|
|
128
165
|
expect(result.current.activeIndex).toBe(3);
|
|
129
166
|
pressKey('k');
|
|
130
167
|
expect(result.current.activeIndex).toBe(2);
|
|
131
168
|
pressKey('up');
|
|
132
169
|
expect(result.current.activeIndex).toBe(0);
|
|
133
170
|
});
|
|
134
|
-
it('should
|
|
135
|
-
const { result } =
|
|
171
|
+
it('should ignore navigation keys when shift is pressed', async () => {
|
|
172
|
+
const { result } = await renderSelectionListHook({
|
|
173
|
+
items,
|
|
174
|
+
initialIndex: 2, // Start at middle item 'C'
|
|
175
|
+
onSelect: mockOnSelect,
|
|
176
|
+
});
|
|
177
|
+
expect(result.current.activeIndex).toBe(2);
|
|
178
|
+
// Shift+Down / Shift+J should not move down
|
|
179
|
+
pressKey('down', undefined, { shift: true });
|
|
180
|
+
expect(result.current.activeIndex).toBe(2);
|
|
181
|
+
pressKey('j', undefined, { shift: true });
|
|
182
|
+
expect(result.current.activeIndex).toBe(2);
|
|
183
|
+
// Shift+Up / Shift+K should not move up
|
|
184
|
+
pressKey('up', undefined, { shift: true });
|
|
185
|
+
expect(result.current.activeIndex).toBe(2);
|
|
186
|
+
pressKey('k', undefined, { shift: true });
|
|
187
|
+
expect(result.current.activeIndex).toBe(2);
|
|
188
|
+
// Verify normal navigation still works
|
|
189
|
+
pressKey('down');
|
|
190
|
+
expect(result.current.activeIndex).toBe(3);
|
|
191
|
+
});
|
|
192
|
+
it('should wrap navigation correctly', async () => {
|
|
193
|
+
const { result } = await renderSelectionListHook({
|
|
136
194
|
items,
|
|
137
195
|
initialIndex: items.length - 1,
|
|
138
196
|
onSelect: mockOnSelect,
|
|
139
|
-
})
|
|
197
|
+
});
|
|
140
198
|
expect(result.current.activeIndex).toBe(3);
|
|
141
199
|
pressKey('down');
|
|
142
200
|
expect(result.current.activeIndex).toBe(0);
|
|
143
201
|
pressKey('up');
|
|
144
202
|
expect(result.current.activeIndex).toBe(3);
|
|
145
203
|
});
|
|
146
|
-
it('should call onHighlight when index changes', () => {
|
|
147
|
-
|
|
204
|
+
it('should call onHighlight when index changes', async () => {
|
|
205
|
+
await renderSelectionListHook({
|
|
148
206
|
items,
|
|
149
207
|
onSelect: mockOnSelect,
|
|
150
208
|
onHighlight: mockOnHighlight,
|
|
151
|
-
})
|
|
209
|
+
});
|
|
152
210
|
pressKey('down');
|
|
153
211
|
expect(mockOnHighlight).toHaveBeenCalledTimes(1);
|
|
154
212
|
expect(mockOnHighlight).toHaveBeenCalledWith('C');
|
|
155
213
|
});
|
|
156
|
-
it('should not move or call onHighlight if navigation results in the same index (e.g., single item)', () => {
|
|
214
|
+
it('should not move or call onHighlight if navigation results in the same index (e.g., single item)', async () => {
|
|
157
215
|
const singleItem = [{ value: 'A', key: 'A' }];
|
|
158
|
-
const { result } =
|
|
216
|
+
const { result } = await renderSelectionListHook({
|
|
159
217
|
items: singleItem,
|
|
160
218
|
onSelect: mockOnSelect,
|
|
161
219
|
onHighlight: mockOnHighlight,
|
|
162
|
-
})
|
|
220
|
+
});
|
|
163
221
|
pressKey('down');
|
|
164
222
|
expect(result.current.activeIndex).toBe(0);
|
|
165
223
|
expect(mockOnHighlight).not.toHaveBeenCalled();
|
|
166
224
|
});
|
|
167
|
-
it('should not move or call onHighlight if all items are disabled', () => {
|
|
225
|
+
it('should not move or call onHighlight if all items are disabled', async () => {
|
|
168
226
|
const allDisabled = [
|
|
169
227
|
{ value: 'A', disabled: true, key: 'A' },
|
|
170
228
|
{ value: 'B', disabled: true, key: 'B' },
|
|
171
229
|
];
|
|
172
|
-
const { result } =
|
|
230
|
+
const { result } = await renderSelectionListHook({
|
|
173
231
|
items: allDisabled,
|
|
174
232
|
onSelect: mockOnSelect,
|
|
175
233
|
onHighlight: mockOnHighlight,
|
|
176
|
-
})
|
|
234
|
+
});
|
|
177
235
|
const initialIndex = result.current.activeIndex;
|
|
178
236
|
pressKey('down');
|
|
179
237
|
expect(result.current.activeIndex).toBe(initialIndex);
|
|
@@ -181,33 +239,33 @@ describe('useSelectionList', () => {
|
|
|
181
239
|
});
|
|
182
240
|
});
|
|
183
241
|
describe('Selection (Enter)', () => {
|
|
184
|
-
it('should call onSelect when "return" is pressed on enabled item', () => {
|
|
185
|
-
|
|
242
|
+
it('should call onSelect when "return" is pressed on enabled item', async () => {
|
|
243
|
+
await renderSelectionListHook({
|
|
186
244
|
items,
|
|
187
245
|
initialIndex: 2,
|
|
188
246
|
onSelect: mockOnSelect,
|
|
189
|
-
})
|
|
247
|
+
});
|
|
190
248
|
pressKey('return');
|
|
191
249
|
expect(mockOnSelect).toHaveBeenCalledTimes(1);
|
|
192
250
|
expect(mockOnSelect).toHaveBeenCalledWith('C');
|
|
193
251
|
});
|
|
194
|
-
it('should not call onSelect if the active item is disabled', () => {
|
|
195
|
-
const { result } =
|
|
252
|
+
it('should not call onSelect if the active item is disabled', async () => {
|
|
253
|
+
const { result } = await renderSelectionListHook({
|
|
196
254
|
items,
|
|
197
255
|
onSelect: mockOnSelect,
|
|
198
|
-
})
|
|
256
|
+
});
|
|
199
257
|
act(() => result.current.setActiveIndex(1));
|
|
200
258
|
pressKey('return');
|
|
201
259
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
202
260
|
});
|
|
203
261
|
});
|
|
204
262
|
describe('Keyboard Navigation Robustness (Rapid Input)', () => {
|
|
205
|
-
it('should handle rapid navigation and selection robustly (avoiding stale state)', () => {
|
|
206
|
-
const { result } =
|
|
263
|
+
it('should handle rapid navigation and selection robustly (avoiding stale state)', async () => {
|
|
264
|
+
const { result } = await renderSelectionListHook({
|
|
207
265
|
items, // A, B(disabled), C, D. Initial index 0 (A).
|
|
208
266
|
onSelect: mockOnSelect,
|
|
209
267
|
onHighlight: mockOnHighlight,
|
|
210
|
-
})
|
|
268
|
+
});
|
|
211
269
|
// Simulate rapid inputs with separate act blocks to allow effects to run
|
|
212
270
|
if (!activeKeypressHandler)
|
|
213
271
|
throw new Error('Handler not active');
|
|
@@ -243,12 +301,12 @@ describe('useSelectionList', () => {
|
|
|
243
301
|
expect(mockOnSelect).toHaveBeenCalledWith('D');
|
|
244
302
|
expect(mockOnSelect).not.toHaveBeenCalledWith('A');
|
|
245
303
|
});
|
|
246
|
-
it('should handle ultra-rapid input (multiple presses in single act) without stale state', () => {
|
|
247
|
-
const { result } =
|
|
304
|
+
it('should handle ultra-rapid input (multiple presses in single act) without stale state', async () => {
|
|
305
|
+
const { result } = await renderSelectionListHook({
|
|
248
306
|
items, // A, B(disabled), C, D. Initial index 0 (A).
|
|
249
307
|
onSelect: mockOnSelect,
|
|
250
308
|
onHighlight: mockOnHighlight,
|
|
251
|
-
})
|
|
309
|
+
});
|
|
252
310
|
// Simulate ultra-rapid inputs where all keypresses happen faster than React can re-render
|
|
253
311
|
act(() => {
|
|
254
312
|
if (!activeKeypressHandler)
|
|
@@ -277,34 +335,45 @@ describe('useSelectionList', () => {
|
|
|
277
335
|
});
|
|
278
336
|
});
|
|
279
337
|
describe('Focus Management (isFocused)', () => {
|
|
280
|
-
it('should activate the keypress handler when focused (default) and items exist', () => {
|
|
281
|
-
const { result } =
|
|
338
|
+
it('should activate the keypress handler when focused (default) and items exist', async () => {
|
|
339
|
+
const { result } = await renderSelectionListHook({
|
|
340
|
+
items,
|
|
341
|
+
onSelect: mockOnSelect,
|
|
342
|
+
});
|
|
282
343
|
expect(activeKeypressHandler).not.toBeNull();
|
|
283
344
|
pressKey('down');
|
|
284
345
|
expect(result.current.activeIndex).toBe(2);
|
|
285
346
|
});
|
|
286
|
-
it('should not activate the keypress handler when isFocused is false', () => {
|
|
287
|
-
|
|
347
|
+
it('should not activate the keypress handler when isFocused is false', async () => {
|
|
348
|
+
await renderSelectionListHook({
|
|
349
|
+
items,
|
|
350
|
+
onSelect: mockOnSelect,
|
|
351
|
+
isFocused: false,
|
|
352
|
+
});
|
|
288
353
|
expect(activeKeypressHandler).toBeNull();
|
|
289
354
|
expect(() => pressKey('down')).toThrow(/keypress handler is not active/);
|
|
290
355
|
});
|
|
291
|
-
it('should not activate the keypress handler when items list is empty', () => {
|
|
292
|
-
|
|
356
|
+
it('should not activate the keypress handler when items list is empty', async () => {
|
|
357
|
+
await renderSelectionListHook({
|
|
293
358
|
items: [],
|
|
294
359
|
onSelect: mockOnSelect,
|
|
295
360
|
isFocused: true,
|
|
296
|
-
})
|
|
361
|
+
});
|
|
297
362
|
expect(activeKeypressHandler).toBeNull();
|
|
298
363
|
expect(() => pressKey('down')).toThrow(/keypress handler is not active/);
|
|
299
364
|
});
|
|
300
|
-
it('should activate/deactivate when isFocused prop changes', () => {
|
|
301
|
-
const { result, rerender } =
|
|
365
|
+
it('should activate/deactivate when isFocused prop changes', async () => {
|
|
366
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
367
|
+
items,
|
|
368
|
+
onSelect: mockOnSelect,
|
|
369
|
+
isFocused: false,
|
|
370
|
+
});
|
|
302
371
|
expect(activeKeypressHandler).toBeNull();
|
|
303
|
-
rerender({ isFocused: true });
|
|
372
|
+
await rerender({ isFocused: true });
|
|
304
373
|
expect(activeKeypressHandler).not.toBeNull();
|
|
305
374
|
pressKey('down');
|
|
306
375
|
expect(result.current.activeIndex).toBe(2);
|
|
307
|
-
rerender({ isFocused: false });
|
|
376
|
+
await rerender({ isFocused: false });
|
|
308
377
|
expect(activeKeypressHandler).toBeNull();
|
|
309
378
|
expect(() => pressKey('down')).toThrow(/keypress handler is not active/);
|
|
310
379
|
});
|
|
@@ -319,19 +388,22 @@ describe('useSelectionList', () => {
|
|
|
319
388
|
const shortList = items;
|
|
320
389
|
const longList = Array.from({ length: 15 }, (_, i) => ({ value: `Item ${i + 1}`, key: `Item ${i + 1}` }));
|
|
321
390
|
const pressNumber = (num) => pressKey(num, num);
|
|
322
|
-
it('should not respond to numbers if showNumbers is false (default)', () => {
|
|
323
|
-
const { result } =
|
|
391
|
+
it('should not respond to numbers if showNumbers is false (default)', async () => {
|
|
392
|
+
const { result } = await renderSelectionListHook({
|
|
393
|
+
items: shortList,
|
|
394
|
+
onSelect: mockOnSelect,
|
|
395
|
+
});
|
|
324
396
|
pressNumber('1');
|
|
325
397
|
expect(result.current.activeIndex).toBe(0);
|
|
326
398
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
327
399
|
});
|
|
328
|
-
it('should select item immediately if the number cannot be extended (unambiguous)', () => {
|
|
329
|
-
const { result } =
|
|
400
|
+
it('should select item immediately if the number cannot be extended (unambiguous)', async () => {
|
|
401
|
+
const { result } = await renderSelectionListHook({
|
|
330
402
|
items: shortList,
|
|
331
403
|
onSelect: mockOnSelect,
|
|
332
404
|
onHighlight: mockOnHighlight,
|
|
333
405
|
showNumbers: true,
|
|
334
|
-
})
|
|
406
|
+
});
|
|
335
407
|
pressNumber('3');
|
|
336
408
|
expect(result.current.activeIndex).toBe(2);
|
|
337
409
|
expect(mockOnHighlight).toHaveBeenCalledWith('C');
|
|
@@ -339,14 +411,14 @@ describe('useSelectionList', () => {
|
|
|
339
411
|
expect(mockOnSelect).toHaveBeenCalledWith('C');
|
|
340
412
|
expect(vi.getTimerCount()).toBe(0);
|
|
341
413
|
});
|
|
342
|
-
it('should highlight and wait for timeout if the number can be extended (ambiguous)', () => {
|
|
343
|
-
const { result } =
|
|
414
|
+
it('should highlight and wait for timeout if the number can be extended (ambiguous)', async () => {
|
|
415
|
+
const { result } = await renderSelectionListHook({
|
|
344
416
|
items: longList,
|
|
345
417
|
initialIndex: 1, // Start at index 1 so pressing "1" (index 0) causes a change
|
|
346
418
|
onSelect: mockOnSelect,
|
|
347
419
|
onHighlight: mockOnHighlight,
|
|
348
420
|
showNumbers: true,
|
|
349
|
-
})
|
|
421
|
+
});
|
|
350
422
|
pressNumber('1');
|
|
351
423
|
expect(result.current.activeIndex).toBe(0);
|
|
352
424
|
expect(mockOnHighlight).toHaveBeenCalledWith('Item 1');
|
|
@@ -358,12 +430,12 @@ describe('useSelectionList', () => {
|
|
|
358
430
|
expect(mockOnSelect).toHaveBeenCalledTimes(1);
|
|
359
431
|
expect(mockOnSelect).toHaveBeenCalledWith('Item 1');
|
|
360
432
|
});
|
|
361
|
-
it('should handle multi-digit input correctly', () => {
|
|
362
|
-
const { result } =
|
|
433
|
+
it('should handle multi-digit input correctly', async () => {
|
|
434
|
+
const { result } = await renderSelectionListHook({
|
|
363
435
|
items: longList,
|
|
364
436
|
onSelect: mockOnSelect,
|
|
365
437
|
showNumbers: true,
|
|
366
|
-
})
|
|
438
|
+
});
|
|
367
439
|
pressNumber('1');
|
|
368
440
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
369
441
|
pressNumber('2');
|
|
@@ -371,12 +443,12 @@ describe('useSelectionList', () => {
|
|
|
371
443
|
expect(mockOnSelect).toHaveBeenCalledTimes(1);
|
|
372
444
|
expect(mockOnSelect).toHaveBeenCalledWith('Item 12');
|
|
373
445
|
});
|
|
374
|
-
it('should reset buffer if input becomes invalid (out of bounds)', () => {
|
|
375
|
-
const { result } =
|
|
446
|
+
it('should reset buffer if input becomes invalid (out of bounds)', async () => {
|
|
447
|
+
const { result } = await renderSelectionListHook({
|
|
376
448
|
items: shortList,
|
|
377
449
|
onSelect: mockOnSelect,
|
|
378
450
|
showNumbers: true,
|
|
379
|
-
})
|
|
451
|
+
});
|
|
380
452
|
pressNumber('5');
|
|
381
453
|
expect(result.current.activeIndex).toBe(0);
|
|
382
454
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
@@ -384,12 +456,12 @@ describe('useSelectionList', () => {
|
|
|
384
456
|
expect(result.current.activeIndex).toBe(2);
|
|
385
457
|
expect(mockOnSelect).toHaveBeenCalledWith('C');
|
|
386
458
|
});
|
|
387
|
-
it('should allow "0" as subsequent digit, but ignore as first digit', () => {
|
|
388
|
-
const { result } =
|
|
459
|
+
it('should allow "0" as subsequent digit, but ignore as first digit', async () => {
|
|
460
|
+
const { result } = await renderSelectionListHook({
|
|
389
461
|
items: longList,
|
|
390
462
|
onSelect: mockOnSelect,
|
|
391
463
|
showNumbers: true,
|
|
392
|
-
})
|
|
464
|
+
});
|
|
393
465
|
pressNumber('0');
|
|
394
466
|
expect(result.current.activeIndex).toBe(0);
|
|
395
467
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
@@ -401,12 +473,12 @@ describe('useSelectionList', () => {
|
|
|
401
473
|
expect(result.current.activeIndex).toBe(9);
|
|
402
474
|
expect(mockOnSelect).toHaveBeenCalledWith('Item 10');
|
|
403
475
|
});
|
|
404
|
-
it('should clear the initial "0" input after timeout', () => {
|
|
405
|
-
|
|
476
|
+
it('should clear the initial "0" input after timeout', async () => {
|
|
477
|
+
await renderSelectionListHook({
|
|
406
478
|
items: longList,
|
|
407
479
|
onSelect: mockOnSelect,
|
|
408
480
|
showNumbers: true,
|
|
409
|
-
})
|
|
481
|
+
});
|
|
410
482
|
pressNumber('0');
|
|
411
483
|
act(() => vi.advanceTimersByTime(1000)); // Timeout the '0' input
|
|
412
484
|
pressNumber('1');
|
|
@@ -414,30 +486,30 @@ describe('useSelectionList', () => {
|
|
|
414
486
|
act(() => vi.advanceTimersByTime(1000)); // Timeout '1'
|
|
415
487
|
expect(mockOnSelect).toHaveBeenCalledWith('Item 1');
|
|
416
488
|
});
|
|
417
|
-
it('should highlight but not select a disabled item (immediate selection case)', () => {
|
|
418
|
-
const { result } =
|
|
489
|
+
it('should highlight but not select a disabled item (immediate selection case)', async () => {
|
|
490
|
+
const { result } = await renderSelectionListHook({
|
|
419
491
|
items: shortList, // B (index 1, number 2) is disabled
|
|
420
492
|
onSelect: mockOnSelect,
|
|
421
493
|
onHighlight: mockOnHighlight,
|
|
422
494
|
showNumbers: true,
|
|
423
|
-
})
|
|
495
|
+
});
|
|
424
496
|
pressNumber('2');
|
|
425
497
|
expect(result.current.activeIndex).toBe(1);
|
|
426
498
|
expect(mockOnHighlight).toHaveBeenCalledWith('B');
|
|
427
499
|
// Should not select immediately, even though 20 > 4
|
|
428
500
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
429
501
|
});
|
|
430
|
-
it('should highlight but not select a disabled item (timeout case)', () => {
|
|
502
|
+
it('should highlight but not select a disabled item (timeout case)', async () => {
|
|
431
503
|
// Create a list where the ambiguous prefix points to a disabled item
|
|
432
504
|
const disabledAmbiguousList = [
|
|
433
505
|
{ value: 'Item 1 Disabled', disabled: true, key: 'Item 1 Disabled' },
|
|
434
506
|
...longList.slice(1),
|
|
435
507
|
];
|
|
436
|
-
const { result } =
|
|
508
|
+
const { result } = await renderSelectionListHook({
|
|
437
509
|
items: disabledAmbiguousList,
|
|
438
510
|
onSelect: mockOnSelect,
|
|
439
511
|
showNumbers: true,
|
|
440
|
-
})
|
|
512
|
+
});
|
|
441
513
|
pressNumber('1');
|
|
442
514
|
expect(result.current.activeIndex).toBe(0);
|
|
443
515
|
expect(vi.getTimerCount()).toBe(1);
|
|
@@ -447,12 +519,12 @@ describe('useSelectionList', () => {
|
|
|
447
519
|
// Should not select after timeout
|
|
448
520
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
449
521
|
});
|
|
450
|
-
it('should clear the number buffer if a non-numeric key (e.g., navigation) is pressed', () => {
|
|
451
|
-
const { result } =
|
|
522
|
+
it('should clear the number buffer if a non-numeric key (e.g., navigation) is pressed', async () => {
|
|
523
|
+
const { result } = await renderSelectionListHook({
|
|
452
524
|
items: longList,
|
|
453
525
|
onSelect: mockOnSelect,
|
|
454
526
|
showNumbers: true,
|
|
455
|
-
})
|
|
527
|
+
});
|
|
456
528
|
pressNumber('1');
|
|
457
529
|
expect(vi.getTimerCount()).toBe(1);
|
|
458
530
|
pressKey('down');
|
|
@@ -462,12 +534,12 @@ describe('useSelectionList', () => {
|
|
|
462
534
|
// Should select '3', not '13'
|
|
463
535
|
expect(result.current.activeIndex).toBe(2);
|
|
464
536
|
});
|
|
465
|
-
it('should clear the number buffer if "return" is pressed', () => {
|
|
466
|
-
|
|
537
|
+
it('should clear the number buffer if "return" is pressed', async () => {
|
|
538
|
+
await renderSelectionListHook({
|
|
467
539
|
items: longList,
|
|
468
540
|
onSelect: mockOnSelect,
|
|
469
541
|
showNumbers: true,
|
|
470
|
-
})
|
|
542
|
+
});
|
|
471
543
|
pressNumber('1');
|
|
472
544
|
pressKey('return');
|
|
473
545
|
expect(mockOnSelect).toHaveBeenCalledTimes(1);
|
|
@@ -479,95 +551,107 @@ describe('useSelectionList', () => {
|
|
|
479
551
|
});
|
|
480
552
|
});
|
|
481
553
|
describe('Reactivity (Dynamic Updates)', () => {
|
|
482
|
-
it('should update activeIndex when initialIndex prop changes', () => {
|
|
483
|
-
const { result, rerender } =
|
|
554
|
+
it('should update activeIndex when initialIndex prop changes', async () => {
|
|
555
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
484
556
|
items,
|
|
485
557
|
onSelect: mockOnSelect,
|
|
486
|
-
initialIndex,
|
|
487
|
-
})
|
|
488
|
-
rerender({ initialIndex: 2 });
|
|
489
|
-
|
|
558
|
+
initialIndex: 0,
|
|
559
|
+
});
|
|
560
|
+
await rerender({ initialIndex: 2 });
|
|
561
|
+
await waitFor(() => {
|
|
562
|
+
expect(result.current.activeIndex).toBe(2);
|
|
563
|
+
});
|
|
490
564
|
});
|
|
491
|
-
it('should respect a new initialIndex even after user interaction', () => {
|
|
492
|
-
const { result, rerender } =
|
|
565
|
+
it('should respect a new initialIndex even after user interaction', async () => {
|
|
566
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
493
567
|
items,
|
|
494
568
|
onSelect: mockOnSelect,
|
|
495
|
-
initialIndex,
|
|
496
|
-
})
|
|
569
|
+
initialIndex: 0,
|
|
570
|
+
});
|
|
497
571
|
// User navigates, changing the active index
|
|
498
572
|
pressKey('down');
|
|
499
573
|
expect(result.current.activeIndex).toBe(2);
|
|
500
574
|
// The component re-renders with a new initial index
|
|
501
|
-
rerender({ initialIndex: 3 });
|
|
575
|
+
await rerender({ initialIndex: 3 });
|
|
502
576
|
// The hook should now respect the new initial index
|
|
503
|
-
|
|
577
|
+
await waitFor(() => {
|
|
578
|
+
expect(result.current.activeIndex).toBe(3);
|
|
579
|
+
});
|
|
504
580
|
});
|
|
505
|
-
it('should validate index when initialIndex prop changes to a disabled item', () => {
|
|
506
|
-
const { result, rerender } =
|
|
581
|
+
it('should validate index when initialIndex prop changes to a disabled item', async () => {
|
|
582
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
507
583
|
items,
|
|
508
584
|
onSelect: mockOnSelect,
|
|
509
|
-
initialIndex,
|
|
510
|
-
})
|
|
511
|
-
rerender({ initialIndex: 1 });
|
|
512
|
-
|
|
585
|
+
initialIndex: 0,
|
|
586
|
+
});
|
|
587
|
+
await rerender({ initialIndex: 1 });
|
|
588
|
+
await waitFor(() => {
|
|
589
|
+
expect(result.current.activeIndex).toBe(2);
|
|
590
|
+
});
|
|
513
591
|
});
|
|
514
|
-
it('should adjust activeIndex if items change and the initialIndex is now out of bounds', () => {
|
|
515
|
-
const { result, rerender } =
|
|
592
|
+
it('should adjust activeIndex if items change and the initialIndex is now out of bounds', async () => {
|
|
593
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
516
594
|
onSelect: mockOnSelect,
|
|
517
595
|
initialIndex: 3,
|
|
518
|
-
items
|
|
519
|
-
})
|
|
596
|
+
items,
|
|
597
|
+
});
|
|
520
598
|
expect(result.current.activeIndex).toBe(3);
|
|
521
599
|
const shorterItems = [
|
|
522
600
|
{ value: 'X', key: 'X' },
|
|
523
601
|
{ value: 'Y', key: 'Y' },
|
|
524
602
|
];
|
|
525
|
-
rerender({ items: shorterItems }); // Length 2
|
|
603
|
+
await rerender({ items: shorterItems }); // Length 2
|
|
526
604
|
// The useEffect syncs based on the initialIndex (3) which is now out of bounds. It defaults to 0.
|
|
527
|
-
|
|
605
|
+
await waitFor(() => {
|
|
606
|
+
expect(result.current.activeIndex).toBe(0);
|
|
607
|
+
});
|
|
528
608
|
});
|
|
529
|
-
it('should adjust activeIndex if items change and the initialIndex becomes disabled', () => {
|
|
609
|
+
it('should adjust activeIndex if items change and the initialIndex becomes disabled', async () => {
|
|
530
610
|
const initialItems = [
|
|
531
611
|
{ value: 'A', key: 'A' },
|
|
532
612
|
{ value: 'B', key: 'B' },
|
|
533
613
|
{ value: 'C', key: 'C' },
|
|
534
614
|
];
|
|
535
|
-
const { result, rerender } =
|
|
615
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
536
616
|
onSelect: mockOnSelect,
|
|
537
617
|
initialIndex: 1,
|
|
538
|
-
items:
|
|
539
|
-
})
|
|
618
|
+
items: initialItems,
|
|
619
|
+
});
|
|
540
620
|
expect(result.current.activeIndex).toBe(1);
|
|
541
621
|
const newItems = [
|
|
542
622
|
{ value: 'A', key: 'A' },
|
|
543
623
|
{ value: 'B', disabled: true, key: 'B' },
|
|
544
624
|
{ value: 'C', key: 'C' },
|
|
545
625
|
];
|
|
546
|
-
rerender({ items: newItems });
|
|
547
|
-
|
|
626
|
+
await rerender({ items: newItems });
|
|
627
|
+
await waitFor(() => {
|
|
628
|
+
expect(result.current.activeIndex).toBe(2);
|
|
629
|
+
});
|
|
548
630
|
});
|
|
549
|
-
it('should reset to 0 if items change to an empty list', () => {
|
|
550
|
-
const { result, rerender } =
|
|
631
|
+
it('should reset to 0 if items change to an empty list', async () => {
|
|
632
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
551
633
|
onSelect: mockOnSelect,
|
|
552
634
|
initialIndex: 2,
|
|
553
|
-
items
|
|
554
|
-
})
|
|
555
|
-
rerender({ items: [] });
|
|
556
|
-
|
|
635
|
+
items,
|
|
636
|
+
});
|
|
637
|
+
await rerender({ items: [] });
|
|
638
|
+
await waitFor(() => {
|
|
639
|
+
expect(result.current.activeIndex).toBe(0);
|
|
640
|
+
});
|
|
557
641
|
});
|
|
558
|
-
it('should not reset activeIndex when items are deeply equal', () => {
|
|
642
|
+
it('should not reset activeIndex when items are deeply equal', async () => {
|
|
559
643
|
const initialItems = [
|
|
560
644
|
{ value: 'A', key: 'A' },
|
|
561
645
|
{ value: 'B', disabled: true, key: 'B' },
|
|
562
646
|
{ value: 'C', key: 'C' },
|
|
563
647
|
{ value: 'D', key: 'D' },
|
|
564
648
|
];
|
|
565
|
-
const { result, rerender } =
|
|
649
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
566
650
|
onSelect: mockOnSelect,
|
|
567
651
|
onHighlight: mockOnHighlight,
|
|
568
652
|
initialIndex: 2,
|
|
569
|
-
items:
|
|
570
|
-
})
|
|
653
|
+
items: initialItems,
|
|
654
|
+
});
|
|
571
655
|
expect(result.current.activeIndex).toBe(2);
|
|
572
656
|
act(() => {
|
|
573
657
|
result.current.setActiveIndex(3);
|
|
@@ -581,25 +665,27 @@ describe('useSelectionList', () => {
|
|
|
581
665
|
{ value: 'C', key: 'C' },
|
|
582
666
|
{ value: 'D', key: 'D' },
|
|
583
667
|
];
|
|
584
|
-
rerender({ items: newItems });
|
|
668
|
+
await rerender({ items: newItems });
|
|
585
669
|
// Active index should remain the same since items are deeply equal
|
|
586
|
-
|
|
670
|
+
await waitFor(() => {
|
|
671
|
+
expect(result.current.activeIndex).toBe(3);
|
|
672
|
+
});
|
|
587
673
|
// onHighlight should NOT be called since the index didn't change
|
|
588
674
|
expect(mockOnHighlight).not.toHaveBeenCalled();
|
|
589
675
|
});
|
|
590
|
-
it('should update activeIndex when items change structurally', () => {
|
|
676
|
+
it('should update activeIndex when items change structurally', async () => {
|
|
591
677
|
const initialItems = [
|
|
592
678
|
{ value: 'A', key: 'A' },
|
|
593
679
|
{ value: 'B', disabled: true, key: 'B' },
|
|
594
680
|
{ value: 'C', key: 'C' },
|
|
595
681
|
{ value: 'D', key: 'D' },
|
|
596
682
|
];
|
|
597
|
-
const { result, rerender } =
|
|
683
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
598
684
|
onSelect: mockOnSelect,
|
|
599
685
|
onHighlight: mockOnHighlight,
|
|
600
686
|
initialIndex: 3,
|
|
601
|
-
items:
|
|
602
|
-
})
|
|
687
|
+
items: initialItems,
|
|
688
|
+
});
|
|
603
689
|
expect(result.current.activeIndex).toBe(3);
|
|
604
690
|
mockOnHighlight.mockClear();
|
|
605
691
|
// Change item values (not deeply equal)
|
|
@@ -608,21 +694,23 @@ describe('useSelectionList', () => {
|
|
|
608
694
|
{ value: 'Y', key: 'Y' },
|
|
609
695
|
{ value: 'Z', key: 'Z' },
|
|
610
696
|
];
|
|
611
|
-
rerender({ items: newItems });
|
|
697
|
+
await rerender({ items: newItems });
|
|
612
698
|
// Active index should update based on initialIndex and new items
|
|
613
|
-
|
|
699
|
+
await waitFor(() => {
|
|
700
|
+
expect(result.current.activeIndex).toBe(0);
|
|
701
|
+
});
|
|
614
702
|
});
|
|
615
|
-
it('should handle partial changes in items array', () => {
|
|
703
|
+
it('should handle partial changes in items array', async () => {
|
|
616
704
|
const initialItems = [
|
|
617
705
|
{ value: 'A', key: 'A' },
|
|
618
706
|
{ value: 'B', key: 'B' },
|
|
619
707
|
{ value: 'C', key: 'C' },
|
|
620
708
|
];
|
|
621
|
-
const { result, rerender } =
|
|
709
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
622
710
|
onSelect: mockOnSelect,
|
|
623
711
|
initialIndex: 1,
|
|
624
|
-
items:
|
|
625
|
-
})
|
|
712
|
+
items: initialItems,
|
|
713
|
+
});
|
|
626
714
|
expect(result.current.activeIndex).toBe(1);
|
|
627
715
|
// Change only one item's disabled status
|
|
628
716
|
const newItems = [
|
|
@@ -630,20 +718,22 @@ describe('useSelectionList', () => {
|
|
|
630
718
|
{ value: 'B', disabled: true, key: 'B' },
|
|
631
719
|
{ value: 'C', key: 'C' },
|
|
632
720
|
];
|
|
633
|
-
rerender({ items: newItems });
|
|
721
|
+
await rerender({ items: newItems });
|
|
634
722
|
// Should find next valid index since current became disabled
|
|
635
|
-
|
|
723
|
+
await waitFor(() => {
|
|
724
|
+
expect(result.current.activeIndex).toBe(2);
|
|
725
|
+
});
|
|
636
726
|
});
|
|
637
|
-
it('should update selection when a new item is added to the start of the list', () => {
|
|
727
|
+
it('should update selection when a new item is added to the start of the list', async () => {
|
|
638
728
|
const initialItems = [
|
|
639
729
|
{ value: 'A', key: 'A' },
|
|
640
730
|
{ value: 'B', key: 'B' },
|
|
641
731
|
{ value: 'C', key: 'C' },
|
|
642
732
|
];
|
|
643
|
-
const { result, rerender } =
|
|
733
|
+
const { result, rerender } = await renderSelectionListHook({
|
|
644
734
|
onSelect: mockOnSelect,
|
|
645
|
-
items:
|
|
646
|
-
})
|
|
735
|
+
items: initialItems,
|
|
736
|
+
});
|
|
647
737
|
pressKey('down');
|
|
648
738
|
expect(result.current.activeIndex).toBe(1);
|
|
649
739
|
const newItems = [
|
|
@@ -652,23 +742,35 @@ describe('useSelectionList', () => {
|
|
|
652
742
|
{ value: 'B', key: 'B' },
|
|
653
743
|
{ value: 'C', key: 'C' },
|
|
654
744
|
];
|
|
655
|
-
rerender({ items: newItems });
|
|
656
|
-
|
|
745
|
+
await rerender({ items: newItems });
|
|
746
|
+
await waitFor(() => {
|
|
747
|
+
expect(result.current.activeIndex).toBe(2);
|
|
748
|
+
});
|
|
657
749
|
});
|
|
658
|
-
it('should not re-initialize when items have identical keys but are different objects', () => {
|
|
750
|
+
it('should not re-initialize when items have identical keys but are different objects', async () => {
|
|
659
751
|
const initialItems = [
|
|
660
752
|
{ value: 'A', key: 'A' },
|
|
661
753
|
{ value: 'B', key: 'B' },
|
|
662
754
|
];
|
|
663
755
|
let renderCount = 0;
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
756
|
+
const renderHookWithCount = async (initialProps) => {
|
|
757
|
+
function TestComponent(props) {
|
|
758
|
+
renderCount++;
|
|
759
|
+
useSelectionList({
|
|
760
|
+
onSelect: mockOnSelect,
|
|
761
|
+
onHighlight: mockOnHighlight,
|
|
762
|
+
items: props.items,
|
|
763
|
+
});
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
const { rerender } = render(_jsx(TestComponent, { ...initialProps }));
|
|
767
|
+
return {
|
|
768
|
+
rerender: async (newProps) => {
|
|
769
|
+
rerender(_jsx(TestComponent, { ...initialProps, ...newProps }));
|
|
770
|
+
},
|
|
771
|
+
};
|
|
772
|
+
};
|
|
773
|
+
const { rerender } = await renderHookWithCount({ items: initialItems });
|
|
672
774
|
// Initial render
|
|
673
775
|
expect(renderCount).toBe(1);
|
|
674
776
|
// Create new items with the same keys but different object references
|
|
@@ -676,23 +778,10 @@ describe('useSelectionList', () => {
|
|
|
676
778
|
{ value: 'A', key: 'A' },
|
|
677
779
|
{ value: 'B', key: 'B' },
|
|
678
780
|
];
|
|
679
|
-
rerender({ items: newItems });
|
|
781
|
+
await rerender({ items: newItems });
|
|
680
782
|
expect(renderCount).toBe(2);
|
|
681
783
|
});
|
|
682
784
|
});
|
|
683
|
-
describe('Manual Control', () => {
|
|
684
|
-
it('should allow manual setting of active index via setActiveIndex', () => {
|
|
685
|
-
const { result } = renderHook(() => useSelectionList({ items, onSelect: mockOnSelect }));
|
|
686
|
-
act(() => {
|
|
687
|
-
result.current.setActiveIndex(3);
|
|
688
|
-
});
|
|
689
|
-
expect(result.current.activeIndex).toBe(3);
|
|
690
|
-
act(() => {
|
|
691
|
-
result.current.setActiveIndex(1);
|
|
692
|
-
});
|
|
693
|
-
expect(result.current.activeIndex).toBe(1);
|
|
694
|
-
});
|
|
695
|
-
});
|
|
696
785
|
describe('Cleanup', () => {
|
|
697
786
|
beforeEach(() => {
|
|
698
787
|
vi.useFakeTimers();
|
|
@@ -700,20 +789,20 @@ describe('useSelectionList', () => {
|
|
|
700
789
|
afterEach(() => {
|
|
701
790
|
vi.useRealTimers();
|
|
702
791
|
});
|
|
703
|
-
it('should clear timeout on unmount when timer is active', () => {
|
|
792
|
+
it('should clear timeout on unmount when timer is active', async () => {
|
|
704
793
|
const longList = Array.from({ length: 15 }, (_, i) => ({ value: `Item ${i + 1}`, key: `Item ${i + 1}` }));
|
|
705
|
-
const { unmount } =
|
|
794
|
+
const { unmount } = await renderSelectionListHook({
|
|
706
795
|
items: longList,
|
|
707
796
|
onSelect: mockOnSelect,
|
|
708
797
|
showNumbers: true,
|
|
709
|
-
})
|
|
798
|
+
});
|
|
710
799
|
pressKey('1', '1');
|
|
711
800
|
expect(vi.getTimerCount()).toBe(1);
|
|
712
801
|
act(() => {
|
|
713
802
|
vi.advanceTimersByTime(500);
|
|
714
803
|
});
|
|
715
804
|
expect(mockOnSelect).not.toHaveBeenCalled();
|
|
716
|
-
unmount();
|
|
805
|
+
await unmount();
|
|
717
806
|
expect(vi.getTimerCount()).toBe(0);
|
|
718
807
|
act(() => {
|
|
719
808
|
vi.advanceTimersByTime(1000);
|