@weasel-js/gestures 0.5.0

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 ADDED
@@ -0,0 +1,556 @@
1
+ // src/grammar/gestures.ts
2
+ var GESTURE_DESCRIPTORS = [
3
+ { name: "click", hasTarget: true },
4
+ { name: "pointerDown", hasTarget: true },
5
+ { name: "dblTap", hasTarget: true },
6
+ { name: "drag", hasTarget: true },
7
+ { name: "wheel", hasTarget: false, arg: { name: "direction", values: ["up", "down", "*"], default: "*" } },
8
+ { name: "keyDown", hasTarget: false, arg: { name: "key", values: "free" } },
9
+ { name: "keyUp", hasTarget: false, arg: { name: "key", values: "free" } },
10
+ { name: "keyHeld", hasTarget: false, arg: { name: "key", values: "free" } },
11
+ { name: "contextMenu", hasTarget: true },
12
+ { name: "multiTouchTap", hasTarget: false, arg: { name: "fingers", values: ["2", "3", "4"] } }
13
+ ];
14
+ var BY_NAME = new Map(
15
+ GESTURE_DESCRIPTORS.map((d) => [d.name, d])
16
+ );
17
+ function getGestureDescriptor(name) {
18
+ const d = BY_NAME.get(name);
19
+ if (!d) throw new Error(`unknown gesture: ${name}`);
20
+ return d;
21
+ }
22
+ function isKnownGestureName(name) {
23
+ return BY_NAME.has(name);
24
+ }
25
+
26
+ // src/grammar/modifiers.ts
27
+ function mods(...keys) {
28
+ if (keys.length === 0) return "default";
29
+ const set = new Set(keys);
30
+ return [
31
+ set.has("mod") && "mod",
32
+ set.has("shift") && "shift",
33
+ set.has("alt") && "alt"
34
+ ].filter(Boolean).join("+");
35
+ }
36
+
37
+ // src/grammar/routeGrammar.ts
38
+ var RESERVED_ID_PREFIXES = /* @__PURE__ */ new Set([
39
+ "!",
40
+ "@",
41
+ "#",
42
+ "$",
43
+ "%",
44
+ "^",
45
+ "&",
46
+ "*"
47
+ ]);
48
+ var RESERVED_ID_NAMES = /* @__PURE__ */ new Set([
49
+ "initial",
50
+ "engaged"
51
+ ]);
52
+ var VALID_MOD_NAMES = ["mod", "shift", "alt", "ctrl", "meta"];
53
+ var RESERVED_SIGILS = /* @__PURE__ */ new Set(["!", "@", "#", "$", "%", "^", "&"]);
54
+ var ACTIVE_SIGILS = /* @__PURE__ */ new Set(["+", "?"]);
55
+ var MOD_NAME_SET = new Set(VALID_MOD_NAMES);
56
+ function parseRoute(input) {
57
+ const trimmed = input.trim();
58
+ if (!trimmed.startsWith("[")) {
59
+ throw new Error(`invalid route (phase brackets required): ${input}`);
60
+ }
61
+ const closeIdx = trimmed.indexOf("]");
62
+ if (closeIdx < 0) throw new Error(`invalid route (unclosed phase bracket): ${input}`);
63
+ const phaseListRaw = trimmed.slice(1, closeIdx).trim();
64
+ const phases = parsePhaseList(phaseListRaw, input);
65
+ let rest = trimmed.slice(closeIdx + 1).trim();
66
+ const gestureMatch = /^([A-Za-z]+)/.exec(rest);
67
+ if (!gestureMatch) throw new Error(`invalid route (no gesture name): ${input}`);
68
+ const gestureName = gestureMatch[1];
69
+ if (!isKnownGestureName(gestureName)) {
70
+ throw new Error(`invalid route (unknown gesture "${gestureName}"): ${input}`);
71
+ }
72
+ rest = rest.slice(gestureMatch[0].length).trimStart();
73
+ const desc = getGestureDescriptor(gestureName);
74
+ let arg;
75
+ if (rest.startsWith("(")) {
76
+ const closeArg = rest.indexOf(")");
77
+ if (closeArg < 0) throw new Error(`invalid route (unbalanced arg parens): ${input}`);
78
+ const argRaw = rest.slice(1, closeArg);
79
+ if (!desc.arg) throw new Error(`invalid route (${gestureName} has no arg): ${input}`);
80
+ if (argRaw !== "*" && desc.arg.values !== "free" && !desc.arg.values.includes(argRaw)) {
81
+ throw new Error(`invalid route ("${argRaw}" not in ${desc.arg.values.join("|")}): ${input}`);
82
+ }
83
+ arg = argRaw;
84
+ rest = rest.slice(closeArg + 1).trimStart();
85
+ } else if (desc.arg) {
86
+ arg = desc.arg.default ?? "*";
87
+ }
88
+ let target;
89
+ if (rest.startsWith("=>")) {
90
+ if (!desc.hasTarget) throw new Error(`invalid route (${gestureName} has no target): ${input}`);
91
+ rest = rest.slice(2).trimStart();
92
+ const tgtMatch = /^([^\s+?!@#$%^&]+)/.exec(rest);
93
+ if (!tgtMatch) throw new Error(`invalid route (missing target after "=>"): ${input}`);
94
+ target = tgtMatch[1];
95
+ rest = rest.slice(tgtMatch[0].length).trimStart();
96
+ } else if (desc.hasTarget) {
97
+ target = "*";
98
+ }
99
+ const modifiers = {};
100
+ while (rest.length > 0) {
101
+ const ch = rest[0];
102
+ if (RESERVED_SIGILS.has(ch)) {
103
+ throw new Error(`invalid route ("${ch}" is reserved for future use): ${input}`);
104
+ }
105
+ if (!ACTIVE_SIGILS.has(ch)) {
106
+ throw new Error(`invalid route (unexpected "${ch}" at "${rest}"): ${input}`);
107
+ }
108
+ const sigil = ch;
109
+ rest = rest.slice(1);
110
+ const nameMatch = /^([a-z]+)/.exec(rest);
111
+ if (!nameMatch) throw new Error(`invalid route (sigil "${sigil}" without modifier name): ${input}`);
112
+ const name = nameMatch[1];
113
+ if (!MOD_NAME_SET.has(name)) {
114
+ throw new Error(`invalid route (unknown modifier "${name}"): ${input}`);
115
+ }
116
+ if (modifiers[name] !== void 0) {
117
+ throw new Error(`invalid route (duplicate modifier "${name}"): ${input}`);
118
+ }
119
+ modifiers[name] = sigil === "+" ? "required" : "optional";
120
+ rest = rest.slice(nameMatch[0].length).trimStart();
121
+ }
122
+ return { phases, gesture: gestureName, arg, target, modifiers };
123
+ }
124
+ function parsePhaseList(raw, input) {
125
+ if (raw === "") throw new Error(`invalid route (empty phase list): ${input}`);
126
+ const tokens = raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
127
+ if (tokens.length === 0) throw new Error(`invalid route (empty phase list): ${input}`);
128
+ return tokens.map((t) => parsePhaseAtom(t, input));
129
+ }
130
+ var VALID_PHASES = /* @__PURE__ */ new Set(["initial", "engaged", "*"]);
131
+ function parsePhaseAtom(raw, input) {
132
+ const parts = raw.split(":");
133
+ if (parts.length > 2) {
134
+ throw new Error(`invalid route (phase atom "${raw}" has multiple ":"): ${input}`);
135
+ }
136
+ if (parts.length === 1) {
137
+ const phase2 = parts[0];
138
+ if (!VALID_PHASES.has(phase2)) {
139
+ throw new Error(`invalid route (unknown phase "${phase2}" in "${raw}"): ${input}`);
140
+ }
141
+ return { channel: "&", phase: phase2 };
142
+ }
143
+ const channel = parts[0];
144
+ const phase = parts[1];
145
+ if (channel === "") {
146
+ throw new Error(`invalid route (empty channel before ":" in "${raw}"): ${input}`);
147
+ }
148
+ if (!VALID_PHASES.has(phase)) {
149
+ throw new Error(`invalid route (unknown phase "${phase}" in "${raw}"): ${input}`);
150
+ }
151
+ if (channel !== "&" && channel !== "*") {
152
+ if (RESERVED_ID_NAMES.has(channel)) {
153
+ throw new Error(`invalid route (channel "${channel}" is a reserved phase keyword): ${input}`);
154
+ }
155
+ if (RESERVED_ID_PREFIXES.has(channel[0])) {
156
+ throw new Error(`invalid route (channel "${channel}" starts with reserved sigil "${channel[0]}"): ${input}`);
157
+ }
158
+ }
159
+ return { channel, phase };
160
+ }
161
+ function formatPhaseAtom(a) {
162
+ if (a.channel === "&") return a.phase;
163
+ return `${a.channel}:${a.phase}`;
164
+ }
165
+ function collapseShiftPairs(routes) {
166
+ if (routes.length < 2) return [...routes];
167
+ const parsed = routes.map((r) => ({ raw: r, p: parseRoute(r) }));
168
+ const consumed = /* @__PURE__ */ new Set();
169
+ const out = [];
170
+ for (let i = 0; i < parsed.length; i++) {
171
+ if (consumed.has(i)) continue;
172
+ const a = parsed[i];
173
+ let twinIndex = -1;
174
+ for (let j = i + 1; j < parsed.length; j++) {
175
+ if (consumed.has(j)) continue;
176
+ const b = parsed[j];
177
+ if (isShiftTwin(a.p, b.p)) {
178
+ twinIndex = j;
179
+ break;
180
+ }
181
+ }
182
+ if (twinIndex < 0) {
183
+ out.push(a.raw);
184
+ continue;
185
+ }
186
+ consumed.add(twinIndex);
187
+ const folded = {
188
+ ...a.p,
189
+ modifiers: { ...withoutShift(a.p.modifiers), shift: "optional" }
190
+ };
191
+ out.push(formatRoute(folded));
192
+ }
193
+ return out;
194
+ }
195
+ function isShiftTwin(a, b) {
196
+ if (a.gesture !== b.gesture) return false;
197
+ if (a.arg !== b.arg) return false;
198
+ if (a.target !== b.target) return false;
199
+ if (!samePhases(a.phases, b.phases)) return false;
200
+ const aShift = a.modifiers.shift;
201
+ const bShift = b.modifiers.shift;
202
+ const aHas = aShift === "required";
203
+ const bHas = bShift === "required";
204
+ if (!(aHas !== bHas)) return false;
205
+ if (aShift === "optional" || bShift === "optional") return false;
206
+ for (const name of VALID_MOD_NAMES) {
207
+ if (name === "shift") continue;
208
+ if (a.modifiers[name] !== b.modifiers[name]) return false;
209
+ }
210
+ return true;
211
+ }
212
+ function samePhases(a, b) {
213
+ if (a.length !== b.length) return false;
214
+ for (let i = 0; i < a.length; i++) {
215
+ if (a[i].channel !== b[i].channel || a[i].phase !== b[i].phase) return false;
216
+ }
217
+ return true;
218
+ }
219
+ function withoutShift(m) {
220
+ const { shift: _shift, ...rest } = m;
221
+ return rest;
222
+ }
223
+ var MOD_ORDER = ["mod", "shift", "alt", "ctrl", "meta"];
224
+ function formatRoute(r) {
225
+ const desc = getGestureDescriptor(r.gesture);
226
+ const phaseStr = `[${r.phases.map(formatPhaseAtom).join(",")}]`;
227
+ let out = `${phaseStr} ${r.gesture}`;
228
+ if (desc.arg) {
229
+ const isDefault = r.arg === void 0 || desc.arg.default !== void 0 && r.arg === desc.arg.default;
230
+ if (!isDefault) out += `(${r.arg})`;
231
+ }
232
+ if (desc.hasTarget && r.target !== void 0 && r.target !== "*") {
233
+ out += ` => ${r.target}`;
234
+ }
235
+ for (const name of MOD_ORDER) {
236
+ const req = r.modifiers[name];
237
+ if (req === "required") out += ` +${name}`;
238
+ else if (req === "optional") out += ` ?${name}`;
239
+ }
240
+ return out;
241
+ }
242
+
243
+ // src/grammar/keyRouteGrammar.ts
244
+ var OPTIONAL_SET = new Set(VALID_MOD_NAMES);
245
+ function parseKeyRoute(input) {
246
+ const [key, ...mods2] = input.split("?");
247
+ if (!key) throw new Error(`invalid key route (empty key): ${input}`);
248
+ const seen = /* @__PURE__ */ new Set();
249
+ for (const m of mods2) {
250
+ if (!OPTIONAL_SET.has(m)) throw new Error(`unknown optional modifier "${m}" in ${input}`);
251
+ if (seen.has(m)) throw new Error(`duplicate optional modifier "${m}" in ${input}`);
252
+ seen.add(m);
253
+ }
254
+ return { key, optionalMods: mods2 };
255
+ }
256
+ function formatKeyRoute(r) {
257
+ return r.optionalMods.length === 0 ? r.key : `${r.key}?${r.optionalMods.join("?")}`;
258
+ }
259
+ function keyRouteToSpec(r) {
260
+ const mods2 = {};
261
+ for (const m of r.optionalMods) mods2[m] = "optional";
262
+ const spec = { kind: "key", key: r.key };
263
+ if (Object.keys(mods2).length > 0) spec.mods = mods2;
264
+ return spec;
265
+ }
266
+
267
+ // src/grammar/describeRoute.ts
268
+ var MOD_NAMES = {
269
+ mod: "Mod",
270
+ shift: "Shift",
271
+ alt: "Alt",
272
+ ctrl: "Ctrl",
273
+ meta: "Meta"
274
+ };
275
+ var MOD_ORDER2 = ["mod", "shift", "alt", "ctrl", "meta"];
276
+ var ROUTE_TERMS = {
277
+ idle: "Not in the middle of a drag or other synchronous operation.",
278
+ "mid-gesture": "In the middle of a drag or other synchronous operation."
279
+ };
280
+ var ROUTE_FIELD_DEFINITIONS = {
281
+ phases: "Which lifecycle stage(s) a channel must be in for this route to fire. `initial` = the channel is idle; `engaged` = the channel is mid-gesture. The channel is the binding's own tool (`&`), any tool (`*`), or a named tool id.",
282
+ gesture: "The class of input event that triggers this route \u2014 click, drag, double-tap, keyDown/keyUp, wheel, contextMenu, or multiTouchTap.",
283
+ arg: "Sub-class of the gesture. Direction for wheel (up / down / *), key name for keyDown / keyUp, finger count for multiTouchTap. Other gestures have no arg slot.",
284
+ target: "Which hit-test result the gesture must land on. `*` matches any target; `empty` matches the empty canvas; otherwise the value names a specific hit-target kind.",
285
+ modifiers: "Modifier keys the user must hold (`+key`) or may optionally hold (`?key`) for this route to match. Unlisted modifiers must not be held."
286
+ };
287
+ function term(label) {
288
+ return { kind: "term", label, definition: ROUTE_TERMS[label] };
289
+ }
290
+ function joinAnd(parts) {
291
+ if (parts.length === 0) return "";
292
+ if (parts.length === 1) return parts[0];
293
+ if (parts.length === 2) return `${parts[0]} and ${parts[1]}`;
294
+ return `${parts.slice(0, -1).join(", ")}, and ${parts[parts.length - 1]}`;
295
+ }
296
+ function partitionModifiers(mods2) {
297
+ const required = [];
298
+ const optional = [];
299
+ for (const name of MOD_ORDER2) {
300
+ const req = mods2[name];
301
+ if (req === "required") required.push(MOD_NAMES[name]);
302
+ else if (req === "optional") optional.push(MOD_NAMES[name]);
303
+ }
304
+ return { required, optional };
305
+ }
306
+ function phaseAtomParts({ channel, phase }) {
307
+ const subject = channel === "&" ? "the tool" : channel === "*" ? "any tool" : `the ${channel} tool`;
308
+ if (phase === "initial") return [`${subject} is `, term("idle")];
309
+ if (phase === "engaged") return [`${subject} is `, term("mid-gesture")];
310
+ return [`${subject} is in any phase`];
311
+ }
312
+ function phasesParts(phases) {
313
+ if (phases.length === 1) return phaseAtomParts(phases[0]);
314
+ const out = [];
315
+ phases.forEach((p, i) => {
316
+ if (i > 0) out.push(" or ");
317
+ out.push(...phaseAtomParts(p));
318
+ });
319
+ return out;
320
+ }
321
+ function targetClause(target, hasTarget) {
322
+ if (!hasTarget || target === void 0) return "";
323
+ if (target === "*") return " anywhere";
324
+ if (target === "empty") return " on empty canvas";
325
+ return ` on a ${target}`;
326
+ }
327
+ function actionClause(parsed, required) {
328
+ const desc = getGestureDescriptor(parsed.gesture);
329
+ const modPrefix = required.length > 0 ? `${joinAnd(required)}-` : "";
330
+ const target = targetClause(parsed.target, desc.hasTarget);
331
+ switch (parsed.gesture) {
332
+ case "keyDown":
333
+ case "keyUp":
334
+ case "keyHeld": {
335
+ const verb = parsed.gesture === "keyDown" ? "presses" : parsed.gesture === "keyUp" ? "releases" : "holds";
336
+ const key = parsed.arg ?? "any key";
337
+ return required.length > 0 ? `the user holds ${joinAnd(required)} and ${verb} ${key}` : `the user ${verb} ${key}`;
338
+ }
339
+ case "wheel": {
340
+ const direction = parsed.arg === "up" ? " up" : parsed.arg === "down" ? " down" : "";
341
+ return `the user ${modPrefix}scrolls${direction}`;
342
+ }
343
+ case "multiTouchTap":
344
+ return `the user taps with ${parsed.arg ?? "multiple"} fingers`;
345
+ case "contextMenu":
346
+ return `the user ${modPrefix}opens the context menu${target}`;
347
+ case "click":
348
+ return `the user ${modPrefix}clicks${target}`;
349
+ case "pointerDown":
350
+ return `the user ${modPrefix}presses${target}`;
351
+ case "dblTap":
352
+ return `the user ${modPrefix}double-taps${target}`;
353
+ case "drag":
354
+ return `the user ${modPrefix}drags${target}`;
355
+ }
356
+ }
357
+ function describeRouteParts(parsed, opts = {}) {
358
+ const { capitalize = true, period = true } = opts;
359
+ const { required, optional } = partitionModifiers(parsed.modifiers);
360
+ const action = actionClause(parsed, required);
361
+ const optClause = optional.length > 0 ? ` (${joinAnd(optional)} optional)` : "";
362
+ const parts = [];
363
+ const head = `fires when ${action}, while `;
364
+ parts.push(capitalize ? head.charAt(0).toUpperCase() + head.slice(1) : head);
365
+ parts.push(...phasesParts(parsed.phases));
366
+ if (optClause) parts.push(optClause);
367
+ if (period) parts.push(".");
368
+ return mergeAdjacentStrings(parts);
369
+ }
370
+ function describeRoute(parsed, opts = {}) {
371
+ return describeRouteParts(parsed, opts).map((p) => typeof p === "string" ? p : p.label).join("");
372
+ }
373
+ function mergeAdjacentStrings(parts) {
374
+ const out = [];
375
+ for (const p of parts) {
376
+ const last = out[out.length - 1];
377
+ if (typeof p === "string" && typeof last === "string") out[out.length - 1] = last + p;
378
+ else out.push(p);
379
+ }
380
+ return out;
381
+ }
382
+
383
+ // src/grammar/modifierComboToParsed.ts
384
+ function modifierComboToParsed(key) {
385
+ if (key === "default") return {};
386
+ const out = {};
387
+ for (const part of key.split("+")) {
388
+ out[part] = "required";
389
+ }
390
+ return out;
391
+ }
392
+ function canonicalModifiers(mods2) {
393
+ return Object.entries(mods2).sort(([a], [b]) => a.localeCompare(b)).map(([name, req]) => `${name}=${req}`).join("&");
394
+ }
395
+
396
+ // src/ui/match.ts
397
+ function resolveSpecValue(value) {
398
+ if (value === true) return "required";
399
+ if (value === "optional") return "optional";
400
+ return "forbidden";
401
+ }
402
+ function matchModifiers(e, mods2, isMac) {
403
+ let alt = "forbidden";
404
+ let ctrl = "forbidden";
405
+ let meta = "forbidden";
406
+ let shift = "forbidden";
407
+ if (mods2) {
408
+ alt = resolveSpecValue(mods2.alt);
409
+ shift = resolveSpecValue(mods2.shift);
410
+ if (mods2.mod !== void 0) {
411
+ const modReq = resolveSpecValue(mods2.mod);
412
+ if (isMac) meta = modReq;
413
+ else ctrl = modReq;
414
+ } else {
415
+ meta = resolveSpecValue(mods2.meta);
416
+ ctrl = resolveSpecValue(mods2.ctrl);
417
+ }
418
+ }
419
+ return checkKey(alt, e.altKey) && checkKey(ctrl, e.ctrlKey) && checkKey(meta, e.metaKey) && checkKey(shift, e.shiftKey);
420
+ }
421
+ function checkKey(req, held) {
422
+ if (req === "required") return held;
423
+ if (req === "forbidden") return !held;
424
+ return true;
425
+ }
426
+ function matchKey(eventKey, specKey) {
427
+ const lower = eventKey.toLowerCase();
428
+ if (Array.isArray(specKey)) {
429
+ return specKey.some((k) => k.toLowerCase() === lower);
430
+ }
431
+ return specKey.toLowerCase() === lower;
432
+ }
433
+ function matchTarget(target, specTarget, bodyTarget) {
434
+ if (specTarget === void 0) return true;
435
+ if (typeof specTarget === "object" && specTarget !== null && "kindOf" in specTarget && typeof specTarget.kindOf === "function") {
436
+ return specTarget.kindOf(target, bodyTarget);
437
+ }
438
+ if (specTarget === "empty" || specTarget === "selected-body" || specTarget === "unselected-body") {
439
+ if (bodyTarget === void 0) return false;
440
+ return bodyTarget === specTarget;
441
+ }
442
+ return false;
443
+ }
444
+ function normalizePhase(spec) {
445
+ if (typeof spec === "string") {
446
+ return [{ channel: "&", phase: spec }];
447
+ }
448
+ return spec;
449
+ }
450
+ function matchPhase(spec, ctx) {
451
+ if (spec === void 0) return true;
452
+ const atoms = normalizePhase(spec);
453
+ if (atoms.length === 0) return true;
454
+ for (const a of atoms) {
455
+ if (matchPhaseAtom(a, ctx)) return true;
456
+ }
457
+ return false;
458
+ }
459
+ function matchPhaseAtom(a, ctx) {
460
+ if (a.channel === "*") {
461
+ if (a.phase === "*") return true;
462
+ const anyEngaged = ctx.engagedChannels.size > 0;
463
+ return a.phase === "engaged" ? anyEngaged : !anyEngaged;
464
+ }
465
+ const id = a.channel === "&" ? ctx.selfChannel : a.channel;
466
+ if (id == null) return false;
467
+ if (a.phase === "*") return true;
468
+ const isEngaged = ctx.engagedChannels.has(id);
469
+ return a.phase === "engaged" ? isEngaged : !isEngaged;
470
+ }
471
+ function mimeMatchesGlob(mime, glob) {
472
+ const m = mime.toLowerCase();
473
+ const g = glob.toLowerCase();
474
+ if (g === "*" || g === "*/*") return true;
475
+ if (g.endsWith("/*")) return m.startsWith(g.slice(0, -1));
476
+ return m === g;
477
+ }
478
+ function matchIngestTypes(items, types) {
479
+ if (!types || types.length === 0) return true;
480
+ return items.some((it) => types.some((g) => mimeMatchesGlob(it.mime, g)));
481
+ }
482
+ function matchSpec(e, spec, isMac, phaseCtx) {
483
+ if (spec.phase !== void 0) {
484
+ const ctx = phaseCtx ?? { selfChannel: null, engagedChannels: EMPTY_ENGAGED };
485
+ if (!matchPhase(spec.phase, ctx)) return false;
486
+ }
487
+ switch (spec.kind) {
488
+ case "key": {
489
+ if (e.kind !== "key") return false;
490
+ if (!matchKey(e.key, spec.key)) return false;
491
+ return matchModifiers(e, spec.mods, isMac);
492
+ }
493
+ case "key-held": {
494
+ if (e.kind !== "key-held") return false;
495
+ if (e.phase !== "down") return false;
496
+ if (!matchKey(e.key, spec.key)) return false;
497
+ return matchModifiers(e, spec.mods, isMac);
498
+ }
499
+ case "wheel": {
500
+ if (e.kind !== "wheel") return false;
501
+ if (!matchModifiers(e, spec.mods, isMac)) return false;
502
+ const direction = spec.direction ?? "*";
503
+ if (direction === "up" && !(e.deltaY < 0)) return false;
504
+ if (direction === "down" && !(e.deltaY > 0)) return false;
505
+ return true;
506
+ }
507
+ case "click": {
508
+ if (e.kind !== "click") return false;
509
+ if (!matchModifiers(e, spec.mods, isMac)) return false;
510
+ return matchTarget(e.target, spec.target, e.bodyTarget);
511
+ }
512
+ case "doubleClick": {
513
+ if (e.kind !== "doubleclick") return false;
514
+ if (!matchModifiers(e, spec.mods, isMac)) return false;
515
+ return matchTarget(e.target, spec.target, e.bodyTarget);
516
+ }
517
+ case "contextMenu": {
518
+ if (e.kind !== "contextmenu") return false;
519
+ if (!matchModifiers(e, spec.mods, isMac)) return false;
520
+ return matchTarget(e.target, spec.target, e.bodyTarget);
521
+ }
522
+ case "drag": {
523
+ if (e.kind !== "pointerdown") return false;
524
+ if (!matchModifiers(e, spec.mods, isMac)) return false;
525
+ return matchTarget(e.affordance, spec.target, e.bodyTarget);
526
+ }
527
+ case "multiTouch": {
528
+ if (e.kind !== "multitouch") return false;
529
+ if (e.fingers !== spec.fingers) return false;
530
+ return matchModifiers(e, spec.mods, isMac);
531
+ }
532
+ case "multiTouchTap": {
533
+ if (e.kind !== "multitouchtap") return false;
534
+ if (e.fingers !== spec.fingers) return false;
535
+ return matchModifiers(e, spec.mods, isMac);
536
+ }
537
+ case "drop": {
538
+ if (e.kind !== "drop") return false;
539
+ if (!matchIngestTypes(e.items, spec.types)) return false;
540
+ return matchModifiers(e, spec.mods, isMac);
541
+ }
542
+ case "paste": {
543
+ if (e.kind !== "paste") return false;
544
+ if (!matchIngestTypes(e.items, spec.types)) return false;
545
+ return matchModifiers(e, spec.mods, isMac);
546
+ }
547
+ default: {
548
+ return false;
549
+ }
550
+ }
551
+ }
552
+ var EMPTY_ENGAGED = /* @__PURE__ */ new Set();
553
+
554
+ export { ACTIVE_SIGILS, GESTURE_DESCRIPTORS, MOD_NAME_SET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, VALID_MOD_NAMES, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, keyRouteToSpec, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, parseKeyRoute, parseRoute };
555
+ //# sourceMappingURL=index.js.map
556
+ //# sourceMappingURL=index.js.map