@n-uf/motion 26.11.3 → 26.11.4

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/drag.js ADDED
@@ -0,0 +1,151 @@
1
+ // src/drag/intent.ts
2
+ var DRAG_DEFAULTS = {
3
+ lift: 5,
4
+ touchHold: 180,
5
+ touchLift: 8,
6
+ speedWindow: 50,
7
+ aimSpeed: 0.45,
8
+ still: 12,
9
+ dwell: 90,
10
+ band: 10,
11
+ breakthrough: 4,
12
+ gapGrace: 120,
13
+ switchHold: 150,
14
+ roomAfter: 160,
15
+ homeInset: 6
16
+ };
17
+ function inRect(rect, point, margin = 0) {
18
+ return point.x >= rect.x - margin && point.x <= rect.x + rect.width + margin && point.y >= rect.y - margin && point.y <= rect.y + rect.height + margin;
19
+ }
20
+ var area = (r) => r.width * r.height;
21
+ function targetAt(targets, point) {
22
+ let best = null;
23
+ for (const t of targets) {
24
+ if (!inRect(t.hit, point)) continue;
25
+ if (!best || t.priority < best.priority || t.priority === best.priority && area(t.hit) < area(best.hit)) best = t;
26
+ }
27
+ return best;
28
+ }
29
+ function liftDecision(press, tuning = {}) {
30
+ const t = { ...DRAG_DEFAULTS, ...tuning };
31
+ if (!press.touch) return press.distance >= t.lift ? "lift" : "wait";
32
+ if (press.elapsed < t.touchHold) return press.distance >= t.touchLift ? "refuse" : "wait";
33
+ return press.distance >= t.touchLift ? "lift" : "wait";
34
+ }
35
+ function createDragIntent(options) {
36
+ const tuning = { ...DRAG_DEFAULTS, ...options.tuning };
37
+ const placeOf = options.placeOf ?? ((t) => t.id);
38
+ let home = { ...options.home };
39
+ let samples = [];
40
+ let cur = null;
41
+ let curSince = 0;
42
+ let lastInside = 0;
43
+ let shown = null;
44
+ let shownSince = 0;
45
+ let place = null;
46
+ let placeSince = 0;
47
+ let roomPlace = null;
48
+ let leftHome = false;
49
+ let speed = 0;
50
+ let anchor = null;
51
+ let stillSince = 0;
52
+ let restart = false;
53
+ const same = (a, b) => a === null || b === null ? a === b : a.id === b.id;
54
+ const follow = (t, targets) => t ? targets.find((x) => x.id === t.id) ?? t : null;
55
+ return {
56
+ tuning,
57
+ get state() {
58
+ return { speed, current: cur, shown, leftHome };
59
+ },
60
+ update(point, time, targets) {
61
+ const p = point;
62
+ const t = time;
63
+ samples.push({ x: p.x, y: p.y, t });
64
+ while (samples.length > 2 && t - samples[0].t > tuning.speedWindow) samples.shift();
65
+ const a = samples[0];
66
+ speed = speed * 0.5 + Math.hypot(p.x - a.x, p.y - a.y) / Math.max(1, t - a.t) * 0.5;
67
+ if (!anchor || Math.hypot(p.x - anchor.x, p.y - anchor.y) > tuning.still) {
68
+ anchor = { x: p.x, y: p.y };
69
+ stillSince = t;
70
+ }
71
+ if (!inRect(home, p, -tuning.homeInset)) leftHome = true;
72
+ const atHome = inRect(home, p);
73
+ const raw = atHome ? null : targetAt(targets, p);
74
+ cur = follow(cur, targets);
75
+ shown = follow(shown, targets);
76
+ let next = raw;
77
+ if (cur && !atHome && inRect(cur.hit, p, tuning.band)) {
78
+ const breaks = raw !== null && !same(raw, cur) && raw.priority < cur.priority && inRect(raw.hit, p, -tuning.breakthrough);
79
+ next = breaks ? raw : cur;
80
+ }
81
+ if (!next && cur && !atHome && t - lastInside < tuning.gapGrace) next = cur;
82
+ if (next && inRect(next.hit, p)) lastInside = t;
83
+ if (!same(next, cur)) curSince = t;
84
+ cur = next;
85
+ const aiming = !restart && (speed < tuning.aimSpeed || t - stillSince >= tuning.dwell);
86
+ restart = false;
87
+ const show = (s) => {
88
+ if (!same(s, shown)) shownSince = t;
89
+ shown = s;
90
+ };
91
+ const under = !!cur && inRect(cur.hit, p, tuning.band);
92
+ if (!shown) {
93
+ if (cur && under && leftHome && aiming) show(cur);
94
+ } else if (same(cur, shown)) {
95
+ if (!aiming && !under) show(null);
96
+ else shown = cur;
97
+ } else if (!cur || !aiming) {
98
+ show(null);
99
+ } else if (cur.priority < shown.priority && inRect(cur.hit, p, -tuning.breakthrough) || under && t - curSince >= tuning.switchHold) {
100
+ show(cur);
101
+ }
102
+ const at = shown ? placeOf(shown, p) : null;
103
+ if (at !== place) {
104
+ place = at;
105
+ placeSince = t;
106
+ }
107
+ if (!shown || shown.free) roomPlace = null;
108
+ else if (t - shownSince >= tuning.roomAfter && t - placeSince >= tuning.roomAfter) roomPlace = place;
109
+ else if (shownSince === t) roomPlace = null;
110
+ return { shown, room: roomPlace !== null, roomPlace, aiming };
111
+ },
112
+ release(point, targets) {
113
+ if (inRect(home, point)) return null;
114
+ const s = follow(shown, targets);
115
+ if (s) return s;
116
+ return targetAt(targets, point);
117
+ },
118
+ hide(time) {
119
+ shown = null;
120
+ cur = null;
121
+ shownSince = time;
122
+ place = null;
123
+ roomPlace = null;
124
+ samples = [];
125
+ anchor = null;
126
+ restart = true;
127
+ },
128
+ moveHome(dx, dy) {
129
+ home = { ...home, x: home.x + dx, y: home.y + dy };
130
+ }
131
+ };
132
+ }
133
+
134
+ // src/drag/preview.ts
135
+ var DRAG_PREVIEW_DEFAULT = "snap";
136
+ function previewPlan(frame, preview, slotted = !!frame.shown && !frame.shown.free) {
137
+ const shown = !!frame.shown;
138
+ if (preview === "indicator") return { showIndicator: shown, makeRoom: false, snapItem: false };
139
+ if (preview === "gap") return { showIndicator: shown, makeRoom: frame.room, snapItem: false };
140
+ return { showIndicator: shown && !slotted, makeRoom: frame.room, snapItem: frame.room && shown && slotted };
141
+ }
142
+ export {
143
+ DRAG_DEFAULTS,
144
+ DRAG_PREVIEW_DEFAULT,
145
+ createDragIntent,
146
+ inRect,
147
+ liftDecision,
148
+ previewPlan,
149
+ targetAt
150
+ };
151
+ //# sourceMappingURL=drag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/drag/intent.ts","../src/drag/preview.ts"],"sourcesContent":["import type { Point, Rect } from \"../shapes\";\n\n/**\n * The drag intent model's tuning. Distances in px, speeds in px/ms, times in\n * ms; every value can be overridden per intent (see\n * {@link DragIntentOptions.tuning}).\n */\nexport interface DragTuning {\n /** A mouse press lifts once the pointer has moved this far. */\n readonly lift: number;\n /** A touch press lifts only after it has been held this long… */\n readonly touchHold: number;\n /** …and then moved this far (moving that far before the hold is over is not a drag). */\n readonly touchLift: number;\n /** The pointer's speed is measured over this window and smoothed. */\n readonly speedWindow: number;\n /** Aiming: the smoothed speed is below this… */\n readonly aimSpeed: number;\n /** …or the pointer has stayed within `still` px of one spot for `dwell` ms. */\n readonly still: number;\n readonly dwell: number;\n /** The current target holds while the pointer is within this band of its zone. */\n readonly band: number;\n /** A higher-priority target takes over at once when the pointer is this far inside it. */\n readonly breakthrough: number;\n /** A gap between zones shorter than this keeps the current target (for a pointer that aims). */\n readonly gapGrace: number;\n /** Aiming, the shown target moves to another one only once that one has held this long. */\n readonly switchHold: number;\n /** Room is made once the shown target, and the place in it, have held this long. */\n readonly roomAfter: number;\n /** The pointer has left the item's home once it is outside the home shrunk by this much on every side. */\n readonly homeInset: number;\n}\n\n/**\n * The defaults: a mouse lifts after 5 px, a touch after a 180 ms hold and\n * 8 px; aiming is slower than 0.45 px/ms over 50 ms, or within 12 px for\n * 90 ms; a 10 px band, a 4 px breakthrough and a 120 ms gap grace; a switch\n * waits 150 ms (the shortest an indicator may show); room after 160 ms.\n */\nexport const DRAG_DEFAULTS: DragTuning = {\n lift: 5,\n touchHold: 180,\n touchLift: 8,\n speedWindow: 50,\n aimSpeed: 0.45,\n still: 12,\n dwell: 90,\n band: 10,\n breakthrough: 4,\n gapGrace: 120,\n switchHold: 150,\n roomAfter: 160,\n homeInset: 6,\n};\n\n/**\n * A drop target: plain data. `hit` is the zone the pointer can be in;\n * `priority` how precise it is (1 beats 2 beats 3; equal priorities go to the\n * smaller zone). `slot` is where the dragged item would land, `label` what to\n * call it; the model reads neither. A `free` target has no slot (the item\n * floats where it is dropped): no room is made for it.\n */\nexport interface DragTarget {\n readonly id: string;\n readonly priority: 1 | 2 | 3;\n readonly hit: Rect;\n readonly slot?: Rect;\n readonly label?: string;\n readonly free?: boolean;\n}\n\n/** Whether `point` lies in `rect` grown by `margin` px on every side (shrunk, for a negative margin). */\nexport function inRect(rect: Rect, point: Point, margin = 0): boolean {\n return point.x >= rect.x - margin && point.x <= rect.x + rect.width + margin && point.y >= rect.y - margin && point.y <= rect.y + rect.height + margin;\n}\n\nconst area = (r: Rect): number => r.width * r.height;\n\n/** The most precise target under `point`: the lowest priority number, then the smallest zone; null when none is. */\nexport function targetAt<T extends DragTarget>(targets: readonly T[], point: Point): T | null {\n let best: T | null = null;\n for (const t of targets) {\n if (!inRect(t.hit, point)) continue;\n if (!best || t.priority < best.priority || (t.priority === best.priority && area(t.hit) < area(best.hit))) best = t;\n }\n return best;\n}\n\n/** What a press does so far: not yet a drag (`wait`), a drag (`lift`), or never one (`refuse`: a touch that moved too soon). */\nexport type LiftDecision = \"wait\" | \"lift\" | \"refuse\";\n\n/**\n * The lift rule for a press that has moved `distance` px in `elapsed` ms. A\n * mouse (or pen) lifts at `lift` px. A touch lifts only after `touchHold` ms,\n * then at `touchLift` px; moving `touchLift` px before the hold is over\n * refuses the drag (the finger is scrolling or swiping).\n */\nexport function liftDecision(press: { readonly touch: boolean; readonly distance: number; readonly elapsed: number }, tuning: Partial<DragTuning> = {}): LiftDecision {\n const t = { ...DRAG_DEFAULTS, ...tuning };\n if (!press.touch) return press.distance >= t.lift ? \"lift\" : \"wait\";\n if (press.elapsed < t.touchHold) return press.distance >= t.touchLift ? \"refuse\" : \"wait\";\n return press.distance >= t.touchLift ? \"lift\" : \"wait\";\n}\n\n/** One update's answer. */\nexport interface DragFrame<T extends DragTarget> {\n /** The target the drop indicator shows, or null. */\n readonly shown: T | null;\n /** The others make room for the shown target: it, and the place in it, have held `roomAfter` ms. */\n readonly room: boolean;\n /**\n * The place the room is made for, or null. Within one target it stays on\n * the old place until a new one has held `roomAfter` ms (see\n * {@link DragIntentOptions.placeOf}).\n */\n readonly roomPlace: string | null;\n /** The pointer is aiming: slow, or nearly still for a moment. */\n readonly aiming: boolean;\n}\n\n/** What a drag intent knows now. */\nexport interface DragIntentState<T extends DragTarget> {\n /** The pointer's smoothed speed, px/ms. */\n readonly speed: number;\n /** The target under the pointer as the hysteresis holds it, or null. */\n readonly current: T | null;\n /** The target the indicator shows, or null. */\n readonly shown: T | null;\n /** The pointer has left the item's home. */\n readonly leftHome: boolean;\n}\n\nexport interface DragIntentOptions<T extends DragTarget> {\n /** Where the item was lifted from: the indicator stays off until the pointer leaves it, and a release there does nothing. */\n readonly home: Rect;\n /** Overrides of {@link DRAG_DEFAULTS}. */\n readonly tuning?: Partial<DragTuning>;\n /**\n * The place within a target the pointer is at (a tab index, a stack\n * position), unique across targets; default: the target's id. Moving between places of the\n * shown target moves the indicator at once but the room only once the new\n * place has held `roomAfter` ms.\n */\n readonly placeOf?: (target: T, point: Point) => string;\n}\n\n/** A drag's intent: feed it the pointer on every frame; it says what the indicator shows and what a release lands on. */\nexport interface DragIntent<T extends DragTarget> {\n /**\n * A pointer sample at `time` (ms), with the targets as they stand (they may\n * be rebuilt between calls: the model follows them by id). Call it once a\n * frame while the item is held, also when the pointer doesn't move: a\n * dwell is time passing.\n */\n update(point: Point, time: number, targets: readonly T[]): DragFrame<T>;\n /**\n * What a release at `point` lands on: the shown target whenever one shows\n * (a drop lands where the indicator was), else the target under the\n * pointer, else null (the item goes home). A release over home is null: it\n * does nothing. Feed the release point to `update` first, so a last jump\n * of the pointer counts.\n */\n release(point: Point, targets: readonly T[]): T | null;\n /**\n * Hide the indicator (the view is scrolling under the pointer, say). The\n * aim starts afresh: the next sample never counts as aiming, and a dwell\n * starts again.\n */\n hide(time: number): void;\n /** The item's home moved with the view (it scrolled) by (dx, dy). */\n moveHome(dx: number, dy: number): void;\n readonly state: DragIntentState<T>;\n readonly tuning: DragTuning;\n}\n\n/**\n * The drag intent model: when the drop indicator shows, which target it\n * shows, when the others make room, and what a release lands on. Pure: fed\n * pointer samples and plain-data targets, no DOM and no clock of its own.\n *\n * - The indicator shows only when the pointer has left the item's home, a\n * target is under it, and it is aiming (slow, or nearly still for a\n * moment). Time spent crossing a big target at speed doesn't count.\n * - The most precise target wins (priority, then the smaller zone).\n * - Hysteresis: the current target holds while the pointer is within `band`\n * px of its zone, unless a more precise one is clearly (`breakthrough` px)\n * under the pointer; for a pointer that aims, a short gap between zones\n * (`gapGrace` ms) keeps it too.\n * - Leaving the shown target: flying, the indicator hides at once; aiming, it\n * moves to the new target once that has held `switchHold` ms (so no\n * indicator shows for less than that), at once for a breakthrough. A target\n * kept only by the gap grace can keep the indicator, never show it.\n * - Room is made once the shown target has held `roomAfter` ms, never for a\n * free target, and closes at once when it changes.\n */\nexport function createDragIntent<T extends DragTarget>(options: DragIntentOptions<T>): DragIntent<T> {\n const tuning: DragTuning = { ...DRAG_DEFAULTS, ...options.tuning };\n const placeOf = options.placeOf ?? ((t: T) => t.id);\n let home: Rect = { ...options.home };\n let samples: { x: number; y: number; t: number }[] = [];\n let cur: T | null = null;\n let curSince = 0;\n let lastInside = 0;\n let shown: T | null = null;\n let shownSince = 0;\n let place: string | null = null;\n let placeSince = 0;\n let roomPlace: string | null = null;\n let leftHome = false;\n let speed = 0;\n let anchor: Point | null = null;\n let stillSince = 0;\n let restart = false;\n const same = (a: T | null, b: T | null): boolean => (a === null || b === null ? a === b : a.id === b.id);\n // Targets may be rebuilt between calls: follow the ones held by id.\n const follow = (t: T | null, targets: readonly T[]): T | null => (t ? (targets.find((x) => x.id === t.id) ?? t) : null);\n\n return {\n tuning,\n get state(): DragIntentState<T> {\n return { speed, current: cur, shown, leftHome };\n },\n update(point, time, targets) {\n const p = point;\n const t = time;\n samples.push({ x: p.x, y: p.y, t });\n while (samples.length > 2 && t - samples[0]!.t > tuning.speedWindow) samples.shift();\n const a = samples[0]!;\n speed = speed * 0.5 + (Math.hypot(p.x - a.x, p.y - a.y) / Math.max(1, t - a.t)) * 0.5;\n if (!anchor || Math.hypot(p.x - anchor.x, p.y - anchor.y) > tuning.still) {\n anchor = { x: p.x, y: p.y };\n stillSince = t;\n }\n if (!inRect(home, p, -tuning.homeInset)) leftHome = true;\n const atHome = inRect(home, p);\n const raw = atHome ? null : targetAt(targets, p);\n cur = follow(cur, targets);\n shown = follow(shown, targets);\n let next = raw;\n if (cur && !atHome && inRect(cur.hit, p, tuning.band)) {\n const breaks = raw !== null && !same(raw, cur) && raw.priority < cur.priority && inRect(raw.hit, p, -tuning.breakthrough);\n next = breaks ? raw : cur;\n }\n if (!next && cur && !atHome && t - lastInside < tuning.gapGrace) next = cur;\n if (next && inRect(next.hit, p)) lastInside = t;\n if (!same(next, cur)) curSince = t;\n cur = next;\n const aiming = !restart && (speed < tuning.aimSpeed || t - stillSince >= tuning.dwell);\n restart = false;\n const show = (s: T | null): void => {\n if (!same(s, shown)) shownSince = t;\n shown = s;\n };\n // Under the pointer (within its band), not just kept by the gap grace.\n const under = !!cur && inRect(cur.hit, p, tuning.band);\n if (!shown) {\n if (cur && under && leftHome && aiming) show(cur);\n } else if (same(cur, shown)) {\n // It stays while its target holds; but a pointer flying out past the band hides it at once.\n if (!aiming && !under) show(null);\n else shown = cur;\n } else if (!cur || !aiming) {\n show(null);\n } else if ((cur.priority < shown.priority && inRect(cur.hit, p, -tuning.breakthrough)) || (under && t - curSince >= tuning.switchHold)) {\n show(cur);\n }\n // The place within the shown target, and the room: after the target and the place have both held.\n const at = shown ? placeOf(shown, p) : null;\n if (at !== place) {\n place = at;\n placeSince = t;\n }\n if (!shown || shown.free) roomPlace = null;\n else if (t - shownSince >= tuning.roomAfter && t - placeSince >= tuning.roomAfter) roomPlace = place;\n else if (shownSince === t) roomPlace = null;\n return { shown, room: roomPlace !== null, roomPlace, aiming };\n },\n release(point, targets) {\n if (inRect(home, point)) return null;\n // Drop = shown: a shown target is kept until it hides (flying out past its band hides it at once).\n const s = follow(shown, targets);\n if (s) return s;\n return targetAt(targets, point);\n },\n hide(time) {\n shown = null;\n cur = null;\n shownSince = time;\n place = null;\n roomPlace = null;\n samples = [];\n anchor = null;\n restart = true;\n },\n moveHome(dx, dy) {\n home = { ...home, x: home.x + dx, y: home.y + dy };\n },\n };\n}\n","import type { DragFrame, DragTarget } from \"./intent\";\n\n/**\n * How a drag previews its drop, from least to most motion while dragging:\n *\n * - `\"indicator\"`: nothing moves; only the indicator (an outline or an\n * insertion marker) shows the target.\n * - `\"gap\"`: once the room is made, the others move aside and open the slot;\n * the item stays under the pointer.\n * - `\"snap\"`: the gap opens and the item itself glides into it (for a target\n * with a slot; one without keeps the indicator).\n *\n * Every mode follows the same intent: what shows, when, and what a release\n * lands on are the drag intent's, so a drop always lands where the preview\n * showed it.\n */\nexport type DragPreview = \"indicator\" | \"gap\" | \"snap\";\n\n/** The preview a drag uses unless the host picks another. */\nexport const DRAG_PREVIEW_DEFAULT: DragPreview = \"snap\";\n\n/** What to draw for one frame of a drag. */\nexport interface PreviewPlan {\n /** Draw the indicator on the shown target. */\n readonly showIndicator: boolean;\n /** Lay the others out around the room (the gap is open). */\n readonly makeRoom: boolean;\n /** Draw the item in its slot instead of under the pointer. */\n readonly snapItem: boolean;\n}\n\n/**\n * The plan for a frame of the drag intent under `preview`. `slotted` says\n * whether the shown target's drop has a slot the item can sit in (default: a\n * target that isn't `free`); only such a target snaps, and in `\"snap\"` it\n * previews with the item rather than the indicator.\n *\n * - `\"indicator\"`: the indicator, never room, never a snap.\n * - `\"gap\"`: the indicator, and room when the intent makes it.\n * - `\"snap\"`: room when the intent makes it, the item snapped into a slotted\n * target's room; the indicator only for a target without a slot.\n */\nexport function previewPlan<T extends DragTarget>(\n frame: Pick<DragFrame<T>, \"shown\" | \"room\">,\n preview: DragPreview,\n slotted: boolean = !!frame.shown && !frame.shown.free,\n): PreviewPlan {\n const shown = !!frame.shown;\n if (preview === \"indicator\") return { showIndicator: shown, makeRoom: false, snapItem: false };\n if (preview === \"gap\") return { showIndicator: shown, makeRoom: frame.room, snapItem: false };\n // By design a slotted target draws nothing until the room opens (`roomAfter`); a release then still lands on it.\n return { showIndicator: shown && !slotted, makeRoom: frame.room, snapItem: frame.room && shown && slotted };\n}\n"],"mappings":"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","names":[]}
@@ -6,7 +6,7 @@ import { C as ClockPort, F as FrameSource, T as TimerSource } from './port-CmlUc
6
6
  * touches the DOM; the host copies the fields it needs out of PointerEvent /
