giggles 0.3.4 → 0.3.5
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/ui/index.d.ts +14 -12
- package/dist/ui/index.js +150 -132
- package/package.json +1 -1
package/dist/ui/index.d.ts
CHANGED
|
@@ -3,6 +3,17 @@ import React__default from 'react';
|
|
|
3
3
|
import { R as RegisteredKeybinding } from '../types-Dmw9TKt4.js';
|
|
4
4
|
import 'ink';
|
|
5
5
|
|
|
6
|
+
type PaginatorStyle = 'arrows' | 'scrollbar' | 'counter';
|
|
7
|
+
type PaginatorProps = {
|
|
8
|
+
total: number;
|
|
9
|
+
offset: number;
|
|
10
|
+
visible: number;
|
|
11
|
+
style?: PaginatorStyle;
|
|
12
|
+
position?: 'above' | 'below';
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
declare function Paginator({ total, offset, visible, style, position }: PaginatorProps): react_jsx_runtime.JSX.Element | null;
|
|
16
|
+
|
|
6
17
|
type CommandPaletteRenderProps = {
|
|
7
18
|
query: string;
|
|
8
19
|
filtered: RegisteredKeybinding[];
|
|
@@ -11,9 +22,11 @@ type CommandPaletteRenderProps = {
|
|
|
11
22
|
};
|
|
12
23
|
type CommandPaletteProps = {
|
|
13
24
|
onClose: () => void;
|
|
25
|
+
maxVisible?: number;
|
|
26
|
+
paginatorStyle?: PaginatorStyle;
|
|
14
27
|
render?: (props: CommandPaletteRenderProps) => React__default.ReactNode;
|
|
15
28
|
};
|
|
16
|
-
declare function CommandPalette({ onClose, render }: CommandPaletteProps): react_jsx_runtime.JSX.Element;
|
|
29
|
+
declare function CommandPalette({ onClose, maxVisible, paginatorStyle, render }: CommandPaletteProps): react_jsx_runtime.JSX.Element;
|
|
17
30
|
|
|
18
31
|
type TextInputRenderProps = {
|
|
19
32
|
value: string;
|
|
@@ -32,17 +45,6 @@ type TextInputProps = {
|
|
|
32
45
|
};
|
|
33
46
|
declare function TextInput({ label, value, onChange, onSubmit, placeholder, render }: TextInputProps): react_jsx_runtime.JSX.Element;
|
|
34
47
|
|
|
35
|
-
type PaginatorStyle = 'arrows' | 'scrollbar' | 'counter';
|
|
36
|
-
type PaginatorProps = {
|
|
37
|
-
total: number;
|
|
38
|
-
offset: number;
|
|
39
|
-
visible: number;
|
|
40
|
-
style?: PaginatorStyle;
|
|
41
|
-
position?: 'above' | 'below';
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
declare function Paginator({ total, offset, visible, style, position }: PaginatorProps): react_jsx_runtime.JSX.Element | null;
|
|
45
|
-
|
|
46
48
|
type SelectOption<T> = {
|
|
47
49
|
label: string;
|
|
48
50
|
value: T;
|
package/dist/ui/index.js
CHANGED
|
@@ -7,9 +7,104 @@ import {
|
|
|
7
7
|
} from "../chunk-OYQZHF73.js";
|
|
8
8
|
|
|
9
9
|
// src/ui/CommandPalette.tsx
|
|
10
|
-
import { useState } from "react";
|
|
10
|
+
import { useState as useState2 } from "react";
|
|
11
|
+
import { Box as Box3, Text as Text2 } from "ink";
|
|
12
|
+
|
|
13
|
+
// src/ui/VirtualList.tsx
|
|
14
|
+
import React, { useState } from "react";
|
|
15
|
+
import { Box as Box2 } from "ink";
|
|
16
|
+
|
|
17
|
+
// src/ui/Paginator.tsx
|
|
11
18
|
import { Box, Text } from "ink";
|
|
12
|
-
import {
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
function Paginator({ total, offset, visible, style = "arrows", position }) {
|
|
21
|
+
if (total <= visible) return null;
|
|
22
|
+
const hasAbove = offset > 0;
|
|
23
|
+
const hasBelow = offset + visible < total;
|
|
24
|
+
if (style === "arrows") {
|
|
25
|
+
if (position === "above" && hasAbove) return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191" });
|
|
26
|
+
if (position === "below" && hasBelow) return /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2193" });
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
if (style === "counter") {
|
|
30
|
+
if (position === "above") return null;
|
|
31
|
+
return /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
32
|
+
offset + 1,
|
|
33
|
+
"\u2013",
|
|
34
|
+
Math.min(offset + visible, total),
|
|
35
|
+
" of ",
|
|
36
|
+
total
|
|
37
|
+
] });
|
|
38
|
+
}
|
|
39
|
+
const thumbSize = Math.max(1, Math.round(visible / total * visible));
|
|
40
|
+
const maxThumbOffset = visible - thumbSize;
|
|
41
|
+
const maxScrollOffset = total - visible;
|
|
42
|
+
const thumbOffset = maxScrollOffset === 0 ? 0 : Math.round(offset / maxScrollOffset * maxThumbOffset);
|
|
43
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: Array.from({ length: visible }, (_, i) => {
|
|
44
|
+
const isThumb = i >= thumbOffset && i < thumbOffset + thumbSize;
|
|
45
|
+
return /* @__PURE__ */ jsx(Text, { dimColor: !isThumb, children: isThumb ? "\u2588" : "\u2502" }, i);
|
|
46
|
+
}) });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/ui/VirtualList.tsx
|
|
50
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
51
|
+
function VirtualList({
|
|
52
|
+
items,
|
|
53
|
+
highlightIndex,
|
|
54
|
+
scrollOffset: controlledOffset,
|
|
55
|
+
maxVisible,
|
|
56
|
+
paginatorStyle = "arrows",
|
|
57
|
+
render
|
|
58
|
+
}) {
|
|
59
|
+
const [internalOffset, setInternalOffset] = useState(0);
|
|
60
|
+
if (maxVisible == null || items.length <= maxVisible) {
|
|
61
|
+
return /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: items.map((item, index) => /* @__PURE__ */ jsx2(React.Fragment, { children: render({ item, index }) }, index)) });
|
|
62
|
+
}
|
|
63
|
+
const maxOffset = Math.max(0, items.length - maxVisible);
|
|
64
|
+
let offset;
|
|
65
|
+
if (controlledOffset != null) {
|
|
66
|
+
offset = Math.min(controlledOffset, maxOffset);
|
|
67
|
+
} else {
|
|
68
|
+
offset = Math.min(internalOffset, maxOffset);
|
|
69
|
+
if (highlightIndex != null && highlightIndex >= 0) {
|
|
70
|
+
if (highlightIndex < offset) {
|
|
71
|
+
offset = highlightIndex;
|
|
72
|
+
} else if (highlightIndex >= offset + maxVisible) {
|
|
73
|
+
offset = highlightIndex - maxVisible + 1;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (offset !== internalOffset) {
|
|
77
|
+
setInternalOffset(offset);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const visible = items.slice(offset, offset + maxVisible);
|
|
81
|
+
const paginatorProps = {
|
|
82
|
+
total: items.length,
|
|
83
|
+
offset,
|
|
84
|
+
visible: maxVisible,
|
|
85
|
+
style: paginatorStyle
|
|
86
|
+
};
|
|
87
|
+
if (paginatorStyle === "scrollbar") {
|
|
88
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", gap: 1, children: [
|
|
89
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: visible.map((item, i) => {
|
|
90
|
+
const index = offset + i;
|
|
91
|
+
return /* @__PURE__ */ jsx2(React.Fragment, { children: render({ item, index }) }, index);
|
|
92
|
+
}) }),
|
|
93
|
+
/* @__PURE__ */ jsx2(Paginator, { ...paginatorProps })
|
|
94
|
+
] });
|
|
95
|
+
}
|
|
96
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
97
|
+
/* @__PURE__ */ jsx2(Paginator, { ...paginatorProps, position: "above" }),
|
|
98
|
+
visible.map((item, i) => {
|
|
99
|
+
const index = offset + i;
|
|
100
|
+
return /* @__PURE__ */ jsx2(React.Fragment, { children: render({ item, index }) }, index);
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ jsx2(Paginator, { ...paginatorProps, position: "below" })
|
|
103
|
+
] });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/ui/CommandPalette.tsx
|
|
107
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
13
108
|
var EMPTY_KEY = {
|
|
14
109
|
upArrow: false,
|
|
15
110
|
downArrow: false,
|
|
@@ -42,10 +137,10 @@ function fuzzyMatch(name, query) {
|
|
|
42
137
|
}
|
|
43
138
|
return qi === lowerQuery.length;
|
|
44
139
|
}
|
|
45
|
-
function Inner({ onClose, render }) {
|
|
140
|
+
function Inner({ onClose, maxVisible, paginatorStyle, render }) {
|
|
46
141
|
const focus = useFocus();
|
|
47
|
-
const [query, setQuery] =
|
|
48
|
-
const [selectedIndex, setSelectedIndex] =
|
|
142
|
+
const [query, setQuery] = useState2("");
|
|
143
|
+
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
49
144
|
const registry = useKeybindingRegistry();
|
|
50
145
|
const filtered = registry.all.filter((cmd) => fuzzyMatch(cmd.name, query));
|
|
51
146
|
const clampedIndex = Math.min(selectedIndex, Math.max(0, filtered.length - 1));
|
|
@@ -79,28 +174,37 @@ function Inner({ onClose, render }) {
|
|
|
79
174
|
}
|
|
80
175
|
);
|
|
81
176
|
if (render) {
|
|
82
|
-
return /* @__PURE__ */
|
|
177
|
+
return /* @__PURE__ */ jsx3(Fragment, { children: render({ query, filtered, selectedIndex: clampedIndex, onSelect }) });
|
|
83
178
|
}
|
|
84
|
-
return /* @__PURE__ */
|
|
85
|
-
/* @__PURE__ */
|
|
86
|
-
/* @__PURE__ */
|
|
87
|
-
/* @__PURE__ */
|
|
88
|
-
/* @__PURE__ */
|
|
179
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "round", width: 40, children: [
|
|
180
|
+
/* @__PURE__ */ jsxs3(Box3, { paddingX: 1, children: [
|
|
181
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: "> " }),
|
|
182
|
+
/* @__PURE__ */ jsx3(Text2, { children: query }),
|
|
183
|
+
/* @__PURE__ */ jsx3(Text2, { inverse: true, children: " " })
|
|
89
184
|
] }),
|
|
90
|
-
/* @__PURE__ */
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
185
|
+
/* @__PURE__ */ jsx3(Box3, { flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsx3(Box3, { paddingX: 1, children: /* @__PURE__ */ jsx3(Text2, { dimColor: true, children: "No commands found" }) }) : /* @__PURE__ */ jsx3(
|
|
186
|
+
VirtualList,
|
|
187
|
+
{
|
|
188
|
+
items: filtered,
|
|
189
|
+
highlightIndex: clampedIndex,
|
|
190
|
+
maxVisible,
|
|
191
|
+
paginatorStyle,
|
|
192
|
+
render: ({ item: cmd, index }) => /* @__PURE__ */ jsxs3(Box3, { justifyContent: "space-between", paddingX: 1, children: [
|
|
193
|
+
/* @__PURE__ */ jsx3(Text2, { inverse: index === clampedIndex, children: cmd.name }),
|
|
194
|
+
/* @__PURE__ */ jsx3(Text2, { dimColor: true, children: cmd.key })
|
|
195
|
+
] }, `${cmd.nodeId}-${cmd.key}`)
|
|
196
|
+
}
|
|
197
|
+
) })
|
|
94
198
|
] });
|
|
95
199
|
}
|
|
96
|
-
function CommandPalette({ onClose, render }) {
|
|
97
|
-
return /* @__PURE__ */
|
|
200
|
+
function CommandPalette({ onClose, maxVisible, paginatorStyle, render }) {
|
|
201
|
+
return /* @__PURE__ */ jsx3(FocusTrap, { children: /* @__PURE__ */ jsx3(Inner, { onClose, maxVisible, paginatorStyle, render }) });
|
|
98
202
|
}
|
|
99
203
|
|
|
100
204
|
// src/ui/TextInput.tsx
|
|
101
205
|
import { useReducer, useRef } from "react";
|
|
102
|
-
import { Text as
|
|
103
|
-
import { Fragment as Fragment2, jsx as
|
|
206
|
+
import { Text as Text3 } from "ink";
|
|
207
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
104
208
|
function TextInput({ label, value, onChange, onSubmit, placeholder, render }) {
|
|
105
209
|
const focus = useFocus();
|
|
106
210
|
const cursorRef = useRef(value.length);
|
|
@@ -157,123 +261,28 @@ function TextInput({ label, value, onChange, onSubmit, placeholder, render }) {
|
|
|
157
261
|
const cursorChar = value[cursor] ?? " ";
|
|
158
262
|
const after = value.slice(cursor + 1);
|
|
159
263
|
if (render) {
|
|
160
|
-
return /* @__PURE__ */
|
|
264
|
+
return /* @__PURE__ */ jsx4(Fragment2, { children: render({ value, focused: focus.focused, before, cursorChar, after }) });
|
|
161
265
|
}
|
|
162
266
|
const displayValue = value.length > 0 ? value : placeholder ?? "";
|
|
163
267
|
const isPlaceholder = value.length === 0;
|
|
164
268
|
const prefix = label != null ? `${label} ` : "";
|
|
165
269
|
if (focus.focused) {
|
|
166
|
-
return /* @__PURE__ */
|
|
270
|
+
return /* @__PURE__ */ jsxs4(Text3, { children: [
|
|
167
271
|
prefix,
|
|
168
272
|
before,
|
|
169
|
-
/* @__PURE__ */
|
|
273
|
+
/* @__PURE__ */ jsx4(Text3, { inverse: true, children: cursorChar }),
|
|
170
274
|
after
|
|
171
275
|
] });
|
|
172
276
|
}
|
|
173
|
-
return /* @__PURE__ */
|
|
277
|
+
return /* @__PURE__ */ jsxs4(Text3, { children: [
|
|
174
278
|
prefix,
|
|
175
|
-
/* @__PURE__ */
|
|
279
|
+
/* @__PURE__ */ jsx4(Text3, { dimColor: isPlaceholder, children: displayValue })
|
|
176
280
|
] });
|
|
177
281
|
}
|
|
178
282
|
|
|
179
283
|
// src/ui/Select.tsx
|
|
180
|
-
import React4, { useState as useState3 } from "react";
|
|
284
|
+
import React4, { useEffect, useState as useState3 } from "react";
|
|
181
285
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
182
|
-
|
|
183
|
-
// src/ui/VirtualList.tsx
|
|
184
|
-
import React3, { useState as useState2 } from "react";
|
|
185
|
-
import { Box as Box3 } from "ink";
|
|
186
|
-
|
|
187
|
-
// src/ui/Paginator.tsx
|
|
188
|
-
import { Box as Box2, Text as Text3 } from "ink";
|
|
189
|
-
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
190
|
-
function Paginator({ total, offset, visible, style = "arrows", position }) {
|
|
191
|
-
if (total <= visible) return null;
|
|
192
|
-
const hasAbove = offset > 0;
|
|
193
|
-
const hasBelow = offset + visible < total;
|
|
194
|
-
if (style === "arrows") {
|
|
195
|
-
if (position === "above" && hasAbove) return /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2191" });
|
|
196
|
-
if (position === "below" && hasBelow) return /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "\u2193" });
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
if (style === "counter") {
|
|
200
|
-
if (position === "above") return null;
|
|
201
|
-
return /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
|
|
202
|
-
offset + 1,
|
|
203
|
-
"\u2013",
|
|
204
|
-
Math.min(offset + visible, total),
|
|
205
|
-
" of ",
|
|
206
|
-
total
|
|
207
|
-
] });
|
|
208
|
-
}
|
|
209
|
-
const thumbSize = Math.max(1, Math.round(visible / total * visible));
|
|
210
|
-
const maxThumbOffset = visible - thumbSize;
|
|
211
|
-
const maxScrollOffset = total - visible;
|
|
212
|
-
const thumbOffset = maxScrollOffset === 0 ? 0 : Math.round(offset / maxScrollOffset * maxThumbOffset);
|
|
213
|
-
return /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", children: Array.from({ length: visible }, (_, i) => {
|
|
214
|
-
const isThumb = i >= thumbOffset && i < thumbOffset + thumbSize;
|
|
215
|
-
return /* @__PURE__ */ jsx3(Text3, { dimColor: !isThumb, children: isThumb ? "\u2588" : "\u2502" }, i);
|
|
216
|
-
}) });
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// src/ui/VirtualList.tsx
|
|
220
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
221
|
-
function VirtualList({
|
|
222
|
-
items,
|
|
223
|
-
highlightIndex,
|
|
224
|
-
scrollOffset: controlledOffset,
|
|
225
|
-
maxVisible,
|
|
226
|
-
paginatorStyle = "arrows",
|
|
227
|
-
render
|
|
228
|
-
}) {
|
|
229
|
-
const [internalOffset, setInternalOffset] = useState2(0);
|
|
230
|
-
if (maxVisible == null || items.length <= maxVisible) {
|
|
231
|
-
return /* @__PURE__ */ jsx4(Box3, { flexDirection: "column", children: items.map((item, index) => /* @__PURE__ */ jsx4(React3.Fragment, { children: render({ item, index }) }, index)) });
|
|
232
|
-
}
|
|
233
|
-
const maxOffset = Math.max(0, items.length - maxVisible);
|
|
234
|
-
let offset;
|
|
235
|
-
if (controlledOffset != null) {
|
|
236
|
-
offset = Math.min(controlledOffset, maxOffset);
|
|
237
|
-
} else {
|
|
238
|
-
offset = Math.min(internalOffset, maxOffset);
|
|
239
|
-
if (highlightIndex != null && highlightIndex >= 0) {
|
|
240
|
-
if (highlightIndex < offset) {
|
|
241
|
-
offset = highlightIndex;
|
|
242
|
-
} else if (highlightIndex >= offset + maxVisible) {
|
|
243
|
-
offset = highlightIndex - maxVisible + 1;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
if (offset !== internalOffset) {
|
|
247
|
-
setInternalOffset(offset);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
const visible = items.slice(offset, offset + maxVisible);
|
|
251
|
-
const paginatorProps = {
|
|
252
|
-
total: items.length,
|
|
253
|
-
offset,
|
|
254
|
-
visible: maxVisible,
|
|
255
|
-
style: paginatorStyle
|
|
256
|
-
};
|
|
257
|
-
if (paginatorStyle === "scrollbar") {
|
|
258
|
-
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "row", gap: 1, children: [
|
|
259
|
-
/* @__PURE__ */ jsx4(Box3, { flexDirection: "column", children: visible.map((item, i) => {
|
|
260
|
-
const index = offset + i;
|
|
261
|
-
return /* @__PURE__ */ jsx4(React3.Fragment, { children: render({ item, index }) }, index);
|
|
262
|
-
}) }),
|
|
263
|
-
/* @__PURE__ */ jsx4(Paginator, { ...paginatorProps })
|
|
264
|
-
] });
|
|
265
|
-
}
|
|
266
|
-
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", children: [
|
|
267
|
-
/* @__PURE__ */ jsx4(Paginator, { ...paginatorProps, position: "above" }),
|
|
268
|
-
visible.map((item, i) => {
|
|
269
|
-
const index = offset + i;
|
|
270
|
-
return /* @__PURE__ */ jsx4(React3.Fragment, { children: render({ item, index }) }, index);
|
|
271
|
-
}),
|
|
272
|
-
/* @__PURE__ */ jsx4(Paginator, { ...paginatorProps, position: "below" })
|
|
273
|
-
] });
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// src/ui/Select.tsx
|
|
277
286
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
278
287
|
function Select({
|
|
279
288
|
options,
|
|
@@ -300,9 +309,11 @@ function Select({
|
|
|
300
309
|
const focus = useFocus();
|
|
301
310
|
const [highlightIndex, setHighlightIndex] = useState3(0);
|
|
302
311
|
const safeIndex = options.length === 0 ? -1 : Math.min(highlightIndex, options.length - 1);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
312
|
+
useEffect(() => {
|
|
313
|
+
if (safeIndex !== highlightIndex) {
|
|
314
|
+
setHighlightIndex(Math.max(0, safeIndex));
|
|
315
|
+
}
|
|
316
|
+
}, [safeIndex, highlightIndex]);
|
|
306
317
|
const moveHighlight = (delta) => {
|
|
307
318
|
if (options.length === 0) return;
|
|
308
319
|
const next2 = wrap ? (safeIndex + delta + options.length) % options.length : Math.max(0, Math.min(options.length - 1, safeIndex + delta));
|
|
@@ -358,7 +369,7 @@ function Select({
|
|
|
358
369
|
}
|
|
359
370
|
|
|
360
371
|
// src/ui/MultiSelect.tsx
|
|
361
|
-
import React5, { useState as useState4 } from "react";
|
|
372
|
+
import React5, { useEffect as useEffect2, useState as useState4 } from "react";
|
|
362
373
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
363
374
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
364
375
|
function MultiSelect({
|
|
@@ -385,9 +396,11 @@ function MultiSelect({
|
|
|
385
396
|
const focus = useFocus();
|
|
386
397
|
const [highlightIndex, setHighlightIndex] = useState4(0);
|
|
387
398
|
const safeIndex = options.length === 0 ? -1 : Math.min(highlightIndex, options.length - 1);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
399
|
+
useEffect2(() => {
|
|
400
|
+
if (safeIndex !== highlightIndex) {
|
|
401
|
+
setHighlightIndex(Math.max(0, safeIndex));
|
|
402
|
+
}
|
|
403
|
+
}, [safeIndex, highlightIndex]);
|
|
391
404
|
const moveHighlight = (delta) => {
|
|
392
405
|
if (options.length === 0) return;
|
|
393
406
|
const next2 = wrap ? (safeIndex + delta + options.length) % options.length : Math.max(0, Math.min(options.length - 1, safeIndex + delta));
|
|
@@ -460,7 +473,7 @@ function Confirm({ message, defaultValue = true, onSubmit }) {
|
|
|
460
473
|
}
|
|
461
474
|
|
|
462
475
|
// src/ui/Autocomplete.tsx
|
|
463
|
-
import { useReducer as useReducer2, useRef as useRef2, useState as useState5 } from "react";
|
|
476
|
+
import { useEffect as useEffect3, useMemo, useReducer as useReducer2, useRef as useRef2, useState as useState5 } from "react";
|
|
464
477
|
import { Box as Box6, Text as Text7 } from "ink";
|
|
465
478
|
import { jsx as jsx7, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
466
479
|
function defaultFilter(query, option) {
|
|
@@ -497,11 +510,16 @@ function Autocomplete({
|
|
|
497
510
|
const [highlightIndex, setHighlightIndex] = useState5(0);
|
|
498
511
|
const cursorRef = useRef2(0);
|
|
499
512
|
const [, forceRender] = useReducer2((c) => c + 1, 0);
|
|
500
|
-
const filtered =
|
|
513
|
+
const filtered = useMemo(
|
|
514
|
+
() => query.length === 0 ? options : options.filter((opt) => filter(query, opt)),
|
|
515
|
+
[options, query, filter]
|
|
516
|
+
);
|
|
501
517
|
const safeIndex = filtered.length === 0 ? -1 : Math.min(highlightIndex, filtered.length - 1);
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
518
|
+
useEffect3(() => {
|
|
519
|
+
if (safeIndex >= 0 && safeIndex !== highlightIndex) {
|
|
520
|
+
setHighlightIndex(safeIndex);
|
|
521
|
+
}
|
|
522
|
+
}, [safeIndex, highlightIndex]);
|
|
505
523
|
const cursor = Math.min(cursorRef.current, query.length);
|
|
506
524
|
cursorRef.current = cursor;
|
|
507
525
|
const moveHighlight = (delta) => {
|