@abelfubu/dv 0.1.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/ansi-html.d.ts +42 -0
- package/dist/ansi-html.d.ts.map +1 -0
- package/dist/ansi-html.js +327 -0
- package/dist/ansi-output.d.ts +22 -0
- package/dist/ansi-output.d.ts.map +1 -0
- package/dist/ansi-output.js +154 -0
- package/dist/balance-delimiters.d.ts +25 -0
- package/dist/balance-delimiters.d.ts.map +1 -0
- package/dist/balance-delimiters.js +539 -0
- package/dist/balance-delimiters.test.d.ts +2 -0
- package/dist/balance-delimiters.test.d.ts.map +1 -0
- package/dist/balance-delimiters.test.js +1029 -0
- package/dist/cli-copy-notification.test.d.ts +2 -0
- package/dist/cli-copy-notification.test.d.ts.map +1 -0
- package/dist/cli-copy-notification.test.js +80 -0
- package/dist/cli-scroll.test.d.ts +2 -0
- package/dist/cli-scroll.test.d.ts.map +1 -0
- package/dist/cli-scroll.test.js +283 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +976 -0
- package/dist/clipboard.d.ts +16 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +128 -0
- package/dist/components/diff-view.d.ts +32 -0
- package/dist/components/diff-view.d.ts.map +1 -0
- package/dist/components/diff-view.js +123 -0
- package/dist/components/diff-view.test.d.ts +5 -0
- package/dist/components/diff-view.test.d.ts.map +1 -0
- package/dist/components/diff-view.test.js +312 -0
- package/dist/components/directory-tree-view.d.ts +33 -0
- package/dist/components/directory-tree-view.d.ts.map +1 -0
- package/dist/components/directory-tree-view.js +262 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +5 -0
- package/dist/components/toast.d.ts +21 -0
- package/dist/components/toast.d.ts.map +1 -0
- package/dist/components/toast.js +47 -0
- package/dist/diff-cursor-utils.d.ts +20 -0
- package/dist/diff-cursor-utils.d.ts.map +1 -0
- package/dist/diff-cursor-utils.js +105 -0
- package/dist/diff-cursor-utils.test.d.ts +2 -0
- package/dist/diff-cursor-utils.test.d.ts.map +1 -0
- package/dist/diff-cursor-utils.test.js +40 -0
- package/dist/diff-surface-copy.d.ts +23 -0
- package/dist/diff-surface-copy.d.ts.map +1 -0
- package/dist/diff-surface-copy.js +64 -0
- package/dist/diff-surface-copy.test.d.ts +5 -0
- package/dist/diff-surface-copy.test.d.ts.map +1 -0
- package/dist/diff-surface-copy.test.js +142 -0
- package/dist/diff-utils.d.ts +196 -0
- package/dist/diff-utils.d.ts.map +1 -0
- package/dist/diff-utils.js +682 -0
- package/dist/diff-utils.test.d.ts +2 -0
- package/dist/diff-utils.test.d.ts.map +1 -0
- package/dist/diff-utils.test.js +727 -0
- package/dist/directory-tree.d.ts +72 -0
- package/dist/directory-tree.d.ts.map +1 -0
- package/dist/directory-tree.js +161 -0
- package/dist/directory-tree.test.d.ts +2 -0
- package/dist/directory-tree.test.d.ts.map +1 -0
- package/dist/directory-tree.test.js +383 -0
- package/dist/dropdown.d.ts +26 -0
- package/dist/dropdown.d.ts.map +1 -0
- package/dist/dropdown.js +172 -0
- package/dist/dropdown.test.d.ts +2 -0
- package/dist/dropdown.test.d.ts.map +1 -0
- package/dist/dropdown.test.js +106 -0
- package/dist/filter-submodule.e2e.test.d.ts +2 -0
- package/dist/filter-submodule.e2e.test.d.ts.map +1 -0
- package/dist/filter-submodule.e2e.test.js +109 -0
- package/dist/hooks/use-copy-selection.d.ts +29 -0
- package/dist/hooks/use-copy-selection.d.ts.map +1 -0
- package/dist/hooks/use-copy-selection.js +46 -0
- package/dist/kv-codec.d.ts +16 -0
- package/dist/kv-codec.d.ts.map +1 -0
- package/dist/kv-codec.js +36 -0
- package/dist/license.d.ts +14 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +63 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +78 -0
- package/dist/monochrome.d.ts +34 -0
- package/dist/monochrome.d.ts.map +1 -0
- package/dist/monochrome.js +613 -0
- package/dist/monotone.d.ts +22 -0
- package/dist/monotone.d.ts.map +1 -0
- package/dist/monotone.js +185 -0
- package/dist/parsers-config.d.ts +19 -0
- package/dist/parsers-config.d.ts.map +1 -0
- package/dist/parsers-config.js +271 -0
- package/dist/patch-terminal-dimensions.d.ts +2 -0
- package/dist/patch-terminal-dimensions.d.ts.map +1 -0
- package/dist/patch-terminal-dimensions.js +45 -0
- package/dist/stdin-pager.test.d.ts +2 -0
- package/dist/stdin-pager.test.d.ts.map +1 -0
- package/dist/stdin-pager.test.js +497 -0
- package/dist/store.d.ts +16 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +48 -0
- package/dist/themes/github.json +247 -0
- package/dist/themes.d.ts +59 -0
- package/dist/themes.d.ts.map +1 -0
- package/dist/themes.js +248 -0
- package/dist/tree-icons.d.ts +4 -0
- package/dist/tree-icons.d.ts.map +1 -0
- package/dist/tree-icons.js +18 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +13 -0
- package/dist/web-utils.d.ts +56 -0
- package/dist/web-utils.d.ts.map +1 -0
- package/dist/web-utils.js +363 -0
- package/package.json +37 -0
- package/public/jetbrains-mono-nerd.ttf +0 -0
- package/public/jetbrains-mono-nerd.woff2 +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-copy-notification.test.d.ts","sourceRoot":"","sources":["../src/cli-copy-notification.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@opentuah/react/jsx-runtime";
|
|
2
|
+
// Tests for the transient copy notification shown after pressing `y`.
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
5
|
+
import { act } from "react";
|
|
6
|
+
import { testRender } from "@opentuah/react/test-utils";
|
|
7
|
+
import { App } from "./cli.js";
|
|
8
|
+
const sampleDiff = `diff --git a/a.ts b/a.ts
|
|
9
|
+
index 1111111..2222222 100644
|
|
10
|
+
--- a/a.ts
|
|
11
|
+
+++ b/a.ts
|
|
12
|
+
@@ -1,4 +1,4 @@
|
|
13
|
+
context
|
|
14
|
+
-old
|
|
15
|
+
+new
|
|
16
|
+
-more
|
|
17
|
+
+more-new
|
|
18
|
+
keep
|
|
19
|
+
`;
|
|
20
|
+
function createParsedFile(path) {
|
|
21
|
+
return {
|
|
22
|
+
oldFileName: `a/${path}`,
|
|
23
|
+
newFileName: `b/${path}`,
|
|
24
|
+
hunks: [{ lines: [" context", "-old", "+new", "-more", "+more-new", " keep"] }],
|
|
25
|
+
rawDiff: sampleDiff,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async function renderUntilStable(testSetup, times = 8) {
|
|
29
|
+
for (let index = 0; index < times; index++) {
|
|
30
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
31
|
+
await testSetup.renderOnce();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
describe("App copy notification", () => {
|
|
35
|
+
let testSetup;
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
if (testSetup) {
|
|
38
|
+
act(() => {
|
|
39
|
+
testSetup.renderer.destroy();
|
|
40
|
+
});
|
|
41
|
+
testSetup = undefined;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
it("shows a transient success notification after copying selected lines", async () => {
|
|
45
|
+
const parsedFiles = [createParsedFile("a.ts")];
|
|
46
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
47
|
+
width: 120,
|
|
48
|
+
height: 16,
|
|
49
|
+
});
|
|
50
|
+
await renderUntilStable(testSetup);
|
|
51
|
+
// Focus diff pane, start selection, extend by one line, then copy.
|
|
52
|
+
await act(async () => {
|
|
53
|
+
testSetup.mockInput.pressTab();
|
|
54
|
+
await testSetup.renderOnce();
|
|
55
|
+
});
|
|
56
|
+
await act(async () => {
|
|
57
|
+
testSetup.mockInput.pressKey("v");
|
|
58
|
+
await testSetup.renderOnce();
|
|
59
|
+
});
|
|
60
|
+
await act(async () => {
|
|
61
|
+
testSetup.mockInput.pressKey("j");
|
|
62
|
+
await testSetup.renderOnce();
|
|
63
|
+
});
|
|
64
|
+
await act(async () => {
|
|
65
|
+
testSetup.mockInput.pressKey("y");
|
|
66
|
+
await testSetup.renderOnce();
|
|
67
|
+
});
|
|
68
|
+
const frame = testSetup.captureCharFrame();
|
|
69
|
+
expect(frame).toContain("Copied 2 lines");
|
|
70
|
+
expect(frame).toContain("✓");
|
|
71
|
+
// Wait for the auto-hide timeout to clear the notification.
|
|
72
|
+
await new Promise((resolve) => setTimeout(resolve, 2500));
|
|
73
|
+
await act(async () => {
|
|
74
|
+
await testSetup.renderOnce();
|
|
75
|
+
});
|
|
76
|
+
const clearedFrame = testSetup.captureCharFrame();
|
|
77
|
+
expect(clearedFrame).not.toContain("Copied 2 lines");
|
|
78
|
+
expect(clearedFrame).not.toContain("✓");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-scroll.test.d.ts","sourceRoot":"","sources":["../src/cli-scroll.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { jsx as _jsx } from "@opentuah/react/jsx-runtime";
|
|
2
|
+
// Tests mouse-wheel scrolling behavior in the main diff App scrollbox.
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
5
|
+
import { act } from "react";
|
|
6
|
+
import { testRender } from "@opentuah/react/test-utils";
|
|
7
|
+
import { App } from "./cli.js";
|
|
8
|
+
function createParsedFile(path, index, lineCount = 1) {
|
|
9
|
+
const lines = Array.from({ length: lineCount }, (_, i) => `+line${i}`);
|
|
10
|
+
return {
|
|
11
|
+
oldFileName: path,
|
|
12
|
+
newFileName: path,
|
|
13
|
+
hunks: [{ lines }],
|
|
14
|
+
rawDiff: [
|
|
15
|
+
`diff --git a/${path} b/${path}`,
|
|
16
|
+
`--- ${path}`,
|
|
17
|
+
`+++ ${path}`,
|
|
18
|
+
`@@ -0,0 +1,${lineCount} @@`,
|
|
19
|
+
...lines,
|
|
20
|
+
].join("\n"),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
describe("App scrollbox", () => {
|
|
24
|
+
let testSetup;
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
if (testSetup) {
|
|
27
|
+
act(() => {
|
|
28
|
+
testSetup.renderer.destroy();
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
it("renders the sidebar navigator beside the diff document", async () => {
|
|
33
|
+
const parsedFiles = [
|
|
34
|
+
createParsedFile("README.md", 0),
|
|
35
|
+
createParsedFile("src/file-01.ts", 1),
|
|
36
|
+
];
|
|
37
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
38
|
+
width: 120,
|
|
39
|
+
height: 12,
|
|
40
|
+
});
|
|
41
|
+
await act(async () => {
|
|
42
|
+
await testSetup.renderOnce();
|
|
43
|
+
});
|
|
44
|
+
const frame = testSetup.captureCharFrame();
|
|
45
|
+
const lines = frame.split("\n");
|
|
46
|
+
// Sidebar tree content should be visible
|
|
47
|
+
expect(lines[1]).toContain("README.md (+1)");
|
|
48
|
+
expect(lines[2]).toContain("src");
|
|
49
|
+
expect(lines[3]).toContain("file-01.ts (+1)");
|
|
50
|
+
// Diff content should be visible somewhere in the frame
|
|
51
|
+
expect(frame).toContain("line0");
|
|
52
|
+
});
|
|
53
|
+
it("shows only the current file in diff pane", async () => {
|
|
54
|
+
const parsedFiles = [
|
|
55
|
+
createParsedFile("README.md", 0),
|
|
56
|
+
createParsedFile("src/file-01.ts", 1),
|
|
57
|
+
createParsedFile("src/file-02.ts", 2),
|
|
58
|
+
];
|
|
59
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
60
|
+
width: 120,
|
|
61
|
+
height: 12,
|
|
62
|
+
});
|
|
63
|
+
await act(async () => {
|
|
64
|
+
await testSetup.renderOnce();
|
|
65
|
+
});
|
|
66
|
+
const frame = testSetup.captureCharFrame();
|
|
67
|
+
// Should show first file's content
|
|
68
|
+
expect(frame).toContain("line0");
|
|
69
|
+
// Should NOT show other files' content
|
|
70
|
+
expect(frame).not.toContain("file-01.ts +1-0");
|
|
71
|
+
expect(frame).not.toContain("file-02.ts +1-0");
|
|
72
|
+
});
|
|
73
|
+
it("toggles sidebar visibility with b key", async () => {
|
|
74
|
+
const parsedFiles = [
|
|
75
|
+
createParsedFile("README.md", 0),
|
|
76
|
+
createParsedFile("src/file-01.ts", 1),
|
|
77
|
+
];
|
|
78
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
79
|
+
width: 120,
|
|
80
|
+
height: 12,
|
|
81
|
+
});
|
|
82
|
+
await act(async () => {
|
|
83
|
+
await testSetup.renderOnce();
|
|
84
|
+
});
|
|
85
|
+
// Sidebar is visible initially
|
|
86
|
+
const before = testSetup.captureCharFrame();
|
|
87
|
+
expect(before).toContain("README.md (+1)");
|
|
88
|
+
// Press b to hide sidebar
|
|
89
|
+
testSetup.mockInput.pressKey("b");
|
|
90
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
91
|
+
await act(async () => {
|
|
92
|
+
await testSetup.renderOnce();
|
|
93
|
+
});
|
|
94
|
+
const hidden = testSetup.captureCharFrame();
|
|
95
|
+
// Sidebar content should no longer be visible in the frame
|
|
96
|
+
expect(hidden).not.toContain("README.md (+1)");
|
|
97
|
+
// Press b again to show sidebar
|
|
98
|
+
testSetup.mockInput.pressKey("b");
|
|
99
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
100
|
+
await act(async () => {
|
|
101
|
+
await testSetup.renderOnce();
|
|
102
|
+
});
|
|
103
|
+
const shown = testSetup.captureCharFrame();
|
|
104
|
+
expect(shown).toContain("README.md (+1)");
|
|
105
|
+
});
|
|
106
|
+
it("does not reopen sidebar when file picker selects a file", async () => {
|
|
107
|
+
const parsedFiles = [
|
|
108
|
+
createParsedFile("README.md", 0),
|
|
109
|
+
createParsedFile("src/file-01.ts", 1),
|
|
110
|
+
];
|
|
111
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
112
|
+
width: 120,
|
|
113
|
+
height: 12,
|
|
114
|
+
});
|
|
115
|
+
await act(async () => {
|
|
116
|
+
await testSetup.renderOnce();
|
|
117
|
+
});
|
|
118
|
+
// Hide sidebar
|
|
119
|
+
testSetup.mockInput.pressKey("b");
|
|
120
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
121
|
+
await act(async () => {
|
|
122
|
+
await testSetup.renderOnce();
|
|
123
|
+
});
|
|
124
|
+
const hidden = testSetup.captureCharFrame();
|
|
125
|
+
expect(hidden).not.toContain("README.md (+1)");
|
|
126
|
+
// Open file picker
|
|
127
|
+
testSetup.mockInput.pressKey("p");
|
|
128
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
129
|
+
await act(async () => {
|
|
130
|
+
await testSetup.renderOnce();
|
|
131
|
+
});
|
|
132
|
+
// Dropdown should be visible
|
|
133
|
+
const withDropdown = testSetup.captureCharFrame();
|
|
134
|
+
expect(withDropdown).toContain("Search files...");
|
|
135
|
+
// Select first option (README.md) with Enter
|
|
136
|
+
testSetup.mockInput.pressEnter();
|
|
137
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
138
|
+
await act(async () => {
|
|
139
|
+
await testSetup.renderOnce();
|
|
140
|
+
});
|
|
141
|
+
// Dropdown should close and sidebar should remain hidden
|
|
142
|
+
const afterSelect = testSetup.captureCharFrame();
|
|
143
|
+
expect(afterSelect).not.toContain("Search files...");
|
|
144
|
+
expect(afterSelect).not.toContain("README.md (+1)");
|
|
145
|
+
});
|
|
146
|
+
it("navigates files with j/k when sidebar is focused", async () => {
|
|
147
|
+
const parsedFiles = [
|
|
148
|
+
createParsedFile("README.md", 0),
|
|
149
|
+
createParsedFile("src/file-01.ts", 1),
|
|
150
|
+
createParsedFile("src/file-02.ts", 2),
|
|
151
|
+
];
|
|
152
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
153
|
+
width: 120,
|
|
154
|
+
height: 12,
|
|
155
|
+
});
|
|
156
|
+
await act(async () => {
|
|
157
|
+
await testSetup.renderOnce();
|
|
158
|
+
});
|
|
159
|
+
const initialFrame = testSetup.captureCharFrame();
|
|
160
|
+
expect(initialFrame).toContain("line0");
|
|
161
|
+
expect(initialFrame).not.toContain("Select theme");
|
|
162
|
+
// Sidebar is focused by default, press j to move to next file
|
|
163
|
+
testSetup.mockInput.pressKey("j");
|
|
164
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
165
|
+
await act(async () => {
|
|
166
|
+
await testSetup.renderOnce();
|
|
167
|
+
});
|
|
168
|
+
const afterJ = testSetup.captureCharFrame();
|
|
169
|
+
// Should show file 1's header
|
|
170
|
+
expect(afterJ).toContain("file-01.ts");
|
|
171
|
+
// Press k to move back to previous file
|
|
172
|
+
testSetup.mockInput.pressKey("k");
|
|
173
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
174
|
+
await act(async () => {
|
|
175
|
+
await testSetup.renderOnce();
|
|
176
|
+
});
|
|
177
|
+
const afterK = testSetup.captureCharFrame();
|
|
178
|
+
// Should show file 0's header
|
|
179
|
+
expect(afterK).toContain("README.md");
|
|
180
|
+
});
|
|
181
|
+
it("scrolls within single file with j/k when diff pane is focused", async () => {
|
|
182
|
+
// Create a single file with many lines
|
|
183
|
+
const parsedFiles = [
|
|
184
|
+
createParsedFile("src/large-file.ts", 0, 20),
|
|
185
|
+
];
|
|
186
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
187
|
+
width: 120,
|
|
188
|
+
height: 12,
|
|
189
|
+
});
|
|
190
|
+
await act(async () => {
|
|
191
|
+
await testSetup.renderOnce();
|
|
192
|
+
});
|
|
193
|
+
const before = testSetup.captureCharFrame();
|
|
194
|
+
expect(before).toContain("line0");
|
|
195
|
+
// Switch to diff pane focus
|
|
196
|
+
testSetup.mockInput.pressTab();
|
|
197
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
198
|
+
// Press j several times to scroll down within the file
|
|
199
|
+
for (let i = 0; i < 5; i++) {
|
|
200
|
+
testSetup.mockInput.pressKey("j");
|
|
201
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
202
|
+
}
|
|
203
|
+
await act(async () => {
|
|
204
|
+
await testSetup.renderOnce();
|
|
205
|
+
});
|
|
206
|
+
const afterJ = testSetup.captureCharFrame();
|
|
207
|
+
// After scrolling, frame should have changed
|
|
208
|
+
expect(afterJ).not.toBe(before);
|
|
209
|
+
});
|
|
210
|
+
it("file picker works after tab focus switch", async () => {
|
|
211
|
+
const parsedFiles = [
|
|
212
|
+
createParsedFile("README.md", 0),
|
|
213
|
+
createParsedFile("src/file-01.ts", 1),
|
|
214
|
+
];
|
|
215
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
216
|
+
width: 120,
|
|
217
|
+
height: 12,
|
|
218
|
+
});
|
|
219
|
+
await act(async () => {
|
|
220
|
+
await testSetup.renderOnce();
|
|
221
|
+
});
|
|
222
|
+
// Press tab to switch focus, then p to open picker
|
|
223
|
+
testSetup.mockInput.pressTab();
|
|
224
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
225
|
+
testSetup.mockInput.pressKey("p");
|
|
226
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
227
|
+
await act(async () => {
|
|
228
|
+
await testSetup.renderOnce();
|
|
229
|
+
});
|
|
230
|
+
// Press escape to close
|
|
231
|
+
testSetup.mockInput.pressEscape();
|
|
232
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
233
|
+
await act(async () => {
|
|
234
|
+
await testSetup.renderOnce();
|
|
235
|
+
});
|
|
236
|
+
// Should not crash; frame should be valid
|
|
237
|
+
const frame = testSetup.captureCharFrame();
|
|
238
|
+
expect(frame).toContain("README.md");
|
|
239
|
+
});
|
|
240
|
+
it("toggles folder collapse with l/h when sidebar is focused", async () => {
|
|
241
|
+
const parsedFiles = [
|
|
242
|
+
createParsedFile("src/file-01.ts", 0),
|
|
243
|
+
createParsedFile("src/file-02.ts", 1),
|
|
244
|
+
];
|
|
245
|
+
testSetup = await testRender(_jsx(App, { parsedFiles: parsedFiles }), {
|
|
246
|
+
width: 120,
|
|
247
|
+
height: 12,
|
|
248
|
+
});
|
|
249
|
+
await act(async () => {
|
|
250
|
+
await testSetup.renderOnce();
|
|
251
|
+
});
|
|
252
|
+
const initialFrame = testSetup.captureCharFrame();
|
|
253
|
+
expect(initialFrame).toContain("src");
|
|
254
|
+
expect(initialFrame).toContain("file-01.ts");
|
|
255
|
+
expect(initialFrame).toContain("file-02.ts");
|
|
256
|
+
// Focus is on file-01.ts (row 1). Press k to move to src folder (row 0).
|
|
257
|
+
testSetup.mockInput.pressKey("k");
|
|
258
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
259
|
+
await act(async () => {
|
|
260
|
+
await testSetup.renderOnce();
|
|
261
|
+
});
|
|
262
|
+
// Press l to collapse the folder
|
|
263
|
+
testSetup.mockInput.pressKey("l");
|
|
264
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
265
|
+
await act(async () => {
|
|
266
|
+
await testSetup.renderOnce();
|
|
267
|
+
});
|
|
268
|
+
const afterCollapse = testSetup.captureCharFrame();
|
|
269
|
+
// Sidebar shows closed folder icon, no TypeScript file icons
|
|
270
|
+
expect(afterCollapse).toContain("");
|
|
271
|
+
expect(afterCollapse).not.toContain("");
|
|
272
|
+
// Press h to expand the folder
|
|
273
|
+
testSetup.mockInput.pressKey("h");
|
|
274
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
275
|
+
await act(async () => {
|
|
276
|
+
await testSetup.renderOnce();
|
|
277
|
+
});
|
|
278
|
+
const afterExpand = testSetup.captureCharFrame();
|
|
279
|
+
// Sidebar shows open folder icon and TypeScript file icons again
|
|
280
|
+
expect(afterExpand).toContain("");
|
|
281
|
+
expect(afterExpand).toContain("");
|
|
282
|
+
});
|
|
283
|
+
});
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import "./patch-terminal-dimensions.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { type ParsedFile } from "./diff-utils.js";
|
|
5
|
+
export interface AppProps {
|
|
6
|
+
parsedFiles: ParsedFile[];
|
|
7
|
+
}
|
|
8
|
+
export declare function App({ parsedFiles }: AppProps): React.ReactNode;
|
|
9
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";AAOA,OAAO,gCAAgC,CAAC;AAoBxC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAgB/B,OAAO,EAoBN,KAAK,UAAU,EACf,MAAM,iBAAiB,CAAC;AAuIzB,MAAM,WAAW,QAAQ;IACxB,WAAW,EAAE,UAAU,EAAE,CAAC;CAC1B;AAKD,wBAAgB,GAAG,CAAC,EAAE,WAAW,EAAE,EAAE,QAAQ,GAAG,KAAK,CAAC,SAAS,CAuzB9D"}
|