@lamemind/loom-deck 0.50.0 → 0.51.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/cli.js CHANGED
@@ -8,7 +8,7 @@ import { rowIndexOfKey, selectedRow, } from './search.js';
8
8
  import { appendNote, appendPin, appendSessionRecord, appendTaskBinding, } from './task-index.js';
9
9
  import { assembleSessionList, firstSelectableId, moveSelection, neighborId, rowIndexOf, selectedSession, unpinLandingId, } from './session-list.js';
10
10
  import { cellWidth, launchLegend, LAUNCH_SEP, loadArchivableDays, loadIdentity, loadLaunch, } from './config.js';
11
- import { anchorFrame, enableMouse, FRAME_TEXT_COL, hitRegion, isWheel, LAUNCH_ROW, rowRegions, takeMouse, } from './mouse.js';
11
+ import { anchorFrame, enableMouse, FRAME_TEXT_COL, hitRegion, isWheel, LAUNCH_ROW, rowRegions, takeMouse, WHEEL_LINES, wheelDir, } from './mouse.js';
12
12
  import { cycleSessionView, cycleTaskView, selectSessionRows, selectTasks, sessionView, taskView, TASK_VIEWS, } from './pane-views.js';
13
13
  import { isCompact, layoutBudget, searchPreviewCapacity, windowRange, } from './viewport.js';
14
14
  import { cut, cutMiddle, sanitize, termWidth } from './width.js';
@@ -33,7 +33,7 @@ import { useSearchOverlay } from './overlays/search.js';
33
33
  import { useSheetOverlay } from './overlays/sheet.js';
34
34
  import { useAssignOverlay } from './overlays/assign.js';
35
35
  import { useProjectStatus } from './overlays/status.js';
36
- import { captures } from './input-modes.js';
36
+ import { captures, scrolls } from './input-modes.js';
37
37
  import { VERSION } from './version.js';
38
38
  // T116 — l'avviso della prima pressione di `^C`. La durata è INTERPOLATA dalla
39
39
  // finestra, non ricopiata: un numero scritto a mano in un testo che promette un
@@ -994,6 +994,15 @@ function Deck({ cwd, tasksPath, tasksDir }) {
994
994
  edit: onEditKey,
995
995
  purge: onPurgeKey,
996
996
  };
