@claude-collective/cli 0.2.0 → 0.8.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/CHANGELOG.md +178 -0
- package/README.md +1 -1
- package/dist/chunk-3HBTELJN.js +114 -0
- package/dist/chunk-3HBTELJN.js.map +1 -0
- package/dist/chunk-3ZCB5K33.js +54 -0
- package/dist/chunk-3ZCB5K33.js.map +1 -0
- package/dist/chunk-66UDJBF6.js +96 -0
- package/dist/chunk-66UDJBF6.js.map +1 -0
- package/dist/chunk-6LS7XO3H.js +31 -0
- package/dist/chunk-6LS7XO3H.js.map +1 -0
- package/dist/chunk-A3J6IAXK.js +57 -0
- package/dist/chunk-A3J6IAXK.js.map +1 -0
- package/dist/chunk-A65SBAAJ.js +69 -0
- package/dist/chunk-A65SBAAJ.js.map +1 -0
- package/dist/chunk-ALEPJ6YN.js +80 -0
- package/dist/chunk-ALEPJ6YN.js.map +1 -0
- package/dist/chunk-C4ZTIYFR.js +84 -0
- package/dist/chunk-C4ZTIYFR.js.map +1 -0
- package/dist/chunk-CIY5UBRB.js +453 -0
- package/dist/chunk-CIY5UBRB.js.map +1 -0
- package/dist/chunk-DHET7RCE.js +50 -0
- package/dist/chunk-DHET7RCE.js.map +1 -0
- package/dist/chunk-DHFFRMF6.js +31 -0
- package/dist/chunk-DHFFRMF6.js.map +1 -0
- package/dist/chunk-DKGL77IY.js +307 -0
- package/dist/chunk-DKGL77IY.js.map +1 -0
- package/dist/chunk-ED73HCW2.js +315 -0
- package/dist/chunk-ED73HCW2.js.map +1 -0
- package/dist/chunk-FNOYEXUE.js +308 -0
- package/dist/chunk-FNOYEXUE.js.map +1 -0
- package/dist/chunk-G2FBJOZG.js +141 -0
- package/dist/chunk-G2FBJOZG.js.map +1 -0
- package/dist/chunk-HNDT5QRB.js +120 -0
- package/dist/chunk-HNDT5QRB.js.map +1 -0
- package/dist/chunk-K7PTOVX4.js +158 -0
- package/dist/chunk-K7PTOVX4.js.map +1 -0
- package/dist/chunk-LQTST4WY.js +91 -0
- package/dist/chunk-LQTST4WY.js.map +1 -0
- package/dist/chunk-LVKRVFYR.js +54 -0
- package/dist/chunk-LVKRVFYR.js.map +1 -0
- package/dist/chunk-M7YCPFIX.js +108 -0
- package/dist/chunk-M7YCPFIX.js.map +1 -0
- package/dist/chunk-MJSFR562.js +57 -0
- package/dist/chunk-MJSFR562.js.map +1 -0
- package/dist/chunk-MMDXNZPF.js +69 -0
- package/dist/chunk-MMDXNZPF.js.map +1 -0
- package/dist/chunk-MYAVQ23U.js +356 -0
- package/dist/chunk-MYAVQ23U.js.map +1 -0
- package/dist/chunk-NGBFJJ7Q.js +124 -0
- package/dist/chunk-NGBFJJ7Q.js.map +1 -0
- package/dist/chunk-OLBOTK3O.js +64 -0
- package/dist/chunk-OLBOTK3O.js.map +1 -0
- package/dist/chunk-PPNTD5LO.js +330 -0
- package/dist/chunk-PPNTD5LO.js.map +1 -0
- package/dist/chunk-Q2LH2DAB.js +392 -0
- package/dist/chunk-Q2LH2DAB.js.map +1 -0
- package/dist/chunk-Q6DR5QUH.js +547 -0
- package/dist/chunk-Q6DR5QUH.js.map +1 -0
- package/dist/chunk-QESUUPOE.js +241 -0
- package/dist/chunk-QESUUPOE.js.map +1 -0
- package/dist/chunk-QGGSLMO3.js +607 -0
- package/dist/chunk-QGGSLMO3.js.map +1 -0
- package/dist/chunk-SEBPPFUW.js +478 -0
- package/dist/chunk-SEBPPFUW.js.map +1 -0
- package/dist/chunk-SYQ7R2JO.js +95 -0
- package/dist/chunk-SYQ7R2JO.js.map +1 -0
- package/dist/chunk-TOPAIL5W.js +22 -0
- package/dist/chunk-TOPAIL5W.js.map +1 -0
- package/dist/chunk-U4VYHKPM.js +110 -0
- package/dist/chunk-U4VYHKPM.js.map +1 -0
- package/dist/chunk-UOWHJ6BE.js +83 -0
- package/dist/chunk-UOWHJ6BE.js.map +1 -0
- package/dist/chunk-XKEG3SCV.js +86 -0
- package/dist/chunk-XKEG3SCV.js.map +1 -0
- package/dist/chunk-XY3XDVMI.js +15599 -0
- package/dist/chunk-XY3XDVMI.js.map +1 -0
- package/dist/chunk-Y3V43XCU.js +76 -0
- package/dist/chunk-Y3V43XCU.js.map +1 -0
- package/dist/chunk-YKXBGCFD.js +129 -0
- package/dist/chunk-YKXBGCFD.js.map +1 -0
- package/dist/cli-v2/defaults/agent-mappings.yaml +185 -0
- package/dist/commands/build/marketplace.js +254 -0
- package/dist/commands/build/marketplace.js.map +1 -0
- package/dist/commands/build/plugins.js +324 -0
- package/dist/commands/build/plugins.js.map +1 -0
- package/dist/commands/build/stack.js +169 -0
- package/dist/commands/build/stack.js.map +1 -0
- package/dist/commands/compile.js +461 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/config/get.js +60 -0
- package/dist/commands/config/get.js.map +1 -0
- package/dist/commands/config/index.js +22 -0
- package/dist/commands/config/index.js.map +1 -0
- package/dist/commands/config/path.js +35 -0
- package/dist/commands/config/path.js.map +1 -0
- package/dist/commands/config/set-project.js +61 -0
- package/dist/commands/config/set-project.js.map +1 -0
- package/dist/commands/config/set.js +60 -0
- package/dist/commands/config/set.js.map +1 -0
- package/dist/commands/config/show.js +13 -0
- package/dist/commands/config/show.js.map +1 -0
- package/dist/commands/config/unset-project.js +57 -0
- package/dist/commands/config/unset-project.js.map +1 -0
- package/dist/commands/config/unset.js +56 -0
- package/dist/commands/config/unset.js.map +1 -0
- package/dist/commands/diff.js +755 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.js +413 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/edit.js +254 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/eject.js +208 -0
- package/dist/commands/eject.js.map +1 -0
- package/dist/commands/info.js +205 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.js +915 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.js +44 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/new/agent.js +230 -0
- package/dist/commands/new/agent.js.map +1 -0
- package/dist/commands/new/skill.js +204 -0
- package/dist/commands/new/skill.js.map +1 -0
- package/dist/commands/outdated.js +242 -0
- package/dist/commands/outdated.js.map +1 -0
- package/dist/commands/search.js +115 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/test-imports.js +92 -0
- package/dist/commands/test-imports.js.map +1 -0
- package/dist/commands/uninstall.js +309 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.js +428 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.js +375 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/version/bump.js +95 -0
- package/dist/commands/version/bump.js.map +1 -0
- package/dist/commands/version/index.js +70 -0
- package/dist/commands/version/index.js.map +1 -0
- package/dist/commands/version/set.js +101 -0
- package/dist/commands/version/set.js.map +1 -0
- package/dist/commands/version/show.js +70 -0
- package/dist/commands/version/show.js.map +1 -0
- package/dist/components/common/confirm.js +9 -0
- package/dist/components/common/confirm.js.map +1 -0
- package/dist/components/common/message.js +24 -0
- package/dist/components/common/message.js.map +1 -0
- package/dist/components/common/spinner.js +14 -0
- package/dist/components/common/spinner.js.map +1 -0
- package/dist/components/wizard/category-grid.js +9 -0
- package/dist/components/wizard/category-grid.js.map +1 -0
- package/dist/components/wizard/category-grid.test.js +728 -0
- package/dist/components/wizard/category-grid.test.js.map +1 -0
- package/dist/components/wizard/section-progress.js +9 -0
- package/dist/components/wizard/section-progress.js.map +1 -0
- package/dist/components/wizard/section-progress.test.js +281 -0
- package/dist/components/wizard/section-progress.test.js.map +1 -0
- package/dist/components/wizard/step-approach.js +11 -0
- package/dist/components/wizard/step-approach.js.map +1 -0
- package/dist/components/wizard/step-build.js +15 -0
- package/dist/components/wizard/step-build.js.map +1 -0
- package/dist/components/wizard/step-build.test.js +729 -0
- package/dist/components/wizard/step-build.test.js.map +1 -0
- package/dist/components/wizard/step-confirm.js +9 -0
- package/dist/components/wizard/step-confirm.js.map +1 -0
- package/dist/components/wizard/step-refine.js +9 -0
- package/dist/components/wizard/step-refine.js.map +1 -0
- package/dist/components/wizard/step-refine.test.js +235 -0
- package/dist/components/wizard/step-refine.test.js.map +1 -0
- package/dist/components/wizard/step-stack-options.js +11 -0
- package/dist/components/wizard/step-stack-options.js.map +1 -0
- package/dist/components/wizard/step-stack.js +11 -0
- package/dist/components/wizard/step-stack.js.map +1 -0
- package/dist/components/wizard/wizard-tabs.js +11 -0
- package/dist/components/wizard/wizard-tabs.js.map +1 -0
- package/dist/components/wizard/wizard.js +20 -0
- package/dist/components/wizard/wizard.js.map +1 -0
- package/dist/hooks/init.js +41 -0
- package/dist/hooks/init.js.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/magic-string.es-RGXYGAW3.js +1316 -0
- package/dist/magic-string.es-RGXYGAW3.js.map +1 -0
- package/dist/stores/wizard-store.js +10 -0
- package/dist/stores/wizard-store.js.map +1 -0
- package/dist/stores/wizard-store.test.js +405 -0
- package/dist/stores/wizard-store.test.js.map +1 -0
- package/package.json +44 -25
- package/dist/cli/index.js +0 -6314
- package/dist/cli/index.js.map +0 -1
|
@@ -0,0 +1,728 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ARROW_DOWN,
|
|
4
|
+
ARROW_LEFT,
|
|
5
|
+
ARROW_RIGHT,
|
|
6
|
+
ARROW_UP,
|
|
7
|
+
INPUT_DELAY_MS,
|
|
8
|
+
RENDER_DELAY_MS,
|
|
9
|
+
TAB,
|
|
10
|
+
delay
|
|
11
|
+
} from "../../chunk-6LS7XO3H.js";
|
|
12
|
+
import {
|
|
13
|
+
render
|
|
14
|
+
} from "../../chunk-66UDJBF6.js";
|
|
15
|
+
import {
|
|
16
|
+
afterEach,
|
|
17
|
+
describe,
|
|
18
|
+
globalExpect,
|
|
19
|
+
it,
|
|
20
|
+
vi
|
|
21
|
+
} from "../../chunk-XY3XDVMI.js";
|
|
22
|
+
import {
|
|
23
|
+
CategoryGrid
|
|
24
|
+
} from "../../chunk-PPNTD5LO.js";
|
|
25
|
+
import {
|
|
26
|
+
init_esm_shims
|
|
27
|
+
} from "../../chunk-DHET7RCE.js";
|
|
28
|
+
|
|
29
|
+
// src/cli-v2/components/wizard/category-grid.test.tsx
|
|
30
|
+
init_esm_shims();
|
|
31
|
+
import { jsx } from "react/jsx-runtime";
|
|
32
|
+
var createOption = (id, label, overrides = {}) => ({
|
|
33
|
+
id,
|
|
34
|
+
label,
|
|
35
|
+
state: "normal",
|
|
36
|
+
selected: false,
|
|
37
|
+
...overrides
|
|
38
|
+
});
|
|
39
|
+
var createCategory = (id, name, options, overrides = {}) => ({
|
|
40
|
+
id,
|
|
41
|
+
name,
|
|
42
|
+
required: false,
|
|
43
|
+
exclusive: true,
|
|
44
|
+
options,
|
|
45
|
+
...overrides
|
|
46
|
+
});
|
|
47
|
+
var defaultCategories = [
|
|
48
|
+
createCategory(
|
|
49
|
+
"framework",
|
|
50
|
+
"Framework",
|
|
51
|
+
[
|
|
52
|
+
createOption("react", "react", {
|
|
53
|
+
state: "recommended",
|
|
54
|
+
stateReason: "Popular choice"
|
|
55
|
+
}),
|
|
56
|
+
createOption("vue", "vue"),
|
|
57
|
+
createOption("angular", "angular"),
|
|
58
|
+
createOption("svelte", "svelte")
|
|
59
|
+
],
|
|
60
|
+
{ required: true }
|
|
61
|
+
),
|
|
62
|
+
createCategory(
|
|
63
|
+
"styling",
|
|
64
|
+
"Styling",
|
|
65
|
+
[
|
|
66
|
+
createOption("scss-mod", "scss-mod", { selected: true }),
|
|
67
|
+
createOption("tailwind", "tailwind", { state: "recommended" }),
|
|
68
|
+
createOption("styled", "styled"),
|
|
69
|
+
createOption("vanilla", "vanilla")
|
|
70
|
+
],
|
|
71
|
+
{ required: true }
|
|
72
|
+
),
|
|
73
|
+
createCategory("client-state", "Client State", [
|
|
74
|
+
createOption("zustand", "zustand", { state: "recommended" }),
|
|
75
|
+
createOption("jotai", "jotai"),
|
|
76
|
+
createOption("redux", "redux", {
|
|
77
|
+
state: "discouraged",
|
|
78
|
+
stateReason: "Complex for most apps"
|
|
79
|
+
}),
|
|
80
|
+
createOption("mobx", "mobx")
|
|
81
|
+
]),
|
|
82
|
+
createCategory("server-state", "Server State", [
|
|
83
|
+
createOption("react-query", "react-query", { selected: true }),
|
|
84
|
+
createOption("swr", "swr"),
|
|
85
|
+
createOption("apollo", "apollo")
|
|
86
|
+
]),
|
|
87
|
+
createCategory("analytics", "Analytics", [
|
|
88
|
+
createOption("posthog", "posthog")
|
|
89
|
+
])
|
|
90
|
+
];
|
|
91
|
+
var defaultProps = {
|
|
92
|
+
categories: defaultCategories,
|
|
93
|
+
focusedRow: 0,
|
|
94
|
+
focusedCol: 0,
|
|
95
|
+
showDescriptions: false,
|
|
96
|
+
expertMode: false,
|
|
97
|
+
onToggle: vi.fn(),
|
|
98
|
+
onFocusChange: vi.fn(),
|
|
99
|
+
onToggleDescriptions: vi.fn(),
|
|
100
|
+
onToggleExpertMode: vi.fn()
|
|
101
|
+
};
|
|
102
|
+
var renderGrid = (props = {}) => {
|
|
103
|
+
return render(/* @__PURE__ */ jsx(CategoryGrid, { ...defaultProps, ...props }));
|
|
104
|
+
};
|
|
105
|
+
describe("CategoryGrid component", () => {
|
|
106
|
+
let cleanup;
|
|
107
|
+
afterEach(() => {
|
|
108
|
+
cleanup?.();
|
|
109
|
+
cleanup = void 0;
|
|
110
|
+
vi.clearAllMocks();
|
|
111
|
+
});
|
|
112
|
+
describe("rendering", () => {
|
|
113
|
+
it("should render all categories", () => {
|
|
114
|
+
const { lastFrame, unmount } = renderGrid();
|
|
115
|
+
cleanup = unmount;
|
|
116
|
+
const output = lastFrame();
|
|
117
|
+
globalExpect(output).toContain("Framework");
|
|
118
|
+
globalExpect(output).toContain("Styling");
|
|
119
|
+
globalExpect(output).toContain("Client State");
|
|
120
|
+
globalExpect(output).toContain("Server State");
|
|
121
|
+
globalExpect(output).toContain("Analytics");
|
|
122
|
+
});
|
|
123
|
+
it("should render all options in each category", () => {
|
|
124
|
+
const { lastFrame, unmount } = renderGrid();
|
|
125
|
+
cleanup = unmount;
|
|
126
|
+
const output = lastFrame();
|
|
127
|
+
globalExpect(output).toContain("react");
|
|
128
|
+
globalExpect(output).toContain("vue");
|
|
129
|
+
globalExpect(output).toContain("angular");
|
|
130
|
+
globalExpect(output).toContain("svelte");
|
|
131
|
+
globalExpect(output).toContain("scss-mod");
|
|
132
|
+
globalExpect(output).toContain("tailwind");
|
|
133
|
+
});
|
|
134
|
+
it("should show required indicator (*) for required categories", () => {
|
|
135
|
+
const { lastFrame, unmount } = renderGrid();
|
|
136
|
+
cleanup = unmount;
|
|
137
|
+
const output = lastFrame();
|
|
138
|
+
globalExpect(output).toContain("*");
|
|
139
|
+
});
|
|
140
|
+
it("should show (optional) for non-required categories", () => {
|
|
141
|
+
const { lastFrame, unmount } = renderGrid();
|
|
142
|
+
cleanup = unmount;
|
|
143
|
+
const output = lastFrame();
|
|
144
|
+
globalExpect(output).toContain("(optional)");
|
|
145
|
+
});
|
|
146
|
+
it("should render legend row", () => {
|
|
147
|
+
const { lastFrame, unmount } = renderGrid();
|
|
148
|
+
cleanup = unmount;
|
|
149
|
+
const output = lastFrame();
|
|
150
|
+
globalExpect(output).toContain("Legend:");
|
|
151
|
+
globalExpect(output).toContain("selected");
|
|
152
|
+
globalExpect(output).toContain("recommended");
|
|
153
|
+
globalExpect(output).toContain("discouraged");
|
|
154
|
+
globalExpect(output).toContain("disabled");
|
|
155
|
+
});
|
|
156
|
+
it("should render header with toggle hints", () => {
|
|
157
|
+
const { lastFrame, unmount } = renderGrid();
|
|
158
|
+
cleanup = unmount;
|
|
159
|
+
const output = lastFrame();
|
|
160
|
+
globalExpect(output).toContain("[Tab] Show descriptions");
|
|
161
|
+
globalExpect(output).toContain("[e] Expert Mode");
|
|
162
|
+
});
|
|
163
|
+
it("should handle empty categories array", () => {
|
|
164
|
+
const { lastFrame, unmount } = renderGrid({ categories: [] });
|
|
165
|
+
cleanup = unmount;
|
|
166
|
+
const output = lastFrame();
|
|
167
|
+
globalExpect(output).toContain("No categories to display");
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
describe("visual states", () => {
|
|
171
|
+
it("should show selected symbol for selected options", () => {
|
|
172
|
+
const { lastFrame, unmount } = renderGrid();
|
|
173
|
+
cleanup = unmount;
|
|
174
|
+
const output = lastFrame();
|
|
175
|
+
globalExpect(output).toContain("\u25CF");
|
|
176
|
+
});
|
|
177
|
+
it("should show unselected symbol for unselected options", () => {
|
|
178
|
+
const { lastFrame, unmount } = renderGrid();
|
|
179
|
+
cleanup = unmount;
|
|
180
|
+
const output = lastFrame();
|
|
181
|
+
globalExpect(output).toContain("\u25CB");
|
|
182
|
+
});
|
|
183
|
+
it("should show recommended indicator for recommended options", () => {
|
|
184
|
+
const { lastFrame, unmount } = renderGrid();
|
|
185
|
+
cleanup = unmount;
|
|
186
|
+
const output = lastFrame();
|
|
187
|
+
globalExpect(output).toContain("\u2B50");
|
|
188
|
+
});
|
|
189
|
+
it("should show discouraged indicator for discouraged options", () => {
|
|
190
|
+
const { lastFrame, unmount } = renderGrid();
|
|
191
|
+
cleanup = unmount;
|
|
192
|
+
const output = lastFrame();
|
|
193
|
+
globalExpect(output).toContain("\u26A0");
|
|
194
|
+
});
|
|
195
|
+
it("should show disabled symbol for disabled options", () => {
|
|
196
|
+
const categories = [
|
|
197
|
+
createCategory("test", "Test", [
|
|
198
|
+
createOption("opt1", "Option 1"),
|
|
199
|
+
createOption("opt2", "Option 2", { state: "disabled" })
|
|
200
|
+
])
|
|
201
|
+
];
|
|
202
|
+
const { lastFrame, unmount } = renderGrid({ categories });
|
|
203
|
+
cleanup = unmount;
|
|
204
|
+
const output = lastFrame();
|
|
205
|
+
globalExpect(output).toContain("\u2717");
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe("focus indicator", () => {
|
|
209
|
+
it("should show focus indicator (>) on focused option", () => {
|
|
210
|
+
const { lastFrame, unmount } = renderGrid({
|
|
211
|
+
focusedRow: 0,
|
|
212
|
+
focusedCol: 0
|
|
213
|
+
});
|
|
214
|
+
cleanup = unmount;
|
|
215
|
+
const output = lastFrame();
|
|
216
|
+
globalExpect(output).toContain(">");
|
|
217
|
+
});
|
|
218
|
+
it("should update focus indicator when focusedRow changes", () => {
|
|
219
|
+
const { lastFrame: frame1, unmount: unmount1 } = renderGrid({
|
|
220
|
+
focusedRow: 0,
|
|
221
|
+
focusedCol: 0
|
|
222
|
+
});
|
|
223
|
+
const output1 = frame1();
|
|
224
|
+
unmount1();
|
|
225
|
+
const { lastFrame: frame2, unmount: unmount2 } = renderGrid({
|
|
226
|
+
focusedRow: 1,
|
|
227
|
+
focusedCol: 0
|
|
228
|
+
});
|
|
229
|
+
cleanup = unmount2;
|
|
230
|
+
const output2 = frame2();
|
|
231
|
+
globalExpect(output1).toContain(">");
|
|
232
|
+
globalExpect(output2).toContain(">");
|
|
233
|
+
});
|
|
234
|
+
it("should highlight focused category name", () => {
|
|
235
|
+
const { lastFrame, unmount } = renderGrid({
|
|
236
|
+
focusedRow: 1,
|
|
237
|
+
focusedCol: 0
|
|
238
|
+
});
|
|
239
|
+
cleanup = unmount;
|
|
240
|
+
const output = lastFrame();
|
|
241
|
+
globalExpect(output).toContain("Styling");
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
describe("keyboard navigation - arrow keys", () => {
|
|
245
|
+
it("should call onFocusChange when pressing left arrow", async () => {
|
|
246
|
+
const onFocusChange = vi.fn();
|
|
247
|
+
const { stdin, unmount } = renderGrid({
|
|
248
|
+
focusedRow: 0,
|
|
249
|
+
focusedCol: 1,
|
|
250
|
+
onFocusChange
|
|
251
|
+
});
|
|
252
|
+
cleanup = unmount;
|
|
253
|
+
await delay(RENDER_DELAY_MS);
|
|
254
|
+
await stdin.write(ARROW_LEFT);
|
|
255
|
+
await delay(INPUT_DELAY_MS);
|
|
256
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
257
|
+
});
|
|
258
|
+
it("should call onFocusChange when pressing right arrow", async () => {
|
|
259
|
+
const onFocusChange = vi.fn();
|
|
260
|
+
const { stdin, unmount } = renderGrid({
|
|
261
|
+
focusedRow: 0,
|
|
262
|
+
focusedCol: 0,
|
|
263
|
+
onFocusChange
|
|
264
|
+
});
|
|
265
|
+
cleanup = unmount;
|
|
266
|
+
await delay(RENDER_DELAY_MS);
|
|
267
|
+
await stdin.write(ARROW_RIGHT);
|
|
268
|
+
await delay(INPUT_DELAY_MS);
|
|
269
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 1);
|
|
270
|
+
});
|
|
271
|
+
it("should call onFocusChange when pressing up arrow", async () => {
|
|
272
|
+
const onFocusChange = vi.fn();
|
|
273
|
+
const { stdin, unmount } = renderGrid({
|
|
274
|
+
focusedRow: 1,
|
|
275
|
+
focusedCol: 0,
|
|
276
|
+
onFocusChange
|
|
277
|
+
});
|
|
278
|
+
cleanup = unmount;
|
|
279
|
+
await delay(RENDER_DELAY_MS);
|
|
280
|
+
await stdin.write(ARROW_UP);
|
|
281
|
+
await delay(INPUT_DELAY_MS);
|
|
282
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
283
|
+
});
|
|
284
|
+
it("should call onFocusChange when pressing down arrow", async () => {
|
|
285
|
+
const onFocusChange = vi.fn();
|
|
286
|
+
const { stdin, unmount } = renderGrid({
|
|
287
|
+
focusedRow: 0,
|
|
288
|
+
focusedCol: 0,
|
|
289
|
+
onFocusChange
|
|
290
|
+
});
|
|
291
|
+
cleanup = unmount;
|
|
292
|
+
await delay(RENDER_DELAY_MS);
|
|
293
|
+
await stdin.write(ARROW_DOWN);
|
|
294
|
+
await delay(INPUT_DELAY_MS);
|
|
295
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(1, 0);
|
|
296
|
+
});
|
|
297
|
+
it("should wrap horizontally when pressing left at first column", async () => {
|
|
298
|
+
const onFocusChange = vi.fn();
|
|
299
|
+
const { stdin, unmount } = renderGrid({
|
|
300
|
+
focusedRow: 0,
|
|
301
|
+
focusedCol: 0,
|
|
302
|
+
onFocusChange
|
|
303
|
+
});
|
|
304
|
+
cleanup = unmount;
|
|
305
|
+
await delay(RENDER_DELAY_MS);
|
|
306
|
+
await stdin.write(ARROW_LEFT);
|
|
307
|
+
await delay(INPUT_DELAY_MS);
|
|
308
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 3);
|
|
309
|
+
});
|
|
310
|
+
it("should wrap horizontally when pressing right at last column", async () => {
|
|
311
|
+
const onFocusChange = vi.fn();
|
|
312
|
+
const { stdin, unmount } = renderGrid({
|
|
313
|
+
focusedRow: 0,
|
|
314
|
+
focusedCol: 3,
|
|
315
|
+
// Last option in framework
|
|
316
|
+
onFocusChange
|
|
317
|
+
});
|
|
318
|
+
cleanup = unmount;
|
|
319
|
+
await delay(RENDER_DELAY_MS);
|
|
320
|
+
await stdin.write(ARROW_RIGHT);
|
|
321
|
+
await delay(INPUT_DELAY_MS);
|
|
322
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
323
|
+
});
|
|
324
|
+
it("should wrap vertically when pressing up at first row", async () => {
|
|
325
|
+
const onFocusChange = vi.fn();
|
|
326
|
+
const { stdin, unmount } = renderGrid({
|
|
327
|
+
focusedRow: 0,
|
|
328
|
+
focusedCol: 0,
|
|
329
|
+
onFocusChange
|
|
330
|
+
});
|
|
331
|
+
cleanup = unmount;
|
|
332
|
+
await delay(RENDER_DELAY_MS);
|
|
333
|
+
await stdin.write(ARROW_UP);
|
|
334
|
+
await delay(INPUT_DELAY_MS);
|
|
335
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(4, 0);
|
|
336
|
+
});
|
|
337
|
+
it("should wrap vertically when pressing down at last row", async () => {
|
|
338
|
+
const onFocusChange = vi.fn();
|
|
339
|
+
const { stdin, unmount } = renderGrid({
|
|
340
|
+
focusedRow: 4,
|
|
341
|
+
// Last category (analytics)
|
|
342
|
+
focusedCol: 0,
|
|
343
|
+
onFocusChange
|
|
344
|
+
});
|
|
345
|
+
cleanup = unmount;
|
|
346
|
+
await delay(RENDER_DELAY_MS);
|
|
347
|
+
await stdin.write(ARROW_DOWN);
|
|
348
|
+
await delay(INPUT_DELAY_MS);
|
|
349
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
350
|
+
});
|
|
351
|
+
});
|
|
352
|
+
describe("keyboard navigation - vim keys", () => {
|
|
353
|
+
it("should move left with h key", async () => {
|
|
354
|
+
const onFocusChange = vi.fn();
|
|
355
|
+
const { stdin, unmount } = renderGrid({
|
|
356
|
+
focusedRow: 0,
|
|
357
|
+
focusedCol: 1,
|
|
358
|
+
onFocusChange
|
|
359
|
+
});
|
|
360
|
+
cleanup = unmount;
|
|
361
|
+
await delay(RENDER_DELAY_MS);
|
|
362
|
+
await stdin.write("h");
|
|
363
|
+
await delay(INPUT_DELAY_MS);
|
|
364
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
365
|
+
});
|
|
366
|
+
it("should move right with l key", async () => {
|
|
367
|
+
const onFocusChange = vi.fn();
|
|
368
|
+
const { stdin, unmount } = renderGrid({
|
|
369
|
+
focusedRow: 0,
|
|
370
|
+
focusedCol: 0,
|
|
371
|
+
onFocusChange
|
|
372
|
+
});
|
|
373
|
+
cleanup = unmount;
|
|
374
|
+
await delay(RENDER_DELAY_MS);
|
|
375
|
+
await stdin.write("l");
|
|
376
|
+
await delay(INPUT_DELAY_MS);
|
|
377
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 1);
|
|
378
|
+
});
|
|
379
|
+
it("should move up with k key", async () => {
|
|
380
|
+
const onFocusChange = vi.fn();
|
|
381
|
+
const { stdin, unmount } = renderGrid({
|
|
382
|
+
focusedRow: 1,
|
|
383
|
+
focusedCol: 0,
|
|
384
|
+
onFocusChange
|
|
385
|
+
});
|
|
386
|
+
cleanup = unmount;
|
|
387
|
+
await delay(RENDER_DELAY_MS);
|
|
388
|
+
await stdin.write("k");
|
|
389
|
+
await delay(INPUT_DELAY_MS);
|
|
390
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
391
|
+
});
|
|
392
|
+
it("should move down with j key", async () => {
|
|
393
|
+
const onFocusChange = vi.fn();
|
|
394
|
+
const { stdin, unmount } = renderGrid({
|
|
395
|
+
focusedRow: 0,
|
|
396
|
+
focusedCol: 0,
|
|
397
|
+
onFocusChange
|
|
398
|
+
});
|
|
399
|
+
cleanup = unmount;
|
|
400
|
+
await delay(RENDER_DELAY_MS);
|
|
401
|
+
await stdin.write("j");
|
|
402
|
+
await delay(INPUT_DELAY_MS);
|
|
403
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(1, 0);
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
describe("selection toggle", () => {
|
|
407
|
+
it("should call onToggle when pressing space on a normal option", async () => {
|
|
408
|
+
const onToggle = vi.fn();
|
|
409
|
+
const { stdin, unmount } = renderGrid({
|
|
410
|
+
focusedRow: 0,
|
|
411
|
+
focusedCol: 1,
|
|
412
|
+
// vue (normal state)
|
|
413
|
+
onToggle
|
|
414
|
+
});
|
|
415
|
+
cleanup = unmount;
|
|
416
|
+
await delay(RENDER_DELAY_MS);
|
|
417
|
+
await stdin.write(" ");
|
|
418
|
+
await delay(INPUT_DELAY_MS);
|
|
419
|
+
globalExpect(onToggle).toHaveBeenCalledWith("framework", "vue");
|
|
420
|
+
});
|
|
421
|
+
it("should call onToggle when pressing space on a selected option", async () => {
|
|
422
|
+
const onToggle = vi.fn();
|
|
423
|
+
const { stdin, unmount } = renderGrid({
|
|
424
|
+
focusedRow: 1,
|
|
425
|
+
focusedCol: 0,
|
|
426
|
+
// scss-mod (selected) - first in expert mode
|
|
427
|
+
expertMode: true,
|
|
428
|
+
onToggle
|
|
429
|
+
});
|
|
430
|
+
cleanup = unmount;
|
|
431
|
+
await delay(RENDER_DELAY_MS);
|
|
432
|
+
await stdin.write(" ");
|
|
433
|
+
await delay(INPUT_DELAY_MS);
|
|
434
|
+
globalExpect(onToggle).toHaveBeenCalledWith("styling", "scss-mod");
|
|
435
|
+
});
|
|
436
|
+
it("should NOT call onToggle when pressing space on a disabled option", async () => {
|
|
437
|
+
const onToggle = vi.fn();
|
|
438
|
+
const categories = [
|
|
439
|
+
createCategory("test", "Test", [
|
|
440
|
+
createOption("opt1", "Option 1", { state: "disabled" }),
|
|
441
|
+
createOption("opt2", "Option 2")
|
|
442
|
+
])
|
|
443
|
+
];
|
|
444
|
+
const { stdin, unmount } = renderGrid({
|
|
445
|
+
categories,
|
|
446
|
+
focusedRow: 0,
|
|
447
|
+
focusedCol: 0,
|
|
448
|
+
// Disabled option (first in expert mode)
|
|
449
|
+
expertMode: true,
|
|
450
|
+
onToggle
|
|
451
|
+
});
|
|
452
|
+
cleanup = unmount;
|
|
453
|
+
await delay(RENDER_DELAY_MS);
|
|
454
|
+
await stdin.write(" ");
|
|
455
|
+
await delay(INPUT_DELAY_MS);
|
|
456
|
+
globalExpect(onToggle).not.toHaveBeenCalled();
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
describe("disabled options navigation", () => {
|
|
460
|
+
it("should skip disabled options when navigating right", async () => {
|
|
461
|
+
const onFocusChange = vi.fn();
|
|
462
|
+
const categories = [
|
|
463
|
+
createCategory("test", "Test", [
|
|
464
|
+
createOption("opt1", "Option 1"),
|
|
465
|
+
createOption("opt2", "Option 2", { state: "disabled" }),
|
|
466
|
+
createOption("opt3", "Option 3")
|
|
467
|
+
])
|
|
468
|
+
];
|
|
469
|
+
const { stdin, unmount } = renderGrid({
|
|
470
|
+
categories,
|
|
471
|
+
focusedRow: 0,
|
|
472
|
+
focusedCol: 0,
|
|
473
|
+
expertMode: true,
|
|
474
|
+
onFocusChange
|
|
475
|
+
});
|
|
476
|
+
cleanup = unmount;
|
|
477
|
+
await delay(RENDER_DELAY_MS);
|
|
478
|
+
await stdin.write(ARROW_RIGHT);
|
|
479
|
+
await delay(INPUT_DELAY_MS);
|
|
480
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 2);
|
|
481
|
+
});
|
|
482
|
+
it("should skip disabled options when navigating left", async () => {
|
|
483
|
+
const onFocusChange = vi.fn();
|
|
484
|
+
const categories = [
|
|
485
|
+
createCategory("test", "Test", [
|
|
486
|
+
createOption("opt1", "Option 1"),
|
|
487
|
+
createOption("opt2", "Option 2", { state: "disabled" }),
|
|
488
|
+
createOption("opt3", "Option 3")
|
|
489
|
+
])
|
|
490
|
+
];
|
|
491
|
+
const { stdin, unmount } = renderGrid({
|
|
492
|
+
categories,
|
|
493
|
+
focusedRow: 0,
|
|
494
|
+
focusedCol: 2,
|
|
495
|
+
// Start at opt3
|
|
496
|
+
expertMode: true,
|
|
497
|
+
onFocusChange
|
|
498
|
+
});
|
|
499
|
+
cleanup = unmount;
|
|
500
|
+
await delay(RENDER_DELAY_MS);
|
|
501
|
+
await stdin.write(ARROW_LEFT);
|
|
502
|
+
await delay(INPUT_DELAY_MS);
|
|
503
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
504
|
+
});
|
|
505
|
+
it("should handle all options disabled in a row", async () => {
|
|
506
|
+
const onFocusChange = vi.fn();
|
|
507
|
+
const categories = [
|
|
508
|
+
createCategory("test", "Test", [
|
|
509
|
+
createOption("opt1", "Option 1", { state: "disabled" }),
|
|
510
|
+
createOption("opt2", "Option 2", { state: "disabled" })
|
|
511
|
+
])
|
|
512
|
+
];
|
|
513
|
+
const { stdin, unmount } = renderGrid({
|
|
514
|
+
categories,
|
|
515
|
+
focusedRow: 0,
|
|
516
|
+
focusedCol: 0,
|
|
517
|
+
expertMode: true,
|
|
518
|
+
onFocusChange
|
|
519
|
+
});
|
|
520
|
+
cleanup = unmount;
|
|
521
|
+
await delay(RENDER_DELAY_MS);
|
|
522
|
+
await stdin.write(ARROW_RIGHT);
|
|
523
|
+
await delay(INPUT_DELAY_MS);
|
|
524
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(0, 0);
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
describe("exclusive categories", () => {
|
|
528
|
+
it("should render exclusive category correctly", () => {
|
|
529
|
+
const { lastFrame, unmount } = renderGrid();
|
|
530
|
+
cleanup = unmount;
|
|
531
|
+
const output = lastFrame();
|
|
532
|
+
globalExpect(output).toContain("Framework");
|
|
533
|
+
});
|
|
534
|
+
});
|
|
535
|
+
describe("show descriptions toggle", () => {
|
|
536
|
+
it("should call onToggleDescriptions when pressing Tab", async () => {
|
|
537
|
+
const onToggleDescriptions = vi.fn();
|
|
538
|
+
const { stdin, unmount } = renderGrid({
|
|
539
|
+
onToggleDescriptions
|
|
540
|
+
});
|
|
541
|
+
cleanup = unmount;
|
|
542
|
+
await delay(RENDER_DELAY_MS);
|
|
543
|
+
await stdin.write(TAB);
|
|
544
|
+
await delay(INPUT_DELAY_MS);
|
|
545
|
+
globalExpect(onToggleDescriptions).toHaveBeenCalled();
|
|
546
|
+
});
|
|
547
|
+
it("should show descriptions when showDescriptions is true", () => {
|
|
548
|
+
const { lastFrame, unmount } = renderGrid({ showDescriptions: true });
|
|
549
|
+
cleanup = unmount;
|
|
550
|
+
const output = lastFrame();
|
|
551
|
+
globalExpect(output).toContain("Popular choice");
|
|
552
|
+
});
|
|
553
|
+
it("should hide descriptions when showDescriptions is false", () => {
|
|
554
|
+
const { lastFrame, unmount } = renderGrid({ showDescriptions: false });
|
|
555
|
+
cleanup = unmount;
|
|
556
|
+
const output = lastFrame();
|
|
557
|
+
globalExpect(output).toBeDefined();
|
|
558
|
+
});
|
|
559
|
+
it("should show toggle state in header", () => {
|
|
560
|
+
const { lastFrame: frame1, unmount: unmount1 } = renderGrid({
|
|
561
|
+
showDescriptions: false
|
|
562
|
+
});
|
|
563
|
+
const output1 = frame1();
|
|
564
|
+
unmount1();
|
|
565
|
+
const { lastFrame: frame2, unmount: unmount2 } = renderGrid({
|
|
566
|
+
showDescriptions: true
|
|
567
|
+
});
|
|
568
|
+
cleanup = unmount2;
|
|
569
|
+
const output2 = frame2();
|
|
570
|
+
globalExpect(output1).toContain("Show descriptions: OFF");
|
|
571
|
+
globalExpect(output2).toContain("Show descriptions: ON");
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
describe("expert mode toggle", () => {
|
|
575
|
+
it("should call onToggleExpertMode when pressing e", async () => {
|
|
576
|
+
const onToggleExpertMode = vi.fn();
|
|
577
|
+
const { stdin, unmount } = renderGrid({
|
|
578
|
+
onToggleExpertMode
|
|
579
|
+
});
|
|
580
|
+
cleanup = unmount;
|
|
581
|
+
await delay(RENDER_DELAY_MS);
|
|
582
|
+
await stdin.write("e");
|
|
583
|
+
await delay(INPUT_DELAY_MS);
|
|
584
|
+
globalExpect(onToggleExpertMode).toHaveBeenCalled();
|
|
585
|
+
});
|
|
586
|
+
it("should call onToggleExpertMode when pressing E (uppercase)", async () => {
|
|
587
|
+
const onToggleExpertMode = vi.fn();
|
|
588
|
+
const { stdin, unmount } = renderGrid({
|
|
589
|
+
onToggleExpertMode
|
|
590
|
+
});
|
|
591
|
+
cleanup = unmount;
|
|
592
|
+
await delay(RENDER_DELAY_MS);
|
|
593
|
+
await stdin.write("E");
|
|
594
|
+
await delay(INPUT_DELAY_MS);
|
|
595
|
+
globalExpect(onToggleExpertMode).toHaveBeenCalled();
|
|
596
|
+
});
|
|
597
|
+
it("should show toggle state in header", () => {
|
|
598
|
+
const { lastFrame: frame1, unmount: unmount1 } = renderGrid({
|
|
599
|
+
expertMode: false
|
|
600
|
+
});
|
|
601
|
+
const output1 = frame1();
|
|
602
|
+
unmount1();
|
|
603
|
+
const { lastFrame: frame2, unmount: unmount2 } = renderGrid({
|
|
604
|
+
expertMode: true
|
|
605
|
+
});
|
|
606
|
+
cleanup = unmount2;
|
|
607
|
+
const output2 = frame2();
|
|
608
|
+
globalExpect(output1).toContain("Expert Mode: OFF");
|
|
609
|
+
globalExpect(output2).toContain("Expert Mode: ON");
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
describe("option ordering", () => {
|
|
613
|
+
it("should sort options by state when expertMode is false", () => {
|
|
614
|
+
const { lastFrame, unmount } = renderGrid({ expertMode: false });
|
|
615
|
+
cleanup = unmount;
|
|
616
|
+
const output = lastFrame();
|
|
617
|
+
globalExpect(output).toBeDefined();
|
|
618
|
+
});
|
|
619
|
+
it("should preserve original order when expertMode is true", () => {
|
|
620
|
+
const { lastFrame, unmount } = renderGrid({ expertMode: true });
|
|
621
|
+
cleanup = unmount;
|
|
622
|
+
const output = lastFrame();
|
|
623
|
+
globalExpect(output).toBeDefined();
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
describe("edge cases", () => {
|
|
627
|
+
it("should handle single category", () => {
|
|
628
|
+
const categories = [
|
|
629
|
+
createCategory("single", "Single Category", [
|
|
630
|
+
createOption("opt1", "Option 1")
|
|
631
|
+
])
|
|
632
|
+
];
|
|
633
|
+
const { lastFrame, unmount } = renderGrid({ categories });
|
|
634
|
+
cleanup = unmount;
|
|
635
|
+
const output = lastFrame();
|
|
636
|
+
globalExpect(output).toContain("Single Category");
|
|
637
|
+
globalExpect(output).toContain("Option 1");
|
|
638
|
+
});
|
|
639
|
+
it("should handle single option in category", () => {
|
|
640
|
+
const categories = [
|
|
641
|
+
createCategory("single", "Single", [
|
|
642
|
+
createOption("only", "Only Option")
|
|
643
|
+
])
|
|
644
|
+
];
|
|
645
|
+
const { lastFrame, unmount } = renderGrid({ categories });
|
|
646
|
+
cleanup = unmount;
|
|
647
|
+
const output = lastFrame();
|
|
648
|
+
globalExpect(output).toContain("Only Option");
|
|
649
|
+
});
|
|
650
|
+
it("should handle category with many options", () => {
|
|
651
|
+
const options = Array.from(
|
|
652
|
+
{ length: 10 },
|
|
653
|
+
(_, i) => createOption(`opt${i}`, `Option ${i}`)
|
|
654
|
+
);
|
|
655
|
+
const categories = [
|
|
656
|
+
createCategory("many", "Many Options", options)
|
|
657
|
+
];
|
|
658
|
+
const { lastFrame, unmount } = renderGrid({ categories });
|
|
659
|
+
cleanup = unmount;
|
|
660
|
+
const output = lastFrame();
|
|
661
|
+
globalExpect(output).toContain("Many Options");
|
|
662
|
+
globalExpect(output).toContain("Option 0");
|
|
663
|
+
globalExpect(output).toContain("Option 9");
|
|
664
|
+
});
|
|
665
|
+
it("should handle long option labels", () => {
|
|
666
|
+
const categories = [
|
|
667
|
+
createCategory("long", "Long Labels", [
|
|
668
|
+
createOption("long1", "very-long-option-name-here"),
|
|
669
|
+
createOption("long2", "another-very-long-option")
|
|
670
|
+
])
|
|
671
|
+
];
|
|
672
|
+
const { lastFrame, unmount } = renderGrid({ categories });
|
|
673
|
+
cleanup = unmount;
|
|
674
|
+
const output = lastFrame();
|
|
675
|
+
globalExpect(output).toContain("very-long-option-name-here");
|
|
676
|
+
});
|
|
677
|
+
it("should handle categories with different option counts", () => {
|
|
678
|
+
const categories = [
|
|
679
|
+
createCategory("cat1", "Category 1", [
|
|
680
|
+
createOption("opt1", "Option 1"),
|
|
681
|
+
createOption("opt2", "Option 2")
|
|
682
|
+
]),
|
|
683
|
+
createCategory("cat2", "Category 2", [
|
|
684
|
+
createOption("opt3", "Option 3")
|
|
685
|
+
]),
|
|
686
|
+
createCategory("cat3", "Category 3", [
|
|
687
|
+
createOption("opt4", "Option 4"),
|
|
688
|
+
createOption("opt5", "Option 5"),
|
|
689
|
+
createOption("opt6", "Option 6")
|
|
690
|
+
])
|
|
691
|
+
];
|
|
692
|
+
const { lastFrame, unmount } = renderGrid({ categories });
|
|
693
|
+
cleanup = unmount;
|
|
694
|
+
const output = lastFrame();
|
|
695
|
+
globalExpect(output).toContain("Category 1");
|
|
696
|
+
globalExpect(output).toContain("Category 2");
|
|
697
|
+
globalExpect(output).toContain("Category 3");
|
|
698
|
+
});
|
|
699
|
+
});
|
|
700
|
+
describe("column adjustment", () => {
|
|
701
|
+
it("should adjust focusedCol when changing to row with fewer options", async () => {
|
|
702
|
+
const onFocusChange = vi.fn();
|
|
703
|
+
const categories = [
|
|
704
|
+
createCategory("cat1", "Category 1", [
|
|
705
|
+
createOption("opt1", "Option 1"),
|
|
706
|
+
createOption("opt2", "Option 2"),
|
|
707
|
+
createOption("opt3", "Option 3")
|
|
708
|
+
]),
|
|
709
|
+
createCategory("cat2", "Category 2", [
|
|
710
|
+
createOption("opt4", "Option 4")
|
|
711
|
+
])
|
|
712
|
+
];
|
|
713
|
+
const { stdin, unmount } = renderGrid({
|
|
714
|
+
categories,
|
|
715
|
+
focusedRow: 0,
|
|
716
|
+
focusedCol: 2,
|
|
717
|
+
// Last option in first row
|
|
718
|
+
onFocusChange
|
|
719
|
+
});
|
|
720
|
+
cleanup = unmount;
|
|
721
|
+
await delay(RENDER_DELAY_MS);
|
|
722
|
+
await stdin.write(ARROW_DOWN);
|
|
723
|
+
await delay(INPUT_DELAY_MS);
|
|
724
|
+
globalExpect(onFocusChange).toHaveBeenCalledWith(1, 0);
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
//# sourceMappingURL=category-grid.test.js.map
|