@mt-gloss/ui 0.1.72 → 0.1.74

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.
@@ -1,66 +0,0 @@
1
- import { ResizeState, ResizeDirection } from './useEdgeHoverResize';
2
- export interface EdgeHoverHandleProps {
3
- state: ResizeState;
4
- onPointerDown: (e: React.PointerEvent) => void;
5
- onPointerUp: (e: React.PointerEvent) => void;
6
- /**
7
- * Bug E (260417-drag-resize-5th-attempt) — handle's own pointerenter/leave
8
- * keeps the edge-hover zone alive when pointer crosses from sentinel to
9
- * handle (they're siblings, so sentinel.pointerleave would otherwise collapse
10
- * state to idle, hiding the handle mid-gesture).
11
- */
12
- onPointerEnter?: () => void;
13
- onPointerLeave?: (e: React.PointerEvent) => void;
14
- /**
15
- * D-13 — right-edge resize only. Left-edge support dropped (CONTEXT D-13);
16
- * narrowed to the literal 'right'. Prop retained so downstream data-edge
17
- * attributes and future bidirectional revival can slot in without a
18
- * breaking API change.
19
- */
20
- edge?: 'right';
21
- /** D-16 — keyboard step handler (ArrowLeft → 'shrink', ArrowRight → 'grow'). */
22
- onKeyboardStep?: (direction: ResizeDirection) => void;
23
- /**
24
- * Quick 260422-gfr — fires when the browser implicitly releases pointer
25
- * capture from the <button> (window blur / Alt-Tab / modal focus steal /
26
- * touchcancel). Consumers wire this to the hook's `cancel()` so the gesture
27
- * deterministically exits `'dragging'` on capture loss. Companion to the
28
- * window-level blur / visibilitychange / pointercancel listeners installed
29
- * inside useEdgeHoverResize. See .planning/debug/resize-state-leak-cross-card.md.
30
- */
31
- onLostPointerCapture?: (e: React.PointerEvent) => void;
32
- ariaLabel?: string;
33
- }
34
- /**
35
- * EdgeHoverHandle — Corner/edge handle affordance for the resize gesture.
36
- *
37
- * Visibility is derived from resize state: only visible when state is
38
- * 'handle-visible', 'dragging', or 'settling'. Invisible at 'idle' to avoid
39
- * colliding with the chip-menu click target on the value/row area.
40
- *
41
- * Motion contract (AN-06): opacity transitions driven by edge-hover.scss
42
- * using enterMs=180ms (enter) / exitMs=120ms (exit via ghost-preview).
43
- *
44
- * Pointer capture (debug 260417-qt00z / D-02+D-03 root cause): the handle is
45
- * only 10px wide. On pointerdown we call setPointerCapture(pointerId) so all
46
- * subsequent pointermove/pointerup events route to this element even after
47
- * the cursor leaves the handle's hit region. Without this, dragging rightward
48
- * (the natural grow gesture) moves the pointer off the handle within the
49
- * first few px — pointerup then fires on whatever is underneath, the handle's
50
- * React onPointerUp never runs, and the state machine stays stuck at
51
- * 'dragging' (so onResize is never called and the card never commits).
52
- *
53
- * Cross-card gesture suppression (260503-aff): during ANY drag/resize, the
54
- * resize handles on NON-source cards must hide so they don't compete with
55
- * the in-flight gesture's chrome. Achieved by AND-gating ONLY the
56
- * `'handle-visible'` branch on `useAffordanceVisibility().affordancesVisible`.
57
- * The `'dragging'` and `'settling'` branches stay un-gated to preserve the
58
- * SOURCE card's pointer-capture invariant — the source card's own handle MUST
59
- * remain visible (and pointer-capture-eligible) throughout its own gesture,
60
- * regardless of `affordancesVisible`. Non-source cards sit at
61
- * `'handle-visible'` or earlier, so when `affordancesVisible=false` (during
62
- * any global gesture + 200ms idle dwell), they hide. After the global
63
- * gesture settles back to idle and the dwell elapses, all handles re-emerge
64
- * together with the rest of the affordance chrome.
65
- */
66
- export declare const EdgeHoverHandle: import('react').ForwardRefExoticComponent<EdgeHoverHandleProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -1,93 +0,0 @@
1
- /**
2
- * NYQUIST-10 — Phase 19.2 Cross-Card Hover-State Unification behavior matrix fixture.
3
- *
4
- * Parametrized behavior definitions that the NYQUIST-10 runner iterates over
5
- * via `it.each(BEHAVIOR_MATRIX)`. Each row pins one contract-level invariant
6
- * asserted by Phase 19.2 plans 19.2-01 / 19.2-02 / 19.2-03. The matrix acts as a
7
- * high-level regression net: if a future wave regresses ANY of the 10 rows,
8
- * the runner fails with a specific row label even if the underlying test
9
- * file lives elsewhere.
10
- *
11
- * Orthogonal axes (per VALIDATION.md §Orthogonal Sampling Matrix):
12
- * - gridSize: 3 | 6 | 9 cards (leak-rate scaling)
13
- * - intervalMs: 8 | 16 | 32 ms (event interval vs frame boundary)
14
- * - eventCount: 10 | 20 | 40 (min signal / debug baseline / worst case)
15
- * - cardType: standard | stackable | mixed (StackedGroupCard hover unit)
16
- * - dndActive: boolean (dnd-kit drag suppression, RESEARCH Pitfall 4)
17
- * - reducedMotion: boolean (prefers-reduced-motion parity)
18
- *
19
- * Row-count pin: the runner asserts exactly 10 rows so that accidentally
20
- * dropping or silently renaming a behavior fails fast.
21
- *
22
- * Invariant each row asserts (after 200ms settle — D-16):
23
- * 1. ≤1 card has `[data-visible="true"]` on its ActionStrip
24
- * 2. Every non-hovered card's `useEdgeHoverResize` state === 'idle'
25
- * 3. `hoveredCardId === expectedFinalCardId || null`
26
- * 4. `vi.getTimerCount() === 0`
27
- *
28
- * @see .planning/phases/19.2-cross-card-hover-state-unification/19.2-CONTEXT.md (D-16, D-17, D-18)
29
- * @see .planning/phases/19.2-cross-card-hover-state-unification/19.2-VALIDATION.md §Orthogonal Sampling Matrix
30
- * @see .planning/phases/19.2-cross-card-hover-state-unification/19.2-PATTERNS.md Analog 8 (nyquist-11-fixtures.ts)
31
- */
32
- export interface NyquistHarness {
33
- /** Root grid container element (for dispatchEvent). */
34
- gridRoot: HTMLElement;
35
- /** Ordered list of card root elements (each has data-instance-id). */
36
- cards: HTMLElement[];
37
- /**
38
- * Returns current hoveredCardId value from the grid (reads from
39
- * data-hovered-card-id attribute on root, or a test-only prop hook).
40
- */
41
- getHoveredCardId: () => string | null;
42
- /**
43
- * Returns the useEdgeHoverResize state for a given card id — reads
44
- * data-resize-state attribute from slot root.
45
- */
46
- getEdgeHoverStateFor: (cardId: string) => string;
47
- /** Cleanup harness-mounted DOM. */
48
- unmount: () => void;
49
- }
50
- export interface BehaviorParams {
51
- gridSize: 3 | 6 | 9;
52
- intervalMs: 8 | 16 | 32;
53
- eventCount: 10 | 20 | 40;
54
- cardType: 'standard' | 'stackable' | 'mixed';
55
- dndActive: boolean;
56
- reducedMotion: boolean;
57
- }
58
- export interface BehaviorDef {
59
- /** 1-indexed for human readability in test output. */
60
- id: number;
61
- /** Short, greppable label. */
62
- label: string;
63
- /** Orthogonal axis values for this row. */
64
- params: BehaviorParams;
65
- /**
66
- * The contract invariant this row pins. Either an assert-lambda that the
67
- * runner invokes inside `it.each`, or `null` when the row is documented as
68
- * covered by a sibling test file (runner skips but keeps the row in the
69
- * matrix count pin). Wave 0 ships with `null` assert bodies; Task 2 wires
70
- * the invariant body via it.each + harness mount, NOT via these callbacks.
71
- */
72
- assert: ((harness: NyquistHarness) => Promise<void>) | null;
73
- /**
74
- * When present, the runner skips the row with the returned reason string
75
- * instead of calling `assert`. Used to document rows whose contract is
76
- * pinned by a dedicated sibling test file (cross-reference maintained in
77
- * 19.2-VALIDATION.md).
78
- */
79
- skipFor?: () => string | undefined;
80
- }
81
- /**
82
- * The 10 NYQUIST-10 behaviors. Each row's `assert` is `null` in Wave 0; the
83
- * invariant body lives in hoveredCardId.invariant.test.tsx driven by
84
- * `it.each(BEHAVIOR_MATRIX)`. Rows remain in the matrix so the row-count pin
85
- * (10) catches silent drops or reorder.
86
- */
87
- export declare const BEHAVIOR_MATRIX: BehaviorDef[];
88
- /**
89
- * Row-count pin — NYQUIST-10 runner asserts exactly this number of rows.
90
- * Changing the behavior set requires updating this constant and adding a
91
- * line in 19.2-VALIDATION.md §Orthogonal Sampling Matrix.
92
- */
93
- export declare const BEHAVIOR_ROW_COUNT = 10;
@@ -1,130 +0,0 @@
1
- import { MotionValue } from 'motion/react';
2
- import { ResizePhysicsConfig } from './resizePhysics';
3
- export type ResizeState = 'idle' | 'dwelling' | 'handle-visible' | 'dragging' | 'settling' | 'cancelled';
4
- export type ResizeDirection = 'grow' | 'shrink';
5
- export type ResizeMode = 'slot-fill' | 'sparkline-fidelity';
6
- export interface ResizeCommit {
7
- direction: ResizeDirection;
8
- targetColSpan: 1 | 2 | 3;
9
- mode: ResizeMode;
10
- }
11
- export interface UseEdgeHoverResizeArgs {
12
- currentColSpan: 1 | 2 | 3;
13
- stackable: boolean;
14
- onResize: (commit: ResizeCommit) => void;
15
- onCancel?: () => void;
16
- /** D-14 — colWidth snapshot passed per-render; captured at pointerdown. Default: 180px (1280px viewport). */
17
- step?: number;
18
- /**
19
- * Grid gap (px) between adjacent columns. Used to compute the ghost's
20
- * left-anchored width as `colSpan * step + (colSpan - 1) * gap`. Default: 0
21
- * (single-column grids). Rework 260419-v2 — ghost is width-driven, not
22
- * translateX-driven; this is the companion scalar.
23
- */
24
- gap?: number;
25
- /** D-03 panel override; falls back to DEFAULT_RESIZE_PHYSICS. */
26
- tuning?: Partial<ResizePhysicsConfig>;
27
- /** Hover dwell time before handle appears. Default: 60ms */
28
- dwellMs?: number;
29
- /**
30
- * Grace period (ms) after pointer leaves the edge zone before collapsing to idle.
31
- * Prevents the handle from disappearing on brief mouse-off during natural mouse
32
- * movement (e.g. crossing the sentinel/handle gap). Default: 150ms.
33
- */
34
- graceExitMs?: number;
35
- /** AN-06 enter motion duration exposed for consumer CSS. Default: 180ms */
36
- enterMs?: number;
37
- /** AN-06 exit motion duration exposed for consumer CSS. Default: 120ms */
38
- exitMs?: number;
39
- /**
40
- * Max colSpan supported by the grid (D-13 — right-edge-only grow). Default: 3.
41
- * Used to clamp ghostWidth writes during drag so the ghost cannot grow
42
- * past the maximum-allowed column width at any cursor position (debug
43
- * session 260419-ghost-slides-across-page — AP-17 companion invariant).
44
- *
45
- * Bug fix 260420-resize-past-sections — this cap is now enforced on the
46
- * COMMIT path as well (onPointerUp + onKeyboardStep + hysteresisSnap).
47
- * Previously only the live ghost width was clamped; onPointerUp passed
48
- * raw `dx` to hysteresisSnap whose forward walk + final clamp used a
49
- * hardcoded `3`, letting fast drags commit `targetColSpan = 3` past the
50
- * section boundary.
51
- */
52
- maxColSpan?: 1 | 2 | 3;
53
- /**
54
- * Phase 19.2 D-04 — grid-driven synchronous idle reset.
55
- *
56
- * When `true`, the hook synchronously clears pending dwell/touch-idle
57
- * timers and transitions state to `'idle'`. Protects the drag grip:
58
- * no-op during `'dragging'` or `'settling'` states (pointer-captured;
59
- * spring owns settle; see D-05 + D-11 + debug/260419-hover-state-stuck-multi-card.md).
60
- *
61
- * Replaces the legacy "Polish Fix #7" window-pointermove self-heal
62
- * (now deleted — grid-driven beats window-driven; D-04 ¶2).
63
- *
64
- * Prop-driven only. DO NOT add a ref-based imperative path (D-05).
65
- *
66
- * @default undefined (treated as false — hook runs normally)
67
- */
68
- forceIdle?: boolean;
69
- }
70
- export interface UseEdgeHoverResizeReturn {
71
- state: ResizeState;
72
- enterEdgeZone: () => void;
73
- leaveEdgeZone: () => void;
74
- handleProps: {
75
- onPointerDown: (e: React.PointerEvent) => void;
76
- onPointerUp: (e: React.PointerEvent) => void;
77
- onPointerEnter: () => void;
78
- onPointerLeave: () => void;
79
- };
80
- /**
81
- * Live preview during drag. Always clamped to 1..3.
82
- * Reflects the colSpan the user would commit at the current cursor position,
83
- * with hysteresis snap (D-06).
84
- */
85
- previewColSpan: 1 | 2 | 3;
86
- ghostProps: {
87
- visible: boolean;
88
- targetColSpan: 1 | 2 | 3;
89
- /**
90
- * D-07 rework 260419-v2 — MotionValue driving ghost WIDTH (left-anchored).
91
- * The ghost LEFT edge is pinned at the slot origin; the ghost RIGHT edge
92
- * follows the cursor; `ghostWidth` carries that width imperatively with
93
- * zero React re-renders per pointermove. Supersedes the prior `motionX`
94
- * translateX semantic (which slid the entire ghost horizontally — see
95
- * debug session 260419-ghost-slides-across-page).
96
- */
97
- ghostWidth: MotionValue<number>;
98
- enterMs: number;
99
- exitMs: number;
100
- };
101
- /** D-16 — keyboard resize step (grow/shrink by 1) on focused handle. */
102
- onKeyboardStep: (direction: ResizeDirection) => void;
103
- /** D-19 — touch tap-to-reveal: show handle immediately on touch pointerdown on card body. */
104
- onTouchReveal: () => void;
105
- /** D-19 — outside-tap dismissal for touch. */
106
- onTouchDismiss: () => void;
107
- /** D-18 — cancel (used by parent; springs back if dragging). */
108
- cancel: () => void;
109
- }
110
- /**
111
- * useEdgeHoverResize — Phase 19 reworked state machine for edge-hover-to-resize.
112
- *
113
- * Changes vs Phase 10.5 original:
114
- * - MotionValue ghost tracking (D-07) — zero React re-renders per pointermove
115
- * - Hysteresis snap (D-06) replaces Math.round(dx/step)
116
- * - Velocity ring buffer (D-09) feeds spring commit
117
- * - Spring commit via framer-motion animate() (D-08: stiffness 500, damping 22, mass 1 — retuned 260419 for visible overshoot, was damping 35)
118
- * - 'settling' state (D-12) hard-blocks re-engagement during spring
119
- * - committed state removed (D-05) — rolls into settling → idle
120
- * - Keyboard step (D-16): onKeyboardStep('grow'|'shrink')
121
- * - Escape spring-back with cursor velocity (D-15)
122
- * - Touch tap-to-reveal with 5s idle (D-19)
123
- * - prefers-reduced-motion bypass (D-22) — instant transform
124
- *
125
- * Preserved invariants:
126
- * - Bug A React 19 updater purity — side effects fire OUTSIDE setState updaters
127
- * - Bug E handle pointerenter keeps zone alive on sentinel→handle crossover
128
- * - Dwell timer cleanup on unmount
129
- */
130
- export declare function useEdgeHoverResize({ currentColSpan, stackable, onResize, onCancel, step, gap, tuning, dwellMs, graceExitMs, enterMs, exitMs, maxColSpan, forceIdle, }: UseEdgeHoverResizeArgs): UseEdgeHoverResizeReturn;