@mt-gloss/ui 0.0.42 → 0.0.44
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/index.d.ts +2 -0
- package/index.js +1405 -1063
- package/lib/primitives/dashboard/DevTuningPanel/DevTuningPanel.d.ts +13 -0
- package/lib/primitives/dashboard/DevTuningPanel/index.d.ts +11 -0
- package/lib/primitives/dashboard/DevTuningPanel/useResizeTuning.d.ts +47 -0
- package/lib/primitives/dashboard/MetricCard/EdgeHoverHandle.d.ts +12 -5
- package/lib/primitives/dashboard/MetricCard/GhostPreview.d.ts +8 -5
- package/lib/primitives/dashboard/MetricCard/__tests__/fixtures/nyquist-09-parity-matrix.d.ts +76 -0
- package/lib/primitives/dashboard/MetricCard/index.d.ts +4 -0
- package/lib/primitives/dashboard/MetricCard/resizePhysics.d.ts +19 -0
- package/lib/primitives/dashboard/MetricCard/useEdgeHoverResize.d.ts +44 -20
- package/lib/primitives/dashboard/MetricCard/velocityBuffer.d.ts +39 -0
- package/lib/primitives/dashboard/index.d.ts +1 -0
- package/package.json +1 -1
- package/ui.css +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface DevTuningPanelProps {
|
|
3
|
+
/**
|
|
4
|
+
* Reserved — optional DOM portal target. Not currently used; panel is
|
|
5
|
+
* position:fixed so it does not need a portal. Included in the public
|
|
6
|
+
* interface for forward compatibility.
|
|
7
|
+
*/
|
|
8
|
+
container?: HTMLElement;
|
|
9
|
+
}
|
|
10
|
+
export declare function DevTuningPanel(_props?: DevTuningPanelProps): React.ReactElement | null;
|
|
11
|
+
export declare namespace DevTuningPanel {
|
|
12
|
+
var displayName: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 19 Plan 02 — DevTuningPanel barrel export.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the dev-only Resize Tuning primitive + its localStorage-backed
|
|
5
|
+
* hook. Barrel is zero-side-effect; the SCSS is imported from
|
|
6
|
+
* `DevTuningPanel.tsx` so consumers that only import the hook pay no CSS cost.
|
|
7
|
+
*/
|
|
8
|
+
export { DevTuningPanel } from './DevTuningPanel';
|
|
9
|
+
export type { DevTuningPanelProps } from './DevTuningPanel';
|
|
10
|
+
export { useResizeTuning, TUNING_STORAGE_KEY, TUNING_DEFAULTS } from './useResizeTuning';
|
|
11
|
+
export type { UseResizeTuningReturn, TuningConfig } from './useResizeTuning';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** D-03 — exact localStorage key. */
|
|
2
|
+
export declare const TUNING_STORAGE_KEY = "resize.tuning.dev";
|
|
3
|
+
/**
|
|
4
|
+
* TUNING_DEFAULTS extends ResizePhysicsConfig with px-expressed snap thresholds
|
|
5
|
+
* that the UI surfaces (UI-SPEC §Surface 3 rows 4 & 5). The hook consumer
|
|
6
|
+
* converts to fractions at drag-start (`snapInFraction = snapInPx / step`).
|
|
7
|
+
* Defaults match DEFAULT_RESIZE_PHYSICS fraction math against the 180px GRID_STEP:
|
|
8
|
+
* snapInPx = 180 × 1/3 = 60
|
|
9
|
+
* snapOutPx = 180 × 1/2 = 90
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Raw defaults — declared as `as const` so the shape's keys are pinned, but
|
|
13
|
+
* `TuningConfig` below widens each field to `number` so downstream setters
|
|
14
|
+
* accept the full slider range (e.g. `snapOutPx: 110`), not just the literal
|
|
15
|
+
* default (`snapOutPx: 90`).
|
|
16
|
+
*/
|
|
17
|
+
declare const _TUNING_DEFAULTS_LITERAL: {
|
|
18
|
+
readonly snapInPx: 60;
|
|
19
|
+
readonly snapOutPx: 90;
|
|
20
|
+
readonly stiffness: 500;
|
|
21
|
+
readonly damping: 35;
|
|
22
|
+
readonly mass: 1;
|
|
23
|
+
readonly snapInFraction: number;
|
|
24
|
+
readonly snapOutFraction: number;
|
|
25
|
+
readonly blueprintOpacity: 0.25;
|
|
26
|
+
readonly blueprintFadeInMs: 150;
|
|
27
|
+
readonly blueprintFadeOutMs: 120;
|
|
28
|
+
readonly rippleStaggerMs: 50;
|
|
29
|
+
readonly velocityMultiplier: 1;
|
|
30
|
+
};
|
|
31
|
+
export type TuningConfig = {
|
|
32
|
+
-readonly [K in keyof typeof _TUNING_DEFAULTS_LITERAL]: number;
|
|
33
|
+
};
|
|
34
|
+
/** Public defaults — widened to `TuningConfig` so consumers can reassign. */
|
|
35
|
+
export declare const TUNING_DEFAULTS: TuningConfig;
|
|
36
|
+
export interface UseResizeTuningReturn {
|
|
37
|
+
/** Current tuning values (defaults merged with any persisted deltas). */
|
|
38
|
+
values: TuningConfig;
|
|
39
|
+
/** Update a single key; persists to localStorage. */
|
|
40
|
+
setValue<K extends keyof TuningConfig>(key: K, value: TuningConfig[K]): void;
|
|
41
|
+
/** Restore a single key to its TUNING_DEFAULTS value. */
|
|
42
|
+
resetRow<K extends keyof TuningConfig>(key: K): void;
|
|
43
|
+
/** Restore every key to TUNING_DEFAULTS. */
|
|
44
|
+
resetAll(): void;
|
|
45
|
+
}
|
|
46
|
+
export declare function useResizeTuning(): UseResizeTuningReturn;
|
|
47
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ResizeState } from './useEdgeHoverResize';
|
|
1
|
+
import { ResizeState, ResizeDirection } from './useEdgeHoverResize';
|
|
2
2
|
export interface EdgeHoverHandleProps {
|
|
3
3
|
state: ResizeState;
|
|
4
4
|
onPointerDown: (e: React.PointerEvent) => void;
|
|
@@ -11,16 +11,23 @@ export interface EdgeHoverHandleProps {
|
|
|
11
11
|
*/
|
|
12
12
|
onPointerEnter?: () => void;
|
|
13
13
|
onPointerLeave?: (e: React.PointerEvent) => void;
|
|
14
|
-
/**
|
|
15
|
-
|
|
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;
|
|
16
23
|
ariaLabel?: string;
|
|
17
24
|
}
|
|
18
25
|
/**
|
|
19
26
|
* EdgeHoverHandle — Corner/edge handle affordance for the resize gesture.
|
|
20
27
|
*
|
|
21
28
|
* Visibility is derived from resize state: only visible when state is
|
|
22
|
-
* 'handle-visible' or '
|
|
23
|
-
* with the chip-menu click target on the value/row area.
|
|
29
|
+
* 'handle-visible', 'dragging', or 'settling'. Invisible at 'idle' to avoid
|
|
30
|
+
* colliding with the chip-menu click target on the value/row area.
|
|
24
31
|
*
|
|
25
32
|
* Motion contract (AN-06): opacity transitions driven by edge-hover.scss
|
|
26
33
|
* using enterMs=180ms (enter) / exitMs=120ms (exit via ghost-preview).
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { MotionValue } from 'framer-motion';
|
|
1
2
|
export interface GhostPreviewProps {
|
|
2
|
-
/** Whether the ghost overlay is currently visible (active during drag). */
|
|
3
|
+
/** Whether the ghost overlay is currently visible (active during drag/settling). */
|
|
3
4
|
visible: boolean;
|
|
4
5
|
/** The target column span being previewed. */
|
|
5
6
|
targetColSpan: 1 | 2 | 3;
|
|
7
|
+
/** D-07 — MotionValue driving translateX. Zero React re-renders per pointermove. */
|
|
8
|
+
motionX: MotionValue<number>;
|
|
6
9
|
/** AN-06 enter duration in ms. Default: 180ms */
|
|
7
10
|
enterMs?: number;
|
|
8
11
|
/** AN-06 exit duration in ms. Default: 120ms */
|
|
@@ -11,14 +14,14 @@ export interface GhostPreviewProps {
|
|
|
11
14
|
/**
|
|
12
15
|
* GhostPreview — Dashed outline overlay rendered during an active resize drag.
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
+
* Phase 19 evolution: consumes a framer-motion MotionValue for translateX
|
|
18
|
+
* (D-07) so ghost tracks the cursor 1:1 without React re-renders on
|
|
19
|
+
* pointermove (AP-17). Opacity transitions still use CSS enterMs/exitMs.
|
|
17
20
|
*
|
|
18
21
|
* Hidden via aria-hidden — purely decorative visual feedback.
|
|
19
22
|
* Motion contract (AN-06): enter 180ms, exit 120ms.
|
|
20
23
|
*/
|
|
21
|
-
export declare function GhostPreview({ visible, targetColSpan, enterMs, exitMs, }: GhostPreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export declare function GhostPreview({ visible, targetColSpan, motionX, enterMs, exitMs, }: GhostPreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
22
25
|
export declare namespace GhostPreview {
|
|
23
26
|
var displayName: string;
|
|
24
27
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NYQUIST-09 Parity Matrix — Phase 19 plan 19-05.
|
|
3
|
+
*
|
|
4
|
+
* Typed array of 144 rows enumerating the 7-axis resize parity space:
|
|
5
|
+
*
|
|
6
|
+
* spring — 3 presets: default (S500D35M1), gentle (S300D30M1), stiff (S700D40M1)
|
|
7
|
+
* viewport — round-robin across [1280, 1920, 2560] (all 3 appear in asserted set)
|
|
8
|
+
* reducedMotion — {false, true}
|
|
9
|
+
* pointerType — {'mouse', 'touch'}
|
|
10
|
+
* cardMode — {'slot-fill', 'sparkline-fidelity'}
|
|
11
|
+
* cancelPath — {'commit', 'escape', 'out-of-range'}
|
|
12
|
+
* dndKitActive — {false, true}
|
|
13
|
+
*
|
|
14
|
+
* Arithmetic (per 19-RESEARCH §NYQUIST-09 Fixture Matrix):
|
|
15
|
+
* 3 × 2 × 2 × 2 × 3 × 2 = 144 logical rows.
|
|
16
|
+
* Viewport axis is DERIVED per-row (round-robin) so every asserted row still
|
|
17
|
+
* represents one of the 3 canonical viewports without multiplying the base
|
|
18
|
+
* by a 4th full axis — this matches the RESEARCH-stated 144 count exactly.
|
|
19
|
+
*
|
|
20
|
+
* SkipFor taxonomy (~84 rows tagged; first-match wins):
|
|
21
|
+
*
|
|
22
|
+
* Rule 1 — reducedMotion && spring === 'stiff':
|
|
23
|
+
* Reduced motion bypasses spring; stiffer preset collapses to same
|
|
24
|
+
* instant-jump code path as default. (default spring + gentle preset
|
|
25
|
+
* still carry the rm=true assertion to exercise the branch.)
|
|
26
|
+
*
|
|
27
|
+
* Rule 2 — pointerType === 'touch' && cancelPath === 'escape':
|
|
28
|
+
* Touch devices lack Escape key; covered by separate touch-pointercancel
|
|
29
|
+
* fixture (useEdgeHoverResize.touch.test.tsx).
|
|
30
|
+
*
|
|
31
|
+
* Rule 3 — cardMode === 'sparkline-fidelity' && dndKitActive:
|
|
32
|
+
* Non-stackable cards are not sortable; dnd-kit active state is
|
|
33
|
+
* impossible (invariant from PagesContext.tsx stack rules).
|
|
34
|
+
*
|
|
35
|
+
* Rule 4 — cancelPath === 'out-of-range' && !dndKitActive && spring !== default:
|
|
36
|
+
* Out-of-range clamp is independent of spring variant; default-spring row
|
|
37
|
+
* carries the clamp assertion. Non-default springs on the clamp path are
|
|
38
|
+
* redundant (physics variant does not affect Math.min(3, …) behavior).
|
|
39
|
+
*
|
|
40
|
+
* Asserted target: 60 ± 5 rows (plan acceptance criterion).
|
|
41
|
+
* Actual asserted: 63 / 144 (skipped 81). Viewport distribution across
|
|
42
|
+
* asserted rows: 1280 → 25, 1920 → 18, 2560 → 20 (all 3 represented).
|
|
43
|
+
*
|
|
44
|
+
* @see .planning/phases/19-resize-interaction-rework/19-RESEARCH.md §NYQUIST-09 Fixture Matrix
|
|
45
|
+
* @see .planning/phases/19-resize-interaction-rework/19-PATTERNS.md §S10 NYQUIST matrix authoring
|
|
46
|
+
* @see .planning/phases/19-resize-interaction-rework/19-05-PLAN.md Task 1
|
|
47
|
+
*/
|
|
48
|
+
export interface Nyquist09Row {
|
|
49
|
+
/**
|
|
50
|
+
* Stable row id, e.g. 'S500D35M1-vw1280-rm_off-mouse-stack-commit-dndk_on'.
|
|
51
|
+
* Shape: `S{stiffness}D{damping}M{mass}-vw{viewport}-rm_{on|off}-{pointer}-{stack|spark}-{cancelPath}-dndk_{on|off}`.
|
|
52
|
+
*/
|
|
53
|
+
id: string;
|
|
54
|
+
spring: {
|
|
55
|
+
stiffness: number;
|
|
56
|
+
damping: number;
|
|
57
|
+
mass: number;
|
|
58
|
+
};
|
|
59
|
+
viewport: 1280 | 1920 | 2560;
|
|
60
|
+
reducedMotion: boolean;
|
|
61
|
+
pointerType: 'mouse' | 'touch';
|
|
62
|
+
cardMode: 'slot-fill' | 'sparkline-fidelity';
|
|
63
|
+
cancelPath: 'commit' | 'escape' | 'out-of-range';
|
|
64
|
+
dndKitActive: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* If set, row is test.skip with this reason string. Acceptance criterion:
|
|
67
|
+
* skipped ≤ 84, asserted ≥ 55 (see PLAN threat-model T-19-16).
|
|
68
|
+
*/
|
|
69
|
+
skipFor?: string;
|
|
70
|
+
}
|
|
71
|
+
/** Canonical 144-row NYQUIST-09 parity matrix — enumerated explicitly for diff-ability. */
|
|
72
|
+
export declare const NYQUIST_09_MATRIX: readonly Nyquist09Row[];
|
|
73
|
+
/** Convenience: number of rows that actually run (skipFor === undefined). Exported for CI sanity check. */
|
|
74
|
+
export declare const NYQUIST_09_ASSERTED_COUNT: number;
|
|
75
|
+
/** Convenience: number of rows tagged skipFor. Exported for CI sanity check. */
|
|
76
|
+
export declare const NYQUIST_09_SKIPPED_COUNT: number;
|
|
@@ -10,6 +10,10 @@ export { EdgeHoverHandle } from './EdgeHoverHandle';
|
|
|
10
10
|
export { GhostPreview } from './GhostPreview';
|
|
11
11
|
export { useSlideOutReveal } from './useSlideOutReveal';
|
|
12
12
|
export { useEdgeHoverResize } from './useEdgeHoverResize';
|
|
13
|
+
export { DEFAULT_RESIZE_PHYSICS } from './resizePhysics';
|
|
14
|
+
export type { ResizePhysicsConfig } from './resizePhysics';
|
|
15
|
+
export { VelocityBuffer } from './velocityBuffer';
|
|
16
|
+
export type { VelocitySample } from './velocityBuffer';
|
|
13
17
|
export * from './flipAndStage';
|
|
14
18
|
export * from './types';
|
|
15
19
|
export type { CardBackProps } from './CardBack';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resizePhysics — D-08 / D-06 / D-11 / D-20 single source of truth.
|
|
3
|
+
*
|
|
4
|
+
* Constants consumed by both useEdgeHoverResize (spring commit) and the
|
|
5
|
+
* DevTuningPanel (Plan 19-02) so the panel and the hook never drift.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_RESIZE_PHYSICS: {
|
|
8
|
+
readonly stiffness: 500;
|
|
9
|
+
readonly damping: 35;
|
|
10
|
+
readonly mass: 1;
|
|
11
|
+
readonly snapInFraction: number;
|
|
12
|
+
readonly snapOutFraction: number;
|
|
13
|
+
readonly blueprintOpacity: 0.25;
|
|
14
|
+
readonly blueprintFadeInMs: 150;
|
|
15
|
+
readonly blueprintFadeOutMs: 120;
|
|
16
|
+
readonly rippleStaggerMs: 50;
|
|
17
|
+
readonly velocityMultiplier: 1;
|
|
18
|
+
};
|
|
19
|
+
export type ResizePhysicsConfig = typeof DEFAULT_RESIZE_PHYSICS;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { MotionValue } from 'framer-motion';
|
|
2
|
+
import { ResizePhysicsConfig } from './resizePhysics';
|
|
3
|
+
export type ResizeState = 'idle' | 'dwelling' | 'handle-visible' | 'dragging' | 'settling' | 'cancelled';
|
|
2
4
|
export type ResizeDirection = 'grow' | 'shrink';
|
|
3
5
|
export type ResizeMode = 'slot-fill' | 'sparkline-fidelity';
|
|
4
6
|
export interface ResizeCommit {
|
|
@@ -11,12 +13,23 @@ export interface UseEdgeHoverResizeArgs {
|
|
|
11
13
|
stackable: boolean;
|
|
12
14
|
onResize: (commit: ResizeCommit) => void;
|
|
13
15
|
onCancel?: () => void;
|
|
16
|
+
/** D-14 — colWidth snapshot passed per-render; captured at pointerdown. Default: 180px (1280px viewport). */
|
|
17
|
+
step?: number;
|
|
18
|
+
/** D-03 panel override; falls back to DEFAULT_RESIZE_PHYSICS. */
|
|
19
|
+
tuning?: Partial<ResizePhysicsConfig>;
|
|
14
20
|
/** Hover dwell time before handle appears. Default: 120ms */
|
|
15
21
|
dwellMs?: number;
|
|
16
22
|
/** AN-06 enter motion duration exposed for consumer CSS. Default: 180ms */
|
|
17
23
|
enterMs?: number;
|
|
18
24
|
/** AN-06 exit motion duration exposed for consumer CSS. Default: 120ms */
|
|
19
25
|
exitMs?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Max colSpan supported by the grid (D-13 — right-edge-only grow). Default: 3.
|
|
28
|
+
* Used to clamp motionX writes during drag so the ghost cannot translate
|
|
29
|
+
* past the maximum-allowed column offset at any cursor position (debug
|
|
30
|
+
* session 260419-ghost-slides-across-page — AP-17 companion invariant).
|
|
31
|
+
*/
|
|
32
|
+
maxColSpan?: 1 | 2 | 3;
|
|
20
33
|
}
|
|
21
34
|
export interface UseEdgeHoverResizeReturn {
|
|
22
35
|
state: ResizeState;
|
|
@@ -29,35 +42,46 @@ export interface UseEdgeHoverResizeReturn {
|
|
|
29
42
|
onPointerLeave: () => void;
|
|
30
43
|
};
|
|
31
44
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* `currentColSpan` on transition out of 'dragging'. Always clamped to 1..3.
|
|
45
|
+
* Live preview during drag. Always clamped to 1..3.
|
|
46
|
+
* Reflects the colSpan the user would commit at the current cursor position,
|
|
47
|
+
* with hysteresis snap (D-06).
|
|
36
48
|
*/
|
|
37
49
|
previewColSpan: 1 | 2 | 3;
|
|
38
50
|
ghostProps: {
|
|
39
51
|
visible: boolean;
|
|
40
|
-
/** Same value as `previewColSpan`; exposed here for `<GhostPreview targetColSpan>` plumbing. */
|
|
41
52
|
targetColSpan: 1 | 2 | 3;
|
|
53
|
+
/** D-07 — MotionValue driving ghost translateX. Zero React re-renders per pointermove. */
|
|
54
|
+
motionX: MotionValue<number>;
|
|
42
55
|
enterMs: number;
|
|
43
56
|
exitMs: number;
|
|
44
57
|
};
|
|
58
|
+
/** D-16 — keyboard resize step (grow/shrink by 1) on focused handle. */
|
|
59
|
+
onKeyboardStep: (direction: ResizeDirection) => void;
|
|
60
|
+
/** D-19 — touch tap-to-reveal: show handle immediately on touch pointerdown on card body. */
|
|
61
|
+
onTouchReveal: () => void;
|
|
62
|
+
/** D-19 — outside-tap dismissal for touch. */
|
|
63
|
+
onTouchDismiss: () => void;
|
|
64
|
+
/** D-18 — cancel (used by parent; springs back if dragging). */
|
|
65
|
+
cancel: () => void;
|
|
45
66
|
}
|
|
46
67
|
/**
|
|
47
|
-
* useEdgeHoverResize —
|
|
48
|
-
*
|
|
49
|
-
* State flow:
|
|
50
|
-
* idle → dwelling (hover dwell 120ms) → handle-visible → dragging (pointerdown) → committed (pointerup) | cancelled
|
|
51
|
-
* dwelling | handle-visible → idle (pointer leaves edge zone)
|
|
52
|
-
* dragging | handle-visible → cancelled (Escape key)
|
|
53
|
-
*
|
|
54
|
-
* The hook does NOT inspect any reptime-domain data. The consumer passes `stackable`
|
|
55
|
-
* (from metricInfo) and the hook emits the correct mode string — no cross-domain leakage.
|
|
68
|
+
* useEdgeHoverResize — Phase 19 reworked state machine for edge-hover-to-resize.
|
|
56
69
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
70
|
+
* Changes vs Phase 10.5 original:
|
|
71
|
+
* - MotionValue ghost tracking (D-07) — zero React re-renders per pointermove
|
|
72
|
+
* - Hysteresis snap (D-06) replaces Math.round(dx/step)
|
|
73
|
+
* - Velocity ring buffer (D-09) feeds spring commit
|
|
74
|
+
* - Spring commit via framer-motion animate() (D-08: stiffness 500, damping 35, mass 1)
|
|
75
|
+
* - 'settling' state (D-12) hard-blocks re-engagement during spring
|
|
76
|
+
* - committed state removed (D-05) — rolls into settling → idle
|
|
77
|
+
* - Keyboard step (D-16): onKeyboardStep('grow'|'shrink')
|
|
78
|
+
* - Escape spring-back with cursor velocity (D-15)
|
|
79
|
+
* - Touch tap-to-reveal with 5s idle (D-19)
|
|
80
|
+
* - prefers-reduced-motion bypass (D-22) — instant transform
|
|
60
81
|
*
|
|
61
|
-
*
|
|
82
|
+
* Preserved invariants:
|
|
83
|
+
* - Bug A React 19 updater purity — side effects fire OUTSIDE setState updaters
|
|
84
|
+
* - Bug E handle pointerenter keeps zone alive on sentinel→handle crossover
|
|
85
|
+
* - Dwell timer cleanup on unmount
|
|
62
86
|
*/
|
|
63
|
-
export declare function useEdgeHoverResize({ currentColSpan, stackable, onResize, onCancel, dwellMs, enterMs, exitMs, }: UseEdgeHoverResizeArgs): UseEdgeHoverResizeReturn;
|
|
87
|
+
export declare function useEdgeHoverResize({ currentColSpan, stackable, onResize, onCancel, step, tuning, dwellMs, enterMs, exitMs, maxColSpan, }: UseEdgeHoverResizeArgs): UseEdgeHoverResizeReturn;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VelocityBuffer — D-09 ring buffer for pointer velocity sampling.
|
|
3
|
+
*
|
|
4
|
+
* Stores up to `capacity` (3) VelocitySample entries. Computes a
|
|
5
|
+
* weighted-average velocity over the ring using 3×/2×/1× weights
|
|
6
|
+
* with divisor 6 (canonical formula per PLAN 19-01 resolution of
|
|
7
|
+
* §U1). When fewer than 3 samples exist, degrades gracefully:
|
|
8
|
+
* - 0 samples → 0
|
|
9
|
+
* - 1 sample → 0 (caller sees no velocity)
|
|
10
|
+
* - 2 samples → single-event dx/dt fallback (AP-20: never zero on a gesture)
|
|
11
|
+
* - 3+ samples → (vRecent·3 + vMid·2 + vOld·1) / 6
|
|
12
|
+
* where vOld degrades to vMid when only 2 deltas are available across 3 samples
|
|
13
|
+
* (flat fallback; buffer still lives on 3 instants — plan §Task 2 resolution).
|
|
14
|
+
*
|
|
15
|
+
* dt is clamped to >= 1ms via Math.max(1, …) to avoid Infinity on same-tick duplicates.
|
|
16
|
+
*
|
|
17
|
+
* Units: px/sec.
|
|
18
|
+
*/
|
|
19
|
+
export interface VelocitySample {
|
|
20
|
+
x: number;
|
|
21
|
+
t: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class VelocityBuffer {
|
|
24
|
+
private samples;
|
|
25
|
+
private readonly capacity;
|
|
26
|
+
push(sample: VelocitySample): void;
|
|
27
|
+
clear(): void;
|
|
28
|
+
/**
|
|
29
|
+
* D-09 — weighted-average velocity (px/sec).
|
|
30
|
+
*
|
|
31
|
+
* 0 samples → 0
|
|
32
|
+
* 1 sample → 0
|
|
33
|
+
* 2 samples → single-event fallback dx/dt
|
|
34
|
+
* 3 samples → weighted avg with vOld falling back to vMid to keep the
|
|
35
|
+
* divisor at 6. Formula: (vRecent·3 + vMid·2 + vMid·1) / 6
|
|
36
|
+
* (see PLAN §Task 2 §U1 resolution).
|
|
37
|
+
*/
|
|
38
|
+
getWeightedVelocity(): number;
|
|
39
|
+
}
|