997
+ // T21 (mandata 2) — la ROTELLA, per i soli modi che scorrono un contenuto
998
+ // lungo (`SCROLLING_MODES`). Stessa forma di `MODE_KEYS`: un `Record` sul
999
+ // catalogo, quindi un modo dichiarato scorrevole senza uno scroll da chiamare
1000
+ // non compila. Il delta è in righe, col segno del verso.
1001
+ const MODE_WHEEL = {
1002
+ detail: sheet.scroll,
1003
+ status: status.scroll,
1004
+ reader: search.scrollReader,
1005
+ };
997
1006
  /**
998
1007
  * T21 — il MOUSE precede tutto, in ogni modo del deck.
999
1008
  *
@@ -1019,10 +1028,25 @@ function Deck({ cwd, tasksPath, tasksDir }) {
1019
1028
  });
1020
1029
  function onMouse(ev) {
1021
1030
  // Un click produce due eventi (pressione e rilascio): agire su entrambi
1022
- // spawnerebbe due volte. La rotella è mandata 2 qui scartata, non
1023
- // silenziosamente equiparata a un click. Il bottone si legge sui due bit
1024
- // bassi, perché gli alti portano i modificatori (shift/meta/ctrl).
1025
- if (!ev.press || isWheel(ev.button) || (ev.button & 3) !== 0)
1031
+ // spawnerebbe due volte. La rotella arriva come sola pressione, quindi il
1032
+ // filtro su `press` la lascia passare e non la dedoppia.
1033
+ if (!ev.press)
1034
+ return;
1035
+ if (isWheel(ev.button)) {
1036
+ // La rotella NON rientra dalla porta della tastiera come il click: nel
1037
+ // detail `↑↓` muovono il fuoco fra i campi (T117), non il testo, e il
1038
+ // tasto che scorre — `PgUp`/`PgDn` — ha la granularità sbagliata per una
1039
+ // tacca. Va quindi allo scroll del modo, in righe. Fuori dai modi
1040
+ // scorrevoli è inerte: nelle liste la rotella non muove mai la
1041
+ // selezione (D5), e una tacca mentre il deck è sulla lista non deve
1042
+ // fare niente.
1043
+ if (scrolls(mode))
1044
+ MODE_WHEEL[mode](wheelDir(ev.button) * WHEEL_LINES);
1045
+ return;
1046
+ }
1047
+ // Il bottone si legge sui due bit bassi, perché gli alti portano i
1048
+ // modificatori (shift/meta/ctrl).
1049
+ if ((ev.button & 3) !== 0)
1026
1050
  return;
1027
1051
  // Le superfici esistono solo nella lista: un modo capturing prende il
1028
1052
  // frame intero e a quella riga c'è dell'altro.
@@ -55,3 +55,23 @@ export function captures(mode) {
55
55
  export const CTRL_DEROGATIONS = {
56
56
  detail: ['f'],
57
57
  };
58
+ /**
59
+ * T21 (mandata 2) — i modi che SCORRONO un contenuto lungo, cioè gli unici in
60
+ * cui la rotella del mouse fa qualcosa.
61
+ *
62
+ * La rotella scorre il TESTO, mai la selezione di una lista (D5): nelle liste
63
+ * la selezione è un'intenzione — la riga su cui si preme `⏎` — e una rotella
64
+ * che la muovesse trasformerebbe ogni sfioramento in una scelta. Nei tre modi
65
+ * qui sotto lo scroll non sceglie niente, è solo posizione di lettura. Non
66
+ * coincide con «ha un documento a schermo»: `search` mostra un'anteprima, ma
67
+ * il fuoco lì è sulla lista dei risultati, che è una selezione.
68
+ *
69
+ * Il custode è `MODE_WHEEL` in `cli.tsx`, un `Record<ScrollingMode, …>` che non
70
+ * compila se un modo entra qui senza uno scroll da chiamare.
71
+ */
72
+ export const SCROLLING_MODES = ['detail', 'status', 'reader'];
73
+ const SCROLLING = new Set(SCROLLING_MODES);
74
+ /** `true` se la rotella scorre il contenuto del modo. */
75
+ export function scrolls(mode) {
76
+ return SCROLLING.has(mode);
77
+ }
package/dist/mouse.js CHANGED
@@ -32,6 +32,28 @@ const SGR_MOUSE = /\x1b?\[<(\d+);(\d+);(\d+)([Mm])/g;
32
32
  export function isWheel(button) {
33
33
  return (button & 64) !== 0;
34
34
  }
35
+ /**
36
+ * Verso della rotella: `-1` su (codice 64), `+1` giù (65), `0` se non è una
37
+ * rotella. Il verso sta nel bit 0, i modificatori nei bit 2-4 (shift/meta/
38
+ * ctrl): `66`/`67` sono le rotelle orizzontali, che qui valgono `0` perché il
39
+ * deck non ha nulla da scorrere in orizzontale.
40
+ *
41
+ * Un terminale manda la rotella come SOLA pressione (`M`), mai seguita da un
42
+ * rilascio: un tacca = un evento, e il chiamante non deve dedoppiare come fa
43
+ * per il click.
44
+ */
45
+ export function wheelDir(button) {
46
+ if (!isWheel(button) || (button & 2) !== 0)
47
+ return 0;
48
+ return (button & 1) === 0 ? -1 : 1;
49
+ }
50
+ /**
51
+ * Righe scorse per tacca di rotella nei contenuti lunghi (detail, project
52
+ * status, reader). Tre è la convenzione dei terminali e dei browser: una tacca
53
+ * a riga singola costringe a girare la rotella quanto basta a stancare la mano,
54
+ * una a pagina salta il testo che si stava leggendo.
55
+ */
56
+ export const WHEEL_LINES = 3;
35
57
  /**
36
58
  * Separa le sequenze mouse dal testo di un chunk di `useInput`.
37
59
  *
@@ -255,5 +255,6 @@ export function useSearchOverlay(deps) {
255
255
  open,
256
256
  onReaderKey,
257
257
  onSearchKey,
258
+ scrollReader,
258
259
  };
259
260
  }
@@ -286,5 +286,6 @@ export function useSheetOverlay(deps) {
286
286
  occCur,
287
287
  open,
288
288
  onKey,
289
+ scroll,
289
290
  };
290
291
  }
@@ -155,5 +155,6 @@ export function useProjectStatus(deps) {
155
155
  generate,
156
156
  open,
157
157
  onKey,
158
+ scroll,
158
159
  };
159
160
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamemind/loom-deck",
3
- "version": "0.50.0",
3
+ "version": "0.51.0",
4
4
  "description": "Deck TUI Ink per-progetto della famiglia loom: legge tasks.md e spawna sessioni Claude Code bound via LOOM_TASK",
5
5
  "type": "module",
6
6
  "bin": {