giggles 0.3.5 → 0.3.6
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/{chunk-OYQZHF73.js → chunk-FEQYHTG7.js} +27 -1
- package/dist/index.d.ts +21 -2
- package/dist/index.js +9 -5
- package/dist/ui/index.d.ts +27 -22
- package/dist/ui/index.js +229 -170
- package/package.json +1 -1
|
@@ -452,6 +452,30 @@ function FocusTrap({ children }) {
|
|
|
452
452
|
return /* @__PURE__ */ jsx5(FocusNodeContext.Provider, { value: id, children });
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
+
// src/core/theme.tsx
|
|
456
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
457
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
458
|
+
var defaultTheme = {
|
|
459
|
+
accentColor: "#6B9FD4",
|
|
460
|
+
selectedColor: "#8FBF7F",
|
|
461
|
+
hintColor: "#8A8A8A",
|
|
462
|
+
hintDimColor: "#5C5C5C",
|
|
463
|
+
hintHighlightColor: "#D4D4D4",
|
|
464
|
+
hintHighlightDimColor: "#A0A0A0",
|
|
465
|
+
indicator: "\u25B8",
|
|
466
|
+
checkedIndicator: "\u2713",
|
|
467
|
+
uncheckedIndicator: "\u25CB"
|
|
468
|
+
};
|
|
469
|
+
var ThemeContext = createContext4(defaultTheme);
|
|
470
|
+
function ThemeProvider({ theme, children }) {
|
|
471
|
+
const parent = useContext4(ThemeContext);
|
|
472
|
+
const merged = { ...parent, ...theme };
|
|
473
|
+
return /* @__PURE__ */ jsx6(ThemeContext.Provider, { value: merged, children });
|
|
474
|
+
}
|
|
475
|
+
function useTheme() {
|
|
476
|
+
return useContext4(ThemeContext);
|
|
477
|
+
}
|
|
478
|
+
|
|
455
479
|
export {
|
|
456
480
|
GigglesError,
|
|
457
481
|
FocusProvider,
|
|
@@ -464,5 +488,7 @@ export {
|
|
|
464
488
|
FocusTrap,
|
|
465
489
|
useFocus,
|
|
466
490
|
FocusGroup,
|
|
467
|
-
useFocusState
|
|
491
|
+
useFocusState,
|
|
492
|
+
ThemeProvider,
|
|
493
|
+
useTheme
|
|
468
494
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -9,10 +9,29 @@ declare class GigglesError extends Error {
|
|
|
9
9
|
constructor(message: string);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
type GigglesTheme = {
|
|
13
|
+
accentColor: string;
|
|
14
|
+
selectedColor: string;
|
|
15
|
+
hintColor: string;
|
|
16
|
+
hintDimColor: string;
|
|
17
|
+
hintHighlightColor: string;
|
|
18
|
+
hintHighlightDimColor: string;
|
|
19
|
+
indicator: string;
|
|
20
|
+
checkedIndicator: string;
|
|
21
|
+
uncheckedIndicator: string;
|
|
22
|
+
};
|
|
23
|
+
type ThemeProviderProps = {
|
|
24
|
+
theme?: Partial<GigglesTheme>;
|
|
25
|
+
children: React__default.ReactNode;
|
|
26
|
+
};
|
|
27
|
+
declare function ThemeProvider({ theme, children }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
|
|
28
|
+
declare function useTheme(): GigglesTheme;
|
|
29
|
+
|
|
12
30
|
type GigglesProviderProps = {
|
|
31
|
+
theme?: Partial<GigglesTheme>;
|
|
13
32
|
children: React__default.ReactNode;
|
|
14
33
|
};
|
|
15
|
-
declare function GigglesProvider({ children }: GigglesProviderProps): react_jsx_runtime.JSX.Element;
|
|
34
|
+
declare function GigglesProvider({ theme, children }: GigglesProviderProps): react_jsx_runtime.JSX.Element;
|
|
16
35
|
|
|
17
36
|
declare function useKeybindings(focus: FocusHandle, bindings: Keybindings, options?: KeybindingOptions): void;
|
|
18
37
|
|
|
@@ -79,4 +98,4 @@ type NavigationContextValue = {
|
|
|
79
98
|
|
|
80
99
|
declare const useNavigation: () => NavigationContextValue;
|
|
81
100
|
|
|
82
|
-
export { FocusGroup, type FocusHandle, FocusTrap, GigglesError, GigglesProvider, KeybindingOptions, type KeybindingRegistry, Keybindings, type NavigationContextValue, RegisteredKeybinding, Router, Screen, useFocus, useFocusState, useKeybindingRegistry, useKeybindings, useNavigation };
|
|
101
|
+
export { FocusGroup, type FocusHandle, FocusTrap, GigglesError, GigglesProvider, type GigglesTheme, KeybindingOptions, type KeybindingRegistry, Keybindings, type NavigationContextValue, RegisteredKeybinding, Router, Screen, ThemeProvider, useFocus, useFocusState, useKeybindingRegistry, useKeybindings, useNavigation, useTheme };
|
package/dist/index.js
CHANGED
|
@@ -9,17 +9,19 @@ import {
|
|
|
9
9
|
GigglesError,
|
|
10
10
|
InputProvider,
|
|
11
11
|
InputRouter,
|
|
12
|
+
ThemeProvider,
|
|
12
13
|
useFocus,
|
|
13
14
|
useFocusContext,
|
|
14
15
|
useFocusState,
|
|
15
16
|
useKeybindingRegistry,
|
|
16
|
-
useKeybindings
|
|
17
|
-
|
|
17
|
+
useKeybindings,
|
|
18
|
+
useTheme
|
|
19
|
+
} from "./chunk-FEQYHTG7.js";
|
|
18
20
|
|
|
19
21
|
// src/core/GigglesProvider.tsx
|
|
20
22
|
import { jsx } from "react/jsx-runtime";
|
|
21
|
-
function GigglesProvider({ children }) {
|
|
22
|
-
return /* @__PURE__ */ jsx(AlternateScreen, { children: /* @__PURE__ */ jsx(FocusProvider, { children: /* @__PURE__ */ jsx(InputProvider, { children: /* @__PURE__ */ jsx(InputRouter, { children }) }) }) });
|
|
23
|
+
function GigglesProvider({ theme, children }) {
|
|
24
|
+
return /* @__PURE__ */ jsx(AlternateScreen, { children: /* @__PURE__ */ jsx(ThemeProvider, { theme, children: /* @__PURE__ */ jsx(FocusProvider, { children: /* @__PURE__ */ jsx(InputProvider, { children: /* @__PURE__ */ jsx(InputRouter, { children }) }) }) }) });
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
// src/core/router/Router.tsx
|
|
@@ -181,9 +183,11 @@ export {
|
|
|
181
183
|
GigglesProvider,
|
|
182
184
|
Router,
|
|
183
185
|
Screen,
|
|
186
|
+
ThemeProvider,
|
|
184
187
|
useFocus,
|
|
185
188
|
useFocusState,
|
|
186
189
|
useKeybindingRegistry,
|
|
187
190
|
useKeybindings,
|
|
188
|
-
useNavigation
|
|
191
|
+
useNavigation,
|
|
192
|
+
useTheme
|
|
189
193
|
};
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import React__default from 'react';
|
|
3
2
|
import { R as RegisteredKeybinding } from '../types-Dmw9TKt4.js';
|
|
3
|
+
import React__default from 'react';
|
|
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
|
-
|
|
17
6
|
type CommandPaletteRenderProps = {
|
|
18
7
|
query: string;
|
|
19
8
|
filtered: RegisteredKeybinding[];
|
|
@@ -21,12 +10,11 @@ type CommandPaletteRenderProps = {
|
|
|
21
10
|
onSelect: (cmd: RegisteredKeybinding) => void;
|
|
22
11
|
};
|
|
23
12
|
type CommandPaletteProps = {
|
|
24
|
-
onClose
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
render?: (props: CommandPaletteRenderProps) => React__default.ReactNode;
|
|
13
|
+
onClose?: () => void;
|
|
14
|
+
interactive?: boolean;
|
|
15
|
+
render?: (props: CommandPaletteRenderProps) => React.ReactNode;
|
|
28
16
|
};
|
|
29
|
-
declare function CommandPalette({ onClose,
|
|
17
|
+
declare function CommandPalette({ onClose, interactive, render }: CommandPaletteProps): react_jsx_runtime.JSX.Element;
|
|
30
18
|
|
|
31
19
|
type TextInputRenderProps = {
|
|
32
20
|
value: string;
|
|
@@ -45,6 +33,18 @@ type TextInputProps = {
|
|
|
45
33
|
};
|
|
46
34
|
declare function TextInput({ label, value, onChange, onSubmit, placeholder, render }: TextInputProps): react_jsx_runtime.JSX.Element;
|
|
47
35
|
|
|
36
|
+
type PaginatorStyle = 'dots' | 'arrows' | 'scrollbar' | 'counter' | 'none';
|
|
37
|
+
type PaginatorProps = {
|
|
38
|
+
total: number;
|
|
39
|
+
offset: number;
|
|
40
|
+
visible: number;
|
|
41
|
+
gap?: number;
|
|
42
|
+
style?: PaginatorStyle;
|
|
43
|
+
position?: 'above' | 'below';
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
declare function Paginator({ total, offset, visible, gap, style, position }: PaginatorProps): react_jsx_runtime.JSX.Element | null;
|
|
47
|
+
|
|
48
48
|
type SelectOption<T> = {
|
|
49
49
|
label: string;
|
|
50
50
|
value: T;
|
|
@@ -64,12 +64,13 @@ type SelectProps<T> = {
|
|
|
64
64
|
label?: string;
|
|
65
65
|
immediate?: boolean;
|
|
66
66
|
direction?: 'vertical' | 'horizontal';
|
|
67
|
+
gap?: number;
|
|
67
68
|
maxVisible?: number;
|
|
68
69
|
paginatorStyle?: PaginatorStyle;
|
|
69
70
|
wrap?: boolean;
|
|
70
71
|
render?: (props: SelectRenderProps<T>) => React__default.ReactNode;
|
|
71
72
|
};
|
|
72
|
-
declare function Select<T>({ options, value, onChange, onSubmit, onHighlight, label, immediate, direction, maxVisible, paginatorStyle, wrap, render }: SelectProps<T>): react_jsx_runtime.JSX.Element;
|
|
73
|
+
declare function Select<T>({ options, value, onChange, onSubmit, onHighlight, label, immediate, direction, gap, maxVisible, paginatorStyle, wrap, render }: SelectProps<T>): react_jsx_runtime.JSX.Element;
|
|
73
74
|
|
|
74
75
|
type MultiSelectRenderProps<T> = {
|
|
75
76
|
option: SelectOption<T>;
|
|
@@ -85,12 +86,13 @@ type MultiSelectProps<T> = {
|
|
|
85
86
|
onHighlight?: (value: T) => void;
|
|
86
87
|
label?: string;
|
|
87
88
|
direction?: 'vertical' | 'horizontal';
|
|
89
|
+
gap?: number;
|
|
88
90
|
maxVisible?: number;
|
|
89
91
|
paginatorStyle?: PaginatorStyle;
|
|
90
92
|
wrap?: boolean;
|
|
91
93
|
render?: (props: MultiSelectRenderProps<T>) => React__default.ReactNode;
|
|
92
94
|
};
|
|
93
|
-
declare function MultiSelect<T>({ options, value, onChange, onSubmit, onHighlight, label, direction, maxVisible, paginatorStyle, wrap, render }: MultiSelectProps<T>): react_jsx_runtime.JSX.Element;
|
|
95
|
+
declare function MultiSelect<T>({ options, value, onChange, onSubmit, onHighlight, label, direction, gap, maxVisible, paginatorStyle, wrap, render }: MultiSelectProps<T>): react_jsx_runtime.JSX.Element;
|
|
94
96
|
|
|
95
97
|
type ConfirmProps = {
|
|
96
98
|
message: string;
|
|
@@ -114,12 +116,13 @@ type AutocompleteProps<T> = {
|
|
|
114
116
|
label?: string;
|
|
115
117
|
placeholder?: string;
|
|
116
118
|
filter?: (query: string, option: SelectOption<T>) => boolean;
|
|
119
|
+
gap?: number;
|
|
117
120
|
maxVisible?: number;
|
|
118
121
|
paginatorStyle?: PaginatorStyle;
|
|
119
122
|
wrap?: boolean;
|
|
120
123
|
render?: (props: AutocompleteRenderProps<T>) => React__default.ReactNode;
|
|
121
124
|
};
|
|
122
|
-
declare function Autocomplete<T>({ options, value, onChange, onSubmit, onHighlight, label, placeholder, filter, maxVisible, paginatorStyle, wrap, render }: AutocompleteProps<T>): react_jsx_runtime.JSX.Element;
|
|
125
|
+
declare function Autocomplete<T>({ options, value, onChange, onSubmit, onHighlight, label, placeholder, filter, gap, maxVisible, paginatorStyle, wrap, render }: AutocompleteProps<T>): react_jsx_runtime.JSX.Element;
|
|
123
126
|
|
|
124
127
|
type VirtualListRenderProps<T> = {
|
|
125
128
|
item: T;
|
|
@@ -127,6 +130,7 @@ type VirtualListRenderProps<T> = {
|
|
|
127
130
|
};
|
|
128
131
|
type VirtualListBase<T> = {
|
|
129
132
|
items: T[];
|
|
133
|
+
gap?: number;
|
|
130
134
|
maxVisible?: number;
|
|
131
135
|
paginatorStyle?: PaginatorStyle;
|
|
132
136
|
render: (props: VirtualListRenderProps<T>) => React__default.ReactNode;
|
|
@@ -138,7 +142,7 @@ type VirtualListProps<T> = VirtualListBase<T> & ({
|
|
|
138
142
|
highlightIndex?: never;
|
|
139
143
|
scrollOffset?: number;
|
|
140
144
|
});
|
|
141
|
-
declare function VirtualList<T>({ items, highlightIndex, scrollOffset: controlledOffset, maxVisible, paginatorStyle, render }: VirtualListProps<T>): react_jsx_runtime.JSX.Element;
|
|
145
|
+
declare function VirtualList<T>({ items, highlightIndex, scrollOffset: controlledOffset, gap, maxVisible, paginatorStyle, render }: VirtualListProps<T>): react_jsx_runtime.JSX.Element;
|
|
142
146
|
|
|
143
147
|
type ViewportRenderProps<T> = {
|
|
144
148
|
item: T;
|
|
@@ -149,9 +153,10 @@ type ViewportProps<T> = {
|
|
|
149
153
|
items: T[];
|
|
150
154
|
maxVisible: number;
|
|
151
155
|
showLineNumbers?: boolean;
|
|
156
|
+
gap?: number;
|
|
152
157
|
paginatorStyle?: PaginatorStyle;
|
|
153
158
|
render?: (props: ViewportRenderProps<T>) => React__default.ReactNode;
|
|
154
159
|
};
|
|
155
|
-
declare function Viewport<T>({ items, maxVisible, showLineNumbers, paginatorStyle, render }: ViewportProps<T>): react_jsx_runtime.JSX.Element;
|
|
160
|
+
declare function Viewport<T>({ items, maxVisible, showLineNumbers, gap, paginatorStyle, render }: ViewportProps<T>): react_jsx_runtime.JSX.Element;
|
|
156
161
|
|
|
157
162
|
export { Autocomplete, type AutocompleteRenderProps, CommandPalette, type CommandPaletteRenderProps, Confirm, MultiSelect, type MultiSelectRenderProps, Paginator, type PaginatorStyle, Select, type SelectOption, type SelectRenderProps, TextInput, type TextInputRenderProps, Viewport, type ViewportRenderProps, VirtualList, type VirtualListRenderProps };
|
package/dist/ui/index.js
CHANGED
|
@@ -3,108 +3,14 @@ import {
|
|
|
3
3
|
GigglesError,
|
|
4
4
|
useFocus,
|
|
5
5
|
useKeybindingRegistry,
|
|
6
|
-
useKeybindings
|
|
7
|
-
|
|
6
|
+
useKeybindings,
|
|
7
|
+
useTheme
|
|
8
|
+
} from "../chunk-FEQYHTG7.js";
|
|
8
9
|
|
|
9
10
|
// src/ui/CommandPalette.tsx
|
|
10
|
-
import { useState
|
|
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
|
+
import { useState } from "react";
|
|
18
12
|
import { Box, Text } from "ink";
|
|
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
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
108
14
|
var EMPTY_KEY = {
|
|
109
15
|
upArrow: false,
|
|
110
16
|
downArrow: false,
|
|
@@ -137,12 +43,14 @@ function fuzzyMatch(name, query) {
|
|
|
137
43
|
}
|
|
138
44
|
return qi === lowerQuery.length;
|
|
139
45
|
}
|
|
140
|
-
function Inner({ onClose,
|
|
46
|
+
function Inner({ onClose, render }) {
|
|
141
47
|
const focus = useFocus();
|
|
142
|
-
const
|
|
143
|
-
const [
|
|
48
|
+
const theme = useTheme();
|
|
49
|
+
const [query, setQuery] = useState("");
|
|
50
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
144
51
|
const registry = useKeybindingRegistry();
|
|
145
|
-
const
|
|
52
|
+
const named = registry.all.filter((cmd) => cmd.name != null);
|
|
53
|
+
const filtered = named.filter((cmd) => fuzzyMatch(cmd.name, query));
|
|
146
54
|
const clampedIndex = Math.min(selectedIndex, Math.max(0, filtered.length - 1));
|
|
147
55
|
const onSelect = (cmd) => {
|
|
148
56
|
cmd.handler("", EMPTY_KEY);
|
|
@@ -156,8 +64,8 @@ function Inner({ onClose, maxVisible, paginatorStyle, render }) {
|
|
|
156
64
|
const cmd = filtered[clampedIndex];
|
|
157
65
|
if (cmd) onSelect(cmd);
|
|
158
66
|
},
|
|
159
|
-
|
|
160
|
-
|
|
67
|
+
left: () => setSelectedIndex((i) => (i - 1 + filtered.length) % filtered.length),
|
|
68
|
+
right: () => setSelectedIndex((i) => (i + 1) % filtered.length),
|
|
161
69
|
backspace: () => {
|
|
162
70
|
setQuery((q) => q.slice(0, -1));
|
|
163
71
|
setSelectedIndex(0);
|
|
@@ -174,37 +82,56 @@ function Inner({ onClose, maxVisible, paginatorStyle, render }) {
|
|
|
174
82
|
}
|
|
175
83
|
);
|
|
176
84
|
if (render) {
|
|
177
|
-
return /* @__PURE__ */
|
|
85
|
+
return /* @__PURE__ */ jsx(Fragment, { children: render({ query, filtered, selectedIndex: clampedIndex, onSelect }) });
|
|
178
86
|
}
|
|
179
|
-
return /* @__PURE__ */
|
|
180
|
-
/* @__PURE__ */
|
|
181
|
-
/* @__PURE__ */
|
|
182
|
-
/* @__PURE__ */
|
|
183
|
-
/* @__PURE__ */
|
|
87
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
88
|
+
query.length > 0 && /* @__PURE__ */ jsxs(Text, { children: [
|
|
89
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "> " }),
|
|
90
|
+
/* @__PURE__ */ jsx(Text, { children: query }),
|
|
91
|
+
/* @__PURE__ */ jsx(Text, { inverse: true, children: " " })
|
|
184
92
|
] }),
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
197
|
-
) })
|
|
93
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "No commands found" }) : /* @__PURE__ */ jsx(Box, { flexWrap: "wrap", children: filtered.map((cmd, index) => {
|
|
94
|
+
const highlighted = index === clampedIndex;
|
|
95
|
+
const keyColor = highlighted ? theme.hintHighlightColor : theme.hintColor;
|
|
96
|
+
const labelColor = highlighted ? theme.hintHighlightDimColor : theme.hintDimColor;
|
|
97
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
98
|
+
/* @__PURE__ */ jsx(Text, { color: keyColor, bold: true, children: cmd.key }),
|
|
99
|
+
/* @__PURE__ */ jsxs(Text, { color: labelColor, children: [
|
|
100
|
+
" ",
|
|
101
|
+
cmd.name
|
|
102
|
+
] }),
|
|
103
|
+
index < filtered.length - 1 && /* @__PURE__ */ jsx(Text, { color: theme.hintDimColor, children: " \u2022 " })
|
|
104
|
+
] }, `${cmd.nodeId}-${cmd.key}`);
|
|
105
|
+
}) })
|
|
198
106
|
] });
|
|
199
107
|
}
|
|
200
|
-
function
|
|
201
|
-
|
|
108
|
+
function HintsBar() {
|
|
109
|
+
const registry = useKeybindingRegistry();
|
|
110
|
+
const theme = useTheme();
|
|
111
|
+
const commands = registry.available.filter((cmd) => cmd.name != null);
|
|
112
|
+
if (commands.length === 0) return null;
|
|
113
|
+
return /* @__PURE__ */ jsx(Box, { flexWrap: "wrap", children: commands.map((cmd, index) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
114
|
+
/* @__PURE__ */ jsx(Text, { color: theme.hintColor, bold: true, children: cmd.key }),
|
|
115
|
+
/* @__PURE__ */ jsxs(Text, { color: theme.hintDimColor, children: [
|
|
116
|
+
" ",
|
|
117
|
+
cmd.name
|
|
118
|
+
] }),
|
|
119
|
+
index < commands.length - 1 && /* @__PURE__ */ jsx(Text, { color: theme.hintDimColor, children: " \u2022 " })
|
|
120
|
+
] }, `${cmd.nodeId}-${cmd.key}`)) });
|
|
121
|
+
}
|
|
122
|
+
var noop = () => {
|
|
123
|
+
};
|
|
124
|
+
function CommandPalette({ onClose, interactive = true, render }) {
|
|
125
|
+
if (!interactive) {
|
|
126
|
+
return /* @__PURE__ */ jsx(HintsBar, {});
|
|
127
|
+
}
|
|
128
|
+
return /* @__PURE__ */ jsx(FocusTrap, { children: /* @__PURE__ */ jsx(Inner, { onClose: onClose ?? noop, render }) });
|
|
202
129
|
}
|
|
203
130
|
|
|
204
131
|
// src/ui/TextInput.tsx
|
|
205
132
|
import { useReducer, useRef } from "react";
|
|
206
|
-
import { Text as
|
|
207
|
-
import { Fragment as Fragment2, jsx as
|
|
133
|
+
import { Text as Text2 } from "ink";
|
|
134
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
208
135
|
function TextInput({ label, value, onChange, onSubmit, placeholder, render }) {
|
|
209
136
|
const focus = useFocus();
|
|
210
137
|
const cursorRef = useRef(value.length);
|
|
@@ -261,28 +188,149 @@ function TextInput({ label, value, onChange, onSubmit, placeholder, render }) {
|
|
|
261
188
|
const cursorChar = value[cursor] ?? " ";
|
|
262
189
|
const after = value.slice(cursor + 1);
|
|
263
190
|
if (render) {
|
|
264
|
-
return /* @__PURE__ */
|
|
191
|
+
return /* @__PURE__ */ jsx2(Fragment2, { children: render({ value, focused: focus.focused, before, cursorChar, after }) });
|
|
265
192
|
}
|
|
266
193
|
const displayValue = value.length > 0 ? value : placeholder ?? "";
|
|
267
194
|
const isPlaceholder = value.length === 0;
|
|
268
|
-
const prefix = label != null ? `${label} ` : "";
|
|
269
195
|
if (focus.focused) {
|
|
270
|
-
return /* @__PURE__ */
|
|
271
|
-
|
|
196
|
+
return /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
197
|
+
label != null && /* @__PURE__ */ jsxs2(Text2, { bold: true, children: [
|
|
198
|
+
label,
|
|
199
|
+
" "
|
|
200
|
+
] }),
|
|
272
201
|
before,
|
|
273
|
-
/* @__PURE__ */
|
|
202
|
+
/* @__PURE__ */ jsx2(Text2, { inverse: true, children: cursorChar }),
|
|
274
203
|
after
|
|
275
204
|
] });
|
|
276
205
|
}
|
|
277
|
-
return /* @__PURE__ */
|
|
278
|
-
|
|
279
|
-
|
|
206
|
+
return /* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
207
|
+
label != null && /* @__PURE__ */ jsxs2(Text2, { children: [
|
|
208
|
+
label,
|
|
209
|
+
" "
|
|
210
|
+
] }),
|
|
211
|
+
isPlaceholder ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: displayValue }) : displayValue
|
|
280
212
|
] });
|
|
281
213
|
}
|
|
282
214
|
|
|
283
215
|
// src/ui/Select.tsx
|
|
284
|
-
import
|
|
216
|
+
import React3, { useEffect as useEffect2, useState as useState3 } from "react";
|
|
285
217
|
import { Box as Box4, Text as Text4 } from "ink";
|
|
218
|
+
|
|
219
|
+
// src/ui/VirtualList.tsx
|
|
220
|
+
import React2, { useEffect, useRef as useRef2, useState as useState2 } from "react";
|
|
221
|
+
import { Box as Box3 } from "ink";
|
|
222
|
+
|
|
223
|
+
// src/ui/Paginator.tsx
|
|
224
|
+
import { Box as Box2, Text as Text3 } from "ink";
|
|
225
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
226
|
+
function Paginator({ total, offset, visible, gap = 0, style = "arrows", position }) {
|
|
227
|
+
const theme = useTheme();
|
|
228
|
+
if (style === "none" || total <= visible) return null;
|
|
229
|
+
const hasAbove = offset > 0;
|
|
230
|
+
const hasBelow = offset + visible < total;
|
|
231
|
+
if (style === "arrows") {
|
|
232
|
+
if (position === "above" && hasAbove) return /* @__PURE__ */ jsx3(Text3, { color: theme.accentColor, children: "\u2191" });
|
|
233
|
+
if (position === "below" && hasBelow) return /* @__PURE__ */ jsx3(Text3, { color: theme.accentColor, children: "\u2193" });
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
if (style === "dots") {
|
|
237
|
+
if (position === "above") return null;
|
|
238
|
+
const totalPages = Math.ceil(total / visible);
|
|
239
|
+
const maxOffset = Math.max(1, total - visible);
|
|
240
|
+
const currentPage = Math.round(offset / maxOffset * (totalPages - 1));
|
|
241
|
+
return /* @__PURE__ */ jsx3(Text3, { children: Array.from({ length: totalPages }, (_, i) => /* @__PURE__ */ jsxs3(Text3, { color: i === currentPage ? theme.accentColor : void 0, dimColor: i !== currentPage, children: [
|
|
242
|
+
i === currentPage ? "\u25CF" : "\u25CB",
|
|
243
|
+
i < totalPages - 1 ? " " : ""
|
|
244
|
+
] }, i)) });
|
|
245
|
+
}
|
|
246
|
+
if (style === "counter") {
|
|
247
|
+
if (position === "above") return null;
|
|
248
|
+
return /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
|
|
249
|
+
offset + 1,
|
|
250
|
+
"\u2013",
|
|
251
|
+
Math.min(offset + visible, total),
|
|
252
|
+
" of ",
|
|
253
|
+
total
|
|
254
|
+
] });
|
|
255
|
+
}
|
|
256
|
+
const totalLines = visible + gap * (visible - 1);
|
|
257
|
+
const thumbSize = Math.max(1, Math.round(visible / total * totalLines));
|
|
258
|
+
const maxThumbOffset = totalLines - thumbSize;
|
|
259
|
+
const maxScrollOffset = total - visible;
|
|
260
|
+
const thumbOffset = maxScrollOffset === 0 ? 0 : Math.round(offset / maxScrollOffset * maxThumbOffset);
|
|
261
|
+
return /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", children: Array.from({ length: totalLines }, (_, i) => {
|
|
262
|
+
const isThumb = i >= thumbOffset && i < thumbOffset + thumbSize;
|
|
263
|
+
return /* @__PURE__ */ jsx3(Text3, { color: isThumb ? theme.accentColor : void 0, dimColor: !isThumb, children: isThumb ? "\u2588" : "\u2502" }, i);
|
|
264
|
+
}) });
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/ui/VirtualList.tsx
|
|
268
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
269
|
+
function VirtualList({
|
|
270
|
+
items,
|
|
271
|
+
highlightIndex,
|
|
272
|
+
scrollOffset: controlledOffset,
|
|
273
|
+
gap = 0,
|
|
274
|
+
maxVisible,
|
|
275
|
+
paginatorStyle = "dots",
|
|
276
|
+
render
|
|
277
|
+
}) {
|
|
278
|
+
const [internalOffset, setInternalOffset] = useState2(0);
|
|
279
|
+
const offsetRef = useRef2(0);
|
|
280
|
+
const windowed = maxVisible != null && items.length > maxVisible;
|
|
281
|
+
let offset = 0;
|
|
282
|
+
if (windowed) {
|
|
283
|
+
const maxOffset = Math.max(0, items.length - maxVisible);
|
|
284
|
+
if (controlledOffset != null) {
|
|
285
|
+
offset = Math.min(controlledOffset, maxOffset);
|
|
286
|
+
} else {
|
|
287
|
+
offset = Math.min(internalOffset, maxOffset);
|
|
288
|
+
if (highlightIndex != null && highlightIndex >= 0) {
|
|
289
|
+
if (highlightIndex < offset) {
|
|
290
|
+
offset = highlightIndex;
|
|
291
|
+
} else if (highlightIndex >= offset + maxVisible) {
|
|
292
|
+
offset = highlightIndex - maxVisible + 1;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
offsetRef.current = offset;
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
if (windowed && offsetRef.current !== internalOffset) {
|
|
300
|
+
setInternalOffset(offsetRef.current);
|
|
301
|
+
}
|
|
302
|
+
}, [windowed, highlightIndex, controlledOffset, internalOffset]);
|
|
303
|
+
if (!windowed) {
|
|
304
|
+
return /* @__PURE__ */ jsx4(Box3, { flexDirection: "column", gap, children: items.map((item, index) => /* @__PURE__ */ jsx4(React2.Fragment, { children: render({ item, index }) }, index)) });
|
|
305
|
+
}
|
|
306
|
+
const visible = items.slice(offset, offset + maxVisible);
|
|
307
|
+
const paginatorProps = {
|
|
308
|
+
total: items.length,
|
|
309
|
+
offset,
|
|
310
|
+
visible: maxVisible,
|
|
311
|
+
gap,
|
|
312
|
+
style: paginatorStyle
|
|
313
|
+
};
|
|
314
|
+
if (paginatorStyle === "scrollbar") {
|
|
315
|
+
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "row", gap: 1, children: [
|
|
316
|
+
/* @__PURE__ */ jsx4(Box3, { flexDirection: "column", gap, flexGrow: 1, children: visible.map((item, i) => {
|
|
317
|
+
const index = offset + i;
|
|
318
|
+
return /* @__PURE__ */ jsx4(React2.Fragment, { children: render({ item, index }) }, index);
|
|
319
|
+
}) }),
|
|
320
|
+
/* @__PURE__ */ jsx4(Paginator, { ...paginatorProps })
|
|
321
|
+
] });
|
|
322
|
+
}
|
|
323
|
+
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", gap, children: [
|
|
324
|
+
/* @__PURE__ */ jsx4(Paginator, { ...paginatorProps, position: "above" }),
|
|
325
|
+
visible.map((item, i) => {
|
|
326
|
+
const index = offset + i;
|
|
327
|
+
return /* @__PURE__ */ jsx4(React2.Fragment, { children: render({ item, index }) }, index);
|
|
328
|
+
}),
|
|
329
|
+
/* @__PURE__ */ jsx4(Paginator, { ...paginatorProps, position: "below" })
|
|
330
|
+
] });
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// src/ui/Select.tsx
|
|
286
334
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
287
335
|
function Select({
|
|
288
336
|
options,
|
|
@@ -293,6 +341,7 @@ function Select({
|
|
|
293
341
|
label,
|
|
294
342
|
immediate,
|
|
295
343
|
direction = "vertical",
|
|
344
|
+
gap,
|
|
296
345
|
maxVisible,
|
|
297
346
|
paginatorStyle,
|
|
298
347
|
wrap = true,
|
|
@@ -307,9 +356,10 @@ function Select({
|
|
|
307
356
|
seen.add(key);
|
|
308
357
|
}
|
|
309
358
|
const focus = useFocus();
|
|
359
|
+
const theme = useTheme();
|
|
310
360
|
const [highlightIndex, setHighlightIndex] = useState3(0);
|
|
311
361
|
const safeIndex = options.length === 0 ? -1 : Math.min(highlightIndex, options.length - 1);
|
|
312
|
-
|
|
362
|
+
useEffect2(() => {
|
|
313
363
|
if (safeIndex !== highlightIndex) {
|
|
314
364
|
setHighlightIndex(Math.max(0, safeIndex));
|
|
315
365
|
}
|
|
@@ -347,19 +397,17 @@ function Select({
|
|
|
347
397
|
if (render) {
|
|
348
398
|
return render({ option, focused: focus.focused, highlighted, selected });
|
|
349
399
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
" ",
|
|
353
|
-
option.label
|
|
354
|
-
] }, String(option.value));
|
|
400
|
+
const active = highlighted && focus.focused;
|
|
401
|
+
return /* @__PURE__ */ jsx5(Box4, { children: /* @__PURE__ */ jsx5(Text4, { dimColor: !focus.focused && !highlighted, children: /* @__PURE__ */ jsx5(Text4, { color: active ? theme.accentColor : void 0, bold: highlighted, children: option.label }) }) }, String(option.value));
|
|
355
402
|
};
|
|
356
403
|
return /* @__PURE__ */ jsxs5(Box4, { flexDirection: isHorizontal ? "row" : "column", gap: isHorizontal ? 1 : 0, children: [
|
|
357
404
|
label != null && /* @__PURE__ */ jsx5(Text4, { children: label }),
|
|
358
|
-
isHorizontal ? options.map((option, index) => /* @__PURE__ */ jsx5(
|
|
405
|
+
isHorizontal ? options.map((option, index) => /* @__PURE__ */ jsx5(React3.Fragment, { children: renderOption({ item: option, index }) }, String(option.value))) : /* @__PURE__ */ jsx5(
|
|
359
406
|
VirtualList,
|
|
360
407
|
{
|
|
361
408
|
items: options,
|
|
362
409
|
highlightIndex: safeIndex,
|
|
410
|
+
gap,
|
|
363
411
|
maxVisible,
|
|
364
412
|
paginatorStyle,
|
|
365
413
|
render: renderOption
|
|
@@ -369,7 +417,7 @@ function Select({
|
|
|
369
417
|
}
|
|
370
418
|
|
|
371
419
|
// src/ui/MultiSelect.tsx
|
|
372
|
-
import
|
|
420
|
+
import React4, { useEffect as useEffect3, useState as useState4 } from "react";
|
|
373
421
|
import { Box as Box5, Text as Text5 } from "ink";
|
|
374
422
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
375
423
|
function MultiSelect({
|
|
@@ -380,6 +428,7 @@ function MultiSelect({
|
|
|
380
428
|
onHighlight,
|
|
381
429
|
label,
|
|
382
430
|
direction = "vertical",
|
|
431
|
+
gap,
|
|
383
432
|
maxVisible,
|
|
384
433
|
paginatorStyle,
|
|
385
434
|
wrap = true,
|
|
@@ -394,9 +443,10 @@ function MultiSelect({
|
|
|
394
443
|
seen.add(key);
|
|
395
444
|
}
|
|
396
445
|
const focus = useFocus();
|
|
446
|
+
const theme = useTheme();
|
|
397
447
|
const [highlightIndex, setHighlightIndex] = useState4(0);
|
|
398
448
|
const safeIndex = options.length === 0 ? -1 : Math.min(highlightIndex, options.length - 1);
|
|
399
|
-
|
|
449
|
+
useEffect3(() => {
|
|
400
450
|
if (safeIndex !== highlightIndex) {
|
|
401
451
|
setHighlightIndex(Math.max(0, safeIndex));
|
|
402
452
|
}
|
|
@@ -430,21 +480,21 @@ function MultiSelect({
|
|
|
430
480
|
if (render) {
|
|
431
481
|
return render({ option, focused: focus.focused, highlighted, selected });
|
|
432
482
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
] }, String(option.value));
|
|
483
|
+
const active = highlighted && focus.focused;
|
|
484
|
+
return /* @__PURE__ */ jsx6(Box5, { children: /* @__PURE__ */ jsxs6(Text5, { dimColor: !focus.focused && !highlighted, children: [
|
|
485
|
+
/* @__PURE__ */ jsx6(Text5, { color: selected ? theme.selectedColor : void 0, bold: selected, children: selected ? theme.checkedIndicator : theme.uncheckedIndicator }),
|
|
486
|
+
" ",
|
|
487
|
+
/* @__PURE__ */ jsx6(Text5, { color: active ? theme.accentColor : void 0, bold: highlighted, children: option.label })
|
|
488
|
+
] }) }, String(option.value));
|
|
440
489
|
};
|
|
441
490
|
return /* @__PURE__ */ jsxs6(Box5, { flexDirection: isHorizontal ? "row" : "column", gap: isHorizontal ? 1 : 0, children: [
|
|
442
491
|
label != null && /* @__PURE__ */ jsx6(Text5, { children: label }),
|
|
443
|
-
isHorizontal ? options.map((option, index) => /* @__PURE__ */ jsx6(
|
|
492
|
+
isHorizontal ? options.map((option, index) => /* @__PURE__ */ jsx6(React4.Fragment, { children: renderOption({ item: option, index }) }, String(option.value))) : /* @__PURE__ */ jsx6(
|
|
444
493
|
VirtualList,
|
|
445
494
|
{
|
|
446
495
|
items: options,
|
|
447
496
|
highlightIndex: safeIndex,
|
|
497
|
+
gap,
|
|
448
498
|
maxVisible,
|
|
449
499
|
paginatorStyle,
|
|
450
500
|
render: renderOption
|
|
@@ -466,14 +516,17 @@ function Confirm({ message, defaultValue = true, onSubmit }) {
|
|
|
466
516
|
const hint = defaultValue ? "Y/n" : "y/N";
|
|
467
517
|
return /* @__PURE__ */ jsxs7(Text6, { dimColor: !focus.focused, children: [
|
|
468
518
|
message,
|
|
469
|
-
"
|
|
470
|
-
|
|
471
|
-
|
|
519
|
+
" ",
|
|
520
|
+
/* @__PURE__ */ jsxs7(Text6, { dimColor: true, children: [
|
|
521
|
+
"(",
|
|
522
|
+
hint,
|
|
523
|
+
")"
|
|
524
|
+
] })
|
|
472
525
|
] });
|
|
473
526
|
}
|
|
474
527
|
|
|
475
528
|
// src/ui/Autocomplete.tsx
|
|
476
|
-
import { useEffect as
|
|
529
|
+
import { useEffect as useEffect4, useMemo, useReducer as useReducer2, useRef as useRef3, useState as useState5 } from "react";
|
|
477
530
|
import { Box as Box6, Text as Text7 } from "ink";
|
|
478
531
|
import { jsx as jsx7, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
479
532
|
function defaultFilter(query, option) {
|
|
@@ -492,6 +545,7 @@ function Autocomplete({
|
|
|
492
545
|
label,
|
|
493
546
|
placeholder,
|
|
494
547
|
filter = defaultFilter,
|
|
548
|
+
gap,
|
|
495
549
|
maxVisible,
|
|
496
550
|
paginatorStyle,
|
|
497
551
|
wrap = true,
|
|
@@ -506,16 +560,17 @@ function Autocomplete({
|
|
|
506
560
|
seen.add(key);
|
|
507
561
|
}
|
|
508
562
|
const focus = useFocus();
|
|
563
|
+
const theme = useTheme();
|
|
509
564
|
const [query, setQuery] = useState5("");
|
|
510
565
|
const [highlightIndex, setHighlightIndex] = useState5(0);
|
|
511
|
-
const cursorRef =
|
|
566
|
+
const cursorRef = useRef3(0);
|
|
512
567
|
const [, forceRender] = useReducer2((c) => c + 1, 0);
|
|
513
568
|
const filtered = useMemo(
|
|
514
569
|
() => query.length === 0 ? options : options.filter((opt) => filter(query, opt)),
|
|
515
570
|
[options, query, filter]
|
|
516
571
|
);
|
|
517
572
|
const safeIndex = filtered.length === 0 ? -1 : Math.min(highlightIndex, filtered.length - 1);
|
|
518
|
-
|
|
573
|
+
useEffect4(() => {
|
|
519
574
|
if (safeIndex >= 0 && safeIndex !== highlightIndex) {
|
|
520
575
|
setHighlightIndex(safeIndex);
|
|
521
576
|
}
|
|
@@ -590,15 +645,20 @@ function Autocomplete({
|
|
|
590
645
|
const before = query.slice(0, cursor);
|
|
591
646
|
const cursorChar = query[cursor] ?? " ";
|
|
592
647
|
const after = query.slice(cursor + 1);
|
|
593
|
-
|
|
594
|
-
return /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", children: [
|
|
648
|
+
return /* @__PURE__ */ jsxs8(Box6, { flexDirection: "column", gap: 1, children: [
|
|
595
649
|
focus.focused ? /* @__PURE__ */ jsxs8(Text7, { children: [
|
|
596
|
-
|
|
650
|
+
label != null && /* @__PURE__ */ jsxs8(Text7, { bold: true, children: [
|
|
651
|
+
label,
|
|
652
|
+
" "
|
|
653
|
+
] }),
|
|
597
654
|
before,
|
|
598
655
|
/* @__PURE__ */ jsx7(Text7, { inverse: true, children: cursorChar }),
|
|
599
656
|
after
|
|
600
657
|
] }) : /* @__PURE__ */ jsxs8(Text7, { dimColor: true, children: [
|
|
601
|
-
|
|
658
|
+
label != null && /* @__PURE__ */ jsxs8(Text7, { children: [
|
|
659
|
+
label,
|
|
660
|
+
" "
|
|
661
|
+
] }),
|
|
602
662
|
query.length > 0 ? query : placeholder ?? ""
|
|
603
663
|
] }),
|
|
604
664
|
/* @__PURE__ */ jsx7(
|
|
@@ -606,6 +666,7 @@ function Autocomplete({
|
|
|
606
666
|
{
|
|
607
667
|
items: filtered,
|
|
608
668
|
highlightIndex: safeIndex,
|
|
669
|
+
gap,
|
|
609
670
|
maxVisible,
|
|
610
671
|
paginatorStyle,
|
|
611
672
|
render: ({ item: option, index }) => {
|
|
@@ -614,11 +675,8 @@ function Autocomplete({
|
|
|
614
675
|
if (render) {
|
|
615
676
|
return render({ option, focused: focus.focused, highlighted, selected });
|
|
616
677
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
" ",
|
|
620
|
-
option.label
|
|
621
|
-
] });
|
|
678
|
+
const active = highlighted && focus.focused;
|
|
679
|
+
return /* @__PURE__ */ jsx7(Box6, { children: /* @__PURE__ */ jsx7(Text7, { dimColor: !focus.focused && !highlighted, children: /* @__PURE__ */ jsx7(Text7, { color: active ? theme.accentColor : void 0, bold: highlighted, children: option.label }) }) });
|
|
622
680
|
}
|
|
623
681
|
}
|
|
624
682
|
)
|
|
@@ -629,7 +687,7 @@ function Autocomplete({
|
|
|
629
687
|
import { useState as useState6 } from "react";
|
|
630
688
|
import { Text as Text8 } from "ink";
|
|
631
689
|
import { jsx as jsx8, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
632
|
-
function Viewport({ items, maxVisible, showLineNumbers, paginatorStyle, render }) {
|
|
690
|
+
function Viewport({ items, maxVisible, showLineNumbers, gap, paginatorStyle, render }) {
|
|
633
691
|
const focus = useFocus();
|
|
634
692
|
const [scrollOffset, setScrollOffset] = useState6(0);
|
|
635
693
|
const maxOffset = Math.max(0, items.length - maxVisible);
|
|
@@ -652,6 +710,7 @@ function Viewport({ items, maxVisible, showLineNumbers, paginatorStyle, render }
|
|
|
652
710
|
{
|
|
653
711
|
items,
|
|
654
712
|
scrollOffset,
|
|
713
|
+
gap,
|
|
655
714
|
maxVisible,
|
|
656
715
|
paginatorStyle,
|
|
657
716
|
render: ({ item, index }) => {
|