@dreamboard-games/sdk 0.5.0-alpha.22 → 0.5.0-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/react.d.ts +20 -1
- package/dist/react.js +357 -60
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
} from "./chunk-CZRPUWCT.js";
|
|
74
74
|
|
|
75
75
|
// src/package-set.ts
|
|
76
|
-
var DREAMBOARD_SDK_VERSION = true ? "0.5.0-alpha.
|
|
76
|
+
var DREAMBOARD_SDK_VERSION = true ? "0.5.0-alpha.23" : "0.0.0-development";
|
|
77
77
|
var DREAMBOARD_SDK_PACKAGES = {
|
|
78
78
|
"@dreamboard-games/sdk": DREAMBOARD_SDK_VERSION
|
|
79
79
|
};
|
package/dist/react.d.ts
CHANGED
|
@@ -7,6 +7,19 @@ import 'zod';
|
|
|
7
7
|
import 'honeycomb-grid';
|
|
8
8
|
import '@tanstack/store';
|
|
9
9
|
|
|
10
|
+
/** How the dragged card would show where it lands if dropped now. */
|
|
11
|
+
interface DragFit {
|
|
12
|
+
/**
|
|
13
|
+
* The width of the card-sized box marked `data-drop-landing` there,
|
|
14
|
+
* relative to the picked-up card's layout width. Null until the card has
|
|
15
|
+
* been over such a box; between areas it keeps the last one's.
|
|
16
|
+
*/
|
|
17
|
+
readonly scale: number | null;
|
|
18
|
+
/** Drawn in a pile's slot. */
|
|
19
|
+
readonly snapped: boolean;
|
|
20
|
+
/** The area's zone would conceal the card. */
|
|
21
|
+
readonly concealed: boolean;
|
|
22
|
+
}
|
|
10
23
|
interface CardGestureProps {
|
|
11
24
|
onPointerDown(event: PointerEvent<Element>): void;
|
|
12
25
|
onFocus(event: FocusEvent<Element>): void;
|
|
@@ -83,6 +96,12 @@ interface DragOverlay<G> {
|
|
|
83
96
|
readonly target: DropTarget<G> | null;
|
|
84
97
|
/** A registered zone landing; absent for interactions with no zone destination. */
|
|
85
98
|
readonly landing: PositionTarget<IdOf<G, "zoneId">, ZoneHostId<G>> | null;
|
|
99
|
+
/**
|
|
100
|
+
* Draw the copy at `fit.scale` once it is known, in place of its lifted
|
|
101
|
+
* size, and as its back while `fit.concealed`. The ref already moves it
|
|
102
|
+
* into a pile's slot while `fit.snapped`.
|
|
103
|
+
*/
|
|
104
|
+
readonly fit: DragFit;
|
|
86
105
|
/** Attach to a fixed-position copy of the card; it follows the pointer. */
|
|
87
106
|
readonly ref: (element: HTMLElement | null) => (() => void) | undefined;
|
|
88
107
|
}
|
|
@@ -155,4 +174,4 @@ declare function useMarqueeSelection<Id extends string>(options: {
|
|
|
155
174
|
};
|
|
156
175
|
};
|
|
157
176
|
|
|
158
|
-
export { type CardGesture, type CardGestureOptions, type CardGestureProps, type CardPresentation, type CardRow, type DragOverlay, type DropArea, DropAreaBinding, type DropAreaOptions, type MarqueeBounds, type SelectionOptions, type ZonePresentation, createGameHook, useMarqueeSelection };
|
|
177
|
+
export { type CardGesture, type CardGestureOptions, type CardGestureProps, type CardPresentation, type CardRow, type DragFit, type DragOverlay, type DropArea, DropAreaBinding, type DropAreaOptions, type MarqueeBounds, type SelectionOptions, type ZonePresentation, createGameHook, useMarqueeSelection };
|
package/dist/react.js
CHANGED
|
@@ -93,6 +93,165 @@ import {
|
|
|
93
93
|
createContext,
|
|
94
94
|
useContext
|
|
95
95
|
} from "react";
|
|
96
|
+
|
|
97
|
+
// src/headless/drop-snap.ts
|
|
98
|
+
var SNAP = Object.freeze({
|
|
99
|
+
/** A pile catches a card whose centre comes this close to its own. */
|
|
100
|
+
slotCatch: 0.75,
|
|
101
|
+
/** A caught card leaves the pile beyond this. */
|
|
102
|
+
slotRelease: 1.15,
|
|
103
|
+
/** A finger reaches this much further. */
|
|
104
|
+
coarseReach: 0.2,
|
|
105
|
+
/** Another pile takes a caught card only when this much closer. */
|
|
106
|
+
slotSwitch: 0.1,
|
|
107
|
+
/** A card enters a zone once this share of it covers the zone... */
|
|
108
|
+
zoneEnter: 0.35,
|
|
109
|
+
/** ...and leaves it once less than this share does. */
|
|
110
|
+
zoneLeave: 0.1,
|
|
111
|
+
/** How much a card in a pile still follows the pointer. */
|
|
112
|
+
slotGive: 0.15,
|
|
113
|
+
/** How much a card held inside a zone's edge follows the pointer beyond it. */
|
|
114
|
+
edgeGive: 0.25
|
|
115
|
+
});
|
|
116
|
+
var centerOf = (box) => ({
|
|
117
|
+
x: box.x + box.width / 2,
|
|
118
|
+
y: box.y + box.height / 2
|
|
119
|
+
});
|
|
120
|
+
var toward = (from, to, share) => ({
|
|
121
|
+
x: from.x + (to.x - from.x) * share,
|
|
122
|
+
y: from.y + (to.y - from.y) * share
|
|
123
|
+
});
|
|
124
|
+
var contains = (box, point) => point.x >= box.x && point.x <= box.x + box.width && point.y >= box.y && point.y <= box.y + box.height;
|
|
125
|
+
function cover(card, box) {
|
|
126
|
+
const width = Math.min(card.x + card.width, box.x + box.width) - Math.max(card.x, box.x);
|
|
127
|
+
const height = Math.min(card.y + card.height, box.y + box.height) - Math.max(card.y, box.y);
|
|
128
|
+
return width > 0 && height > 0 ? width * height / (card.width * card.height) : 0;
|
|
129
|
+
}
|
|
130
|
+
function snapDrop({
|
|
131
|
+
pointer,
|
|
132
|
+
card,
|
|
133
|
+
areas,
|
|
134
|
+
hit,
|
|
135
|
+
retained,
|
|
136
|
+
coarse
|
|
137
|
+
}) {
|
|
138
|
+
const free = centerOf(card);
|
|
139
|
+
const inSlot = (index, box) => ({
|
|
140
|
+
index,
|
|
141
|
+
center: toward(centerOf(box), free, SNAP.slotGive),
|
|
142
|
+
held: true
|
|
143
|
+
});
|
|
144
|
+
let best = -1;
|
|
145
|
+
let score = Infinity;
|
|
146
|
+
areas.forEach((area, index) => {
|
|
147
|
+
const box = area?.slot ? area.box : null;
|
|
148
|
+
if (!box?.width || !box.height) return;
|
|
149
|
+
const middle = centerOf(box);
|
|
150
|
+
const distance = Math.hypot(
|
|
151
|
+
(free.x - middle.x) / box.width,
|
|
152
|
+
(free.y - middle.y) / box.height
|
|
153
|
+
);
|
|
154
|
+
const kept2 = index === retained;
|
|
155
|
+
const reach = (kept2 ? SNAP.slotRelease : SNAP.slotCatch) + (coarse ? SNAP.coarseReach : 0);
|
|
156
|
+
const value = kept2 ? distance - SNAP.slotSwitch : distance;
|
|
157
|
+
if (distance <= reach && value < score) {
|
|
158
|
+
best = index;
|
|
159
|
+
score = value;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
if (best >= 0) return inSlot(best, areas[best].box);
|
|
163
|
+
const under = hit >= 0 ? areas[hit] : null;
|
|
164
|
+
if (under)
|
|
165
|
+
return under.slot && under.box?.width ? inSlot(hit, under.box) : { index: hit, center: free, held: false };
|
|
166
|
+
const hold = (index, box) => {
|
|
167
|
+
if (contains(box, pointer)) return { index, center: free, held: false };
|
|
168
|
+
const inside = {
|
|
169
|
+
x: Math.max(box.x, Math.min(free.x, box.x + box.width)),
|
|
170
|
+
y: Math.max(box.y, Math.min(free.y, box.y + box.height))
|
|
171
|
+
};
|
|
172
|
+
return { index, center: toward(inside, free, SNAP.edgeGive), held: true };
|
|
173
|
+
};
|
|
174
|
+
const zone = (index) => {
|
|
175
|
+
const area = areas[index];
|
|
176
|
+
return area && !area.slot && area.box?.width ? area.box : null;
|
|
177
|
+
};
|
|
178
|
+
const kept = retained >= 0 ? zone(retained) : null;
|
|
179
|
+
if (kept && (cover(card, kept) >= SNAP.zoneLeave || magneticDropPoint(pointer, kept, true, coarse)))
|
|
180
|
+
return hold(retained, kept);
|
|
181
|
+
let chosen = -1;
|
|
182
|
+
let share = 0;
|
|
183
|
+
areas.forEach((_, index) => {
|
|
184
|
+
const box = zone(index);
|
|
185
|
+
if (!box) return;
|
|
186
|
+
const value = cover(card, box);
|
|
187
|
+
if (value < SNAP.zoneEnter && !magneticDropPoint(pointer, box, false, coarse))
|
|
188
|
+
return;
|
|
189
|
+
const deeper = chosen < 0 || areas[index].depth > areas[chosen].depth;
|
|
190
|
+
if (deeper || areas[index].depth === areas[chosen].depth && value > share) {
|
|
191
|
+
chosen = index;
|
|
192
|
+
share = value;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
return chosen >= 0 ? hold(chosen, zone(chosen)) : { index: -1, center: free, held: false };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/react/gesture.tsx
|
|
199
|
+
var UNFIT = Object.freeze({
|
|
200
|
+
scale: null,
|
|
201
|
+
snapped: false,
|
|
202
|
+
concealed: false
|
|
203
|
+
});
|
|
204
|
+
var CATCH_UP_MS = 50;
|
|
205
|
+
var SCROLL_EDGE = { fine: 48, coarse: 64 };
|
|
206
|
+
var SCROLL_SPEED = 16;
|
|
207
|
+
var VISUALLY_HIDDEN = {
|
|
208
|
+
position: "fixed",
|
|
209
|
+
width: "1px",
|
|
210
|
+
height: "1px",
|
|
211
|
+
overflow: "hidden",
|
|
212
|
+
clipPath: "inset(50%)",
|
|
213
|
+
whiteSpace: "nowrap"
|
|
214
|
+
};
|
|
215
|
+
function landingIn(area) {
|
|
216
|
+
for (const element of area?.querySelectorAll("[data-drop-landing]") ?? [])
|
|
217
|
+
if (element instanceof HTMLElement && element.closest("[data-drop-area]") === area)
|
|
218
|
+
return element;
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
function visibleBox(element, clips) {
|
|
222
|
+
let { left, top, right, bottom } = element.getBoundingClientRect();
|
|
223
|
+
for (const clip of clips) {
|
|
224
|
+
const box = clip.getBoundingClientRect();
|
|
225
|
+
left = Math.max(left, box.left);
|
|
226
|
+
top = Math.max(top, box.top);
|
|
227
|
+
right = Math.min(right, box.right);
|
|
228
|
+
bottom = Math.min(bottom, box.bottom);
|
|
229
|
+
}
|
|
230
|
+
return right > left && bottom > top ? { x: left, y: top, width: right - left, height: bottom - top } : null;
|
|
231
|
+
}
|
|
232
|
+
function scrollStep(node, at, edge, frames) {
|
|
233
|
+
const root = node === document.scrollingElement;
|
|
234
|
+
const { overflowX, overflowY } = getComputedStyle(node);
|
|
235
|
+
const box = root ? { left: 0, top: 0, right: innerWidth, bottom: innerHeight } : node.getBoundingClientRect();
|
|
236
|
+
const speed = (gap) => gap < edge ? SCROLL_SPEED * frames * (1 - Math.max(0, gap) / edge) ** 2 : 0;
|
|
237
|
+
const axis = (overflow, position, room, before, after) => (root || overflow === "auto" || overflow === "scroll") && room > 0 ? (position < room ? speed(after) : 0) - (position > 0 ? speed(before) : 0) : 0;
|
|
238
|
+
return {
|
|
239
|
+
x: axis(
|
|
240
|
+
overflowX,
|
|
241
|
+
node.scrollLeft,
|
|
242
|
+
node.scrollWidth - node.clientWidth,
|
|
243
|
+
at.x - box.left,
|
|
244
|
+
box.right - at.x
|
|
245
|
+
),
|
|
246
|
+
y: axis(
|
|
247
|
+
overflowY,
|
|
248
|
+
node.scrollTop,
|
|
249
|
+
node.scrollHeight - node.clientHeight,
|
|
250
|
+
at.y - box.top,
|
|
251
|
+
box.bottom - at.y
|
|
252
|
+
)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
96
255
|
var CARD_STYLE = Object.freeze({
|
|
97
256
|
// Sideways movement stays native scrolling; everything else reaches the recognizer.
|
|
98
257
|
touchAction: "pan-x",
|
|
@@ -152,6 +311,18 @@ function createGestureSession(game) {
|
|
|
152
311
|
let domFocused = null;
|
|
153
312
|
let alt = false;
|
|
154
313
|
let pointer = { x: 0, y: 0 };
|
|
314
|
+
let goal = { x: 0, y: 0 };
|
|
315
|
+
let offset = { x: 0, y: 0 };
|
|
316
|
+
let lag = { x: 0, y: 0 };
|
|
317
|
+
let shown = { x: 0, y: 0 };
|
|
318
|
+
let held = false;
|
|
319
|
+
let reduced = false;
|
|
320
|
+
let frame = 0;
|
|
321
|
+
let lastFrame = 0;
|
|
322
|
+
let remeasure = false;
|
|
323
|
+
const located = /* @__PURE__ */ new Map();
|
|
324
|
+
const engaged = /* @__PURE__ */ new Set();
|
|
325
|
+
let announcer = null;
|
|
155
326
|
let swallowing = false;
|
|
156
327
|
let guardingClicks = false;
|
|
157
328
|
let disposed = false;
|
|
@@ -209,57 +380,174 @@ function createGestureSession(game) {
|
|
|
209
380
|
if (drag?.settling && (game.request === null || changedSnapshot || changedLifetime))
|
|
210
381
|
set({ drag: null });
|
|
211
382
|
});
|
|
212
|
-
function
|
|
383
|
+
function hitAreas(at) {
|
|
213
384
|
for (const element of document.elementsFromPoint(at.x, at.y)) {
|
|
214
385
|
if (element.closest("[data-drag-overlay]")) continue;
|
|
215
|
-
const
|
|
216
|
-
|
|
386
|
+
const ids = [];
|
|
387
|
+
for (let area = element.closest("[data-drop-area]"); area; area = area.parentElement?.closest("[data-drop-area]") ?? null)
|
|
388
|
+
ids.push(area.getAttribute("data-drop-area"));
|
|
389
|
+
if (ids.length) return ids;
|
|
217
390
|
}
|
|
218
|
-
return
|
|
391
|
+
return [];
|
|
219
392
|
}
|
|
220
|
-
function
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
393
|
+
function locate(id2) {
|
|
394
|
+
const known = located.get(id2);
|
|
395
|
+
const element = known?.element?.isConnected ? known.element : document.querySelector(`[data-drop-area="${CSS.escape(id2)}"]`);
|
|
396
|
+
const landing = landingIn(element);
|
|
397
|
+
const slot = landing?.dataset.dropLanding === "slot" ? landing : null;
|
|
398
|
+
if (known && known.element === element && known.slot === slot) return known;
|
|
399
|
+
const clips = [];
|
|
400
|
+
for (let node = (slot ?? element)?.parentElement; node; node = node.parentElement) {
|
|
401
|
+
const { overflowX, overflowY } = getComputedStyle(node);
|
|
402
|
+
if (/auto|scroll|hidden|clip/.test(overflowX + overflowY))
|
|
403
|
+
clips.push(node);
|
|
404
|
+
}
|
|
405
|
+
let depth = 0;
|
|
406
|
+
for (let node = element?.parentElement; node; node = node.parentElement) {
|
|
407
|
+
if (node.hasAttribute("data-drop-area")) depth++;
|
|
408
|
+
}
|
|
409
|
+
const next = {
|
|
410
|
+
element,
|
|
411
|
+
clips,
|
|
412
|
+
slot,
|
|
413
|
+
depth
|
|
414
|
+
};
|
|
415
|
+
located.set(id2, next);
|
|
416
|
+
return next;
|
|
417
|
+
}
|
|
418
|
+
function destinationOf(area, target) {
|
|
419
|
+
const areaPresentation = area ? presentations.get(area)?.() : void 0;
|
|
420
|
+
const position = target?.kind === "position" ? target.value : null;
|
|
421
|
+
const zone = position ?? areaPresentation?.zone;
|
|
422
|
+
const presentation = zone ? [
|
|
423
|
+
areaPresentation,
|
|
424
|
+
...Array.from(presentations.values(), (read) => read())
|
|
425
|
+
].find(
|
|
426
|
+
(candidate) => candidate?.zone.zoneId === zone.zoneId && candidate.zone.hostId === zone.hostId
|
|
427
|
+
) : void 0;
|
|
428
|
+
return { zone, position, presentation };
|
|
429
|
+
}
|
|
430
|
+
const conceals = (presentation, hostId) => presentation.visibility === "hidden" || presentation.visibility === "ownerOnly" && hostId !== game.me?.id;
|
|
431
|
+
function announce(area) {
|
|
432
|
+
const element = area === null ? null : locate(area).element;
|
|
433
|
+
const label = element?.getAttribute("aria-label") ?? element?.getAttribute("aria-labelledby")?.split(/\s+/).map((labelId) => document.getElementById(labelId)?.textContent).join(" ") ?? "";
|
|
434
|
+
if (!announcer?.isConnected) {
|
|
435
|
+
announcer = document.createElement("div");
|
|
436
|
+
announcer.setAttribute("role", "status");
|
|
437
|
+
Object.assign(announcer.style, VISUALLY_HIDDEN);
|
|
438
|
+
document.body.append(announcer);
|
|
254
439
|
}
|
|
255
|
-
|
|
440
|
+
announcer.textContent = label;
|
|
441
|
+
}
|
|
442
|
+
function retarget(at) {
|
|
443
|
+
const drag = store.get().drag;
|
|
444
|
+
if (!press?.dragging || !drag) return;
|
|
445
|
+
pointer = at;
|
|
446
|
+
const ids = [...areas.keys()];
|
|
447
|
+
const found = ids.map((id2) => {
|
|
448
|
+
const target2 = resolveDropArea(game.drag, areas.get(id2)(at));
|
|
449
|
+
if (!target2) return null;
|
|
450
|
+
const { element, clips, slot, depth } = locate(id2);
|
|
451
|
+
const box = element instanceof HTMLElement ? visibleBox(slot ?? element, clips) : null;
|
|
452
|
+
return { target: target2, box, slot: slot !== null, depth };
|
|
453
|
+
});
|
|
454
|
+
const pickup = drag.width > 0 && drag.size.width > 0 ? drag.size.width / drag.width : 1;
|
|
455
|
+
const ratio = drag.fit.scale === null ? 1 : drag.fit.scale / pickup;
|
|
456
|
+
const width = drag.size.width * ratio;
|
|
457
|
+
const height = drag.size.height * ratio;
|
|
458
|
+
const free = {
|
|
459
|
+
x: at.x - (drag.grab.x - drag.size.width / 2) * ratio,
|
|
460
|
+
y: at.y - (drag.grab.y - drag.size.height / 2) * ratio
|
|
461
|
+
};
|
|
462
|
+
const snap = snapDrop({
|
|
463
|
+
pointer: at,
|
|
464
|
+
card: { x: free.x - width / 2, y: free.y - height / 2, width, height },
|
|
465
|
+
areas: found,
|
|
466
|
+
hit: ids.indexOf(hitAreas(at).find((id2) => found[ids.indexOf(id2)]) ?? ""),
|
|
467
|
+
retained: press.area === null ? -1 : ids.indexOf(press.area),
|
|
468
|
+
coarse: press.pointerType === "touch"
|
|
469
|
+
});
|
|
470
|
+
const area = snap.index < 0 ? null : ids[snap.index];
|
|
471
|
+
const target = snap.index < 0 ? null : found[snap.index].target;
|
|
472
|
+
const changed = area !== press.area || !sameDropTarget(target, press.target);
|
|
473
|
+
if (changed) {
|
|
256
474
|
press.area = area;
|
|
257
475
|
press.target = target;
|
|
258
476
|
game.drag?.setDropTarget(target);
|
|
259
|
-
|
|
260
|
-
|
|
477
|
+
announce(area);
|
|
478
|
+
remeasure = true;
|
|
261
479
|
}
|
|
262
|
-
|
|
480
|
+
const { zone, presentation } = destinationOf(area, target);
|
|
481
|
+
const place = area === null ? null : locate(area);
|
|
482
|
+
const landing = place && (place.slot ?? landingIn(place.element));
|
|
483
|
+
const fit = {
|
|
484
|
+
scale: landing && drag.width > 0 ? landing.offsetWidth / drag.width : drag.fit.scale,
|
|
485
|
+
snapped: snap.held && !!found[snap.index]?.slot,
|
|
486
|
+
concealed: !!presentation && !!zone && conceals(presentation, zone.hostId)
|
|
487
|
+
};
|
|
488
|
+
const refit = Math.abs((fit.scale ?? 0) - (drag.fit.scale ?? 0)) > 0.01 || fit.snapped !== drag.fit.snapped || fit.concealed !== drag.fit.concealed;
|
|
489
|
+
if (changed || refit)
|
|
490
|
+
set({
|
|
491
|
+
drag: {
|
|
492
|
+
...drag,
|
|
493
|
+
area,
|
|
494
|
+
target,
|
|
495
|
+
fit: refit ? fit : drag.fit
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
draw(snap.center, changed || refit || snap.held !== held);
|
|
499
|
+
held = snap.held;
|
|
500
|
+
schedule();
|
|
501
|
+
}
|
|
502
|
+
function draw(next, jump) {
|
|
503
|
+
const nextOffset = { x: next.x - pointer.x, y: next.y - pointer.y };
|
|
504
|
+
if (jump && !reduced)
|
|
505
|
+
lag = {
|
|
506
|
+
x: lag.x + offset.x - nextOffset.x,
|
|
507
|
+
y: lag.y + offset.y - nextOffset.y
|
|
508
|
+
};
|
|
509
|
+
offset = nextOffset;
|
|
510
|
+
goal = next;
|
|
511
|
+
show();
|
|
512
|
+
if (lag.x || lag.y) schedule();
|
|
513
|
+
}
|
|
514
|
+
function show() {
|
|
515
|
+
shown = { x: goal.x + lag.x, y: goal.y + lag.y };
|
|
516
|
+
for (const follow of followers) follow(shown);
|
|
517
|
+
}
|
|
518
|
+
function schedule() {
|
|
519
|
+
if (frame || disposed) return;
|
|
520
|
+
lastFrame = performance.now();
|
|
521
|
+
frame = requestAnimationFrame(tick);
|
|
522
|
+
}
|
|
523
|
+
function tick(now) {
|
|
524
|
+
frame = 0;
|
|
525
|
+
if (!store.get().drag) return;
|
|
526
|
+
const elapsed = Math.min(64, Math.max(0, now - lastFrame));
|
|
527
|
+
const decay = Math.exp(-elapsed / CATCH_UP_MS);
|
|
528
|
+
lag = Math.hypot(lag.x, lag.y) * decay < 0.5 ? { x: 0, y: 0 } : { x: lag.x * decay, y: lag.y * decay };
|
|
529
|
+
const scrolling = press?.dragging ? autoScroll(elapsed / 16.7) : false;
|
|
530
|
+
if (scrolling || remeasure) {
|
|
531
|
+
remeasure = false;
|
|
532
|
+
retarget(pointer);
|
|
533
|
+
} else show();
|
|
534
|
+
if (lag.x || lag.y || scrolling) schedule();
|
|
535
|
+
}
|
|
536
|
+
function autoScroll(frames) {
|
|
537
|
+
const edge = SCROLL_EDGE[press?.pointerType === "touch" ? "coarse" : "fine"];
|
|
538
|
+
const top = document.elementsFromPoint(pointer.x, pointer.y).find((element) => !element.closest("[data-drag-overlay]"));
|
|
539
|
+
for (let node = top ?? null; node; node = node.parentElement) {
|
|
540
|
+
const step = scrollStep(node, pointer, edge, frames);
|
|
541
|
+
if (!step.x && !step.y) {
|
|
542
|
+
if (node.scrollHeight > node.clientHeight || node.scrollWidth > node.clientWidth)
|
|
543
|
+
engaged.add(node);
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (!engaged.has(node)) return false;
|
|
547
|
+
node.scrollBy(step.x, step.y);
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
return false;
|
|
263
551
|
}
|
|
264
552
|
function swallow(event) {
|
|
265
553
|
if (!swallowing || event.detail === 0) return;
|
|
@@ -386,12 +674,26 @@ function createGestureSession(game) {
|
|
|
386
674
|
clearHover();
|
|
387
675
|
focused = null;
|
|
388
676
|
press.dragging = true;
|
|
677
|
+
located.clear();
|
|
678
|
+
engaged.clear();
|
|
679
|
+
if (announcer) announcer.textContent = "";
|
|
680
|
+
reduced = matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
681
|
+
held = false;
|
|
682
|
+
remeasure = false;
|
|
683
|
+
lag = { x: 0, y: 0 };
|
|
684
|
+
goal = shown = {
|
|
685
|
+
x: box.left + box.width / 2,
|
|
686
|
+
y: box.top + box.height / 2
|
|
687
|
+
};
|
|
688
|
+
offset = { x: goal.x - origin.x, y: goal.y - origin.y };
|
|
389
689
|
set({
|
|
390
690
|
drag: {
|
|
391
691
|
cardIds: game.drag?.active?.cardIds ?? [cardId2],
|
|
392
692
|
cardId: cardId2,
|
|
393
693
|
grab: { x: origin.x - box.left, y: origin.y - box.top },
|
|
394
694
|
size: { width: box.width, height: box.height },
|
|
695
|
+
width: element2 instanceof HTMLElement ? element2.offsetWidth : 0,
|
|
696
|
+
fit: UNFIT,
|
|
395
697
|
settling: false,
|
|
396
698
|
area: null,
|
|
397
699
|
target: null,
|
|
@@ -402,10 +704,7 @@ function createGestureSession(game) {
|
|
|
402
704
|
});
|
|
403
705
|
return true;
|
|
404
706
|
},
|
|
405
|
-
dragMove
|
|
406
|
-
pointer = retarget(at);
|
|
407
|
-
for (const follow of followers) follow(pointer);
|
|
408
|
-
},
|
|
707
|
+
dragMove: retarget,
|
|
409
708
|
browse: scrubTo,
|
|
410
709
|
end(kind, at) {
|
|
411
710
|
const dragging = press.dragging;
|
|
@@ -423,15 +722,10 @@ function createGestureSession(game) {
|
|
|
423
722
|
}
|
|
424
723
|
const before = game.request;
|
|
425
724
|
const drag = store.get().drag;
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
areaPresentation,
|
|
431
|
-
...Array.from(presentations.values(), (read) => read())
|
|
432
|
-
].find(
|
|
433
|
-
(candidate) => candidate?.zone.zoneId === zone.zoneId && candidate.zone.hostId === zone.hostId
|
|
434
|
-
) : void 0;
|
|
725
|
+
const { zone, position, presentation } = destinationOf(
|
|
726
|
+
drag?.area ?? null,
|
|
727
|
+
drag?.target ?? null
|
|
728
|
+
);
|
|
435
729
|
const destination = zone && game.zones.find(zone.zoneId, zone.hostId);
|
|
436
730
|
const cards = drag?.cardIds.flatMap((id2) => {
|
|
437
731
|
const card2 = game.cards.find(id2);
|
|
@@ -441,7 +735,7 @@ function createGestureSession(game) {
|
|
|
441
735
|
zoneId: zone.zoneId,
|
|
442
736
|
hostId: zone.hostId,
|
|
443
737
|
index: position?.index ?? presentation?.index ?? destination.getCards().length,
|
|
444
|
-
concealed: presentation ? presentation
|
|
738
|
+
concealed: presentation ? conceals(presentation, zone.hostId) : cards.some(
|
|
445
739
|
(card2) => card2.zone !== zone.zoneId || card2.hostId !== zone.hostId || card2.hidden
|
|
446
740
|
),
|
|
447
741
|
cards: Object.freeze(cards),
|
|
@@ -542,11 +836,11 @@ function createGestureSession(game) {
|
|
|
542
836
|
width: px(drag.size.width),
|
|
543
837
|
height: px(drag.size.height)
|
|
544
838
|
});
|
|
545
|
-
const follow = (
|
|
546
|
-
element.style.left = px(
|
|
547
|
-
element.style.top = px(
|
|
839
|
+
const follow = (center) => {
|
|
840
|
+
element.style.left = px(center.x - drag.size.width / 2);
|
|
841
|
+
element.style.top = px(center.y - drag.size.height / 2);
|
|
548
842
|
};
|
|
549
|
-
follow(
|
|
843
|
+
follow(shown);
|
|
550
844
|
followers.add(follow);
|
|
551
845
|
return () => {
|
|
552
846
|
followers.delete(follow);
|
|
@@ -630,6 +924,8 @@ function createGestureSession(game) {
|
|
|
630
924
|
dispose() {
|
|
631
925
|
disposed = true;
|
|
632
926
|
press?.recognizer.cancel();
|
|
927
|
+
cancelAnimationFrame(frame);
|
|
928
|
+
announcer?.remove();
|
|
633
929
|
clearHover();
|
|
634
930
|
removeEventListener("keydown", key);
|
|
635
931
|
removeEventListener("keyup", key);
|
|
@@ -990,6 +1286,7 @@ function createGameHook() {
|
|
|
990
1286
|
hostId: drag.landing.hostId,
|
|
991
1287
|
index: drag.landing.index
|
|
992
1288
|
} : null,
|
|
1289
|
+
fit: drag.fit,
|
|
993
1290
|
ref: session.overlayRef
|
|
994
1291
|
} : null;
|
|
995
1292
|
}
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/create-game-hook.tsx","../src/react/shortcuts.ts","../src/react/gesture.tsx","../src/react/marquee.ts"],"sourcesContent":["import { createStore } from \"@tanstack/store\";\nimport { inputValueKey } from \"../shared/input-domain.js\";\nimport { useShortcutsAdapter } from \"./shortcuts.js\";\nimport type {\n ShortcutOptions,\n ShortcutTarget,\n ShortcutHint,\n ShortcutActivity,\n ShortcutsController,\n RuntimeShortcutTarget,\n} from \"../headless/features/shortcuts.js\";\nimport {\n createGestureSession,\n resolveDropArea,\n sameDropTarget,\n GestureContext,\n useGestureSession,\n useGestureState,\n type CardGestureProps,\n type DropAreaInput,\n type GestureGame,\n type GestureSession,\n} from \"./gesture.js\";\nimport type { SeatCardId, IdOf, ZoneHostId, Card } from \"../headless/model.js\";\nimport type { ZoneVisibility } from \"../shared/domain/contracts.js\";\nimport type {\n DropAreaBinding,\n DropTarget,\n RuntimeTargetOptions,\n TargetOptions,\n} from \"../headless/targets.js\";\nimport {\n createContext,\n useContext,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n useMemo,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport { createGameInstance } from \"../headless/instance.js\";\nimport type {\n CoreInstance,\n FeatureContext,\n Features,\n GameInstance,\n GameSnapshot,\n GameSource,\n InstanceOptions,\n} from \"../headless/model.js\";\n\nexport interface SelectionOptions<Value> {\n readonly compare?: (previous: Value, next: Value) => boolean;\n}\n\n/** Inspection stays enabled when this control does not support dragging. */\nexport interface CardGestureOptions<Game> {\n readonly drag: false | TargetOptions<Game>;\n}\n\n/** An area that runs this interaction with whichever card is dropped on it. */\nexport type { DropAreaBinding } from \"../headless/targets.js\";\n\nexport interface CardGesture {\n /** Spread on the card's own control, after the card's selection props. */\n readonly props: CardGestureProps;\n readonly canDrag: boolean;\n readonly isDragging: boolean;\n /** Submitted and waiting for the authoritative frame; cannot start another gesture. */\n readonly isPending: boolean;\n readonly isActive: boolean;\n /** Held on touch, or rested on with a mouse. */\n readonly inspecting: \"hold\" | \"hover\" | null;\n}\n\nexport interface DropAreaOptions<Game> {\n readonly zone: import(\"../headless/features/shortcuts.js\").ShortcutZoneTarget<Game> extends infer Target\n ? Target extends { readonly kind: \"zone\" }\n ? Omit<Target, \"kind\">\n : never\n : never;\n readonly visibility: ZoneVisibility;\n /** Defaults to the end of the zone; piles can land on their top at index 0. */\n readonly index?: number;\n}\n\nexport interface ZonePresentation<Game, Enabled extends Features> {\n readonly cards: readonly Card<Game, Enabled>[];\n readonly count: number;\n readonly arrivingIds: readonly SeatCardId<Game>[];\n}\n\nexport interface CardPresentation<Game, Enabled extends Features> {\n readonly card: Card<Game, Enabled> | undefined;\n readonly isPending: boolean;\n readonly hidden: boolean;\n}\n\nexport interface CardRow {\n /** Spread on the element holding the row's cards; touching them never scrolls. */\n readonly props: {\n readonly \"data-card-row\": string;\n readonly style: CSSProperties;\n };\n}\n\nexport interface DropArea {\n readonly props: {\n readonly \"data-drop-area\": string;\n readonly \"data-drop-target\"?: \"true\";\n readonly \"data-drop-over\"?: true;\n };\n readonly isEligible: boolean;\n readonly isOver: boolean;\n}\n\nexport interface DragOverlay<G> {\n readonly cardId: SeatCardId<G>;\n readonly cardIds: readonly SeatCardId<G>[];\n /** Dropped and submitted; the authoritative frame has not arrived yet. */\n readonly settling: boolean;\n /** Where the card lands if dropped now; kept while it settles. */\n readonly target: DropTarget<G> | null;\n /** A registered zone landing; absent for interactions with no zone destination. */\n readonly landing:\n | import(\"../shared/position-target.js\").PositionTarget<\n IdOf<G, \"zoneId\">,\n ZoneHostId<G>\n >\n | null;\n /** Attach to a fixed-position copy of the card; it follows the pointer. */\n readonly ref: (element: HTMLElement | null) => (() => void) | undefined;\n}\n\n/** Bind erased game types and features; each provider owns its source lifetime. */\nexport function createGameHook<Game, Source extends GameSource = GameSource>() {\n return function <const Enabled extends Features = Record<never, never>>(\n defaults: Omit<InstanceOptions<Game, Source>, \"source\"> & {\n features?: (\n core: CoreInstance<Game>,\n context: FeatureContext<Game>,\n ) => Enabled;\n },\n ) {\n type Instance = GameInstance<Game, Enabled, Source>;\n type Snapshot = GameSnapshot<Game, Enabled>;\n type ProviderProps = Partial<\n Omit<InstanceOptions<Game, Source>, \"source\">\n > & {\n source: Source;\n children?: ReactNode;\n };\n const Context = createContext<Instance | null>(null);\n\n /** Owns the source. Do not share it between independently mounted providers. */\n function GameProvider({ children, ...overrides }: ProviderProps) {\n const [owned, setOwned] = useState<{\n instance: Instance;\n session: GestureSession;\n } | null>(null);\n const lifetime = useRef<{\n instance: Instance;\n session: GestureSession;\n generation: number;\n } | null>(null);\n const options = {\n ...defaults,\n ...overrides,\n };\n useLayoutEffect(() => {\n let current = lifetime.current;\n if (!current) {\n const instance = createGameInstance<Game>()(options);\n current = {\n instance,\n // One bound game crosses into the framework adapter's erased runtime.\n session: createGestureSession(instance as GestureGame),\n generation: 0,\n };\n lifetime.current = current;\n setOwned({ instance, session: current.session });\n }\n const owned = current;\n ++owned.generation;\n return () => {\n const generation = ++owned.generation;\n queueMicrotask(() => {\n if (owned.generation !== generation) return;\n owned.session.dispose();\n owned.instance.dispose();\n if (lifetime.current === owned) lifetime.current = null;\n });\n };\n // Construction belongs to this committed provider lifetime. Current\n // options are installed separately without recreating features.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Construct once per committed provider lifetime; the next effect updates options.\n }, []);\n useLayoutEffect(() => {\n lifetime.current?.instance.setOptions(options);\n });\n return owned ? (\n <Context.Provider value={owned.instance}>\n <GestureContext.Provider value={owned.session}>\n {children}\n </GestureContext.Provider>\n </Context.Provider>\n ) : null;\n }\n\n function useInstance(): Instance {\n const instance = useContext(Context);\n if (!instance) throw new Error(\"useGame requires its GameProvider.\");\n return instance;\n }\n\n function useGame(): Instance;\n function useGame<Value>(\n selector: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Value;\n function useGame<Value>(\n selector?: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Instance | Value {\n const instance = useInstance();\n const selected = useSelector(\n instance.store,\n (snapshot): { value: Value } | { snapshot: Snapshot } =>\n selector ? { value: selector(snapshot) } : { snapshot },\n {\n compare: (previous, next) =>\n \"value\" in previous && \"value\" in next\n ? (options?.compare ?? Object.is)(previous.value, next.value)\n : \"snapshot\" in previous &&\n \"snapshot\" in next &&\n Object.is(previous.snapshot, next.snapshot),\n },\n );\n return \"value\" in selected ? selected.value : instance;\n }\n\n function Subscribe<Value>({\n selector,\n compare,\n children,\n }: {\n selector: (snapshot: Snapshot) => Value;\n compare?: SelectionOptions<Value>[\"compare\"];\n children: (value: Value) => ReactNode;\n }) {\n return children(useGame(selector, { compare }));\n }\n\n // Game-binding boundary: typed ids and routes cross into the erased session.\n const dragOf = (snapshot: Snapshot) =>\n (snapshot as Pick<GestureGame, \"drag\">).drag;\n\n /** Tap, hold, drag and browse on one card; hover intent with a mouse. */\n function useCardGesture(\n cardId: SeatCardId<Game>,\n options: CardGestureOptions<Game>,\n ): CardGesture {\n const session = useGestureSession();\n const control = `${session.id}${useId()}`;\n const routes = options.drag as false | RuntimeTargetOptions;\n const latestRoutes = useRef(routes);\n useLayoutEffect(() => {\n latestRoutes.current = routes;\n });\n useLayoutEffect(\n () => session.registerControl(control, () => latestRoutes.current),\n [session, control],\n );\n const canDrag = useGame(\n (snapshot) =>\n routes !== false &&\n (dragOf(snapshot)?.getCanDrag(cardId, routes) ?? false),\n );\n const dragging = useGestureState(\n session,\n (state) => state.drag?.cardIds.includes(cardId) ?? false,\n );\n const pending = useGestureState(\n session,\n (state) =>\n !!state.drag?.settling && state.drag.cardIds.includes(cardId),\n );\n const inspecting = useGestureState(session, (state) =>\n state.inspect?.cardId === cardId ? state.inspect.via : null,\n );\n const isActive = useGestureState(\n session,\n (state) =>\n state.activeTarget?.kind === \"card\" &&\n state.activeTarget.value === cardId,\n );\n return {\n props: session.cardProps(cardId, control, routes, {\n dragging,\n inspecting,\n }),\n canDrag,\n isDragging: dragging,\n isPending: pending,\n isActive,\n inspecting,\n };\n }\n\n /**\n * Marks an element where a dragged card can land: a board destination,\n * or an area that runs an interaction with the dropped card. A function\n * is read at each dragged point, as for the insertion point under the\n * pointer; that area is eligible and over while the card is over it.\n */\n function useDropArea(\n binding:\n | DropTarget<Game>\n | DropAreaBinding<Game>\n | null\n | ((point: {\n readonly x: number;\n readonly y: number;\n }) => DropTarget<Game> | DropAreaBinding<Game> | null),\n options?: DropAreaOptions<Game>,\n ): DropArea {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const erased = binding as DropAreaInput;\n const fixed = typeof erased === \"function\" ? null : erased;\n const target = useGame(\n (snapshot) => resolveDropArea(dragOf(snapshot), fixed),\n { compare: sameDropTarget },\n );\n const isOver = useGame((snapshot) => {\n const active = dragOf(snapshot)?.active?.target;\n return !!target && sameDropTarget(active ?? null, target);\n });\n const following = useGestureState(\n session,\n (state) =>\n typeof erased === \"function\" &&\n state.drag?.area === id &&\n state.drag.target !== null,\n );\n const latest = useRef(erased);\n const latestPresentation = useRef(options);\n useLayoutEffect(() => {\n latest.current = erased;\n latestPresentation.current = options;\n });\n useLayoutEffect(\n () =>\n session.registerArea(\n id,\n (point) => {\n const current = latest.current;\n return typeof current === \"function\" ? current(point) : current;\n },\n () => latestPresentation.current,\n ),\n [session, id],\n );\n return {\n props: {\n \"data-drop-area\": id,\n \"data-drop-target\": target || following ? \"true\" : undefined,\n \"data-drop-over\": isOver || following || undefined,\n },\n isEligible: target !== null || following,\n isOver: isOver || following,\n };\n }\n\n /** Presentation-only zone contents. The source snapshot and domain models stay authoritative. */\n function useZonePresentation<Z extends IdOf<Game, \"zoneId\">>(\n zoneId: Z,\n hostId: ZoneHostId<Game, Z>,\n options?: { readonly order: readonly SeatCardId<Game>[] },\n ): ZonePresentation<Game, Enabled> {\n const game = useGame();\n const session = useGestureSession();\n const landing = useGestureState(session, (state) =>\n state.drag?.settling ? state.drag.landing : null,\n );\n const zone = game.zones.find(zoneId, hostId);\n const actual = useMemo(\n () => (zone?.getCards() ?? []) as readonly Card<Game, Enabled>[],\n [zone],\n );\n const active = landing?.snapshot === game.snapshot ? landing : null;\n const incoming = active?.zoneId === zoneId && active.hostId === hostId;\n const outgoing =\n active?.cards.filter(\n (card) => card.zone === zoneId && card.hostId === hostId,\n ) ?? [];\n const cards = useMemo(() => {\n const ordered = options\n ? options.order.flatMap((id) => {\n const card = actual.find((card) => card.id === id);\n return card ? [card] : [];\n })\n : actual;\n if (!active) return ordered;\n const moving = new Set(active.cards.map((card) => card.id));\n const remaining = ordered.filter((card) => !moving.has(card.id));\n if (incoming) {\n const before = ordered\n .slice(0, active.index)\n .filter((card) => moving.has(card.id)).length;\n const index = Math.max(\n 0,\n Math.min(remaining.length, active.index - before),\n );\n // This hook belongs to the same bound game as the captured drag.\n remaining.splice(\n index,\n 0,\n ...(active.cards as readonly Card<Game, Enabled>[]),\n );\n }\n return remaining;\n }, [actual, active, incoming, options]);\n const source = game.getOptions().source;\n const me = game.me?.id;\n const count =\n (zone?.count ?? 0) -\n outgoing.length +\n (incoming ? active.cards.length : 0);\n const previous = useRef({\n source,\n me,\n ids: new Set(actual.map((card) => card.id)),\n incoming: 0,\n count: zone?.count ?? 0,\n });\n const newlyArriving =\n previous.current.source === source && previous.current.me === me\n ? cards\n .filter(\n (card) =>\n !previous.current.ids.has(card.id) &&\n !active?.cards.some((pending) => pending.id === card.id),\n )\n .map((card) => card.id as SeatCardId<Game>)\n : [];\n // A concealed source can reveal a different ID on acceptance. Suppress\n // a second flight when the already-filled destination is replaced by\n // exactly that many new cards; never invent a persistent hidden identity.\n const arrivingIds =\n previous.current.incoming > 0 &&\n newlyArriving.length === previous.current.incoming &&\n count === previous.current.count\n ? []\n : newlyArriving;\n useLayoutEffect(() => {\n // Include authority as well as the display list so rejection cannot replay an old arrival.\n previous.current = {\n source,\n me,\n ids: new Set([...actual, ...cards].map((card) => card.id)),\n incoming: incoming ? active.cards.length : 0,\n count,\n };\n });\n return {\n cards,\n count,\n arrivingIds,\n };\n }\n\n /** One card's face and pending status, shared by every standard card control. */\n function useCardPresentation(\n cardId: SeatCardId<Game>,\n ): CardPresentation<Game, Enabled> {\n const game = useGame();\n const session = useGestureSession();\n const landing = useGestureState(session, (state) =>\n state.drag?.settling ? state.drag.landing : null,\n );\n const active = landing?.snapshot === game.snapshot ? landing : null;\n const captured = active?.cards.find((card) => card.id === cardId);\n const card =\n game.cards.find(cardId) ??\n (captured as Card<Game, Enabled> | undefined);\n return {\n card,\n isPending: !!captured,\n hidden:\n card?.hidden === true || (!!captured && active?.concealed === true),\n };\n }\n\n const shortcutsOf = (snapshot: Snapshot) =>\n (\n snapshot as Snapshot & {\n readonly shortcuts?: ShortcutsController<Game>;\n }\n ).shortcuts;\n const noShortcutsConfiguration = createStore<ShortcutOptions<Game> | null>(\n null,\n );\n const sameHints = (\n left: readonly ShortcutHint<Game>[],\n right: readonly ShortcutHint<Game>[],\n ) =>\n left.length === right.length &&\n left.every((hint, index) => {\n const next = right[index];\n return (\n hint.label === next.label &&\n hint.kind === next.kind &&\n (hint.kind !== \"interaction\" ||\n (next.kind === \"interaction\" &&\n hint.interaction === next.interaction)) &&\n hint.keys.length === next.keys.length &&\n hint.keys.every((key, at) => key === next.keys[at])\n );\n });\n /** Current eligible hints; configuration and projected domains each notify their own readers. */\n function useShortcutHints(\n target: ShortcutTarget<Game> | null,\n ): readonly ShortcutHint<Game>[] {\n const controller = shortcutsOf(useInstance());\n const session = useGestureSession();\n useSelector(session.store, () => session.getShortcutActivity(), {\n compare: (left, right) =>\n left.focusedTarget === right.focusedTarget &&\n left.pointerActive === right.pointerActive,\n });\n useGame(\n (snapshot) =>\n shortcutsOf(snapshot)?.getHints(\n target,\n session.getShortcutActivity() as ShortcutActivity<Game>,\n ) ?? [],\n {\n compare: sameHints,\n },\n );\n return useSelector(\n controller?.configuration ?? noShortcutsConfiguration,\n () =>\n controller?.getHints(\n target,\n session.getShortcutActivity() as ShortcutActivity<Game>,\n ) ?? [],\n { compare: sameHints },\n );\n }\n\n /** Installs the authored keyboard bindings for this mounted application. */\n function useGameShortcuts(options: ShortcutOptions<Game>): {\n readonly target: ShortcutTarget<Game> | null;\n readonly hints: readonly ShortcutHint<Game>[];\n } {\n const instance = useInstance();\n const session = useGestureSession();\n // Feature-composition boundary: this binding and its installed root feature share Game.\n const controller = shortcutsOf(instance);\n if (!controller)\n throw new Error(\n \"useGameShortcuts requires shortcutsFeature in the game binding.\",\n );\n useShortcutsAdapter(instance, controller, session, options, (result) => {\n if (result instanceof Error) instance.getOptions().onError?.(result);\n else if (result.kind === \"interaction\" && !result.result.accepted)\n instance.getOptions().onError?.(\n new Error(result.result.message ?? result.result.errorCode, {\n cause: result.result,\n }),\n );\n });\n const target = useGestureState(\n session,\n (state) => state.activeTarget,\n ) as ShortcutTarget<Game> | null;\n const hints = useShortcutHints(target);\n return { target, hints };\n }\n\n /** Shares the canonical pointer and keyboard focus with a zone, tile or board control. */\n function useShortcutTarget(target: ShortcutTarget<Game>) {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const latest = useRef<RuntimeShortcutTarget>(target);\n const targetKey = inputValueKey(target);\n useLayoutEffect(() => {\n latest.current = target;\n });\n useLayoutEffect(\n () => session.registerTarget(id, () => latest.current),\n [session, id, targetKey],\n );\n return { props: session.targetProps(id) };\n }\n\n /** The card being dragged, and a ref that keeps its copy under the pointer. */\n function useDragOverlay(): DragOverlay<Game> | null {\n const session = useGestureSession();\n const drag = useGestureState(session, (state) => state.drag);\n return drag\n ? {\n cardId: drag.cardId as SeatCardId<Game>,\n cardIds: drag.cardIds as readonly SeatCardId<Game>[],\n settling: drag.settling,\n // The drag feature resolved this target from this game's routes.\n target: drag.target as DropTarget<Game> | null,\n landing: drag.landing\n ? {\n zoneId: drag.landing.zoneId as IdOf<Game, \"zoneId\">,\n hostId: drag.landing.hostId as ZoneHostId<Game>,\n index: drag.landing.index,\n }\n : null,\n ref: session.overlayRef,\n }\n : null;\n }\n\n /**\n * Marks a row of cards that fits without scrolling, such as a hand. A\n * finger pressed on one of its cards slides along the row: `cardAt`\n * names the card whose resting place is under a viewport point, or null\n * off the row. That card becomes active; lifting the finger there clicks\n * it, and pulling up drags it.\n */\n function useCardRow(\n cardAt: (point: {\n readonly x: number;\n readonly y: number;\n }) => SeatCardId<Game> | null,\n ): CardRow {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const latest = useRef(cardAt);\n useLayoutEffect(() => {\n latest.current = cardAt;\n });\n useLayoutEffect(\n () => session.registerRow(id, (point) => latest.current(point)),\n [session, id],\n );\n return { props: session.rowProps(id) };\n }\n\n /** Presentation focus shared by the fan, inspection and pointer activation. */\n function useActiveCard(): SeatCardId<Game> | null {\n const session = useGestureSession();\n return useGestureState(\n session,\n (state) =>\n (state.activeTarget?.kind === \"card\"\n ? state.activeTarget.value\n : null) as SeatCardId<Game> | null,\n );\n }\n\n return {\n GameProvider,\n useGame,\n Subscribe,\n useCardGesture,\n useCardRow,\n useActiveCard,\n useGameShortcuts,\n useShortcutTarget,\n useShortcutHints,\n useDropArea,\n useDragOverlay,\n useZonePresentation,\n useCardPresentation,\n };\n };\n}\n","import { useLayoutEffect, useRef } from \"react\";\nimport type {\n ShortcutOptions,\n ShortcutTarget,\n ShortcutsController,\n RuntimeShortcutTarget,\n ShortcutActivity,\n ShortcutResult,\n} from \"../headless/features/shortcuts.js\";\nimport type { CoreInstance } from \"../headless/model.js\";\n\n/** Browser adapter input; the gesture session owns the single active target. */\nexport interface ShortcutSession {\n getActiveTarget(): RuntimeShortcutTarget | null;\n getShortcutActivity(): ShortcutActivity<unknown>;\n}\nfunction canHandle(event: KeyboardEvent) {\n const target = event.target;\n return (\n !event.defaultPrevented &&\n !event.repeat &&\n !event.isComposing &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.shiftKey &&\n !(\n target instanceof Element &&\n target.closest(\n \"input:not([type='radio']), textarea, select, [contenteditable]:not([contenteditable='false']), [role='textbox']\",\n )\n ) &&\n !Array.from(\n document.querySelectorAll(\n \"[aria-modal='true'], dialog[open], [role='dialog'], [role='menu'], [role='listbox']\",\n ),\n ).some(\n (surface) =>\n !surface.closest(\"[aria-hidden='true']\") &&\n surface.checkVisibility({\n visibilityProperty: true,\n opacityProperty: true,\n }),\n )\n );\n}\n/** Installs only for a committed child beneath the bound GameProvider. */\nexport function useShortcutsAdapter<G>(\n game: CoreInstance<G>,\n controller: ShortcutsController<G>,\n session: ShortcutSession,\n options: ShortcutOptions<G>,\n onResult: (result: ShortcutResult | Error) => void,\n) {\n const latest = useRef({ options, onResult });\n const registration = useRef<ReturnType<\n ShortcutsController<G>[\"register\"]\n > | null>(null);\n useLayoutEffect(() => {\n latest.current = { options, onResult };\n });\n useLayoutEffect(() => {\n let mounted = true;\n const owned = controller.register(latest.current.options);\n registration.current = owned;\n let source = game.getOptions().source;\n let seat = game.snapshot?.me;\n let lifetime = 0;\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const nextSeat = game.snapshot?.me;\n if (source === nextSource && seat === nextSeat) return;\n source = nextSource;\n seat = nextSeat;\n ++lifetime;\n });\n function keydown(event: KeyboardEvent) {\n if (!canHandle(event)) return;\n // Bound game identity boundary; session targets originate from its own controls.\n const started = lifetime;\n const active = () => mounted && lifetime === started;\n const pending = controller.handle(\n event.key,\n session.getActiveTarget() as ShortcutTarget<G> | null,\n session.getShortcutActivity() as ShortcutActivity<G>,\n );\n if (!pending) return;\n event.preventDefault();\n void pending.then(\n (result) => {\n if (active()) latest.current.onResult(result);\n },\n (cause: unknown) => {\n if (active())\n latest.current.onResult(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n },\n );\n }\n window.addEventListener(\"keydown\", keydown);\n return () => {\n mounted = false;\n unsubscribe();\n window.removeEventListener(\"keydown\", keydown);\n registration.current = null;\n owned.dispose();\n };\n }, [game, controller, session]);\n useLayoutEffect(() => {\n registration.current?.update(options);\n });\n}\n","import type { RuntimeShortcutTarget } from \"../headless/features/shortcuts.js\";\nimport type { CoreInstance, InstanceOptions, Card } from \"../headless/model.js\";\nimport type { ZoneVisibility } from \"../shared/domain/contracts.js\";\nimport { inputValueKey } from \"../shared/input-domain.js\";\nimport { createStore } from \"@tanstack/store\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport {\n createContext,\n useContext,\n type CSSProperties,\n type DragEvent,\n type FocusEvent,\n type MouseEvent,\n type PointerEvent,\n} from \"react\";\nimport {\n createGestureRecognizer,\n magneticDropPoint,\n type GestureRecognizer,\n} from \"../headless/gesture.js\";\nimport { isSameDropTarget } from \"../headless/drop-targets.js\";\nimport type { PositionTarget } from \"../shared/position-target.js\";\nimport type { Point } from \"../headless/features/pointer-session.js\";\nimport type {\n RuntimeDropTarget,\n RuntimeTargetOptions,\n} from \"../headless/targets.js\";\n\n/** The runtime surface of `dragFeature` that a gesture needs. */\nexport interface GestureDrag {\n readonly active: {\n readonly target: RuntimeDropTarget | null;\n readonly cardIds?: readonly string[];\n } | null;\n getCanDrag(cardId: string, options?: RuntimeTargetOptions): boolean;\n getDropTargets(): readonly RuntimeDropTarget[];\n getIsDropTarget(target: RuntimeDropTarget): boolean;\n begin(cardId: string, options?: RuntimeTargetOptions): boolean;\n setDropTarget(target: RuntimeDropTarget | null): void;\n drop(): void;\n cancel(): void;\n}\nexport interface GestureGame extends Pick<\n CoreInstance<unknown>,\n \"snapshot\" | \"subscribe\" | \"cards\" | \"zones\" | \"me\"\n> {\n readonly drag?: GestureDrag;\n readonly request: unknown;\n getOptions(): Pick<InstanceOptions<unknown>, \"source\">;\n}\n\nexport interface GestureState {\n readonly activeTarget: RuntimeShortcutTarget | null;\n readonly focusedTarget: RuntimeShortcutTarget | null;\n readonly pointerActive: boolean;\n readonly drag: {\n readonly cardId: string;\n readonly cardIds: readonly string[];\n /** Pointer offset inside the card where it was picked up. */\n readonly grab: Point;\n readonly size: { readonly width: number; readonly height: number };\n /** Dropped and submitted; waiting for the authoritative frame. */\n readonly settling: boolean;\n /** The area under the card and where it would land there, kept while settling. */\n readonly area: string | null;\n readonly target: RuntimeDropTarget | null;\n readonly landing: {\n readonly zoneId: string;\n readonly hostId: string;\n readonly index: number;\n readonly concealed: boolean;\n readonly cards: readonly Card<unknown, Record<never, never>>[];\n readonly snapshot: GestureGame[\"snapshot\"];\n } | null;\n } | null;\n readonly inspect: {\n readonly cardId: string;\n readonly via: \"hold\" | \"hover\";\n } | null;\n}\n\n/** A renderer's destination identity and its existing disclosure policy. */\nexport interface RuntimeDropPresentation {\n readonly zone: { readonly zoneId: string; readonly hostId: string };\n readonly visibility: ZoneVisibility;\n readonly index?: number;\n}\n\nexport interface CardGestureProps {\n onPointerDown(event: PointerEvent<Element>): void;\n onFocus(event: FocusEvent<Element>): void;\n onBlur(): void;\n onContextMenu(event: MouseEvent<Element>): void;\n onDragStart(event: DragEvent<Element>): void;\n readonly style: CSSProperties;\n readonly \"data-dragging\"?: true;\n readonly \"data-inspecting\"?: \"hold\" | \"hover\";\n readonly \"data-card-gesture\": string;\n readonly \"data-card-control\": string;\n readonly \"data-gesture-session\": string;\n}\n\nconst CARD_STYLE: CSSProperties = Object.freeze({\n // Sideways movement stays native scrolling; everything else reaches the recognizer.\n touchAction: \"pan-x\",\n userSelect: \"none\",\n WebkitUserSelect: \"none\",\n WebkitTouchCallout: \"none\",\n});\nconst INSPECTION_STYLE: CSSProperties = Object.freeze({\n ...CARD_STYLE,\n // Inspection-only cards should not block their table's native scrolling.\n touchAction: \"manipulation\",\n});\nconst ROW_STYLE: CSSProperties = Object.freeze({\n // A row that fits never scrolls; its cards' sideways movement scrubs instead.\n touchAction: \"none\",\n});\nconst px = (value: number) => `${value}px`;\n\n/** The card whose resting place in a row is under a viewport point, or null off the row. */\nexport type CardRowLookup = (point: Point) => string | null;\n\n/** A resolved destination, the interaction an area runs, or an insertion point it offers. */\nexport type DropAreaValue =\n | RuntimeDropTarget\n | {\n readonly interaction: string;\n readonly input?: string;\n readonly params?: import(\"../headless/targets.js\").RuntimeInteractionDropTarget[\"params\"];\n readonly position?: PositionTarget;\n }\n | null;\n/** A fixed binding, or one read at each dragged point, as for an insertion point under the pointer. */\nexport type DropAreaInput = DropAreaValue | ((point: Point) => DropAreaValue);\n\nexport function resolveDropArea(\n drag: GestureDrag | undefined,\n binding: DropAreaValue,\n): RuntimeDropTarget | null {\n if (!drag || !binding) return null;\n if (\"interactionKey\" in binding)\n return drag.getIsDropTarget(binding) ? binding : null;\n const { position } = binding;\n const matches = drag\n .getDropTargets()\n .filter(\n (target) =>\n target.kind === (position ? \"position\" : \"interaction\") &&\n target.interactionKey === binding.interaction &&\n (!binding.input || target.cardInputKey === binding.input) &&\n (!position ||\n (target.kind === \"position\" &&\n inputValueKey(target.value) === inputValueKey(position))),\n );\n if (position)\n return matches.length === 1 && drag.getIsDropTarget(matches[0])\n ? matches[0]\n : null;\n // Two card inputs on one interaction need an explicit `input`.\n if (matches.length !== 1) return null;\n const target = {\n ...matches[0],\n ...(binding.params === undefined ? {} : { params: binding.params }),\n };\n return drag.getIsDropTarget(target) ? target : null;\n}\n/** Targets are rebuilt with every drag update; compare what they route. */\nexport const sameDropTarget = (\n left: RuntimeDropTarget | null,\n right: RuntimeDropTarget | null,\n) => left === right || (!!left && !!right && isSameDropTarget(left, right));\nlet sessions = 0;\n\nexport type GestureSession = ReturnType<typeof createGestureSession>;\n\n/**\n * One press at a time for a provider: tap, hold, drag or browse, plus mouse\n * hover intent. The session outlives the pressed element, so a hand may move\n * the card into an overlay mid-drag. Drop areas are found with the browser's\n * own hit testing, so transformed and SVG areas need no geometry. A finger on\n * a card in a row slides along it: the row names the card whose resting place\n * is under the finger, which becomes active; lifting there clicks that card,\n * and pulling up drags it.\n */\nexport function createGestureSession(game: GestureGame) {\n const id = `g${++sessions}`;\n const store = createStore<GestureState>({\n activeTarget: null,\n focusedTarget: null,\n pointerActive: false,\n drag: null,\n inspect: null,\n });\n const targets = new Map<string, () => RuntimeShortcutTarget>();\n const sameTarget = (\n left: RuntimeShortcutTarget | null,\n right: RuntimeShortcutTarget | null,\n ) => inputValueKey(left) === inputValueKey(right);\n const areas = new Map<string, (point: Point) => DropAreaValue>();\n const presentations = new Map<\n string,\n () => RuntimeDropPresentation | undefined\n >();\n const rows = new Map<string, CardRowLookup>();\n // A slide can end on a control other than the pressed one; it drags with\n // that mounted control's own routes.\n const controls = new Map<string, () => false | RuntimeTargetOptions>();\n const followers = new Set<(point: Point) => void>();\n let press: {\n readonly recognizer: GestureRecognizer;\n readonly pointerType: string;\n readonly detach: () => void;\n dragging: boolean;\n area: string | null;\n target: RuntimeDropTarget | null;\n } | null = null;\n let hover: RuntimeShortcutTarget | null = null;\n let hoverPoint: Point | null = null;\n let focused: RuntimeShortcutTarget | null = null;\n // Real DOM focus remains a local-action scope when mouse browsing changes presentation focus.\n let domFocused: RuntimeShortcutTarget | null = null;\n let alt = false;\n let pointer: Point = { x: 0, y: 0 };\n let swallowing = false;\n let guardingClicks = false;\n let disposed = false;\n\n const set = (patch: Partial<GestureState>) =>\n store.setState((previous) => {\n const next = { ...previous, ...patch };\n return {\n ...next,\n focusedTarget: domFocused,\n pointerActive: press !== null || next.drag !== null,\n };\n });\n\n let snapshot = game.snapshot;\n let source = game.getOptions().source;\n function admitted(target: RuntimeShortcutTarget | null) {\n if (!target || !game.snapshot) return null;\n const zones = game.snapshot.frame.zones;\n if (target.kind === \"zone\")\n return zones[target.zoneId]?.[target.hostId] ? target : null;\n if (target.kind === \"card\")\n return Object.entries(snapshot?.frame.zones ?? {}).some(\n ([zoneId, hosts]) =>\n Object.entries(hosts).some(\n ([hostId, zone]) =>\n zone.cardIds.includes(target.value) &&\n zones[zoneId]?.[hostId]?.cardIds.includes(target.value),\n ),\n )\n ? target\n : null;\n // Board controls own their mounted identity; each shortcut still checks\n // the current projected input domain before submitting.\n return [...targets.values()].some((read) => sameTarget(read(), target))\n ? target\n : null;\n }\n function admittedFocus(target: RuntimeShortcutTarget | null) {\n if (!target || !sameTarget(target, targetOf(document.activeElement)))\n return null;\n if (target.kind !== \"card\") return admitted(target);\n // A mounted focused card can move between zones without another focus event.\n return Object.values(game.snapshot?.frame.zones ?? {}).some((hosts) =>\n Object.values(hosts).some((zone) => zone.cardIds.includes(target.value)),\n )\n ? target\n : null;\n }\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const changedLifetime =\n source !== nextSource || snapshot?.me !== game.snapshot?.me;\n const changedSnapshot = snapshot !== game.snapshot;\n if (changedLifetime || snapshot !== game.snapshot) {\n // Cancelling first lets a scrubbing finger take its activity with it.\n press?.recognizer.cancel();\n const nextHover = changedLifetime ? null : admitted(hover);\n const nextFocused = changedLifetime ? null : admitted(focused);\n const nextDomFocused = changedLifetime ? null : admittedFocus(domFocused);\n source = nextSource;\n snapshot = game.snapshot;\n alt = false;\n // A parked pointer or keyboard focus survives an admitted same-seat\n // frame, so separate key presses can keep acting on the same control.\n hover = nextHover;\n focused = nextFocused;\n domFocused = nextDomFocused;\n if (changedLifetime) hoverPoint = null;\n set({ activeTarget: hover ?? focused, inspect: null });\n }\n // New frames, seats and sources cancel the semantic drag; end the press with it.\n if (press?.dragging && !game.drag?.active) press.recognizer.cancel();\n const drag = store.get().drag;\n if (\n drag?.settling &&\n (game.request === null || changedSnapshot || changedLifetime)\n )\n set({ drag: null });\n });\n\n function hitArea(at: Point): string | null {\n for (const element of document.elementsFromPoint(at.x, at.y)) {\n if (element.closest(\"[data-drag-overlay]\")) continue;\n const area = element.closest(\"[data-drop-area]\");\n if (area) return area.getAttribute(\"data-drop-area\");\n }\n return null;\n }\n function retarget(at: Point): Point {\n if (!press?.dragging) return at;\n let area = hitArea(at);\n const read = area === null ? undefined : areas.get(area);\n let target = read ? resolveDropArea(game.drag, read(at)) : null;\n let point = at;\n // Direct hits win; outside a target retain its edge before looking for a new one.\n if (!target) {\n const candidates = [...areas].sort(([left], [right]) =>\n left === press?.area ? -1 : right === press?.area ? 1 : 0,\n );\n let distance = Infinity;\n for (const [id, binding] of candidates) {\n const resolved = resolveDropArea(game.drag, binding(at));\n if (\n !resolved ||\n !game.drag\n ?.getDropTargets()\n .some((item) => sameDropTarget(item, resolved))\n )\n continue;\n const element = document.querySelector(\n `[data-drop-area=\"${CSS.escape(id)}\"]`,\n );\n if (!(element instanceof HTMLElement)) continue;\n const snapped = magneticDropPoint(\n at,\n element.getBoundingClientRect(),\n id === press.area,\n press.pointerType === \"touch\",\n );\n if (!snapped) continue;\n const nextDistance = Math.hypot(at.x - snapped.x, at.y - snapped.y);\n if (nextDistance >= distance) continue;\n area = id;\n target = resolved;\n point = snapped;\n distance = nextDistance;\n if (id === press.area) break;\n }\n }\n if (area !== press.area || !sameDropTarget(target, press.target)) {\n press.area = area;\n press.target = target;\n game.drag?.setDropTarget(target);\n const drag = store.get().drag;\n if (drag) set({ drag: { ...drag, area, target } });\n }\n return point;\n }\n // Keyboard clicks (detail 0) and clicks from a new press are never swallowed.\n function swallow(event: globalThis.MouseEvent) {\n if (!swallowing || event.detail === 0) return;\n swallowing = false;\n event.stopPropagation();\n event.preventDefault();\n }\n function newPress() {\n swallowing = false;\n }\n /** A non-tap stays suppressed until its click or a new press, even after cancellation. */\n function swallowNextClick() {\n swallowing = true;\n if (guardingClicks) return;\n guardingClicks = true;\n addEventListener(\"click\", swallow, true);\n addEventListener(\"pointerdown\", newPress, true);\n }\n function clearHover() {\n hover = null;\n }\n function inspectWithAlt() {\n const target = hover ?? focused;\n const cardId = target?.kind === \"card\" ? target.value : null;\n const pending = store.get().drag;\n set({\n activeTarget: target,\n inspect:\n alt &&\n cardId &&\n !press &&\n !(pending?.settling && pending.cardIds.includes(cardId))\n ? { cardId, via: \"hover\" }\n : null,\n });\n }\n function targetOf(element: Element | null): RuntimeShortcutTarget | null {\n const hit = element?.closest(\"[data-card-gesture], [data-shortcut-target]\");\n const control =\n hit?.getAttribute(\"data-gesture-session\") === id ? hit : null;\n const targetId = control?.getAttribute(\"data-shortcut-target\");\n const cardId = control?.getAttribute(\"data-card-gesture\");\n return targetId\n ? (targets.get(targetId)?.() ?? null)\n : cardId\n ? { kind: \"card\", value: cardId }\n : null;\n }\n function hoverAt(at: Point) {\n hoverPoint = at;\n const wasFocused = focused !== null;\n focused = null;\n const next = targetOf(document.elementFromPoint(at.x, at.y));\n if (sameTarget(hover, next) && !wasFocused) return;\n hover = next;\n inspectWithAlt();\n }\n // CSS transforms generate enter/leave events under a parked mouse. Only\n // physical movement changes its target; down uses the actual pressed control.\n const browse = (event: globalThis.PointerEvent) => {\n if (event.pointerType !== \"mouse\" || press) return;\n if (hoverPoint?.x === event.clientX && hoverPoint.y === event.clientY)\n return;\n alt = event.altKey;\n hoverAt({ x: event.clientX, y: event.clientY });\n };\n const key = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n press?.recognizer.cancel();\n alt = false;\n set({ inspect: null });\n } else if (event.key === \"Alt\") {\n alt = event.type === \"keydown\";\n inspectWithAlt();\n }\n };\n const loseFocus = () => {\n alt = false;\n clearHover();\n hoverPoint = null;\n focused = null;\n domFocused = null;\n set({ activeTarget: null, inspect: null });\n };\n addEventListener(\"keydown\", key);\n addEventListener(\"keyup\", key);\n addEventListener(\"blur\", loseFocus);\n const leaveWindow = (event: globalThis.PointerEvent) => {\n if (event.pointerType !== \"mouse\" || event.relatedTarget !== null) return;\n clearHover();\n hoverPoint = null;\n focused = null;\n alt = false;\n inspectWithAlt();\n };\n addEventListener(\"pointermove\", browse);\n addEventListener(\"pointerout\", leaveWindow);\n function release() {\n press?.detach();\n press = null;\n set({});\n }\n\n function start(\n event: globalThis.PointerEvent,\n cardId: string,\n element: Element,\n options: false | RuntimeTargetOptions,\n ) {\n if (disposed || press || event.button !== 0) return;\n const pending = store.get().drag;\n if (pending?.settling && pending.cardIds.includes(cardId)) return;\n // The card a press acts on; a sliding finger moves it, or leaves the row.\n let card: {\n cardId: string;\n element: Element;\n options: false | RuntimeTargetOptions;\n } | null = { cardId, element, options };\n const row =\n event.pointerType === \"mouse\" ? null : element.closest(\"[data-card-row]\");\n const cardAt = rows.get(row?.getAttribute(\"data-card-row\") ?? \"\");\n const scrubbing = cardAt !== undefined;\n const activate = (next: string | null) => {\n if ((hover?.kind === \"card\" ? hover.value : null) === next) return;\n hover = next === null ? null : { kind: \"card\", value: next };\n inspectWithAlt();\n };\n // Resting places, not the raised face's, keep every card a strip's travel apart.\n function scrubTo(at: Point) {\n const next = cardAt!(at);\n const control =\n next === null\n ? null\n : row!.querySelector(`[data-card-gesture=\"${CSS.escape(next)}\"]`);\n const routes = controls.get(\n control?.getAttribute(\"data-card-control\") ?? \"\",\n );\n card =\n next === null || !control || !routes\n ? null\n : { cardId: next, element: control, options: routes() };\n activate(card?.cardId ?? null);\n }\n const recognizer = createGestureRecognizer(\n event,\n {\n // A hold comes before any movement, so the pressed card is still chosen.\n hold() {\n set({ inspect: { cardId, via: \"hold\" } });\n },\n dragStart(origin) {\n if (!card) return false;\n const { cardId, element, options } = card;\n if (options === false || !game.drag?.begin(cardId, options))\n return false;\n const box = element.getBoundingClientRect();\n clearHover();\n focused = null;\n press!.dragging = true;\n set({\n drag: {\n cardIds: game.drag?.active?.cardIds ?? [cardId],\n cardId,\n grab: { x: origin.x - box.left, y: origin.y - box.top },\n size: { width: box.width, height: box.height },\n settling: false,\n area: null,\n target: null,\n landing: null,\n },\n inspect: null,\n activeTarget: null,\n });\n return true;\n },\n dragMove(at) {\n pointer = retarget(at);\n for (const follow of followers) follow(pointer);\n },\n browse: scrubTo,\n end(kind, at) {\n const dragging = press!.dragging;\n const pointerType = press!.pointerType;\n // A finger lifted from a scrub chooses the card under it, as a tap would.\n const chosen = scrubbing && kind === \"browse\" ? card?.element : null;\n if (dragging) retarget(at);\n release();\n // A finger leaves no hover behind.\n if (scrubbing) activate(null);\n // Clicked before the guard below, so the choice is never swallowed.\n if (chosen instanceof HTMLElement) chosen.click();\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (!dragging) {\n // A rejected drag or inspection-only mouse press may browse to a\n // different face. Its final physical point becomes the canonical target.\n if (kind === \"browse\" && pointerType === \"mouse\") hoverAt(at);\n return;\n }\n const before = game.request;\n const drag = store.get().drag;\n const areaPresentation = drag?.area\n ? presentations.get(drag.area)?.()\n : undefined;\n const position =\n drag?.target?.kind === \"position\" ? drag.target.value : null;\n const zone = position ?? areaPresentation?.zone;\n // Hand insertion areas carry a canonical position; inherit the\n // enclosing zone's disclosure policy when they have no metadata.\n const presentation = zone\n ? [\n areaPresentation,\n ...Array.from(presentations.values(), (read) => read()),\n ].find(\n (candidate) =>\n candidate?.zone.zoneId === zone.zoneId &&\n candidate.zone.hostId === zone.hostId,\n )\n : undefined;\n const destination = zone && game.zones.find(zone.zoneId, zone.hostId);\n const cards =\n drag?.cardIds.flatMap((id) => {\n const card = game.cards.find(id);\n return card ? [card] : [];\n }) ?? [];\n const landing =\n destination && zone && cards.length\n ? Object.freeze({\n zoneId: zone.zoneId,\n hostId: zone.hostId,\n index:\n position?.index ??\n presentation?.index ??\n destination.getCards().length,\n concealed: presentation\n ? presentation.visibility === \"hidden\" ||\n (presentation.visibility === \"ownerOnly\" &&\n zone.hostId !== game.me?.id)\n : cards.some(\n (card) =>\n card.zone !== zone.zoneId ||\n card.hostId !== zone.hostId ||\n card.hidden,\n ),\n cards: Object.freeze(cards),\n snapshot: game.snapshot,\n })\n : null;\n game.drag?.drop();\n // A submitted move keeps its overlay until the authoritative frame.\n if (drag && game.request !== null && game.request !== before)\n set({ drag: { ...drag, settling: true, landing } });\n else set({ drag: null });\n },\n cancel(kind) {\n const dragging = press!.dragging;\n release();\n if (scrubbing) activate(null);\n // Cancellation does not turn a non-tap into a selection on release.\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (dragging) {\n game.drag?.cancel();\n set({ drag: null });\n }\n },\n },\n { scrub: scrubbing },\n );\n const move = (next: globalThis.PointerEvent) => recognizer.move(next);\n const up = (next: globalThis.PointerEvent) => recognizer.up(next);\n const cancel = (next: globalThis.PointerEvent) => recognizer.cancel(next);\n const blur = () => recognizer.cancel();\n addEventListener(\"pointermove\", move);\n addEventListener(\"pointerup\", up);\n addEventListener(\"pointercancel\", cancel);\n addEventListener(\"blur\", blur);\n if (event.pointerType === \"mouse\") {\n // A mouse keeps reporting outside the card; touch is captured implicitly.\n try {\n element.setPointerCapture(event.pointerId);\n } catch {\n // The pointer may already be gone.\n }\n }\n press = {\n recognizer,\n pointerType: event.pointerType,\n dragging: false,\n area: null,\n target: null,\n detach() {\n removeEventListener(\"pointermove\", move);\n removeEventListener(\"pointerup\", up);\n removeEventListener(\"pointercancel\", cancel);\n removeEventListener(\"blur\", blur);\n },\n };\n set({});\n }\n\n function cardProps(\n cardId: string,\n control: string,\n options: false | RuntimeTargetOptions,\n flags: { dragging: boolean; inspecting: \"hold\" | \"hover\" | null },\n ): CardGestureProps {\n return {\n onPointerDown(event) {\n if (event.pointerType === \"mouse\") {\n hover = { kind: \"card\", value: cardId };\n alt = event.altKey;\n inspectWithAlt();\n }\n start(event.nativeEvent, cardId, event.currentTarget, options);\n },\n onFocus(event) {\n focused = event.currentTarget.matches(\":focus-visible\")\n ? { kind: \"card\", value: cardId }\n : null;\n domFocused = { kind: \"card\", value: cardId };\n if (focused) hover = null;\n inspectWithAlt();\n },\n onBlur() {\n if (focused?.kind === \"card\" && focused.value === cardId)\n focused = null;\n if (domFocused?.kind === \"card\" && domFocused.value === cardId)\n domFocused = null;\n inspectWithAlt();\n },\n onContextMenu(event) {\n // A long press must inspect the card, not open the browser's menu.\n if ((press && press.pointerType !== \"mouse\") || swallowing)\n event.preventDefault();\n },\n onDragStart: (event) => event.preventDefault(),\n style: options === false ? INSPECTION_STYLE : CARD_STYLE,\n \"data-dragging\": flags.dragging || undefined,\n \"data-inspecting\": flags.inspecting ?? undefined,\n \"data-card-gesture\": cardId,\n \"data-card-control\": control,\n \"data-gesture-session\": id,\n };\n }\n\n /** Positions the dragged card's overlay without rendering on each move. */\n function overlayRef(element: HTMLElement | null) {\n const drag = store.get().drag;\n if (!element || !drag) return;\n element.setAttribute(\"data-drag-overlay\", \"\");\n Object.assign(element.style, {\n position: \"fixed\",\n margin: \"0\",\n pointerEvents: \"none\",\n width: px(drag.size.width),\n height: px(drag.size.height),\n });\n const follow = (at: Point) => {\n element.style.left = px(at.x - drag.grab.x);\n element.style.top = px(at.y - drag.grab.y);\n };\n follow(pointer);\n followers.add(follow);\n return () => {\n followers.delete(follow);\n };\n }\n\n return {\n id,\n store,\n cardProps,\n getActiveCardId() {\n const target = store.get().activeTarget;\n return target?.kind === \"card\" ? target.value : null;\n },\n getActiveTarget: () => store.get().activeTarget,\n getShortcutActivity: () => ({\n // Removal can change DOM focus without emitting blur. Admit the current mounted control.\n focusedTarget: sameTarget(domFocused, targetOf(document.activeElement))\n ? domFocused\n : null,\n pointerActive: store.get().pointerActive,\n }),\n registerTarget(targetId: string, read: () => RuntimeShortcutTarget) {\n const target = read();\n targets.set(targetId, read);\n return () => {\n targets.delete(targetId);\n if (sameTarget(hover, target)) hover = null;\n if (sameTarget(focused, target)) focused = null;\n if (sameTarget(domFocused, target)) domFocused = null;\n inspectWithAlt();\n };\n },\n targetProps(targetId: string) {\n return {\n \"data-shortcut-target\": targetId,\n \"data-gesture-session\": id,\n onPointerDown(event: PointerEvent<Element>) {\n if (event.pointerType !== \"mouse\") return;\n hover = targets.get(targetId)?.() ?? null;\n alt = event.altKey;\n inspectWithAlt();\n },\n onFocus(event: FocusEvent<Element>) {\n focused = event.currentTarget.matches(\":focus-visible\")\n ? (targets.get(targetId)?.() ?? null)\n : null;\n domFocused = targets.get(targetId)?.() ?? null;\n if (focused) hover = null;\n inspectWithAlt();\n },\n onBlur() {\n const target = targets.get(targetId)?.() ?? null;\n if (sameTarget(focused, target)) focused = null;\n if (sameTarget(domFocused, target)) domFocused = null;\n inspectWithAlt();\n },\n };\n },\n overlayRef,\n /** `read` returns the area's current binding; targets resolve when hit. */\n registerArea(\n area: string,\n read: (point: Point) => DropAreaValue,\n presentation: () => RuntimeDropPresentation | undefined,\n ) {\n areas.set(area, read);\n presentations.set(area, presentation);\n return () => {\n areas.delete(area);\n presentations.delete(area);\n };\n },\n /** `read` returns a mounted card control's current drag routes. */\n registerControl(control: string, read: () => false | RuntimeTargetOptions) {\n controls.set(control, read);\n return () => {\n controls.delete(control);\n };\n },\n registerRow(row: string, cardAt: CardRowLookup) {\n rows.set(row, cardAt);\n return () => {\n rows.delete(row);\n };\n },\n rowProps(row: string) {\n return { \"data-card-row\": row, style: ROW_STYLE };\n },\n dispose() {\n disposed = true;\n press?.recognizer.cancel();\n clearHover();\n removeEventListener(\"keydown\", key);\n removeEventListener(\"keyup\", key);\n removeEventListener(\"blur\", loseFocus);\n removeEventListener(\"pointermove\", browse);\n removeEventListener(\"pointerout\", leaveWindow);\n unsubscribe();\n followers.clear();\n targets.clear();\n areas.clear();\n presentations.clear();\n rows.clear();\n controls.clear();\n if (!guardingClicks) return;\n removeEventListener(\"click\", swallow, true);\n removeEventListener(\"pointerdown\", newPress, true);\n },\n };\n}\n\nexport const GestureContext = createContext<GestureSession | null>(null);\n\nexport function useGestureSession(): GestureSession {\n const session = useContext(GestureContext);\n if (!session) throw new Error(\"Gesture hooks require their GameProvider.\");\n return session;\n}\n\nexport function useGestureState<Value>(\n session: GestureSession,\n select: (state: GestureState) => Value,\n): Value {\n return useSelector(session.store, select);\n}\n","import { useEffect, useRef, useState, type PointerEvent } from \"react\";\n\nexport interface MarqueeBounds {\n readonly left: number;\n readonly top: number;\n readonly width: number;\n readonly height: number;\n}\n\n/** An opt-in background gesture. Bounds use viewport coordinates for an authored fixed overlay. */\nexport function useMarqueeSelection<Id extends string>(options: {\n readonly enabled: boolean;\n readonly getCards: () => readonly {\n readonly id: Id;\n readonly element: Element;\n }[];\n readonly onSelect: (ids: readonly Id[], additive: boolean) => void;\n}) {\n const latest = useRef(options);\n latest.current = options;\n const [bounds, setBounds] = useState<MarqueeBounds | null>(null);\n const cleanup = useRef<(() => void) | null>(null);\n useEffect(() => () => cleanup.current?.(), []);\n useEffect(() => {\n if (!options.enabled) {\n cleanup.current?.();\n setBounds(null);\n }\n }, [options.enabled]);\n return {\n bounds,\n props: {\n onPointerDown(event: PointerEvent<HTMLElement>) {\n if (\n !latest.current.enabled ||\n event.button !== 0 ||\n event.pointerType === \"touch\" ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n (event.target as Element).closest(\n \"button, input, select, textarea, a, [contenteditable], [data-card-gesture]\",\n )\n )\n return;\n event.preventDefault();\n cleanup.current?.();\n const x = event.clientX,\n y = event.clientY,\n pointerId = event.pointerId;\n const area = event.currentTarget;\n const additive = event.shiftKey;\n const doc = event.currentTarget.ownerDocument;\n let rectangle: MarqueeBounds | null = null;\n function move(next: globalThis.PointerEvent) {\n if (next.pointerId !== pointerId) return;\n if (!rectangle && Math.hypot(next.clientX - x, next.clientY - y) < 8)\n return;\n const box = area.getBoundingClientRect();\n const right = Math.min(box.right, Math.max(x, next.clientX));\n const bottom = Math.min(box.bottom, Math.max(y, next.clientY));\n const left = Math.max(box.left, Math.min(x, next.clientX));\n const top = Math.max(box.top, Math.min(y, next.clientY));\n rectangle = { left, top, width: right - left, height: bottom - top };\n setBounds(rectangle);\n next.preventDefault();\n }\n function stop() {\n doc.removeEventListener(\"pointermove\", move);\n doc.removeEventListener(\"pointerup\", up);\n doc.removeEventListener(\"pointercancel\", cancel);\n doc.removeEventListener(\"keydown\", key);\n doc.defaultView?.removeEventListener(\"blur\", cancel);\n cleanup.current = null;\n }\n function cancel() {\n stop();\n setBounds(null);\n }\n function key(next: KeyboardEvent) {\n if (next.key === \"Escape\") {\n next.preventDefault();\n cancel();\n }\n }\n function up(next: globalThis.PointerEvent) {\n if (next.pointerId !== pointerId) return;\n const ids = rectangle\n ? latest.current\n .getCards()\n .filter(({ element }) => {\n const box = element.getBoundingClientRect();\n const region = rectangle!;\n return (\n box.right > region.left &&\n box.left < region.left + region.width &&\n box.bottom > region.top &&\n box.top < region.top + region.height\n );\n })\n .map((card) => card.id)\n : [];\n stop();\n setBounds(null);\n latest.current.onSelect(ids, additive);\n }\n cleanup.current = stop;\n doc.addEventListener(\"pointermove\", move, { passive: false });\n doc.addEventListener(\"pointerup\", up);\n doc.addEventListener(\"pointercancel\", cancel);\n doc.addEventListener(\"keydown\", key);\n doc.defaultView?.addEventListener(\"blur\", cancel);\n },\n },\n };\n}\n"],"mappings":"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","names":["createStore","target","id","cardId","element","options","card","createContext","useContext","useLayoutEffect","useRef","useSelector","createContext","useRef","useLayoutEffect","owned","useContext","useSelector","card","createStore","useRef","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/create-game-hook.tsx","../src/react/shortcuts.ts","../src/react/gesture.tsx","../src/headless/drop-snap.ts","../src/react/marquee.ts"],"sourcesContent":["import { createStore } from \"@tanstack/store\";\nimport { inputValueKey } from \"../shared/input-domain.js\";\nimport { useShortcutsAdapter } from \"./shortcuts.js\";\nimport type {\n ShortcutOptions,\n ShortcutTarget,\n ShortcutHint,\n ShortcutActivity,\n ShortcutsController,\n RuntimeShortcutTarget,\n} from \"../headless/features/shortcuts.js\";\nimport {\n createGestureSession,\n resolveDropArea,\n sameDropTarget,\n GestureContext,\n useGestureSession,\n useGestureState,\n type CardGestureProps,\n type DragFit,\n type DropAreaInput,\n type GestureGame,\n type GestureSession,\n} from \"./gesture.js\";\nimport type { SeatCardId, IdOf, ZoneHostId, Card } from \"../headless/model.js\";\nimport type { ZoneVisibility } from \"../shared/domain/contracts.js\";\nimport type {\n DropAreaBinding,\n DropTarget,\n RuntimeTargetOptions,\n TargetOptions,\n} from \"../headless/targets.js\";\nimport {\n createContext,\n useContext,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n useMemo,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport { createGameInstance } from \"../headless/instance.js\";\nimport type {\n CoreInstance,\n FeatureContext,\n Features,\n GameInstance,\n GameSnapshot,\n GameSource,\n InstanceOptions,\n} from \"../headless/model.js\";\n\nexport interface SelectionOptions<Value> {\n readonly compare?: (previous: Value, next: Value) => boolean;\n}\n\n/** Inspection stays enabled when this control does not support dragging. */\nexport interface CardGestureOptions<Game> {\n readonly drag: false | TargetOptions<Game>;\n}\n\n/** An area that runs this interaction with whichever card is dropped on it. */\nexport type { DropAreaBinding } from \"../headless/targets.js\";\n\nexport interface CardGesture {\n /** Spread on the card's own control, after the card's selection props. */\n readonly props: CardGestureProps;\n readonly canDrag: boolean;\n readonly isDragging: boolean;\n /** Submitted and waiting for the authoritative frame; cannot start another gesture. */\n readonly isPending: boolean;\n readonly isActive: boolean;\n /** Held on touch, or rested on with a mouse. */\n readonly inspecting: \"hold\" | \"hover\" | null;\n}\n\nexport interface DropAreaOptions<Game> {\n readonly zone: import(\"../headless/features/shortcuts.js\").ShortcutZoneTarget<Game> extends infer Target\n ? Target extends { readonly kind: \"zone\" }\n ? Omit<Target, \"kind\">\n : never\n : never;\n readonly visibility: ZoneVisibility;\n /** Defaults to the end of the zone; piles can land on their top at index 0. */\n readonly index?: number;\n}\n\nexport interface ZonePresentation<Game, Enabled extends Features> {\n readonly cards: readonly Card<Game, Enabled>[];\n readonly count: number;\n readonly arrivingIds: readonly SeatCardId<Game>[];\n}\n\nexport interface CardPresentation<Game, Enabled extends Features> {\n readonly card: Card<Game, Enabled> | undefined;\n readonly isPending: boolean;\n readonly hidden: boolean;\n}\n\nexport interface CardRow {\n /** Spread on the element holding the row's cards; touching them never scrolls. */\n readonly props: {\n readonly \"data-card-row\": string;\n readonly style: CSSProperties;\n };\n}\n\nexport interface DropArea {\n readonly props: {\n readonly \"data-drop-area\": string;\n readonly \"data-drop-target\"?: \"true\";\n readonly \"data-drop-over\"?: true;\n };\n readonly isEligible: boolean;\n readonly isOver: boolean;\n}\n\nexport interface DragOverlay<G> {\n readonly cardId: SeatCardId<G>;\n readonly cardIds: readonly SeatCardId<G>[];\n /** Dropped and submitted; the authoritative frame has not arrived yet. */\n readonly settling: boolean;\n /** Where the card lands if dropped now; kept while it settles. */\n readonly target: DropTarget<G> | null;\n /** A registered zone landing; absent for interactions with no zone destination. */\n readonly landing:\n | import(\"../shared/position-target.js\").PositionTarget<\n IdOf<G, \"zoneId\">,\n ZoneHostId<G>\n >\n | null;\n /**\n * Draw the copy at `fit.scale` once it is known, in place of its lifted\n * size, and as its back while `fit.concealed`. The ref already moves it\n * into a pile's slot while `fit.snapped`.\n */\n readonly fit: DragFit;\n /** Attach to a fixed-position copy of the card; it follows the pointer. */\n readonly ref: (element: HTMLElement | null) => (() => void) | undefined;\n}\n\n/** Bind erased game types and features; each provider owns its source lifetime. */\nexport function createGameHook<Game, Source extends GameSource = GameSource>() {\n return function <const Enabled extends Features = Record<never, never>>(\n defaults: Omit<InstanceOptions<Game, Source>, \"source\"> & {\n features?: (\n core: CoreInstance<Game>,\n context: FeatureContext<Game>,\n ) => Enabled;\n },\n ) {\n type Instance = GameInstance<Game, Enabled, Source>;\n type Snapshot = GameSnapshot<Game, Enabled>;\n type ProviderProps = Partial<\n Omit<InstanceOptions<Game, Source>, \"source\">\n > & {\n source: Source;\n children?: ReactNode;\n };\n const Context = createContext<Instance | null>(null);\n\n /** Owns the source. Do not share it between independently mounted providers. */\n function GameProvider({ children, ...overrides }: ProviderProps) {\n const [owned, setOwned] = useState<{\n instance: Instance;\n session: GestureSession;\n } | null>(null);\n const lifetime = useRef<{\n instance: Instance;\n session: GestureSession;\n generation: number;\n } | null>(null);\n const options = {\n ...defaults,\n ...overrides,\n };\n useLayoutEffect(() => {\n let current = lifetime.current;\n if (!current) {\n const instance = createGameInstance<Game>()(options);\n current = {\n instance,\n // One bound game crosses into the framework adapter's erased runtime.\n session: createGestureSession(instance as GestureGame),\n generation: 0,\n };\n lifetime.current = current;\n setOwned({ instance, session: current.session });\n }\n const owned = current;\n ++owned.generation;\n return () => {\n const generation = ++owned.generation;\n queueMicrotask(() => {\n if (owned.generation !== generation) return;\n owned.session.dispose();\n owned.instance.dispose();\n if (lifetime.current === owned) lifetime.current = null;\n });\n };\n // Construction belongs to this committed provider lifetime. Current\n // options are installed separately without recreating features.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- Construct once per committed provider lifetime; the next effect updates options.\n }, []);\n useLayoutEffect(() => {\n lifetime.current?.instance.setOptions(options);\n });\n return owned ? (\n <Context.Provider value={owned.instance}>\n <GestureContext.Provider value={owned.session}>\n {children}\n </GestureContext.Provider>\n </Context.Provider>\n ) : null;\n }\n\n function useInstance(): Instance {\n const instance = useContext(Context);\n if (!instance) throw new Error(\"useGame requires its GameProvider.\");\n return instance;\n }\n\n function useGame(): Instance;\n function useGame<Value>(\n selector: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Value;\n function useGame<Value>(\n selector?: (snapshot: Snapshot) => Value,\n options?: SelectionOptions<Value>,\n ): Instance | Value {\n const instance = useInstance();\n const selected = useSelector(\n instance.store,\n (snapshot): { value: Value } | { snapshot: Snapshot } =>\n selector ? { value: selector(snapshot) } : { snapshot },\n {\n compare: (previous, next) =>\n \"value\" in previous && \"value\" in next\n ? (options?.compare ?? Object.is)(previous.value, next.value)\n : \"snapshot\" in previous &&\n \"snapshot\" in next &&\n Object.is(previous.snapshot, next.snapshot),\n },\n );\n return \"value\" in selected ? selected.value : instance;\n }\n\n function Subscribe<Value>({\n selector,\n compare,\n children,\n }: {\n selector: (snapshot: Snapshot) => Value;\n compare?: SelectionOptions<Value>[\"compare\"];\n children: (value: Value) => ReactNode;\n }) {\n return children(useGame(selector, { compare }));\n }\n\n // Game-binding boundary: typed ids and routes cross into the erased session.\n const dragOf = (snapshot: Snapshot) =>\n (snapshot as Pick<GestureGame, \"drag\">).drag;\n\n /** Tap, hold, drag and browse on one card; hover intent with a mouse. */\n function useCardGesture(\n cardId: SeatCardId<Game>,\n options: CardGestureOptions<Game>,\n ): CardGesture {\n const session = useGestureSession();\n const control = `${session.id}${useId()}`;\n const routes = options.drag as false | RuntimeTargetOptions;\n const latestRoutes = useRef(routes);\n useLayoutEffect(() => {\n latestRoutes.current = routes;\n });\n useLayoutEffect(\n () => session.registerControl(control, () => latestRoutes.current),\n [session, control],\n );\n const canDrag = useGame(\n (snapshot) =>\n routes !== false &&\n (dragOf(snapshot)?.getCanDrag(cardId, routes) ?? false),\n );\n const dragging = useGestureState(\n session,\n (state) => state.drag?.cardIds.includes(cardId) ?? false,\n );\n const pending = useGestureState(\n session,\n (state) =>\n !!state.drag?.settling && state.drag.cardIds.includes(cardId),\n );\n const inspecting = useGestureState(session, (state) =>\n state.inspect?.cardId === cardId ? state.inspect.via : null,\n );\n const isActive = useGestureState(\n session,\n (state) =>\n state.activeTarget?.kind === \"card\" &&\n state.activeTarget.value === cardId,\n );\n return {\n props: session.cardProps(cardId, control, routes, {\n dragging,\n inspecting,\n }),\n canDrag,\n isDragging: dragging,\n isPending: pending,\n isActive,\n inspecting,\n };\n }\n\n /**\n * Marks an element where a dragged card can land: a board destination,\n * or an area that runs an interaction with the dropped card. A function\n * is read at each dragged point, as for the insertion point under the\n * pointer; that area is eligible and over while the card is over it.\n */\n function useDropArea(\n binding:\n | DropTarget<Game>\n | DropAreaBinding<Game>\n | null\n | ((point: {\n readonly x: number;\n readonly y: number;\n }) => DropTarget<Game> | DropAreaBinding<Game> | null),\n options?: DropAreaOptions<Game>,\n ): DropArea {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const erased = binding as DropAreaInput;\n const fixed = typeof erased === \"function\" ? null : erased;\n const target = useGame(\n (snapshot) => resolveDropArea(dragOf(snapshot), fixed),\n { compare: sameDropTarget },\n );\n const isOver = useGame((snapshot) => {\n const active = dragOf(snapshot)?.active?.target;\n return !!target && sameDropTarget(active ?? null, target);\n });\n const following = useGestureState(\n session,\n (state) =>\n typeof erased === \"function\" &&\n state.drag?.area === id &&\n state.drag.target !== null,\n );\n const latest = useRef(erased);\n const latestPresentation = useRef(options);\n useLayoutEffect(() => {\n latest.current = erased;\n latestPresentation.current = options;\n });\n useLayoutEffect(\n () =>\n session.registerArea(\n id,\n (point) => {\n const current = latest.current;\n return typeof current === \"function\" ? current(point) : current;\n },\n () => latestPresentation.current,\n ),\n [session, id],\n );\n return {\n props: {\n \"data-drop-area\": id,\n \"data-drop-target\": target || following ? \"true\" : undefined,\n \"data-drop-over\": isOver || following || undefined,\n },\n isEligible: target !== null || following,\n isOver: isOver || following,\n };\n }\n\n /** Presentation-only zone contents. The source snapshot and domain models stay authoritative. */\n function useZonePresentation<Z extends IdOf<Game, \"zoneId\">>(\n zoneId: Z,\n hostId: ZoneHostId<Game, Z>,\n options?: { readonly order: readonly SeatCardId<Game>[] },\n ): ZonePresentation<Game, Enabled> {\n const game = useGame();\n const session = useGestureSession();\n const landing = useGestureState(session, (state) =>\n state.drag?.settling ? state.drag.landing : null,\n );\n const zone = game.zones.find(zoneId, hostId);\n const actual = useMemo(\n () => (zone?.getCards() ?? []) as readonly Card<Game, Enabled>[],\n [zone],\n );\n const active = landing?.snapshot === game.snapshot ? landing : null;\n const incoming = active?.zoneId === zoneId && active.hostId === hostId;\n const outgoing =\n active?.cards.filter(\n (card) => card.zone === zoneId && card.hostId === hostId,\n ) ?? [];\n const cards = useMemo(() => {\n const ordered = options\n ? options.order.flatMap((id) => {\n const card = actual.find((card) => card.id === id);\n return card ? [card] : [];\n })\n : actual;\n if (!active) return ordered;\n const moving = new Set(active.cards.map((card) => card.id));\n const remaining = ordered.filter((card) => !moving.has(card.id));\n if (incoming) {\n const before = ordered\n .slice(0, active.index)\n .filter((card) => moving.has(card.id)).length;\n const index = Math.max(\n 0,\n Math.min(remaining.length, active.index - before),\n );\n // This hook belongs to the same bound game as the captured drag.\n remaining.splice(\n index,\n 0,\n ...(active.cards as readonly Card<Game, Enabled>[]),\n );\n }\n return remaining;\n }, [actual, active, incoming, options]);\n const source = game.getOptions().source;\n const me = game.me?.id;\n const count =\n (zone?.count ?? 0) -\n outgoing.length +\n (incoming ? active.cards.length : 0);\n const previous = useRef({\n source,\n me,\n ids: new Set(actual.map((card) => card.id)),\n incoming: 0,\n count: zone?.count ?? 0,\n });\n const newlyArriving =\n previous.current.source === source && previous.current.me === me\n ? cards\n .filter(\n (card) =>\n !previous.current.ids.has(card.id) &&\n !active?.cards.some((pending) => pending.id === card.id),\n )\n .map((card) => card.id as SeatCardId<Game>)\n : [];\n // A concealed source can reveal a different ID on acceptance. Suppress\n // a second flight when the already-filled destination is replaced by\n // exactly that many new cards; never invent a persistent hidden identity.\n const arrivingIds =\n previous.current.incoming > 0 &&\n newlyArriving.length === previous.current.incoming &&\n count === previous.current.count\n ? []\n : newlyArriving;\n useLayoutEffect(() => {\n // Include authority as well as the display list so rejection cannot replay an old arrival.\n previous.current = {\n source,\n me,\n ids: new Set([...actual, ...cards].map((card) => card.id)),\n incoming: incoming ? active.cards.length : 0,\n count,\n };\n });\n return {\n cards,\n count,\n arrivingIds,\n };\n }\n\n /** One card's face and pending status, shared by every standard card control. */\n function useCardPresentation(\n cardId: SeatCardId<Game>,\n ): CardPresentation<Game, Enabled> {\n const game = useGame();\n const session = useGestureSession();\n const landing = useGestureState(session, (state) =>\n state.drag?.settling ? state.drag.landing : null,\n );\n const active = landing?.snapshot === game.snapshot ? landing : null;\n const captured = active?.cards.find((card) => card.id === cardId);\n const card =\n game.cards.find(cardId) ??\n (captured as Card<Game, Enabled> | undefined);\n return {\n card,\n isPending: !!captured,\n hidden:\n card?.hidden === true || (!!captured && active?.concealed === true),\n };\n }\n\n const shortcutsOf = (snapshot: Snapshot) =>\n (\n snapshot as Snapshot & {\n readonly shortcuts?: ShortcutsController<Game>;\n }\n ).shortcuts;\n const noShortcutsConfiguration = createStore<ShortcutOptions<Game> | null>(\n null,\n );\n const sameHints = (\n left: readonly ShortcutHint<Game>[],\n right: readonly ShortcutHint<Game>[],\n ) =>\n left.length === right.length &&\n left.every((hint, index) => {\n const next = right[index];\n return (\n hint.label === next.label &&\n hint.kind === next.kind &&\n (hint.kind !== \"interaction\" ||\n (next.kind === \"interaction\" &&\n hint.interaction === next.interaction)) &&\n hint.keys.length === next.keys.length &&\n hint.keys.every((key, at) => key === next.keys[at])\n );\n });\n /** Current eligible hints; configuration and projected domains each notify their own readers. */\n function useShortcutHints(\n target: ShortcutTarget<Game> | null,\n ): readonly ShortcutHint<Game>[] {\n const controller = shortcutsOf(useInstance());\n const session = useGestureSession();\n useSelector(session.store, () => session.getShortcutActivity(), {\n compare: (left, right) =>\n left.focusedTarget === right.focusedTarget &&\n left.pointerActive === right.pointerActive,\n });\n useGame(\n (snapshot) =>\n shortcutsOf(snapshot)?.getHints(\n target,\n session.getShortcutActivity() as ShortcutActivity<Game>,\n ) ?? [],\n {\n compare: sameHints,\n },\n );\n return useSelector(\n controller?.configuration ?? noShortcutsConfiguration,\n () =>\n controller?.getHints(\n target,\n session.getShortcutActivity() as ShortcutActivity<Game>,\n ) ?? [],\n { compare: sameHints },\n );\n }\n\n /** Installs the authored keyboard bindings for this mounted application. */\n function useGameShortcuts(options: ShortcutOptions<Game>): {\n readonly target: ShortcutTarget<Game> | null;\n readonly hints: readonly ShortcutHint<Game>[];\n } {\n const instance = useInstance();\n const session = useGestureSession();\n // Feature-composition boundary: this binding and its installed root feature share Game.\n const controller = shortcutsOf(instance);\n if (!controller)\n throw new Error(\n \"useGameShortcuts requires shortcutsFeature in the game binding.\",\n );\n useShortcutsAdapter(instance, controller, session, options, (result) => {\n if (result instanceof Error) instance.getOptions().onError?.(result);\n else if (result.kind === \"interaction\" && !result.result.accepted)\n instance.getOptions().onError?.(\n new Error(result.result.message ?? result.result.errorCode, {\n cause: result.result,\n }),\n );\n });\n const target = useGestureState(\n session,\n (state) => state.activeTarget,\n ) as ShortcutTarget<Game> | null;\n const hints = useShortcutHints(target);\n return { target, hints };\n }\n\n /** Shares the canonical pointer and keyboard focus with a zone, tile or board control. */\n function useShortcutTarget(target: ShortcutTarget<Game>) {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const latest = useRef<RuntimeShortcutTarget>(target);\n const targetKey = inputValueKey(target);\n useLayoutEffect(() => {\n latest.current = target;\n });\n useLayoutEffect(\n () => session.registerTarget(id, () => latest.current),\n [session, id, targetKey],\n );\n return { props: session.targetProps(id) };\n }\n\n /** The card being dragged, and a ref that keeps its copy under the pointer. */\n function useDragOverlay(): DragOverlay<Game> | null {\n const session = useGestureSession();\n const drag = useGestureState(session, (state) => state.drag);\n return drag\n ? {\n cardId: drag.cardId as SeatCardId<Game>,\n cardIds: drag.cardIds as readonly SeatCardId<Game>[],\n settling: drag.settling,\n // The drag feature resolved this target from this game's routes.\n target: drag.target as DropTarget<Game> | null,\n landing: drag.landing\n ? {\n zoneId: drag.landing.zoneId as IdOf<Game, \"zoneId\">,\n hostId: drag.landing.hostId as ZoneHostId<Game>,\n index: drag.landing.index,\n }\n : null,\n fit: drag.fit,\n ref: session.overlayRef,\n }\n : null;\n }\n\n /**\n * Marks a row of cards that fits without scrolling, such as a hand. A\n * finger pressed on one of its cards slides along the row: `cardAt`\n * names the card whose resting place is under a viewport point, or null\n * off the row. That card becomes active; lifting the finger there clicks\n * it, and pulling up drags it.\n */\n function useCardRow(\n cardAt: (point: {\n readonly x: number;\n readonly y: number;\n }) => SeatCardId<Game> | null,\n ): CardRow {\n const session = useGestureSession();\n const id = `${session.id}${useId()}`;\n const latest = useRef(cardAt);\n useLayoutEffect(() => {\n latest.current = cardAt;\n });\n useLayoutEffect(\n () => session.registerRow(id, (point) => latest.current(point)),\n [session, id],\n );\n return { props: session.rowProps(id) };\n }\n\n /** Presentation focus shared by the fan, inspection and pointer activation. */\n function useActiveCard(): SeatCardId<Game> | null {\n const session = useGestureSession();\n return useGestureState(\n session,\n (state) =>\n (state.activeTarget?.kind === \"card\"\n ? state.activeTarget.value\n : null) as SeatCardId<Game> | null,\n );\n }\n\n return {\n GameProvider,\n useGame,\n Subscribe,\n useCardGesture,\n useCardRow,\n useActiveCard,\n useGameShortcuts,\n useShortcutTarget,\n useShortcutHints,\n useDropArea,\n useDragOverlay,\n useZonePresentation,\n useCardPresentation,\n };\n };\n}\n","import { useLayoutEffect, useRef } from \"react\";\nimport type {\n ShortcutOptions,\n ShortcutTarget,\n ShortcutsController,\n RuntimeShortcutTarget,\n ShortcutActivity,\n ShortcutResult,\n} from \"../headless/features/shortcuts.js\";\nimport type { CoreInstance } from \"../headless/model.js\";\n\n/** Browser adapter input; the gesture session owns the single active target. */\nexport interface ShortcutSession {\n getActiveTarget(): RuntimeShortcutTarget | null;\n getShortcutActivity(): ShortcutActivity<unknown>;\n}\nfunction canHandle(event: KeyboardEvent) {\n const target = event.target;\n return (\n !event.defaultPrevented &&\n !event.repeat &&\n !event.isComposing &&\n !event.altKey &&\n !event.ctrlKey &&\n !event.metaKey &&\n !event.shiftKey &&\n !(\n target instanceof Element &&\n target.closest(\n \"input:not([type='radio']), textarea, select, [contenteditable]:not([contenteditable='false']), [role='textbox']\",\n )\n ) &&\n !Array.from(\n document.querySelectorAll(\n \"[aria-modal='true'], dialog[open], [role='dialog'], [role='menu'], [role='listbox']\",\n ),\n ).some(\n (surface) =>\n !surface.closest(\"[aria-hidden='true']\") &&\n surface.checkVisibility({\n visibilityProperty: true,\n opacityProperty: true,\n }),\n )\n );\n}\n/** Installs only for a committed child beneath the bound GameProvider. */\nexport function useShortcutsAdapter<G>(\n game: CoreInstance<G>,\n controller: ShortcutsController<G>,\n session: ShortcutSession,\n options: ShortcutOptions<G>,\n onResult: (result: ShortcutResult | Error) => void,\n) {\n const latest = useRef({ options, onResult });\n const registration = useRef<ReturnType<\n ShortcutsController<G>[\"register\"]\n > | null>(null);\n useLayoutEffect(() => {\n latest.current = { options, onResult };\n });\n useLayoutEffect(() => {\n let mounted = true;\n const owned = controller.register(latest.current.options);\n registration.current = owned;\n let source = game.getOptions().source;\n let seat = game.snapshot?.me;\n let lifetime = 0;\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const nextSeat = game.snapshot?.me;\n if (source === nextSource && seat === nextSeat) return;\n source = nextSource;\n seat = nextSeat;\n ++lifetime;\n });\n function keydown(event: KeyboardEvent) {\n if (!canHandle(event)) return;\n // Bound game identity boundary; session targets originate from its own controls.\n const started = lifetime;\n const active = () => mounted && lifetime === started;\n const pending = controller.handle(\n event.key,\n session.getActiveTarget() as ShortcutTarget<G> | null,\n session.getShortcutActivity() as ShortcutActivity<G>,\n );\n if (!pending) return;\n event.preventDefault();\n void pending.then(\n (result) => {\n if (active()) latest.current.onResult(result);\n },\n (cause: unknown) => {\n if (active())\n latest.current.onResult(\n cause instanceof Error ? cause : new Error(String(cause)),\n );\n },\n );\n }\n window.addEventListener(\"keydown\", keydown);\n return () => {\n mounted = false;\n unsubscribe();\n window.removeEventListener(\"keydown\", keydown);\n registration.current = null;\n owned.dispose();\n };\n }, [game, controller, session]);\n useLayoutEffect(() => {\n registration.current?.update(options);\n });\n}\n","import type { RuntimeShortcutTarget } from \"../headless/features/shortcuts.js\";\nimport type { CoreInstance, InstanceOptions, Card } from \"../headless/model.js\";\nimport type { ZoneVisibility } from \"../shared/domain/contracts.js\";\nimport { inputValueKey } from \"../shared/input-domain.js\";\nimport { createStore } from \"@tanstack/store\";\nimport { useSelector } from \"@tanstack/react-store\";\nimport {\n createContext,\n useContext,\n type CSSProperties,\n type DragEvent,\n type FocusEvent,\n type MouseEvent,\n type PointerEvent,\n} from \"react\";\nimport {\n createGestureRecognizer,\n type GestureRecognizer,\n} from \"../headless/gesture.js\";\nimport { snapDrop, type Box, type SnapArea } from \"../headless/drop-snap.js\";\nimport { isSameDropTarget } from \"../headless/drop-targets.js\";\nimport type { PositionTarget } from \"../shared/position-target.js\";\nimport type { Point } from \"../headless/features/pointer-session.js\";\nimport type {\n RuntimeDropTarget,\n RuntimeTargetOptions,\n} from \"../headless/targets.js\";\n\n/** The runtime surface of `dragFeature` that a gesture needs. */\nexport interface GestureDrag {\n readonly active: {\n readonly target: RuntimeDropTarget | null;\n readonly cardIds?: readonly string[];\n } | null;\n getCanDrag(cardId: string, options?: RuntimeTargetOptions): boolean;\n getDropTargets(): readonly RuntimeDropTarget[];\n getIsDropTarget(target: RuntimeDropTarget): boolean;\n begin(cardId: string, options?: RuntimeTargetOptions): boolean;\n setDropTarget(target: RuntimeDropTarget | null): void;\n drop(): void;\n cancel(): void;\n}\nexport interface GestureGame extends Pick<\n CoreInstance<unknown>,\n \"snapshot\" | \"subscribe\" | \"cards\" | \"zones\" | \"me\"\n> {\n readonly drag?: GestureDrag;\n readonly request: unknown;\n getOptions(): Pick<InstanceOptions<unknown>, \"source\">;\n}\n\nexport interface GestureState {\n readonly activeTarget: RuntimeShortcutTarget | null;\n readonly focusedTarget: RuntimeShortcutTarget | null;\n readonly pointerActive: boolean;\n readonly drag: {\n readonly cardId: string;\n readonly cardIds: readonly string[];\n /** Pointer offset inside the card where it was picked up. */\n readonly grab: Point;\n readonly size: { readonly width: number; readonly height: number };\n /** The card's layout width, before the transforms it was drawn with when picked up. */\n readonly width: number;\n readonly fit: DragFit;\n /** Dropped and submitted; waiting for the authoritative frame. */\n readonly settling: boolean;\n /** The area under the card and where it would land there, kept while settling. */\n readonly area: string | null;\n readonly target: RuntimeDropTarget | null;\n readonly landing: {\n readonly zoneId: string;\n readonly hostId: string;\n readonly index: number;\n readonly concealed: boolean;\n readonly cards: readonly Card<unknown, Record<never, never>>[];\n readonly snapshot: GestureGame[\"snapshot\"];\n } | null;\n } | null;\n readonly inspect: {\n readonly cardId: string;\n readonly via: \"hold\" | \"hover\";\n } | null;\n}\n\n/** How the dragged card would show where it lands if dropped now. */\nexport interface DragFit {\n /**\n * The width of the card-sized box marked `data-drop-landing` there,\n * relative to the picked-up card's layout width. Null until the card has\n * been over such a box; between areas it keeps the last one's.\n */\n readonly scale: number | null;\n /** Drawn in a pile's slot. */\n readonly snapped: boolean;\n /** The area's zone would conceal the card. */\n readonly concealed: boolean;\n}\nconst UNFIT: DragFit = Object.freeze({\n scale: null,\n snapped: false,\n concealed: false,\n});\n/** How long, in ms, the drawn card takes to make up two thirds of a jump. */\nconst CATCH_UP_MS = 50;\n/** Dragging within this many CSS pixels of a scroller's edge scrolls it, faster nearer the edge. */\nconst SCROLL_EDGE = { fine: 48, coarse: 64 };\n/** Pixels per 60 Hz frame at the very edge. */\nconst SCROLL_SPEED = 16;\nconst VISUALLY_HIDDEN: Partial<CSSStyleDeclaration> = {\n position: \"fixed\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n clipPath: \"inset(50%)\",\n whiteSpace: \"nowrap\",\n};\n\n/** A drop area's element and geometry owners, refreshed when its landing slot changes. */\ninterface LocatedArea {\n readonly element: Element | null;\n readonly clips: readonly Element[];\n readonly slot: HTMLElement | null;\n readonly depth: number;\n}\n/** The card-sized box a dropped card shows in, marked inside the area that owns it. */\nfunction landingIn(area: Element | null): HTMLElement | null {\n for (const element of area?.querySelectorAll(\"[data-drop-landing]\") ?? [])\n if (\n element instanceof HTMLElement &&\n element.closest(\"[data-drop-area]\") === area\n )\n return element;\n return null;\n}\n/** An element's box as far as its scrolling ancestors show it, or null when hidden. */\nfunction visibleBox(element: Element, clips: readonly Element[]): Box | null {\n let { left, top, right, bottom } = element.getBoundingClientRect();\n for (const clip of clips) {\n const box = clip.getBoundingClientRect();\n left = Math.max(left, box.left);\n top = Math.max(top, box.top);\n right = Math.min(right, box.right);\n bottom = Math.min(bottom, box.bottom);\n }\n return right > left && bottom > top\n ? { x: left, y: top, width: right - left, height: bottom - top }\n : null;\n}\n/** How far to scroll `node` this frame for a pointer near its edges. */\nfunction scrollStep(node: Element, at: Point, edge: number, frames: number) {\n const root = node === document.scrollingElement;\n const { overflowX, overflowY } = getComputedStyle(node);\n const box = root\n ? { left: 0, top: 0, right: innerWidth, bottom: innerHeight }\n : node.getBoundingClientRect();\n const speed = (gap: number) =>\n gap < edge ? SCROLL_SPEED * frames * (1 - Math.max(0, gap) / edge) ** 2 : 0;\n const axis = (\n overflow: string,\n position: number,\n room: number,\n before: number,\n after: number,\n ) =>\n (root || overflow === \"auto\" || overflow === \"scroll\") && room > 0\n ? (position < room ? speed(after) : 0) -\n (position > 0 ? speed(before) : 0)\n : 0;\n return {\n x: axis(\n overflowX,\n node.scrollLeft,\n node.scrollWidth - node.clientWidth,\n at.x - box.left,\n box.right - at.x,\n ),\n y: axis(\n overflowY,\n node.scrollTop,\n node.scrollHeight - node.clientHeight,\n at.y - box.top,\n box.bottom - at.y,\n ),\n };\n}\n\n/** A renderer's destination identity and its existing disclosure policy. */\nexport interface RuntimeDropPresentation {\n readonly zone: { readonly zoneId: string; readonly hostId: string };\n readonly visibility: ZoneVisibility;\n readonly index?: number;\n}\n\nexport interface CardGestureProps {\n onPointerDown(event: PointerEvent<Element>): void;\n onFocus(event: FocusEvent<Element>): void;\n onBlur(): void;\n onContextMenu(event: MouseEvent<Element>): void;\n onDragStart(event: DragEvent<Element>): void;\n readonly style: CSSProperties;\n readonly \"data-dragging\"?: true;\n readonly \"data-inspecting\"?: \"hold\" | \"hover\";\n readonly \"data-card-gesture\": string;\n readonly \"data-card-control\": string;\n readonly \"data-gesture-session\": string;\n}\n\nconst CARD_STYLE: CSSProperties = Object.freeze({\n // Sideways movement stays native scrolling; everything else reaches the recognizer.\n touchAction: \"pan-x\",\n userSelect: \"none\",\n WebkitUserSelect: \"none\",\n WebkitTouchCallout: \"none\",\n});\nconst INSPECTION_STYLE: CSSProperties = Object.freeze({\n ...CARD_STYLE,\n // Inspection-only cards should not block their table's native scrolling.\n touchAction: \"manipulation\",\n});\nconst ROW_STYLE: CSSProperties = Object.freeze({\n // A row that fits never scrolls; its cards' sideways movement scrubs instead.\n touchAction: \"none\",\n});\nconst px = (value: number) => `${value}px`;\n\n/** The card whose resting place in a row is under a viewport point, or null off the row. */\nexport type CardRowLookup = (point: Point) => string | null;\n\n/** A resolved destination, the interaction an area runs, or an insertion point it offers. */\nexport type DropAreaValue =\n | RuntimeDropTarget\n | {\n readonly interaction: string;\n readonly input?: string;\n readonly params?: import(\"../headless/targets.js\").RuntimeInteractionDropTarget[\"params\"];\n readonly position?: PositionTarget;\n }\n | null;\n/** A fixed binding, or one read at each dragged point, as for an insertion point under the pointer. */\nexport type DropAreaInput = DropAreaValue | ((point: Point) => DropAreaValue);\n\nexport function resolveDropArea(\n drag: GestureDrag | undefined,\n binding: DropAreaValue,\n): RuntimeDropTarget | null {\n if (!drag || !binding) return null;\n if (\"interactionKey\" in binding)\n return drag.getIsDropTarget(binding) ? binding : null;\n const { position } = binding;\n const matches = drag\n .getDropTargets()\n .filter(\n (target) =>\n target.kind === (position ? \"position\" : \"interaction\") &&\n target.interactionKey === binding.interaction &&\n (!binding.input || target.cardInputKey === binding.input) &&\n (!position ||\n (target.kind === \"position\" &&\n inputValueKey(target.value) === inputValueKey(position))),\n );\n if (position)\n return matches.length === 1 && drag.getIsDropTarget(matches[0])\n ? matches[0]\n : null;\n // Two card inputs on one interaction need an explicit `input`.\n if (matches.length !== 1) return null;\n const target = {\n ...matches[0],\n ...(binding.params === undefined ? {} : { params: binding.params }),\n };\n return drag.getIsDropTarget(target) ? target : null;\n}\n/** Targets are rebuilt with every drag update; compare what they route. */\nexport const sameDropTarget = (\n left: RuntimeDropTarget | null,\n right: RuntimeDropTarget | null,\n) => left === right || (!!left && !!right && isSameDropTarget(left, right));\nlet sessions = 0;\n\nexport type GestureSession = ReturnType<typeof createGestureSession>;\n\n/**\n * One press at a time for a provider: tap, hold, drag or browse, plus mouse\n * hover intent. The session outlives the pressed element, so a hand may move\n * the card into an overlay mid-drag. Drop areas are found with the browser's\n * own hit testing, so transformed and SVG areas need no geometry. A finger on\n * a card in a row slides along it: the row names the card whose resting place\n * is under the finger, which becomes active; lifting there clicks that card,\n * and pulling up drags it.\n */\nexport function createGestureSession(game: GestureGame) {\n const id = `g${++sessions}`;\n const store = createStore<GestureState>({\n activeTarget: null,\n focusedTarget: null,\n pointerActive: false,\n drag: null,\n inspect: null,\n });\n const targets = new Map<string, () => RuntimeShortcutTarget>();\n const sameTarget = (\n left: RuntimeShortcutTarget | null,\n right: RuntimeShortcutTarget | null,\n ) => inputValueKey(left) === inputValueKey(right);\n const areas = new Map<string, (point: Point) => DropAreaValue>();\n const presentations = new Map<\n string,\n () => RuntimeDropPresentation | undefined\n >();\n const rows = new Map<string, CardRowLookup>();\n // A slide can end on a control other than the pressed one; it drags with\n // that mounted control's own routes.\n const controls = new Map<string, () => false | RuntimeTargetOptions>();\n const followers = new Set<(point: Point) => void>();\n let press: {\n readonly recognizer: GestureRecognizer;\n readonly pointerType: string;\n readonly detach: () => void;\n dragging: boolean;\n area: string | null;\n target: RuntimeDropTarget | null;\n } | null = null;\n let hover: RuntimeShortcutTarget | null = null;\n let hoverPoint: Point | null = null;\n let focused: RuntimeShortcutTarget | null = null;\n // Real DOM focus remains a local-action scope when mouse browsing changes presentation focus.\n let domFocused: RuntimeShortcutTarget | null = null;\n let alt = false;\n let pointer: Point = { x: 0, y: 0 };\n // The dragged card's centre is drawn at `goal` plus a `lag` that decays\n // after a jump, such as snapping into a pile, so it glides there instead.\n // A jump is a change in where the card sits relative to the pointer.\n let goal: Point = { x: 0, y: 0 };\n let offset: Point = { x: 0, y: 0 };\n let lag: Point = { x: 0, y: 0 };\n let shown: Point = { x: 0, y: 0 };\n let held = false;\n let reduced = false;\n let frame = 0;\n let lastFrame = 0;\n // A changed target may mount a landing box or move the areas; measure again next frame.\n let remeasure = false;\n const located = new Map<string, LocatedArea>();\n // Scrollers the pointer has been well inside; only these scroll at their edges,\n // so a card lifted out of a hand does not scroll the table it crosses into.\n const engaged = new Set<Element>();\n let announcer: HTMLElement | null = null;\n let swallowing = false;\n let guardingClicks = false;\n let disposed = false;\n\n const set = (patch: Partial<GestureState>) =>\n store.setState((previous) => {\n const next = { ...previous, ...patch };\n return {\n ...next,\n focusedTarget: domFocused,\n pointerActive: press !== null || next.drag !== null,\n };\n });\n\n let snapshot = game.snapshot;\n let source = game.getOptions().source;\n function admitted(target: RuntimeShortcutTarget | null) {\n if (!target || !game.snapshot) return null;\n const zones = game.snapshot.frame.zones;\n if (target.kind === \"zone\")\n return zones[target.zoneId]?.[target.hostId] ? target : null;\n if (target.kind === \"card\")\n return Object.entries(snapshot?.frame.zones ?? {}).some(\n ([zoneId, hosts]) =>\n Object.entries(hosts).some(\n ([hostId, zone]) =>\n zone.cardIds.includes(target.value) &&\n zones[zoneId]?.[hostId]?.cardIds.includes(target.value),\n ),\n )\n ? target\n : null;\n // Board controls own their mounted identity; each shortcut still checks\n // the current projected input domain before submitting.\n return [...targets.values()].some((read) => sameTarget(read(), target))\n ? target\n : null;\n }\n function admittedFocus(target: RuntimeShortcutTarget | null) {\n if (!target || !sameTarget(target, targetOf(document.activeElement)))\n return null;\n if (target.kind !== \"card\") return admitted(target);\n // A mounted focused card can move between zones without another focus event.\n return Object.values(game.snapshot?.frame.zones ?? {}).some((hosts) =>\n Object.values(hosts).some((zone) => zone.cardIds.includes(target.value)),\n )\n ? target\n : null;\n }\n const unsubscribe = game.subscribe(() => {\n const nextSource = game.getOptions().source;\n const changedLifetime =\n source !== nextSource || snapshot?.me !== game.snapshot?.me;\n const changedSnapshot = snapshot !== game.snapshot;\n if (changedLifetime || snapshot !== game.snapshot) {\n // Cancelling first lets a scrubbing finger take its activity with it.\n press?.recognizer.cancel();\n const nextHover = changedLifetime ? null : admitted(hover);\n const nextFocused = changedLifetime ? null : admitted(focused);\n const nextDomFocused = changedLifetime ? null : admittedFocus(domFocused);\n source = nextSource;\n snapshot = game.snapshot;\n alt = false;\n // A parked pointer or keyboard focus survives an admitted same-seat\n // frame, so separate key presses can keep acting on the same control.\n hover = nextHover;\n focused = nextFocused;\n domFocused = nextDomFocused;\n if (changedLifetime) hoverPoint = null;\n set({ activeTarget: hover ?? focused, inspect: null });\n }\n // New frames, seats and sources cancel the semantic drag; end the press with it.\n if (press?.dragging && !game.drag?.active) press.recognizer.cancel();\n const drag = store.get().drag;\n if (\n drag?.settling &&\n (game.request === null || changedSnapshot || changedLifetime)\n )\n set({ drag: null });\n });\n\n /** The drop areas around the topmost element under the pointer, innermost first. */\n function hitAreas(at: Point): string[] {\n for (const element of document.elementsFromPoint(at.x, at.y)) {\n if (element.closest(\"[data-drag-overlay]\")) continue;\n const ids: string[] = [];\n for (\n let area = element.closest(\"[data-drop-area]\");\n area;\n area = area.parentElement?.closest(\"[data-drop-area]\") ?? null\n )\n ids.push(area.getAttribute(\"data-drop-area\")!);\n if (ids.length) return ids;\n }\n return [];\n }\n function locate(id: string): LocatedArea {\n const known = located.get(id);\n const element = known?.element?.isConnected\n ? known.element\n : document.querySelector(`[data-drop-area=\"${CSS.escape(id)}\"]`);\n // Landing content can mount or be replaced after an area becomes eligible or over.\n const landing = landingIn(element);\n const slot = landing?.dataset.dropLanding === \"slot\" ? landing : null;\n if (known && known.element === element && known.slot === slot) return known;\n const clips: Element[] = [];\n for (\n let node = (slot ?? element)?.parentElement;\n node;\n node = node.parentElement\n ) {\n const { overflowX, overflowY } = getComputedStyle(node);\n if (/auto|scroll|hidden|clip/.test(overflowX + overflowY))\n clips.push(node);\n }\n let depth = 0;\n for (let node = element?.parentElement; node; node = node.parentElement) {\n if (node.hasAttribute(\"data-drop-area\")) depth++;\n }\n const next = {\n element,\n clips,\n slot,\n depth,\n };\n located.set(id, next);\n return next;\n }\n /** Where a drop on `area` lands, and the presentation registered for that zone. */\n function destinationOf(\n area: string | null,\n target: RuntimeDropTarget | null,\n ) {\n const areaPresentation = area ? presentations.get(area)?.() : undefined;\n const position = target?.kind === \"position\" ? target.value : null;\n const zone = position ?? areaPresentation?.zone;\n // Hand insertion areas carry a canonical position; inherit the\n // enclosing zone's disclosure policy when they have no metadata.\n const presentation = zone\n ? [\n areaPresentation,\n ...Array.from(presentations.values(), (read) => read()),\n ].find(\n (candidate) =>\n candidate?.zone.zoneId === zone.zoneId &&\n candidate.zone.hostId === zone.hostId,\n )\n : undefined;\n return { zone, position, presentation };\n }\n const conceals = (\n presentation: RuntimeDropPresentation,\n hostId: string,\n ): boolean =>\n presentation.visibility === \"hidden\" ||\n (presentation.visibility === \"ownerOnly\" && hostId !== game.me?.id);\n function announce(area: string | null) {\n const element = area === null ? null : locate(area).element;\n const label =\n element?.getAttribute(\"aria-label\") ??\n element\n ?.getAttribute(\"aria-labelledby\")\n ?.split(/\\s+/)\n .map((labelId) => document.getElementById(labelId)?.textContent)\n .join(\" \") ??\n \"\";\n if (!announcer?.isConnected) {\n announcer = document.createElement(\"div\");\n announcer.setAttribute(\"role\", \"status\");\n Object.assign(announcer.style, VISUALLY_HIDDEN);\n document.body.append(announcer);\n }\n announcer.textContent = label;\n }\n /**\n * Chooses the target for the pointer at `at` and where the card is drawn:\n * snapped into a pile, held inside a zone's edge, or under the pointer.\n */\n function retarget(at: Point) {\n const drag = store.get().drag;\n if (!press?.dragging || !drag) return;\n pointer = at;\n const ids = [...areas.keys()];\n const found = ids.map((id) => {\n const target = resolveDropArea(game.drag, areas.get(id)!(at));\n if (!target) return null;\n const { element, clips, slot, depth } = locate(id);\n // SVG and transformed board targets keep the browser's own hit testing.\n const box =\n element instanceof HTMLElement\n ? visibleBox(slot ?? element, clips)\n : null;\n return { target, box, slot: slot !== null, depth } satisfies SnapArea & {\n target: RuntimeDropTarget;\n };\n });\n // A card shrunk to fit its last landing keeps the same point under the pointer.\n const pickup =\n drag.width > 0 && drag.size.width > 0 ? drag.size.width / drag.width : 1;\n const ratio = drag.fit.scale === null ? 1 : drag.fit.scale / pickup;\n const width = drag.size.width * ratio;\n const height = drag.size.height * ratio;\n const free = {\n x: at.x - (drag.grab.x - drag.size.width / 2) * ratio,\n y: at.y - (drag.grab.y - drag.size.height / 2) * ratio,\n };\n const snap = snapDrop({\n pointer: at,\n card: { x: free.x - width / 2, y: free.y - height / 2, width, height },\n areas: found,\n hit: ids.indexOf(hitAreas(at).find((id) => found[ids.indexOf(id)]) ?? \"\"),\n retained: press.area === null ? -1 : ids.indexOf(press.area),\n coarse: press.pointerType === \"touch\",\n });\n const area = snap.index < 0 ? null : ids[snap.index];\n const target = snap.index < 0 ? null : found[snap.index]!.target;\n const changed =\n area !== press.area || !sameDropTarget(target, press.target);\n if (changed) {\n press.area = area;\n press.target = target;\n game.drag?.setDropTarget(target);\n announce(area);\n remeasure = true;\n }\n const { zone, presentation } = destinationOf(area, target);\n const place = area === null ? null : locate(area);\n const landing = place && (place.slot ?? landingIn(place.element));\n const fit: DragFit = {\n scale:\n landing && drag.width > 0\n ? landing.offsetWidth / drag.width\n : drag.fit.scale,\n snapped: snap.held && !!found[snap.index]?.slot,\n concealed:\n !!presentation && !!zone && conceals(presentation, zone.hostId),\n };\n const refit =\n Math.abs((fit.scale ?? 0) - (drag.fit.scale ?? 0)) > 0.01 ||\n fit.snapped !== drag.fit.snapped ||\n fit.concealed !== drag.fit.concealed;\n if (changed || refit)\n set({\n drag: {\n ...drag,\n area,\n target,\n fit: refit ? fit : drag.fit,\n },\n });\n draw(snap.center, changed || refit || snap.held !== held);\n held = snap.held;\n // Each move gives the frame loop a chance to scroll and remeasure.\n schedule();\n }\n /** Draws the card centred at `next`, gliding there after a jump. */\n function draw(next: Point, jump: boolean) {\n const nextOffset = { x: next.x - pointer.x, y: next.y - pointer.y };\n if (jump && !reduced)\n lag = {\n x: lag.x + offset.x - nextOffset.x,\n y: lag.y + offset.y - nextOffset.y,\n };\n offset = nextOffset;\n goal = next;\n show();\n if (lag.x || lag.y) schedule();\n }\n function show() {\n shown = { x: goal.x + lag.x, y: goal.y + lag.y };\n for (const follow of followers) follow(shown);\n }\n function schedule() {\n if (frame || disposed) return;\n lastFrame = performance.now();\n frame = requestAnimationFrame(tick);\n }\n function tick(now: number) {\n frame = 0;\n if (!store.get().drag) return;\n const elapsed = Math.min(64, Math.max(0, now - lastFrame));\n const decay = Math.exp(-elapsed / CATCH_UP_MS);\n lag =\n Math.hypot(lag.x, lag.y) * decay < 0.5\n ? { x: 0, y: 0 }\n : { x: lag.x * decay, y: lag.y * decay };\n const scrolling = press?.dragging ? autoScroll(elapsed / 16.7) : false;\n if (scrolling || remeasure) {\n remeasure = false;\n retarget(pointer);\n } else show();\n if (lag.x || lag.y || scrolling) schedule();\n }\n /** Scrolls the innermost engaged scroller under the pointer that it is near the edge of. */\n function autoScroll(frames: number): boolean {\n const edge =\n SCROLL_EDGE[press?.pointerType === \"touch\" ? \"coarse\" : \"fine\"];\n const top = document\n .elementsFromPoint(pointer.x, pointer.y)\n .find((element) => !element.closest(\"[data-drag-overlay]\"));\n for (let node = top ?? null; node; node = node.parentElement) {\n const step = scrollStep(node, pointer, edge, frames);\n if (!step.x && !step.y) {\n if (\n node.scrollHeight > node.clientHeight ||\n node.scrollWidth > node.clientWidth\n )\n engaged.add(node);\n continue;\n }\n if (!engaged.has(node)) return false;\n node.scrollBy(step.x, step.y);\n // Rects change as the content moves.\n return true;\n }\n return false;\n }\n // Keyboard clicks (detail 0) and clicks from a new press are never swallowed.\n function swallow(event: globalThis.MouseEvent) {\n if (!swallowing || event.detail === 0) return;\n swallowing = false;\n event.stopPropagation();\n event.preventDefault();\n }\n function newPress() {\n swallowing = false;\n }\n /** A non-tap stays suppressed until its click or a new press, even after cancellation. */\n function swallowNextClick() {\n swallowing = true;\n if (guardingClicks) return;\n guardingClicks = true;\n addEventListener(\"click\", swallow, true);\n addEventListener(\"pointerdown\", newPress, true);\n }\n function clearHover() {\n hover = null;\n }\n function inspectWithAlt() {\n const target = hover ?? focused;\n const cardId = target?.kind === \"card\" ? target.value : null;\n const pending = store.get().drag;\n set({\n activeTarget: target,\n inspect:\n alt &&\n cardId &&\n !press &&\n !(pending?.settling && pending.cardIds.includes(cardId))\n ? { cardId, via: \"hover\" }\n : null,\n });\n }\n function targetOf(element: Element | null): RuntimeShortcutTarget | null {\n const hit = element?.closest(\"[data-card-gesture], [data-shortcut-target]\");\n const control =\n hit?.getAttribute(\"data-gesture-session\") === id ? hit : null;\n const targetId = control?.getAttribute(\"data-shortcut-target\");\n const cardId = control?.getAttribute(\"data-card-gesture\");\n return targetId\n ? (targets.get(targetId)?.() ?? null)\n : cardId\n ? { kind: \"card\", value: cardId }\n : null;\n }\n function hoverAt(at: Point) {\n hoverPoint = at;\n const wasFocused = focused !== null;\n focused = null;\n const next = targetOf(document.elementFromPoint(at.x, at.y));\n if (sameTarget(hover, next) && !wasFocused) return;\n hover = next;\n inspectWithAlt();\n }\n // CSS transforms generate enter/leave events under a parked mouse. Only\n // physical movement changes its target; down uses the actual pressed control.\n const browse = (event: globalThis.PointerEvent) => {\n if (event.pointerType !== \"mouse\" || press) return;\n if (hoverPoint?.x === event.clientX && hoverPoint.y === event.clientY)\n return;\n alt = event.altKey;\n hoverAt({ x: event.clientX, y: event.clientY });\n };\n const key = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n press?.recognizer.cancel();\n alt = false;\n set({ inspect: null });\n } else if (event.key === \"Alt\") {\n alt = event.type === \"keydown\";\n inspectWithAlt();\n }\n };\n const loseFocus = () => {\n alt = false;\n clearHover();\n hoverPoint = null;\n focused = null;\n domFocused = null;\n set({ activeTarget: null, inspect: null });\n };\n addEventListener(\"keydown\", key);\n addEventListener(\"keyup\", key);\n addEventListener(\"blur\", loseFocus);\n const leaveWindow = (event: globalThis.PointerEvent) => {\n if (event.pointerType !== \"mouse\" || event.relatedTarget !== null) return;\n clearHover();\n hoverPoint = null;\n focused = null;\n alt = false;\n inspectWithAlt();\n };\n addEventListener(\"pointermove\", browse);\n addEventListener(\"pointerout\", leaveWindow);\n function release() {\n press?.detach();\n press = null;\n set({});\n }\n\n function start(\n event: globalThis.PointerEvent,\n cardId: string,\n element: Element,\n options: false | RuntimeTargetOptions,\n ) {\n if (disposed || press || event.button !== 0) return;\n const pending = store.get().drag;\n if (pending?.settling && pending.cardIds.includes(cardId)) return;\n // The card a press acts on; a sliding finger moves it, or leaves the row.\n let card: {\n cardId: string;\n element: Element;\n options: false | RuntimeTargetOptions;\n } | null = { cardId, element, options };\n const row =\n event.pointerType === \"mouse\" ? null : element.closest(\"[data-card-row]\");\n const cardAt = rows.get(row?.getAttribute(\"data-card-row\") ?? \"\");\n const scrubbing = cardAt !== undefined;\n const activate = (next: string | null) => {\n if ((hover?.kind === \"card\" ? hover.value : null) === next) return;\n hover = next === null ? null : { kind: \"card\", value: next };\n inspectWithAlt();\n };\n // Resting places, not the raised face's, keep every card a strip's travel apart.\n function scrubTo(at: Point) {\n const next = cardAt!(at);\n const control =\n next === null\n ? null\n : row!.querySelector(`[data-card-gesture=\"${CSS.escape(next)}\"]`);\n const routes = controls.get(\n control?.getAttribute(\"data-card-control\") ?? \"\",\n );\n card =\n next === null || !control || !routes\n ? null\n : { cardId: next, element: control, options: routes() };\n activate(card?.cardId ?? null);\n }\n const recognizer = createGestureRecognizer(\n event,\n {\n // A hold comes before any movement, so the pressed card is still chosen.\n hold() {\n set({ inspect: { cardId, via: \"hold\" } });\n },\n dragStart(origin) {\n if (!card) return false;\n const { cardId, element, options } = card;\n if (options === false || !game.drag?.begin(cardId, options))\n return false;\n const box = element.getBoundingClientRect();\n clearHover();\n focused = null;\n press!.dragging = true;\n located.clear();\n engaged.clear();\n // A screen reader announces the same area again on the next drag.\n if (announcer) announcer.textContent = \"\";\n reduced = matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n held = false;\n remeasure = false;\n lag = { x: 0, y: 0 };\n goal = shown = {\n x: box.left + box.width / 2,\n y: box.top + box.height / 2,\n };\n offset = { x: goal.x - origin.x, y: goal.y - origin.y };\n set({\n drag: {\n cardIds: game.drag?.active?.cardIds ?? [cardId],\n cardId,\n grab: { x: origin.x - box.left, y: origin.y - box.top },\n size: { width: box.width, height: box.height },\n width: element instanceof HTMLElement ? element.offsetWidth : 0,\n fit: UNFIT,\n settling: false,\n area: null,\n target: null,\n landing: null,\n },\n inspect: null,\n activeTarget: null,\n });\n return true;\n },\n dragMove: retarget,\n browse: scrubTo,\n end(kind, at) {\n const dragging = press!.dragging;\n const pointerType = press!.pointerType;\n // A finger lifted from a scrub chooses the card under it, as a tap would.\n const chosen = scrubbing && kind === \"browse\" ? card?.element : null;\n if (dragging) retarget(at);\n release();\n // A finger leaves no hover behind.\n if (scrubbing) activate(null);\n // Clicked before the guard below, so the choice is never swallowed.\n if (chosen instanceof HTMLElement) chosen.click();\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (!dragging) {\n // A rejected drag or inspection-only mouse press may browse to a\n // different face. Its final physical point becomes the canonical target.\n if (kind === \"browse\" && pointerType === \"mouse\") hoverAt(at);\n return;\n }\n const before = game.request;\n const drag = store.get().drag;\n const { zone, position, presentation } = destinationOf(\n drag?.area ?? null,\n drag?.target ?? null,\n );\n const destination = zone && game.zones.find(zone.zoneId, zone.hostId);\n const cards =\n drag?.cardIds.flatMap((id) => {\n const card = game.cards.find(id);\n return card ? [card] : [];\n }) ?? [];\n const landing =\n destination && zone && cards.length\n ? Object.freeze({\n zoneId: zone.zoneId,\n hostId: zone.hostId,\n index:\n position?.index ??\n presentation?.index ??\n destination.getCards().length,\n concealed: presentation\n ? conceals(presentation, zone.hostId)\n : cards.some(\n (card) =>\n card.zone !== zone.zoneId ||\n card.hostId !== zone.hostId ||\n card.hidden,\n ),\n cards: Object.freeze(cards),\n snapshot: game.snapshot,\n })\n : null;\n game.drag?.drop();\n // A submitted move keeps its overlay until the authoritative frame.\n if (drag && game.request !== null && game.request !== before)\n set({ drag: { ...drag, settling: true, landing } });\n else set({ drag: null });\n },\n cancel(kind) {\n const dragging = press!.dragging;\n release();\n if (scrubbing) activate(null);\n // Cancellation does not turn a non-tap into a selection on release.\n if (kind !== \"tap\") swallowNextClick();\n if (kind === \"hold\") set({ inspect: null });\n if (dragging) {\n game.drag?.cancel();\n set({ drag: null });\n }\n },\n },\n { scrub: scrubbing },\n );\n const move = (next: globalThis.PointerEvent) => recognizer.move(next);\n const up = (next: globalThis.PointerEvent) => recognizer.up(next);\n const cancel = (next: globalThis.PointerEvent) => recognizer.cancel(next);\n const blur = () => recognizer.cancel();\n addEventListener(\"pointermove\", move);\n addEventListener(\"pointerup\", up);\n addEventListener(\"pointercancel\", cancel);\n addEventListener(\"blur\", blur);\n if (event.pointerType === \"mouse\") {\n // A mouse keeps reporting outside the card; touch is captured implicitly.\n try {\n element.setPointerCapture(event.pointerId);\n } catch {\n // The pointer may already be gone.\n }\n }\n press = {\n recognizer,\n pointerType: event.pointerType,\n dragging: false,\n area: null,\n target: null,\n detach() {\n removeEventListener(\"pointermove\", move);\n removeEventListener(\"pointerup\", up);\n removeEventListener(\"pointercancel\", cancel);\n removeEventListener(\"blur\", blur);\n },\n };\n set({});\n }\n\n function cardProps(\n cardId: string,\n control: string,\n options: false | RuntimeTargetOptions,\n flags: { dragging: boolean; inspecting: \"hold\" | \"hover\" | null },\n ): CardGestureProps {\n return {\n onPointerDown(event) {\n if (event.pointerType === \"mouse\") {\n hover = { kind: \"card\", value: cardId };\n alt = event.altKey;\n inspectWithAlt();\n }\n start(event.nativeEvent, cardId, event.currentTarget, options);\n },\n onFocus(event) {\n focused = event.currentTarget.matches(\":focus-visible\")\n ? { kind: \"card\", value: cardId }\n : null;\n domFocused = { kind: \"card\", value: cardId };\n if (focused) hover = null;\n inspectWithAlt();\n },\n onBlur() {\n if (focused?.kind === \"card\" && focused.value === cardId)\n focused = null;\n if (domFocused?.kind === \"card\" && domFocused.value === cardId)\n domFocused = null;\n inspectWithAlt();\n },\n onContextMenu(event) {\n // A long press must inspect the card, not open the browser's menu.\n if ((press && press.pointerType !== \"mouse\") || swallowing)\n event.preventDefault();\n },\n onDragStart: (event) => event.preventDefault(),\n style: options === false ? INSPECTION_STYLE : CARD_STYLE,\n \"data-dragging\": flags.dragging || undefined,\n \"data-inspecting\": flags.inspecting ?? undefined,\n \"data-card-gesture\": cardId,\n \"data-card-control\": control,\n \"data-gesture-session\": id,\n };\n }\n\n /**\n * Positions the dragged card's overlay without rendering on each move. It\n * moves by `left` and `top`: Motion's shared layout inside it measures\n * against the overlay's layout box, which a transform would leave behind.\n */\n function overlayRef(element: HTMLElement | null) {\n const drag = store.get().drag;\n if (!element || !drag) return;\n element.setAttribute(\"data-drag-overlay\", \"\");\n Object.assign(element.style, {\n position: \"fixed\",\n margin: \"0\",\n pointerEvents: \"none\",\n width: px(drag.size.width),\n height: px(drag.size.height),\n });\n const follow = (center: Point) => {\n element.style.left = px(center.x - drag.size.width / 2);\n element.style.top = px(center.y - drag.size.height / 2);\n };\n follow(shown);\n followers.add(follow);\n return () => {\n followers.delete(follow);\n };\n }\n\n return {\n id,\n store,\n cardProps,\n getActiveCardId() {\n const target = store.get().activeTarget;\n return target?.kind === \"card\" ? target.value : null;\n },\n getActiveTarget: () => store.get().activeTarget,\n getShortcutActivity: () => ({\n // Removal can change DOM focus without emitting blur. Admit the current mounted control.\n focusedTarget: sameTarget(domFocused, targetOf(document.activeElement))\n ? domFocused\n : null,\n pointerActive: store.get().pointerActive,\n }),\n registerTarget(targetId: string, read: () => RuntimeShortcutTarget) {\n const target = read();\n targets.set(targetId, read);\n return () => {\n targets.delete(targetId);\n if (sameTarget(hover, target)) hover = null;\n if (sameTarget(focused, target)) focused = null;\n if (sameTarget(domFocused, target)) domFocused = null;\n inspectWithAlt();\n };\n },\n targetProps(targetId: string) {\n return {\n \"data-shortcut-target\": targetId,\n \"data-gesture-session\": id,\n onPointerDown(event: PointerEvent<Element>) {\n if (event.pointerType !== \"mouse\") return;\n hover = targets.get(targetId)?.() ?? null;\n alt = event.altKey;\n inspectWithAlt();\n },\n onFocus(event: FocusEvent<Element>) {\n focused = event.currentTarget.matches(\":focus-visible\")\n ? (targets.get(targetId)?.() ?? null)\n : null;\n domFocused = targets.get(targetId)?.() ?? null;\n if (focused) hover = null;\n inspectWithAlt();\n },\n onBlur() {\n const target = targets.get(targetId)?.() ?? null;\n if (sameTarget(focused, target)) focused = null;\n if (sameTarget(domFocused, target)) domFocused = null;\n inspectWithAlt();\n },\n };\n },\n overlayRef,\n /** `read` returns the area's current binding; targets resolve when hit. */\n registerArea(\n area: string,\n read: (point: Point) => DropAreaValue,\n presentation: () => RuntimeDropPresentation | undefined,\n ) {\n areas.set(area, read);\n presentations.set(area, presentation);\n return () => {\n areas.delete(area);\n presentations.delete(area);\n };\n },\n /** `read` returns a mounted card control's current drag routes. */\n registerControl(control: string, read: () => false | RuntimeTargetOptions) {\n controls.set(control, read);\n return () => {\n controls.delete(control);\n };\n },\n registerRow(row: string, cardAt: CardRowLookup) {\n rows.set(row, cardAt);\n return () => {\n rows.delete(row);\n };\n },\n rowProps(row: string) {\n return { \"data-card-row\": row, style: ROW_STYLE };\n },\n dispose() {\n disposed = true;\n press?.recognizer.cancel();\n cancelAnimationFrame(frame);\n announcer?.remove();\n clearHover();\n removeEventListener(\"keydown\", key);\n removeEventListener(\"keyup\", key);\n removeEventListener(\"blur\", loseFocus);\n removeEventListener(\"pointermove\", browse);\n removeEventListener(\"pointerout\", leaveWindow);\n unsubscribe();\n followers.clear();\n targets.clear();\n areas.clear();\n presentations.clear();\n rows.clear();\n controls.clear();\n if (!guardingClicks) return;\n removeEventListener(\"click\", swallow, true);\n removeEventListener(\"pointerdown\", newPress, true);\n },\n };\n}\n\nexport const GestureContext = createContext<GestureSession | null>(null);\n\nexport function useGestureSession(): GestureSession {\n const session = useContext(GestureContext);\n if (!session) throw new Error(\"Gesture hooks require their GameProvider.\");\n return session;\n}\n\nexport function useGestureState<Value>(\n session: GestureSession,\n select: (state: GestureState) => Value,\n): Value {\n return useSelector(session.store, select);\n}\n","import type { Point } from \"./features/pointer-session.js\";\nimport { magneticDropPoint } from \"./gesture.js\";\n\nexport interface Box {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\n/** Tuned by hand with a mouse and emulated touch. Distances to a pile are in its own slot sizes. */\nconst SNAP = Object.freeze({\n /** A pile catches a card whose centre comes this close to its own. */\n slotCatch: 0.75,\n /** A caught card leaves the pile beyond this. */\n slotRelease: 1.15,\n /** A finger reaches this much further. */\n coarseReach: 0.2,\n /** Another pile takes a caught card only when this much closer. */\n slotSwitch: 0.1,\n /** A card enters a zone once this share of it covers the zone... */\n zoneEnter: 0.35,\n /** ...and leaves it once less than this share does. */\n zoneLeave: 0.1,\n /** How much a card in a pile still follows the pointer. */\n slotGive: 0.15,\n /** How much a card held inside a zone's edge follows the pointer beyond it. */\n edgeGive: 0.25,\n});\n\n/** An eligible area: a pile's slot, a zone's visible box, or neither for SVG targets. */\nexport interface SnapArea {\n readonly box: Box | null;\n readonly slot: boolean;\n /** How many other areas contain it; the innermost covered zone wins. */\n readonly depth: number;\n}\n\nexport interface Snap {\n /** The chosen area, or -1. */\n readonly index: number;\n /** Where the card's centre is drawn: in its pile, held inside a zone's edge, or free. */\n readonly center: Point;\n /** Drawn somewhere other than under the pointer. */\n readonly held: boolean;\n}\n\nconst centerOf = (box: Box): Point => ({\n x: box.x + box.width / 2,\n y: box.y + box.height / 2,\n});\nconst toward = (from: Point, to: Point, share: number): Point => ({\n x: from.x + (to.x - from.x) * share,\n y: from.y + (to.y - from.y) * share,\n});\nconst contains = (box: Box, point: Point) =>\n point.x >= box.x &&\n point.x <= box.x + box.width &&\n point.y >= box.y &&\n point.y <= box.y + box.height;\n/** The share of `card` over `box`. */\nfunction cover(card: Box, box: Box) {\n const width =\n Math.min(card.x + card.width, box.x + box.width) - Math.max(card.x, box.x);\n const height =\n Math.min(card.y + card.height, box.y + box.height) -\n Math.max(card.y, box.y);\n return width > 0 && height > 0\n ? (width * height) / (card.width * card.height)\n : 0;\n}\n\n/**\n * Chooses where a dragged card lands and where it is drawn. A pile catches the\n * card by its centre and draws it in its slot; the area under the pointer\n * comes next; a zone takes a card that covers enough of it, or that the\n * pointer nearly reaches, and holds it inside its edge until it is pulled\n * clear. `retained` is the current area, which each rule favours so the\n * choice never flickers at a boundary.\n */\nexport function snapDrop({\n pointer,\n card,\n areas,\n hit,\n retained,\n coarse,\n}: {\n readonly pointer: Point;\n /** The card as it would be drawn under the pointer. */\n readonly card: Box;\n /** Null where an area cannot take the card now. */\n readonly areas: readonly (SnapArea | null)[];\n /** The area the browser hit-tests under the pointer, or -1. */\n readonly hit: number;\n readonly retained: number;\n readonly coarse: boolean;\n}): Snap {\n const free = centerOf(card);\n const inSlot = (index: number, box: Box): Snap => ({\n index,\n center: toward(centerOf(box), free, SNAP.slotGive),\n held: true,\n });\n let best = -1;\n let score = Infinity;\n areas.forEach((area, index) => {\n const box = area?.slot ? area.box : null;\n if (!box?.width || !box.height) return;\n const middle = centerOf(box);\n const distance = Math.hypot(\n (free.x - middle.x) / box.width,\n (free.y - middle.y) / box.height,\n );\n const kept = index === retained;\n const reach =\n (kept ? SNAP.slotRelease : SNAP.slotCatch) +\n (coarse ? SNAP.coarseReach : 0);\n const value = kept ? distance - SNAP.slotSwitch : distance;\n if (distance <= reach && value < score) {\n best = index;\n score = value;\n }\n });\n if (best >= 0) return inSlot(best, areas[best]!.box!);\n const under = hit >= 0 ? areas[hit] : null;\n if (under)\n return under.slot && under.box?.width\n ? inSlot(hit, under.box)\n : { index: hit, center: free, held: false };\n // A held card stays inside the zone's edge and gives a little toward the pointer.\n const hold = (index: number, box: Box): Snap => {\n if (contains(box, pointer)) return { index, center: free, held: false };\n const inside = {\n x: Math.max(box.x, Math.min(free.x, box.x + box.width)),\n y: Math.max(box.y, Math.min(free.y, box.y + box.height)),\n };\n return { index, center: toward(inside, free, SNAP.edgeGive), held: true };\n };\n const zone = (index: number) => {\n const area = areas[index];\n return area && !area.slot && area.box?.width ? area.box : null;\n };\n const kept = retained >= 0 ? zone(retained) : null;\n if (\n kept &&\n (cover(card, kept) >= SNAP.zoneLeave ||\n magneticDropPoint(pointer, kept, true, coarse))\n )\n return hold(retained, kept);\n let chosen = -1;\n let share = 0;\n areas.forEach((_, index) => {\n const box = zone(index);\n if (!box) return;\n const value = cover(card, box);\n if (\n value < SNAP.zoneEnter &&\n !magneticDropPoint(pointer, box, false, coarse)\n )\n return;\n const deeper = chosen < 0 || areas[index]!.depth > areas[chosen]!.depth;\n if (\n deeper ||\n (areas[index]!.depth === areas[chosen]!.depth && value > share)\n ) {\n chosen = index;\n share = value;\n }\n });\n return chosen >= 0\n ? hold(chosen, zone(chosen)!)\n : { index: -1, center: free, held: false };\n}\n","import { useEffect, useRef, useState, type PointerEvent } from \"react\";\n\nexport interface MarqueeBounds {\n readonly left: number;\n readonly top: number;\n readonly width: number;\n readonly height: number;\n}\n\n/** An opt-in background gesture. Bounds use viewport coordinates for an authored fixed overlay. */\nexport function useMarqueeSelection<Id extends string>(options: {\n readonly enabled: boolean;\n readonly getCards: () => readonly {\n readonly id: Id;\n readonly element: Element;\n }[];\n readonly onSelect: (ids: readonly Id[], additive: boolean) => void;\n}) {\n const latest = useRef(options);\n latest.current = options;\n const [bounds, setBounds] = useState<MarqueeBounds | null>(null);\n const cleanup = useRef<(() => void) | null>(null);\n useEffect(() => () => cleanup.current?.(), []);\n useEffect(() => {\n if (!options.enabled) {\n cleanup.current?.();\n setBounds(null);\n }\n }, [options.enabled]);\n return {\n bounds,\n props: {\n onPointerDown(event: PointerEvent<HTMLElement>) {\n if (\n !latest.current.enabled ||\n event.button !== 0 ||\n event.pointerType === \"touch\" ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey ||\n (event.target as Element).closest(\n \"button, input, select, textarea, a, [contenteditable], [data-card-gesture]\",\n )\n )\n return;\n event.preventDefault();\n cleanup.current?.();\n const x = event.clientX,\n y = event.clientY,\n pointerId = event.pointerId;\n const area = event.currentTarget;\n const additive = event.shiftKey;\n const doc = event.currentTarget.ownerDocument;\n let rectangle: MarqueeBounds | null = null;\n function move(next: globalThis.PointerEvent) {\n if (next.pointerId !== pointerId) return;\n if (!rectangle && Math.hypot(next.clientX - x, next.clientY - y) < 8)\n return;\n const box = area.getBoundingClientRect();\n const right = Math.min(box.right, Math.max(x, next.clientX));\n const bottom = Math.min(box.bottom, Math.max(y, next.clientY));\n const left = Math.max(box.left, Math.min(x, next.clientX));\n const top = Math.max(box.top, Math.min(y, next.clientY));\n rectangle = { left, top, width: right - left, height: bottom - top };\n setBounds(rectangle);\n next.preventDefault();\n }\n function stop() {\n doc.removeEventListener(\"pointermove\", move);\n doc.removeEventListener(\"pointerup\", up);\n doc.removeEventListener(\"pointercancel\", cancel);\n doc.removeEventListener(\"keydown\", key);\n doc.defaultView?.removeEventListener(\"blur\", cancel);\n cleanup.current = null;\n }\n function cancel() {\n stop();\n setBounds(null);\n }\n function key(next: KeyboardEvent) {\n if (next.key === \"Escape\") {\n next.preventDefault();\n cancel();\n }\n }\n function up(next: globalThis.PointerEvent) {\n if (next.pointerId !== pointerId) return;\n const ids = rectangle\n ? latest.current\n .getCards()\n .filter(({ element }) => {\n const box = element.getBoundingClientRect();\n const region = rectangle!;\n return (\n box.right > region.left &&\n box.left < region.left + region.width &&\n box.bottom > region.top &&\n box.top < region.top + region.height\n );\n })\n .map((card) => card.id)\n : [];\n stop();\n setBounds(null);\n latest.current.onSelect(ids, additive);\n }\n cleanup.current = stop;\n doc.addEventListener(\"pointermove\", move, { passive: false });\n doc.addEventListener(\"pointerup\", up);\n doc.addEventListener(\"pointercancel\", cancel);\n doc.addEventListener(\"keydown\", key);\n doc.defaultView?.addEventListener(\"blur\", cancel);\n },\n },\n };\n}\n"],"mappings":"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","names":["createStore","kept","target","id","cardId","element","options","card","createContext","useContext","useLayoutEffect","useRef","useSelector","createContext","useRef","useLayoutEffect","owned","useContext","useSelector","card","createStore","useRef","useState"]}
|
package/package.json
CHANGED