ispbills-icli 8.4.10 → 8.4.11
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/package.json +1 -1
- package/src/tui/app.js +34 -15
package/package.json
CHANGED
package/src/tui/app.js
CHANGED
|
@@ -131,41 +131,60 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, ve
|
|
|
131
131
|
});
|
|
132
132
|
|
|
133
133
|
// ── Mouse event handling ────────────────────────────────────────────────────
|
|
134
|
-
// Tab bar
|
|
135
|
-
//
|
|
136
|
-
//
|
|
134
|
+
// Tab bar x-ranges (1-indexed). Layout: paddingX=1 on the TabBar outer Box
|
|
135
|
+
// so text starts at column 2. Each tab = 2-char prefix (' ' or '❯ ') +
|
|
136
|
+
// label text, followed by marginRight=2 before the next tab.
|
|
137
137
|
const tabClickRanges = useMemo(() => {
|
|
138
|
-
let x = 2; // paddingX=1 → first
|
|
138
|
+
let x = 2; // paddingX=1 → first tab starts at column 2
|
|
139
139
|
return TABS.map((label) => {
|
|
140
140
|
const start = x;
|
|
141
|
-
const w = 2 + label.length; //
|
|
142
|
-
x += w + 2; // +
|
|
141
|
+
const w = 2 + label.length; // prefix (2 chars) + label
|
|
142
|
+
x += w + 2; // advance past tab + marginRight=2
|
|
143
143
|
return { start, end: start + w - 1 };
|
|
144
144
|
});
|
|
145
145
|
}, []);
|
|
146
146
|
|
|
147
147
|
useEffect(() => {
|
|
148
|
-
const TAB_ROW = 1; // y=1 in SGR coords (first row)
|
|
149
|
-
|
|
150
148
|
const onMouse = ({ btn, x, y, press }) => {
|
|
151
|
-
// ── Scroll wheel UP → scroll
|
|
149
|
+
// ── Scroll wheel UP → scroll viewport to reveal history ──────────────
|
|
152
150
|
if (btn === 64) {
|
|
153
151
|
try { process.stdout.write('\x1b[3S'); } catch {}
|
|
154
152
|
return;
|
|
155
153
|
}
|
|
156
|
-
// ── Scroll wheel DOWN → swallowed
|
|
154
|
+
// ── Scroll wheel DOWN → swallowed ─────────────────────────────────────
|
|
157
155
|
if (btn === 65) return;
|
|
158
156
|
|
|
159
|
-
// ── Left click
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
// ── Left click → tab bar ─────────────────────────────────────────────
|
|
158
|
+
// Ink renders INLINE at the bottom of the terminal — NOT at y=1.
|
|
159
|
+
// SGR y coordinates are 1-indexed from the terminal top.
|
|
160
|
+
//
|
|
161
|
+
// Layout rows at idle (bottom-to-top):
|
|
162
|
+
// rows = footer hint
|
|
163
|
+
// rows-1 = composer bottom border
|
|
164
|
+
// rows-2 = composer input
|
|
165
|
+
// rows-3 = composer top border
|
|
166
|
+
// rows-4 = blank (marginTop=1 before composer)
|
|
167
|
+
// rows-5 = tab separator
|
|
168
|
+
// rows-6 = tab labels ← TAB_ROW at idle
|
|
169
|
+
// rows-7 = compact header
|
|
170
|
+
//
|
|
171
|
+
// When there is live content of height h between tab separator and
|
|
172
|
+
// composer, each row shifts up by h: TAB_ROW = rows - 6 - liveH.
|
|
173
|
+
if (btn === 0 && press) {
|
|
174
|
+
const liveH = live
|
|
175
|
+
? 1 + Math.min((live.status?.length || 0) + (live.text ? 2 : 0) + (!live.text && !live.reply?.steps ? 1 : 0), 12)
|
|
176
|
+
: 0;
|
|
177
|
+
const tabRowY = rows - 6 - liveH;
|
|
178
|
+
if (Math.abs(y - tabRowY) <= 1) { // ±1 row tolerance
|
|
179
|
+
const idx = tabClickRanges.findIndex((r) => x >= r.start && x <= r.end);
|
|
180
|
+
if (idx >= 0) setActiveTab(idx);
|
|
181
|
+
}
|
|
163
182
|
}
|
|
164
183
|
};
|
|
165
184
|
|
|
166
185
|
mouseEvents.on('event', onMouse);
|
|
167
186
|
return () => mouseEvents.off('event', onMouse);
|
|
168
|
-
}, [tabClickRanges]);
|
|
187
|
+
}, [tabClickRanges, rows, live]);
|
|
169
188
|
|
|
170
189
|
const setAutopilotMode = useCallback((next) => {
|
|
171
190
|
apRef.current = next;
|