@xynogen/pix-toolbox 0.1.8 → 0.1.9

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/toolbox.ts +41 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xynogen/pix-toolbox",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Pi tool — gated tool toggle UI (/toolbox)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
package/src/toolbox.ts CHANGED
@@ -34,7 +34,13 @@ import {
34
34
  type TUI,
35
35
  visibleWidth,
36
36
  } from "@earendil-works/pi-tui";
37
- import { frameLines, modalWidth } from "@xynogen/pix-pretty/modal-frame";
37
+ import {
38
+ frameModal,
39
+ MIN_MODAL_HEIGHT,
40
+ ModalPager,
41
+ modalWidth,
42
+ terminalModalHeight,
43
+ } from "@xynogen/pix-pretty/modal-frame";
38
44
 
39
45
  // ─── Constants ──────────────────────────────────────────────────────────────
40
46
 
@@ -334,7 +340,7 @@ export default function registerToolbox(pi: ExtensionAPI): void {
334
340
  };
335
341
  }): Promise<void> {
336
342
  await ctx.ui.custom<null>(
337
- (tui: TUI, theme: Theme, _kb: KeybindingsManager, done: (r: null) => void) => {
343
+ (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (r: null) => void) => {
338
344
  const accent = "accent";
339
345
  const mute = (s: string) => theme.fg("muted", s);
340
346
 
@@ -371,7 +377,7 @@ export default function registerToolbox(pi: ExtensionAPI): void {
371
377
 
372
378
  const list = new SelectList(
373
379
  allItems,
374
- Math.min(allItems.length, 14),
380
+ Math.max(1, allItems.length),
375
381
  {
376
382
  selectedPrefix: (t: string) => theme.fg(accent, t),
377
383
  selectedText: (t: string) => theme.fg(accent, t),
@@ -393,6 +399,7 @@ export default function registerToolbox(pi: ExtensionAPI): void {
393
399
 
394
400
  const search = new Input();
395
401
  let statusText = "";
402
+ const pager = new ModalPager();
396
403
 
397
404
  const refreshLabels = () => {
398
405
  for (const it of internal.items) {
@@ -442,30 +449,48 @@ export default function registerToolbox(pi: ExtensionAPI): void {
442
449
  render(w: number) {
443
450
  const mw = modalWidth(w);
444
451
  const inner = mw - 4; // CHROME = 2 border + 2 padding
445
- const lines: string[] = [
446
- theme.fg(accent, theme.bold("🧰 Toolbox")),
447
- theme.fg("muted", "Search:"),
448
- ...search.render(inner),
449
- ...list.render(inner),
450
- ];
451
- if (statusText) lines.push(statusText);
452
- lines.push(
453
- theme.fg("dim", "↑↓ navigate · e enable · d disable · space toggle · esc close"),
452
+ const footer = statusText ? [statusText] : [];
453
+ footer.push(
454
+ theme.fg(
455
+ "dim",
456
+ "↑↓ navigate · ←→/PgUp/PgDn inspect · e enable · d disable · space toggle · esc close",
457
+ ),
454
458
  );
455
- return frameLines({
459
+ const result = frameModal({
456
460
  width: mw,
457
- lines,
461
+ maxHeight: terminalModalHeight(tui.terminal.rows),
462
+ minHeight: MIN_MODAL_HEIGHT,
463
+ header: [
464
+ theme.fg(accent, theme.bold("🧰 Toolbox")),
465
+ theme.fg("muted", "Search:"),
466
+ ...search.render(inner),
467
+ ],
468
+ body: list.render(inner),
469
+ selectedBodyRange: pager.selectedRange({
470
+ start: internal.selectedIndex,
471
+ end: internal.selectedIndex + 1,
472
+ }),
473
+ footer,
474
+ bodyOffset: pager.bodyOffset,
458
475
  color: (s) => theme.fg(accent, s),
459
476
  bg: (s) => theme.bg("customMessageBg", s),
477
+ fg: (s) => theme.fg("text", s),
460
478
  });
479
+ pager.sync(result);
480
+ return result.lines;
461
481
  },
462
482
  invalidate() {
463
483
  list.invalidate();
464
484
  search.invalidate();
465
485
  },
466
486
  handleInput(data: string) {
487
+ if (pager.handleInput(data, keybindings, true)) {
488
+ tui.requestRender?.();
489
+ return;
490
+ }
467
491
  if (matchesKey(data, Key.up) || matchesKey(data, Key.down)) {
468
492
  list.handleInput?.(data);
493
+ pager.followSelection();
469
494
  } else if (matchesKey(data, Key.enter) || matchesKey(data, Key.escape)) {
470
495
  done(null);
471
496
  return;
@@ -481,10 +506,12 @@ export default function registerToolbox(pi: ExtensionAPI): void {
481
506
  } else {
482
507
  search.handleInput?.(data);
483
508
  applyFilter(search.getValue?.() ?? "");
509
+ pager.followSelection();
484
510
  }
485
511
  } else {
486
512
  search.handleInput?.(data);
487
513
  applyFilter(search.getValue?.() ?? "");
514
+ pager.followSelection();
488
515
  }
489
516
  }
490
517
  list.invalidate();