7
7
  * WheelEvent / Safari's GestureEvent.
8
8
  *
9
- * Ported from the pdfized surface's input layer, whose recogniser this is.
9
+ * Ported from a host app's input layer, whose recogniser this is.
10
10
  * Hit testing and routing (what is under a point, who gets a gesture) stay
11
11
  * with the host.
12
12
  */
package/dist/gestures.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  resolveDragModifier,
21
21
  toModifiers,
22
22
  wheelDeltaPx
23
- } from "./chunk-NFQ4LIIR.js";
23
+ } from "./chunk-C4M62FUT.js";
24
24
  import "./chunk-OOKRBVMB.js";
25
25
  export {
26
26
  DWELL_DEFAULTS,
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { C as ClockPort, F as FrameSource, T as TimerSource } from './port-CmlUc
2
2
  export { FakeClock, FakeClockOptions, createFakeClock } from './clock.js';
3
3
  export { F as FrameInfo, a as FrameLoop, b as FrameLoopOptions, c as FrameStats, d as FrameTask, P as PHASES, e as Phase, R as RepeatingTask, S as ScheduleOptions, f as createFrameLoop } from './frame-loop-C88dc9xw.js';
4
4
  export { EffectCleanup, EffectOptions, Equals, ReadonlySignal, Signal, SignalOptions, batch, computed, effect, isSignal, signal, untracked } from './signals.js';
5
- export { Animator, AnimatorValue, Easing, MotionOptions, MotionValue, PopIn, RevealFrame, SETTLE_DEFAULTS, SETTLE_TEMPO, SPRING_DEFAULTS, SetOptions, Settle, SettleConfig, Spring, SpringConfig, SpringParams, SpringState, Tween, TweenConfig, createSettle, createSpring, createTween, cubicBezier, ease, easeIn, easeInOut, easeInOutCubic, easeOut, easeOutCubic, linear, motionValue, popIn, resolveSpring, reveal, settleValue, springStep, springValue, tweenValue } from './values.js';
5
+ export { Animator, AnimatorValue, Easing, MotionOptions, MotionValue, SETTLE_DEFAULTS, SETTLE_TEMPO, SPRING_DEFAULTS, SetOptions, Settle, SettleConfig, Spring, SpringConfig, SpringParams, SpringState, Tween, TweenConfig, createSettle, createSpring, createTween, cubicBezier, ease, easeIn, easeInOut, easeInOutCubic, easeOut, easeOutCubic, linear, motionValue, resolveSpring, settleValue, springStep, springValue, tweenValue } from './values.js';
6
+ export { P as PopIn, R as RevealFrame, p as popIn, r as reveal } from './reveal-my7U6UyE.js';
6
7
  export { CancelReason, CoalescerOptions, DWELL_DEFAULTS, DWELL_IDLE, Deadline, DwellConfig, DwellInput, DwellMachineOptions, DwellState, FrameCoalescer, InputGesture, InputGestureType, Machine, MachineOptions, ModifierDrag, ModifierKey, Modifiers, NO_MODIFIERS, Platform, PointerKind, RECOGNIZER_DEFAULTS, RawInputEvent, RawPointerEvent, RawPointerType, RawSafariGestureEvent, RawWheelEvent, Recognizer, RecognizerOptions, RecognizerTimers, SurfacePointer, WHEEL_DEFAULTS, WHEEL_PAN_DEFAULTS, WheelIntent, WheelOptions, WheelPanOptions, classifyWheel, createDwellMachine, createFrameCoalescer, createMachine, createRecognizer, dampWheelPan, defaultDragModifier, dwellDeadline, dwellReducer, isHeld, modHeld, platformButton, resolveDragModifier, toModifiers, wheelDeltaPx } from './gestures.js';
7
8
  export { A as Animatable, P as Point, R as Rect, V as Vector, W as Widen, s as shapeEquals } from './shapes-EbQlwbCu.js';
package/dist/index.js CHANGED
@@ -5,10 +5,7 @@ import {
5
5
  } from "./chunk-BVPVUJ42.js";
6
6
  import "./chunk-FQNHO2VT.js";
7
7
  import {
8
- SETTLE_DEFAULTS,
9
- SETTLE_TEMPO,
10
8
  SPRING_DEFAULTS,
11
- createSettle,
12
9
  createSpring,
13
10
  createTween,
14
11
  cubicBezier,
@@ -20,15 +17,12 @@ import {
20
17
  easeOutCubic,
21
18
  linear,
22
19
  motionValue,
23
- popIn,
24
20
  resolveSpring,
25
- reveal,
26
21
  settleValue,
27
- shapeEquals,
28
22
  springStep,
29
23
  springValue,
30
24
  tweenValue
31
- } from "./chunk-6W5KW7XQ.js";
25
+ } from "./chunk-CM6WVNDH.js";
32
26
  import {
33
27
  DWELL_DEFAULTS,
34
28
  DWELL_IDLE,
@@ -51,7 +45,7 @@ import {
51
45
  resolveDragModifier,
52
46
  toModifiers,
53
47
  wheelDeltaPx
54
- } from "./chunk-NFQ4LIIR.js";
48
+ } from "./chunk-C4M62FUT.js";
55
49
  import {
56
50
  batch,
57
51
  computed,
@@ -60,6 +54,14 @@ import {
60
54
  signal,
61
55
  untracked
62
56
  } from "./chunk-OOKRBVMB.js";
57
+ import {
58
+ SETTLE_DEFAULTS,
59
+ SETTLE_TEMPO,
60
+ createSettle,
61
+ popIn,
62
+ reveal,
63
+ shapeEquals
64
+ } from "./chunk-WQQ2E25M.js";
63
65
  export {
64
66
  DWELL_DEFAULTS,
65
67
  DWELL_IDLE,
@@ -0,0 +1,258 @@
1
+ import { F as FrameInfo, a as FrameLoop, e as Phase } from './frame-loop-C88dc9xw.js';
2
+ import { R as Rect, P as Point } from './shapes-EbQlwbCu.js';
3
+ import { R as RevealFrame, P as PopIn } from './reveal-my7U6UyE.js';
4
+ import './port-CmlUctqx.js';
5
+
6
+ /**
7
+ * What a {@link Drawable} draws on a frame: where the item is drawn, the box its content is laid out in, how to draw
8
+ * the one at the other without stretching ({@link reveal}), and its appearance ({@link popIn}).
9
+ */
10
+ interface DrawFrame {
11
+ /** Where the item is drawn this frame (its frame: background, border, shadow). */
12
+ readonly drawn: Rect;
13
+ /** The box its content is laid out in: where it is heading, or (held) where it was laid out last. */
14
+ readonly box: Rect;
15
+ /** How to draw `box`'s content at `drawn`: a move, the frame at the drawn size, the content clipped. */
16
+ readonly reveal: RevealFrame;
17
+ /** Its uniform appearance: scale about its centre and opacity. */
18
+ readonly pop: PopIn;
19
+ /** How shown it is, 0 (gone) to 1. */
20
+ readonly shown: number;
21
+ /** All the way gone: hidden and at rest (out of sight and out of the way of the pointer). */
22
+ readonly gone: boolean;
23
+ }
24
+ /**
25
+ * How an item reaches the screen. The layout motion never measures or touches anything itself: it lays an item's
26
+ * content out once per new box and draws it once per frame through this. {@link domDrawable} writes an element's
27
+ * style; a canvas or a test can draw anything else.
28
+ */
29
+ interface Drawable {
30
+ /** Lay the content out in `box` (its position and size): called once per new box, never per frame. */
31
+ layOut(box: Rect): void;
32
+ /** Draw the item for this frame. */
33
+ draw(frame: DrawFrame): void;
34
+ }
35
+ /**
36
+ * One item the layout motion moves: give it a new place and it settles there from wherever it is drawn.
37
+ *
38
+ * - {@link LayoutItem.moveTo}: a settle to the new place, retargeted from the drawn rect (no jump, no overshoot);
39
+ * the content is laid out at the new box at once and the item redrawn at once, so no frame shows the old offset
40
+ * from the new box.
41
+ * - A size change is revealed: the content is laid out at the target size and the frame clipped, never scaled.
42
+ * - {@link LayoutItem.show}: appear or disappear with a uniform-scale fade.
43
+ */
44
+ interface LayoutItem {
45
+ readonly id: string;
46
+ /** Where it is drawn now. */
47
+ readonly drawn: Rect;
48
+ /** Where it is heading (its settle's target). */
49
+ readonly target: Rect;
50
+ /** The box its content is laid out in. */
51
+ readonly box: Rect;
52
+ /** At rest on its target. */
53
+ readonly settled: boolean;
54
+ /** How shown it is, 0 to 1, and whether it is heading for shown. */
55
+ readonly shown: number;
56
+ readonly showing: boolean;
57
+ /** Its appearance is at rest (fully shown, or gone). */
58
+ readonly shownSettled: boolean;
59
+ /** Settle to `to` from where it is drawn; lays the content out at `to` and redraws at once. */
60
+ moveTo(to: Rect): void;
61
+ /** Be at `to` now, at rest: no glide. */
62
+ jumpTo(to: Rect): void;
63
+ /** Drawn at `from` now, then settle to `to` (a FLIP's invert and play: `from` in the item's own coordinates). */
64
+ glideFrom(from: Rect, to: Rect): void;
65
+ /** Exactly at `r`, at rest (what a pointer holds); the content stays laid out in its box, moved with it. */
66
+ hold(r: Rect): void;
67
+ /** Appear (true) or disappear (false) with a uniform-scale fade; `now`: without the fade. */
68
+ show(on: boolean, options?: {
69
+ readonly now?: boolean;
70
+ }): void;
71
+ /** Draw it again now (after its drawable's element was laid out anew from outside). */
72
+ redraw(): void;
73
+ }
74
+ /** A task the layout motion runs on every frame before it steps the items; true keeps the frames coming. */
75
+ type LayoutTask = (frame: FrameInfo) => boolean | void;
76
+ interface LayoutMotionOptions {
77
+ /** The frame loop every item steps on (one loop for all of them). */
78
+ readonly loop: FrameLoop;
79
+ /** The settle tempo, per second ({@link SETTLE_TEMPO}); default `SETTLE_TEMPO.default`. */
80
+ readonly omega?: number;
81
+ /** The frame phase the items step and draw in; default `"layout"`. */
82
+ readonly phase?: Phase;
83
+ /** Where an appearing item grows from, as a share of its size ({@link popIn}'s `from`); default 0.87. */
84
+ readonly popFrom?: number;
85
+ }
86
+ /**
87
+ * Layout motion: items with an id and a target rect, each settled to its place on one shared frame loop.
88
+ *
89
+ * Give an item a new place ({@link LayoutItem.moveTo}) and it glides there from wherever it is drawn: the window
90
+ * motion rules of `values/` (settle, reveal, popIn) applied to every item at once. The loop runs only while
91
+ * something moves, or a task asks for frames, and stops by itself.
92
+ *
93
+ * It only animates the rects it is given: which items move where, and when, is the caller's layout.
94
+ */
95
+ interface LayoutMotion {
96
+ /** Add an item drawn by `drawable`, at `at`, shown (or gone: `{ shown: false }`). Its content is laid out at once. */
97
+ add(id: string, drawable: Drawable, at: Rect, options?: {
98
+ readonly shown?: boolean;
99
+ }): LayoutItem;
100
+ get(id: string): LayoutItem | undefined;
101
+ /** Stop moving an item (its drawable is not touched again). */
102
+ remove(id: string): void;
103
+ readonly items: ReadonlyMap<string, LayoutItem>;
104
+ /** Run `task` on every frame, before the items step; returns how to stop it. */
105
+ task(task: LayoutTask): () => void;
106
+ /** Call `listener` on every frame, after the items have stepped and been drawn; returns how to stop it. */
107
+ onFrame(listener: (frame: FrameInfo) => void): () => void;
108
+ /** Call `listener` each time the frames stop (nothing moves); returns how to stop it. */
109
+ onIdle(listener: () => void): () => void;
110
+ /** Make sure at least one more frame runs (a task has something to do). */
111
+ wake(): void;
112
+ /** Frames are running. */
113
+ readonly running: boolean;
114
+ /** Set the tempo for every item (and the ones added later). */
115
+ configure(config: {
116
+ readonly omega?: number;
117
+ }): void;
118
+ /** Resolves once nothing moves (at once if nothing does). */
119
+ idle(): Promise<void>;
120
+ /** Stop the frames and forget every item. */
121
+ dispose(): void;
122
+ }
123
+ /** Create the {@link LayoutMotion} for one surface. */
124
+ declare function createLayoutMotion(options: LayoutMotionOptions): LayoutMotion;
125
+
126
+ /**
127
+ * An item held by a pointer: the real item (no copy) follows the pointer 1:1 from where it was grabbed, at the size
128
+ * it was lifted at; its place stays reserved (that is the caller's layout). Then:
129
+ *
130
+ * - {@link HeldDrag.snapTo}: glide into a slot (a snap preview); `null` leaves the slot and glides back to the
131
+ * pointer, following it as it moves ({@link HeldDrag.follow} once a frame), until it is under it again.
132
+ * - {@link HeldDrag.land}: let go into a slot: the landing settles from where it was let go (the release rect), never
133
+ * from its old home. Snapped into that slot already, it simply finishes that glide.
134
+ * - {@link HeldDrag.cancel}: let go with no drop: it glides home from where it was let go.
135
+ * - {@link HeldDrag.preview}: the three drop previews, per frame: indicator and gap keep the item under the pointer
136
+ * (gap with the caller's room open), snap glides it into the slot; leaving glides it back to the pointer.
137
+ * - {@link HeldDrag.resize}: the item takes a new size mid-drag (its content laid out anew by the caller): it settles
138
+ * to it from where it is drawn, the size revealed (never stretched), and is held 1:1 again once there.
139
+ */
140
+ interface HeldDrag {
141
+ /** Where the pointer is (null before the first move). */
142
+ readonly pointer: Point | null;
143
+ /** Where the pointer holds the item: the pointer less the grab offset, at the held size (lifted, or resized). */
144
+ readonly held: Rect | null;
145
+ /** The slot it sits in (a snap), or null. */
146
+ readonly snapped: Rect | null;
147
+ /** It left a slot (or took a new size) and is gliding back to the pointer. */
148
+ readonly returning: boolean;
149
+ /** The pointer moved: held 1:1 (unless it sits in a slot or is on its way back). */
150
+ move(pointer: Point): void;
151
+ /**
152
+ * Into `slot` (a glide from where it is drawn; the same slot again does nothing), or out of the slot it sits in
153
+ * (`null`: back to the pointer). Returns what changed: `"snapped"`, `"left"`, or null.
154
+ */
155
+ snapTo(slot: Rect | null): "snapped" | "left" | null;
156
+ /** Once a frame: on its way back, retarget to the pointer; true on the frame it is under the pointer again. */
157
+ follow(): boolean;
158
+ /**
159
+ * Once a frame, a drop preview's part for the item (`plan`: `@n-uf/motion/drag`'s `previewPlan`, or any
160
+ * `{ snapItem }`): with `snapItem` it glides into `slot` (snap); else it stays under the pointer, or glides back to
161
+ * it from a slot it left (indicator, gap). The room, if the plan makes any, is the caller's layout. In place of
162
+ * {@link HeldDrag.snapTo} and {@link HeldDrag.follow}; returns what changed.
163
+ */
164
+ preview(plan: {
165
+ readonly snapItem: boolean;
166
+ }, slot: Rect | null): "snapped" | "left" | null;
167
+ /**
168
+ * Hold it at `size` from now on (the caller has laid its content out for that size). The grab point keeps its share
169
+ * of the item, so the pointer stays on the same spot of it; the item settles from where it is drawn to its new held
170
+ * rect (its size revealed, never stretched), then is held 1:1 again ({@link HeldDrag.follow} once a frame). In a
171
+ * slot it stays there, taking the new size when it leaves. The same size again does nothing; returns true on a
172
+ * change.
173
+ */
174
+ resize(size: {
175
+ readonly width: number;
176
+ readonly height: number;
177
+ }): boolean;
178
+ /** Let go into `slot`: returns the release rect, where the landing starts. */
179
+ land(slot: Rect): Rect;
180
+ /** Let go with no drop: glides `home` from the release rect, which it returns. */
181
+ cancel(home: Rect): Rect;
182
+ }
183
+ /** Hold `item` from the pointer at `grab` (the pointer's offset from its top-left corner), at its drawn size now. */
184
+ declare function holdItem(item: LayoutItem, grab: Point): HeldDrag;
185
+
186
+ /** A rect as a DOM rect reports it (`getBoundingClientRect()`): left, top, width, height. */
187
+ interface RectLike {
188
+ readonly left: number;
189
+ readonly top: number;
190
+ readonly width: number;
191
+ readonly height: number;
192
+ }
193
+ /** Anything that can say where it is drawn: a DOM node, or a test's stand-in. */
194
+ interface Measurable {
195
+ getBoundingClientRect(): RectLike;
196
+ }
197
+ /** A {@link RectLike} as a {@link Rect}. */
198
+ declare const rectOf: (r: RectLike) => Rect;
199
+ /** One member of a {@link flip}: an item, the node it draws, and where it goes once the DOM has changed. */
200
+ interface FlipEntry {
201
+ readonly item: LayoutItem;
202
+ readonly node: Measurable;
203
+ /**
204
+ * Once the DOM has changed: the old rect (as measured before, in page coordinates) in the item's own coordinates
205
+ * now, and its new place there.
206
+ */
207
+ readonly place: (before: Rect) => {
208
+ readonly from: Rect;
209
+ readonly to: Rect;
210
+ };
211
+ }
212
+ /**
213
+ * FLIP for DOM groups, on settle: record where each node is drawn (first), change the DOM (`change`: move nodes to
214
+ * other parents, reorder them), then each item is drawn at its old rect and settles to its new place (last, invert,
215
+ * play). No transform tween: a settle from the rect it was drawn at, so it never jumps or overshoots, and its size
216
+ * changes through reveal.
217
+ */
218
+ declare function flip(entries: readonly FlipEntry[], change: () => void): void;
219
+
220
+ /**
221
+ * The style properties the layout motion writes, as strings (a DOM node's `style` has them all). Structural: the
222
+ * library needs no DOM types.
223
+ */
224
+ interface StyleLike {
225
+ left: string;
226
+ top: string;
227
+ width: string;
228
+ height: string;
229
+ transform: string;
230
+ opacity: string;
231
+ clipPath: string;
232
+ visibility: string;
233
+ }
234
+ /** Something with a writable {@link StyleLike} `style`: a DOM node. */
235
+ interface Styled {
236
+ readonly style: StyleLike;
237
+ }
238
+ /**
239
+ * The nodes of a drawn box: `node` is laid out at the box and moved to the drawn rect; `frame` (background, border,
240
+ * shadow) is drawn at the drawn size; `content` is clipped to it. With no `frame` and `content`, `node` itself is
241
+ * clipped (its content laid out at the box, never stretched).
242
+ */
243
+ interface BoxNodes {
244
+ readonly node: Styled;
245
+ readonly frame?: Styled;
246
+ readonly content?: Styled;
247
+ }
248
+ /** Lay `node` out at `box`: its position and size, in its offset parent's coordinates. */
249
+ declare function layOutBox(node: Styled, box: Rect): void;
250
+ /**
251
+ * Draw one frame of a box laid out by {@link layOutBox}: one transform (the move to the drawn rect, and the uniform
252
+ * appearance about its centre), the frame at the drawn size, the content clipped (reveal); hidden when gone.
253
+ */
254
+ declare function drawBox(nodes: BoxNodes, frame: DrawFrame): void;
255
+ /** A {@link Drawable} for DOM nodes: {@link layOutBox} on a new box, {@link drawBox} on every frame. */
256
+ declare function domDrawable(nodes: BoxNodes): Drawable;
257
+
258
+ export { type BoxNodes, type DrawFrame, type Drawable, type FlipEntry, type HeldDrag, type LayoutItem, type LayoutMotion, type LayoutMotionOptions, type LayoutTask, type Measurable, type RectLike, type StyleLike, type Styled, createLayoutMotion, domDrawable, drawBox, flip, holdItem, layOutBox, rectOf };