@google/gemini-cli 0.9.0-nightly.20250926.1487841d → 0.9.0-nightly.20251001.14dbda91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -54
- package/dist/package.json +2 -2
- package/dist/src/commands/extensions/new.test.js +4 -3
- package/dist/src/commands/extensions/new.test.js.map +1 -1
- package/dist/src/commands/extensions/update.js +18 -4
- package/dist/src/commands/extensions/update.js.map +1 -1
- package/dist/src/commands/mcp/list.js +3 -2
- package/dist/src/commands/mcp/list.js.map +1 -1
- package/dist/src/config/config.d.ts +3 -2
- package/dist/src/config/config.js +52 -47
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/extension.d.ts +6 -4
- package/dist/src/config/extension.js +40 -58
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/extensions/extensionEnablement.d.ts +12 -9
- package/dist/src/config/extensions/extensionEnablement.js +37 -9
- package/dist/src/config/extensions/extensionEnablement.js.map +1 -1
- package/dist/src/config/extensions/extensionEnablement.test.js +72 -0
- package/dist/src/config/extensions/extensionEnablement.test.js.map +1 -1
- package/dist/src/config/extensions/github.js +7 -4
- package/dist/src/config/extensions/github.js.map +1 -1
- package/dist/src/config/extensions/update.d.ts +4 -5
- package/dist/src/config/extensions/update.js +54 -40
- package/dist/src/config/extensions/update.js.map +1 -1
- package/dist/src/config/extensions/update.test.js +84 -69
- package/dist/src/config/extensions/update.test.js.map +1 -1
- package/dist/src/config/settings.js +1 -0
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +21 -3
- package/dist/src/config/settingsSchema.js +20 -2
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/settingsSchema.test.js +9 -1
- package/dist/src/config/settingsSchema.test.js.map +1 -1
- package/dist/src/gemini.js +8 -7
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +1 -1
- 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/test-utils/render.d.ts +3 -1
- package/dist/src/test-utils/render.js +4 -1
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/ui/App.js +7 -9
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/AppContainer.js +47 -9
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/AppContainer.test.js +269 -7
- package/dist/src/ui/AppContainer.test.js.map +1 -1
- package/dist/src/ui/IdeIntegrationNudge.js +3 -0
- package/dist/src/ui/IdeIntegrationNudge.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.js +8 -1
- package/dist/src/ui/auth/AuthDialog.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.test.js +1 -0
- package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.js +14 -10
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/mcpCommand.js +78 -260
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/toolsCommand.js +10 -24
- package/dist/src/ui/commands/toolsCommand.js.map +1 -1
- package/dist/src/ui/commands/types.d.ts +6 -5
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/components/Composer.js +4 -21
- package/dist/src/ui/components/Composer.js.map +1 -1
- package/dist/src/ui/components/ConsentPrompt.d.ts +13 -0
- package/dist/src/ui/components/ConsentPrompt.js +19 -0
- package/dist/src/ui/components/ConsentPrompt.js.map +1 -0
- package/dist/src/ui/components/ConsentPrompt.test.d.ts +6 -0
- package/dist/src/ui/components/ConsentPrompt.test.js +67 -0
- package/dist/src/ui/components/ConsentPrompt.test.js.map +1 -0
- package/dist/src/ui/components/DialogManager.d.ts +2 -1
- package/dist/src/ui/components/DialogManager.js +9 -9
- package/dist/src/ui/components/DialogManager.js.map +1 -1
- package/dist/src/ui/components/EditorSettingsDialog.js +11 -2
- package/dist/src/ui/components/EditorSettingsDialog.js.map +1 -1
- package/dist/src/ui/components/ExitWarning.d.ts +7 -0
- package/dist/src/ui/components/ExitWarning.js +9 -0
- package/dist/src/ui/components/ExitWarning.js.map +1 -0
- package/dist/src/ui/components/FolderTrustDialog.js +3 -0
- package/dist/src/ui/components/FolderTrustDialog.js.map +1 -1
- package/dist/src/ui/components/Footer.d.ts +1 -19
- package/dist/src/ui/components/Footer.js +28 -2
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Help.js +1 -1
- package/dist/src/ui/components/Help.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.d.ts +1 -0
- package/dist/src/ui/components/HistoryItemDisplay.js +5 -2
- package/dist/src/ui/components/HistoryItemDisplay.js.map +1 -1
- package/dist/src/ui/components/HistoryItemDisplay.test.js +50 -10
- package/dist/src/ui/components/HistoryItemDisplay.test.js.map +1 -1
- package/dist/src/ui/components/IdeTrustChangeDialog.d.ts +11 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.js +32 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.js.map +1 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.test.d.ts +6 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.test.js +57 -0
- package/dist/src/ui/components/IdeTrustChangeDialog.test.js.map +1 -0
- package/dist/src/ui/components/InputPrompt.d.ts +6 -0
- package/dist/src/ui/components/InputPrompt.js +43 -13
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/LoopDetectionConfirmation.js +2 -0
- package/dist/src/ui/components/LoopDetectionConfirmation.js.map +1 -1
- package/dist/src/ui/components/MainContent.js +6 -1
- package/dist/src/ui/components/MainContent.js.map +1 -1
- package/dist/src/ui/components/ModelDialog.js +4 -0
- package/dist/src/ui/components/ModelDialog.js.map +1 -1
- package/dist/src/ui/components/PermissionsModifyTrustDialog.js +3 -0
- package/dist/src/ui/components/PermissionsModifyTrustDialog.js.map +1 -1
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js +0 -4
- package/dist/src/ui/components/PermissionsModifyTrustDialog.test.js.map +1 -1
- package/dist/src/ui/components/ProQuotaDialog.js +2 -0
- package/dist/src/ui/components/ProQuotaDialog.js.map +1 -1
- package/dist/src/ui/components/ProQuotaDialog.test.js +2 -0
- package/dist/src/ui/components/ProQuotaDialog.test.js.map +1 -1
- package/dist/src/ui/components/SettingsDialog.js +5 -2
- package/dist/src/ui/components/SettingsDialog.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.js +3 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -1
- package/dist/src/ui/components/ThemeDialog.js +2 -0
- package/dist/src/ui/components/ThemeDialog.js.map +1 -1
- package/dist/src/ui/components/WorkspaceMigrationDialog.js +2 -2
- package/dist/src/ui/components/WorkspaceMigrationDialog.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +14 -0
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/components/messages/ToolMessage.js +24 -1
- package/dist/src/ui/components/messages/ToolMessage.js.map +1 -1
- package/dist/src/ui/components/messages/UserMessage.js +1 -2
- package/dist/src/ui/components/messages/UserMessage.js.map +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.d.ts +5 -10
- package/dist/src/ui/components/shared/BaseSelectionList.js +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.js.map +1 -1
- package/dist/src/ui/components/shared/BaseSelectionList.test.js +7 -5
- package/dist/src/ui/components/shared/BaseSelectionList.test.js.map +1 -1
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.d.ts +2 -3
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.js +1 -1
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.js.map +1 -1
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.js +13 -2
- package/dist/src/ui/components/shared/DescriptiveRadioButtonSelect.test.js.map +1 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.d.ts +2 -3
- package/dist/src/ui/components/shared/RadioButtonSelect.js +1 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.js.map +1 -1
- package/dist/src/ui/components/shared/RadioButtonSelect.test.js +5 -3
- package/dist/src/ui/components/shared/RadioButtonSelect.test.js.map +1 -1
- package/dist/src/ui/components/shared/ScopeSelector.js +4 -1
- package/dist/src/ui/components/shared/ScopeSelector.js.map +1 -1
- package/dist/src/ui/components/views/McpStatus.d.ts +27 -0
- package/dist/src/ui/components/views/McpStatus.js +77 -0
- package/dist/src/ui/components/views/McpStatus.js.map +1 -0
- package/dist/src/ui/components/views/McpStatus.test.d.ts +6 -0
- package/dist/src/ui/components/views/McpStatus.test.js +117 -0
- package/dist/src/ui/components/views/McpStatus.test.js.map +1 -0
- package/dist/src/ui/components/views/ToolsList.d.ts +14 -0
- package/dist/src/ui/components/views/ToolsList.js +7 -0
- package/dist/src/ui/components/views/ToolsList.js.map +1 -0
- package/dist/src/ui/components/views/ToolsList.test.d.ts +6 -0
- package/dist/src/ui/components/views/ToolsList.test.js +45 -0
- package/dist/src/ui/components/views/ToolsList.test.js.map +1 -0
- package/dist/src/ui/contexts/UIStateContext.d.ts +4 -1
- package/dist/src/ui/contexts/UIStateContext.js +1 -0
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +5 -5
- package/dist/src/ui/hooks/slashCommandProcessor.js +4 -2
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.d.ts +10 -1
- package/dist/src/ui/hooks/useExtensionUpdates.js +97 -51
- package/dist/src/ui/hooks/useExtensionUpdates.js.map +1 -1
- package/dist/src/ui/hooks/useExtensionUpdates.test.js +158 -80
- package/dist/src/ui/hooks/useExtensionUpdates.test.js.map +1 -1
- package/dist/src/ui/hooks/useIdeTrustListener.d.ts +4 -2
- package/dist/src/ui/hooks/useIdeTrustListener.js +40 -14
- package/dist/src/ui/hooks/useIdeTrustListener.js.map +1 -1
- package/dist/src/ui/hooks/useIdeTrustListener.test.d.ts +6 -0
- package/dist/src/ui/hooks/useIdeTrustListener.test.js +183 -0
- package/dist/src/ui/hooks/useIdeTrustListener.test.js.map +1 -0
- package/dist/src/ui/hooks/useSelectionList.d.ts +1 -0
- package/dist/src/ui/hooks/useSelectionList.js +63 -43
- package/dist/src/ui/hooks/useSelectionList.js.map +1 -1
- package/dist/src/ui/hooks/useSelectionList.test.js +111 -37
- package/dist/src/ui/hooks/useSelectionList.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +2 -2
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/layouts/DefaultAppLayout.d.ts +7 -0
- package/dist/src/ui/layouts/DefaultAppLayout.js +13 -0
- package/dist/src/ui/layouts/DefaultAppLayout.js.map +1 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.d.ts +7 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.js +14 -0
- package/dist/src/ui/layouts/ScreenReaderAppLayout.js.map +1 -0
- package/dist/src/ui/noninteractive/nonInteractiveUi.js +2 -1
- package/dist/src/ui/noninteractive/nonInteractiveUi.js.map +1 -1
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js +2 -2
- package/dist/src/ui/privacy/CloudFreePrivacyNotice.js.map +1 -1
- package/dist/src/ui/state/extensions.d.ts +27 -0
- package/dist/src/ui/state/extensions.js +45 -0
- package/dist/src/ui/state/extensions.js.map +1 -1
- package/dist/src/ui/types.d.ts +45 -3
- package/dist/src/ui/types.js +2 -0
- package/dist/src/ui/types.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.js +1 -2
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.test.js +94 -91
- package/dist/src/ui/utils/MarkdownDisplay.test.js.map +1 -1
- package/dist/src/ui/utils/displayUtils.d.ts +1 -0
- package/dist/src/ui/utils/displayUtils.js +3 -0
- package/dist/src/ui/utils/displayUtils.js.map +1 -1
- package/dist/src/ui/utils/displayUtils.test.js +36 -17
- package/dist/src/ui/utils/displayUtils.test.js.map +1 -1
- package/dist/src/utils/windowTitle.d.ts +12 -0
- package/dist/src/utils/windowTitle.js +19 -0
- package/dist/src/utils/windowTitle.js.map +1 -0
- package/dist/src/utils/windowTitle.test.d.ts +6 -0
- package/dist/src/utils/windowTitle.test.js +49 -0
- package/dist/src/utils/windowTitle.test.js.map +1 -0
- package/dist/src/zed-integration/fileSystemService.d.ts +1 -0
- package/dist/src/zed-integration/fileSystemService.js +3 -0
- package/dist/src/zed-integration/fileSystemService.js.map +1 -1
- package/dist/src/zed-integration/zedIntegration.d.ts +1 -1
- package/dist/src/zed-integration/zedIntegration.js +3 -1
- package/dist/src/zed-integration/zedIntegration.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIdeTrustListener.test.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useIdeTrustListener.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,26 +3,9 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
import { useReducer, useRef, useEffect } from 'react';
|
|
6
|
+
import { useReducer, useRef, useEffect, useCallback } from 'react';
|
|
7
7
|
import { useKeypress } from './useKeypress.js';
|
|
8
8
|
const NUMBER_INPUT_TIMEOUT_MS = 1000;
|
|
9
|
-
/**
|
|
10
|
-
* Performs an equality check on two arrays of SelectionListItem<T>.
|
|
11
|
-
*
|
|
12
|
-
* It compares the length of the arrays and then the 'value' and 'disabled'
|
|
13
|
-
* properties of each item.
|
|
14
|
-
*/
|
|
15
|
-
const areItemsEqual = (a, b) => {
|
|
16
|
-
if (a.length !== b.length) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
for (let i = 0; i < a.length; i++) {
|
|
20
|
-
if (a[i].value !== b[i].value || a[i].disabled !== b[i].disabled) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return true;
|
|
25
|
-
};
|
|
26
9
|
/**
|
|
27
10
|
* Helper function to find the next enabled index in a given direction, supporting wrapping.
|
|
28
11
|
*/
|
|
@@ -43,10 +26,17 @@ const findNextValidIndex = (currentIndex, direction, items) => {
|
|
|
43
26
|
// If all items are disabled, return the original index
|
|
44
27
|
return currentIndex;
|
|
45
28
|
};
|
|
46
|
-
const computeInitialIndex = (initialIndex, items) => {
|
|
29
|
+
const computeInitialIndex = (initialIndex, items, initialKey) => {
|
|
47
30
|
if (items.length === 0) {
|
|
48
31
|
return 0;
|
|
49
32
|
}
|
|
33
|
+
if (initialKey !== undefined) {
|
|
34
|
+
for (let i = 0; i < items.length; i++) {
|
|
35
|
+
if (items[i].key === initialKey && !items[i].disabled) {
|
|
36
|
+
return i;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
50
40
|
let targetIndex = initialIndex;
|
|
51
41
|
if (targetIndex < 0 || targetIndex >= items.length) {
|
|
52
42
|
targetIndex = 0;
|
|
@@ -60,7 +50,8 @@ const computeInitialIndex = (initialIndex, items) => {
|
|
|
60
50
|
function selectionListReducer(state, action) {
|
|
61
51
|
switch (action.type) {
|
|
62
52
|
case 'SET_ACTIVE_INDEX': {
|
|
63
|
-
const { index
|
|
53
|
+
const { index } = action.payload;
|
|
54
|
+
const { items } = state;
|
|
64
55
|
// Only update if index actually changed and is valid
|
|
65
56
|
if (index === state.activeIndex) {
|
|
66
57
|
return state;
|
|
@@ -71,7 +62,7 @@ function selectionListReducer(state, action) {
|
|
|
71
62
|
return state;
|
|
72
63
|
}
|
|
73
64
|
case 'MOVE_UP': {
|
|
74
|
-
const { items } =
|
|
65
|
+
const { items } = state;
|
|
75
66
|
const newIndex = findNextValidIndex(state.activeIndex, 'up', items);
|
|
76
67
|
if (newIndex !== state.activeIndex) {
|
|
77
68
|
return { ...state, activeIndex: newIndex, pendingHighlight: true };
|
|
@@ -79,7 +70,7 @@ function selectionListReducer(state, action) {
|
|
|
79
70
|
return state;
|
|
80
71
|
}
|
|
81
72
|
case 'MOVE_DOWN': {
|
|
82
|
-
const { items } =
|
|
73
|
+
const { items } = state;
|
|
83
74
|
const newIndex = findNextValidIndex(state.activeIndex, 'down', items);
|
|
84
75
|
if (newIndex !== state.activeIndex) {
|
|
85
76
|
return { ...state, activeIndex: newIndex, pendingHighlight: true };
|
|
@@ -91,14 +82,16 @@ function selectionListReducer(state, action) {
|
|
|
91
82
|
}
|
|
92
83
|
case 'INITIALIZE': {
|
|
93
84
|
const { initialIndex, items } = action.payload;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
85
|
+
const activeKey = initialIndex === state.initialIndex &&
|
|
86
|
+
state.activeIndex !== state.initialIndex
|
|
87
|
+
? state.items[state.activeIndex]?.key
|
|
88
|
+
: undefined;
|
|
89
|
+
// We don't need to check for equality here anymore as it is handled in the effect
|
|
90
|
+
const targetIndex = computeInitialIndex(initialIndex, items, activeKey);
|
|
99
91
|
return {
|
|
100
92
|
...state,
|
|
101
93
|
items,
|
|
94
|
+
initialIndex,
|
|
102
95
|
activeIndex: targetIndex,
|
|
103
96
|
pendingHighlight: false,
|
|
104
97
|
};
|
|
@@ -117,6 +110,21 @@ function selectionListReducer(state, action) {
|
|
|
117
110
|
}
|
|
118
111
|
}
|
|
119
112
|
}
|
|
113
|
+
function areBaseItemsEqual(a, b) {
|
|
114
|
+
if (a === b)
|
|
115
|
+
return true;
|
|
116
|
+
if (a.length !== b.length)
|
|
117
|
+
return false;
|
|
118
|
+
for (let i = 0; i < a.length; i++) {
|
|
119
|
+
if (a[i].key !== b[i].key || a[i].disabled !== b[i].disabled) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
function toBaseItems(items) {
|
|
126
|
+
return items.map(({ key, disabled }) => ({ key, disabled }));
|
|
127
|
+
}
|
|
120
128
|
/**
|
|
121
129
|
* A headless hook that provides keyboard navigation and selection logic
|
|
122
130
|
* for list-based selection components like radio buttons and menus.
|
|
@@ -129,19 +137,31 @@ function selectionListReducer(state, action) {
|
|
|
129
137
|
* - Wrapping navigation (last to first, first to last)
|
|
130
138
|
*/
|
|
131
139
|
export function useSelectionList({ items, initialIndex = 0, onSelect, onHighlight, isFocused = true, showNumbers = false, }) {
|
|
132
|
-
const
|
|
133
|
-
|
|
140
|
+
const baseItems = toBaseItems(items);
|
|
141
|
+
const [state, dispatch] = useReducer(selectionListReducer, {
|
|
142
|
+
activeIndex: computeInitialIndex(initialIndex, baseItems),
|
|
134
143
|
initialIndex,
|
|
135
144
|
pendingHighlight: false,
|
|
136
145
|
pendingSelect: false,
|
|
137
|
-
items,
|
|
146
|
+
items: baseItems,
|
|
138
147
|
});
|
|
139
148
|
const numberInputRef = useRef('');
|
|
140
149
|
const numberInputTimer = useRef(null);
|
|
150
|
+
const prevBaseItemsRef = useRef(baseItems);
|
|
151
|
+
const prevInitialIndexRef = useRef(initialIndex);
|
|
141
152
|
// Initialize/synchronize state when initialIndex or items change
|
|
142
153
|
useEffect(() => {
|
|
143
|
-
|
|
144
|
-
|
|
154
|
+
const baseItemsChanged = !areBaseItemsEqual(prevBaseItemsRef.current, baseItems);
|
|
155
|
+
const initialIndexChanged = prevInitialIndexRef.current !== initialIndex;
|
|
156
|
+
if (baseItemsChanged || initialIndexChanged) {
|
|
157
|
+
dispatch({
|
|
158
|
+
type: 'INITIALIZE',
|
|
159
|
+
payload: { initialIndex, items: baseItems },
|
|
160
|
+
});
|
|
161
|
+
prevBaseItemsRef.current = baseItems;
|
|
162
|
+
prevInitialIndexRef.current = initialIndex;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
145
165
|
// Handle side effects based on state changes
|
|
146
166
|
useEffect(() => {
|
|
147
167
|
let needsClear = false;
|
|
@@ -172,7 +192,8 @@ export function useSelectionList({ items, initialIndex = 0, onSelect, onHighligh
|
|
|
172
192
|
clearTimeout(numberInputTimer.current);
|
|
173
193
|
}
|
|
174
194
|
}, []);
|
|
175
|
-
|
|
195
|
+
const itemsLength = items.length;
|
|
196
|
+
const handleKeypress = useCallback((key) => {
|
|
176
197
|
const { sequence, name } = key;
|
|
177
198
|
const isNumeric = showNumbers && /^[0-9]$/.test(sequence);
|
|
178
199
|
// Clear number input buffer on non-numeric key press
|
|
@@ -181,15 +202,15 @@ export function useSelectionList({ items, initialIndex = 0, onSelect, onHighligh
|
|
|
181
202
|
numberInputRef.current = '';
|
|
182
203
|
}
|
|
183
204
|
if (name === 'k' || name === 'up') {
|
|
184
|
-
dispatch({ type: 'MOVE_UP'
|
|
205
|
+
dispatch({ type: 'MOVE_UP' });
|
|
185
206
|
return;
|
|
186
207
|
}
|
|
187
208
|
if (name === 'j' || name === 'down') {
|
|
188
|
-
dispatch({ type: 'MOVE_DOWN'
|
|
209
|
+
dispatch({ type: 'MOVE_DOWN' });
|
|
189
210
|
return;
|
|
190
211
|
}
|
|
191
212
|
if (name === 'return') {
|
|
192
|
-
dispatch({ type: 'SELECT_CURRENT'
|
|
213
|
+
dispatch({ type: 'SELECT_CURRENT' });
|
|
193
214
|
return;
|
|
194
215
|
}
|
|
195
216
|
// Handle numeric input for quick selection
|
|
@@ -207,17 +228,16 @@ export function useSelectionList({ items, initialIndex = 0, onSelect, onHighligh
|
|
|
207
228
|
}, NUMBER_INPUT_TIMEOUT_MS);
|
|
208
229
|
return;
|
|
209
230
|
}
|
|
210
|
-
if (targetIndex >= 0 && targetIndex <
|
|
231
|
+
if (targetIndex >= 0 && targetIndex < itemsLength) {
|
|
211
232
|
dispatch({
|
|
212
233
|
type: 'SET_ACTIVE_INDEX',
|
|
213
|
-
payload: { index: targetIndex
|
|
234
|
+
payload: { index: targetIndex },
|
|
214
235
|
});
|
|
215
236
|
// If the number can't be a prefix for another valid number, select immediately
|
|
216
237
|
const potentialNextNumber = Number.parseInt(newNumberInput + '0', 10);
|
|
217
|
-
if (potentialNextNumber >
|
|
238
|
+
if (potentialNextNumber > itemsLength) {
|
|
218
239
|
dispatch({
|
|
219
240
|
type: 'SELECT_CURRENT',
|
|
220
|
-
payload: { items },
|
|
221
241
|
});
|
|
222
242
|
numberInputRef.current = '';
|
|
223
243
|
}
|
|
@@ -226,7 +246,6 @@ export function useSelectionList({ items, initialIndex = 0, onSelect, onHighligh
|
|
|
226
246
|
numberInputTimer.current = setTimeout(() => {
|
|
227
247
|
dispatch({
|
|
228
248
|
type: 'SELECT_CURRENT',
|
|
229
|
-
payload: { items },
|
|
230
249
|
});
|
|
231
250
|
numberInputRef.current = '';
|
|
232
251
|
}, NUMBER_INPUT_TIMEOUT_MS);
|
|
@@ -237,11 +256,12 @@ export function useSelectionList({ items, initialIndex = 0, onSelect, onHighligh
|
|
|
237
256
|
numberInputRef.current = '';
|
|
238
257
|
}
|
|
239
258
|
}
|
|
240
|
-
},
|
|
259
|
+
}, [dispatch, itemsLength, showNumbers]);
|
|
260
|
+
useKeypress(handleKeypress, { isActive: !!(isFocused && itemsLength > 0) });
|
|
241
261
|
const setActiveIndex = (index) => {
|
|
242
262
|
dispatch({
|
|
243
263
|
type: 'SET_ACTIVE_INDEX',
|
|
244
|
-
payload: { index
|
|
264
|
+
payload: { index },
|
|
245
265
|
});
|
|
246
266
|
};
|
|
247
267
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSelectionList.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useSelectionList.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useSelectionList.js","sourceRoot":"","sources":["../../../../src/ui/hooks/useSelectionList.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACnE,OAAO,EAAE,WAAW,EAAY,MAAM,kBAAkB,CAAC;AA2DzD,MAAM,uBAAuB,GAAG,IAAI,CAAC;AAErC;;GAEG;AACH,MAAM,kBAAkB,GAAG,CACzB,YAAoB,EACpB,SAAwB,EACxB,KAA0B,EAClB,EAAE;IACV,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACzB,IAAI,GAAG,KAAK,CAAC;QAAE,OAAO,YAAY,CAAC;IAEnC,IAAI,SAAS,GAAG,YAAY,CAAC;IAC7B,MAAM,IAAI,GAAG,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,0DAA0D;QAC1D,uFAAuF;QACvF,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;QAE3C,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IAED,uDAAuD;IACvD,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAC1B,YAAoB,EACpB,KAA0B,EAC1B,UAAmB,EACX,EAAE;IACV,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,KAAK,CAAC,CAAC,CAAE,CAAC,GAAG,KAAK,UAAU,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,QAAQ,EAAE,CAAC;gBACxD,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,WAAW,GAAG,YAAY,CAAC;IAE/B,IAAI,WAAW,GAAG,CAAC,IAAI,WAAW,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACnD,WAAW,GAAG,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,KAAK,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,CAAC;QACjC,MAAM,SAAS,GAAG,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACjE,WAAW,GAAG,SAAS,CAAC;IAC1B,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC,CAAC;AAEF,SAAS,oBAAoB,CAC3B,KAAyB,EACzB,MAA2B;IAE3B,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,kBAAkB,CAAC,CAAC,CAAC;YACxB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;YACjC,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;YAExB,qDAAqD;YACrD,IAAI,KAAK,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;gBAChC,OAAO,KAAK,CAAC;YACf,CAAC;YAED,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBACvC,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;YAClE,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;YACxB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YACpE,IAAI,QAAQ,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;gBACnC,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;YACrE,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;YACxB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YACtE,IAAI,QAAQ,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC;gBACnC,OAAO,EAAE,GAAG,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;YACrE,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,KAAK,gBAAgB,CAAC,CAAC,CAAC;YACtB,OAAO,EAAE,GAAG,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;QAC3C,CAAC;QAED,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;YAC/C,MAAM,SAAS,GACb,YAAY,KAAK,KAAK,CAAC,YAAY;gBACnC,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,YAAY;gBACtC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG;gBACrC,CAAC,CAAC,SAAS,CAAC;YAEhB,kFAAkF;YAClF,MAAM,WAAW,GAAG,mBAAmB,CAAC,YAAY,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;YAExE,OAAO;gBACL,GAAG,KAAK;gBACR,KAAK;gBACL,YAAY;gBACZ,WAAW,EAAE,WAAW;gBACxB,gBAAgB,EAAE,KAAK;aACxB,CAAC;QACJ,CAAC;QAED,KAAK,qBAAqB,CAAC,CAAC,CAAC;YAC3B,OAAO;gBACL,GAAG,KAAK;gBACR,gBAAgB,EAAE,KAAK;gBACvB,aAAa,EAAE,KAAK;aACrB,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,eAAe,GAAU,MAAM,CAAC;YACtC,OAAO,CAAC,KAAK,CAAC,kCAAkC,eAAe,EAAE,CAAC,CAAC;YACnE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CACxB,CAAsB,EACtB,CAAsB;IAEtB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAExC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAE,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAE,CAAC,QAAQ,EAAE,CAAC;YACjE,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAClB,KAAkC;IAElC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAI,EAClC,KAAK,EACL,YAAY,GAAG,CAAC,EAChB,QAAQ,EACR,WAAW,EACX,SAAS,GAAG,IAAI,EAChB,WAAW,GAAG,KAAK,GACQ;IAC3B,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAErC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,UAAU,CAAC,oBAAoB,EAAE;QACzD,WAAW,EAAE,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC;QACzD,YAAY;QACZ,gBAAgB,EAAE,KAAK;QACvB,aAAa,EAAE,KAAK;QACpB,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAClC,MAAM,gBAAgB,GAAG,MAAM,CAAwB,IAAI,CAAC,CAAC;IAE7D,MAAM,gBAAgB,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,mBAAmB,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IAEjD,iEAAiE;IACjE,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,gBAAgB,GAAG,CAAC,iBAAiB,CACzC,gBAAgB,CAAC,OAAO,EACxB,SAAS,CACV,CAAC;QACF,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,OAAO,KAAK,YAAY,CAAC;QAEzE,IAAI,gBAAgB,IAAI,mBAAmB,EAAE,CAAC;YAC5C,QAAQ,CAAC;gBACP,IAAI,EAAE,YAAY;gBAClB,OAAO,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE;aAC5C,CAAC,CAAC;YACH,gBAAgB,CAAC,OAAO,GAAG,SAAS,CAAC;YACrC,mBAAmB,CAAC,OAAO,GAAG,YAAY,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,6CAA6C;IAC7C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACvD,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAE,CAAC,KAAK,CAAC,CAAC;YAC/C,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;QAED,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;YACpD,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;YAC7C,IAAI,WAAW,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;gBACzC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;YACD,UAAU,GAAG,IAAI,CAAC;QACpB,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,QAAQ,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,EAAE;QACD,KAAK,CAAC,gBAAgB;QACtB,KAAK,CAAC,aAAa;QACnB,KAAK,CAAC,WAAW;QACjB,KAAK;QACL,WAAW;QACX,QAAQ;KACT,CAAC,CAAC;IAEH,SAAS,CACP,GAAG,EAAE,CAAC,GAAG,EAAE;QACT,IAAI,gBAAgB,CAAC,OAAO,EAAE,CAAC;YAC7B,YAAY,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,EACD,EAAE,CACH,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC;IACjC,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,GAAQ,EAAE,EAAE;QACX,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC;QAC/B,MAAM,SAAS,GAAG,WAAW,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE1D,qDAAqD;QACrD,IAAI,CAAC,SAAS,IAAI,gBAAgB,CAAC,OAAO,EAAE,CAAC;YAC3C,YAAY,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACvC,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACpC,QAAQ,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;YAChC,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,QAAQ,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,2CAA2C;QAC3C,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,gBAAgB,CAAC,OAAO,EAAE,CAAC;gBAC7B,YAAY,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YACzC,CAAC;YAED,MAAM,cAAc,GAAG,cAAc,CAAC,OAAO,GAAG,QAAQ,CAAC;YACzD,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC;YAExC,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;YAE5D,oCAAoC;YACpC,IAAI,cAAc,KAAK,GAAG,EAAE,CAAC;gBAC3B,gBAAgB,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;oBACzC,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC;gBAC9B,CAAC,EAAE,uBAAuB,CAAC,CAAC;gBAC5B,OAAO;YACT,CAAC;YAED,IAAI,WAAW,IAAI,CAAC,IAAI,WAAW,GAAG,WAAW,EAAE,CAAC;gBAClD,QAAQ,CAAC;oBACP,IAAI,EAAE,kBAAkB;oBACxB,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE;iBAChC,CAAC,CAAC;gBAEH,+EAA+E;gBAC/E,MAAM,mBAAmB,GAAG,MAAM,CAAC,QAAQ,CAAC,cAAc,GAAG,GAAG,EAAE,EAAE,CAAC,CAAC;gBACtE,IAAI,mBAAmB,GAAG,WAAW,EAAE,CAAC;oBACtC,QAAQ,CAAC;wBACP,IAAI,EAAE,gBAAgB;qBACvB,CAAC,CAAC;oBACH,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC;gBAC9B,CAAC;qBAAM,CAAC;oBACN,2CAA2C;oBAC3C,gBAAgB,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;wBACzC,QAAQ,CAAC;4BACP,IAAI,EAAE,gBAAgB;yBACvB,CAAC,CAAC;wBACH,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC;oBAC9B,CAAC,EAAE,uBAAuB,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,0BAA0B;gBAC1B,cAAc,CAAC,OAAO,GAAG,EAAE,CAAC;YAC9B,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CACrC,CAAC;IAEF,WAAW,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,WAAW,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5E,MAAM,cAAc,GAAG,CAAC,KAAa,EAAE,EAAE;QACvC,QAAQ,CAAC;YACP,IAAI,EAAE,kBAAkB;YACxB,OAAO,EAAE,EAAE,KAAK,EAAE;SACnB,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,OAAO;QACL,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,cAAc;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -13,10 +13,10 @@ describe('useSelectionList', () => {
|
|
|
13
13
|
const mockOnSelect = vi.fn();
|
|
14
14
|
const mockOnHighlight = vi.fn();
|
|
15
15
|
const items = [
|
|
16
|
-
{ value: 'A' },
|
|
17
|
-
{ value: 'B', disabled: true },
|
|
18
|
-
{ value: 'C' },
|
|
19
|
-
{ value: 'D' },
|
|
16
|
+
{ value: 'A', key: 'A' },
|
|
17
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
18
|
+
{ value: 'C', key: 'C' },
|
|
19
|
+
{ value: 'D', key: 'D' },
|
|
20
20
|
];
|
|
21
21
|
beforeEach(() => {
|
|
22
22
|
activeKeypressHandler = null;
|
|
@@ -76,9 +76,9 @@ describe('useSelectionList', () => {
|
|
|
76
76
|
});
|
|
77
77
|
it('should wrap around to find the next enabled item if initialIndex is disabled', () => {
|
|
78
78
|
const wrappingItems = [
|
|
79
|
-
{ value: 'A' },
|
|
80
|
-
{ value: 'B', disabled: true },
|
|
81
|
-
{ value: 'C', disabled: true },
|
|
79
|
+
{ value: 'A', key: 'A' },
|
|
80
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
81
|
+
{ value: 'C', disabled: true, key: 'C' },
|
|
82
82
|
];
|
|
83
83
|
const { result } = renderHook(() => useSelectionList({
|
|
84
84
|
items: wrappingItems,
|
|
@@ -103,8 +103,8 @@ describe('useSelectionList', () => {
|
|
|
103
103
|
});
|
|
104
104
|
it('should stick to the initial index if all items are disabled', () => {
|
|
105
105
|
const allDisabled = [
|
|
106
|
-
{ value: 'A', disabled: true },
|
|
107
|
-
{ value: 'B', disabled: true },
|
|
106
|
+
{ value: 'A', disabled: true, key: 'A' },
|
|
107
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
108
108
|
];
|
|
109
109
|
const { result } = renderHook(() => useSelectionList({
|
|
110
110
|
items: allDisabled,
|
|
@@ -154,7 +154,7 @@ describe('useSelectionList', () => {
|
|
|
154
154
|
expect(mockOnHighlight).toHaveBeenCalledWith('C');
|
|
155
155
|
});
|
|
156
156
|
it('should not move or call onHighlight if navigation results in the same index (e.g., single item)', () => {
|
|
157
|
-
const singleItem = [{ value: 'A' }];
|
|
157
|
+
const singleItem = [{ value: 'A', key: 'A' }];
|
|
158
158
|
const { result } = renderHook(() => useSelectionList({
|
|
159
159
|
items: singleItem,
|
|
160
160
|
onSelect: mockOnSelect,
|
|
@@ -166,8 +166,8 @@ describe('useSelectionList', () => {
|
|
|
166
166
|
});
|
|
167
167
|
it('should not move or call onHighlight if all items are disabled', () => {
|
|
168
168
|
const allDisabled = [
|
|
169
|
-
{ value: 'A', disabled: true },
|
|
170
|
-
{ value: 'B', disabled: true },
|
|
169
|
+
{ value: 'A', disabled: true, key: 'A' },
|
|
170
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
171
171
|
];
|
|
172
172
|
const { result } = renderHook(() => useSelectionList({
|
|
173
173
|
items: allDisabled,
|
|
@@ -317,7 +317,7 @@ describe('useSelectionList', () => {
|
|
|
317
317
|
vi.useRealTimers();
|
|
318
318
|
});
|
|
319
319
|
const shortList = items;
|
|
320
|
-
const longList = Array.from({ length: 15 }, (_, i) => ({ value: `Item ${i + 1}` }));
|
|
320
|
+
const longList = Array.from({ length: 15 }, (_, i) => ({ value: `Item ${i + 1}`, key: `Item ${i + 1}` }));
|
|
321
321
|
const pressNumber = (num) => pressKey(num, num);
|
|
322
322
|
it('should not respond to numbers if showNumbers is false (default)', () => {
|
|
323
323
|
const { result } = renderHook(() => useSelectionList({ items: shortList, onSelect: mockOnSelect }));
|
|
@@ -430,7 +430,7 @@ describe('useSelectionList', () => {
|
|
|
430
430
|
it('should highlight but not select a disabled item (timeout case)', () => {
|
|
431
431
|
// Create a list where the ambiguous prefix points to a disabled item
|
|
432
432
|
const disabledAmbiguousList = [
|
|
433
|
-
{ value: 'Item 1 Disabled', disabled: true },
|
|
433
|
+
{ value: 'Item 1 Disabled', disabled: true, key: 'Item 1 Disabled' },
|
|
434
434
|
...longList.slice(1),
|
|
435
435
|
];
|
|
436
436
|
const { result } = renderHook(() => useSelectionList({
|
|
@@ -488,6 +488,20 @@ describe('useSelectionList', () => {
|
|
|
488
488
|
rerender({ initialIndex: 2 });
|
|
489
489
|
expect(result.current.activeIndex).toBe(2);
|
|
490
490
|
});
|
|
491
|
+
it('should respect a new initialIndex even after user interaction', () => {
|
|
492
|
+
const { result, rerender } = renderHook(({ initialIndex }) => useSelectionList({
|
|
493
|
+
items,
|
|
494
|
+
onSelect: mockOnSelect,
|
|
495
|
+
initialIndex,
|
|
496
|
+
}), { initialProps: { initialIndex: 0 } });
|
|
497
|
+
// User navigates, changing the active index
|
|
498
|
+
pressKey('down');
|
|
499
|
+
expect(result.current.activeIndex).toBe(2);
|
|
500
|
+
// The component re-renders with a new initial index
|
|
501
|
+
rerender({ initialIndex: 3 });
|
|
502
|
+
// The hook should now respect the new initial index
|
|
503
|
+
expect(result.current.activeIndex).toBe(3);
|
|
504
|
+
});
|
|
491
505
|
it('should validate index when initialIndex prop changes to a disabled item', () => {
|
|
492
506
|
const { result, rerender } = renderHook(({ initialIndex }) => useSelectionList({
|
|
493
507
|
items,
|
|
@@ -504,13 +518,20 @@ describe('useSelectionList', () => {
|
|
|
504
518
|
items: testItems,
|
|
505
519
|
}), { initialProps: { items } });
|
|
506
520
|
expect(result.current.activeIndex).toBe(3);
|
|
507
|
-
const shorterItems = [
|
|
521
|
+
const shorterItems = [
|
|
522
|
+
{ value: 'X', key: 'X' },
|
|
523
|
+
{ value: 'Y', key: 'Y' },
|
|
524
|
+
];
|
|
508
525
|
rerender({ items: shorterItems }); // Length 2
|
|
509
526
|
// The useEffect syncs based on the initialIndex (3) which is now out of bounds. It defaults to 0.
|
|
510
527
|
expect(result.current.activeIndex).toBe(0);
|
|
511
528
|
});
|
|
512
529
|
it('should adjust activeIndex if items change and the initialIndex becomes disabled', () => {
|
|
513
|
-
const initialItems = [
|
|
530
|
+
const initialItems = [
|
|
531
|
+
{ value: 'A', key: 'A' },
|
|
532
|
+
{ value: 'B', key: 'B' },
|
|
533
|
+
{ value: 'C', key: 'C' },
|
|
534
|
+
];
|
|
514
535
|
const { result, rerender } = renderHook(({ items: testItems }) => useSelectionList({
|
|
515
536
|
onSelect: mockOnSelect,
|
|
516
537
|
initialIndex: 1,
|
|
@@ -518,9 +539,9 @@ describe('useSelectionList', () => {
|
|
|
518
539
|
}), { initialProps: { items: initialItems } });
|
|
519
540
|
expect(result.current.activeIndex).toBe(1);
|
|
520
541
|
const newItems = [
|
|
521
|
-
{ value: 'A' },
|
|
522
|
-
{ value: 'B', disabled: true },
|
|
523
|
-
{ value: 'C' },
|
|
542
|
+
{ value: 'A', key: 'A' },
|
|
543
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
544
|
+
{ value: 'C', key: 'C' },
|
|
524
545
|
];
|
|
525
546
|
rerender({ items: newItems });
|
|
526
547
|
expect(result.current.activeIndex).toBe(2);
|
|
@@ -536,10 +557,10 @@ describe('useSelectionList', () => {
|
|
|
536
557
|
});
|
|
537
558
|
it('should not reset activeIndex when items are deeply equal', () => {
|
|
538
559
|
const initialItems = [
|
|
539
|
-
{ value: 'A' },
|
|
540
|
-
{ value: 'B', disabled: true },
|
|
541
|
-
{ value: 'C' },
|
|
542
|
-
{ value: 'D' },
|
|
560
|
+
{ value: 'A', key: 'A' },
|
|
561
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
562
|
+
{ value: 'C', key: 'C' },
|
|
563
|
+
{ value: 'D', key: 'D' },
|
|
543
564
|
];
|
|
544
565
|
const { result, rerender } = renderHook(({ items: testItems }) => useSelectionList({
|
|
545
566
|
onSelect: mockOnSelect,
|
|
@@ -555,10 +576,10 @@ describe('useSelectionList', () => {
|
|
|
555
576
|
mockOnHighlight.mockClear();
|
|
556
577
|
// Create new array with same content (deeply equal but not identical)
|
|
557
578
|
const newItems = [
|
|
558
|
-
{ value: 'A' },
|
|
559
|
-
{ value: 'B', disabled: true },
|
|
560
|
-
{ value: 'C' },
|
|
561
|
-
{ value: 'D' },
|
|
579
|
+
{ value: 'A', key: 'A' },
|
|
580
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
581
|
+
{ value: 'C', key: 'C' },
|
|
582
|
+
{ value: 'D', key: 'D' },
|
|
562
583
|
];
|
|
563
584
|
rerender({ items: newItems });
|
|
564
585
|
// Active index should remain the same since items are deeply equal
|
|
@@ -568,10 +589,10 @@ describe('useSelectionList', () => {
|
|
|
568
589
|
});
|
|
569
590
|
it('should update activeIndex when items change structurally', () => {
|
|
570
591
|
const initialItems = [
|
|
571
|
-
{ value: 'A' },
|
|
572
|
-
{ value: 'B', disabled: true },
|
|
573
|
-
{ value: 'C' },
|
|
574
|
-
{ value: 'D' },
|
|
592
|
+
{ value: 'A', key: 'A' },
|
|
593
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
594
|
+
{ value: 'C', key: 'C' },
|
|
595
|
+
{ value: 'D', key: 'D' },
|
|
575
596
|
];
|
|
576
597
|
const { result, rerender } = renderHook(({ items: testItems }) => useSelectionList({
|
|
577
598
|
onSelect: mockOnSelect,
|
|
@@ -582,13 +603,21 @@ describe('useSelectionList', () => {
|
|
|
582
603
|
expect(result.current.activeIndex).toBe(3);
|
|
583
604
|
mockOnHighlight.mockClear();
|
|
584
605
|
// Change item values (not deeply equal)
|
|
585
|
-
const newItems = [
|
|
606
|
+
const newItems = [
|
|
607
|
+
{ value: 'X', key: 'X' },
|
|
608
|
+
{ value: 'Y', key: 'Y' },
|
|
609
|
+
{ value: 'Z', key: 'Z' },
|
|
610
|
+
];
|
|
586
611
|
rerender({ items: newItems });
|
|
587
612
|
// Active index should update based on initialIndex and new items
|
|
588
613
|
expect(result.current.activeIndex).toBe(0);
|
|
589
614
|
});
|
|
590
615
|
it('should handle partial changes in items array', () => {
|
|
591
|
-
const initialItems = [
|
|
616
|
+
const initialItems = [
|
|
617
|
+
{ value: 'A', key: 'A' },
|
|
618
|
+
{ value: 'B', key: 'B' },
|
|
619
|
+
{ value: 'C', key: 'C' },
|
|
620
|
+
];
|
|
592
621
|
const { result, rerender } = renderHook(({ items: testItems }) => useSelectionList({
|
|
593
622
|
onSelect: mockOnSelect,
|
|
594
623
|
initialIndex: 1,
|
|
@@ -597,14 +626,59 @@ describe('useSelectionList', () => {
|
|
|
597
626
|
expect(result.current.activeIndex).toBe(1);
|
|
598
627
|
// Change only one item's disabled status
|
|
599
628
|
const newItems = [
|
|
600
|
-
{ value: 'A' },
|
|
601
|
-
{ value: 'B', disabled: true },
|
|
602
|
-
{ value: 'C' },
|
|
629
|
+
{ value: 'A', key: 'A' },
|
|
630
|
+
{ value: 'B', disabled: true, key: 'B' },
|
|
631
|
+
{ value: 'C', key: 'C' },
|
|
603
632
|
];
|
|
604
633
|
rerender({ items: newItems });
|
|
605
634
|
// Should find next valid index since current became disabled
|
|
606
635
|
expect(result.current.activeIndex).toBe(2);
|
|
607
636
|
});
|
|
637
|
+
it('should update selection when a new item is added to the start of the list', () => {
|
|
638
|
+
const initialItems = [
|
|
639
|
+
{ value: 'A', key: 'A' },
|
|
640
|
+
{ value: 'B', key: 'B' },
|
|
641
|
+
{ value: 'C', key: 'C' },
|
|
642
|
+
];
|
|
643
|
+
const { result, rerender } = renderHook(({ items: testItems }) => useSelectionList({
|
|
644
|
+
onSelect: mockOnSelect,
|
|
645
|
+
items: testItems,
|
|
646
|
+
}), { initialProps: { items: initialItems } });
|
|
647
|
+
pressKey('down');
|
|
648
|
+
expect(result.current.activeIndex).toBe(1);
|
|
649
|
+
const newItems = [
|
|
650
|
+
{ value: 'D', key: 'D' },
|
|
651
|
+
{ value: 'A', key: 'A' },
|
|
652
|
+
{ value: 'B', key: 'B' },
|
|
653
|
+
{ value: 'C', key: 'C' },
|
|
654
|
+
];
|
|
655
|
+
rerender({ items: newItems });
|
|
656
|
+
expect(result.current.activeIndex).toBe(2);
|
|
657
|
+
});
|
|
658
|
+
it('should not re-initialize when items have identical keys but are different objects', () => {
|
|
659
|
+
const initialItems = [
|
|
660
|
+
{ value: 'A', key: 'A' },
|
|
661
|
+
{ value: 'B', key: 'B' },
|
|
662
|
+
];
|
|
663
|
+
let renderCount = 0;
|
|
664
|
+
const { rerender } = renderHook(({ items: testItems }) => {
|
|
665
|
+
renderCount++;
|
|
666
|
+
return useSelectionList({
|
|
667
|
+
onSelect: mockOnSelect,
|
|
668
|
+
onHighlight: mockOnHighlight,
|
|
669
|
+
items: testItems,
|
|
670
|
+
});
|
|
671
|
+
}, { initialProps: { items: initialItems } });
|
|
672
|
+
// Initial render
|
|
673
|
+
expect(renderCount).toBe(1);
|
|
674
|
+
// Create new items with the same keys but different object references
|
|
675
|
+
const newItems = [
|
|
676
|
+
{ value: 'A', key: 'A' },
|
|
677
|
+
{ value: 'B', key: 'B' },
|
|
678
|
+
];
|
|
679
|
+
rerender({ items: newItems });
|
|
680
|
+
expect(renderCount).toBe(2);
|
|
681
|
+
});
|
|
608
682
|
});
|
|
609
683
|
describe('Manual Control', () => {
|
|
610
684
|
it('should allow manual setting of active index via setActiveIndex', () => {
|
|
@@ -627,7 +701,7 @@ describe('useSelectionList', () => {
|
|
|
627
701
|
vi.useRealTimers();
|
|
628
702
|
});
|
|
629
703
|
it('should clear timeout on unmount when timer is active', () => {
|
|
630
|
-
const longList = Array.from({ length: 15 }, (_, i) => ({ value: `Item ${i + 1}` }));
|
|
704
|
+
const longList = Array.from({ length: 15 }, (_, i) => ({ value: `Item ${i + 1}`, key: `Item ${i + 1}` }));
|
|
631
705
|
const { unmount } = renderHook(() => useSelectionList({
|
|
632
706
|
items: longList,
|
|
633
707
|
onSelect: mockOnSelect,
|