vzcode 2.15.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/assets/{bindings_wasm_bg-9w8E-TmY.wasm → bindings_wasm_bg-D9vNLG9F.wasm} +0 -0
  2. package/dist/assets/buildWorker-DL4wXpRr.js +695 -0
  3. package/dist/assets/index-BiPmUreW.js +474 -0
  4. package/dist/assets/{index-DLm5FQ0E.css → index-BvGPtSrr.css} +1 -1
  5. package/dist/assets/worker-RJ-cjbld.js +327 -0
  6. package/dist/index.html +2 -2
  7. package/dist/server/aiChatHandler/chatOperations.js +168 -35
  8. package/dist/server/aiChatHandler/index.js +11 -30
  9. package/dist/server/aiChatHandler/llmStreaming.js +105 -118
  10. package/package.json +11 -11
  11. package/src/client/AIAssist/AIAssistWidget/index.tsx +12 -1
  12. package/src/client/App/useShareDB.ts +1 -1
  13. package/src/client/CodeEditor/index.tsx +9 -10
  14. package/src/client/VZCodeContext/types.ts +3 -1
  15. package/src/client/VZCodeContext/useVZCodeState.ts +7 -5
  16. package/src/client/VZRight.tsx +10 -2
  17. package/src/client/VZSidebar/AIChat/ChatInput.tsx +1 -7
  18. package/src/client/VZSidebar/AIChat/DiffView.scss +1 -0
  19. package/src/client/VZSidebar/AIChat/DiffView.tsx +72 -29
  20. package/src/client/VZSidebar/AIChat/FileEditingIndicator.tsx +89 -0
  21. package/src/client/VZSidebar/AIChat/IndividualFileDiff.tsx +86 -0
  22. package/src/client/VZSidebar/AIChat/JumpToLatestButton.tsx +64 -0
  23. package/src/client/VZSidebar/AIChat/Message.tsx +124 -56
  24. package/src/client/VZSidebar/AIChat/MessageList.tsx +155 -114
  25. package/src/client/VZSidebar/AIChat/ThinkingScratchpad.tsx +4 -118
  26. package/src/client/VZSidebar/AIChat/index.tsx +59 -19
  27. package/src/client/VZSidebar/AIChat/styles.scss +190 -43
  28. package/src/client/VZSidebar/Item.tsx +2 -2
  29. package/src/client/VZSidebar/Search.tsx +13 -6
  30. package/src/client/VZSidebar/VisualEditor/VisualEditor.tsx +39 -23
  31. package/src/client/VZSidebar/VisualEditor/utils.ts +1 -1
  32. package/src/client/VZSidebar/index.tsx +12 -10
  33. package/src/client/VZSidebar/useDragAndDrop.tsx +225 -214
  34. package/src/client/featureFlags.ts +3 -0
  35. package/src/client/hooks/useAutoScroll.ts +328 -0
  36. package/src/client/tabsSearchParameters.ts +1 -17
  37. package/src/client/useFileCRUD.ts +5 -2
  38. package/src/client/useKeyboardShortcuts.ts +7 -0
  39. package/src/client/useOpenDirectories.ts +2 -1
  40. package/src/client/usePrettier/index.ts +1 -1
  41. package/src/client/useURLSync.ts +1 -0
  42. package/src/client/utils/scrollUtils.ts +170 -0
  43. package/src/client/vzReducer/searchReducer.ts +6 -3
  44. package/src/server/aiChatHandler/chatOperations.ts +224 -43
  45. package/src/server/aiChatHandler/index.ts +8 -48
  46. package/src/server/aiChatHandler/llmStreaming.ts +149 -170
  47. package/src/types.ts +81 -1
  48. package/dist/assets/buildWorker-Bi6wsfQk.js +0 -695
  49. package/dist/assets/index-BpUpNto4.js +0 -461
  50. package/dist/assets/worker-BSzbM0Uo.js +0 -330
  51. package/src/client/VZSidebar/AIChat/StreamingMessage.tsx +0 -35
@@ -1,10 +1,4 @@
1
- import {
2
- memo,
3
- useRef,
4
- useEffect,
5
- useCallback,
6
- useState,
7
- } from 'react';
1
+ import { memo } from 'react';
8
2
  import Markdown from 'react-markdown';
9
3
  import remarkGfm from 'remark-gfm';
10
4
 
