@tooee/themes 0.7.3 → 0.9.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.
- package/dist/context.d.ts +4 -3
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +4 -3
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +19 -64
- package/dist/loader.js.map +1 -1
- package/dist/types.d.ts +56 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +31 -80
- package/dist/types.js.map +1 -1
- package/package.json +2 -4
- package/src/context.tsx +5 -4
- package/src/index.ts +1 -6
- package/src/loader.ts +29 -70
- package/src/types.ts +39 -85
- package/dist/close-button.d.ts +0 -17
- package/dist/close-button.d.ts.map +0 -1
- package/dist/close-button.js +0 -23
- package/dist/close-button.js.map +0 -1
- package/dist/theme-picker.d.ts +0 -14
- package/dist/theme-picker.d.ts.map +0 -1
- package/dist/theme-picker.js +0 -109
- package/dist/theme-picker.js.map +0 -1
- package/src/close-button.tsx +0 -45
- package/src/theme-picker.tsx +0 -189
package/src/theme-picker.tsx
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { useState, useMemo, useCallback } from "react";
|
|
2
|
-
import { useCommand } from "@tooee/commands";
|
|
3
|
-
import { fuzzyMatch } from "@tooee/fuzzy";
|
|
4
|
-
import { useTheme } from "./context.js";
|
|
5
|
-
import { CloseButton } from "./close-button.js";
|
|
6
|
-
|
|
7
|
-
export interface ThemePickerEntry {
|
|
8
|
-
id: string;
|
|
9
|
-
title: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface ThemePickerProps {
|
|
13
|
-
entries: ThemePickerEntry[];
|
|
14
|
-
currentTheme: string;
|
|
15
|
-
onSelect: (name: string) => void;
|
|
16
|
-
onClose: () => void;
|
|
17
|
-
onNavigate: (name: string) => void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const ThemePicker = function ThemePicker({
|
|
21
|
-
entries,
|
|
22
|
-
currentTheme,
|
|
23
|
-
onSelect,
|
|
24
|
-
onClose,
|
|
25
|
-
onNavigate,
|
|
26
|
-
}: ThemePickerProps): React.ReactNode {
|
|
27
|
-
const { theme } = useTheme();
|
|
28
|
-
const [filter, setFilter] = useState("");
|
|
29
|
-
const [activeIndex, setActiveIndex] = useState(() => {
|
|
30
|
-
const idx = entries.findIndex((e) => e.id === currentTheme);
|
|
31
|
-
return Math.max(idx, 0);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const filtered = useMemo(() => {
|
|
35
|
-
if (!filter) {
|
|
36
|
-
return entries;
|
|
37
|
-
}
|
|
38
|
-
const results: { entry: ThemePickerEntry; score: number }[] = [];
|
|
39
|
-
for (const entry of entries) {
|
|
40
|
-
const score = fuzzyMatch(filter, entry.title);
|
|
41
|
-
if (score !== null) {
|
|
42
|
-
results.push({ entry, score });
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
results.sort((a, b) => b.score - a.score);
|
|
46
|
-
return results.map((r) => r.entry);
|
|
47
|
-
}, [entries, filter]);
|
|
48
|
-
|
|
49
|
-
const handleSelect = useCallback(() => {
|
|
50
|
-
const item = filtered[activeIndex];
|
|
51
|
-
if (item !== undefined) {
|
|
52
|
-
onSelect(item.id);
|
|
53
|
-
}
|
|
54
|
-
}, [filtered, activeIndex, onSelect]);
|
|
55
|
-
|
|
56
|
-
const navigateTo = useCallback(
|
|
57
|
-
(index: number) => {
|
|
58
|
-
setActiveIndex(index);
|
|
59
|
-
const item = filtered[index];
|
|
60
|
-
if (item !== undefined) {
|
|
61
|
-
onNavigate(item.id);
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
[filtered, onNavigate],
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const moveUp = useCallback(() => {
|
|
68
|
-
navigateTo(Math.max(0, activeIndex - 1));
|
|
69
|
-
}, [activeIndex, navigateTo]);
|
|
70
|
-
|
|
71
|
-
const moveDown = useCallback(() => {
|
|
72
|
-
navigateTo(Math.min(filtered.length - 1, activeIndex + 1));
|
|
73
|
-
}, [activeIndex, filtered.length, navigateTo]);
|
|
74
|
-
|
|
75
|
-
useCommand({
|
|
76
|
-
handler: onClose,
|
|
77
|
-
hidden: true,
|
|
78
|
-
hotkey: "Escape",
|
|
79
|
-
id: "theme-picker:close",
|
|
80
|
-
modes: ["insert", "cursor"],
|
|
81
|
-
title: "Close theme picker",
|
|
82
|
-
});
|
|
83
|
-
useCommand({
|
|
84
|
-
handler: handleSelect,
|
|
85
|
-
hidden: true,
|
|
86
|
-
hotkey: "Enter",
|
|
87
|
-
id: "theme-picker:select",
|
|
88
|
-
modes: ["insert", "cursor"],
|
|
89
|
-
title: "Select theme",
|
|
90
|
-
});
|
|
91
|
-
useCommand({
|
|
92
|
-
handler: moveUp,
|
|
93
|
-
hidden: true,
|
|
94
|
-
hotkey: "up",
|
|
95
|
-
id: "theme-picker:move-up",
|
|
96
|
-
modes: ["insert", "cursor"],
|
|
97
|
-
title: "Move up",
|
|
98
|
-
});
|
|
99
|
-
useCommand({
|
|
100
|
-
handler: moveDown,
|
|
101
|
-
hidden: true,
|
|
102
|
-
hotkey: "down",
|
|
103
|
-
id: "theme-picker:move-down",
|
|
104
|
-
modes: ["insert", "cursor"],
|
|
105
|
-
title: "Move down",
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<box
|
|
110
|
-
position="absolute"
|
|
111
|
-
left="20%"
|
|
112
|
-
right="20%"
|
|
113
|
-
top={2}
|
|
114
|
-
maxHeight="60%"
|
|
115
|
-
flexDirection="column"
|
|
116
|
-
backgroundColor={theme.backgroundPanel}
|
|
117
|
-
border
|
|
118
|
-
borderColor={theme.border}
|
|
119
|
-
>
|
|
120
|
-
{/* Filter row */}
|
|
121
|
-
<box flexDirection="row" paddingLeft={1} paddingRight={1} height={1}>
|
|
122
|
-
<text content="🎨 " fg={theme.accent} />
|
|
123
|
-
<input
|
|
124
|
-
focused
|
|
125
|
-
placeholder="Filter themes..."
|
|
126
|
-
onSubmit={handleSelect}
|
|
127
|
-
onInput={(value: string) => {
|
|
128
|
-
setFilter(value);
|
|
129
|
-
setActiveIndex(0);
|
|
130
|
-
// Preview first match
|
|
131
|
-
if (value) {
|
|
132
|
-
const results: { entry: ThemePickerEntry; score: number }[] = [];
|
|
133
|
-
for (const entry of entries) {
|
|
134
|
-
const score = fuzzyMatch(value, entry.title);
|
|
135
|
-
if (score !== null) {
|
|
136
|
-
results.push({ entry, score });
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
results.sort((a, b) => b.score - a.score);
|
|
140
|
-
if (results.length > 0) {
|
|
141
|
-
onNavigate(results[0].entry.id);
|
|
142
|
-
}
|
|
143
|
-
} else if (entries.length > 0) {
|
|
144
|
-
onNavigate(entries[0].id);
|
|
145
|
-
}
|
|
146
|
-
}}
|
|
147
|
-
backgroundColor="transparent"
|
|
148
|
-
focusedBackgroundColor="transparent"
|
|
149
|
-
textColor={theme.text}
|
|
150
|
-
placeholderColor={theme.textMuted}
|
|
151
|
-
cursorColor={theme.accent}
|
|
152
|
-
style={{ flexGrow: 1 }}
|
|
153
|
-
/>
|
|
154
|
-
<text content={` ${filtered.length}`} fg={theme.textMuted} />
|
|
155
|
-
<CloseButton onClose={onClose} />
|
|
156
|
-
</box>
|
|
157
|
-
|
|
158
|
-
{/* Separator */}
|
|
159
|
-
<box height={1} width="100%" backgroundColor={theme.border} />
|
|
160
|
-
|
|
161
|
-
{/* Theme list */}
|
|
162
|
-
<scrollbox focused={false} style={{ flexGrow: 1 }}>
|
|
163
|
-
{filtered.map(
|
|
164
|
-
(entry, i): React.ReactNode => (
|
|
165
|
-
<box
|
|
166
|
-
key={entry.id}
|
|
167
|
-
flexDirection="row"
|
|
168
|
-
paddingLeft={1}
|
|
169
|
-
paddingRight={1}
|
|
170
|
-
height={1}
|
|
171
|
-
backgroundColor={i === activeIndex ? theme.backgroundElement : undefined}
|
|
172
|
-
onMouseDown={(event) => {
|
|
173
|
-
// Left-click applies the theme — same code path as Enter.
|
|
174
|
-
if (event.button !== 0) {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
event.preventDefault();
|
|
178
|
-
event.stopPropagation();
|
|
179
|
-
onSelect(entry.id);
|
|
180
|
-
}}
|
|
181
|
-
>
|
|
182
|
-
<text content={entry.title} fg={theme.text} style={{ flexGrow: 1 }} />
|
|
183
|
-
</box>
|
|
184
|
-
),
|
|
185
|
-
)}
|
|
186
|
-
</scrollbox>
|
|
187
|
-
</box>
|
|
188
|
-
);
|
|
189
|
-
};
|