@n-uf/motion 26.11.2 → 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/CHANGELOG.md +72 -3
- package/README.md +137 -4
- package/dist/{chunk-NFQ4LIIR.js → chunk-C4M62FUT.js} +1 -1
- package/dist/chunk-C4M62FUT.js.map +1 -0
- package/dist/{chunk-LCTGXGOI.js → chunk-CM6WVNDH.js} +13 -61
- package/dist/chunk-CM6WVNDH.js.map +1 -0
- package/dist/chunk-WQQ2E25M.js +212 -0
- package/dist/chunk-WQQ2E25M.js.map +1 -0
- package/dist/drag.d.ts +202 -0
- package/dist/drag.js +151 -0
- package/dist/drag.js.map +1 -0
- package/dist/gestures.d.ts +1 -1
- package/dist/gestures.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +17 -3
- package/dist/layout.d.ts +258 -0
- package/dist/layout.js +312 -0
- package/dist/layout.js.map +1 -0
- package/dist/reveal-my7U6UyE.d.ts +51 -0
- package/dist/testing.d.ts +87 -0
- package/dist/testing.js +93 -0
- package/dist/testing.js.map +1 -0
- package/dist/values.d.ts +80 -4
- package/dist/values.js +15 -1
- package/package.json +13 -1
- package/dist/chunk-LCTGXGOI.js.map +0 -1
- package/dist/chunk-NFQ4LIIR.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,75 @@
|
|
|
3
3
|
Versions are calendar versions, `YY.M.R` (year, month of the release, counter
|
|
4
4
|
within the month), the same scheme as `@n-uf/hypr-tiling`.
|
|
5
5
|
|
|
6
|
+
## 26.11.4
|
|
7
|
+
|
|
8
|
+
- New entry `@n-uf/motion/drag`: the drag intent model, pure and DOM-free.
|
|
9
|
+
`createDragIntent({ home, tuning?, placeOf? })` takes the pointer once a
|
|
10
|
+
frame and plain-data targets (`{ id, priority, hit, slot?, label?, free? }`)
|
|
11
|
+
and says what the drop indicator shows, when the others make room, and what
|
|
12
|
+
a release lands on:
|
|
13
|
+
- the indicator shows only when the pointer has left home, a target is
|
|
14
|
+
under it, and it aims (below 0.45 px/ms over 50 ms, or within 12 px for
|
|
15
|
+
90 ms); crossing targets at speed shows nothing;
|
|
16
|
+
- the most precise target wins (priority, then the smaller zone), held
|
|
17
|
+
within a 10 px band unless a more precise one is 4 px inside; a 120 ms
|
|
18
|
+
gap grace for an aiming pointer;
|
|
19
|
+
- leaving the shown target, a flying pointer hides the indicator at once;
|
|
20
|
+
an aiming one moves it once the new target has held 150 ms; a target only
|
|
21
|
+
the grace keeps never shows;
|
|
22
|
+
- room after 160 ms, also when the place within a target changes; never
|
|
23
|
+
for a free target;
|
|
24
|
+
- a release lands on the shown target whenever one shows (drop = shown),
|
|
25
|
+
else the one under the pointer, else nowhere; over home it does nothing. `hide()` starts the
|
|
26
|
+
aim afresh (the next sample never aims).
|
|
27
|
+
`DRAG_DEFAULTS` holds the numbers, each overridable; `targetAt`, `inRect`
|
|
28
|
+
and `liftDecision` (a mouse lifts at 5 px, a touch after a 180 ms hold and
|
|
29
|
+
8 px) are there too.
|
|
30
|
+
- Three drop previews, one intent: `previewPlan(frame, preview, slotted?)`
|
|
31
|
+
gives `{ showIndicator, makeRoom, snapItem }` for `"indicator"` (nothing
|
|
32
|
+
moves; never room), `"gap"` (the others open the slot once the intent
|
|
33
|
+
makes room; the item stays under the pointer) and `"snap"` (the gap
|
|
34
|
+
opens and the item glides into a slot; a target without one keeps the
|
|
35
|
+
indicator). `DRAG_PREVIEW_DEFAULT` is `"snap"`.
|
|
36
|
+
- New entry `@n-uf/motion/layout`: the window motion rules applied to a whole
|
|
37
|
+
surface. `createLayoutMotion({ loop })` moves items by id and target rect,
|
|
38
|
+
all on one frame loop that runs only while something moves: a settle on
|
|
39
|
+
every new target from the drawn rect, size changes through reveal (never a
|
|
40
|
+
non-uniform scale), an immediate redraw when the layout box changes (no
|
|
41
|
+
frame at the old offset from the new box), and enter, exit and fold with a
|
|
42
|
+
uniform-scale fade. `holdItem` holds the real item 1:1 at the pointer (no
|
|
43
|
+
copy), snaps it into a slot and back, and lands or cancels from the release
|
|
44
|
+
rect; `preview(plan, slot)` plays the three drop previews of `./drag`'s
|
|
45
|
+
`previewPlan` (indicator and gap keep it under the pointer, snap glides it
|
|
46
|
+
into the slot); `resize(size)` takes a new size mid-drag, revealed from
|
|
47
|
+
where it is drawn. `flip` is FLIP for DOM groups on settle. `domDrawable`, `layOutBox`
|
|
48
|
+
and `drawBox` write DOM styles through structural shapes (no DOM types).
|
|
49
|
+
It animates the rects it is given; which items move where stays the
|
|
50
|
+
caller's.
|
|
51
|
+
- Nothing existing changes behaviour.
|
|
52
|
+
|
|
53
|
+
## 26.11.3
|
|
54
|
+
|
|
55
|
+
- New in `values/`: the window motion rules, the one motion model for
|
|
56
|
+
hypr-tiling and a host app's window surface.
|
|
57
|
+
- `createSettle(initial, { omega?, restDelta? })` and `settleValue(loop, …)`:
|
|
58
|
+
the curve for moving to a new place. A critically damped spring whose
|
|
59
|
+
velocity is set on every new target to `omega · distance` toward it, so it
|
|
60
|
+
follows `distance · e^(−omega·t)` from wherever it is drawn: front-loaded
|
|
61
|
+
(90 % in `ln(10)/omega` s), and it never passes its target, on position
|
|
62
|
+
or size, however often it is retargeted. A velocity set by hand toward
|
|
63
|
+
the target is capped at that speed; one away from it is kept. Tempos in
|
|
64
|
+
`SETTLE_TEMPO` (`calm` 20, `default` 25, `quick` 37 per second).
|
|
65
|
+
- `settle.hold(value)`: what a pointer owns sits exactly under it, at rest;
|
|
66
|
+
the next target launches from there.
|
|
67
|
+
- `reveal(drawn, target)`: draw a gliding window without stretching its
|
|
68
|
+
content (move, frame at the drawn size, clip the content laid out at the
|
|
69
|
+
target size). `popIn(progress, from = 0.87)`: uniform open and close.
|
|
70
|
+
- New entry `@n-uf/motion/testing`: frame-sampled checks of those rules
|
|
71
|
+
(`checkNoOvershoot`, `checkMonotonic`, `checkNoJumps`, `checkHeld`,
|
|
72
|
+
`checkContentScale`, `checkTempo`), each returning `{ ok, failures }`.
|
|
73
|
+
- Nothing existing changes behaviour.
|
|
74
|
+
|
|
6
75
|
## 26.11.2
|
|
7
76
|
|
|
8
77
|
- A two-finger pan is no longer taken for a pinch. One finger's event arrives
|
|
@@ -28,11 +97,11 @@ within the month), the same scheme as `@n-uf/hypr-tiling`.
|
|
|
28
97
|
resizes like Cmd+right-drag. Not when Ctrl is the drag modifier (Ctrl+drag
|
|
29
98
|
moves), and not for a pen, a finger or another platform.
|
|
30
99
|
`platformButton(press, platform, dragModifier)` is the rule on its own.
|
|
31
|
-
Ported from
|
|
100
|
+
Ported from a downstream app's input session, with its tests.
|
|
32
101
|
|
|
33
102
|
## 26.11.0
|
|
34
103
|
|
|
35
|
-
First version: the motion package of
|
|
104
|
+
First version: the motion package of a host app's layout-and-motion concept.
|
|
36
105
|
|
|
37
106
|
- **clock/**: `createFrameLoop` runs one-shot and repeating tasks in four
|
|
38
107
|
phases (input, update, layout, write), requests frames only while it has
|
|
@@ -47,7 +116,7 @@ First version: the motion package of the surface's layout-and-motion concept.
|
|
|
47
116
|
over numbers, points, rects and vectors; `motionValue` / `springValue` /
|
|
48
117
|
`tweenValue` step them on a loop as signals, with settle events and a
|
|
49
118
|
reduced-motion switch.
|
|
50
|
-
- **gestures/**:
|
|
119
|
+
- **gestures/**: a downstream app's input recogniser, made public:
|
|
51
120
|
`createRecognizer` (click or drag per device, double and triple click, long
|
|
52
121
|
press, pinch and two-finger pan, Safari's trackpad pinch, recovery from
|
|
53
122
|
lost releases), wheel normalisation and modifiers, with its long-press
|
package/README.md
CHANGED
|
@@ -21,15 +21,19 @@ npm i @n-uf/motion
|
|
|
21
21
|
recomputes only what depends on it, and effects can run once per frame.
|
|
22
22
|
- **values/**: springs and tweens over numbers, points, rects and vectors,
|
|
23
23
|
stepped by the clock, with velocity that carries over a retarget, settle
|
|
24
|
-
detection and a reduced-motion switch
|
|
24
|
+
detection and a reduced-motion switch; and the window motion rules:
|
|
25
|
+
`settle` (one fast-then-gentle curve that never passes its target), hold
|
|
26
|
+
(what a pointer owns sits exactly under it) and `reveal` (glide a window
|
|
27
|
+
without stretching its content).
|
|
25
28
|
- **gestures/**: a recogniser that turns pointer, wheel and trackpad events
|
|
26
29
|
(plain objects) into one gesture stream (click or drag, double click, long
|
|
27
30
|
press, pinch, scroll, zoom, recovery from lost releases), a frame coalescer,
|
|
28
31
|
and a dwell (spring-load) machine.
|
|
29
32
|
|
|
30
|
-
One package,
|
|
33
|
+
One package, seven entries: `@n-uf/motion` (everything in the core), its four
|
|
31
34
|
folders on their own (`@n-uf/motion/clock`, `/signals`, `/values`,
|
|
32
|
-
`/gestures`),
|
|
35
|
+
`/gestures`), `@n-uf/motion/testing` (frame-sampled checks of the motion
|
|
36
|
+
rules, for tests and browser specs), and `@n-uf/motion/browser`, the clock on
|
|
33
37
|
`requestAnimationFrame` and the reduced-motion media query. The core entries
|
|
34
38
|
touch no host; importing several of them still gives one signal graph.
|
|
35
39
|
|
|
@@ -155,6 +159,91 @@ rect.set({ x: 300, y: 40, width: 240, height: 100 });
|
|
|
155
159
|
clock.runUntilIdle(); // settled at { x: 300, y: 40, width: 240, height: 100 }
|
|
156
160
|
```
|
|
157
161
|
|
|
162
|
+
### Window motion: settle, hold, reveal
|
|
163
|
+
|
|
164
|
+
Three rules make windows move the way a tiling window manager feels smooth
|
|
165
|
+
(Hyprland is the reference): what the pointer holds is glued to it, everything
|
|
166
|
+
else moves on one front-loaded curve that never passes its target, and content
|
|
167
|
+
is never stretched.
|
|
168
|
+
|
|
169
|
+
| | |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `createSettle(initial, { omega?, restDelta? })` | The one curve for moving to a new place. On a new target every component gets the velocity `omega · distance` toward it from wherever it is drawn, so it follows `distance · e^(−omega·t)`: 90 % in `ln(10)/omega` s, then it eases in, and never passes the target (no overshoot on position, no wobble on size), however often it is retargeted. A velocity set by hand toward the target is capped at that speed; one away from it is kept, and the value turns around without crossing. |
|
|
172
|
+
| `SETTLE_TEMPO` | `{ calm: 20, default: 25, quick: 37 }` (1/s): 90 % in 115, 92 or 62 ms. |
|
|
173
|
+
| `settle.hold(value)` | Hold: put the value exactly there, at rest (same as `jumpTo`). Call it on each pointer move; the next `setTarget` launches from there. |
|
|
174
|
+
| `settleValue(loop, initial, { omega?, restDelta?, phase?, reducedMotion? })` | The settle on a frame loop. Hold it with `mv.jump(rect)`. |
|
|
175
|
+
| `reveal(drawn, target)` | How to draw a window gliding at `drawn` whose content is laid out at `target`: move the element by `dx, dy`, draw the frame (chrome) at `width × height`, clip the content by `clipRight, clipBottom`. No scale, no layout per frame. |
|
|
176
|
+
| `popIn(progress, from = 0.87)` | Opening and closing: a uniform scale about the centre plus opacity. Drive `progress` with a settle on a number with `{ restDelta: 0.001 }` (the default 0.1 is for pixels) or a tween. |
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { createFakeClock, createFrameLoop, settleValue } from "@n-uf/motion";
|
|
180
|
+
|
|
181
|
+
const clock = createFakeClock();
|
|
182
|
+
const loop = createFrameLoop({ clock });
|
|
183
|
+
const win = settleValue(loop, { x: 0, y: 0, width: 400, height: 300 });
|
|
184
|
+
win.set({ x: 400, y: 0, width: 200, height: 300 }); // a reflow: position and size arrive together
|
|
185
|
+
clock.frame();
|
|
186
|
+
win.set({ x: 300, y: 0, width: 300, height: 300 }); // retargeted mid-flight: on from where it is drawn
|
|
187
|
+
clock.runUntilIdle();
|
|
188
|
+
console.log(win.value); // { x: 300, y: 0, width: 300, height: 300 }, never past it on the way
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## layout/
|
|
192
|
+
|
|
193
|
+
`@n-uf/motion/layout` applies the window motion rules to a whole surface:
|
|
194
|
+
give each item an id and a target rect, and it moves the real elements, every
|
|
195
|
+
one on one frame loop that runs only while something moves. It animates the
|
|
196
|
+
rects it is given and nothing else: which items move where (making room,
|
|
197
|
+
drop targets) is the caller's layout.
|
|
198
|
+
|
|
199
|
+
| | |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `createLayoutMotion({ loop, omega?, phase?, popFrom? })` | The surface: `add(id, drawable, at, { shown? })`, `get`, `remove`, `items`; `task(fn)` runs before the items step each frame, `onFrame(fn)` after; `onIdle`, `idle()`, `running`, `wake()`, `configure({ omega })`, `dispose()`. |
|
|
202
|
+
| `item.moveTo(rect)` | Settle there from wherever it is drawn (a retarget mid-flight goes on from the drawn rect). The content is laid out at the new box once, and the item redrawn at once, so no frame shows the old offset from the new box. A size change is revealed, never scaled. |
|
|
203
|
+
| `item.jumpTo(rect)`, `item.hold(rect)`, `item.glideFrom(from, to)` | At once; held exactly where a pointer puts it (the content moves with it); drawn at `from`, then settle to `to`. |
|
|
204
|
+
| `item.show(on, { now? })` | Appear or disappear with a uniform-scale fade (`popIn`); folding is a `moveTo` to the folded size, revealed. |
|
|
205
|
+
| `item.drawn`, `target`, `box`, `settled`, `shown`, `showing`, `shownSettled` | Where it is drawn, where it is heading, where its content is laid out. |
|
|
206
|
+
| `holdItem(item, grab)` | A held drag of the real item, no copy: `move(pointer)` holds it 1:1 from the grab offset; `snapTo(slot)` glides into a slot, `snapTo(null)` back to the pointer (`follow()` once a frame until it is under it again); `land(slot)` and `cancel(home)` settle from the release rect, which they return. `preview(plan, slot)` once a frame plays a drop preview (`plan` from `@n-uf/motion/drag`'s `previewPlan`): indicator and gap keep the item under the pointer (gap with the caller's room open), snap glides it into the slot, and a release there finishes that glide. `resize(size)` holds it at a new size from now on (the caller laid its content out for it): the grab point keeps its share of the item, and it settles there from where it is drawn, revealed, never stretched (in a slot it stays put and takes the size when it leaves). |
|
|
207
|
+
| `flip(entries, change)` | FLIP for DOM groups on settle: record where each node is drawn, run `change` (the DOM moves), then each item glides from its old rect. |
|
|
208
|
+
| `domDrawable({ node, frame?, content? })`, `layOutBox`, `drawBox` | Draw onto DOM styles: the node laid out at the box, moved by one transform, the frame at the drawn size, the content (or the node) clipped; hidden when gone. Any `{ layOut, draw }` drawable works (a canvas, a test). |
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import { createFakeClock, createFrameLoop } from "@n-uf/motion";
|
|
212
|
+
import { createLayoutMotion, holdItem } from "@n-uf/motion/layout";
|
|
213
|
+
|
|
214
|
+
const clock = createFakeClock();
|
|
215
|
+
const loop = createFrameLoop({ clock });
|
|
216
|
+
const motion = createLayoutMotion({ loop });
|
|
217
|
+
const panel = motion.add("panel", { layOut: () => {}, draw: () => {} }, { x: 0, y: 0, width: 200, height: 100 });
|
|
218
|
+
panel.moveTo({ x: 300, y: 0, width: 240, height: 100 }); // a settle, its new width revealed
|
|
219
|
+
clock.runUntilIdle();
|
|
220
|
+
const held = holdItem(panel, { x: 20, y: 10 }); // grabbed 20 px in, 10 px down
|
|
221
|
+
held.move({ x: 120, y: 60 }); // held 1:1: drawn at { x: 100, y: 50 }
|
|
222
|
+
const release = held.land({ x: 0, y: 0, width: 200, height: 100 });
|
|
223
|
+
console.log(release); // { x: 100, y: 50, width: 240, height: 100 }: the landing starts there
|
|
224
|
+
clock.runUntilIdle();
|
|
225
|
+
console.log(panel.drawn); // { x: 0, y: 0, width: 200, height: 100 }
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## testing/
|
|
229
|
+
|
|
230
|
+
`@n-uf/motion/testing` checks recorded frames against the rules. Record what
|
|
231
|
+
was drawn each frame (on the fake clock, or in a browser spec once per
|
|
232
|
+
animation frame) and ask:
|
|
233
|
+
|
|
234
|
+
| | |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `checkNoOvershoot(samples, from, to, tolerance?)` | Every component stays between its start and end: no overshoot, no size wobble. |
|
|
237
|
+
| `checkMonotonic(samples, to, tolerance?)` | The distance to the target never grows: no bounce, no restart backwards. |
|
|
238
|
+
| `checkNoJumps(samples, omega, slack?)` | No frame moves further than a settle at `omega` could: catches snaps and restarts from an old place. Sample times are the stepped time (the loop's `delta`s), not wall-clock timestamps. |
|
|
239
|
+
| `checkHeld(samples, tolerance?)` | A held rect is where the pointer puts it, every frame. |
|
|
240
|
+
| `checkContentScale(samples, { uniformOnly?, tolerance? })` | Content's transform is never non-uniform (stretched); with `uniformOnly: false`, never scaled at all. |
|
|
241
|
+
| `checkTempo(samples, from, to, t90, tolerance?, startT?)` | 90 % of the way within `t90` ms of `startT` (default: the first sample, so record the frame the move began); returns the measured time too. |
|
|
242
|
+
|
|
243
|
+
Each returns `{ ok, failures }`, a failure naming the frame and component.
|
|
244
|
+
The motion lab in the [n-uf/motion repository](https://github.com/n-uf/motion)
|
|
245
|
+
(`apps/lab`) runs them on every move.
|
|
246
|
+
|
|
158
247
|
## gestures/
|
|
159
248
|
|
|
160
249
|
| | |
|
|
@@ -188,6 +277,50 @@ clock.tick(500); // longPress
|
|
|
188
277
|
recognizer.feed({ ...finger, type: "pointerup", buttons: 0, time: clock.now() }); // release, click: false
|
|
189
278
|
```
|
|
190
279
|
|
|
280
|
+
## drag/
|
|
281
|
+
|
|
282
|
+
`@n-uf/motion/drag` decides, from the pointer's path, when a drop indicator
|
|
283
|
+
shows, which target it shows, when the others make room, and what a release
|
|
284
|
+
lands on. It is pure: the host feeds it the pointer once a frame and plain-data
|
|
285
|
+
targets, and draws what it says. It is only there, not in the root.
|
|
286
|
+
|
|
287
|
+
| | |
|
|
288
|
+
|---|---|
|
|
289
|
+
| `createDragIntent({ home, tuning?, placeOf? })` | `update(point, time, targets)` once a frame while an item is held, returning `{ shown, room, roomPlace, aiming }`; `release(point, targets)`, the target a release lands on or null (home); `hide(time)` while the view scrolls under the pointer; `moveHome(dx, dy)`; `state`; `tuning`. |
|
|
290
|
+
| `DRAG_DEFAULTS` | Lift at 5 px (a touch: a 180 ms hold, then 8 px); aiming below 0.45 px/ms over 50 ms, or within 12 px for 90 ms; a 10 px band, a 4 px breakthrough, a 120 ms gap grace; a switch waits 150 ms; room after 160 ms. Each is overridable per intent. |
|
|
291
|
+
| `targetAt(targets, point)`, `inRect(rect, point, margin?)` | The most precise target under a point (priority 1, 2, 3, then the smaller zone); a point in a rect grown or shrunk by a margin. |
|
|
292
|
+
| `liftDecision({ touch, distance, elapsed }, tuning?)` | `"wait"`, `"lift"` or `"refuse"`: when a press becomes a drag. |
|
|
293
|
+
| `previewPlan(frame, preview, slotted?)`, `DragPreview`, `DRAG_PREVIEW_DEFAULT` | What to draw for a frame under one of three previews: `{ showIndicator, makeRoom, snapItem }`. `"indicator"`: only the indicator, nothing moves. `"gap"`: the others make room once the intent does; the item stays under the pointer. `"snap"` (the default): the gap opens and the item glides into a slotted target's room, with no indicator (a target without a slot keeps it). |
|
|
294
|
+
|
|
295
|
+
A target is `{ id, priority, hit, slot?, label?, free? }`: `hit` is the zone
|
|
296
|
+
the pointer can be in, `priority` how precise it is (a tab strip 1, a slot 2,
|
|
297
|
+
a large area 3). The rules:
|
|
298
|
+
|
|
299
|
+
- The indicator shows only when the pointer has left the item's home, a target
|
|
300
|
+
is under it, and the pointer aims (slows down or holds still). Crossing
|
|
301
|
+
targets at speed shows nothing.
|
|
302
|
+
- The current target holds within a band around its zone, unless a more
|
|
303
|
+
precise target is clearly under the pointer. Leaving the shown target, a
|
|
304
|
+
flying pointer hides the indicator at once; an aiming one moves it once the
|
|
305
|
+
new target has held 150 ms, so no indicator ever shows for less.
|
|
306
|
+
- Room is made once the shown target, and the place in it (`placeOf`: a tab
|
|
307
|
+
index, say), have held 160 ms; never for a `free` target.
|
|
308
|
+
- A release lands on the shown target whenever one shows (drop = shown), else
|
|
309
|
+
on the target under the pointer, else nowhere. A release over home does
|
|
310
|
+
nothing.
|
|
311
|
+
- The three previews only change what is drawn: all follow these rules, so a
|
|
312
|
+
drop lands where the preview showed it in each.
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import { createDragIntent, type DragTarget } from "@n-uf/motion/drag";
|
|
316
|
+
|
|
317
|
+
const slot: DragTarget = { id: "slot", priority: 2, hit: { x: 0, y: 0, width: 200, height: 100 } };
|
|
318
|
+
const intent = createDragIntent({ home: { x: 300, y: 300, width: 100, height: 50 } });
|
|
319
|
+
for (let t = 0; t <= 300; t += 16) intent.update({ x: 100, y: 50 }, t, [slot]); // held still over the slot
|
|
320
|
+
console.log(intent.state.shown?.id); // "slot"
|
|
321
|
+
console.log(intent.release({ x: 100, y: 50 }, [slot])?.id); // "slot"
|
|
322
|
+
```
|
|
323
|
+
|
|
191
324
|
## @n-uf/motion/browser
|
|
192
325
|
|
|
193
326
|
| | |
|
|
@@ -202,7 +335,7 @@ their own.
|
|
|
202
335
|
|
|
203
336
|
Everything runs on `createFakeClock()`: frames, timers, springs and machine
|
|
204
337
|
deadlines move only when the test moves the clock, so motion is exact and
|
|
205
|
-
repeatable.
|
|
338
|
+
repeatable. `@n-uf/motion/testing` (above) checks the frames you record.
|
|
206
339
|
|
|
207
340
|
## Benchmarks
|
|
208
341
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/gestures/types.ts","../src/gestures/modifiers.ts","../src/gestures/wheel.ts","../src/gestures/recognizer.ts","../src/gestures/coalescer.ts","../src/gestures/machine.ts","../src/gestures/dwell.ts"],"sourcesContent":["/**\n * Input types: plain event objects in, one gesture stream out. Nothing here\n * touches the DOM; the host copies the fields it needs out of PointerEvent /\n * WheelEvent / Safari's GestureEvent.\n *\n * Ported from a host app's input layer, whose recogniser this is.\n * Hit testing and routing (what is under a point, who gets a gesture) stay\n * with the host.\n */\n\nimport type { Point } from \"../shapes\";\n\nexport type PointerKind = \"mouse\" | \"pen\" | \"touch\";\n\n/** Pointer modifiers, ctrl included (the drag modifier may be \"ctrl\") */\nexport interface Modifiers {\n shift: boolean;\n alt: boolean;\n meta: boolean;\n ctrl: boolean;\n}\n\nexport type ModifierKey = keyof Modifiers;\n\n/** \"mac\": the drag modifier defaults to Cmd; \"other\": Alt (the OS keeps the Win/Super key) */\nexport type Platform = \"mac\" | \"other\";\n\nexport const NO_MODIFIERS: Readonly<Modifiers> = Object.freeze({ shift: false, alt: false, meta: false, ctrl: false });\n\n/**\n * A pointer as the gesture stream reports it (screen, canvas, kind, buttons,\n * modifiers) plus the fields a recogniser needs: which pointer, which button\n * changed, when.\n */\nexport interface SurfacePointer {\n screen: Point; // CSS px relative to the host's view\n canvas: Point; // the host's world units, through its camera at the time of the event (RecognizerOptions.toCanvas)\n kind: PointerKind;\n buttons: number; // PointerEvent.buttons bit mask\n modifiers: Modifiers;\n pointerId: number;\n /** PointerEvent.button: 0 primary, 1 middle, 2 secondary (a pen's barrel button), 5 eraser; -1 none changed */\n button: number;\n time: number; // event timeStamp, ms\n pressure?: number;\n}\n\n// ----------------------------------------------------------------------------\n// Raw events (copied out of DOM events by the host)\n// ----------------------------------------------------------------------------\n\nexport type RawPointerType = \"pointerdown\" | \"pointermove\" | \"pointerup\" | \"pointercancel\" | \"lostpointercapture\";\n\nexport interface RawPointerEvent {\n type: RawPointerType;\n pointerId: number;\n pointerType: PointerKind | string; // unknown types are treated as mouse\n isPrimary?: boolean;\n button: number;\n buttons: number;\n screen: Point; // clientX/Y minus the view's origin\n modifiers?: Partial<Modifiers>;\n time: number;\n pressure?: number;\n /**\n * lostpointercapture only: whose capture was lost. \"content\" (an element inside the view's content, e.g.\n * right after the host took the pointer for a modifier-drag) leaves the gesture alone; default \"surface\".\n */\n lostBy?: \"surface\" | \"content\";\n}\n\nexport interface RawWheelEvent {\n type: \"wheel\";\n deltaX: number;\n deltaY: number;\n /** 0 pixels, 1 lines, 2 pages */\n deltaMode: 0 | 1 | 2;\n screen: Point;\n modifiers?: Partial<Modifiers>;\n time: number;\n}\n\n/** Safari's trackpad pinch (GestureEvent): scale is relative to the gesture's start */\nexport interface RawSafariGestureEvent {\n type: \"gesturestart\" | \"gesturechange\" | \"gestureend\";\n scale: number;\n screen: Point;\n modifiers?: Partial<Modifiers>;\n time: number;\n}\n\nexport type RawInputEvent = RawPointerEvent | RawWheelEvent | RawSafariGestureEvent;\n\n// ----------------------------------------------------------------------------\n// The gesture stream\n// ----------------------------------------------------------------------------\n\n/** What a modifier-drag would do if the pointer travels with the drag modifier held */\nexport type ModifierDrag = \"move\" | \"resize\";\n\nexport type CancelReason =\n | \"pointercancel\" // the browser or OS took the pointer (scroll, system gesture, palm rejection)\n | \"lostcapture\" // pointer capture lost before the pointer went up\n | \"multitouch\" // a second finger turned the press into a pinch\n | \"missed-up\" // its pointerup never came (the same pointer pressed again, or another went down long after)\n | \"escape\"\n | \"reset\" // the view lost focus, the tool changed, the host was disposed\n | (string & {});\n\ninterface PointerGestureBase {\n pointer: SurfacePointer;\n /** The press that started this gesture */\n origin: SurfacePointer;\n}\n\nexport type InputGesture =\n /** A pointer went down (one per gesture; a second touch becomes a pinch instead) */\n | { type: \"press\"; pointer: SurfacePointer; modifierDrag: ModifierDrag | null }\n /** The pointer travelled past the click threshold; modifierDrag is set when the drag modifier was held then */\n | (PointerGestureBase & { type: \"dragStart\"; modifierDrag: ModifierDrag | null })\n /** A move after dragStart (moves inside the threshold are not reported) */\n | (PointerGestureBase & { type: \"move\" })\n /** Held still past the long-press delay (touch and pen by default); at most once per press */\n | (PointerGestureBase & { type: \"longPress\" })\n /**\n * The pointer went up. click: it never crossed the threshold and no long press fired;\n * clickCount counts quick clicks at the same spot (2 = double click).\n */\n | (PointerGestureBase & { type: \"release\"; click: boolean; clickCount: number; dragged: boolean })\n | (PointerGestureBase & { type: \"cancel\"; reason: CancelReason; dragged: boolean })\n /** A pointer moving with no press (mouse and pen hover): cursor and chrome hover */\n | { type: \"hover\"; pointer: SurfacePointer }\n /**\n * Two fingers (touch) or a trackpad pinch. scale is the change since the last update (multiply it in);\n * pan is the centre's screen-px change since the last update. kind is what was recognised first.\n */\n | {\n type: \"pinch\";\n phase: \"start\" | \"update\" | \"end\" | \"cancel\";\n source: \"touch\" | \"trackpad\";\n kind: \"pinch\" | \"pan\";\n center: { screen: Point; canvas: Point };\n scale: number;\n pan: Point;\n modifiers: Modifiers;\n time: number;\n }\n /** A wheel or trackpad scroll that is not a pinch: delta in screen px (lines and pages converted) */\n | { type: \"scroll\"; delta: Point; at: { screen: Point; canvas: Point }; modifiers: Modifiers; time: number }\n /**\n * Zoom by a factor around a point: Cmd/Ctrl+wheel, a trackpad pinch reported as ctrl+wheel\n * (Chrome, Firefox, Edge). Safari's trackpad pinch comes as \"pinch\" with source \"trackpad\".\n */\n | { type: \"zoom\"; factor: number; at: { screen: Point; canvas: Point }; modifiers: Modifiers; time: number };\n\nexport type InputGestureType = InputGesture[\"type\"];\n","/**\n * Modifier keys: event modifiers to one shape, and the drag modifier\n * resolved per platform (Cmd on macOS, Alt elsewhere; null turns it off).\n */\n\nimport { NO_MODIFIERS, type ModifierKey, type Modifiers, type Platform, type PointerKind } from \"./types\";\n\nexport function toModifiers(m: Partial<Modifiers> | undefined): Modifiers {\n if (!m) return { ...NO_MODIFIERS };\n return { shift: !!m.shift, alt: !!m.alt, meta: !!m.meta, ctrl: !!m.ctrl };\n}\n\n/** The default drag modifier: \"meta\" (Cmd) on macOS, \"alt\" elsewhere */\nexport function defaultDragModifier(platform: Platform): ModifierKey {\n return platform === \"mac\" ? \"meta\" : \"alt\";\n}\n\n/**\n * A configured drag modifier as used: undefined → the platform default, null → off.\n */\nexport function resolveDragModifier(config: ModifierKey | null | undefined, platform: Platform): ModifierKey | null {\n if (config === null) return null;\n return config ?? defaultDragModifier(platform);\n}\n\nexport function isHeld(modifiers: Modifiers, key: ModifierKey | null): boolean {\n return key !== null && modifiers[key];\n}\n\n/**\n * The button a press stands for on this platform. On macOS a Ctrl+click is the secondary click (the system's own\n * rule; the browser's contextmenu follows it), so a primary mouse press with Ctrl held is button 2 there, as a\n * right-click is. Not when Ctrl is the drag modifier (Ctrl+drag then moves). A pen, a finger and the other platforms\n * keep their button.\n */\nexport function platformButton(press: { kind: PointerKind; button: number; modifiers: Modifiers }, platform: Platform, dragModifier: ModifierKey | null): number {\n return platform === \"mac\" && press.kind === \"mouse\" && press.button === 0 && press.modifiers.ctrl && dragModifier !== \"ctrl\" ? 2 : press.button;\n}\n\n/** Platform \"Mod\": Cmd on macOS, Ctrl elsewhere (Mod+wheel zooms, Mod+click is content's multi-select) */\nexport function modHeld(modifiers: Modifiers, platform: Platform): boolean {\n return platform === \"mac\" ? modifiers.meta : modifiers.ctrl;\n}\n","/**\n * Wheel normalisation (Figma / tldraw style): lines and pages to pixels;\n * Cmd/Ctrl+wheel and the trackpad pinch (ctrl+wheel in Chrome, Firefox, Edge)\n * zoom by 2^(−dy / sensitivity); any other wheel scrolls, Shift turns\n * vertical into horizontal.\n */\n\nimport type { Point } from \"../shapes\";\nimport type { Modifiers } from \"./types\";\n\nexport interface WheelOptions {\n /** px per line (deltaMode 1); default 40 */\n lineHeight: number;\n /** px per page (deltaMode 2); default 800 */\n pageHeight: number;\n /** zoom factor = 2^(−deltaY / sensitivity); default 300 */\n zoomSensitivity: number;\n}\n\nexport const WHEEL_DEFAULTS: Readonly<WheelOptions> = Object.freeze({ lineHeight: 40, pageHeight: 800, zoomSensitivity: 300 });\n\nexport function wheelDeltaPx(deltaX: number, deltaY: number, deltaMode: 0 | 1 | 2, opts: WheelOptions = WHEEL_DEFAULTS): Point {\n const k = deltaMode === 1 ? opts.lineHeight : deltaMode === 2 ? opts.pageHeight : 1;\n return { x: finite(deltaX) * k, y: finite(deltaY) * k };\n}\n\nexport type WheelIntent = { kind: \"zoom\"; factor: number } | { kind: \"scroll\"; delta: Point };\n\n/**\n * What a wheel event means. Ctrl or Meta held: zoom (a trackpad pinch arrives as ctrl+wheel).\n * Otherwise scroll; with Shift a vertical-only delta scrolls horizontally (mice without a\n * horizontal wheel).\n */\nexport function classifyWheel(delta: Point, modifiers: Modifiers, opts: WheelOptions = WHEEL_DEFAULTS): WheelIntent {\n if (modifiers.ctrl || modifiers.meta) {\n const factor = Math.pow(2, -delta.y / (opts.zoomSensitivity > 0 ? opts.zoomSensitivity : WHEEL_DEFAULTS.zoomSensitivity));\n return { kind: \"zoom\", factor: Number.isFinite(factor) && factor > 0 ? factor : 1 };\n }\n if (modifiers.shift && delta.x === 0) return { kind: \"scroll\", delta: { x: delta.y, y: 0 } };\n return { kind: \"scroll\", delta };\n}\n\n/** Wheel pan damping for a camera that pans on scroll */\nexport interface WheelPanOptions {\n /** Multiplier on the wheel's px; default 0.65 */\n speed: number;\n /** Linear up to this many px per event; default 30 */\n threshold: number;\n /** Hard cap per event, px; default 60 */\n max: number;\n}\n\nexport const WHEEL_PAN_DEFAULTS: Readonly<WheelPanOptions> = Object.freeze({ speed: 0.65, threshold: 30, max: 60 });\n\n/**\n * The camera pan for one wheel scroll, per axis: speed × delta, linear up to the threshold, then\n * square-root damped (threshold + √(4 × excess)) and capped, so a fast flick of a free-spinning wheel or an\n * accelerated trackpad doesn't throw the canvas away.\n */\nexport function dampWheelPan(delta: Point, opts: WheelPanOptions = WHEEL_PAN_DEFAULTS): Point {\n const one = (d: number) => {\n const v = finite(d) * opts.speed;\n const abs = Math.abs(v);\n if (abs <= opts.threshold) return v;\n return Math.sign(v) * Math.min(opts.threshold + Math.sqrt((abs - opts.threshold) * 4), opts.max);\n };\n return { x: one(delta.x), y: one(delta.y) };\n}\n\nfunction finite(v: number): number {\n return Number.isFinite(v) ? v : 0;\n}\n","/**\n * The gesture recogniser: raw pointer, wheel and Safari gesture events (plain\n * objects) in, one stream of InputGesture out. Mouse, pen and touch share one\n * path; two fingers become a pinch (5 % scale or 10 px pan decides which, read\n * once both fingers have moved, so a pan's leading finger is no pinch); a\n * press becomes a drag only past a per-kind threshold, so a modifier+click\n * (Cmd/Ctrl+click to multi-select) stays a click for the content.\n *\n * One press at a time: a second mouse or pen while one is down is ignored, and\n * a second finger cancels the one-finger press (\"multitouch\") and starts a\n * pinch. After a pinch, the fingers left on the glass start nothing until all\n * are lifted.\n *\n * No DOM, no clock: timestamps come with the events and the long-press timer\n * is injected as the timer half of a ClockPort (without timers there is no\n * long press). The stale-press drop works from event timestamps, so it needs\n * no timer.\n */\n\nimport type { ClockPort } from \"../clock/port\";\nimport type { Point } from \"../shapes\";\nimport { isHeld, platformButton, toModifiers } from \"./modifiers\";\nimport type {\n CancelReason,\n InputGesture,\n ModifierDrag,\n ModifierKey,\n Platform,\n PointerKind,\n RawInputEvent,\n RawPointerEvent,\n RawSafariGestureEvent,\n RawWheelEvent,\n SurfacePointer,\n} from \"./types\";\nimport { classifyWheel, WHEEL_DEFAULTS, wheelDeltaPx, type WheelOptions } from \"./wheel\";\n\n/** The timer half of a ClockPort: any clock (createBrowserClock, createFakeClock) is one. */\nexport type RecognizerTimers = Pick<ClockPort, \"setTimer\" | \"clearTimer\">;\n\nexport interface RecognizerOptions {\n /** Screen px (relative to the view) to canvas units, through the current camera */\n toCanvas: (screen: Point) => Point;\n /** For the long press: a clock; without timers no long press fires */\n timers?: RecognizerTimers;\n /** The drag modifier, resolved (see resolveDragModifier); null = off */\n dragModifier?: ModifierKey | null;\n /** \"mac\": a mouse Ctrl+press is the secondary button, as the system has it (platformButton); default \"other\" */\n platform?: Platform;\n /** Click vs drag: a press becomes a drag after travelling more than this many screen px */\n thresholds?: Partial<Record<PointerKind, number>>;\n longPress?: { ms?: number; kinds?: readonly PointerKind[] };\n /** Two clicks within ms and px of each other count as a double click */\n multiClick?: { ms?: number; px?: number };\n pinch?: { scaleThreshold?: number; panThreshold?: number };\n wheel?: Partial<WheelOptions>;\n /** A mouse or pen press, or a resting finger outside any gesture, untouched this long when another pointer goes down, lost its pointerup; default 1000 ms */\n staleMs?: number;\n}\n\nexport const RECOGNIZER_DEFAULTS = Object.freeze({\n thresholds: Object.freeze({ mouse: 4, pen: 6, touch: 8 }) as Readonly<Record<PointerKind, number>>,\n longPress: Object.freeze({ ms: 500, kinds: Object.freeze([\"touch\", \"pen\"]) as readonly PointerKind[] }),\n multiClick: Object.freeze({ ms: 300, px: 5 }),\n pinch: Object.freeze({ scaleThreshold: 0.05, panThreshold: 10 }),\n});\n\nexport interface Recognizer {\n feed(event: RawInputEvent): void;\n /** Cancel the press and the pinch in flight (Escape, a tool change, the view losing focus) */\n cancel(reason: CancelReason): void;\n /** cancel(\"reset\") and forget every pointer (e.g. after the window lost focus mid-touch) */\n reset(): void;\n /** The press in flight, if any */\n active(): { pointerId: number; kind: PointerKind; dragging: boolean } | null;\n pinching(): boolean;\n /** Change the drag modifier; applies from the next press */\n setDragModifier(key: ModifierKey | null): void;\n dispose(): void;\n}\n\ninterface Press {\n origin: SurfacePointer;\n last: SurfacePointer;\n dragging: boolean;\n longPressed: boolean;\n /** What a modifier-drag would do; decided at the press, confirmed (modifier still held) at dragStart */\n candidate: ModifierDrag | null;\n modifierDrag: ModifierDrag | null;\n timer: number | undefined;\n}\n\ninterface Touch {\n screen: Point;\n time: number;\n}\n\ninterface Pinch {\n ids: [number, number];\n startDist: number;\n startCenter: Point;\n lastDist: number;\n lastCenter: Point;\n kind: \"pinch\" | \"pan\" | null;\n /** While undecided: each finger's moves (position changes) since the last look at the kind */\n reported: Map<number, number>;\n}\n\n/**\n * While two fingers are undecided, the kind is looked at once both have moved as often as each other since the last\n * look: one finger's events arrive before the other's (one or a burst), and a pan's leading finger alone changes the\n * distance like a pinch. A finger at rest sends no moves, so a finger this many moves ahead of the other is looked at\n * on its own (a pinch around an anchored thumb).\n */\nconst SOLO_MOVES = 3;\n\nfunction kindOf(pointerType: string): PointerKind {\n return pointerType === \"touch\" || pointerType === \"pen\" ? pointerType : \"mouse\";\n}\n\nfunction dist(a: Point, b: Point): number {\n return Math.hypot(a.x - b.x, a.y - b.y);\n}\n\nfunction mid(a: Point, b: Point): Point {\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n}\n\nfunction finitePoint(p: Point): Point {\n return { x: Number.isFinite(p.x) ? p.x : 0, y: Number.isFinite(p.y) ? p.y : 0 };\n}\n\nexport function createRecognizer(options: RecognizerOptions, emit: (gesture: InputGesture) => void): Recognizer {\n const thresholds = { ...RECOGNIZER_DEFAULTS.thresholds, ...options.thresholds };\n const longPressMs = options.longPress?.ms ?? RECOGNIZER_DEFAULTS.longPress.ms;\n const longPressKinds = options.longPress?.kinds ?? RECOGNIZER_DEFAULTS.longPress.kinds;\n const multiClick = { ...RECOGNIZER_DEFAULTS.multiClick, ...options.multiClick };\n const pinchCfg = { ...RECOGNIZER_DEFAULTS.pinch, ...options.pinch };\n const wheelCfg: WheelOptions = { ...WHEEL_DEFAULTS, ...options.wheel };\n const timers = options.timers;\n const staleMs = options.staleMs ?? 1000;\n let dragModifier: ModifierKey | null = options.dragModifier ?? null;\n const platform: Platform = options.platform ?? \"other\";\n\n let press: Press | null = null;\n let pinch: Pinch | null = null;\n const touches = new Map<number, Touch>();\n /** After a pinch (or a reset mid-touch), fingers still down start nothing until all are up */\n let touchLocked = false;\n let lastClick: { time: number; screen: Point; button: number; count: number } | null = null;\n let safari: { last: number } | null = null;\n let lastTime = 0;\n let disposed = false;\n\n const pointerOf = (e: RawPointerEvent): SurfacePointer => {\n const screen = finitePoint(e.screen);\n return {\n screen,\n canvas: options.toCanvas(screen),\n kind: kindOf(e.pointerType),\n buttons: e.buttons,\n modifiers: toModifiers(e.modifiers),\n pointerId: e.pointerId,\n button: e.button,\n time: e.time,\n ...(e.pressure !== undefined ? { pressure: e.pressure } : {}),\n };\n };\n\n const clearTimer = (p: Press) => {\n if (p.timer !== undefined && timers) timers.clearTimer(p.timer);\n p.timer = undefined;\n };\n\n const endPress = (): Press | null => {\n const p = press;\n if (p) clearTimer(p);\n press = null;\n return p;\n };\n\n const cancelPress = (reason: CancelReason, pointer?: SurfacePointer) => {\n const p = endPress();\n if (!p) return;\n emit({ type: \"cancel\", pointer: pointer ?? p.last, origin: p.origin, reason, dragged: p.dragging });\n };\n\n const releasePress = (pointer: SurfacePointer) => {\n const p = endPress();\n if (!p) return;\n const click = !p.dragging && !p.longPressed;\n let clickCount = 0;\n if (click) {\n const prev = lastClick;\n const repeat =\n !!prev &&\n prev.button === p.origin.button &&\n p.origin.time - prev.time <= multiClick.ms &&\n dist(prev.screen, p.origin.screen) <= multiClick.px;\n clickCount = repeat ? prev!.count + 1 : 1;\n lastClick = { time: pointer.time, screen: p.origin.screen, button: p.origin.button, count: clickCount };\n } else {\n lastClick = null;\n }\n emit({ type: \"release\", pointer, origin: p.origin, click, clickCount, dragged: p.dragging });\n };\n\n const pinchState = (): { center: Point; d: number } | null => {\n if (!pinch) return null;\n const a = touches.get(pinch.ids[0]);\n const b = touches.get(pinch.ids[1]);\n if (!a || !b) return null;\n return { center: mid(a.screen, b.screen), d: Math.max(1, dist(a.screen, b.screen)) };\n };\n\n const pinchEvent = (\n phase: \"start\" | \"update\" | \"end\" | \"cancel\",\n center: Point,\n scale: number,\n pan: Point,\n time: number,\n modifiers: SurfacePointer[\"modifiers\"],\n source: \"touch\" | \"trackpad\",\n kind: \"pinch\" | \"pan\",\n ): InputGesture => ({\n type: \"pinch\",\n phase,\n source,\n kind,\n center: { screen: center, canvas: options.toCanvas(center) },\n scale,\n pan,\n modifiers,\n time,\n });\n\n const endPinch = (phase: \"end\" | \"cancel\", time: number, modifiers: SurfacePointer[\"modifiers\"]) => {\n const p = pinch;\n pinch = null;\n touchLocked = touches.size > 0;\n if (p && p.kind) emit(pinchEvent(phase, p.lastCenter, 1, { x: 0, y: 0 }, time, modifiers, \"touch\", p.kind));\n };\n\n /**\n * A pinch finger moved (`id`), or lifts (`lifting`: the last look, whatever moved). The kind is decided on both\n * fingers' latest positions (see SOLO_MOVES); the thresholds keep their meaning.\n */\n const updatePinch = (id: number, time: number, modifiers: SurfacePointer[\"modifiers\"], moved: boolean, lifting = false) => {\n const p = pinch;\n const now = pinchState();\n if (!p || !now) return;\n if (!p.kind) {\n if (!moved && !lifting) return; // a move that changed nothing (pressure only) is no move\n const moves = (p.reported.get(id) ?? 0) + (moved ? 1 : 0);\n p.reported.set(id, moves);\n const other = p.reported.get(p.ids[0] === id ? p.ids[1] : p.ids[0]) ?? 0;\n const even = moves > 0 && moves === other;\n if (!lifting && !even && Math.abs(moves - other) < SOLO_MOVES) return;\n p.reported.clear();\n const scaleChange = Math.abs(now.d / p.startDist - 1);\n const panDist = dist(now.center, p.startCenter);\n if (scaleChange > pinchCfg.scaleThreshold) p.kind = \"pinch\";\n else if (panDist > pinchCfg.panThreshold) p.kind = \"pan\";\n else return;\n // The first event carries everything since the second finger landed, so nothing is lost.\n const scale = p.kind === \"pinch\" ? now.d / p.startDist : 1;\n const pan = { x: now.center.x - p.startCenter.x, y: now.center.y - p.startCenter.y };\n p.lastDist = now.d;\n p.lastCenter = now.center;\n emit(pinchEvent(\"start\", now.center, scale, pan, time, modifiers, \"touch\", p.kind));\n return;\n }\n const scale = p.kind === \"pinch\" ? now.d / p.lastDist : 1;\n const pan = { x: now.center.x - p.lastCenter.x, y: now.center.y - p.lastCenter.y };\n p.lastDist = now.d;\n p.lastCenter = now.center;\n if (scale === 1 && pan.x === 0 && pan.y === 0) return;\n emit(pinchEvent(\"update\", now.center, scale, pan, time, modifiers, \"touch\", p.kind));\n };\n\n /**\n * A pointerup that never came (released outside the page, a pen lifted out of range, a lost event):\n * a press of the same pointer, or a mouse / pen press untouched for staleMs, is over. A finger that\n * lands again under its old id, or one resting untouched for staleMs outside any press or pinch, is gone.\n */\n const dropMissedUps = (e: RawPointerEvent, kind: PointerKind) => {\n const p = press;\n if (p) {\n const same = p.origin.pointerId === e.pointerId;\n const mixed = kind !== \"touch\" || p.origin.kind !== \"touch\"; // two fingers make a pinch, never a stale press\n if (same || (mixed && e.time - p.last.time > staleMs)) cancelPress(\"missed-up\");\n }\n if (kind !== \"touch\") return;\n if (touches.has(e.pointerId)) {\n if (pinch?.ids.includes(e.pointerId)) endPinch(\"cancel\", e.time, toModifiers(e.modifiers));\n touches.delete(e.pointerId);\n }\n for (const [id, t] of touches) {\n const busy = press?.origin.pointerId === id || !!pinch?.ids.includes(id);\n if (!busy && e.time - t.time > staleMs) touches.delete(id);\n }\n if (touches.size === 0) touchLocked = false;\n };\n\n const onDown = (e: RawPointerEvent) => {\n const down = pointerOf(e);\n // The press's button as the platform means it (macOS: Ctrl+click is a secondary click)\n const pointer: SurfacePointer = { ...down, button: platformButton(down, platform, dragModifier) };\n dropMissedUps(e, pointer.kind);\n if (pointer.kind === \"touch\") {\n touches.set(e.pointerId, { screen: pointer.screen, time: pointer.time });\n if (touchLocked || pinch) return; // a third finger, or fingers after a pinch\n if (touches.size === 2) {\n const ids = [...touches.keys()] as [number, number];\n // The second finger: whatever the first one started is cancelled, a pinch may begin.\n if (press && press.origin.kind === \"touch\") cancelPress(\"multitouch\");\n else if (press) {\n touches.delete(e.pointerId); // a mouse or pen press owns the input; ignore the finger\n return;\n }\n const a = touches.get(ids[0])!;\n const b = touches.get(ids[1])!;\n const d = Math.max(1, dist(a.screen, b.screen));\n const c = mid(a.screen, b.screen);\n pinch = { ids, startDist: d, startCenter: c, lastDist: d, lastCenter: c, kind: null, reported: new Map() };\n return;\n }\n if (touches.size > 2) return;\n }\n if (press || pinch) return; // one press at a time\n const candidate: ModifierDrag | null = isHeld(pointer.modifiers, dragModifier)\n ? pointer.button === 0\n ? \"move\"\n : pointer.button === 2\n ? \"resize\"\n : null\n : null;\n const p: Press = {\n origin: pointer,\n last: pointer,\n dragging: false,\n longPressed: false,\n candidate,\n modifierDrag: null,\n timer: undefined,\n };\n press = p;\n if (timers && longPressKinds.includes(pointer.kind)) {\n p.timer = timers.setTimer(() => {\n p.timer = undefined;\n if (press !== p || p.dragging || disposed) return;\n p.longPressed = true;\n emit({ type: \"longPress\", pointer: p.last, origin: p.origin });\n }, longPressMs);\n }\n emit({ type: \"press\", pointer, modifierDrag: candidate });\n };\n\n const onMove = (e: RawPointerEvent) => {\n const kind = kindOf(e.pointerType);\n if (kind === \"touch\") {\n const t = touches.get(e.pointerId);\n const to = finitePoint(e.screen);\n const moved = !t || t.screen.x !== to.x || t.screen.y !== to.y;\n if (t) {\n t.screen = to;\n t.time = e.time;\n }\n if (pinch && pinch.ids.includes(e.pointerId)) {\n updatePinch(e.pointerId, e.time, toModifiers(e.modifiers), moved);\n return;\n }\n }\n if (press && press.origin.pointerId === e.pointerId) {\n const pointer = pointerOf(e);\n // A mouse or pen moving with no button down and no pointerup before it: the release was missed.\n if (pointer.kind !== \"touch\" && e.buttons === 0) {\n releasePress(pointer);\n return;\n }\n const p = press;\n p.last = pointer;\n if (!p.dragging) {\n if (dist(pointer.screen, p.origin.screen) <= thresholds[p.origin.kind]) return;\n p.dragging = true;\n clearTimer(p);\n // The modifier must still be held when the drag starts: a released Cmd makes it a plain drag.\n p.modifierDrag = p.candidate && isHeld(pointer.modifiers, dragModifier) ? p.candidate : null;\n emit({ type: \"dragStart\", pointer, origin: p.origin, modifierDrag: p.modifierDrag });\n return;\n }\n emit({ type: \"move\", pointer, origin: p.origin });\n return;\n }\n if (!press && kind !== \"touch\" && e.buttons === 0) emit({ type: \"hover\", pointer: pointerOf(e) });\n };\n\n const onUp = (e: RawPointerEvent) => {\n if (kindOf(e.pointerType) === \"touch\") {\n // A finger lifting from an undecided pinch: its last position is looked at once, so a quick pinch still counts\n const t = touches.get(e.pointerId);\n if (t && pinch && !pinch.kind && pinch.ids.includes(e.pointerId)) {\n const to = finitePoint(e.screen);\n const moved = t.screen.x !== to.x || t.screen.y !== to.y;\n t.screen = to;\n updatePinch(e.pointerId, e.time, toModifiers(e.modifiers), moved, true);\n }\n touches.delete(e.pointerId);\n if (pinch && pinch.ids.includes(e.pointerId)) {\n endPinch(\"end\", e.time, toModifiers(e.modifiers));\n return;\n }\n if (touches.size === 0) touchLocked = false;\n }\n if (press && press.origin.pointerId === e.pointerId) releasePress(pointerOf(e));\n };\n\n const onCancel = (e: RawPointerEvent, reason: CancelReason) => {\n if (kindOf(e.pointerType) === \"touch\") {\n const tracked = touches.delete(e.pointerId);\n if (pinch && pinch.ids.includes(e.pointerId)) {\n if (tracked) endPinch(\"cancel\", e.time, toModifiers(e.modifiers));\n return;\n }\n if (touches.size === 0) touchLocked = false;\n }\n if (press && press.origin.pointerId === e.pointerId) cancelPress(reason, pointerOf(e));\n };\n\n const onWheel = (e: RawWheelEvent) => {\n const modifiers = toModifiers(e.modifiers);\n const screen = finitePoint(e.screen);\n const at = { screen, canvas: options.toCanvas(screen) };\n const intent = classifyWheel(wheelDeltaPx(e.deltaX, e.deltaY, e.deltaMode, wheelCfg), modifiers, wheelCfg);\n if (intent.kind === \"zoom\") {\n if (intent.factor !== 1) emit({ type: \"zoom\", factor: intent.factor, at, modifiers, time: e.time });\n return;\n }\n if (intent.delta.x === 0 && intent.delta.y === 0) return;\n emit({ type: \"scroll\", delta: intent.delta, at, modifiers, time: e.time });\n };\n\n const onSafari = (e: RawSafariGestureEvent) => {\n // iOS Safari fires gesture events for touch pinches too; the pointer path handles those.\n if (touches.size > 0 || pinch) return;\n const modifiers = toModifiers(e.modifiers);\n const screen = finitePoint(e.screen);\n const scaleNow = Number.isFinite(e.scale) && e.scale > 0 ? e.scale : 1;\n const none = { x: 0, y: 0 };\n if (e.type === \"gesturestart\") {\n safari = { last: scaleNow };\n emit(pinchEvent(\"start\", screen, 1, none, e.time, modifiers, \"trackpad\", \"pinch\"));\n return;\n }\n if (!safari) return;\n const scale = scaleNow / safari.last;\n safari.last = scaleNow;\n if (e.type === \"gesturechange\") {\n if (scale !== 1) emit(pinchEvent(\"update\", screen, scale, none, e.time, modifiers, \"trackpad\", \"pinch\"));\n return;\n }\n safari = null;\n emit(pinchEvent(\"end\", screen, scale, none, e.time, modifiers, \"trackpad\", \"pinch\"));\n };\n\n const cancelAll = (reason: CancelReason) => {\n cancelPress(reason);\n if (pinch) endPinch(\"cancel\", lastTime, toModifiers(undefined));\n if (safari) {\n safari = null;\n emit(pinchEvent(\"cancel\", { x: 0, y: 0 }, 1, { x: 0, y: 0 }, lastTime, toModifiers(undefined), \"trackpad\", \"pinch\"));\n }\n };\n\n return {\n feed(event) {\n if (disposed) return;\n if (Number.isFinite(event.time)) lastTime = event.time;\n switch (event.type) {\n case \"pointerdown\":\n return onDown(event);\n case \"pointermove\":\n return onMove(event);\n case \"pointerup\":\n return onUp(event);\n case \"pointercancel\":\n return onCancel(event, \"pointercancel\");\n case \"lostpointercapture\":\n // Also fires right after pointerup; by then the press is gone and this is a no-op. The content\n // losing its capture (the surface just took the pointer) is not the gesture's end.\n if (event.lostBy === \"content\") return;\n return onCancel(event, \"lostcapture\");\n case \"wheel\":\n return onWheel(event);\n case \"gesturestart\":\n case \"gesturechange\":\n case \"gestureend\":\n return onSafari(event);\n }\n },\n cancel: cancelAll,\n reset() {\n cancelAll(\"reset\");\n touches.clear();\n touchLocked = false;\n lastClick = null;\n },\n active() {\n return press ? { pointerId: press.origin.pointerId, kind: press.origin.kind, dragging: press.dragging } : null;\n },\n pinching() {\n return !!pinch?.kind || !!safari;\n },\n setDragModifier(key) {\n dragModifier = key;\n },\n dispose() {\n if (press) clearTimer(press);\n press = null;\n pinch = null;\n safari = null;\n touches.clear();\n disposed = true;\n },\n };\n}\n","import type { FrameSource } from \"../clock/port\";\n\n/** Options of {@link createFrameCoalescer}. */\nexport interface CoalescerOptions<T> {\n /**\n * How a new sample folds into the pending one. Default: keep the latest\n * (pointer positions). Wheel deltas want a sum instead.\n */\n readonly merge?: (pending: T, next: T) => T;\n}\n\n/**\n * Collapses a burst of samples into at most one delivery per frame. Same\n * shape as hypr-tiling's `createFrameCoalescer` (`schedule`, `cancel`),\n * plus `flush` and `pending`.\n */\nexport interface FrameCoalescer<T> {\n /** Record a sample and make sure a frame is requested. */\n schedule(sample: T): void;\n /**\n * Deliver the pending sample now, if there is one (before a pointer-up, so\n * the last move is seen first). Returns whether it delivered.\n */\n flush(): boolean;\n /** Drop the pending sample and the requested frame. Nothing is delivered after this. */\n cancel(): void;\n /** Whether a sample is waiting for its frame. */\n readonly pending: boolean;\n}\n\n/**\n * Deliver samples to `onFrame` once per frame of `frames`: the browser clock,\n * the fake clock, or a frame loop phase (`loop.frames(\"input\")`). `onFrame`\n * also gets how many samples were folded into this one.\n */\nexport function createFrameCoalescer<T>(\n onFrame: (sample: T, count: number) => void,\n frames: FrameSource,\n options: CoalescerOptions<T> = {},\n): FrameCoalescer<T> {\n const merge = options.merge;\n let handle: number | null = null;\n let sample: T | undefined;\n let count = 0;\n\n const deliver = (): void => {\n const delivered = sample as T;\n const folded = count;\n sample = undefined;\n count = 0;\n onFrame(delivered, folded);\n };\n\n const onFrameDue = (): void => {\n handle = null;\n if (count > 0) deliver();\n };\n\n return {\n schedule(next) {\n sample = count > 0 && merge !== undefined ? merge(sample as T, next) : next;\n count++;\n if (handle === null) handle = frames.requestFrame(onFrameDue);\n },\n flush() {\n if (handle !== null) {\n frames.cancelFrame(handle);\n handle = null;\n }\n if (count === 0) return false;\n deliver();\n return true;\n },\n cancel() {\n if (handle !== null) {\n frames.cancelFrame(handle);\n handle = null;\n }\n sample = undefined;\n count = 0;\n },\n get pending() {\n return count > 0;\n },\n };\n}\n","import type { TimerSource } from \"../clock/port\";\nimport { signal } from \"../signals/signals\";\n\n/**\n * A timer event a state asks for: send `event(t)` when the clock reaches\n * `at`. Machines stay pure; this is how a long-press or a dwell turns into\n * an event without the reducer touching a timer.\n */\nexport interface Deadline<E> {\n /** Clock time in ms. */\n readonly at: number;\n /** The event to send, given the clock time it fired at. */\n readonly event: (t: number) => E;\n}\n\n/** Options of {@link createMachine}. */\nexport interface MachineOptions<S, E> {\n /** The pure transition function. Returning the same state means \"no change\". */\n readonly reducer: (state: S, event: E) => S;\n readonly initial: S;\n /** Timers come from here (and `now()` for their events). */\n readonly clock: TimerSource;\n /** The timer event the state needs, or `null`. Checked after every transition. */\n readonly deadline?: (state: S) => Deadline<E> | null;\n}\n\n/** A running machine: the state, a way to send events, and change listeners. */\nexport interface Machine<S, E> {\n /** The current state; reactive (read it in a computed or an effect). */\n readonly state: S;\n /** The current state, untracked. */\n peek(): S;\n /**\n * Run `event` through the reducer and return the new state. An event sent\n * from a listener waits until the current one has been handled.\n */\n send(event: E): S;\n /** Called after each change of state (not for events that changed nothing). */\n subscribe(listener: (next: S, previous: S, event: E) => void): () => void;\n /** Clear the timer and drop listeners. Events sent after this are ignored. */\n dispose(): void;\n}\n\n/** Run a pure machine on a clock: it arms and clears the deadline timer for you. */\nexport function createMachine<S, E>(options: MachineOptions<S, E>): Machine<S, E> {\n const { reducer, clock, deadline } = options;\n const state = signal(options.initial);\n const listeners = new Set<(next: S, previous: S, event: E) => void>();\n const inbox: E[] = [];\n let dispatching = false;\n let disposed = false;\n let timer: number | null = null;\n let timerAt: number | null = null;\n let timerEvent: ((t: number) => E) | null = null;\n\n const clearTimer = (): void => {\n if (timer !== null) clock.clearTimer(timer);\n timer = null;\n timerAt = null;\n timerEvent = null;\n };\n\n const arm = (): void => {\n const due = deadline === undefined ? null : deadline(state.peek());\n if (due === null) {\n clearTimer();\n return;\n }\n timerEvent = due.event;\n if (timer !== null && timerAt === due.at) return;\n if (timer !== null) clock.clearTimer(timer);\n timerAt = due.at;\n timer = clock.setTimer(() => {\n const make = timerEvent;\n timer = null;\n timerAt = null;\n timerEvent = null;\n if (make !== null) machine.send(make(clock.now()));\n }, Math.max(0, due.at - clock.now()));\n };\n\n const machine: Machine<S, E> = {\n get state() {\n return state.value;\n },\n peek: () => state.peek(),\n send(event) {\n if (disposed) return state.peek();\n inbox.push(event);\n if (dispatching) return state.peek();\n dispatching = true;\n try {\n let next: E | undefined;\n while ((next = inbox.shift()) !== undefined) {\n const previous = state.peek();\n const after = reducer(previous, next);\n if (after === previous) continue;\n state.value = after;\n arm();\n for (const listener of Array.from(listeners)) listener(after, previous, next);\n if (disposed) break;\n }\n } finally {\n dispatching = false;\n inbox.length = 0;\n }\n return state.peek();\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n dispose() {\n if (disposed) return;\n disposed = true;\n clearTimer();\n listeners.clear();\n },\n };\n arm();\n return machine;\n}\n","import type { TimerSource } from \"../clock/port\";\nimport { createMachine, type Deadline, type Machine } from \"./machine\";\n\n/**\n * The dwell machine (spring-load): hold over the same target long enough and\n * it fires, once.\n *\n * ```text\n * idle ──hover(key)──► dwelling ──tick (t − since ≥ dwellMs)──► fired\n * ▲ │ hover(other key) restarts `since` │\n * │ │ hover(null) ─► idle │\n * └────────┴─────────────── reset ◄─────────────────────┘\n * ```\n *\n * `fired` holds until `reset`: neither a late tick nor a hover change can fire\n * it again or clear it while the host acts on it. Shapes come from\n * hypr-tiling's `springLoadReducer`, with its workspace tab generalised to\n * any `key` (the host passes `null` for anything that shouldn't dwell, such as\n * the active tab).\n */\n\n/** Tunables of the dwell machine. */\nexport interface DwellConfig {\n /** How long in ms the pointer must stay over the same key. Default 500. */\n readonly dwellMs: number;\n}\n\n/** Defaults of {@link DwellConfig}. */\nexport const DWELL_DEFAULTS: DwellConfig = { dwellMs: 500 };\n\n/** The dwell machine's state. `K` is the target key, `P` the payload carried into `fired`. */\nexport type DwellState<K = string, P = unknown> =\n | { readonly phase: \"idle\" }\n | { readonly phase: \"dwelling\"; readonly key: K; readonly since: number; readonly payload: P | undefined }\n | {\n readonly phase: \"fired\";\n readonly key: K;\n readonly since: number;\n readonly firedAt: number;\n readonly payload: P | undefined;\n };\n\n/** Events of the dwell machine. `t` is the clock time in ms. */\nexport type DwellInput<K = string, P = unknown> =\n | { readonly type: \"hover\"; readonly t: number; readonly key: K | null; readonly payload?: P }\n | { readonly type: \"tick\"; readonly t: number }\n | { readonly type: \"reset\" };\n\n/** The idle state (the same object every time). */\nexport const DWELL_IDLE: DwellState<never, never> = { phase: \"idle\" };\n\n/** The dwell machine's pure transition function. */\nexport function dwellReducer<K, P>(\n state: DwellState<K, P>,\n event: DwellInput<K, P>,\n config: DwellConfig = DWELL_DEFAULTS,\n): DwellState<K, P> {\n switch (event.type) {\n case \"reset\":\n return state.phase === \"idle\" ? state : DWELL_IDLE;\n case \"hover\":\n if (state.phase === \"fired\") return state;\n if (event.key === null) return state.phase === \"idle\" ? state : DWELL_IDLE;\n if (state.phase === \"dwelling\" && Object.is(state.key, event.key)) return state;\n return { phase: \"dwelling\", key: event.key, since: event.t, payload: event.payload };\n case \"tick\":\n if (state.phase !== \"dwelling\" || event.t - state.since < config.dwellMs) return state;\n return { phase: \"fired\", key: state.key, since: state.since, firedAt: event.t, payload: state.payload };\n default:\n return state;\n }\n}\n\n/** When a dwelling state fires, as a timer event; `null` outside `dwelling`. */\nexport function dwellDeadline<K, P>(\n state: DwellState<K, P>,\n config: DwellConfig = DWELL_DEFAULTS,\n): Deadline<DwellInput<K, P>> | null {\n if (state.phase !== \"dwelling\") return null;\n return { at: state.since + config.dwellMs, event: (t) => ({ type: \"tick\", t }) };\n}\n\n/** Options of {@link createDwellMachine}. */\nexport interface DwellMachineOptions {\n readonly clock: TimerSource;\n readonly config?: Partial<DwellConfig>;\n}\n\n/** A dwell machine on a clock: the dwell timer is armed for you. */\nexport function createDwellMachine<K = string, P = unknown>(\n options: DwellMachineOptions,\n): Machine<DwellState<K, P>, DwellInput<K, P>> {\n const config: DwellConfig = { ...DWELL_DEFAULTS, ...options.config };\n return createMachine<DwellState<K, P>, DwellInput<K, P>>({\n reducer: (state, event) => dwellReducer(state, event, config),\n initial: DWELL_IDLE,\n clock: options.clock,\n deadline: (state) => dwellDeadline(state, config),\n });\n}\n"],"mappings":"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","names":["scale","pan"]}
|
|
@@ -4,6 +4,14 @@ import {
|
|
|
4
4
|
signal,
|
|
5
5
|
untracked
|
|
6
6
|
} from "./chunk-OOKRBVMB.js";
|
|
7
|
+
import {
|
|
8
|
+
createSettle,
|
|
9
|
+
layoutOf,
|
|
10
|
+
makeValue,
|
|
11
|
+
sameLayout,
|
|
12
|
+
shapeEquals,
|
|
13
|
+
writeComponents
|
|
14
|
+
} from "./chunk-WQQ2E25M.js";
|
|
7
15
|
|
|
8
16
|
// src/values/easing.ts
|
|
9
17
|
var linear = (t) => t;
|
|
@@ -52,65 +60,6 @@ var easeInOut = /* @__PURE__ */ cubicBezier(0.42, 0, 0.58, 1);
|
|
|
52
60
|
var easeOutCubic = (t) => 1 - (1 - t) ** 3;
|
|
53
61
|
var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
54
62
|
|
|
55
|
-
// src/shapes.ts
|
|
56
|
-
var SCALAR = 0;
|
|
57
|
-
var VECTOR = 1;
|
|
58
|
-
var POINT = 2;
|
|
59
|
-
var RECT = 3;
|
|
60
|
-
var SCALAR_LAYOUT = { kind: SCALAR, size: 1 };
|
|
61
|
-
var POINT_LAYOUT = { kind: POINT, size: 2 };
|
|
62
|
-
var RECT_LAYOUT = { kind: RECT, size: 4 };
|
|
63
|
-
function layoutOf(value) {
|
|
64
|
-
if (typeof value === "number") return SCALAR_LAYOUT;
|
|
65
|
-
if (Array.isArray(value)) return { kind: VECTOR, size: value.length };
|
|
66
|
-
if ("width" in value) return RECT_LAYOUT;
|
|
67
|
-
return POINT_LAYOUT;
|
|
68
|
-
}
|
|
69
|
-
function sameLayout(a, b) {
|
|
70
|
-
return a.kind === b.kind && a.size === b.size;
|
|
71
|
-
}
|
|
72
|
-
function writeComponents(value, out) {
|
|
73
|
-
if (typeof value === "number") {
|
|
74
|
-
out[0] = value;
|
|
75
|
-
} else if (Array.isArray(value)) {
|
|
76
|
-
for (let i = 0; i < value.length; i++) out[i] = value[i];
|
|
77
|
-
} else if ("width" in value) {
|
|
78
|
-
out[0] = value.x;
|
|
79
|
-
out[1] = value.y;
|
|
80
|
-
out[2] = value.width;
|
|
81
|
-
out[3] = value.height;
|
|
82
|
-
} else {
|
|
83
|
-
const point = value;
|
|
84
|
-
out[0] = point.x;
|
|
85
|
-
out[1] = point.y;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
function makeValue(layout, components) {
|
|
89
|
-
switch (layout.kind) {
|
|
90
|
-
case SCALAR:
|
|
91
|
-
return components[0];
|
|
92
|
-
case POINT:
|
|
93
|
-
return { x: components[0], y: components[1] };
|
|
94
|
-
case RECT:
|
|
95
|
-
return { x: components[0], y: components[1], width: components[2], height: components[3] };
|
|
96
|
-
default:
|
|
97
|
-
return Array.from(components);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function shapeEquals(a, b) {
|
|
101
|
-
if (typeof a === "number" || typeof b === "number") return a === b;
|
|
102
|
-
if (Array.isArray(a) || Array.isArray(b)) {
|
|
103
|
-
const u = a;
|
|
104
|
-
const v = b;
|
|
105
|
-
if (u.length !== v.length) return false;
|
|
106
|
-
for (let i = 0; i < u.length; i++) if (u[i] !== v[i]) return false;
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
const p = a;
|
|
110
|
-
const q = b;
|
|
111
|
-
return p.x === q.x && p.y === q.y && p.width === q.width && p.height === q.height;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
63
|
// src/values/spring.ts
|
|
115
64
|
var SPRING_DEFAULTS = {
|
|
116
65
|
stiffness: 300,
|
|
@@ -530,6 +479,9 @@ function motionValue(loop, animator, options = {}) {
|
|
|
530
479
|
function springValue(loop, initial, options = {}) {
|
|
531
480
|
return motionValue(loop, createSpring(initial, options), options);
|
|
532
481
|
}
|
|
482
|
+
function settleValue(loop, initial, options = {}) {
|
|
483
|
+
return motionValue(loop, createSettle(initial, options), options);
|
|
484
|
+
}
|
|
533
485
|
function tweenValue(loop, initial, options = {}) {
|
|
534
486
|
return motionValue(loop, createTween(initial, options), options);
|
|
535
487
|
}
|
|
@@ -543,7 +495,6 @@ export {
|
|
|
543
495
|
easeInOut,
|
|
544
496
|
easeOutCubic,
|
|
545
497
|
easeInOutCubic,
|
|
546
|
-
shapeEquals,
|
|
547
498
|
SPRING_DEFAULTS,
|
|
548
499
|
resolveSpring,
|
|
549
500
|
springStep,
|
|
@@ -551,6 +502,7 @@ export {
|
|
|
551
502
|
createTween,
|
|
552
503
|
motionValue,
|
|
553
504
|
springValue,
|
|
505
|
+
settleValue,
|
|
554
506
|
tweenValue
|
|
555
507
|
};
|
|
556
|
-
//# sourceMappingURL=chunk-
|
|
508
|
+
//# sourceMappingURL=chunk-CM6WVNDH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/values/easing.ts","../src/values/spring.ts","../src/values/tween.ts","../src/values/motion-value.ts"],"sourcesContent":["/** Maps progress in [0, 1] to eased progress (0 at 0, 1 at 1). */\nexport type Easing = (progress: number) => number;\n\n/** No easing. */\nexport const linear: Easing = (t) => t;\n\nconst EPSILON = 1e-7;\n\n/**\n * The CSS `cubic-bezier(x1, y1, x2, y2)` curve as a function, solved\n * numerically (Newton steps, then bisection). `x1` and `x2` must be in [0, 1].\n */\nexport function cubicBezier(x1: number, y1: number, x2: number, y2: number): Easing {\n if (!(x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1)) {\n throw new RangeError(`cubicBezier: x1 and x2 must be in [0, 1], got ${x1} and ${x2}`);\n }\n if (x1 === y1 && x2 === y2) return linear;\n const cx = 3 * x1;\n const bx = 3 * (x2 - x1) - cx;\n const ax = 1 - cx - bx;\n const cy = 3 * y1;\n const by = 3 * (y2 - y1) - cy;\n const ay = 1 - cy - by;\n const sampleX = (t: number): number => ((ax * t + bx) * t + cx) * t;\n const sampleY = (t: number): number => ((ay * t + by) * t + cy) * t;\n const slopeX = (t: number): number => (3 * ax * t + 2 * bx) * t + cx;\n const solveX = (x: number): number => {\n let t = x;\n for (let i = 0; i < 8; i++) {\n const error = sampleX(t) - x;\n if (Math.abs(error) < EPSILON) return t;\n const slope = slopeX(t);\n if (Math.abs(slope) < 1e-6) break;\n t -= error / slope;\n }\n let low = 0;\n let high = 1;\n t = x;\n for (let i = 0; i < 40; i++) {\n const value = sampleX(t);\n if (Math.abs(value - x) < EPSILON) return t;\n if (x > value) low = t;\n else high = t;\n t = (low + high) / 2;\n }\n return t;\n };\n return (progress) => (progress <= 0 ? 0 : progress >= 1 ? 1 : sampleY(solveX(progress)));\n}\n\n/** CSS `ease`. */\nexport const ease: Easing = /* @__PURE__ */ cubicBezier(0.25, 0.1, 0.25, 1);\n/** CSS `ease-in`. */\nexport const easeIn: Easing = /* @__PURE__ */ cubicBezier(0.42, 0, 1, 1);\n/** CSS `ease-out`. */\nexport const easeOut: Easing = /* @__PURE__ */ cubicBezier(0, 0, 0.58, 1);\n/** CSS `ease-in-out`. */\nexport const easeInOut: Easing = /* @__PURE__ */ cubicBezier(0.42, 0, 0.58, 1);\n/** Cubic ease-out: fast start, gentle stop. The tween default. */\nexport const easeOutCubic: Easing = (t) => 1 - (1 - t) ** 3;\n/** Cubic ease-in-out. */\nexport const easeInOutCubic: Easing = (t) => (t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2);\n","import type { Animatable, Layout, Widen } from \"../shapes\";\nimport { layoutOf, makeValue, sameLayout, writeComponents } from \"../shapes\";\nimport type { Animator } from \"./animator\";\n\n/**\n * Spring settings. Time is in milliseconds everywhere in the API; the physics\n * runs in seconds, so velocity is in units per second.\n */\nexport interface SpringConfig {\n /** Spring constant k. Higher is snappier. Default 300. */\n readonly stiffness?: number;\n /** Damping coefficient c. When set it wins over `dampingRatio`. */\n readonly damping?: number;\n /**\n * Damping as a fraction of critical damping: 1 is critical (the fastest\n * approach with no overshoot), below 1 overshoots and rings, above 1 is\n * sluggish. Default 1.\n */\n readonly dampingRatio?: number;\n /** Mass m. Default 1. */\n readonly mass?: number;\n /** Distance from the target that counts as arrived. Default 0.1 (tuned for pixels). */\n readonly restDelta?: number;\n /** Speed, in units per second, that counts as stopped. Default 1 (tuned for pixels). */\n readonly restSpeed?: number;\n}\n\n/** A {@link SpringConfig} with every field resolved. */\nexport interface SpringParams {\n readonly stiffness: number;\n readonly damping: number;\n readonly dampingRatio: number;\n readonly mass: number;\n readonly restDelta: number;\n readonly restSpeed: number;\n}\n\n/** Defaults of {@link SpringConfig}: critically damped. */\nexport const SPRING_DEFAULTS: SpringParams = {\n stiffness: 300,\n damping: 2 * Math.sqrt(300),\n dampingRatio: 1,\n mass: 1,\n restDelta: 0.1,\n restSpeed: 1,\n};\n\nfunction positive(name: string, value: number): number {\n if (!(value > 0) || !Number.isFinite(value)) throw new RangeError(`spring: ${name} must be a finite number > 0, got ${value}`);\n return value;\n}\n\n/** Resolve a {@link SpringConfig} over the defaults. Throws on a non-positive field. */\nexport function resolveSpring(config: SpringConfig = {}): SpringParams {\n const stiffness = positive(\"stiffness\", config.stiffness ?? SPRING_DEFAULTS.stiffness);\n const mass = positive(\"mass\", config.mass ?? SPRING_DEFAULTS.mass);\n const critical = 2 * Math.sqrt(stiffness * mass);\n const damping = positive(\n config.damping !== undefined ? \"damping\" : \"dampingRatio\",\n config.damping ?? (config.dampingRatio ?? SPRING_DEFAULTS.dampingRatio) * critical,\n );\n return {\n stiffness,\n damping,\n dampingRatio: damping / critical,\n mass,\n restDelta: positive(\"restDelta\", config.restDelta ?? SPRING_DEFAULTS.restDelta),\n restSpeed: positive(\"restSpeed\", config.restSpeed ?? SPRING_DEFAULTS.restSpeed),\n };\n}\n\nconst UNDERDAMPED = 0;\nconst CRITICAL = 1;\nconst OVERDAMPED = 2;\n\n/** The closed-form solution's constants for one set of params. */\ninterface Solver {\n readonly mode: typeof UNDERDAMPED | typeof CRITICAL | typeof OVERDAMPED;\n readonly omega: number;\n readonly decay: number;\n readonly omegaD: number;\n readonly r1: number;\n readonly r2: number;\n}\n\nfunction solverFor(params: SpringParams): Solver {\n const omega = Math.sqrt(params.stiffness / params.mass);\n const zeta = params.dampingRatio;\n if (Math.abs(zeta - 1) < 1e-6) return { mode: CRITICAL, omega, decay: omega, omegaD: 0, r1: 0, r2: 0 };\n if (zeta < 1) {\n return { mode: UNDERDAMPED, omega, decay: zeta * omega, omegaD: omega * Math.sqrt(1 - zeta * zeta), r1: 0, r2: 0 };\n }\n const root = Math.sqrt(zeta * zeta - 1);\n return { mode: OVERDAMPED, omega, decay: 0, omegaD: 0, r1: -omega * (zeta - root), r2: -omega * (zeta + root) };\n}\n\n/**\n * Advance one component exactly: displacement `d0` from the target and\n * velocity `v0` (per second) after `t` seconds. Writes into out[0], out[1].\n * Exact for any `t`, so the curve doesn't depend on the frame rate.\n */\nfunction advance(solver: Solver, d0: number, v0: number, t: number, out: Float64Array): void {\n if (solver.mode === CRITICAL) {\n const w = solver.omega;\n const e = Math.exp(-w * t);\n const b = v0 + w * d0;\n out[0] = e * (d0 + b * t);\n out[1] = e * (v0 - w * b * t);\n } else if (solver.mode === UNDERDAMPED) {\n const a = solver.decay;\n const wd = solver.omegaD;\n const e = Math.exp(-a * t);\n const cos = Math.cos(wd * t);\n const sin = Math.sin(wd * t);\n out[0] = e * (d0 * cos + ((v0 + a * d0) / wd) * sin);\n out[1] = e * (v0 * cos - ((a * v0 + solver.omega * solver.omega * d0) / wd) * sin);\n } else {\n const { r1, r2 } = solver;\n const c2 = (v0 - r1 * d0) / (r2 - r1);\n const c1 = d0 - c2;\n const e1 = Math.exp(r1 * t);\n const e2 = Math.exp(r2 * t);\n out[0] = c1 * e1 + c2 * e2;\n out[1] = c1 * r1 * e1 + c2 * r2 * e2;\n }\n}\n\n/** A scalar spring's position and velocity (units per second). */\nexport interface SpringState {\n readonly value: number;\n readonly velocity: number;\n}\n\n/**\n * One pure spring step for a scalar: where `state` is after `dtMs` heading for\n * `target`. Doesn't settle or snap; {@link createSpring} does that.\n */\nexport function springStep(state: SpringState, target: number, params: SpringParams, dtMs: number): SpringState {\n const out = new Float64Array(2);\n advance(solverFor(params), state.value - target, state.velocity, dtMs / 1000, out);\n return { value: target + out[0]!, velocity: out[1]! };\n}\n\n/** A spring over any {@link Animatable} shape, stepped by hand or by `motionValue`. */\nexport interface Spring<T> extends Animator<T> {\n /** The resolved settings. */\n readonly params: SpringParams;\n /** Set the velocity in units per second (a gesture's release velocity). */\n setVelocity(velocity: T): void;\n /** Change settings mid-flight; position and velocity carry on. */\n configure(config: SpringConfig): void;\n}\n\nclass SpringAnimator implements Spring<Animatable> {\n readonly layout: Layout;\n readonly x: Float64Array;\n readonly v: Float64Array;\n readonly goal: Float64Array;\n readonly scratch = new Float64Array(2);\n config: SpringConfig;\n params: SpringParams;\n solver: Solver;\n settled = true;\n cachedValue: Animatable | null = null;\n\n constructor(initial: Animatable, config: SpringConfig) {\n this.layout = layoutOf(initial);\n const size = this.layout.size;\n this.x = new Float64Array(size);\n this.v = new Float64Array(size);\n this.goal = new Float64Array(size);\n writeComponents(initial, this.x);\n writeComponents(initial, this.goal);\n this.config = config;\n this.params = resolveSpring(config);\n this.solver = solverFor(this.params);\n }\n\n get value(): Animatable {\n if (this.cachedValue === null) this.cachedValue = makeValue(this.layout, this.x);\n return this.cachedValue;\n }\n\n get velocity(): Animatable {\n return makeValue(this.layout, this.v);\n }\n\n get target(): Animatable {\n return makeValue(this.layout, this.goal);\n }\n\n check(value: Animatable, what: string): void {\n if (!sameLayout(layoutOf(value), this.layout)) {\n throw new TypeError(`spring: ${what} has a different shape than the spring's value`);\n }\n }\n\n /** At rest exactly when on the target and not moving. */\n updateSettled(): void {\n for (let i = 0; i < this.x.length; i++) {\n if (this.x[i] !== this.goal[i] || this.v[i] !== 0) {\n this.settled = false;\n return;\n }\n }\n this.settled = true;\n }\n\n setTarget(target: Animatable): void {\n this.check(target, \"the target\");\n writeComponents(target, this.goal);\n // Position and velocity stay as they are: a retarget carries the motion on.\n this.updateSettled();\n }\n\n setVelocity(velocity: Animatable): void {\n this.check(velocity, \"the velocity\");\n writeComponents(velocity, this.v);\n this.updateSettled();\n }\n\n jumpTo(value: Animatable): void {\n this.check(value, \"the value\");\n writeComponents(value, this.x);\n writeComponents(value, this.goal);\n this.v.fill(0);\n this.cachedValue = null;\n this.settled = true;\n }\n\n snap(): void {\n this.x.set(this.goal);\n this.v.fill(0);\n this.cachedValue = null;\n this.settled = true;\n }\n\n configure(config: SpringConfig): void {\n this.config = { ...this.config, ...config };\n this.params = resolveSpring(this.config);\n this.solver = solverFor(this.params);\n }\n\n step(dtMs: number): boolean {\n if (this.settled) return false;\n if (!(dtMs > 0)) return true;\n const t = dtMs / 1000;\n const { x, v, goal, scratch } = this;\n const { restDelta, restSpeed } = this.params;\n let resting = true;\n for (let i = 0; i < x.length; i++) {\n advance(this.solver, x[i]! - goal[i]!, v[i]!, t, scratch);\n x[i] = goal[i]! + scratch[0]!;\n v[i] = scratch[1]!;\n if (resting && (Math.abs(scratch[0]!) > restDelta || Math.abs(scratch[1]!) > restSpeed)) resting = false;\n }\n this.cachedValue = null;\n if (resting) this.snap();\n return !this.settled;\n }\n}\n\n/**\n * A spring starting at rest on `initial`. `initial` fixes the shape: a\n * number, a vector (array), a point `{ x, y }` or a rect `{ x, y, width,\n * height }`; targets and velocities must have the same shape.\n */\nexport function createSpring<T extends Animatable>(initial: T, config: SpringConfig = {}): Spring<Widen<T>> {\n return new SpringAnimator(initial, config) as unknown as Spring<Widen<T>>;\n}\n","import type { Animatable, Layout, Widen } from \"../shapes\";\nimport { layoutOf, makeValue, sameLayout, writeComponents } from \"../shapes\";\nimport type { Animator } from \"./animator\";\nimport { easeOutCubic, type Easing } from \"./easing\";\n\n/** Tween settings. */\nexport interface TweenConfig {\n /** Length of a run in ms. Default 250. 0 jumps to the target on the next step. */\n readonly duration?: number;\n /** Easing of the run. Default {@link easeOutCubic}. */\n readonly easing?: Easing;\n}\n\n/** A tween over any {@link Animatable} shape. */\nexport interface Tween<T> extends Animator<T> {\n /** Run progress in [0, 1]. */\n readonly progress: number;\n /** Change duration or easing; applies from the next target. */\n configure(config: TweenConfig): void;\n}\n\nclass TweenAnimator implements Tween<Animatable> {\n readonly layout: Layout;\n readonly x: Float64Array;\n readonly from: Float64Array;\n readonly goal: Float64Array;\n duration: number;\n easing: Easing;\n elapsed = 0;\n settled = true;\n cachedValue: Animatable | null = null;\n\n constructor(initial: Animatable, config: TweenConfig) {\n this.layout = layoutOf(initial);\n const size = this.layout.size;\n this.x = new Float64Array(size);\n this.from = new Float64Array(size);\n this.goal = new Float64Array(size);\n writeComponents(initial, this.x);\n writeComponents(initial, this.from);\n writeComponents(initial, this.goal);\n this.duration = 250;\n this.easing = easeOutCubic;\n this.configure(config);\n }\n\n get value(): Animatable {\n if (this.cachedValue === null) this.cachedValue = makeValue(this.layout, this.x);\n return this.cachedValue;\n }\n\n get target(): Animatable {\n return makeValue(this.layout, this.goal);\n }\n\n get progress(): number {\n if (this.settled) return 1;\n return this.duration <= 0 ? 0 : Math.min(1, this.elapsed / this.duration);\n }\n\n /** The eased curve's slope at the current progress, as units per second. */\n get velocity(): Animatable {\n const out = new Float64Array(this.layout.size);\n if (!this.settled && this.duration > 0) {\n const p = this.progress;\n const h = 1e-3;\n const lo = Math.max(0, p - h);\n const hi = Math.min(1, p + h);\n const slope = (this.easing(hi) - this.easing(lo)) / (hi - lo);\n const perSecond = (slope / this.duration) * 1000;\n for (let i = 0; i < out.length; i++) out[i] = (this.goal[i]! - this.from[i]!) * perSecond;\n }\n return makeValue(this.layout, out);\n }\n\n configure(config: TweenConfig): void {\n if (config.duration !== undefined) {\n if (!(config.duration >= 0) || !Number.isFinite(config.duration)) {\n throw new RangeError(`tween: duration must be a finite number >= 0, got ${config.duration}`);\n }\n this.duration = config.duration;\n }\n if (config.easing !== undefined) this.easing = config.easing;\n }\n\n check(value: Animatable, what: string): void {\n if (!sameLayout(layoutOf(value), this.layout)) {\n throw new TypeError(`tween: ${what} has a different shape than the tween's value`);\n }\n }\n\n setTarget(target: Animatable): void {\n this.check(target, \"the target\");\n writeComponents(target, this.goal);\n // A new run starts from wherever the value is now (no jump).\n this.from.set(this.x);\n this.elapsed = 0;\n this.settled = true;\n for (let i = 0; i < this.x.length; i++) {\n if (this.x[i] !== this.goal[i]) {\n this.settled = false;\n break;\n }\n }\n }\n\n jumpTo(value: Animatable): void {\n this.check(value, \"the value\");\n writeComponents(value, this.x);\n writeComponents(value, this.from);\n writeComponents(value, this.goal);\n this.cachedValue = null;\n this.settled = true;\n }\n\n snap(): void {\n this.x.set(this.goal);\n this.from.set(this.goal);\n this.cachedValue = null;\n this.settled = true;\n }\n\n step(dtMs: number): boolean {\n if (this.settled) return false;\n this.elapsed += Math.max(0, dtMs);\n const p = this.duration <= 0 ? 1 : Math.min(1, this.elapsed / this.duration);\n if (p >= 1) {\n this.snap();\n return false;\n }\n const eased = this.easing(p);\n for (let i = 0; i < this.x.length; i++) {\n this.x[i] = this.from[i]! + (this.goal[i]! - this.from[i]!) * eased;\n }\n this.cachedValue = null;\n return true;\n }\n}\n\n/**\n * A tween starting at rest on `initial` (same shapes as `createSpring`).\n * Velocity doesn't carry over a retarget: a new target starts a new run from\n * the current value. Use a spring where motion must stay continuous.\n */\nexport function createTween<T extends Animatable>(initial: T, config: TweenConfig = {}): Tween<Widen<T>> {\n return new TweenAnimator(initial, config) as unknown as Tween<Widen<T>>;\n}\n","import type { FrameInfo, FrameLoop, Phase } from \"../clock/frame-loop\";\nimport type { Animatable, Widen } from \"../shapes\";\nimport { shapeEquals } from \"../shapes\";\nimport { batch, effect, signal, untracked, type ReadonlySignal, type Signal } from \"../signals/signals\";\nimport type { Animator } from \"./animator\";\nimport { createSettle, type Settle, type SettleConfig } from \"./settle\";\nimport { createSpring, type Spring, type SpringConfig } from \"./spring\";\nimport { createTween, type Tween, type TweenConfig } from \"./tween\";\n\n/** Options of {@link motionValue}. */\nexport interface MotionOptions {\n /**\n * The frame phase that steps the value. Default `\"layout\"`: it steps after\n * that phase's one-shot tasks, so a target set in input, update or layout\n * moves the value in the same frame, and `write` sees the new value.\n */\n readonly phase?: Phase;\n /**\n * The reduced-motion switch: while it is (or returns) `true`, every new\n * target is reached at once, and a value in flight snaps on its next frame.\n * A function is read on each `set` and each frame, so it can read a signal\n * or a media query.\n */\n readonly reducedMotion?: boolean | (() => boolean);\n}\n\n/** Options of {@link MotionValue.set}. */\nexport interface SetOptions<T> {\n /** Start with this velocity (units per second), e.g. a gesture's release velocity. Springs and settles (a settle caps it toward the target); tweens ignore it. */\n readonly velocity?: T;\n}\n\n/**\n * An animated value on a frame loop. Reading `value` inside a computed or an\n * effect tracks it; it changes once per frame while moving and the loop goes\n * idle when it settles.\n */\nexport interface MotionValue<T, A extends Animator<unknown> = Animator<T>> extends ReadonlySignal<T> {\n /** Where the value is heading. */\n readonly target: T;\n /** The current velocity, units per second. */\n readonly velocity: T;\n /** Whether it is moving (reactive). */\n readonly moving: boolean;\n /** The spring, settle or tween underneath. Change it through this value (`jump`, not the animator's `hold`), so the signal and the loop follow. */\n readonly animator: A;\n /** Head for `target`; a spring keeps its velocity, a settle launches from where it is drawn, a tween restarts. */\n set(target: T, options?: SetOptions<T>): void;\n /** Put the value at `value` at once, at rest. */\n jump(value: T): void;\n /** Finish now: put the value on its target, at rest. */\n snap(): void;\n /**\n * Keep heading for whatever `source` returns. `source` is tracked like an\n * effect, and re-read in this value's phase at most once per frame. Returns\n * a stop function.\n */\n follow(source: () => T): () => void;\n /**\n * Call `listener` each time the value comes to rest: on the frame it\n * settles, or at once when `set` (under reduced motion), `snap` or `jump`\n * leaves it at rest. Returns an unsubscribe function.\n */\n onSettle(listener: (value: T) => void): () => void;\n /** Stop stepping, drop listeners and follows. */\n dispose(): void;\n}\n\nclass Motion<T> implements MotionValue<T> {\n readonly loop: FrameLoop;\n readonly animator: Animator<T>;\n readonly phase: Phase;\n readonly reduced: () => boolean;\n readonly current: Signal<T>;\n readonly movingSignal: Signal<boolean>;\n readonly listeners = new Set<(value: T) => void>();\n readonly follows = new Set<() => void>();\n stop: (() => void) | null = null;\n disposed = false;\n\n constructor(loop: FrameLoop, animator: Animator<T>, options: MotionOptions) {\n this.loop = loop;\n this.animator = animator;\n this.phase = options.phase ?? \"layout\";\n const reducedMotion = options.reducedMotion ?? false;\n this.reduced = typeof reducedMotion === \"function\" ? reducedMotion : () => reducedMotion;\n this.current = signal(animator.value, {\n equals: shapeEquals as (a: T, b: T) => boolean,\n });\n this.movingSignal = signal(false);\n if (!animator.settled) this.start();\n }\n\n get value(): T {\n return this.current.value;\n }\n\n peek(): T {\n return this.current.peek();\n }\n\n get target(): T {\n return this.animator.target;\n }\n\n get velocity(): T {\n return this.animator.velocity;\n }\n\n get moving(): boolean {\n return this.movingSignal.value;\n }\n\n readonly tick = (frame: FrameInfo): boolean => {\n if (this.reduced()) this.animator.snap();\n else this.animator.step(frame.delta);\n if (!this.animator.settled) {\n this.current.value = this.animator.value;\n return true;\n }\n this.stop = null;\n this.rest();\n return false;\n };\n\n start(): void {\n if (this.stop !== null || this.disposed) return;\n this.stop = this.loop.repeat(this.phase, this.tick);\n this.movingSignal.value = true;\n }\n\n halt(): void {\n if (this.stop === null) return;\n this.stop();\n this.stop = null;\n }\n\n /** Publish the resting value and tell the listeners. */\n rest(): void {\n batch(() => {\n this.current.value = this.animator.value;\n this.movingSignal.value = false;\n });\n const value = this.animator.value;\n for (const listener of Array.from(this.listeners)) listener(value);\n }\n\n set(target: T, options?: SetOptions<T>): void {\n if (this.disposed) return;\n untracked(() => {\n this.animator.setTarget(target);\n if (options?.velocity !== undefined) this.animator.setVelocity?.(options.velocity);\n if (this.reduced()) this.animator.snap();\n if (this.animator.settled) {\n this.halt();\n this.rest();\n } else {\n this.start();\n }\n });\n }\n\n jump(value: T): void {\n if (this.disposed) return;\n untracked(() => {\n this.animator.jumpTo(value);\n this.halt();\n this.rest();\n });\n }\n\n snap(): void {\n if (this.disposed) return;\n untracked(() => {\n this.animator.snap();\n this.halt();\n this.rest();\n });\n }\n\n follow(source: () => T): () => void {\n if (this.disposed) return () => {};\n const dispose = effect(\n () => {\n const target = source();\n this.set(target);\n },\n { schedule: this.loop.scheduler(this.phase) },\n );\n const stop = (): void => {\n dispose();\n this.follows.delete(stop);\n };\n this.follows.add(stop);\n return stop;\n }\n\n onSettle(listener: (value: T) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.halt();\n for (const stop of Array.from(this.follows)) stop();\n this.listeners.clear();\n this.movingSignal.value = false;\n }\n}\n\n/** The value type an animator moves. */\nexport type AnimatorValue<A> = A extends Animator<infer T> ? T : never;\n\n/** Step `animator` on `loop` while it moves, and expose it as a signal. */\nexport function motionValue<A extends Animator<unknown>>(\n loop: FrameLoop,\n animator: A,\n options: MotionOptions = {},\n): MotionValue<AnimatorValue<A>, A> {\n return new Motion(loop, animator, options) as unknown as MotionValue<AnimatorValue<A>, A>;\n}\n\n/** A spring-driven {@link MotionValue}: `createSpring` plus `motionValue`. */\nexport function springValue<T extends Animatable>(\n loop: FrameLoop,\n initial: T,\n options: SpringConfig & MotionOptions = {},\n): MotionValue<Widen<T>, Spring<Widen<T>>> {\n return motionValue(loop, createSpring(initial, options), options) as MotionValue<Widen<T>, Spring<Widen<T>>>;\n}\n\n/**\n * A settle-driven {@link MotionValue}: `createSettle` plus `motionValue`. The\n * one curve for things moving to a new place (see {@link Settle}). To hold it\n * to a pointer, `jump` it on each move; the next `set` launches from there.\n */\nexport function settleValue<T extends Animatable>(\n loop: FrameLoop,\n initial: T,\n options: SettleConfig & MotionOptions = {},\n): MotionValue<Widen<T>, Settle<Widen<T>>> {\n return motionValue(loop, createSettle(initial, options), options) as MotionValue<Widen<T>, Settle<Widen<T>>>;\n}\n\n/** A tween-driven {@link MotionValue}: `createTween` plus `motionValue`. */\nexport function tweenValue<T extends Animatable>(\n loop: FrameLoop,\n initial: T,\n options: TweenConfig & MotionOptions = {},\n): MotionValue<Widen<T>, Tween<Widen<T>>> {\n return motionValue(loop, createTween(initial, options), options) as MotionValue<Widen<T>, Tween<Widen<T>>>;\n}\n"],"mappings":"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","names":[]}
|