@@ -17,115 +11,6 @@ const ThinkingScratchpadComponent = ({
17
11
  content,
18
12
  isVisible,
19
13
  }: ThinkingScratchpadProps) => {
20
- const contentRef = useRef<HTMLDivElement>(null);
21
- const [isUserScrolled, setIsUserScrolled] =
22
- useState(false);
23
- const [autoScrollEnabled, setAutoScrollEnabled] =
24
- useState(true);
25
- const scrollTimeoutRef =
26
- useRef<ReturnType<typeof setTimeout>>();
27
-
28
- // Check if the user is scrolled to the bottom
29
- const isScrolledToBottom = useCallback(() => {
30
- const container = contentRef.current;
31
- if (!container) return true;
32
-
33
- const threshold = 10; // Allow 10px tolerance for "at bottom"
34
- const { scrollTop, scrollHeight, clientHeight } =
35
- container;
36
- return (
37
- scrollHeight - scrollTop - clientHeight < threshold
38
- );
39
- }, []);
40
-
41
- // Smooth scroll to bottom
42
- const scrollToBottom = useCallback(() => {
43
- if (!autoScrollEnabled) return;
44
-
45
- const container = contentRef.current;
46
- if (container) {
47
- container.scrollTo({
48
- top: container.scrollHeight,
49
- behavior: 'smooth',
50
- });
51
- }
52
- }, [autoScrollEnabled]);
53
-
54
- // Handle scroll events to detect user manual scrolling
55
- const handleScroll = useCallback(() => {
56
- const container = contentRef.current;
57
- if (!container) return;
58
-
59
- const isAtBottom = isScrolledToBottom();
60
-
61
- // Clear any existing timeout
62
- if (scrollTimeoutRef.current) {
63
- clearTimeout(scrollTimeoutRef.current);
64
- }
65
-
66
- // If user scrolled up from bottom, disable auto-scroll
67
- if (!isAtBottom && !isUserScrolled) {
68
- setIsUserScrolled(true);
69
- setAutoScrollEnabled(false);
70
- }
71
-
72
- // If user scrolled back to bottom, re-enable auto-scroll after a brief delay
73
- if (isAtBottom && isUserScrolled) {
74
- scrollTimeoutRef.current = setTimeout(() => {
75
- setIsUserScrolled(false);
76
- setAutoScrollEnabled(true);
77
- }, 300); // 300ms delay to prevent flickering
78
- }
79
- }, [isUserScrolled, isScrolledToBottom]);
80
-
81
- // Auto-scroll when content changes, but only if auto-scroll is enabled
82
- useEffect(() => {
83
- if (
84
- autoScrollEnabled &&
85
- !isUserScrolled &&
86
- isVisible &&
87
- content
88
- ) {
89
- // Use a short debounce to prevent multiple scroll calls during rapid updates
90
- if (scrollTimeoutRef.current) {
91
- clearTimeout(scrollTimeoutRef.current);
92
- }
93
-
94
- scrollTimeoutRef.current = setTimeout(() => {
95
- scrollToBottom();
96
- }, 50); // 50ms debounce
97
- }
98
-
99
- return () => {
100
- if (scrollTimeoutRef.current) {
101
- clearTimeout(scrollTimeoutRef.current);
102
- }
103
- };
104
- }, [
105
- content,
106
- autoScrollEnabled,
107
- isUserScrolled,
108
- isVisible,
109
- scrollToBottom,
110
- ]);
111
-
112
- // Clean up timeout on unmount
113
- useEffect(() => {
114
- return () => {
115
- if (scrollTimeoutRef.current) {
116
- clearTimeout(scrollTimeoutRef.current);
117
- }
118
- };
119
- }, []);
120
-
121
- // Reset scroll state when component becomes visible
122
- useEffect(() => {
123
- if (isVisible) {
124
- setIsUserScrolled(false);
125
- setAutoScrollEnabled(true);
126
- }
127
- }, [isVisible]);
128
-
129
14
  if (!isVisible || !content) {
130
15
  return null;
131
16
  }
@@ -140,8 +25,9 @@ const ThinkingScratchpadComponent = ({
140
25
  </div>
141
26
  <div
142
27
  className="thinking-scratchpad-content"
143
- ref={contentRef}
144
- onScroll={handleScroll}
28
+ role="log"
29
+ aria-live="polite"
30
+ aria-relevant="additions"
145
31
  >
146
32
  <Markdown remarkPlugins={[remarkGfm]}>
147
33
  {content}
@@ -7,6 +7,9 @@ import {
7
7
  import { VZCodeContext } from '../../VZCodeContext';
8
8
  import { MessageList } from './MessageList';
9
9
  import { ChatInput } from './ChatInput';
10
+ import { ExtendedVizChat } from '../../../types.js';
11
+ import { useAutoScroll } from '../../hooks/useAutoScroll';
12
+ import { JumpToLatestButton } from './JumpToLatestButton';
10
13
  import './styles.scss';
11
14
 
12
15
  const DEBUG = false;
@@ -50,13 +53,11 @@ export const AIChat = () => {
50
53
  content,
51
54
  aiChatMode,
52
55
  aiChatMessage,
53
- isLoading,
54
56
  currentChatId,
55
57
  selectedChatId,
56
58
  setSelectedChatId,
57
59
  aiErrorMessage,
58
60
  setAIChatMode,
59
- clearStoredAIPrompt,
60
61
  getStoredAIPrompt,
61
62
  setAIChatMessage,
62
63
  handleSendMessage,
@@ -64,17 +65,42 @@ export const AIChat = () => {
64
65
  navigateMessageHistoryUp,
65
66
  navigateMessageHistoryDown,
66
67
  resetMessageHistoryNavigation,
68
+ enableMinimalEditFlow,
67
69
  } = useContext(VZCodeContext);
68
70
 
71
+ // Use the new simplified auto-scroll hook
72
+ const {
73
+ containerRef: messagesContainerRef,
74
+ showJumpButton,
75
+ onNewEvent,
76
+ onJumpToLatest,
77
+ beforeRender,
78
+ afterRender,
79
+ } = useAutoScroll({ threshold: 24 });
80
+
69
81
  // Get the active chat ID and chat data
70
82
  // If selectedChatId is set, use it; otherwise, if no chat selected, don't default to currentChatId
71
83
  const activeChatId = selectedChatId;
72
84
  const currentChat = activeChatId
73
85
  ? content?.chats?.[activeChatId]
74
86
  : null;
75
- const rawMessages = currentChat?.messages || [];
87
+ const rawMessages = useMemo(
88
+ () => currentChat?.messages || [],
89
+ [currentChat?.messages],
90
+ );
76
91
  const aiStatus = currentChat?.aiStatus;
77
92
  const aiScratchpad = currentChat?.aiScratchpad;
93
+ const currentStatus = (currentChat as ExtendedVizChat)
94
+ ?.currentStatus;
95
+
96
+ // Debug logging for AI status
97
+ DEBUG && console.log('AIChat: currentChat:', currentChat);
98
+ DEBUG && console.log('AIChat: aiStatus:', aiStatus);
99
+ DEBUG &&
100
+ console.log(
101
+ 'AIChat: enableMinimalEditFlow:',
102
+ enableMinimalEditFlow,
103
+ );
78
104
 
79
105
  // Transform messages to ensure they have required id field - memoized to avoid recreation
80
106
  const messages = useMemo(
@@ -166,7 +192,10 @@ export const AIChat = () => {
166
192
  return (
167
193
  <div className="ai-chat-container">
168
194
  <div className="ai-chat-content">
169
- <div className="ai-chat-messages-container">
195
+ <div
196
+ className="ai-chat-messages-container"
197
+ ref={messagesContainerRef}
198
+ >
170
199
  {isEmptyState ? (
171
200
  <div className="ai-chat-empty">
172
201
  <div className="ai-chat-empty-icon">✨</div>
@@ -198,7 +227,7 @@ export const AIChat = () => {
198
227
  )
199
228
  }
200
229
  >
201
- "Explain how this works"
230
+ &quot;Explain how this works&quot;
202
231
  </button>
203
232
  <button
204
233
  className="ai-chat-suggested-prompt"
@@ -208,8 +237,8 @@ export const AIChat = () => {
208
237
  )
209
238
  }
210
239
  >
211
- "How could I change it so that the
212
- circles are bigger?"
240
+ &quot;How could I change it so
241
+ that the circles are bigger?&quot;
213
242
  </button>
214
243
  <button
215
244
  className="ai-chat-suggested-prompt"
@@ -219,7 +248,8 @@ export const AIChat = () => {
219
248
  )
220
249
  }
221
250
  >
222
- "What does this function do?"
251
+ &quot;What does this function
252
+ do?&quot;
223
253
  </button>
224
254
  <button
225
255
  className="ai-chat-suggested-prompt"
@@ -229,8 +259,8 @@ export const AIChat = () => {
229
259
  )
230
260
  }
231
261
  >
232
- "How can I make this more
233
- accessible?"
262
+ &quot;How can I make this more
263
+ accessible?&quot;
234
264
  </button>
235
265
  </div>
236
266
  </>
@@ -246,7 +276,8 @@ export const AIChat = () => {
246
276
  )
247
277
  }
248
278
  >
249
- "Change the circles to squares"
279
+ &quot;Change the circles to
280
+ squares&quot;
250
281
  </button>
251
282
  <button
252
283
  className="ai-chat-suggested-prompt"
@@ -256,8 +287,8 @@ export const AIChat = () => {
256
287
  )
257
288
  }
258
289
  >
259
- "Add a button that toggles the
260
- animation"
290
+ &quot;Add a button that toggles
291
+ the animation&quot;
261
292
  </button>
262
293
  <button
263
294
  className="ai-chat-suggested-prompt"
@@ -267,8 +298,8 @@ export const AIChat = () => {
267
298
  )
268
299
  }
269
300
  >
270
- "Fix the CSS so the layout is
271
- responsive"
301
+ &quot;Fix the CSS so the layout is
302
+ responsive&quot;
272
303
  </button>
273
304
  <button
274
305
  className="ai-chat-suggested-prompt"
@@ -278,8 +309,8 @@ export const AIChat = () => {
278
309
  )
279
310
  }
280
311
  >
281
- "Refactor this function to use
282
- async/await"
312
+ &quot;Refactor this function to
313
+ use async/await&quot;
283
314
  </button>
284
315
  </div>
285
316
  </>
@@ -297,9 +328,14 @@ export const AIChat = () => {
297
328
  ) : (
298
329
  <MessageList
299
330
  messages={messages}
300
- isLoading={isLoading}
331
+ isLoading={false}
301
332
  chatId={selectedChatId || currentChatId}
302
333
  aiScratchpad={aiScratchpad}
334
+ currentStatus={currentStatus}
335
+ onNewEvent={onNewEvent}
336
+ onJumpToLatest={onJumpToLatest}
337
+ beforeRender={beforeRender}
338
+ afterRender={afterRender}
303
339
  />
304
340
  )}
305
341
  {aiErrorMessage && (
@@ -321,6 +357,11 @@ export const AIChat = () => {
321
357
  </div>
322
358
  </div>
323
359
  )}
360
+ {/* Jump to Latest Button */}
361
+ <JumpToLatestButton
362
+ visible={showJumpButton}
363
+ onClick={onJumpToLatest}
364
+ />
324
365
  </div>
325
366
  </div>
326
367
  <div className="ai-chat-input-fixed">
@@ -328,7 +369,6 @@ export const AIChat = () => {
328
369
  aiChatMessage={aiChatMessage}
329
370
  setAIChatMessage={setAIChatMessage}
330
371
  onSendMessage={handleSendMessageWithSelection}
331
- isLoading={isLoading}
332
372
  focused={aiChatFocused}
333
373
  aiChatMode={aiChatMode}
334
374
  setAIChatMode={setAIChatMode}
@@ -10,6 +10,7 @@
10
10
  overflow: hidden;
11
11
  display: flex;
12
12
  flex-direction: column;
13
+ position: relative;
13
14
  }
14
15
 
15
16
  .ai-chat-messages-container {
@@ -19,6 +20,21 @@
19
20
  padding-bottom: 0;
20
21
  display: flex;
21
22
  flex-direction: column;
23
+ scroll-behavior: smooth;
24
+
25
+ &::-webkit-scrollbar {
26
+ width: 6px;
27
+ }
28
+
29
+ &::-webkit-scrollbar-track {
30
+ background: var(--vh-color-neutral-02);
31
+ border-radius: 3px;
32
+ }
33
+
34
+ &::-webkit-scrollbar-thumb {
35
+ background: var(--vh-color-neutral-04);
36
+ border-radius: 3px;
37
+ }
22
38
  }
23
39
 
24
40
  .ai-chat-input-fixed {
@@ -111,6 +127,125 @@
111
127
  }
112
128
  }
113
129
 
130
+ // ============================================================================
131
+ // Streaming Message Components
132
+ // ============================================================================
133
+
134
+ .streaming-message {
135
+ .text-chunk {
136
+ margin-bottom: 1rem;
137
+ }
138
+ }
139
+
140
+ .file-editing-indicator {
141
+ display: flex;
142
+ align-items: center;
143
+ margin: 0.25rem 0;
144
+ background-color: var(--vscode-editor-background);
145
+ border: 1px solid var(--vscode-panel-border);
146
+ border-radius: 4px;
147
+
148
+ .file-editing-header {
149
+ display: flex;
150
+ align-items: center;
151
+ gap: 0.5rem;
152
+ width: 100%;
153
+ }
154
+
155
+ .file-editing-icon {
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: center;
159
+ }
160
+
161
+ .file-editing-text {
162
+ color: var(--vscode-foreground);
163
+ font-size: 0.9rem;
164
+ flex: 1;
165
+
166
+ code {
167
+ background-color: var(
168
+ --vscode-textCodeBlock-background
169
+ );
170
+ padding: 0.2rem 0.4rem;
171
+ border-radius: 3px;
172
+ font-family: var(--vscode-editor-font-family);
173
+ }
174
+
175
+ .file-editing-done-container {
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: space-between;
179
+ width: 100%;
180
+ gap: 0.5rem;
181
+ }
182
+
183
+ .file-editing-done-status {
184
+ display: flex;
185
+ align-items: center;
186
+ gap: 8px;
187
+ font-size: 16px;
188
+ font-weight: 500;
189
+ margin-left: 4px;
190
+ }
191
+
192
+ .file-editing-done-widgets {
193
+ display: flex;
194
+ align-items: center;
195
+ gap: 0.5rem;
196
+ flex-shrink: 0;
197
+
198
+ // // Override the margin-top for undo-button-container when inside file editing indicator
199
+ // .undo-button-container {
200
+ // margin-top: 0;
201
+ // margin-bottom: 0;
202
+ // }
203
+ }
204
+ }
205
+ }
206
+
207
+ .status-indicator {
208
+ display: flex;
209
+ align-items: center;
210
+ padding: 0.5rem;
211
+ margin: 0.5rem 0;
212
+ background-color: var(--vscode-notifications-background);
213
+ border-left: 3px solid
214
+ var(--vscode-progressBar-foreground);
215
+ border-radius: 0 4px 4px 0;
216
+
217
+ .status-content {
218
+ display: flex;
219
+ align-items: center;
220
+ gap: 0.5rem;
221
+ }
222
+
223
+ .status-icon {
224
+ display: flex;
225
+ align-items: center;
226
+ justify-content: center;
227
+
228
+ .done-icon {
229
+ font-size: 1rem;
230
+ }
231
+ }
232
+
233
+ .status-text {
234
+ color: var(--vscode-foreground);
235
+ font-size: 0.9rem;
236
+ font-weight: 500;
237
+ }
238
+ }
239
+
240
+ @keyframes spin {
241
+ 0% {
242
+ transform: rotate(0deg);
243
+ }
244
+ 100% {
245
+ transform: rotate(360deg);
246
+ }
247
+ }
248
+
114
249
  .ai-chat-list {
115
250
  margin-top: 20px;
116
251
 
@@ -126,24 +261,8 @@
126
261
 
127
262
  .ai-chat-messages {
128
263
  flex: 1;
129
- overflow-y: auto;
130
264
  margin-bottom: 10px;
131
265
  padding-right: 5px;
132
- scroll-behavior: smooth;
133
-
134
- &::-webkit-scrollbar {
135
- width: 6px;
136
- }
137
-
138
- &::-webkit-scrollbar-track {
139
- background: var(--vh-color-neutral-02);
140
- border-radius: 3px;
141
- }
142
-
143
- &::-webkit-scrollbar-thumb {
144
- background: var(--vh-color-neutral-04);
145
- border-radius: 3px;
146
- }
147
266
  }
148
267
 
149
268
  .ai-chat-message {
@@ -200,33 +319,6 @@
200
319
  line-height: 1.4;
201
320
  word-wrap: break-word;
202
321
 
203
- .undo-button-container {
204
- display: flex;
205
- justify-content: flex-end;
206
- gap: 8px;
207
- margin-top: 16px;
208
- }
209
-
210
- .undo-button {
211
- background-color: #dc3545;
212
- color: white;
213
- border: none;
214
- border-radius: 4px;
215
- padding: 4px 8px;
216
- font-size: 12px;
217
- cursor: pointer;
218
- transition: background-color 0.2s;
219
-
220
- &:hover:not(:disabled) {
221
- background-color: #c82333;
222
- }
223
-
224
- &:disabled {
225
- background-color: #6c757d;
226
- cursor: not-allowed;
227
- }
228
- }
229
-
230
322
  // Markdown styling for dark backgrounds
231
323
  pre {
232
324
  background-color: rgba(0, 0, 0, 0.3);
@@ -549,6 +641,61 @@
549
641
  }
550
642
  }
551
643
 
644
+ // Jump to latest button styles
645
+ .jump-to-latest-button {
646
+ position: absolute;
647
+ left: 50%;
648
+ transform: translateX(-50%);
649
+ bottom: 20px; // Position above the input area
650
+ width: 44px;
651
+ height: 44px;
652
+ border-radius: 50%;
653
+ background: var(--vh-color-primary-01);
654
+ border: none;
655
+ color: white;
656
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
657
+ cursor: pointer;
658
+ display: flex;
659
+ align-items: center;
660
+ justify-content: center;
661
+ z-index: 10;
662
+ transition: all 0.2s ease;
663
+
664
+ &:hover {
665
+ background: var(--vh-color-primary-02);
666
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
667
+ transform: translateX(-50%) scale(1.05);
668
+ }
669
+
670
+ &:focus {
671
+ outline: 2px solid var(--vh-color-primary-01);
672
+ outline-offset: 2px;
673
+ }
674
+
675
+ &:active {
676
+ transform: translateX(-50%) scale(0.95);
677
+ }
678
+
679
+ .jump-to-latest-icon {
680
+ font-size: 16px;
681
+ font-weight: bold;
682
+ line-height: 1;
683
+ }
684
+
685
+ // Respect prefers-reduced-motion
686
+ @media (prefers-reduced-motion: reduce) {
687
+ transition: none;
688
+
689
+ &:hover {
690
+ transform: translateX(-50%);
691
+ }
692
+
693
+ &:active {
694
+ transform: translateX(-50%);
695
+ }
696
+ }
697
+ }
698
+
552
699
  // Thinking scratchpad styles
553
700
  .thinking-scratchpad {
554
701
  background: var(--vh-color-neutral-02);
@@ -140,11 +140,11 @@ export const Item = ({
140
140
 
141
141
  const handleMouseEnter = useCallback(() => {
142
142
  setIsHovered(true);
143
- }, []);
143
+ }, [setIsHovered]);
144
144
 
145
145
  const handleMouseLeave = useCallback(() => {
146
146
  setIsHovered(false);
147
- }, []);
147
+ }, [setIsHovered]);
148
148
 
149
149
  const onChange = useCallback(() => {
150
150
  setRenameValue(renameInputRef.current.value);
@@ -98,7 +98,7 @@ export const Search = () => {
98
98
  } else {
99
99
  setIsMounted(true);
100
100
  }
101
- }, [pattern]);
101
+ }, [pattern, isMounted, setSearchResults, shareDBDoc]);
102
102
 
103
103
  const flattenResult = useCallback(
104
104
  (fileId: string, file: SearchFile) => {
@@ -111,19 +111,26 @@ export const Search = () => {
111
111
  : 'open',
112
112
  );
113
113
  },
114
- [focusedIndex, focusedChildIndex],
114
+ [
115
+ setSearchFileVisibility,
116
+ shareDBDoc,
117
+ focusedChildIndex,
118
+ ],
115
119
  );
116
120
 
117
- const closeResult = useCallback((fileId: VizFileId) => {
118
- setSearchFileVisibility(shareDBDoc, fileId, 'closed');
119
- }, []);
121
+ const closeResult = useCallback(
122
+ (fileId: VizFileId) => {
123
+ setSearchFileVisibility(shareDBDoc, fileId, 'closed');
124
+ },
125
+ [setSearchFileVisibility, shareDBDoc],
126
+ );
120
127
 
121
128
  const focusFileElement = useCallback(
122
129
  (fileId: VizFileId, index: number) => {
123
130
  setActiveFileId(fileId);
124
131
  setSearchFocusedIndex(index, null);
125
132
  },
126
- [],
133
+ [setActiveFileId, setSearchFocusedIndex],
127
134
  );
128
135
 
129
136
  const handleKeyDown = (event) => {