@weasel-js/gestures 1.9.2 → 1.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +57 -21
- package/dist/index.js +38 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Reflection, matcher, and inspector UI all read this table. Adding a new
|
|
8
8
|
* gesture name in one place updates every consumer.
|
|
9
9
|
*/
|
|
10
|
-
type GestureName = 'click' | 'pointerDown' | 'dblTap' | 'drag' | 'wheel' | 'pinch' | 'keyDown' | 'keyUp' | 'keyHeld' | 'contextMenu' | 'longPress' | 'multiTouchTap' | 'drop' | 'paste';
|
|
10
|
+
type GestureName = 'click' | 'pointerDown' | 'dblTap' | 'drag' | 'wheel' | 'pinch' | 'keyDown' | 'keyUp' | 'keyHeld' | 'contextMenu' | 'longPress' | 'multiTouch' | 'multiTouchTap' | 'drop' | 'paste';
|
|
11
11
|
/**
|
|
12
12
|
* Gesture kinds an affordance claim can bar, in the spec vocabulary bindings
|
|
13
13
|
* are written in. `'pointer'` is one token because `pointerDown` / `click` /
|
|
@@ -32,7 +32,7 @@ interface GestureArgSpec {
|
|
|
32
32
|
interface GestureDescriptor {
|
|
33
33
|
name: GestureName;
|
|
34
34
|
/** Does the route's `.target` slot apply? Targetless gestures (`wheel`,
|
|
35
|
-
* `keyDown/Up`, `multiTouchTap`) elide it entirely in the v2 grammar. */
|
|
35
|
+
* `keyDown/Up`, `multiTouch`, `multiTouchTap`) elide it entirely in the v2 grammar. */
|
|
36
36
|
hasTarget: boolean;
|
|
37
37
|
/** Optional argument spec. Encoded as `gesture(value)` in the route string. */
|
|
38
38
|
arg?: GestureArgSpec;
|
|
@@ -208,11 +208,10 @@ declare function formatRoute(r: ParsedRoute): string;
|
|
|
208
208
|
* `mod` is a platform-aware shorthand: matches `metaKey` on mac, `ctrlKey`
|
|
209
209
|
* elsewhere (mirrors `KeyBinding.mod`).
|
|
210
210
|
*
|
|
211
|
-
*
|
|
211
|
+
* Every modifier additionally accepts `'optional'`, meaning "held or not,
|
|
212
212
|
* both acceptable" — the explicit opt-in for loose matching, used by
|
|
213
213
|
* actions like nudge whose step size depends on shift but whose firing
|
|
214
|
-
* does not.
|
|
215
|
-
* a real consumer needs it.
|
|
214
|
+
* does not.
|
|
216
215
|
*/
|
|
217
216
|
type ModSpec = Partial<{
|
|
218
217
|
alt: boolean | 'optional';
|
|
@@ -221,18 +220,28 @@ type ModSpec = Partial<{
|
|
|
221
220
|
mod: boolean | 'optional';
|
|
222
221
|
shift: boolean | 'optional';
|
|
223
222
|
}>;
|
|
224
|
-
/** The predicate form of {@link TargetSpec}. `hit` is the
|
|
225
|
-
*
|
|
223
|
+
/** The predicate form of {@link TargetSpec}. `hit` is the affordance hit
|
|
224
|
+
* under the pointer, for every gesture kind; `bodyTarget` is the optional
|
|
226
225
|
* body-class string ('empty' | 'selected-body' | 'unselected-body') when
|
|
227
|
-
* `classifyTarget` is wired.
|
|
228
|
-
*
|
|
226
|
+
* `classifyTarget` is wired. Build one with `hitPredicate` or
|
|
227
|
+
* `bodyPredicate`, which make the declaration below. */
|
|
229
228
|
interface TargetPredicate {
|
|
230
229
|
(hit: unknown, bodyTarget?: string): boolean;
|
|
231
|
-
/**
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
readsAffordance
|
|
230
|
+
/** Whether the predicate reads `hit`. An exclusive affordance claim bars
|
|
231
|
+
* every binding whose target does not: `false` is a predicate that decides
|
|
232
|
+
* from `bodyTarget` alone, and chrome over a body must not read as that body. */
|
|
233
|
+
readsAffordance: boolean;
|
|
235
234
|
}
|
|
235
|
+
/** A {@link TargetPredicate} that reads the affordance hit, alone or with the
|
|
236
|
+
* body class, so it stays in contention under an exclusive claim. */
|
|
237
|
+
declare function hitPredicate(fn: (hit: unknown, bodyTarget?: string) => boolean): TargetPredicate & {
|
|
238
|
+
readsAffordance: true;
|
|
239
|
+
};
|
|
240
|
+
/** A {@link TargetPredicate} that decides from the body class alone, so an
|
|
241
|
+
* exclusive affordance claim bars it. */
|
|
242
|
+
declare function bodyPredicate(fn: (bodyTarget: string | undefined) => boolean): TargetPredicate & {
|
|
243
|
+
readsAffordance: false;
|
|
244
|
+
};
|
|
236
245
|
/** Target selector for click and drag gesture specs. String forms are sugar
|
|
237
246
|
* for the kit-owned object-kind registry (TODO.md Tier 1 follow-up); until
|
|
238
247
|
* that ships, consumers can pass `{ kindOf: predicate }` to classify hits
|
|
@@ -264,6 +273,11 @@ interface KeySpec {
|
|
|
264
273
|
kind: 'key';
|
|
265
274
|
/** A single key, or an array of acceptable keys (case-insensitive match). */
|
|
266
275
|
key: string | string[];
|
|
276
|
+
/** The physical key, as `KeyboardEvent.code` (`'BracketRight'`), or several.
|
|
277
|
+
* Tried before `key`, and either matching is enough: the binding then holds
|
|
278
|
+
* on that key whatever a layout or a held modifier makes it type, and still
|
|
279
|
+
* on any key that types `key`. `key` is what a route names the binding by. */
|
|
280
|
+
code?: string | string[];
|
|
267
281
|
mods?: ModSpec;
|
|
268
282
|
phase?: PhaseSpec;
|
|
269
283
|
}
|
|
@@ -273,6 +287,8 @@ interface KeyHeldSpec {
|
|
|
273
287
|
kind: 'key-held';
|
|
274
288
|
/** A single key, or an array of acceptable keys (case-insensitive match). */
|
|
275
289
|
key: string | string[];
|
|
290
|
+
/** The physical key or keys, as on {@link KeySpec.code}. */
|
|
291
|
+
code?: string | string[];
|
|
276
292
|
mods?: ModSpec;
|
|
277
293
|
phase?: PhaseSpec;
|
|
278
294
|
}
|
|
@@ -307,7 +323,7 @@ interface ClickSpec {
|
|
|
307
323
|
mods?: ModSpec;
|
|
308
324
|
phase?: PhaseSpec;
|
|
309
325
|
}
|
|
310
|
-
/** Double-click: two `click` events within
|
|
326
|
+
/** Double-click: two `click` events within 600ms and 8px of each other.
|
|
311
327
|
* Synthesized by `useGestureDispatcher`; emitted AFTER the second
|
|
312
328
|
* `click`. Bindings that want to handle a double-click should declare
|
|
313
329
|
* this kind rather than chasing two `click` events. */
|
|
@@ -379,8 +395,9 @@ interface MultiTouchSpec {
|
|
|
379
395
|
phase?: PhaseSpec;
|
|
380
396
|
}
|
|
381
397
|
/** Multi-touch tap gesture — fires when N fingers touch down then release
|
|
382
|
-
* together without movement past the tap threshold
|
|
383
|
-
* dispatcher from the underlying multitouch
|
|
398
|
+
* together without movement past the tap threshold, sooner than a long-press
|
|
399
|
+
* would fire. Synthesized by the dispatcher from the underlying multitouch
|
|
400
|
+
* tracking. */
|
|
384
401
|
interface MultiTouchTapSpec {
|
|
385
402
|
kind: 'multiTouchTap';
|
|
386
403
|
fingers: number;
|
|
@@ -475,8 +492,8 @@ declare const ROUTE_TERMS: {
|
|
|
475
492
|
* means without duplicating prose. */
|
|
476
493
|
declare const ROUTE_FIELD_DEFINITIONS: {
|
|
477
494
|
readonly 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.";
|
|
478
|
-
readonly gesture: "The class of input event that triggers this route — click, drag, double-tap, keyDown/keyUp, wheel, pinch, contextMenu, multiTouchTap, drop, or paste.";
|
|
479
|
-
readonly arg: "Sub-class of the gesture. Direction for wheel (up / down / *) and pinch (in / out / *), key name for keyDown / keyUp, finger count for multiTouchTap, MIME glob for drop / paste. Other gestures have no arg slot.";
|
|
495
|
+
readonly gesture: "The class of input event that triggers this route — click, drag, double-tap, keyDown/keyUp, wheel, pinch, contextMenu, multiTouch, multiTouchTap, drop, or paste.";
|
|
496
|
+
readonly arg: "Sub-class of the gesture. Direction for wheel (up / down / *) and pinch (in / out / *), key name for keyDown / keyUp, finger count for multiTouch / multiTouchTap, MIME glob for drop / paste. Other gestures have no arg slot.";
|
|
480
497
|
readonly 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.";
|
|
481
498
|
readonly modifiers: "Modifier keys the user must hold (`+key`) or may optionally hold (`?key`) for this route to match. Unlisted modifiers must not be held.";
|
|
482
499
|
};
|
|
@@ -571,12 +588,16 @@ interface BodyClassification {
|
|
|
571
588
|
interface KeyEvent extends EventModifiers {
|
|
572
589
|
kind: 'key';
|
|
573
590
|
key: string;
|
|
591
|
+
/** `KeyboardEvent.code`, when the source event had one. */
|
|
592
|
+
code?: string;
|
|
574
593
|
repeat?: boolean;
|
|
575
594
|
}
|
|
576
595
|
/** A held key transitioning down or up (e.g. space-to-pan). */
|
|
577
596
|
interface KeyHeldEvent extends EventModifiers {
|
|
578
597
|
kind: 'key-held';
|
|
579
598
|
key: string;
|
|
599
|
+
/** `KeyboardEvent.code`, when the source event had one. */
|
|
600
|
+
code?: string;
|
|
580
601
|
phase: 'down' | 'up';
|
|
581
602
|
}
|
|
582
603
|
/** A scroll-wheel / trackpad scroll, with raw deltas and client coords. */
|
|
@@ -812,6 +833,12 @@ interface MultiTouchEvent extends EventModifiers {
|
|
|
812
833
|
* event.
|
|
813
834
|
*/
|
|
814
835
|
spread?: number;
|
|
836
|
+
/**
|
|
837
|
+
* Set on the event that ends the running multitouch gesture, whatever its
|
|
838
|
+
* finger count: `'commit'` when a finger lifts, `'cancel'` when one of its
|
|
839
|
+
* pointers is canceled. Such an event starts nothing.
|
|
840
|
+
*/
|
|
841
|
+
end?: 'commit' | 'cancel';
|
|
815
842
|
}
|
|
816
843
|
/** A multi-finger tap (no drag). */
|
|
817
844
|
interface MultiTouchTapEvent extends EventModifiers {
|
|
@@ -1006,11 +1033,20 @@ declare function matchIngestTypes(items: readonly {
|
|
|
1006
1033
|
*
|
|
1007
1034
|
* For `key-held`, only `phase: 'down'` returns true. The dispatcher tracks the
|
|
1008
1035
|
* held state independently and handles `phase: 'up'` itself.
|
|
1009
|
-
*
|
|
1010
|
-
* For TargetSpec string forms, returns false (kind registry not yet available).
|
|
1011
1036
|
*/
|
|
1012
1037
|
declare function matchSpec(e: InputEvent, spec: GestureSpec, isMac: boolean, phaseCtx?: PhaseContext): boolean;
|
|
1013
1038
|
|
|
1039
|
+
/**
|
|
1040
|
+
* Whether this is an Apple platform, where `mod` means the Command key and
|
|
1041
|
+
* not Ctrl. iPhone and iPad count: with a keyboard attached their shortcuts
|
|
1042
|
+
* are Command shortcuts. False where there is no `navigator`.
|
|
1043
|
+
*
|
|
1044
|
+
* Pass the answer to {@link matchModifiers} / {@link matchSpec} as `isMac`,
|
|
1045
|
+
* and read it wherever a `mod` shortcut is drawn, so a label names the key
|
|
1046
|
+
* the matcher listens for.
|
|
1047
|
+
*/
|
|
1048
|
+
declare function isApplePlatform(): boolean;
|
|
1049
|
+
|
|
1014
1050
|
/** CSS-style specificity tuple for a GestureSpec. Higher tuple wins under
|
|
1015
1051
|
* lexicographic compare. Dimensions, in order of precedence:
|
|
1016
1052
|
*
|
|
@@ -1052,4 +1088,4 @@ declare const CONTROL_SELECTOR: string;
|
|
|
1052
1088
|
*/
|
|
1053
1089
|
declare function isInControlWithin(target: EventTarget | null, host: Element): boolean;
|
|
1054
1090
|
|
|
1055
|
-
export { ACTIVE_SIGILS, type BodyClassification, type BodyKind, type BodyTarget, CONTROL_SELECTOR, type ChannelRef, type ClaimableGesture, type ClickEvent, type ClickSpec, type ContextMenuEvent, type ContextMenuSpec, DRAG_THRESHOLD_PX, type DescribeRouteOptions, type DoubleClickEvent, type DoubleClickSpec, type DragSpec, type DropEvent, type DropSpec, type EventModifiers, GESTURE_DESCRIPTORS, type GestureArgSpec, type GestureDescriptor, type GestureName, type GestureSpec, type IngestItem, type InputEvent, type KeyEvent, type KeyHeldEvent, type KeyHeldSpec, type KeySpec, type LongPressEvent, type LongPressSpec, MOD_NAME_SET, type ModRequirement, type ModSpec, type ModifierCombo, type ModifierKey, type ModifiersEvent, type MultiTouchEvent, type MultiTouchSpec, type MultiTouchTapEvent, type MultiTouchTapSpec, type OptionalMod, type ParsedKeyRoute, type ParsedModifiers, type ParsedRoute, type PasteEvent, type PasteSpec, type PhaseAtom, type PhaseContext, type PhaseSpec, type PinchEvent, type PinchSpec, type PointerCancelEvent, type PointerDownEvent, type PointerDownSpec, type PointerIdentity, type PointerMoveEvent, type PointerSampleStylus, type PointerUpEvent, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, type RouteDescriptionPart, type RouteFieldName, type RoutePhase, type RouteTermLabel, type TargetPredicate, type TargetSpec, type TargetSpecForm, VALID_MOD_NAMES, type WheelEvent, type WheelSpec, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, isInControlWithin, isKnownGestureName, keyRouteToSpec, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity };
|
|
1091
|
+
export { ACTIVE_SIGILS, type BodyClassification, type BodyKind, type BodyTarget, CONTROL_SELECTOR, type ChannelRef, type ClaimableGesture, type ClickEvent, type ClickSpec, type ContextMenuEvent, type ContextMenuSpec, DRAG_THRESHOLD_PX, type DescribeRouteOptions, type DoubleClickEvent, type DoubleClickSpec, type DragSpec, type DropEvent, type DropSpec, type EventModifiers, GESTURE_DESCRIPTORS, type GestureArgSpec, type GestureDescriptor, type GestureName, type GestureSpec, type IngestItem, type InputEvent, type KeyEvent, type KeyHeldEvent, type KeyHeldSpec, type KeySpec, type LongPressEvent, type LongPressSpec, MOD_NAME_SET, type ModRequirement, type ModSpec, type ModifierCombo, type ModifierKey, type ModifiersEvent, type MultiTouchEvent, type MultiTouchSpec, type MultiTouchTapEvent, type MultiTouchTapSpec, type OptionalMod, type ParsedKeyRoute, type ParsedModifiers, type ParsedRoute, type PasteEvent, type PasteSpec, type PhaseAtom, type PhaseContext, type PhaseSpec, type PinchEvent, type PinchSpec, type PointerCancelEvent, type PointerDownEvent, type PointerDownSpec, type PointerIdentity, type PointerMoveEvent, type PointerSampleStylus, type PointerUpEvent, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, type RouteDescriptionPart, type RouteFieldName, type RoutePhase, type RouteTermLabel, type TargetPredicate, type TargetSpec, type TargetSpecForm, VALID_MOD_NAMES, type WheelEvent, type WheelSpec, bodyPredicate, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, hitPredicate, isApplePlatform, isInControlWithin, isKnownGestureName, keyRouteToSpec, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity };
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var GESTURE_DESCRIPTORS = [
|
|
|
11
11
|
{ name: "keyHeld", hasTarget: false, arg: { name: "key", values: "free" } },
|
|
12
12
|
{ name: "contextMenu", hasTarget: true },
|
|
13
13
|
{ name: "longPress", hasTarget: true },
|
|
14
|
+
{ name: "multiTouch", hasTarget: false, arg: { name: "fingers", values: ["2", "3", "4"] } },
|
|
14
15
|
{ name: "multiTouchTap", hasTarget: false, arg: { name: "fingers", values: ["2", "3", "4"] } },
|
|
15
16
|
// The arg is the MIME-glob filter. No default: a spec with no `types`
|
|
16
17
|
// matches any payload, which is what an omitted arg slot means for a
|
|
@@ -307,6 +308,10 @@ function matchKey(eventKey, specKey) {
|
|
|
307
308
|
}
|
|
308
309
|
return specKey.toLowerCase() === lower;
|
|
309
310
|
}
|
|
311
|
+
function matchKeyOrCode(e, spec) {
|
|
312
|
+
if (spec.code !== void 0 && e.code !== void 0 && [spec.code].flat().includes(e.code)) return true;
|
|
313
|
+
return matchKey(e.key, spec.key);
|
|
314
|
+
}
|
|
310
315
|
function affordanceKindOf(target) {
|
|
311
316
|
if (typeof target !== "object" || target === null) return void 0;
|
|
312
317
|
const k = target.kind;
|
|
@@ -342,8 +347,7 @@ function matchTarget(target, specTarget, bodyTarget, bodyKind) {
|
|
|
342
347
|
const form = parseTargetSpec(specTarget);
|
|
343
348
|
if (form === null) return false;
|
|
344
349
|
switch (form.form) {
|
|
345
|
-
// Receives the
|
|
346
|
-
// plus the bodyTarget classification.
|
|
350
|
+
// Receives the affordance hit plus the bodyTarget classification.
|
|
347
351
|
case "predicate":
|
|
348
352
|
return form.kindOf(target, bodyTarget);
|
|
349
353
|
// Resolved from the `classifyTarget` result packed into the event's
|
|
@@ -406,13 +410,13 @@ function matchSpec(e, spec, isMac, phaseCtx) {
|
|
|
406
410
|
switch (spec.kind) {
|
|
407
411
|
case "key": {
|
|
408
412
|
if (e.kind !== "key") return false;
|
|
409
|
-
if (!
|
|
413
|
+
if (!matchKeyOrCode(e, spec)) return false;
|
|
410
414
|
return matchModifiers(e, spec.mods, isMac);
|
|
411
415
|
}
|
|
412
416
|
case "key-held": {
|
|
413
417
|
if (e.kind !== "key-held") return false;
|
|
414
418
|
if (e.phase !== "down") return false;
|
|
415
|
-
if (!
|
|
419
|
+
if (!matchKeyOrCode(e, spec)) return false;
|
|
416
420
|
return matchModifiers(e, spec.mods, isMac);
|
|
417
421
|
}
|
|
418
422
|
case "wheel": {
|
|
@@ -501,7 +505,7 @@ var SPEC_KIND_TO_GESTURE = {
|
|
|
501
505
|
longPress: "longPress",
|
|
502
506
|
drag: "drag",
|
|
503
507
|
pointerDown: "pointerDown",
|
|
504
|
-
multiTouch:
|
|
508
|
+
multiTouch: "multiTouch",
|
|
505
509
|
multiTouchTap: "multiTouchTap",
|
|
506
510
|
drop: "drop",
|
|
507
511
|
paste: "paste"
|
|
@@ -567,14 +571,13 @@ function routeToSpec(parsed) {
|
|
|
567
571
|
for (const m of optionalMods) optional[m] = "optional";
|
|
568
572
|
return withMods({ kind, key, ...optionalMods.length > 0 ? { mods: optional } : {} });
|
|
569
573
|
}
|
|
574
|
+
case "multiTouch":
|
|
570
575
|
case "multiTouchTap":
|
|
571
|
-
if (arg === void 0) return fail(
|
|
576
|
+
if (arg === void 0) return fail(`a ${kind} spec needs concrete fingers`);
|
|
572
577
|
return withMods({ kind, fingers: Number(arg) });
|
|
573
578
|
case "drop":
|
|
574
579
|
case "paste":
|
|
575
580
|
return withMods({ kind, ...arg ? { types: arg.split("|") } : {} });
|
|
576
|
-
case "multiTouch":
|
|
577
|
-
return fail("multiTouch has no route gesture");
|
|
578
581
|
}
|
|
579
582
|
}
|
|
580
583
|
|
|
@@ -593,8 +596,8 @@ var ROUTE_TERMS = {
|
|
|
593
596
|
};
|
|
594
597
|
var ROUTE_FIELD_DEFINITIONS = {
|
|
595
598
|
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.",
|
|
596
|
-
gesture: "The class of input event that triggers this route \u2014 click, drag, double-tap, keyDown/keyUp, wheel, pinch, contextMenu, multiTouchTap, drop, or paste.",
|
|
597
|
-
arg: "Sub-class of the gesture. Direction for wheel (up / down / *) and pinch (in / out / *), key name for keyDown / keyUp, finger count for multiTouchTap, MIME glob for drop / paste. Other gestures have no arg slot.",
|
|
599
|
+
gesture: "The class of input event that triggers this route \u2014 click, drag, double-tap, keyDown/keyUp, wheel, pinch, contextMenu, multiTouch, multiTouchTap, drop, or paste.",
|
|
600
|
+
arg: "Sub-class of the gesture. Direction for wheel (up / down / *) and pinch (in / out / *), key name for keyDown / keyUp, finger count for multiTouch / multiTouchTap, MIME glob for drop / paste. Other gestures have no arg slot.",
|
|
598
601
|
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.",
|
|
599
602
|
modifiers: "Modifier keys the user must hold (`+key`) or may optionally hold (`?key`) for this route to match. Unlisted modifiers must not be held."
|
|
600
603
|
};
|
|
@@ -666,6 +669,8 @@ function actionClause(parsed, required) {
|
|
|
666
669
|
const direction = arg === "in" ? " in" : arg === "out" ? " out" : "";
|
|
667
670
|
return userDoes(required, `pinches${direction}${target}`);
|
|
668
671
|
}
|
|
672
|
+
case "multiTouch":
|
|
673
|
+
return userDoes(required, `touches with ${arg ?? "multiple"} fingers`);
|
|
669
674
|
case "multiTouchTap":
|
|
670
675
|
return userDoes(required, `taps with ${arg ?? "multiple"} fingers`);
|
|
671
676
|
case "contextMenu":
|
|
@@ -725,6 +730,28 @@ function canonicalModifiers(mods2) {
|
|
|
725
730
|
return Object.entries(mods2).sort(([a], [b]) => a.localeCompare(b)).map(([name, req]) => `${name}=${req}`).join("&");
|
|
726
731
|
}
|
|
727
732
|
|
|
733
|
+
// src/ui/spec.ts
|
|
734
|
+
function hitPredicate(fn) {
|
|
735
|
+
return Object.assign(
|
|
736
|
+
(hit, bodyTarget) => fn(hit, bodyTarget),
|
|
737
|
+
{ readsAffordance: true }
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
function bodyPredicate(fn) {
|
|
741
|
+
return Object.assign(
|
|
742
|
+
(_hit, bodyTarget) => fn(bodyTarget),
|
|
743
|
+
{ readsAffordance: false }
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// src/ui/platform.ts
|
|
748
|
+
function isApplePlatform() {
|
|
749
|
+
if (typeof navigator === "undefined" || !navigator) return false;
|
|
750
|
+
const nav = navigator;
|
|
751
|
+
const raw = nav.userAgentData?.platform || nav.platform || nav.userAgent || "";
|
|
752
|
+
return /mac|iphone|ipad|ipod/i.test(raw);
|
|
753
|
+
}
|
|
754
|
+
|
|
728
755
|
// src/ui/specificity.ts
|
|
729
756
|
function modsCount(mods2) {
|
|
730
757
|
if (!mods2) return 0;
|
|
@@ -804,6 +831,6 @@ function isInControlWithin(target, host) {
|
|
|
804
831
|
return control !== null && control !== host && host.contains(control);
|
|
805
832
|
}
|
|
806
833
|
|
|
807
|
-
export { ACTIVE_SIGILS, CONTROL_SELECTOR, DRAG_THRESHOLD_PX, 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, isInControlWithin, isKnownGestureName, keyRouteToSpec, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity };
|
|
834
|
+
export { ACTIVE_SIGILS, CONTROL_SELECTOR, DRAG_THRESHOLD_PX, GESTURE_DESCRIPTORS, MOD_NAME_SET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, VALID_MOD_NAMES, bodyPredicate, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, hitPredicate, isApplePlatform, isInControlWithin, isKnownGestureName, keyRouteToSpec, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity };
|
|
808
835
|
//# sourceMappingURL=index.js.map
|
|
809
836
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/grammar/gestures.ts","../src/grammar/modifiers.ts","../src/grammar/routeGrammar.ts","../src/grammar/keyRouteGrammar.ts","../src/ui/match.ts","../src/grammar/specKinds.ts","../src/grammar/routeToSpec.ts","../src/grammar/describeRoute.ts","../src/grammar/modifierComboToParsed.ts","../src/ui/specificity.ts","../src/ui/dragThreshold.ts","../src/ui/controlTarget.ts"],"names":["phase","mods","MOD_ORDER"],"mappings":";AAmEO,IAAM,mBAAA,GAAoD;AAAA,EAC/D,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,aAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,QAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,MAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,IAAA,EAAO,KAAK,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,CAAC,IAAA,EAAM,MAAA,EAAQ,GAAG,CAAA,EAAG,OAAA,EAAS,KAAI,EAAE;AAAA,EACjH,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,IAAA,EAAO,KAAK,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,CAAC,IAAA,EAAM,KAAA,EAAO,GAAG,CAAA,EAAG,OAAA,EAAS,KAAI,EAAE;AAAA,EAChH,EAAE,IAAA,EAAM,SAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,KAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,KAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,SAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,KAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,aAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,WAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,eAAA,EAAiB,SAAA,EAAW,OAAO,GAAA,EAAK,EAAE,IAAA,EAAM,SAAA,EAAa,QAAQ,CAAC,GAAA,EAAK,GAAA,EAAK,GAAG,GAAE,EAAE;AAAA;AAAA;AAAA;AAAA,EAI/F,EAAE,IAAA,EAAM,MAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,OAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,OAAA,EAAa,MAAA,EAAQ,MAAA,EAAO;AACtF;AAEA,IAAM,UAAU,IAAI,GAAA;AAAA,EAClB,mBAAA,CAAoB,IAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,IAAA,EAAM,CAAC,CAAC;AAC5C,CAAA;AAIO,SAAS,qBAAqB,IAAA,EAAsC;AACzE,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AAC1B,EAAA,IAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,IAAI,CAAA,CAAE,CAAA;AAClD,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,mBAAmB,IAAA,EAAmC;AACpE,EAAA,OAAO,OAAA,CAAQ,IAAI,IAAI,CAAA;AACzB;;;ACpFO,SAAS,QACX,IAAA,EACY;AACf,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,SAAA;AAC9B,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAI,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,GAAA,CAAI,GAAA,CAAI,KAAK,CAAA,IAAO,KAAA;AAAA,IACpB,GAAA,CAAI,GAAA,CAAI,OAAO,CAAA,IAAK,OAAA;AAAA,IACpB,GAAA,CAAI,GAAA,CAAI,KAAK,CAAA,IAAO;AAAA,GACtB,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AAC5B;;;ACqBO,IAAM,oBAAA,uBAAgD,GAAA,CAAI;AAAA,EAC/D,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK;AACrC,CAAC;AAKM,IAAM,iBAAA,uBAA6C,GAAA,CAAI;AAAA,EAC5D,SAAA;AAAA,EAAW;AACb,CAAC;AAWM,IAAM,kBAAkB,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,QAAQ,MAAM;AAY9D,IAAM,eAAA,mBAAuC,IAAI,GAAA,CAAI,CAAC,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAC;AAGxF,IAAM,gCAAqC,IAAI,GAAA,CAAI,CAAC,GAAA,EAAK,GAAG,CAAC;AAIpE,IAAM,YAAA,GAAoC,IAAI,GAAA,CAAI,eAAe;AA2B1D,SAAS,WAAW,KAAA,EAA4B;AAErD,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yCAAA,EAA4C,KAAK,CAAA,CAAE,CAAA;AAAA,EACrE;AACA,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AACpC,EAAA,IAAI,WAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,KAAK,CAAA,CAAE,CAAA;AACpF,EAAA,MAAM,eAAe,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,QAAQ,EAAE,IAAA,EAAK;AACrD,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,YAAA,EAAc,KAAK,CAAA;AACjD,EAAA,IAAI,OAAO,OAAA,CAAQ,KAAA,CAAM,QAAA,GAAW,CAAC,EAAE,IAAA,EAAK;AAG5C,EAAA,MAAM,YAAA,GAAe,cAAA,CAAe,IAAA,CAAK,IAAI,CAAA;AAC7C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAK,CAAA,CAAE,CAAA;AAC9E,EAAA,MAAM,WAAA,GAAc,aAAa,CAAC,CAAA;AAClC,EAAA,IAAI,CAAC,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACpC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,WAAW,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EAC9E;AACA,EAAA,IAAA,GAAO,KAAK,KAAA,CAAM,YAAA,CAAa,CAAC,CAAA,CAAE,MAAM,EAAE,SAAA,EAAU;AACpD,EAAA,MAAM,IAAA,GAAO,qBAAqB,WAAW,CAAA;AAG7C,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,EAAG;AACxB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACjC,IAAA,IAAI,WAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,uCAAA,EAA0C,KAAK,CAAA,CAAE,CAAA;AACnF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA;AACrC,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,EAAK,MAAM,IAAI,MAAM,CAAA,eAAA,EAAkB,WAAW,CAAA,cAAA,EAAiB,KAAK,CAAA,CAAE,CAAA;AACpF,IAAA,IAAI,MAAA,KAAW,GAAA,IAAO,IAAA,CAAK,GAAA,CAAI,MAAA,KAAW,MAAA,IAAU,CAAC,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,EAAG;AACrF,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,MAAM,CAAA,SAAA,EAAY,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,GAAG,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAA;AAAA,IAC7F;AACA,IAAA,GAAA,GAAM,MAAA;AACN,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAA,GAAW,CAAC,EAAE,SAAA,EAAU;AAAA,EAC5C,CAAA,MAAA,IAAW,KAAK,GAAA,EAAK;AACnB,IAAA,GAAA,GAAM,IAAA,CAAK,IAAI,OAAA,IAAW,GAAA;AAAA,EAC5B;AAGA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA,EAAG;AACzB,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA,EAAW,MAAM,IAAI,MAAM,CAAA,eAAA,EAAkB,WAAW,CAAA,iBAAA,EAAoB,KAAK,CAAA,CAAE,CAAA;AAC7F,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,SAAA,EAAU;AAC/B,IAAA,MAAM,QAAA,GAAW,oBAAA,CAAqB,IAAA,CAAK,IAAI,CAAA;AAC/C,IAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,KAAK,CAAA,CAAE,CAAA;AACpF,IAAA,MAAA,GAAS,SAAS,CAAC,CAAA;AACnB,IAAA,IAAA,GAAO,KAAK,KAAA,CAAM,QAAA,CAAS,CAAC,CAAA,CAAE,MAAM,EAAE,SAAA,EAAU;AAAA,EAClD,CAAA,MAAA,IAAW,KAAK,SAAA,EAAW;AACzB,IAAA,MAAA,GAAS,GAAA;AAAA,EACX;AAGA,EAAA,MAAM,YAA6B,EAAC;AACpC,EAAA,OAAO,IAAA,CAAK,SAAS,CAAA,EAAG;AACtB,IAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,IAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,EAAE,CAAA,EAAG;AAC3B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,EAAE,CAAA,+BAAA,EAAkC,KAAK,CAAA,CAAE,CAAA;AAAA,IAChF;AACA,IAAA,IAAI,CAAC,aAAA,CAAc,GAAA,CAAI,EAAE,CAAA,EAAG;AAC1B,MAAA,MAAM,IAAI,MAAM,CAAA,2BAAA,EAA8B,EAAE,SAAS,IAAI,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAC7E;AACA,IAAA,MAAM,KAAA,GAAQ,EAAA;AACd,IAAA,IAAA,GAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AACnB,IAAA,MAAM,SAAA,GAAY,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA;AACvC,IAAA,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,CAAA,sBAAA,EAAyB,KAAK,CAAA,0BAAA,EAA6B,KAAK,CAAA,CAAE,CAAA;AAClG,IAAA,MAAM,IAAA,GAAO,UAAU,CAAC,CAAA;AACxB,IAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AAC3B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,IAAI,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IACxE;AACA,IAAA,IAAI,SAAA,CAAU,IAAmB,CAAA,KAAM,MAAA,EAAW;AAChD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,IAAI,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1E;AACA,IAAA,SAAA,CAAU,IAAmB,CAAA,GAAI,KAAA,KAAU,GAAA,GAAM,UAAA,GAAa,UAAA;AAC9D,IAAA,IAAA,GAAO,KAAK,KAAA,CAAM,SAAA,CAAU,CAAC,CAAA,CAAE,MAAM,EAAE,SAAA,EAAU;AAAA,EACnD;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,WAAA,EAAa,GAAA,EAAK,QAAQ,SAAA,EAAU;AAChE;AAEA,SAAS,cAAA,CAAe,KAAa,KAAA,EAAqC;AACxE,EAAA,IAAI,QAAQ,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,KAAK,CAAA,CAAE,CAAA;AAC5E,EAAA,MAAM,SAAS,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAC7E,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,KAAK,CAAA,CAAE,CAAA;AACrF,EAAA,OAAO,OAAO,GAAA,CAAI,CAAC,MAAM,cAAA,CAAe,CAAA,EAAG,KAAK,CAAC,CAAA;AACnD;AAEA,IAAM,+BAAoC,IAAI,GAAA,CAAI,CAAC,SAAA,EAAW,SAAA,EAAW,GAAG,CAAC,CAAA;AAE7E,SAAS,cAAA,CAAe,KAAa,KAAA,EAA0B;AAG7D,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,GAAG,CAAA,qBAAA,EAAwB,KAAK,CAAA,CAAE,CAAA;AAAA,EAClF;AACA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,MAAMA,MAAAA,GAAQ,MAAM,CAAC,CAAA;AACrB,IAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAIA,MAAK,CAAA,EAAG;AAC5B,MAAA,MAAM,IAAI,MAAM,CAAA,8BAAA,EAAiCA,MAAK,SAAS,GAAG,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAClF;AACA,IAAA,OAAO,EAAE,OAAA,EAAS,GAAA,EAAK,KAAA,EAAOA,MAAAA,EAA4B;AAAA,EAC5D;AAEA,EAAA,MAAM,OAAA,GAAU,MAAM,CAAC,CAAA;AACvB,EAAA,MAAM,KAAA,GAAQ,MAAM,CAAC,CAAA;AACrB,EAAA,IAAI,YAAY,EAAA,EAAI;AAClB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,GAAG,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EAClF;AACA,EAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,MAAM,CAAA,8BAAA,EAAiC,KAAK,SAAS,GAAG,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EAClF;AACA,EAAA,IAAI,OAAA,KAAY,GAAA,IAAO,OAAA,KAAY,GAAA,EAAK;AAItC,IAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,OAAO,CAAA,EAAG;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,OAAO,CAAA,gCAAA,EAAmC,KAAK,CAAA,CAAE,CAAA;AAAA,IAC9F;AACA,IAAA,IAAI,oBAAA,CAAqB,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAE,CAAA,EAAG;AACzC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,OAAO,CAAA,8BAAA,EAAiC,QAAQ,CAAC,CAAC,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAC7G;AAAA,EACF;AACA,EAAA,OAAO,EAAE,SAAS,KAAA,EAAmC;AACvD;AAKO,SAAS,gBAAgB,CAAA,EAAsB;AACpD,EAAA,IAAI,CAAA,CAAE,OAAA,KAAY,GAAA,EAAK,OAAO,CAAA,CAAE,KAAA;AAChC,EAAA,OAAO,CAAA,EAAG,CAAA,CAAE,OAAO,CAAA,CAAA,EAAI,EAAE,KAAK,CAAA,CAAA;AAChC;AAiBO,SAAS,mBAAmB,MAAA,EAAqC;AACtE,EAAA,IAAI,OAAO,MAAA,GAAS,CAAA,EAAG,OAAO,CAAC,GAAG,MAAM,CAAA;AACxC,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAA,EAAK,CAAA,EAAG,CAAA,EAAG,UAAA,CAAW,CAAC,CAAA,EAAE,CAAE,CAAA;AAC/D,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,IAAI,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,EAAG;AACrB,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAElB,IAAA,IAAI,SAAA,GAAY,EAAA;AAChB,IAAA,KAAA,IAAS,IAAI,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AAC1C,MAAA,IAAI,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,EAAG;AACrB,MAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,MAAA,IAAI,WAAA,CAAY,CAAA,CAAE,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,EAAG;AAAE,QAAA,SAAA,GAAY,CAAA;AAAG,QAAA;AAAA,MAAO;AAAA,IACrD;AACA,IAAA,IAAI,YAAY,CAAA,EAAG;AAAE,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,GAAG,CAAA;AAAG,MAAA;AAAA,IAAU;AAChD,IAAA,QAAA,CAAS,IAAI,SAAS,CAAA;AAEtB,IAAA,MAAM,MAAA,GAAsB;AAAA,MAC1B,GAAG,CAAA,CAAE,CAAA;AAAA,MACL,SAAA,EAAW,EAAE,GAAG,YAAA,CAAa,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,KAAA,EAAO,UAAA;AAAW,KACjE;AACA,IAAA,GAAA,CAAI,IAAA,CAAK,WAAA,CAAY,MAAM,CAAC,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,WAAA,CAAY,GAAgB,CAAA,EAAyB;AAC5D,EAAA,IAAI,CAAA,CAAE,OAAA,KAAY,CAAA,CAAE,OAAA,EAAS,OAAO,KAAA;AACpC,EAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,CAAA,CAAE,GAAA,EAAK,OAAO,KAAA;AAC5B,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,EAAA,IAAI,CAAC,UAAA,CAAW,CAAA,CAAE,QAAQ,CAAA,CAAE,MAAM,GAAG,OAAO,KAAA;AAE5C,EAAA,MAAM,MAAA,GAAS,EAAE,SAAA,CAAU,KAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,EAAE,SAAA,CAAU,KAAA;AAC3B,EAAA,MAAM,OAAO,MAAA,KAAW,UAAA;AACxB,EAAA,MAAM,OAAO,MAAA,KAAW,UAAA;AACxB,EAAA,IAAI,EAAE,IAAA,KAAS,IAAA,CAAA,EAAO,OAAO,KAAA;AAC7B,EAAA,IAAI,MAAA,KAAW,UAAA,IAAc,MAAA,KAAW,UAAA,EAAY,OAAO,KAAA;AAE3D,EAAA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAClC,IAAA,IAAI,SAAS,OAAA,EAAS;AACtB,IAAA,IAAI,CAAA,CAAE,UAAU,IAAI,CAAA,KAAM,EAAE,SAAA,CAAU,IAAI,GAAG,OAAO,KAAA;AAAA,EACtD;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,UAAA,CACP,GACA,CAAA,EACS;AACT,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK;AACjC,IAAA,IAAI,EAAE,CAAC,CAAA,CAAG,OAAA,KAAY,CAAA,CAAE,CAAC,CAAA,CAAG,OAAA,IAAW,CAAA,CAAE,CAAC,EAAG,KAAA,KAAU,CAAA,CAAE,CAAC,CAAA,CAAG,OAAO,OAAO,KAAA;AAAA,EAC7E;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,aAAa,CAAA,EAAqC;AACzD,EAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,GAAG,MAAK,GAAI,CAAA;AAEnC,EAAA,OAAO,IAAA;AACT;AAEA,IAAM,YAAoC,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,QAAQ,MAAM,CAAA;AAKzE,SAAS,YAAY,CAAA,EAAwB;AAClD,EAAA,MAAM,IAAA,GAAO,oBAAA,CAAqB,CAAA,CAAE,OAAO,CAAA;AAI3C,EAAA,MAAM,QAAA,GAAW,IAAI,CAAA,CAAE,MAAA,CAAO,IAAI,eAAe,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAE5D,EAAA,IAAI,GAAA,GAAM,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,EAAE,OAAO,CAAA,CAAA;AAIlC,EAAA,IAAI,IAAA,CAAK,GAAA,IAAO,CAAA,CAAE,GAAA,KAAQ,MAAA,IAAa,EAAE,GAAA,MAAS,IAAA,CAAK,GAAA,CAAI,OAAA,IAAW,GAAA,CAAA,EAAM;AAC1E,IAAA,GAAA,IAAO,CAAA,CAAA,EAAI,EAAE,GAAG,CAAA,CAAA,CAAA;AAAA,EAClB;AAGA,EAAA,IAAI,KAAK,SAAA,IAAa,CAAA,CAAE,WAAW,MAAA,IAAa,CAAA,CAAE,WAAW,GAAA,EAAK;AAChE,IAAA,GAAA,IAAO,CAAA,IAAA,EAAO,EAAE,MAAM,CAAA,CAAA;AAAA,EACxB;AAGA,EAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC5B,IAAA,MAAM,GAAA,GAAM,CAAA,CAAE,SAAA,CAAU,IAAI,CAAA;AAC5B,IAAA,IAAI,GAAA,KAAQ,UAAA,EAAY,GAAA,IAAO,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA;AAAA,SAAA,IAC/B,GAAA,KAAQ,UAAA,EAAY,GAAA,IAAO,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA;AAAA,EAC/C;AAEA,EAAA,OAAO,GAAA;AACT;;;ACxVA,IAAM,YAAA,GAAe,IAAI,GAAA,CAAY,eAAe,CAAA;AAW7C,SAAS,cAAc,KAAA,EAA+B;AAC3D,EAAA,MAAM,CAAC,GAAA,EAAK,GAAGC,KAAI,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AACtC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,KAAK,CAAA,CAAE,CAAA;AACnE,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,KAAKA,KAAAA,EAAM;AACpB,IAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,CAAC,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAE,CAAA;AACxF,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,CAAC,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAE,CAAA;AACjF,IAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,EACZ;AACA,EAAA,OAAO,EAAE,GAAA,EAAK,YAAA,EAAcA,KAAAA,EAAsB;AACpD;AAIO,SAAS,eAAe,CAAA,EAA2B;AACxD,EAAA,OAAO,CAAA,CAAE,YAAA,CAAa,MAAA,KAAW,CAAA,GAAI,EAAE,GAAA,GAAM,CAAA,EAAG,CAAA,CAAE,GAAG,CAAA,CAAA,EAAI,CAAA,CAAE,YAAA,CAAa,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AACnF;AAMO,SAAS,eAAe,CAAA,EAA4B;AACzD,EAAA,MAAMA,QAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,KAAK,CAAA,CAAE,YAAA,EAAcA,KAAAA,CAAK,CAAC,CAAA,GAAI,UAAA;AAC1C,EAAA,MAAM,OAAgB,EAAE,IAAA,EAAM,KAAA,EAAO,GAAA,EAAK,EAAE,GAAA,EAAI;AAChD,EAAA,IAAI,OAAO,IAAA,CAAKA,KAAI,EAAE,MAAA,GAAS,CAAA,OAAQ,IAAA,GAAOA,KAAAA;AAC9C,EAAA,OAAO,IAAA;AACT;;;ACNA,SAAS,iBAAiB,KAAA,EAAyD;AACjF,EAAA,IAAI,KAAA,KAAU,MAAM,OAAO,UAAA;AAC3B,EAAA,IAAI,KAAA,KAAU,YAAY,OAAO,UAAA;AACjC,EAAA,OAAO,WAAA;AACT;AAeO,SAAS,cAAA,CACd,CAAA,EACAA,KAAAA,EACA,KAAA,EACS;AAET,EAAA,IAAI,GAAA,GAAsB,WAAA;AAC1B,EAAA,IAAI,IAAA,GAAuB,WAAA;AAC3B,EAAA,IAAI,IAAA,GAAuB,WAAA;AAC3B,EAAA,IAAI,KAAA,GAAwB,WAAA;AAE5B,EAAA,IAAIA,KAAAA,EAAM;AACR,IAAA,GAAA,GAAM,gBAAA,CAAiBA,MAAK,GAAG,CAAA;AAC/B,IAAA,KAAA,GAAQ,gBAAA,CAAiBA,MAAK,KAAK,CAAA;AAInC,IAAA,IAAIA,KAAAA,CAAK,QAAQ,MAAA,EAAW;AAC1B,MAAA,MAAM,MAAA,GAAS,gBAAA,CAAiBA,KAAAA,CAAK,GAAG,CAAA;AACxC,MAAA,IAAI,OAAO,IAAA,GAAO,MAAA;AAAA,WACb,IAAA,GAAO,MAAA;AAAA,IACd,CAAA,MAAO;AACL,MAAA,IAAA,GAAO,gBAAA,CAAiBA,MAAK,IAAI,CAAA;AACjC,MAAA,IAAA,GAAO,gBAAA,CAAiBA,MAAK,IAAI,CAAA;AAAA,IACnC;AAAA,EACF;AAEA,EAAA,OACE,SAAS,GAAA,EAAO,CAAA,CAAE,MAAM,CAAA,IACxB,QAAA,CAAS,MAAO,CAAA,CAAE,OAAO,CAAA,IACzB,QAAA,CAAS,MAAO,CAAA,CAAE,OAAO,KACzB,QAAA,CAAS,KAAA,EAAO,EAAE,QAAQ,CAAA;AAE9B;AAEA,SAAS,QAAA,CAAS,KAAqB,IAAA,EAAwB;AAC7D,EAAA,IAAI,GAAA,KAAQ,YAAY,OAAO,IAAA;AAC/B,EAAA,IAAI,GAAA,KAAQ,WAAA,EAAa,OAAO,CAAC,IAAA;AACjC,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,QAAA,CAAS,UAAkB,OAAA,EAAqC;AAC9E,EAAA,MAAM,KAAA,GAAQ,SAAS,WAAA,EAAY;AACnC,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC1B,IAAA,OAAO,QAAQ,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,OAAkB,KAAK,CAAA;AAAA,EACtD;AACA,EAAA,OAAO,OAAA,CAAQ,aAAY,KAAM,KAAA;AACnC;AAQA,SAAS,iBAAiB,MAAA,EAAqC;AAC7D,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,MAAM,OAAO,MAAA;AAC1D,EAAA,MAAM,IAAK,MAAA,CAA8B,IAAA;AACzC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,MAAA;AACrC;AAiBA,SAAS,SAAA,CAA4B,GAAW,MAAA,EAAiC;AAC/E,EAAA,OAAO,CAAA,CAAE,WAAW,MAAM,CAAA;AAC5B;AASO,SAAS,gBAAgB,IAAA,EAAyC;AACvE,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,OAAO,IAAA,KAAS,IAAA,IAAQ,OAAO,IAAA,CAAK,MAAA,KAAW,UAAA,GAC3C,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO,GACzC,IAAA;AAAA,EACN;AACA,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACrC,EAAA,IAAI,IAAA,KAAS,OAAA,IAAW,IAAA,KAAS,eAAA,IAAmB,SAAS,iBAAA,EAAmB;AAC9E,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAK;AAAA,EACpC;AACA,EAAA,IAAI,SAAA,CAAU,IAAA,EAAM,aAAa,CAAA,EAAG;AAClC,IAAA,OAAO,EAAE,MAAM,YAAA,EAAc,IAAA,EAAM,KAAK,KAAA,CAAM,aAAA,CAAc,MAAM,CAAA,EAAE;AAAA,EACtE;AAGA,EAAA,IAAI,SAAA,CAAU,IAAA,EAAM,OAAO,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA;AACtC,IAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,QAAA,CAAS,WAAW,CAAA;AACjD,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,kBAAkB,IAAA,CAAK,KAAA,CAAM,GAAG,CAAC,WAAA,CAAY,MAAM,CAAA,GAAI,IAAA;AAAA,MAC7D;AAAA,KACF;AAAA,EACF;AAGA,EAAA,OAAO,IAAA;AACT;AA6BO,SAAS,WAAA,CACd,MAAA,EACA,UAAA,EACA,UAAA,EACA,QAAA,EACS;AACT,EAAA,IAAI,UAAA,KAAe,QAAW,OAAO,IAAA;AACrC,EAAA,MAAM,IAAA,GAAO,gBAAgB,UAAU,CAAA;AACvC,EAAA,IAAI,IAAA,KAAS,MAAM,OAAO,KAAA;AAE1B,EAAA,QAAQ,KAAK,IAAA;AAAM;AAAA;AAAA,IAGjB,KAAK,WAAA;AACH,MAAA,OAAO,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,UAAU,CAAA;AAAA;AAAA;AAAA,IAIvC,KAAK,MAAA;AACH,MAAA,OAAO,UAAA,KAAe,MAAA,IAAa,UAAA,KAAe,IAAA,CAAK,IAAA;AAAA,IAEzD,KAAK,YAAA;AACH,MAAA,OAAO,gBAAA,CAAiB,MAAM,CAAA,KAAM,IAAA,CAAK,IAAA;AAAA,IAE3C,KAAK,MAAA;AACH,MAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,KAAa,IAAA,CAAK,MAAM,OAAO,KAAA;AAC7D,MAAA,OAAO,IAAA,CAAK,eAAA,GAAkB,UAAA,KAAe,eAAA,GAAkB,IAAA;AAAA,IAEjE,SAAS;AAIP,MAAA,OAAO,KAAA;AAAA,IACT;AAAA;AAEJ;AAuBA,SAAS,eAAe,IAAA,EAAuC;AAC7D,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,OAAO,CAAC,EAAE,OAAA,EAAS,GAAA,EAAK,KAAA,EAAO,MAAM,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,IAAA;AACT;AAMO,SAAS,UAAA,CAAW,MAA6B,GAAA,EAA4B;AAClF,EAAA,IAAI,IAAA,KAAS,QAAW,OAAO,IAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,eAAe,IAAI,CAAA;AACjC,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAC/B,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,IAAI,cAAA,CAAe,CAAA,EAAG,GAAG,CAAA,EAAG,OAAO,IAAA;AAAA,EACrC;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,cAAA,CAAe,GAAc,GAAA,EAA4B;AAChE,EAAA,IAAI,CAAA,CAAE,YAAY,GAAA,EAAK;AAGrB,IAAA,IAAI,CAAA,CAAE,KAAA,KAAU,GAAA,EAAK,OAAO,IAAA;AAC5B,IAAA,MAAM,UAAA,GAAa,GAAA,CAAI,eAAA,CAAgB,IAAA,GAAO,CAAA;AAC9C,IAAA,OAAO,CAAA,CAAE,KAAA,KAAU,SAAA,GAAY,UAAA,GAAa,CAAC,UAAA;AAAA,EAC/C;AAGA,EAAA,MAAM,KAAK,CAAA,CAAE,OAAA,KAAY,GAAA,GAAM,GAAA,CAAI,cAAc,CAAA,CAAE,OAAA;AACnD,EAAA,IAAI,EAAA,IAAM,MAAM,OAAO,KAAA;AACvB,EAAA,IAAI,CAAA,CAAE,KAAA,KAAU,GAAA,EAAK,OAAO,IAAA;AAC5B,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,eAAA,CAAgB,GAAA,CAAI,EAAE,CAAA;AAC5C,EAAA,OAAO,CAAA,CAAE,KAAA,KAAU,SAAA,GAAY,SAAA,GAAY,CAAC,SAAA;AAC9C;AAQO,SAAS,eAAA,CAAgB,MAAc,IAAA,EAAuB;AACnE,EAAA,MAAM,CAAA,GAAI,KAAK,WAAA,EAAY;AAC3B,EAAA,MAAM,CAAA,GAAI,KAAK,WAAA,EAAY;AAC3B,EAAA,IAAI,CAAA,KAAM,GAAA,IAAO,CAAA,KAAM,KAAA,EAAO,OAAO,IAAA;AACrC,EAAA,IAAI,CAAA,CAAE,QAAA,CAAS,IAAI,CAAA,EAAG,OAAO,CAAA,CAAE,UAAA,CAAW,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AACxD,EAAA,OAAO,CAAA,KAAM,CAAA;AACf;AAIO,SAAS,gBAAA,CACd,OACA,KAAA,EACS;AACT,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,MAAA,KAAW,GAAG,OAAO,IAAA;AACzC,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,EAAA,KAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,eAAA,CAAgB,EAAA,CAAG,IAAA,EAAM,CAAC,CAAC,CAAC,CAAA;AAC1E;AAcO,SAAS,SAAA,CACd,CAAA,EACA,IAAA,EACA,KAAA,EACA,QAAA,EACS;AAKT,EAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAW;AAC5B,IAAA,MAAM,MAAoB,QAAA,IAAY,EAAE,WAAA,EAAa,IAAA,EAAM,iBAAiB,aAAA,EAAc;AAC1F,IAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,KAAA,EAAO,GAAG,GAAG,OAAO,KAAA;AAAA,EAC3C;AAEA,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,KAAA,EAAO;AACV,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,KAAA,EAAO,OAAO,KAAA;AAC7B,MAAA,IAAI,CAAC,QAAA,CAAS,CAAA,CAAE,KAAK,IAAA,CAAK,GAAG,GAAG,OAAO,KAAA;AACvC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,UAAA,EAAY;AACf,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,UAAA,EAAY,OAAO,KAAA;AAClC,MAAA,IAAI,CAAA,CAAE,KAAA,KAAU,MAAA,EAAQ,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,QAAA,CAAS,CAAA,CAAE,KAAK,IAAA,CAAK,GAAG,GAAG,OAAO,KAAA;AACvC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,GAAA;AACpC,MAAA,IAAI,cAAc,IAAA,IAAQ,EAAE,CAAA,CAAE,MAAA,GAAS,IAAI,OAAO,KAAA;AAClD,MAAA,IAAI,cAAc,MAAA,IAAU,EAAE,CAAA,CAAE,MAAA,GAAS,IAAI,OAAO,KAAA;AACpD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,GAAA;AACpC,MAAA,IAAI,cAAc,KAAA,IAAS,EAAE,CAAA,CAAE,KAAA,GAAQ,IAAI,OAAO,KAAA;AAClD,MAAA,IAAI,cAAc,IAAA,IAAQ,EAAE,CAAA,CAAE,KAAA,GAAQ,IAAI,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AAMjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,aAAA,EAAe;AAClB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,aAAA,EAAe,OAAO,KAAA;AACrC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,aAAA,EAAe;AAClB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,aAAA,EAAe,OAAO,KAAA;AACrC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,WAAA,EAAa;AAChB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,WAAA,EAAa,OAAO,KAAA;AACnC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AAIjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,MAAA,EAAQ;AAGX,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,aAAA,EAAe,OAAO,KAAA;AAIrC,MAAA,IAAI,CAAA,CAAE,KAAA,KAAU,OAAA,EAAS,OAAO,KAAA;AAChC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AAGjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,aAAA,EAAe;AAGlB,MAAA,IAAI,EAAE,IAAA,KAAS,aAAA,IAAiB,CAAA,CAAE,KAAA,KAAU,SAAS,OAAO,KAAA;AAC5D,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,YAAA,EAAc;AACjB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,YAAA,EAAc,OAAO,KAAA;AACpC,MAAA,IAAI,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,OAAA,EAAS,OAAO,KAAA;AACvC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,eAAA,EAAiB;AACpB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,eAAA,EAAiB,OAAO,KAAA;AACvC,MAAA,IAAI,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,OAAA,EAAS,OAAO,KAAA;AACvC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,MAAA,EAAQ;AACX,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,MAAA,EAAQ,OAAO,KAAA;AAC9B,MAAA,IAAI,CAAC,gBAAA,CAAiB,CAAA,CAAE,OAAO,IAAA,CAAK,KAAK,GAAG,OAAO,KAAA;AACnD,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,gBAAA,CAAiB,CAAA,CAAE,OAAO,IAAA,CAAK,KAAK,GAAG,OAAO,KAAA;AACnD,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,SAAS;AAIP,MAAA,OAAO,KAAA;AAAA,IACT;AAAA;AAEJ;AAEA,IAAM,aAAA,uBAAyC,GAAA,EAAI;;;AC1dnD,IAAM,oBAAA,GAAkE;AAAA,EACtE,GAAA,EAAK,SAAA;AAAA,EACL,UAAA,EAAY,SAAA;AAAA,EACZ,KAAA,EAAO,OAAA;AAAA,EACP,KAAA,EAAO,OAAA;AAAA,EACP,KAAA,EAAO,OAAA;AAAA,EACP,WAAA,EAAa,QAAA;AAAA,EACb,WAAA,EAAa,aAAA;AAAA,EACb,SAAA,EAAW,WAAA;AAAA,EACX,IAAA,EAAM,MAAA;AAAA,EACN,WAAA,EAAa,aAAA;AAAA,EACb,UAAA,EAAY,MAAA;AAAA,EACZ,aAAA,EAAe,eAAA;AAAA,EACf,IAAA,EAAM,MAAA;AAAA,EACN,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,uBAAuB,IAAI,GAAA;AAAA,EAC9B,MAAA,CAAO,QAAQ,oBAAoB,CAAA,CACjC,OAAO,CAAC,CAAA,KAAoC,EAAE,CAAC,CAAA,KAAM,MAAS,CAAA,CAC9D,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,OAAO,CAAA,KAAM,CAAC,OAAA,EAAS,IAAI,CAAC;AAC7C,CAAA;AAIO,SAAS,wBAAwB,IAAA,EAAyC;AAC/E,EAAA,OAAO,qBAAqB,IAAI,CAAA;AAClC;AAIO,SAAS,wBAAwB,OAAA,EAA4C;AAClF,EAAA,OAAO,oBAAA,CAAqB,IAAI,OAAO,CAAA;AACzC;;;ACtBO,SAAS,YAAY,MAAA,EAAkC;AAC5D,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KAAuB;AACnC,IAAA,MAAM,IAAI,MAAM,CAAA,aAAA,EAAgB,GAAG,KAAK,WAAA,CAAY,MAAM,CAAC,CAAA,CAAE,CAAA;AAAA,EAC/D,CAAA;AACA,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,KAAQ,GAAA,GAAM,SAAY,MAAA,CAAO,GAAA;AAEpD,EAAA,MAAMA,QAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,CAAC,MAAM,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,MAAA,CAAO,SAAS,CAAA,EAAG;AAC1D,IAAAA,KAAAA,CAAK,IAAqB,CAAA,GAAI,GAAA,KAAQ,aAAa,IAAA,GAAO,UAAA;AAAA,EAC5D;AAEA,EAAA,MAAM,SAAgD,EAAC;AACvD,EAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,MAAA,CAAO,MAAA,KAAW,KAC5C,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,CAAG,YAAY,GAAA,IAAO,MAAA,CAAO,MAAA,CAAO,CAAC,EAAG,KAAA,KAAU,GAAA;AACtE,EAAA,IAAI,CAAC,eAAA,EAAiB,MAAA,CAAO,KAAA,GAAQ,MAAA,CAAO,MAAA;AAE5C,EAAA,MAAM,QAAA,GAAW,CAAwB,IAAA,KAAe;AACtD,IAAA,MAAM,QAAQ,IAAA,CAAK,IAAA;AACnB,IAAA,MAAM,MAAA,GAAS,EAAE,GAAGA,KAAAA,EAAM,GAAG,KAAA,EAAM;AACnC,IAAA,MAAM,GAAA,GAAM,EAAE,GAAG,IAAA,EAAM,GAAG,MAAA,EAAO;AACjC,IAAA,IAAI,OAAO,IAAA,CAAK,MAAM,EAAE,MAAA,GAAS,CAAA,MAAO,IAAA,GAAO,MAAA;AAC/C,IAAA,OAAO,GAAA;AAAA,EACT,CAAA;AAEA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,WAAW,GAAA,EAAK;AACxD,IAAA,IAAI,eAAA,CAAgB,MAAA,CAAO,MAAoB,CAAA,KAAM,IAAA,EAAM;AACzD,MAAA,IAAA,CAAK,CAAA,CAAA,EAAI,MAAA,CAAO,MAAM,CAAA,sBAAA,CAAwB,CAAA;AAAA,IAChD;AACA,IAAA,MAAA,GAAS,MAAA,CAAO,MAAA;AAAA,EAClB;AACA,EAAA,MAAM,IAAI,MAAA,KAAW,MAAA,GAAY,EAAC,GAAI,EAAE,MAAA,EAAO;AAE/C,EAAA,MAAM,IAAA,GAAO,uBAAA,CAAwB,MAAA,CAAO,OAAO,CAAA;AACnD,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,MAAA;AACH,MAAA,OAAO,IAAA,CAAK,CAAA,EAAG,MAAA,CAAO,OAAO,CAAA,wBAAA,CAA0B,CAAA;AAAA,IACzD,KAAK,OAAA;AAAA,IACL,KAAK,aAAA;AAAA,IACL,KAAK,aAAA;AAAA,IACL,KAAK,MAAA;AAAA,IACL,KAAK,aAAA;AAAA,IACL,KAAK,WAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAG,GAAG,CAAA;AAAA,IAChC,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAI,GAAA,GAAM,EAAE,SAAA,EAAW,GAAA,EAAqB,GAAI,EAAC,EAAI,GAAG,GAAG,CAAA;AAAA,IACrF,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAI,GAAA,GAAM,EAAE,SAAA,EAAW,GAAA,EAAoB,GAAI,EAAC,EAAI,GAAG,GAAG,CAAA;AAAA,IACpF,KAAK,KAAA;AAAA,IACL,KAAK,UAAA,EAAY;AACf,MAAA,IAAI,GAAA,KAAQ,MAAA,EAAW,OAAO,IAAA,CAAK,iCAAiC,CAAA;AACpE,MAAA,MAAM,EAAE,GAAA,EAAK,YAAA,EAAa,GAAI,cAAc,GAAG,CAAA;AAC/C,MAAA,MAAM,WAAoB,EAAC;AAC3B,MAAA,KAAA,MAAW,CAAA,IAAK,YAAA,EAAc,QAAA,CAAS,CAAC,CAAA,GAAI,UAAA;AAC5C,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAA,EAAK,GAAI,YAAA,CAAa,MAAA,GAAS,CAAA,GAAI,EAAE,IAAA,EAAM,QAAA,EAAS,GAAI,IAAK,CAAA;AAAA,IACvF;AAAA,IACA,KAAK,eAAA;AACH,MAAA,IAAI,GAAA,KAAQ,MAAA,EAAW,OAAO,IAAA,CAAK,6CAA6C,CAAA;AAChF,MAAA,OAAO,SAAS,EAAE,IAAA,EAAM,SAAS,MAAA,CAAO,GAAG,GAAG,CAAA;AAAA,IAChD,KAAK,MAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAI,MAAM,EAAE,KAAA,EAAO,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAE,GAAI,IAAK,CAAA;AAAA,IACrE,KAAK,YAAA;AACH,MAAA,OAAO,KAAK,iCAAiC,CAAA;AAAA;AAEnD;;;ACjFA,IAAM,SAAA,GAAyC;AAAA,EAC7C,GAAA,EAAK,KAAA;AAAA,EAAO,KAAA,EAAO,OAAA;AAAA,EAAS,GAAA,EAAK,KAAA;AAAA,EAAO,IAAA,EAAM,MAAA;AAAA,EAAQ,IAAA,EAAM;AAC9D,CAAA;AACA,IAAMC,aAAoC,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,QAAQ,MAAM,CAAA;AAIzE,IAAM,WAAA,GAAc;AAAA,EACzB,IAAA,EAAM,6DAAA;AAAA,EACN,aAAA,EAAe;AACjB;AAKO,IAAM,uBAAA,GAA0B;AAAA,EACrC,MAAA,EAAQ,iOAAA;AAAA,EACR,OAAA,EAAS,4JAAA;AAAA,EACT,GAAA,EAAK,oNAAA;AAAA,EACL,MAAA,EAAQ,iKAAA;AAAA,EACR,SAAA,EAAW;AACb;AAcA,SAAS,KAAK,KAAA,EAA6C;AACzD,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAO,UAAA,EAAY,WAAA,CAAY,KAAK,CAAA,EAAE;AAC/D;AAEA,SAAS,QAAQ,KAAA,EAAkC;AACjD,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AAC/B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAM,CAAC,CAAA;AACtC,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA,EAAG,KAAA,CAAM,CAAC,CAAC,CAAA,KAAA,EAAQ,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAC1D,EAAA,OAAO,CAAA,EAAG,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,MAAA,EAAS,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAC,CAAA,CAAA;AACzE;AAEA,SAAS,mBAAmBD,KAAAA,EAAmE;AAC7F,EAAA,MAAM,WAAqB,EAAC;AAC5B,EAAA,MAAM,WAAqB,EAAC;AAC5B,EAAA,KAAA,MAAW,QAAQC,UAAAA,EAAW;AAC5B,IAAA,MAAM,GAAA,GAAMD,MAAK,IAAI,CAAA;AACrB,IAAA,IAAI,QAAQ,UAAA,EAAY,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,SAAA,IAC5C,QAAQ,UAAA,EAAY,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,EAC5D;AACA,EAAA,OAAO,EAAE,UAAU,QAAA,EAAS;AAC9B;AAEA,SAAS,cAAA,CAAe,EAAE,OAAA,EAAS,KAAA,EAAM,EAAsC;AAC7E,EAAA,MAAM,OAAA,GAAU,YAAY,GAAA,GAAM,UAAA,GAC9B,YAAY,GAAA,GAAM,UAAA,GAClB,OAAO,OAAO,CAAA,KAAA,CAAA;AAClB,EAAA,IAAI,KAAA,KAAU,WAAW,OAAO,CAAC,GAAG,OAAO,CAAA,IAAA,CAAA,EAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC/D,EAAA,IAAI,KAAA,KAAU,WAAW,OAAO,CAAC,GAAG,OAAO,CAAA,IAAA,CAAA,EAAQ,IAAA,CAAK,aAAa,CAAC,CAAA;AACtE,EAAA,OAAO,CAAC,CAAA,EAAG,OAAO,CAAA,gBAAA,CAAkB,CAAA;AACtC;AAEA,SAAS,YAAY,MAAA,EAAsD;AACzE,EAAA,IAAI,OAAO,MAAA,KAAW,CAAA,SAAU,cAAA,CAAe,MAAA,CAAO,CAAC,CAAC,CAAA;AACxD,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACvB,IAAA,IAAI,CAAA,GAAI,CAAA,EAAG,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AAC1B,IAAA,GAAA,CAAI,IAAA,CAAK,GAAG,cAAA,CAAe,CAAC,CAAC,CAAA;AAAA,EAC/B,CAAC,CAAA;AACD,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,YAAA,CAAa,QAA4B,SAAA,EAA4B;AAC5E,EAAA,IAAI,CAAC,SAAA,IAAa,MAAA,KAAW,MAAA,EAAW,OAAO,EAAA;AAC/C,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,WAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,SAAS,OAAO,kBAAA;AAC/B,EAAA,OAAO,SAAS,MAAM,CAAA,CAAA;AACxB;AAIA,SAAS,YAAY,MAAA,EAAyC;AAC5D,EAAA,OAAO,MAAA,CAAO,GAAA,KAAQ,GAAA,GAAM,MAAA,GAAY,MAAA,CAAO,GAAA;AACjD;AAIA,SAAS,QAAA,CAAS,UAA6B,IAAA,EAAsB;AACnE,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,YAAY,IAAI,CAAA,CAAA;AAClD,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG,OAAO,YAAY,QAAA,CAAS,CAAC,CAAC,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AACjE,EAAA,OAAO,CAAA,eAAA,EAAkB,OAAA,CAAQ,QAAQ,CAAC,QAAQ,IAAI,CAAA,CAAA;AACxD;AAEA,SAAS,YAAA,CAAa,QAAqB,QAAA,EAAqC;AAC9E,EAAA,MAAM,IAAA,GAAO,oBAAA,CAAqB,MAAA,CAAO,OAAsB,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAM,YAAY,MAAM,CAAA;AAC9B,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,MAAA,CAAO,MAAA,EAAQ,KAAK,SAAS,CAAA;AAEzD,EAAA,QAAQ,OAAO,OAAA;AAAS,IACtB,KAAK,SAAA;AAAA,IACL,KAAK,OAAA;AAAA,IACL,KAAK,SAAA,EAAW;AACd,MAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KAAY,SAAA,GAAY,YACxC,MAAA,CAAO,OAAA,KAAY,UAAU,UAAA,GAC7B,OAAA;AACJ,MAAA,MAAM,MAAM,GAAA,IAAO,SAAA;AACnB,MAAA,OAAO,QAAA,CAAS,MAAA,GAAS,CAAA,GACrB,CAAA,eAAA,EAAkB,QAAQ,QAAQ,CAAC,CAAA,KAAA,EAAQ,IAAI,IAAI,GAAG,CAAA,CAAA,GACtD,CAAA,SAAA,EAAY,IAAI,IAAI,GAAG,CAAA,CAAA;AAAA,IAC7B;AAAA,IACA,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,YAAY,GAAA,KAAQ,IAAA,GAAO,KAAA,GAC7B,GAAA,KAAQ,SAAS,OAAA,GACjB,EAAA;AACJ,MAAA,OAAO,SAAS,QAAA,EAAU,CAAA,OAAA,EAAU,SAAS,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA;AAAA,IAC1D;AAAA,IACA,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,YAAY,GAAA,KAAQ,IAAA,GAAO,KAAA,GAC7B,GAAA,KAAQ,QAAQ,MAAA,GAChB,EAAA;AACJ,MAAA,OAAO,SAAS,QAAA,EAAU,CAAA,OAAA,EAAU,SAAS,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA;AAAA,IAC1D;AAAA,IACA,KAAK,eAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,UAAA,EAAa,GAAA,IAAO,UAAU,CAAA,QAAA,CAAU,CAAA;AAAA,IACpE,KAAK,aAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,sBAAA,EAAyB,MAAM,CAAA,CAAE,CAAA;AAAA,IAC7D,KAAK,WAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,YAAA,EAAe,MAAM,CAAA,CAAE,CAAA;AAAA,IACnD,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,MAAA,EAAS,MAAM,CAAA,CAAE,CAAA;AAAA,IAC7C,KAAK,aAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,OAAA,EAAU,MAAM,CAAA,CAAE,CAAA;AAAA,IAC9C,KAAK,QAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,WAAA,EAAc,MAAM,CAAA,CAAE,CAAA;AAAA,IAClD,KAAK,MAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAE,CAAA;AAAA,IAC5C,KAAK,MAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,MAAA,EAAS,GAAA,IAAO,KAAK,CAAA,wBAAA,CAA0B,CAAA;AAAA,IAC3E,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,OAAA,EAAU,GAAA,IAAO,KAAK,CAAA,QAAA,CAAU,CAAA;AAAA;AAEhE;AAeO,SAAS,kBAAA,CACd,MAAA,EACA,IAAA,GAA6B,EAAC,EACG;AACjC,EAAA,MAAM,EAAE,UAAA,GAAa,IAAA,EAAM,MAAA,GAAS,MAAK,GAAI,IAAA;AAC7C,EAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAS,GAAI,kBAAA,CAAmB,OAAO,SAAS,CAAA;AAClE,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAA;AAC5C,EAAA,MAAM,SAAA,GAAY,SAAS,MAAA,GAAS,CAAA,GAChC,KAAK,OAAA,CAAQ,QAAQ,CAAC,CAAA,UAAA,CAAA,GACtB,EAAA;AAEJ,EAAA,MAAM,QAAgC,EAAC;AACvC,EAAA,MAAM,IAAA,GAAO,cAAc,MAAM,CAAA,QAAA,CAAA;AACjC,EAAA,KAAA,CAAM,IAAA,CAAK,UAAA,GAAa,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAY,GAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,GAAI,IAAI,CAAA;AAC3E,EAAA,KAAA,CAAM,IAAA,CAAK,GAAG,WAAA,CAAY,MAAA,CAAO,MAAM,CAAC,CAAA;AACxC,EAAA,IAAI,SAAA,EAAW,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AACnC,EAAA,IAAI,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA;AAC1B,EAAA,OAAO,qBAAqB,KAAK,CAAA;AACnC;AAMO,SAAS,aAAA,CAAc,MAAA,EAAqB,IAAA,GAA6B,EAAC,EAAW;AAC1F,EAAA,OAAO,kBAAA,CAAmB,MAAA,EAAQ,IAAI,CAAA,CACnC,IAAI,CAAC,CAAA,KAAO,OAAO,CAAA,KAAM,WAAW,CAAA,GAAI,CAAA,CAAE,KAAM,CAAA,CAChD,KAAK,EAAE,CAAA;AACZ;AAEA,SAAS,qBAAqB,KAAA,EAAgE;AAC5F,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,GAAA,CAAI,MAAA,GAAS,CAAC,CAAA;AAC/B,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,IAAA,KAAS,QAAA,EAAU,GAAA,CAAI,GAAA,CAAI,MAAA,GAAS,CAAC,CAAA,GAAI,IAAA,GAAO,CAAA;AAAA,SAC/E,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACjB;AACA,EAAA,OAAO,GAAA;AACT;;;AClMO,SAAS,sBAAsB,GAAA,EAAqC;AACzE,EAAA,IAAI,GAAA,KAAQ,SAAA,EAAW,OAAO,EAAC;AAC/B,EAAA,MAAM,MAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,IAAA,IAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACjC,IAAA,GAAA,CAAI,IAAmB,CAAA,GAAI,UAAA;AAAA,EAC7B;AACA,EAAA,OAAO,GAAA;AACT;AAKO,SAAS,mBAAmBA,KAAAA,EAA+B;AAChE,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQA,KAAI,CAAA,CACvB,IAAA,CAAK,CAAC,CAAC,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA,KAAM,EAAE,aAAA,CAAc,CAAC,CAAC,CAAA,CACrC,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,GAAG,CAAA,KAAM,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA,CACrC,KAAK,GAAG,CAAA;AACb;;;AClBA,SAAS,UAAUA,KAAAA,EAAmC;AACpD,EAAA,IAAI,CAACA,OAAM,OAAO,CAAA;AAClB,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAIA,KAAAA,CAAK,QAAQ,IAAA,EAAM,CAAA,EAAA;AACvB,EAAA,IAAIA,KAAAA,CAAK,SAAS,IAAA,EAAM,CAAA,EAAA;AACxB,EAAA,IAAIA,KAAAA,CAAK,SAAS,IAAA,EAAM,CAAA,EAAA;AACxB,EAAA,IAAIA,KAAAA,CAAK,QAAQ,IAAA,EAAM,CAAA,EAAA;AACvB,EAAA,IAAIA,KAAAA,CAAK,UAAU,IAAA,EAAM,CAAA,EAAA;AACzB,EAAA,OAAO,CAAA;AACT;AAgBA,SAAS,WAAW,MAAA,EAAwC;AAC1D,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,CAAA;AACjC,EAAA,MAAM,IAAA,GAAO,gBAAgB,MAAM,CAAA;AACnC,EAAA,IAAI,IAAA,KAAS,MAAM,OAAO,CAAA;AAC1B,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,MAAA;AAAQ,MAAA,OAAO,IAAA,CAAK,kBAAkB,CAAA,GAAI,CAAA;AAAA,IAC/C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA;AAAA,IAC1B,KAAK,MAAA;AAAQ,MAAA,OAAO,CAAA;AAAA,IACpB,KAAK,WAAA;AAAa,MAAA,OAAO,CAAA;AAAA,IACzB,SAAS;AAGP,MAAA,OAAO,CAAA;AAAA,IACT;AAAA;AAEJ;AAEA,SAAS,aAAa,IAAA,EAA2C;AAC/D,EAAA,OAAO,QAAA,IAAY,IAAA,GAAO,IAAA,CAAK,MAAA,GAAS,MAAA;AAC1C;AA2BA,SAAS,UAAU,IAAA,EAAqC;AACtD,EAAA,IAAI,IAAA,KAAS,QAAW,OAAO,CAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,KAAS,QAAA,GAC1B,CAAC,EAAE,OAAA,EAAS,GAAA,EAAK,KAAA,EAAO,IAAA,EAAmB,CAAA,GAC3C,IAAA;AACJ,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA;AAC/B,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,MAAM,IAAA,GAAA,CAAQ,EAAE,OAAA,KAAY,GAAA,GAAM,IAAI,CAAA,KAAM,CAAA,CAAE,KAAA,KAAU,GAAA,GAAM,CAAA,GAAI,CAAA,CAAA;AAClE,IAAA,IAAI,IAAA,GAAO,KAAK,GAAA,GAAM,IAAA;AAAA,EACxB;AACA,EAAA,OAAO,GAAA;AACT;AAcO,SAAS,YACd,IAAA,EAC2C;AAC3C,EAAA,MAAM,CAAA,GAAI,UAAA,CAAW,YAAA,CAAa,IAAI,CAAC,CAAA;AACvC,EAAA,MAAMA,KAAAA,GAAQ,MAAA,IAAU,IAAA,GAAO,IAAA,CAAK,IAAA,GAAO,MAAA;AAC3C,EAAA,MAAM,CAAA,GAAI,UAAUA,KAAI,CAAA;AACxB,EAAA,MAAM,IAAI,SAAA,CAAW,OAAA,IAAW,IAAA,GAAO,IAAA,CAAK,QAAQ,MAAmC,CAAA;AAIvF,EAAA,MAAM,KAAA,GAAA,CACH,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,KAAK,IAAA,KAAS,OAAA,KACvC,IAAA,CAAK,KAAA,KAAU,MAAA,IAAa,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,IAC5C,CAAA,GAAI,CAAA;AACV,EAAA,OAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAK,CAAA;AACxB;;;AChHO,IAAM,iBAAA,GAAoB;AAI1B,SAAS,iBAAA,CACd,IAAA,EACA,EAAA,EACA,SAAA,GAAoB,iBAAA,EACX;AACT,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,OAAA,GAAU,IAAA,CAAK,SAAS,EAAA,CAAG,OAAA,GAAU,IAAA,CAAK,OAAO,CAAA,IAAK,SAAA;AAC7E;;;ACfO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,QAAA;AAAA,EAAU,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,UAAA;AAAA,EAAY,SAAA;AAAA,EAAW,sBAAA;AAAA,EAAwB,0BAAA;AAAA,EAC5E,iBAAA;AAAA,EAAmB,mBAAA;AAAA,EAAqB,iBAAA;AAAA,EAAmB,mBAAA;AAAA,EAAqB;AAClF,CAAA,CAAE,KAAK,GAAG;AAQH,SAAS,iBAAA,CAAkB,QAA4B,IAAA,EAAwB;AACpF,EAAA,IAAI,EAAE,MAAA,YAAkB,OAAA,CAAA,EAAU,OAAO,KAAA;AACzC,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,gBAAgB,CAAA;AAC/C,EAAA,OAAO,YAAY,IAAA,IAAQ,OAAA,KAAY,IAAA,IAAQ,IAAA,CAAK,SAAS,OAAO,CAAA;AACtE","file":"index.js","sourcesContent":["/**\n * Declarative gesture taxonomy. Single source of truth for:\n * - which gestures hit-test (have a `.target` slot in the route string)\n * - which gestures carry an argument and what values are legal\n * - the default arg value (used when none is specified in a route)\n *\n * Reflection, matcher, and inspector UI all read this table. Adding a new\n * gesture name in one place updates every consumer.\n */\n\nexport type GestureName =\n | 'click'\n | 'pointerDown'\n | 'dblTap'\n | 'drag'\n | 'wheel'\n | 'pinch'\n | 'keyDown'\n | 'keyUp'\n | 'keyHeld'\n | 'contextMenu'\n | 'longPress'\n | 'multiTouchTap'\n | 'drop'\n | 'paste';\n\n/**\n * Gesture kinds an affordance claim can bar, in the spec vocabulary bindings\n * are written in. `'pointer'` is one token because `pointerDown` / `click` /\n * `drag` are a single press protocol — at the event level the first two are\n * the same `kind: 'pointerdown'`, told apart only by `stage`.\n */\nexport type ClaimableGesture =\n | 'pointer'\n | 'doubleClick'\n | 'contextMenu'\n | 'longPress'\n | 'wheel'\n | 'pinch';\n\n/** Declares the argument a gesture carries: what it is called, which values\n * are legal, and what an omitted arg slot means. */\nexport interface GestureArgSpec {\n /** Display name for the arg in inspector chips (`direction`, `key`, `fingers`). */\n name: string;\n /** Acceptable values. `'free'` means any string (e.g. key names). */\n values: readonly string[] | 'free';\n /** Value an omitted arg slot takes. Must be in `values` unless\n * `values === 'free'`. Omit it to make an omitted slot mean the `'*'`\n * wildcard — match every value. */\n default?: string;\n}\n\n/** What the grammar knows about one gesture — the form of input itself, not\n * any action bound to it. */\nexport interface GestureDescriptor {\n name: GestureName;\n /** Does the route's `.target` slot apply? Targetless gestures (`wheel`,\n * `keyDown/Up`, `multiTouchTap`) elide it entirely in the v2 grammar. */\n hasTarget: boolean;\n /** Optional argument spec. Encoded as `gesture(value)` in the route string. */\n arg?: GestureArgSpec;\n}\n\n/** The gesture taxonomy: one descriptor per gesture the grammar recognizes.\n * Adding a gesture here is what makes it parseable, matchable and\n * inspectable. */\nexport const GESTURE_DESCRIPTORS: readonly GestureDescriptor[] = [\n { name: 'click', hasTarget: true },\n { name: 'pointerDown', hasTarget: true },\n { name: 'dblTap', hasTarget: true },\n { name: 'drag', hasTarget: true },\n { name: 'wheel', hasTarget: true, arg: { name: 'direction', values: ['up', 'down', '*'], default: '*' } },\n { name: 'pinch', hasTarget: true, arg: { name: 'direction', values: ['in', 'out', '*'], default: '*' } },\n { name: 'keyDown', hasTarget: false, arg: { name: 'key', values: 'free' } },\n { name: 'keyUp', hasTarget: false, arg: { name: 'key', values: 'free' } },\n { name: 'keyHeld', hasTarget: false, arg: { name: 'key', values: 'free' } },\n { name: 'contextMenu', hasTarget: true },\n { name: 'longPress', hasTarget: true },\n { name: 'multiTouchTap', hasTarget: false, arg: { name: 'fingers', values: ['2', '3', '4'] } },\n // The arg is the MIME-glob filter. No default: a spec with no `types`\n // matches any payload, which is what an omitted arg slot means for a\n // `'free'` arg.\n { name: 'drop', hasTarget: false, arg: { name: 'types', values: 'free' } },\n { name: 'paste', hasTarget: false, arg: { name: 'types', values: 'free' } },\n];\n\nconst BY_NAME = new Map<string, GestureDescriptor>(\n GESTURE_DESCRIPTORS.map((d) => [d.name, d]),\n);\n\n/** Look up a gesture's descriptor. Throws on an unknown name — callers\n * holding an unvalidated string should gate on `isKnownGestureName` first. */\nexport function getGestureDescriptor(name: GestureName): GestureDescriptor {\n const d = BY_NAME.get(name);\n if (!d) throw new Error(`unknown gesture: ${name}`);\n return d;\n}\n\n/** Whether a string names a gesture the grammar recognizes. */\nexport function isKnownGestureName(name: string): name is GestureName {\n return BY_NAME.has(name);\n}\n","/** All valid keys for a modifier sub-table in a route entry. Canonical\n * order: mod → shift → alt (matches formatShortcut). */\nexport type ModifierCombo =\n | 'default'\n | 'mod' | 'shift' | 'alt'\n | 'mod+shift' | 'mod+alt' | 'shift+alt'\n | 'mod+shift+alt';\n\n/** Convenience: produce the canonical ModifierCombo from modifiers passed\n * in any order. Useful in computed property syntax:\n *\n * ```ts\n * 'rect': {\n * [mods('shift')]: addToSelection,\n * [mods('alt', 'shift')]: cloneAndAdd, // → 'shift+alt'\n * }\n * ```\n */\nexport function mods(\n ...keys: ReadonlyArray<'mod' | 'shift' | 'alt'>\n): ModifierCombo {\n if (keys.length === 0) return 'default';\n const set = new Set(keys);\n return [\n set.has('mod') && 'mod',\n set.has('shift') && 'shift',\n set.has('alt') && 'alt',\n ].filter(Boolean).join('+') as ModifierCombo;\n}\n","/**\n * Route-string grammar v3:\n *\n * route = phaseSlot WS gesture WS argSlot? WS targetSlot? WS modSlot?\n * phaseSlot = '[' phaseList ']'\n * phaseList = phaseAtom (WS ',' WS phaseAtom)*\n * phaseAtom = (channel ':')? phaseValue -- bare phaseValue ≡ '&:phaseValue'\n * channel = '&' | '*' | toolId -- '&' = the binding's own tool\n * phaseValue = 'initial' | 'engaged' | '*'\n * argSlot = '(' argValue ')' -- whitespace inside parens is significant\n * targetSlot = '=>' WS targetValue -- omitted slot defaults to '*' for hasTarget\n * modSlot = modAtom (WS modAtom)*\n * modAtom = sigil modName\n * sigil = '+' | '?' -- ! @ # $ % ^ & * reserved as id-prefix\n * modName = 'mod' | 'shift' | 'alt' | 'ctrl' | 'meta'\n *\n * Shorthand: a bare phaseValue (no `:`) implies channel `&` (\"this tool's\n * own phase\"). `[engaged]` ≡ `[&:engaged]`; `[*]` ≡ `[&:*]`. The truly-loose\n * form (any channel, any phase) is `[*:*]`.\n *\n * Examples:\n * [initial] click => empty +shift -- self idle\n * [engaged] wheel -- self mid-gesture\n * [rect:engaged] wheel -- when rect tool is mid-gesture\n * [*:engaged] keyDown(Delete) -- when any tool is mid-gesture\n * [initial,engaged] contextMenu => empty -- either self phase\n * [*] click => empty -- self, any phase\n */\nimport { getGestureDescriptor, isKnownGestureName, type GestureName } from './gestures';\nimport type { RoutePhase } from '../ui/phase';\n\n// ─── Channel + phase atoms ────────────────────────────────────────────────\n\n/** Channel reference for a phase atom. `'&'` = the binding's own tool;\n * `'*'` = any tool; otherwise a registered tool id. */\nexport type ChannelRef = '&' | '*' | string;\n\n/** One element of a phase list: a (channel, phase) pair. The default\n * channel (omitted in the shorthand) is `'&'`. `phase: '*'` means\n * \"any phase of the given channel\". */\nexport interface PhaseAtom {\n channel: ChannelRef;\n phase: RoutePhase | '*';\n}\n\n/** Reserved id-prefix sigils. Tool ids, action ids, channel names, target\n * kinds, and arg values may not start with any of these — keeps the\n * parser unambiguous and reserves single-char prefixes for future grammar\n * extensions. */\nexport const RESERVED_ID_PREFIXES: ReadonlySet<string> = new Set([\n '!', '@', '#', '$', '%', '^', '&', '*',\n]);\n\n/** Reserved bareword channel/id names. These are keywords in the phase\n * slot — a tool may not register with one of these as its id (collides\n * with the bare-phase shorthand). */\nexport const RESERVED_ID_NAMES: ReadonlySet<string> = new Set([\n 'initial', 'engaged',\n]);\n\n// ─── v3 grammar types ──────────────────────────────────────────────────────\n\n/** v3 modifier requirement on a single modifier key. Absent from a\n * `ParsedModifiers` map means \"must not be held\" (the strict default). */\nexport type ModRequirement = 'required' | 'optional';\n\n/** Canonical modifier names accepted in the modSlot, in canonical order.\n * Single source of truth: the {@link ModifierKey} type and the runtime\n * validator (`MOD_NAME_SET`) are both derived from this tuple. */\nexport const VALID_MOD_NAMES = ['mod', 'shift', 'alt', 'ctrl', 'meta'] as const;\n\n/** A single modifier name accepted in the modSlot. */\nexport type ModifierKey = (typeof VALID_MOD_NAMES)[number];\n\n/** Parsed-form modifiers — structured map; absent keys are implicitly\n * forbidden. Empty object = \"no modifiers held\". */\nexport type ParsedModifiers = Partial<Record<ModifierKey, ModRequirement>>;\n\n/** Reserved sigil characters. The parser rejects any of these with a\n * \"reserved for future use\" error so introducing them later is\n * non-breaking. `*` is NOT in this set — it's the universal wildcard. */\nexport const RESERVED_SIGILS: ReadonlySet<string> = new Set(['!', '@', '#', '$', '%', '^', '&']);\n\n/** Active (parseable) sigils today: `+` required, `?` optional. */\nexport const ACTIVE_SIGILS: ReadonlySet<string> = new Set(['+', '?']);\n\n/** Runtime membership test for {@link ModifierKey}, for validating a modifier\n * name that arrives as a plain string. */\nconst MOD_NAME_SET: ReadonlySet<string> = new Set(VALID_MOD_NAMES);\nexport { MOD_NAME_SET };\n\n/** v3 parsed-route shape. */\nexport interface ParsedRoute {\n /** One or more phase atoms (channel + phase). Empty array is invalid.\n * Bare-phase shorthand in the source string desugars to channel `'&'`,\n * so `[engaged]` parses to `[{ channel: '&', phase: 'engaged' }]`. */\n phases: readonly PhaseAtom[];\n gesture: GestureName;\n /** Resolved arg. For arg-bearing gestures, the descriptor's default\n * fills in when the slot is omitted (e.g. `wheel` → `arg: '*'`).\n * Undefined for gestures whose descriptor has no `arg`. */\n arg: string | undefined;\n /** For hasTarget gestures: target string with `'*'` as the wildcard\n * sentinel. Defaults to `'*'` when the slot is omitted. Undefined for\n * hasTarget=false gestures. */\n target: string | undefined;\n /** Structured modifier requirements; empty map = \"no modifiers held\". */\n modifiers: ParsedModifiers;\n}\n\n/** Parse a route string into its slots, filling in the shorthand defaults the\n * grammar defines (bare phases mean channel `&`; an omitted arg or target\n * slot takes the gesture descriptor's default). Throws with the offending\n * input on anything the grammar does not accept, including sigils reserved\n * for later versions. */\nexport function parseRoute(input: string): ParsedRoute {\n // 1) Extract bracketed phaseSlot from the head.\n const trimmed = input.trim();\n if (!trimmed.startsWith('[')) {\n throw new Error(`invalid route (phase brackets required): ${input}`);\n }\n const closeIdx = trimmed.indexOf(']');\n if (closeIdx < 0) throw new Error(`invalid route (unclosed phase bracket): ${input}`);\n const phaseListRaw = trimmed.slice(1, closeIdx).trim();\n const phases = parsePhaseList(phaseListRaw, input);\n let rest = trimmed.slice(closeIdx + 1).trim();\n\n // 2) Pull off the gesture name (alphanumeric).\n const gestureMatch = /^([A-Za-z]+)/.exec(rest);\n if (!gestureMatch) throw new Error(`invalid route (no gesture name): ${input}`);\n const gestureName = gestureMatch[1]!;\n if (!isKnownGestureName(gestureName)) {\n throw new Error(`invalid route (unknown gesture \"${gestureName}\"): ${input}`);\n }\n rest = rest.slice(gestureMatch[0].length).trimStart();\n const desc = getGestureDescriptor(gestureName);\n\n // 3) Optional argSlot: `(...)`. Whitespace inside parens is significant.\n let arg: string | undefined;\n if (rest.startsWith('(')) {\n const closeArg = rest.indexOf(')');\n if (closeArg < 0) throw new Error(`invalid route (unbalanced arg parens): ${input}`);\n const argRaw = rest.slice(1, closeArg); // no trim — whitespace significant\n if (!desc.arg) throw new Error(`invalid route (${gestureName} has no arg): ${input}`);\n if (argRaw !== '*' && desc.arg.values !== 'free' && !desc.arg.values.includes(argRaw)) {\n throw new Error(`invalid route (\"${argRaw}\" not in ${desc.arg.values.join('|')}): ${input}`);\n }\n arg = argRaw;\n rest = rest.slice(closeArg + 1).trimStart();\n } else if (desc.arg) {\n arg = desc.arg.default ?? '*';\n }\n\n // 4) Optional targetSlot: `=> <target>`. Elided \"=> *\" defaults to '*' for hasTarget gestures.\n let target: string | undefined;\n if (rest.startsWith('=>')) {\n if (!desc.hasTarget) throw new Error(`invalid route (${gestureName} has no target): ${input}`);\n rest = rest.slice(2).trimStart();\n const tgtMatch = /^([^\\s+?!@#$%^&]+)/.exec(rest);\n if (!tgtMatch) throw new Error(`invalid route (missing target after \"=>\"): ${input}`);\n target = tgtMatch[1]!;\n rest = rest.slice(tgtMatch[0].length).trimStart();\n } else if (desc.hasTarget) {\n target = '*';\n }\n\n // 5) modSlot — zero or more sigil-prefixed atoms.\n const modifiers: ParsedModifiers = {};\n while (rest.length > 0) {\n const ch = rest[0]!;\n if (RESERVED_SIGILS.has(ch)) {\n throw new Error(`invalid route (\"${ch}\" is reserved for future use): ${input}`);\n }\n if (!ACTIVE_SIGILS.has(ch)) {\n throw new Error(`invalid route (unexpected \"${ch}\" at \"${rest}\"): ${input}`);\n }\n const sigil = ch;\n rest = rest.slice(1);\n const nameMatch = /^([a-z]+)/.exec(rest);\n if (!nameMatch) throw new Error(`invalid route (sigil \"${sigil}\" without modifier name): ${input}`);\n const name = nameMatch[1]!;\n if (!MOD_NAME_SET.has(name)) {\n throw new Error(`invalid route (unknown modifier \"${name}\"): ${input}`);\n }\n if (modifiers[name as ModifierKey] !== undefined) {\n throw new Error(`invalid route (duplicate modifier \"${name}\"): ${input}`);\n }\n modifiers[name as ModifierKey] = sigil === '+' ? 'required' : 'optional';\n rest = rest.slice(nameMatch[0].length).trimStart();\n }\n\n return { phases, gesture: gestureName, arg, target, modifiers };\n}\n\nfunction parsePhaseList(raw: string, input: string): readonly PhaseAtom[] {\n if (raw === '') throw new Error(`invalid route (empty phase list): ${input}`);\n const tokens = raw.split(',').map((p) => p.trim()).filter((p) => p.length > 0);\n if (tokens.length === 0) throw new Error(`invalid route (empty phase list): ${input}`);\n return tokens.map((t) => parsePhaseAtom(t, input));\n}\n\nconst VALID_PHASES: ReadonlySet<string> = new Set(['initial', 'engaged', '*']);\n\nfunction parsePhaseAtom(raw: string, input: string): PhaseAtom {\n // Split on the channel/phase separator. `parts.length === 1` is the\n // bare-phase shorthand (channel defaults to '&').\n const parts = raw.split(':');\n if (parts.length > 2) {\n throw new Error(`invalid route (phase atom \"${raw}\" has multiple \":\"): ${input}`);\n }\n if (parts.length === 1) {\n const phase = parts[0]!;\n if (!VALID_PHASES.has(phase)) {\n throw new Error(`invalid route (unknown phase \"${phase}\" in \"${raw}\"): ${input}`);\n }\n return { channel: '&', phase: phase as PhaseAtom['phase'] };\n }\n // parts.length === 2 — explicit channel:phase form.\n const channel = parts[0]!;\n const phase = parts[1]!;\n if (channel === '') {\n throw new Error(`invalid route (empty channel before \":\" in \"${raw}\"): ${input}`);\n }\n if (!VALID_PHASES.has(phase)) {\n throw new Error(`invalid route (unknown phase \"${phase}\" in \"${raw}\"): ${input}`);\n }\n if (channel !== '&' && channel !== '*') {\n // Named tool channel. Reject the reserved-id-name keywords (they'd\n // shadow the bare-phase shorthand on parse) and the sigil prefixes\n // (reserved as future grammar surface).\n if (RESERVED_ID_NAMES.has(channel)) {\n throw new Error(`invalid route (channel \"${channel}\" is a reserved phase keyword): ${input}`);\n }\n if (RESERVED_ID_PREFIXES.has(channel[0]!)) {\n throw new Error(`invalid route (channel \"${channel}\" starts with reserved sigil \"${channel[0]}\"): ${input}`);\n }\n }\n return { channel, phase: phase as PhaseAtom['phase'] };\n}\n\n/** Render a single phase atom in canonical shorthand form. `&` channel\n * is elided (\"`engaged`\", \"`*`\"); other channels use the explicit\n * `channel:phase` form (\"`rect:engaged`\", \"`*:*`\"). */\nexport function formatPhaseAtom(a: PhaseAtom): string {\n if (a.channel === '&') return a.phase;\n return `${a.channel}:${a.phase}`;\n}\n\n/** Visual-collapse pass: given a list of route strings, fold pairs that\n * differ ONLY in `shift` presence (one has `+shift`, the other doesn't,\n * everything else identical) into a single route with `?shift`. Useful\n * for inspector / palette displays that want to show \"Cmd+[\" and\n * \"Cmd+Shift+[\" as one Cmd+?Shift+[ chip rather than two rows.\n *\n * Preserves input order — the first member of each fold-pair holds the\n * position; the second is dropped. Routes that don't have a `+shift`\n * vs absent twin pass through unchanged. Does NOT fold other modifier\n * pairs (alt/ctrl/meta/mod) — those tend to carry meaning across the\n * same key (e.g., Cmd+Z vs Cmd+Shift+Z are usually two distinct\n * actions, but Cmd+] vs Cmd+Shift+] is more often parametric variation\n * of one action). Open the helper if a use case for the other\n * modifiers shows up.\n */\nexport function collapseShiftPairs(routes: readonly string[]): string[] {\n if (routes.length < 2) return [...routes];\n const parsed = routes.map((r) => ({ raw: r, p: parseRoute(r) }));\n const consumed = new Set<number>();\n const out: string[] = [];\n for (let i = 0; i < parsed.length; i++) {\n if (consumed.has(i)) continue;\n const a = parsed[i]!;\n // Look ahead for a twin: same gesture/arg/target/phases/mods-except-shift.\n let twinIndex = -1;\n for (let j = i + 1; j < parsed.length; j++) {\n if (consumed.has(j)) continue;\n const b = parsed[j]!;\n if (isShiftTwin(a.p, b.p)) { twinIndex = j; break; }\n }\n if (twinIndex < 0) { out.push(a.raw); continue; }\n consumed.add(twinIndex);\n // Emit the union with shift marked optional.\n const folded: ParsedRoute = {\n ...a.p,\n modifiers: { ...withoutShift(a.p.modifiers), shift: 'optional' },\n };\n out.push(formatRoute(folded));\n }\n return out;\n}\n\nfunction isShiftTwin(a: ParsedRoute, b: ParsedRoute): boolean {\n if (a.gesture !== b.gesture) return false;\n if (a.arg !== b.arg) return false;\n if (a.target !== b.target) return false;\n if (!samePhases(a.phases, b.phases)) return false;\n // Exactly one must have shift required; the other must lack shift.\n const aShift = a.modifiers.shift;\n const bShift = b.modifiers.shift;\n const aHas = aShift === 'required';\n const bHas = bShift === 'required';\n if (!(aHas !== bHas)) return false; // one and only one has shift\n if (aShift === 'optional' || bShift === 'optional') return false; // already optional\n // Every other modifier must match exactly.\n for (const name of VALID_MOD_NAMES) {\n if (name === 'shift') continue;\n if (a.modifiers[name] !== b.modifiers[name]) return false;\n }\n return true;\n}\n\nfunction samePhases(\n a: readonly PhaseAtom[],\n b: readonly PhaseAtom[],\n): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i]!.channel !== b[i]!.channel || a[i]!.phase !== b[i]!.phase) return false;\n }\n return true;\n}\n\nfunction withoutShift(m: ParsedModifiers): ParsedModifiers {\n const { shift: _shift, ...rest } = m;\n void _shift;\n return rest;\n}\n\nconst MOD_ORDER: readonly ModifierKey[] = ['mod', 'shift', 'alt', 'ctrl', 'meta'];\n\n/** Render a parsed route back to a canonical route string: shorthand where\n * the grammar has it, defaulted slots elided, modifiers in canonical order.\n * `parseRoute(formatRoute(r))` yields `r` again. */\nexport function formatRoute(r: ParsedRoute): string {\n const desc = getGestureDescriptor(r.gesture);\n\n // Phase slot — comma-separated atoms in source order; canonical\n // shorthand per atom (`&:engaged` → `engaged`, etc.).\n const phaseStr = `[${r.phases.map(formatPhaseAtom).join(',')}]`;\n\n let out = `${phaseStr} ${r.gesture}`;\n\n // Arg slot — elide the value an omitted slot would parse back to. A\n // descriptor with no declared default takes '*', same as the target slot.\n if (desc.arg && r.arg !== undefined && r.arg !== (desc.arg.default ?? '*')) {\n out += `(${r.arg})`;\n }\n\n // Target slot — elide \"*\" (wildcard default for hasTarget gestures).\n if (desc.hasTarget && r.target !== undefined && r.target !== '*') {\n out += ` => ${r.target}`;\n }\n\n // Mod atoms in canonical order, space-separated.\n for (const name of MOD_ORDER) {\n const req = r.modifiers[name];\n if (req === 'required') out += ` +${name}`;\n else if (req === 'optional') out += ` ?${name}`;\n }\n\n return out;\n}\n","/**\n * Mini-grammar for the `arg` slot of `keyDown` / `keyUp` routes.\n *\n * keyRoute = key ('?' optionalMod)*\n * optionalMod = 'mod' | 'shift' | 'alt' | 'ctrl' | 'meta'\n *\n * `?shift` means \"shift may or may not be held; either fires this route.\"\n * Required modifiers still belong in the route's `:modifiers` slot — this\n * grammar only widens which events match, never narrows.\n */\nimport type { KeySpec, ModSpec } from '../ui/spec';\nimport { VALID_MOD_NAMES, type ModifierKey } from './routeGrammar';\n\n/** An optional modifier in a key route — the same set as the canonical\n * {@link ModifierKey}. */\nexport type OptionalMod = ModifierKey;\nconst OPTIONAL_SET = new Set<string>(VALID_MOD_NAMES);\n\n/** A key route split into the key itself and the modifiers whose state does\n * not affect the match. */\nexport interface ParsedKeyRoute {\n key: string;\n optionalMods: readonly OptionalMod[];\n}\n\n/** Parse the `arg` slot of a `keyDown` / `keyUp` route. Throws on an empty\n * key, an unrecognized optional modifier, or a repeated one. */\nexport function parseKeyRoute(input: string): ParsedKeyRoute {\n const [key, ...mods] = input.split('?');\n if (!key) throw new Error(`invalid key route (empty key): ${input}`);\n const seen = new Set<string>();\n for (const m of mods) {\n if (!OPTIONAL_SET.has(m)) throw new Error(`unknown optional modifier \"${m}\" in ${input}`);\n if (seen.has(m)) throw new Error(`duplicate optional modifier \"${m}\" in ${input}`);\n seen.add(m);\n }\n return { key, optionalMods: mods as OptionalMod[] };\n}\n\n/** Render a parsed key route back to its canonical source form. Round-trips\n * with `parseKeyRoute`. */\nexport function formatKeyRoute(r: ParsedKeyRoute): string {\n return r.optionalMods.length === 0 ? r.key : `${r.key}?${r.optionalMods.join('?')}`;\n}\n\n/** Build a runtime KeySpec from a parsed key route. Each optional modifier\n * becomes `mods.<name>: 'optional'`. The matcher's `matchModifiers`\n * honors `'optional'` uniformly across `mod`, `shift`, `alt`, `ctrl`,\n * and `meta`. */\nexport function keyRouteToSpec(r: ParsedKeyRoute): KeySpec {\n const mods: ModSpec = {};\n for (const m of r.optionalMods) mods[m] = 'optional';\n const spec: KeySpec = { kind: 'key', key: r.key };\n if (Object.keys(mods).length > 0) spec.mods = mods;\n return spec;\n}\n","/**\n * Pure gesture matcher — no React, no state, no DOM.\n *\n * The kit's dispatcher orchestrator wraps these primitives with its\n * actions-layer concerns (BindingScope, ScopedBinding, MatchResult, matchBest).\n *\n * ## key-held phase decision\n * `matchSpec` returns `true` only for `phase: 'down'`, not `phase: 'up'`.\n * The dispatcher tracks the held key independently and handles the `up` phase\n * itself; the matcher never sees an \"un-match\" it needs to distinguish.\n * This keeps the matcher's output a simple boolean and avoids a three-valued\n * return type.\n *\n * ## TargetSpec string forms\n * Every form `TargetSpec` declares is resolved here, each from a different\n * field the dispatcher packs onto the event:\n *\n * | Form | Read from | Supplied by |\n * | --- | --- | --- |\n * | `'empty'` / `'selected-body'` / `'unselected-body'` | `bodyTarget` | the `classifyTarget` thunk |\n * | `kind:<k>` / `kind:<k>:selected` | `bodyKind` + `bodyTarget` | the `classifyTarget` thunk's node-kind resolver |\n * | `affordance:<k>` | the raw target's `.kind` | the `affordanceAt` thunk |\n * | `{ kindOf }` | the raw target + `bodyTarget` | both |\n *\n * A form whose source field is absent does not match — an unwired\n * `classifyTarget` makes every `bodyTarget`/`bodyKind` form `false` rather\n * than a silent wildcard. That is deliberate: a binding that can't be\n * evaluated should stay out of the way of one that can.\n */\n\nimport type { GestureSpec, ModSpec, PhaseSpec, TargetSpec, TargetPredicate } from './spec';\nimport type { InputEvent } from './inputEvent';\nimport type { PhaseAtom } from '../grammar/routeGrammar';\n\n// ---------------------------------------------------------------------------\n// matchModifiers\n// ---------------------------------------------------------------------------\n\n/** The modifier-state fields `matchModifiers` reads. Structural, so a DOM\n * `KeyboardEvent` or `PointerEvent` satisfies it directly. */\nexport type ModifiersEvent = { altKey: boolean; ctrlKey: boolean; metaKey: boolean; shiftKey: boolean };\n\n/** Per-physical-key requirement resolved from a `ModSpec`:\n * - `'required'` — the key MUST be held\n * - `'forbidden'` — the key MUST NOT be held\n * - `'optional'` — either is accepted\n */\ntype KeyRequirement = 'required' | 'forbidden' | 'optional';\n\nfunction resolveSpecValue(value: boolean | 'optional' | undefined): KeyRequirement {\n if (value === true) return 'required';\n if (value === 'optional') return 'optional';\n return 'forbidden';\n}\n\n/**\n * Strict modifier match.\n *\n * - Omitted modifier MUST NOT be held.\n * - `true` MUST be held.\n * - `false` MUST NOT be held (same as omitted; both forms accepted for clarity).\n * - `'optional'` accepts either held or unheld. Supported on every modifier\n * (`alt`, `ctrl`, `meta`, `mod`, `shift`).\n * - `mod` is platform-aware: matches `metaKey` on mac, `ctrlKey` elsewhere.\n * When `mod` is set, the corresponding `meta`/`ctrl` field is implied AND\n * the *other* platform key is forbidden. Callers should not combine `mod`\n * with `meta`/`ctrl`.\n */\nexport function matchModifiers(\n e: ModifiersEvent,\n mods: ModSpec | undefined,\n isMac: boolean,\n): boolean {\n // Start strict: every modifier is forbidden unless the spec opts in.\n let alt: KeyRequirement = 'forbidden';\n let ctrl: KeyRequirement = 'forbidden';\n let meta: KeyRequirement = 'forbidden';\n let shift: KeyRequirement = 'forbidden';\n\n if (mods) {\n alt = resolveSpecValue(mods.alt);\n shift = resolveSpecValue(mods.shift);\n\n // mod: platform-aware shorthand. Resolves to meta on mac, ctrl elsewhere.\n // The *other* platform key stays forbidden (handled by the strict default).\n if (mods.mod !== undefined) {\n const modReq = resolveSpecValue(mods.mod);\n if (isMac) meta = modReq;\n else ctrl = modReq;\n } else {\n meta = resolveSpecValue(mods.meta);\n ctrl = resolveSpecValue(mods.ctrl);\n }\n }\n\n return (\n checkKey(alt, e.altKey) &&\n checkKey(ctrl, e.ctrlKey) &&\n checkKey(meta, e.metaKey) &&\n checkKey(shift, e.shiftKey)\n );\n}\n\nfunction checkKey(req: KeyRequirement, held: boolean): boolean {\n if (req === 'required') return held;\n if (req === 'forbidden') return !held;\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// matchKey\n// ---------------------------------------------------------------------------\n\n/** Case-insensitive key match; supports string or string[] (any-of). */\nexport function matchKey(eventKey: string, specKey: string | string[]): boolean {\n const lower = eventKey.toLowerCase();\n if (Array.isArray(specKey)) {\n return specKey.some((k) => k.toLowerCase() === lower);\n }\n return specKey.toLowerCase() === lower;\n}\n\n// ---------------------------------------------------------------------------\n// matchTarget\n// ---------------------------------------------------------------------------\n\n/** Read a `.kind` string off an affordance hit, or `undefined` when the hit\n * is absent or shaped differently. */\nfunction affordanceKindOf(target: unknown): string | undefined {\n if (typeof target !== 'object' || target === null) return undefined;\n const k = (target as { kind?: unknown }).kind;\n return typeof k === 'string' ? k : undefined;\n}\n\n/**\n * A {@link TargetSpec} resolved to its form, with the parts each form encodes\n * in its string pulled out.\n *\n * This is the one enumeration of the target forms. Three sites act on it and\n * each does something different — `matchTarget` below, and `targetRank` /\n * `targetConsultsAffordance` in `@weasel-js/core`'s dispatcher matcher — so\n * they switch on `form` exhaustively rather than re-deriving the prefixes.\n */\nexport type TargetSpecForm =\n | { form: 'body'; body: 'empty' | 'selected-body' | 'unselected-body' }\n | { form: 'kind'; kind: string; requireSelected: boolean }\n | { form: 'affordance'; kind: string }\n | { form: 'predicate'; kindOf: TargetPredicate };\n\nfunction hasPrefix<P extends string>(s: string, prefix: P): s is `${P}${string}` {\n return s.startsWith(prefix);\n}\n\n/**\n * Resolve a `TargetSpec` to its {@link TargetSpecForm}.\n *\n * `null` means the value is no form this build knows — junk from an untyped\n * consumer, or a spec authored against a newer kit. Every caller treats it as\n * no-match rather than a wildcard.\n */\nexport function parseTargetSpec(spec: TargetSpec): TargetSpecForm | null {\n if (typeof spec === 'object') {\n return spec !== null && typeof spec.kindOf === 'function'\n ? { form: 'predicate', kindOf: spec.kindOf }\n : null;\n }\n if (typeof spec !== 'string') return null;\n if (spec === 'empty' || spec === 'selected-body' || spec === 'unselected-body') {\n return { form: 'body', body: spec };\n }\n if (hasPrefix(spec, 'affordance:')) {\n return { form: 'affordance', kind: spec.slice('affordance:'.length) };\n }\n // `:selected` is only a suffix when it is the LAST segment — `kind:app:note`\n // names a kind that happens to contain a colon.\n if (hasPrefix(spec, 'kind:')) {\n const rest = spec.slice('kind:'.length);\n const requireSelected = rest.endsWith(':selected');\n return {\n form: 'kind',\n kind: requireSelected ? rest.slice(0, -':selected'.length) : rest,\n requireSelected,\n };\n }\n const _exhaustive: never = spec;\n void _exhaustive;\n return null;\n}\n\n/**\n * Match a target value + event against a TargetSpec.\n *\n * - `{ kindOf: predicate }` — calls the predicate with the raw target value\n * (affordance hit on pointerdown; event.target otherwise) AND the\n * `bodyTarget` string. Predicates that only need the target can ignore\n * the second arg.\n * - `'empty'`, `'selected-body'`, `'unselected-body'` — compared against\n * `bodyTarget` on the event (populated by `useGestureDispatcher` when a\n * `classifyTarget` thunk is supplied).\n * - `kind:<k>` — compared against `bodyKind`, the *semantic* kind of the node\n * body under the point (`'text'`, `'rect'`, an app's own `'app:note'`), as\n * resolved by `classifyTarget`. Selection-agnostic.\n * - `kind:<k>:selected` — the same, and additionally requires the body to be\n * in the current selection. Only the final `:selected` is a suffix, so a\n * kind may itself contain colons.\n * - `affordance:<k>` — exact match against the affordance hit's own `kind`.\n * Kit affordance kinds are `handle:<corner>`, `'rotate-handle'`,\n * `anchor:<i>`, `controlIn:<i>` / `controlOut:<i>`, and `layer:<id>` for a\n * registered layer's widget. The match is exact and includes any parameter,\n * so \"any anchor\" needs the `isAnchor` predicate rather than this form.\n * - `undefined` spec.target — any target is accepted.\n *\n * Every string form resolves to `false` when the field it reads is absent, so\n * an unwired `classifyTarget`/`affordanceAt` yields no-match rather than a\n * silent wildcard.\n */\nexport function matchTarget(\n target: unknown,\n specTarget: TargetSpec | undefined,\n bodyTarget?: string,\n bodyKind?: string,\n): boolean {\n if (specTarget === undefined) return true;\n const form = parseTargetSpec(specTarget);\n if (form === null) return false;\n\n switch (form.form) {\n // Receives the raw target (affordance hit for drag, e.target otherwise)\n // plus the bodyTarget classification.\n case 'predicate':\n return form.kindOf(target, bodyTarget);\n\n // Resolved from the `classifyTarget` result packed into the event's\n // `bodyTarget`. Unwired classifyTarget → absent → no match.\n case 'body':\n return bodyTarget !== undefined && bodyTarget === form.body;\n\n case 'affordance':\n return affordanceKindOf(target) === form.kind;\n\n case 'kind':\n if (bodyKind === undefined || bodyKind !== form.kind) return false;\n return form.requireSelected ? bodyTarget === 'selected-body' : true;\n\n default: {\n // Exhaustiveness guard — new target forms are a compile error here.\n const _exhaustive: never = form;\n void _exhaustive;\n return false;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// matchPhase\n// ---------------------------------------------------------------------------\n\n/** Per-tool gesture-lifecycle state at match time.\n *\n * - `selfChannel` is the tool id `'&'` resolves to — i.e., the tool that\n * owns the binding being evaluated. `null` for bindings without an\n * owning tool (e.g. ambient actions registered without scope ties); in\n * that case any `phase: '&'` atom can't match.\n * - `engagedChannels` is the set of tool ids that currently have an\n * in-flight handle. Derived by the dispatcher from its `inFlight()`\n * map keyed by tool id at match time.\n */\nexport interface PhaseContext {\n selfChannel: string | null;\n engagedChannels: ReadonlySet<string>;\n}\n\n/** Normalize the `PhaseSpec` shorthand to an atom array.\n * Bare keywords desugar to a single `'&'`-channel atom. */\nfunction normalizePhase(spec: PhaseSpec): readonly PhaseAtom[] {\n if (typeof spec === 'string') {\n return [{ channel: '&', phase: spec }];\n }\n return spec;\n}\n\n/** True if the binding's `phase` spec is satisfied by the current\n * per-tool engagement state. Omitted spec → always true (no phase\n * constraint). Union semantics: a phase atom list matches when ANY\n * atom matches. */\nexport function matchPhase(spec: PhaseSpec | undefined, ctx: PhaseContext): boolean {\n if (spec === undefined) return true;\n const atoms = normalizePhase(spec);\n if (atoms.length === 0) return true;\n for (const a of atoms) {\n if (matchPhaseAtom(a, ctx)) return true;\n }\n return false;\n}\n\nfunction matchPhaseAtom(a: PhaseAtom, ctx: PhaseContext): boolean {\n if (a.channel === '*') {\n // Any-channel sentinel: 'engaged' matches when any channel is engaged;\n // 'initial' matches when none are; '*' matches both.\n if (a.phase === '*') return true;\n const anyEngaged = ctx.engagedChannels.size > 0;\n return a.phase === 'engaged' ? anyEngaged : !anyEngaged;\n }\n // Resolve '&' to the binding's owning tool. Without an owner, '&' atoms\n // can't match (correct: ambient actions don't have a \"self\").\n const id = a.channel === '&' ? ctx.selfChannel : a.channel;\n if (id == null) return false;\n if (a.phase === '*') return true;\n const isEngaged = ctx.engagedChannels.has(id);\n return a.phase === 'engaged' ? isEngaged : !isEngaged;\n}\n\n// ---------------------------------------------------------------------------\n// matchIngestTypes\n// ---------------------------------------------------------------------------\n\n/** MIME-glob match: `'image/*'` prefix-matches the major type; anything\n * else is an exact (case-insensitive) match; bare `'*'` or `'*\\/*'` matches all. */\nexport function mimeMatchesGlob(mime: string, glob: string): boolean {\n const m = mime.toLowerCase();\n const g = glob.toLowerCase();\n if (g === '*' || g === '*/*') return true;\n if (g.endsWith('/*')) return m.startsWith(g.slice(0, -1));\n return m === g;\n}\n\n/** True if ANY item's MIME matches ANY of the `types` globs.\n * `types: []` (empty) ≡ omitted = match any. */\nexport function matchIngestTypes(\n items: readonly { mime: string }[],\n types: string[] | undefined,\n): boolean {\n if (!types || types.length === 0) return true;\n return items.some((it) => types.some((g) => mimeMatchesGlob(it.mime, g)));\n}\n\n// ---------------------------------------------------------------------------\n// matchSpec\n// ---------------------------------------------------------------------------\n\n/**\n * Match a single GestureSpec against an InputEvent.\n *\n * For `key-held`, only `phase: 'down'` returns true. The dispatcher tracks the\n * held state independently and handles `phase: 'up'` itself.\n *\n * For TargetSpec string forms, returns false (kind registry not yet available).\n */\nexport function matchSpec(\n e: InputEvent,\n spec: GestureSpec,\n isMac: boolean,\n phaseCtx?: PhaseContext,\n): boolean {\n // Phase gate runs first — cheaper than the per-kind logic, and a failed\n // phase rules the spec out regardless of event shape. When no phase ctx\n // is supplied (legacy callers), treat as wildcard-engagement so existing\n // bindings continue to behave as if phase weren't a constraint.\n if (spec.phase !== undefined) {\n const ctx: PhaseContext = phaseCtx ?? { selfChannel: null, engagedChannels: EMPTY_ENGAGED };\n if (!matchPhase(spec.phase, ctx)) return false;\n }\n\n switch (spec.kind) {\n case 'key': {\n if (e.kind !== 'key') return false;\n if (!matchKey(e.key, spec.key)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'key-held': {\n if (e.kind !== 'key-held') return false;\n if (e.phase !== 'down') return false; // only match the down phase\n if (!matchKey(e.key, spec.key)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'wheel': {\n if (e.kind !== 'wheel') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n const direction = spec.direction ?? '*';\n if (direction === 'up' && !(e.deltaY < 0)) return false;\n if (direction === 'down' && !(e.deltaY > 0)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'pinch': {\n if (e.kind !== 'pinch') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n const direction = spec.direction ?? '*';\n if (direction === 'out' && !(e.scale > 1)) return false;\n if (direction === 'in' && !(e.scale < 1)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'click': {\n if (e.kind !== 'click') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n // A `kindOf` predicate gets the affordance the press landed on — the\n // same value it would get on a drag — NOT the DOM target. That\n // symmetry is what lets one predicate describe \"this piece of chrome\"\n // for both gestures, and what lets `hit == null` mean \"not chrome\".\n // String-form specs read `bodyTarget` and don't look at either.\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'doubleClick': {\n if (e.kind !== 'doubleclick') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'contextMenu': {\n if (e.kind !== 'contextmenu') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'longPress': {\n if (e.kind !== 'longpress') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n // Match on the affordance like `drag` does, not the DOM target like\n // `contextMenu` does: a long-press begins as a press, so the useful\n // target is what was under the finger in scene terms.\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'drag': {\n // Drag begins at pointerdown; the dispatcher promotes to drag after\n // threshold is crossed. The matcher fires on pointerdown.\n if (e.kind !== 'pointerdown') return false;\n // ...but not on the eager `stage: 'press'` dispatch, which exists for\n // `pointerDown` specs. Both dispatches come from one physical press;\n // without this gate a press would open its drag handle twice.\n if (e.stage === 'press') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n // Pass the affordance hit as the `target` for `kindOf` predicates.\n // Pass `bodyTarget` for string-form TargetSpec values.\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'pointerDown': {\n // The mirror of the gate above: only the eager dispatch, never the\n // buffered one the drag threshold releases.\n if (e.kind !== 'pointerdown' || e.stage !== 'press') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'multiTouch': {\n if (e.kind !== 'multitouch') return false;\n if (e.fingers !== spec.fingers) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'multiTouchTap': {\n if (e.kind !== 'multitouchtap') return false;\n if (e.fingers !== spec.fingers) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'drop': {\n if (e.kind !== 'drop') return false;\n if (!matchIngestTypes(e.items, spec.types)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'paste': {\n if (e.kind !== 'paste') return false;\n if (!matchIngestTypes(e.items, spec.types)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n default: {\n // Exhaustiveness guard — new spec kinds are a compile error here.\n const _exhaustive: never = spec;\n void _exhaustive;\n return false;\n }\n }\n}\n\nconst EMPTY_ENGAGED: ReadonlySet<string> = new Set();\n","import type { GestureSpec } from '../ui/spec';\nimport type { GestureName } from './gestures';\n\ntype SpecKind = GestureSpec['kind'];\n\n/** `GestureSpec.kind` → route-grammar gesture name. `multiTouch` has no\n * route gesture (only its tap synthesis does), and `keyUp` has no spec kind,\n * so neither direction is total. */\nconst SPEC_KIND_TO_GESTURE: Record<SpecKind, GestureName | undefined> = {\n key: 'keyDown',\n 'key-held': 'keyHeld',\n wheel: 'wheel',\n pinch: 'pinch',\n click: 'click',\n doubleClick: 'dblTap',\n contextMenu: 'contextMenu',\n longPress: 'longPress',\n drag: 'drag',\n pointerDown: 'pointerDown',\n multiTouch: undefined,\n multiTouchTap: 'multiTouchTap',\n drop: 'drop',\n paste: 'paste',\n};\n\nconst GESTURE_TO_SPEC_KIND = new Map<GestureName, SpecKind>(\n (Object.entries(SPEC_KIND_TO_GESTURE) as [SpecKind, GestureName | undefined][])\n .filter((e): e is [SpecKind, GestureName] => e[1] !== undefined)\n .map(([kind, gesture]) => [gesture, kind]),\n);\n\n/** The route-grammar gesture a `GestureSpec.kind` routes as, or `undefined`\n * for a kind the grammar has no name for. */\nexport function routeGestureForSpecKind(kind: SpecKind): GestureName | undefined {\n return SPEC_KIND_TO_GESTURE[kind];\n}\n\n/** The `GestureSpec.kind` a route-grammar gesture is written as, or\n * `undefined` for a gesture no spec can express. */\nexport function specKindForRouteGesture(gesture: GestureName): SpecKind | undefined {\n return GESTURE_TO_SPEC_KIND.get(gesture);\n}\n","import type { GestureSpec, ModSpec, PhaseSpec, TargetSpec } from '../ui/spec';\nimport { parseTargetSpec } from '../ui/match';\nimport { formatRoute, type ParsedRoute } from './routeGrammar';\nimport { parseKeyRoute } from './keyRouteGrammar';\nimport { specKindForRouteGesture } from './specKinds';\n\n/**\n * Build the `GestureSpec` a parsed route describes, so a route string can\n * drive `matchSpec` and `specificity` directly.\n *\n * Wildcards become omitted fields: a `*` target, direction or MIME list, and a\n * `[*:*]` phase slot. `[*]` is `[&:*]`, which an ambient binding never\n * matches, so it stays a phase atom. A `keyDown` / `keyHeld` arg is read as a\n * key route, so `keyDown(z?shift)` yields `mods.shift: 'optional'`; a drop or\n * paste arg is a `|`-separated MIME list.\n *\n * Throws on a route no spec can express: `keyUp`, a key or finger-count\n * wildcard, or a target that is not a `TargetSpec` form.\n */\nexport function routeToSpec(parsed: ParsedRoute): GestureSpec {\n const fail = (why: string): never => {\n throw new Error(`routeToSpec: ${why}: ${formatRoute(parsed)}`);\n };\n const arg = parsed.arg === '*' ? undefined : parsed.arg;\n\n const mods: ModSpec = {};\n for (const [name, req] of Object.entries(parsed.modifiers)) {\n mods[name as keyof ModSpec] = req === 'required' ? true : 'optional';\n }\n\n const common: { mods?: ModSpec; phase?: PhaseSpec } = {};\n const isUnconstrained = parsed.phases.length === 1\n && parsed.phases[0]!.channel === '*' && parsed.phases[0]!.phase === '*';\n if (!isUnconstrained) common.phase = parsed.phases;\n\n const withMods = <S extends GestureSpec>(spec: S): S => {\n const extra = spec.mods;\n const merged = { ...mods, ...extra };\n const out = { ...spec, ...common };\n if (Object.keys(merged).length > 0) out.mods = merged;\n return out;\n };\n\n let target: TargetSpec | undefined;\n if (parsed.target !== undefined && parsed.target !== '*') {\n if (parseTargetSpec(parsed.target as TargetSpec) === null) {\n fail(`\"${parsed.target}\" is not a target form`);\n }\n target = parsed.target as TargetSpec;\n }\n const t = target === undefined ? {} : { target };\n\n const kind = specKindForRouteGesture(parsed.gesture);\n switch (kind) {\n case undefined:\n return fail(`${parsed.gesture} has no GestureSpec kind`);\n case 'click':\n case 'pointerDown':\n case 'doubleClick':\n case 'drag':\n case 'contextMenu':\n case 'longPress':\n return withMods({ kind, ...t });\n case 'wheel':\n return withMods({ kind, ...(arg ? { direction: arg as 'up' | 'down' } : {}), ...t });\n case 'pinch':\n return withMods({ kind, ...(arg ? { direction: arg as 'in' | 'out' } : {}), ...t });\n case 'key':\n case 'key-held': {\n if (arg === undefined) return fail('a key spec needs a concrete key');\n const { key, optionalMods } = parseKeyRoute(arg);\n const optional: ModSpec = {};\n for (const m of optionalMods) optional[m] = 'optional';\n return withMods({ kind, key, ...(optionalMods.length > 0 ? { mods: optional } : {}) });\n }\n case 'multiTouchTap':\n if (arg === undefined) return fail('a multiTouchTap spec needs concrete fingers');\n return withMods({ kind, fingers: Number(arg) });\n case 'drop':\n case 'paste':\n return withMods({ kind, ...(arg ? { types: arg.split('|') } : {}) });\n case 'multiTouch':\n return fail('multiTouch has no route gesture');\n }\n}\n","import { getGestureDescriptor, type GestureName } from './gestures';\nimport type { ParsedRoute, PhaseAtom, ParsedModifiers, ModifierKey } from './routeGrammar';\n\nconst MOD_NAMES: Record<ModifierKey, string> = {\n mod: 'Mod', shift: 'Shift', alt: 'Alt', ctrl: 'Ctrl', meta: 'Meta',\n};\nconst MOD_ORDER: readonly ModifierKey[] = ['mod', 'shift', 'alt', 'ctrl', 'meta'];\n\n/** Glossary for route-vocabulary terms surfaced by `describeRouteParts`.\n * Exposed so docs / inspector UIs can render the same definitions. */\nexport const ROUTE_TERMS = {\n idle: 'Not in the middle of a drag or other synchronous operation.',\n 'mid-gesture': 'In the middle of a drag or other synchronous operation.',\n} as const;\n\n/** Per-field explanations for the slots of a parsed route. Exposed so\n * inspector UIs / docs can describe what each setting in a route table\n * means without duplicating prose. */\nexport const ROUTE_FIELD_DEFINITIONS = {\n 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.',\n gesture: 'The class of input event that triggers this route — click, drag, double-tap, keyDown/keyUp, wheel, pinch, contextMenu, multiTouchTap, drop, or paste.',\n arg: 'Sub-class of the gesture. Direction for wheel (up / down / *) and pinch (in / out / *), key name for keyDown / keyUp, finger count for multiTouchTap, MIME glob for drop / paste. Other gestures have no arg slot.',\n 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.',\n modifiers: 'Modifier keys the user must hold (`+key`) or may optionally hold (`?key`) for this route to match. Unlisted modifiers must not be held.',\n} as const;\n\n/** The slots of a parsed route that `ROUTE_FIELD_DEFINITIONS` explains. */\nexport type RouteFieldName = keyof typeof ROUTE_FIELD_DEFINITIONS;\n\n/** The route-vocabulary terms `ROUTE_TERMS` defines. */\nexport type RouteTermLabel = keyof typeof ROUTE_TERMS;\n\n/** A part of a structured route description. `string` parts are plain prose;\n * `term` parts carry a glossary lookup so renderers can attach tooltips. */\nexport type RouteDescriptionPart =\n | string\n | { kind: 'term'; label: RouteTermLabel; definition: string };\n\nfunction term(label: RouteTermLabel): RouteDescriptionPart {\n return { kind: 'term', label, definition: ROUTE_TERMS[label] };\n}\n\nfunction joinAnd(parts: readonly string[]): string {\n if (parts.length === 0) return '';\n if (parts.length === 1) return parts[0];\n if (parts.length === 2) return `${parts[0]} and ${parts[1]}`;\n return `${parts.slice(0, -1).join(', ')}, and ${parts[parts.length - 1]}`;\n}\n\nfunction partitionModifiers(mods: ParsedModifiers): { required: string[]; optional: string[] } {\n const required: string[] = [];\n const optional: string[] = [];\n for (const name of MOD_ORDER) {\n const req = mods[name];\n if (req === 'required') required.push(MOD_NAMES[name]);\n else if (req === 'optional') optional.push(MOD_NAMES[name]);\n }\n return { required, optional };\n}\n\nfunction phaseAtomParts({ channel, phase }: PhaseAtom): RouteDescriptionPart[] {\n const subject = channel === '&' ? 'the tool'\n : channel === '*' ? 'any tool'\n : `the ${channel} tool`;\n if (phase === 'initial') return [`${subject} is `, term('idle')];\n if (phase === 'engaged') return [`${subject} is `, term('mid-gesture')];\n return [`${subject} is in any phase`];\n}\n\nfunction phasesParts(phases: readonly PhaseAtom[]): RouteDescriptionPart[] {\n if (phases.length === 1) return phaseAtomParts(phases[0]);\n const out: RouteDescriptionPart[] = [];\n phases.forEach((p, i) => {\n if (i > 0) out.push(' or ');\n out.push(...phaseAtomParts(p));\n });\n return out;\n}\n\nfunction targetClause(target: string | undefined, hasTarget: boolean): string {\n if (!hasTarget || target === undefined) return '';\n if (target === '*') return ' anywhere';\n if (target === 'empty') return ' on empty canvas';\n return ` on a ${target}`;\n}\n\n/** The gesture's arg, or undefined when it is the `'*'` wildcard — which\n * `parseRoute` fills in for every omitted slot, so prose must not print it. */\nfunction concreteArg(parsed: ParsedRoute): string | undefined {\n return parsed.arg === '*' ? undefined : parsed.arg;\n}\n\n/** One modifier reads as a compound verb (\"Shift-clicks\"); more read as a\n * held chord (\"holds Mod and Alt and drags\"). */\nfunction userDoes(required: readonly string[], verb: string): string {\n if (required.length === 0) return `the user ${verb}`;\n if (required.length === 1) return `the user ${required[0]}-${verb}`;\n return `the user holds ${joinAnd(required)} and ${verb}`;\n}\n\nfunction actionClause(parsed: ParsedRoute, required: readonly string[]): string {\n const desc = getGestureDescriptor(parsed.gesture as GestureName);\n const arg = concreteArg(parsed);\n const target = targetClause(parsed.target, desc.hasTarget);\n\n switch (parsed.gesture) {\n case 'keyDown':\n case 'keyUp':\n case 'keyHeld': {\n const verb = parsed.gesture === 'keyDown' ? 'presses'\n : parsed.gesture === 'keyUp' ? 'releases'\n : 'holds';\n const key = arg ?? 'any key';\n return required.length > 0\n ? `the user holds ${joinAnd(required)} and ${verb} ${key}`\n : `the user ${verb} ${key}`;\n }\n case 'wheel': {\n const direction = arg === 'up' ? ' up'\n : arg === 'down' ? ' down'\n : '';\n return userDoes(required, `scrolls${direction}${target}`);\n }\n case 'pinch': {\n const direction = arg === 'in' ? ' in'\n : arg === 'out' ? ' out'\n : '';\n return userDoes(required, `pinches${direction}${target}`);\n }\n case 'multiTouchTap':\n return userDoes(required, `taps with ${arg ?? 'multiple'} fingers`);\n case 'contextMenu':\n return userDoes(required, `opens the context menu${target}`);\n case 'longPress':\n return userDoes(required, `long-presses${target}`);\n case 'click':\n return userDoes(required, `clicks${target}`);\n case 'pointerDown':\n return userDoes(required, `presses${target}`);\n case 'dblTap':\n return userDoes(required, `double-taps${target}`);\n case 'drag':\n return userDoes(required, `drags${target}`);\n case 'drop':\n return userDoes(required, `drops ${arg ?? 'any'} content onto the canvas`);\n case 'paste':\n return userDoes(required, `pastes ${arg ?? 'any'} content`);\n }\n}\n\n/** Sentence-shaping options for `describeRoute` and `describeRouteParts` —\n * set both false to embed the description inside a larger sentence. */\nexport interface DescribeRouteOptions {\n /** Capitalize the first letter of the result. Default true. */\n capitalize?: boolean;\n /** Trailing period. Default true. */\n period?: boolean;\n}\n\n/** Structured description of when a parsed route fires. Returns an array of\n * prose strings interspersed with `term` parts (e.g. `idle`, `mid-gesture`)\n * so React-based renderers can attach hover-definition tooltips. Use\n * `describeRoute()` for a plain-string version. */\nexport function describeRouteParts(\n parsed: ParsedRoute,\n opts: DescribeRouteOptions = {},\n): readonly RouteDescriptionPart[] {\n const { capitalize = true, period = true } = opts;\n const { required, optional } = partitionModifiers(parsed.modifiers);\n const action = actionClause(parsed, required);\n const optClause = optional.length > 0\n ? ` (${joinAnd(optional)} optional)`\n : '';\n\n const parts: RouteDescriptionPart[] = [];\n const head = `fires when ${action}, while `;\n parts.push(capitalize ? head.charAt(0).toUpperCase() + head.slice(1) : head);\n parts.push(...phasesParts(parsed.phases));\n if (optClause) parts.push(optClause);\n if (period) parts.push('.');\n return mergeAdjacentStrings(parts);\n}\n\n/** Plain-spoken English summary of when a parsed route fires. Intended for\n * developer-facing documentation. Term parts collapse to their label only\n * (e.g. `idle`); use `describeRouteParts()` if you want to expose the\n * glossary definitions in your renderer. */\nexport function describeRoute(parsed: ParsedRoute, opts: DescribeRouteOptions = {}): string {\n return describeRouteParts(parsed, opts)\n .map((p) => (typeof p === 'string' ? p : p.label))\n .join('');\n}\n\nfunction mergeAdjacentStrings(parts: readonly RouteDescriptionPart[]): RouteDescriptionPart[] {\n const out: RouteDescriptionPart[] = [];\n for (const p of parts) {\n const last = out[out.length - 1];\n if (typeof p === 'string' && typeof last === 'string') out[out.length - 1] = last + p;\n else out.push(p);\n }\n return out;\n}\n","import type { ModifierCombo } from './modifiers';\nimport type { ParsedModifiers, ModifierKey } from './routeGrammar';\n\n/** Translate the tool-authoring `ModifierCombo` enum (positional string,\n * e.g. `'mod+shift'`) to the v3 `ParsedModifiers` structured map\n * (every listed modifier becomes `'required'`; unlisted means\n * forbidden / absent). `'default'` yields `{}`. */\nexport function modifierComboToParsed(key: ModifierCombo): ParsedModifiers {\n if (key === 'default') return {};\n const out: ParsedModifiers = {};\n for (const part of key.split('+')) {\n out[part as ModifierKey] = 'required';\n }\n return out;\n}\n\n/** Stable canonical serialization of a ParsedModifiers map for use as a\n * hash key (conflicts dedup). Sorts mod names alphabetically and emits\n * `name=req` pairs joined by `&`. */\nexport function canonicalModifiers(mods: ParsedModifiers): string {\n return Object.entries(mods)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([name, req]) => `${name}=${req}`)\n .join('&');\n}\n","import { parseTargetSpec } from './match';\nimport type { GestureSpec, ModSpec, PhaseSpec, TargetSpec } from './spec';\nimport type { PhaseAtom } from '../grammar/routeGrammar';\n\n/** Count modifier keys declared as `required` (`true`). `'optional'`,\n * `false`, and `undefined` do NOT discriminate — they don't count. */\nfunction modsCount(mods: ModSpec | undefined): number {\n if (!mods) return 0;\n let n = 0;\n if (mods.alt === true) n++;\n if (mods.ctrl === true) n++;\n if (mods.meta === true) n++;\n if (mods.mod === true) n++;\n if (mods.shift === true) n++;\n return n;\n}\n\n/**\n * Rank a `TargetSpec` by how much it narrows. Graduated so a target that\n * names a specific thing outranks one that only names a class of things:\n *\n * 3 — `kind:<k>:selected`: this kind AND in the selection\n * 2 — `kind:<k>` / `affordance:<k>`: one named kind\n * 1 — `'empty'` / `'selected-body'` / `'unselected-body'` / `{ kindOf }`\n * 0 — no target\n *\n * A predicate stays at 1 because its narrowness is unknowable statically —\n * `hit == null` and `isRotateHandle` are the same shape here. That is also\n * what keeps this addition from reordering any binding that existed before\n * the `kind:`/`affordance:` forms resolved: every one of them ranks 0 or 1.\n */\nfunction targetRank(target: TargetSpec | undefined): number {\n if (target === undefined) return 0;\n const form = parseTargetSpec(target);\n if (form === null) return 1;\n switch (form.form) {\n case 'kind': return form.requireSelected ? 3 : 2;\n case 'affordance': return 2;\n case 'body': return 1;\n case 'predicate': return 1;\n default: {\n const _exhaustive: never = form;\n void _exhaustive;\n return 1;\n }\n }\n}\n\nfunction specTargetOf(spec: GestureSpec): TargetSpec | undefined {\n return 'target' in spec ? spec.target : undefined;\n}\n\n/**\n * Rank a `PhaseSpec` by how much it narrows, on the same graduated principle\n * as `targetRank`. A phase atom constrains two axes — which channel, and its\n * lifecycle state — and each may be wildcarded:\n *\n * 2 — both concrete: `{ channel: '&' | '<toolId>', phase: 'initial' }`,\n * which is also what the bare-keyword shorthand desugars to\n * 1 — one axis wildcarded: `{ channel: '*', phase: 'engaged' }`\n * 0 — `{ channel: '*', phase: '*' }`, or no `phase` field at all\n *\n * The `*:*` case scoring 0 is the point: it matches everything `matchPhase`\n * would have matched with no spec, so grading it above an undeclared phase\n * would let a binding buy precedence with a constraint that constrains\n * nothing — CSS's `:where()` problem.\n *\n * An atom list is a union (`matchPhase` returns true when ANY atom matches),\n * so the list is as broad as its broadest atom and takes the **minimum**.\n *\n * Compat: every phase-bearing spec in the tree keeps its score or rises, and\n * none reorders. The four ambient actions (`escape`, `delete`,\n * `anchorEditing`, `cancelGesture`) all declare `{ channel: '*', phase:\n * <concrete> }` and stay at 1; the polygon and star tools' `phase: 'engaged'`\n * wheel bindings desugar to a concrete `&` atom and rise 1 → 2, which only\n * widens a gap they already won. Nothing in the tree declares `*:*`.\n */\nfunction phaseRank(spec: PhaseSpec | undefined): number {\n if (spec === undefined) return 0;\n const atoms = typeof spec === 'string'\n ? [{ channel: '&', phase: spec } as PhaseAtom]\n : spec;\n if (atoms.length === 0) return 0;\n let min = 2;\n for (const a of atoms) {\n const rank = (a.channel === '*' ? 0 : 1) + (a.phase === '*' ? 0 : 1);\n if (rank < min) min = rank;\n }\n return min;\n}\n\n/** CSS-style specificity tuple for a GestureSpec. Higher tuple wins under\n * lexicographic compare. Dimensions, in order of precedence:\n *\n * [0] target — how much the spec's target narrows; see `targetRank`.\n * [1] mods — count of required modifier keys (shift/alt/ctrl/meta/mod).\n * `'optional'` does NOT count.\n * [2] phase — how much the spec's `phase` narrows; see `phaseRank`.\n * [3] exact — per-kind tiebreak: 2 for a drop/paste spec with a\n * non-empty `types` MIME filter, else 1.\n *\n * Identical tuples fall back to registration order in the matcher's\n * stable sort, preserving the pre-specificity tiebreaker. */\nexport function specificity(\n spec: GestureSpec,\n): readonly [number, number, number, number] {\n const t = targetRank(specTargetOf(spec));\n const mods = ('mods' in spec ? spec.mods : undefined) as ModSpec | undefined;\n const m = modsCount(mods);\n const p = phaseRank(('phase' in spec ? spec.phase : undefined) as PhaseSpec | undefined);\n // Per-kind tiebreak: a MIME-typed drop/paste spec beats an untyped one\n // in the same scope (a consumer's `types: ['text/csv']` binding should\n // win over the kit's catch-all ingest binding).\n const typed =\n (spec.kind === 'drop' || spec.kind === 'paste') &&\n spec.types !== undefined && spec.types.length > 0\n ? 2 : 1;\n return [t, m, p, typed];\n}\n","/**\n * How far, in CSS pixels, a press must travel before it is a drag rather than\n * a click. `drag` specs match only past it: routing's `useGestureDispatcher`\n * holds a pointerdown back until the pointer crosses it, so a press-and-release\n * that stays under it never opens a drag.\n */\nexport const DRAG_THRESHOLD_PX = 4;\n\n/** Whether a pointer that went down at `from` has travelled far enough, by\n * `to`, to be a drag. Both points are client coordinates. */\nexport function pastDragThreshold(\n from: { clientX: number; clientY: number },\n to: { clientX: number; clientY: number },\n threshold: number = DRAG_THRESHOLD_PX,\n): boolean {\n return Math.hypot(to.clientX - from.clientX, to.clientY - from.clientY) >= threshold;\n}\n","/** Elements that handle their own press and keys. */\nexport const CONTROL_SELECTOR = [\n 'button', 'input', 'select', 'textarea', 'a[href]', '[contenteditable=\"\"]', '[contenteditable=\"true\"]',\n '[role=\"button\"]', '[role=\"checkbox\"]', '[role=\"switch\"]', '[role=\"menuitem\"]', '[role=\"link\"]',\n].join(',');\n\n/**\n * Whether `target` sits in a control of its own somewhere inside `host` — a\n * toggle in a list row, a button over a canvas. The host's handlers leave such\n * an event to the control, so a host's press, click and keys never swallow its\n * controls'.\n */\nexport function isInControlWithin(target: EventTarget | null, host: Element): boolean {\n if (!(target instanceof Element)) return false;\n const control = target.closest(CONTROL_SELECTOR);\n return control !== null && control !== host && host.contains(control);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/grammar/gestures.ts","../src/grammar/modifiers.ts","../src/grammar/routeGrammar.ts","../src/grammar/keyRouteGrammar.ts","../src/ui/match.ts","../src/grammar/specKinds.ts","../src/grammar/routeToSpec.ts","../src/grammar/describeRoute.ts","../src/grammar/modifierComboToParsed.ts","../src/ui/spec.ts","../src/ui/platform.ts","../src/ui/specificity.ts","../src/ui/dragThreshold.ts","../src/ui/controlTarget.ts"],"names":["phase","mods","MOD_ORDER"],"mappings":";AAoEO,IAAM,mBAAA,GAAoD;AAAA,EAC/D,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,aAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,QAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,MAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,IAAA,EAAO,KAAK,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,CAAC,IAAA,EAAM,MAAA,EAAQ,GAAG,CAAA,EAAG,OAAA,EAAS,KAAI,EAAE;AAAA,EACjH,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,IAAA,EAAO,KAAK,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,CAAC,IAAA,EAAM,KAAA,EAAO,GAAG,CAAA,EAAG,OAAA,EAAS,KAAI,EAAE;AAAA,EAChH,EAAE,IAAA,EAAM,SAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,KAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,KAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,SAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,KAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,aAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,WAAA,EAAiB,SAAA,EAAW,IAAA,EAAM;AAAA,EAC1C,EAAE,IAAA,EAAM,YAAA,EAAiB,SAAA,EAAW,OAAO,GAAA,EAAK,EAAE,IAAA,EAAM,SAAA,EAAa,QAAQ,CAAC,GAAA,EAAK,GAAA,EAAK,GAAG,GAAE,EAAE;AAAA,EAC/F,EAAE,IAAA,EAAM,eAAA,EAAiB,SAAA,EAAW,OAAO,GAAA,EAAK,EAAE,IAAA,EAAM,SAAA,EAAa,QAAQ,CAAC,GAAA,EAAK,GAAA,EAAK,GAAG,GAAE,EAAE;AAAA;AAAA;AAAA;AAAA,EAI/F,EAAE,IAAA,EAAM,MAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,OAAA,EAAa,MAAA,EAAQ,MAAA,EAAO,EAAE;AAAA,EACtF,EAAE,IAAA,EAAM,OAAA,EAAiB,SAAA,EAAW,KAAA,EAAO,GAAA,EAAK,EAAE,IAAA,EAAM,OAAA,EAAa,MAAA,EAAQ,MAAA,EAAO;AACtF;AAEA,IAAM,UAAU,IAAI,GAAA;AAAA,EAClB,mBAAA,CAAoB,IAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,IAAA,EAAM,CAAC,CAAC;AAC5C,CAAA;AAIO,SAAS,qBAAqB,IAAA,EAAsC;AACzE,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AAC1B,EAAA,IAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,IAAI,CAAA,CAAE,CAAA;AAClD,EAAA,OAAO,CAAA;AACT;AAGO,SAAS,mBAAmB,IAAA,EAAmC;AACpE,EAAA,OAAO,OAAA,CAAQ,IAAI,IAAI,CAAA;AACzB;;;ACtFO,SAAS,QACX,IAAA,EACY;AACf,EAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,SAAA;AAC9B,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAI,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,GAAA,CAAI,GAAA,CAAI,KAAK,CAAA,IAAO,KAAA;AAAA,IACpB,GAAA,CAAI,GAAA,CAAI,OAAO,CAAA,IAAK,OAAA;AAAA,IACpB,GAAA,CAAI,GAAA,CAAI,KAAK,CAAA,IAAO;AAAA,GACtB,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AAC5B;;;ACqBO,IAAM,oBAAA,uBAAgD,GAAA,CAAI;AAAA,EAC/D,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK,GAAA;AAAA,EAAK;AACrC,CAAC;AAKM,IAAM,iBAAA,uBAA6C,GAAA,CAAI;AAAA,EAC5D,SAAA;AAAA,EAAW;AACb,CAAC;AAWM,IAAM,kBAAkB,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,QAAQ,MAAM;AAY9D,IAAM,eAAA,mBAAuC,IAAI,GAAA,CAAI,CAAC,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAC;AAGxF,IAAM,gCAAqC,IAAI,GAAA,CAAI,CAAC,GAAA,EAAK,GAAG,CAAC;AAIpE,IAAM,YAAA,GAAoC,IAAI,GAAA,CAAI,eAAe;AA2B1D,SAAS,WAAW,KAAA,EAA4B;AAErD,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,IAAI,CAAC,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yCAAA,EAA4C,KAAK,CAAA,CAAE,CAAA;AAAA,EACrE;AACA,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AACpC,EAAA,IAAI,WAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,wCAAA,EAA2C,KAAK,CAAA,CAAE,CAAA;AACpF,EAAA,MAAM,eAAe,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,QAAQ,EAAE,IAAA,EAAK;AACrD,EAAA,MAAM,MAAA,GAAS,cAAA,CAAe,YAAA,EAAc,KAAK,CAAA;AACjD,EAAA,IAAI,OAAO,OAAA,CAAQ,KAAA,CAAM,QAAA,GAAW,CAAC,EAAE,IAAA,EAAK;AAG5C,EAAA,MAAM,YAAA,GAAe,cAAA,CAAe,IAAA,CAAK,IAAI,CAAA;AAC7C,EAAA,IAAI,CAAC,YAAA,EAAc,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAK,CAAA,CAAE,CAAA;AAC9E,EAAA,MAAM,WAAA,GAAc,aAAa,CAAC,CAAA;AAClC,EAAA,IAAI,CAAC,kBAAA,CAAmB,WAAW,CAAA,EAAG;AACpC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gCAAA,EAAmC,WAAW,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EAC9E;AACA,EAAA,IAAA,GAAO,KAAK,KAAA,CAAM,YAAA,CAAa,CAAC,CAAA,CAAE,MAAM,EAAE,SAAA,EAAU;AACpD,EAAA,MAAM,IAAA,GAAO,qBAAqB,WAAW,CAAA;AAG7C,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,EAAG;AACxB,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACjC,IAAA,IAAI,WAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,uCAAA,EAA0C,KAAK,CAAA,CAAE,CAAA;AACnF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA;AACrC,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,EAAK,MAAM,IAAI,MAAM,CAAA,eAAA,EAAkB,WAAW,CAAA,cAAA,EAAiB,KAAK,CAAA,CAAE,CAAA;AACpF,IAAA,IAAI,MAAA,KAAW,GAAA,IAAO,IAAA,CAAK,GAAA,CAAI,MAAA,KAAW,MAAA,IAAU,CAAC,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,EAAG;AACrF,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,MAAM,CAAA,SAAA,EAAY,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,GAAG,CAAC,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAA;AAAA,IAC7F;AACA,IAAA,GAAA,GAAM,MAAA;AACN,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,QAAA,GAAW,CAAC,EAAE,SAAA,EAAU;AAAA,EAC5C,CAAA,MAAA,IAAW,KAAK,GAAA,EAAK;AACnB,IAAA,GAAA,GAAM,IAAA,CAAK,IAAI,OAAA,IAAW,GAAA;AAAA,EAC5B;AAGA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,IAAI,CAAA,EAAG;AACzB,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA,EAAW,MAAM,IAAI,MAAM,CAAA,eAAA,EAAkB,WAAW,CAAA,iBAAA,EAAoB,KAAK,CAAA,CAAE,CAAA;AAC7F,IAAA,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,CAAE,SAAA,EAAU;AAC/B,IAAA,MAAM,QAAA,GAAW,oBAAA,CAAqB,IAAA,CAAK,IAAI,CAAA;AAC/C,IAAA,IAAI,CAAC,QAAA,EAAU,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,KAAK,CAAA,CAAE,CAAA;AACpF,IAAA,MAAA,GAAS,SAAS,CAAC,CAAA;AACnB,IAAA,IAAA,GAAO,KAAK,KAAA,CAAM,QAAA,CAAS,CAAC,CAAA,CAAE,MAAM,EAAE,SAAA,EAAU;AAAA,EAClD,CAAA,MAAA,IAAW,KAAK,SAAA,EAAW;AACzB,IAAA,MAAA,GAAS,GAAA;AAAA,EACX;AAGA,EAAA,MAAM,YAA6B,EAAC;AACpC,EAAA,OAAO,IAAA,CAAK,SAAS,CAAA,EAAG;AACtB,IAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,IAAA,IAAI,eAAA,CAAgB,GAAA,CAAI,EAAE,CAAA,EAAG;AAC3B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,gBAAA,EAAmB,EAAE,CAAA,+BAAA,EAAkC,KAAK,CAAA,CAAE,CAAA;AAAA,IAChF;AACA,IAAA,IAAI,CAAC,aAAA,CAAc,GAAA,CAAI,EAAE,CAAA,EAAG;AAC1B,MAAA,MAAM,IAAI,MAAM,CAAA,2BAAA,EAA8B,EAAE,SAAS,IAAI,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAC7E;AACA,IAAA,MAAM,KAAA,GAAQ,EAAA;AACd,IAAA,IAAA,GAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AACnB,IAAA,MAAM,SAAA,GAAY,WAAA,CAAY,IAAA,CAAK,IAAI,CAAA;AACvC,IAAA,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,CAAA,sBAAA,EAAyB,KAAK,CAAA,0BAAA,EAA6B,KAAK,CAAA,CAAE,CAAA;AAClG,IAAA,MAAM,IAAA,GAAO,UAAU,CAAC,CAAA;AACxB,IAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AAC3B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,IAAI,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IACxE;AACA,IAAA,IAAI,SAAA,CAAU,IAAmB,CAAA,KAAM,MAAA,EAAW;AAChD,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,IAAI,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAC1E;AACA,IAAA,SAAA,CAAU,IAAmB,CAAA,GAAI,KAAA,KAAU,GAAA,GAAM,UAAA,GAAa,UAAA;AAC9D,IAAA,IAAA,GAAO,KAAK,KAAA,CAAM,SAAA,CAAU,CAAC,CAAA,CAAE,MAAM,EAAE,SAAA,EAAU;AAAA,EACnD;AAEA,EAAA,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,WAAA,EAAa,GAAA,EAAK,QAAQ,SAAA,EAAU;AAChE;AAEA,SAAS,cAAA,CAAe,KAAa,KAAA,EAAqC;AACxE,EAAA,IAAI,QAAQ,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,KAAK,CAAA,CAAE,CAAA;AAC5E,EAAA,MAAM,SAAS,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,CAAC,CAAA;AAC7E,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,kCAAA,EAAqC,KAAK,CAAA,CAAE,CAAA;AACrF,EAAA,OAAO,OAAO,GAAA,CAAI,CAAC,MAAM,cAAA,CAAe,CAAA,EAAG,KAAK,CAAC,CAAA;AACnD;AAEA,IAAM,+BAAoC,IAAI,GAAA,CAAI,CAAC,SAAA,EAAW,SAAA,EAAW,GAAG,CAAC,CAAA;AAE7E,SAAS,cAAA,CAAe,KAAa,KAAA,EAA0B;AAG7D,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA;AAC3B,EAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,GAAG,CAAA,qBAAA,EAAwB,KAAK,CAAA,CAAE,CAAA;AAAA,EAClF;AACA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,MAAMA,MAAAA,GAAQ,MAAM,CAAC,CAAA;AACrB,IAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAIA,MAAK,CAAA,EAAG;AAC5B,MAAA,MAAM,IAAI,MAAM,CAAA,8BAAA,EAAiCA,MAAK,SAAS,GAAG,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAClF;AACA,IAAA,OAAO,EAAE,OAAA,EAAS,GAAA,EAAK,KAAA,EAAOA,MAAAA,EAA4B;AAAA,EAC5D;AAEA,EAAA,MAAM,OAAA,GAAU,MAAM,CAAC,CAAA;AACvB,EAAA,MAAM,KAAA,GAAQ,MAAM,CAAC,CAAA;AACrB,EAAA,IAAI,YAAY,EAAA,EAAI;AAClB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,GAAG,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EAClF;AACA,EAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,MAAM,CAAA,8BAAA,EAAiC,KAAK,SAAS,GAAG,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,EAClF;AACA,EAAA,IAAI,OAAA,KAAY,GAAA,IAAO,OAAA,KAAY,GAAA,EAAK;AAItC,IAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,OAAO,CAAA,EAAG;AAClC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,OAAO,CAAA,gCAAA,EAAmC,KAAK,CAAA,CAAE,CAAA;AAAA,IAC9F;AACA,IAAA,IAAI,oBAAA,CAAqB,GAAA,CAAI,OAAA,CAAQ,CAAC,CAAE,CAAA,EAAG;AACzC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,OAAO,CAAA,8BAAA,EAAiC,QAAQ,CAAC,CAAC,CAAA,IAAA,EAAO,KAAK,CAAA,CAAE,CAAA;AAAA,IAC7G;AAAA,EACF;AACA,EAAA,OAAO,EAAE,SAAS,KAAA,EAAmC;AACvD;AAKO,SAAS,gBAAgB,CAAA,EAAsB;AACpD,EAAA,IAAI,CAAA,CAAE,OAAA,KAAY,GAAA,EAAK,OAAO,CAAA,CAAE,KAAA;AAChC,EAAA,OAAO,CAAA,EAAG,CAAA,CAAE,OAAO,CAAA,CAAA,EAAI,EAAE,KAAK,CAAA,CAAA;AAChC;AAiBO,SAAS,mBAAmB,MAAA,EAAqC;AACtE,EAAA,IAAI,OAAO,MAAA,GAAS,CAAA,EAAG,OAAO,CAAC,GAAG,MAAM,CAAA;AACxC,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO,EAAE,GAAA,EAAK,CAAA,EAAG,CAAA,EAAG,UAAA,CAAW,CAAC,CAAA,EAAE,CAAE,CAAA;AAC/D,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAY;AACjC,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,IAAI,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,EAAG;AACrB,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAElB,IAAA,IAAI,SAAA,GAAY,EAAA;AAChB,IAAA,KAAA,IAAS,IAAI,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AAC1C,MAAA,IAAI,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,EAAG;AACrB,MAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,MAAA,IAAI,WAAA,CAAY,CAAA,CAAE,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,EAAG;AAAE,QAAA,SAAA,GAAY,CAAA;AAAG,QAAA;AAAA,MAAO;AAAA,IACrD;AACA,IAAA,IAAI,YAAY,CAAA,EAAG;AAAE,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,GAAG,CAAA;AAAG,MAAA;AAAA,IAAU;AAChD,IAAA,QAAA,CAAS,IAAI,SAAS,CAAA;AAEtB,IAAA,MAAM,MAAA,GAAsB;AAAA,MAC1B,GAAG,CAAA,CAAE,CAAA;AAAA,MACL,SAAA,EAAW,EAAE,GAAG,YAAA,CAAa,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,KAAA,EAAO,UAAA;AAAW,KACjE;AACA,IAAA,GAAA,CAAI,IAAA,CAAK,WAAA,CAAY,MAAM,CAAC,CAAA;AAAA,EAC9B;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,WAAA,CAAY,GAAgB,CAAA,EAAyB;AAC5D,EAAA,IAAI,CAAA,CAAE,OAAA,KAAY,CAAA,CAAE,OAAA,EAAS,OAAO,KAAA;AACpC,EAAA,IAAI,CAAA,CAAE,GAAA,KAAQ,CAAA,CAAE,GAAA,EAAK,OAAO,KAAA;AAC5B,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,EAAA,IAAI,CAAC,UAAA,CAAW,CAAA,CAAE,QAAQ,CAAA,CAAE,MAAM,GAAG,OAAO,KAAA;AAE5C,EAAA,MAAM,MAAA,GAAS,EAAE,SAAA,CAAU,KAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,EAAE,SAAA,CAAU,KAAA;AAC3B,EAAA,MAAM,OAAO,MAAA,KAAW,UAAA;AACxB,EAAA,MAAM,OAAO,MAAA,KAAW,UAAA;AACxB,EAAA,IAAI,EAAE,IAAA,KAAS,IAAA,CAAA,EAAO,OAAO,KAAA;AAC7B,EAAA,IAAI,MAAA,KAAW,UAAA,IAAc,MAAA,KAAW,UAAA,EAAY,OAAO,KAAA;AAE3D,EAAA,KAAA,MAAW,QAAQ,eAAA,EAAiB;AAClC,IAAA,IAAI,SAAS,OAAA,EAAS;AACtB,IAAA,IAAI,CAAA,CAAE,UAAU,IAAI,CAAA,KAAM,EAAE,SAAA,CAAU,IAAI,GAAG,OAAO,KAAA;AAAA,EACtD;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,UAAA,CACP,GACA,CAAA,EACS;AACT,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK;AACjC,IAAA,IAAI,EAAE,CAAC,CAAA,CAAG,OAAA,KAAY,CAAA,CAAE,CAAC,CAAA,CAAG,OAAA,IAAW,CAAA,CAAE,CAAC,EAAG,KAAA,KAAU,CAAA,CAAE,CAAC,CAAA,CAAG,OAAO,OAAO,KAAA;AAAA,EAC7E;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,aAAa,CAAA,EAAqC;AACzD,EAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAQ,GAAG,MAAK,GAAI,CAAA;AAEnC,EAAA,OAAO,IAAA;AACT;AAEA,IAAM,YAAoC,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,QAAQ,MAAM,CAAA;AAKzE,SAAS,YAAY,CAAA,EAAwB;AAClD,EAAA,MAAM,IAAA,GAAO,oBAAA,CAAqB,CAAA,CAAE,OAAO,CAAA;AAI3C,EAAA,MAAM,QAAA,GAAW,IAAI,CAAA,CAAE,MAAA,CAAO,IAAI,eAAe,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAE5D,EAAA,IAAI,GAAA,GAAM,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,EAAE,OAAO,CAAA,CAAA;AAIlC,EAAA,IAAI,IAAA,CAAK,GAAA,IAAO,CAAA,CAAE,GAAA,KAAQ,MAAA,IAAa,EAAE,GAAA,MAAS,IAAA,CAAK,GAAA,CAAI,OAAA,IAAW,GAAA,CAAA,EAAM;AAC1E,IAAA,GAAA,IAAO,CAAA,CAAA,EAAI,EAAE,GAAG,CAAA,CAAA,CAAA;AAAA,EAClB;AAGA,EAAA,IAAI,KAAK,SAAA,IAAa,CAAA,CAAE,WAAW,MAAA,IAAa,CAAA,CAAE,WAAW,GAAA,EAAK;AAChE,IAAA,GAAA,IAAO,CAAA,IAAA,EAAO,EAAE,MAAM,CAAA,CAAA;AAAA,EACxB;AAGA,EAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC5B,IAAA,MAAM,GAAA,GAAM,CAAA,CAAE,SAAA,CAAU,IAAI,CAAA;AAC5B,IAAA,IAAI,GAAA,KAAQ,UAAA,EAAY,GAAA,IAAO,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA;AAAA,SAAA,IAC/B,GAAA,KAAQ,UAAA,EAAY,GAAA,IAAO,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA;AAAA,EAC/C;AAEA,EAAA,OAAO,GAAA;AACT;;;ACxVA,IAAM,YAAA,GAAe,IAAI,GAAA,CAAY,eAAe,CAAA;AAW7C,SAAS,cAAc,KAAA,EAA+B;AAC3D,EAAA,MAAM,CAAC,GAAA,EAAK,GAAGC,KAAI,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AACtC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,KAAK,CAAA,CAAE,CAAA;AACnE,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,KAAA,MAAW,KAAKA,KAAAA,EAAM;AACpB,IAAA,IAAI,CAAC,YAAA,CAAa,GAAA,CAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,CAAC,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAE,CAAA;AACxF,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,CAAC,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAE,CAAA;AACjF,IAAA,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,EACZ;AACA,EAAA,OAAO,EAAE,GAAA,EAAK,YAAA,EAAcA,KAAAA,EAAsB;AACpD;AAIO,SAAS,eAAe,CAAA,EAA2B;AACxD,EAAA,OAAO,CAAA,CAAE,YAAA,CAAa,MAAA,KAAW,CAAA,GAAI,EAAE,GAAA,GAAM,CAAA,EAAG,CAAA,CAAE,GAAG,CAAA,CAAA,EAAI,CAAA,CAAE,YAAA,CAAa,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AACnF;AAMO,SAAS,eAAe,CAAA,EAA4B;AACzD,EAAA,MAAMA,QAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,KAAK,CAAA,CAAE,YAAA,EAAcA,KAAAA,CAAK,CAAC,CAAA,GAAI,UAAA;AAC1C,EAAA,MAAM,OAAgB,EAAE,IAAA,EAAM,KAAA,EAAO,GAAA,EAAK,EAAE,GAAA,EAAI;AAChD,EAAA,IAAI,OAAO,IAAA,CAAKA,KAAI,EAAE,MAAA,GAAS,CAAA,OAAQ,IAAA,GAAOA,KAAAA;AAC9C,EAAA,OAAO,IAAA;AACT;;;ACNA,SAAS,iBAAiB,KAAA,EAAyD;AACjF,EAAA,IAAI,KAAA,KAAU,MAAM,OAAO,UAAA;AAC3B,EAAA,IAAI,KAAA,KAAU,YAAY,OAAO,UAAA;AACjC,EAAA,OAAO,WAAA;AACT;AAeO,SAAS,cAAA,CACd,CAAA,EACAA,KAAAA,EACA,KAAA,EACS;AAET,EAAA,IAAI,GAAA,GAAsB,WAAA;AAC1B,EAAA,IAAI,IAAA,GAAuB,WAAA;AAC3B,EAAA,IAAI,IAAA,GAAuB,WAAA;AAC3B,EAAA,IAAI,KAAA,GAAwB,WAAA;AAE5B,EAAA,IAAIA,KAAAA,EAAM;AACR,IAAA,GAAA,GAAM,gBAAA,CAAiBA,MAAK,GAAG,CAAA;AAC/B,IAAA,KAAA,GAAQ,gBAAA,CAAiBA,MAAK,KAAK,CAAA;AAInC,IAAA,IAAIA,KAAAA,CAAK,QAAQ,MAAA,EAAW;AAC1B,MAAA,MAAM,MAAA,GAAS,gBAAA,CAAiBA,KAAAA,CAAK,GAAG,CAAA;AACxC,MAAA,IAAI,OAAO,IAAA,GAAO,MAAA;AAAA,WACb,IAAA,GAAO,MAAA;AAAA,IACd,CAAA,MAAO;AACL,MAAA,IAAA,GAAO,gBAAA,CAAiBA,MAAK,IAAI,CAAA;AACjC,MAAA,IAAA,GAAO,gBAAA,CAAiBA,MAAK,IAAI,CAAA;AAAA,IACnC;AAAA,EACF;AAEA,EAAA,OACE,SAAS,GAAA,EAAO,CAAA,CAAE,MAAM,CAAA,IACxB,QAAA,CAAS,MAAO,CAAA,CAAE,OAAO,CAAA,IACzB,QAAA,CAAS,MAAO,CAAA,CAAE,OAAO,KACzB,QAAA,CAAS,KAAA,EAAO,EAAE,QAAQ,CAAA;AAE9B;AAEA,SAAS,QAAA,CAAS,KAAqB,IAAA,EAAwB;AAC7D,EAAA,IAAI,GAAA,KAAQ,YAAY,OAAO,IAAA;AAC/B,EAAA,IAAI,GAAA,KAAQ,WAAA,EAAa,OAAO,CAAC,IAAA;AACjC,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,QAAA,CAAS,UAAkB,OAAA,EAAqC;AAC9E,EAAA,MAAM,KAAA,GAAQ,SAAS,WAAA,EAAY;AACnC,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC1B,IAAA,OAAO,QAAQ,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,WAAA,OAAkB,KAAK,CAAA;AAAA,EACtD;AACA,EAAA,OAAO,OAAA,CAAQ,aAAY,KAAM,KAAA;AACnC;AAIA,SAAS,cAAA,CACP,GACA,IAAA,EACS;AACT,EAAA,IAAI,KAAK,IAAA,KAAS,MAAA,IAAa,CAAA,CAAE,IAAA,KAAS,UAAa,CAAC,IAAA,CAAK,IAAI,CAAA,CAAE,MAAK,CAAE,QAAA,CAAS,CAAA,CAAE,IAAI,GAAG,OAAO,IAAA;AACnG,EAAA,OAAO,QAAA,CAAS,CAAA,CAAE,GAAA,EAAK,IAAA,CAAK,GAAG,CAAA;AACjC;AAQA,SAAS,iBAAiB,MAAA,EAAqC;AAC7D,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,MAAM,OAAO,MAAA;AAC1D,EAAA,MAAM,IAAK,MAAA,CAA8B,IAAA;AACzC,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,MAAA;AACrC;AAiBA,SAAS,SAAA,CAA4B,GAAW,MAAA,EAAiC;AAC/E,EAAA,OAAO,CAAA,CAAE,WAAW,MAAM,CAAA;AAC5B;AASO,SAAS,gBAAgB,IAAA,EAAyC;AACvE,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,OAAO,IAAA,KAAS,IAAA,IAAQ,OAAO,IAAA,CAAK,MAAA,KAAW,UAAA,GAC3C,EAAE,IAAA,EAAM,WAAA,EAAa,MAAA,EAAQ,IAAA,CAAK,MAAA,EAAO,GACzC,IAAA;AAAA,EACN;AACA,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AACrC,EAAA,IAAI,IAAA,KAAS,OAAA,IAAW,IAAA,KAAS,eAAA,IAAmB,SAAS,iBAAA,EAAmB;AAC9E,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAK;AAAA,EACpC;AACA,EAAA,IAAI,SAAA,CAAU,IAAA,EAAM,aAAa,CAAA,EAAG;AAClC,IAAA,OAAO,EAAE,MAAM,YAAA,EAAc,IAAA,EAAM,KAAK,KAAA,CAAM,aAAA,CAAc,MAAM,CAAA,EAAE;AAAA,EACtE;AAGA,EAAA,IAAI,SAAA,CAAU,IAAA,EAAM,OAAO,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA;AACtC,IAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,QAAA,CAAS,WAAW,CAAA;AACjD,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,kBAAkB,IAAA,CAAK,KAAA,CAAM,GAAG,CAAC,WAAA,CAAY,MAAM,CAAA,GAAI,IAAA;AAAA,MAC7D;AAAA,KACF;AAAA,EACF;AAGA,EAAA,OAAO,IAAA;AACT;AA6BO,SAAS,WAAA,CACd,MAAA,EACA,UAAA,EACA,UAAA,EACA,QAAA,EACS;AACT,EAAA,IAAI,UAAA,KAAe,QAAW,OAAO,IAAA;AACrC,EAAA,MAAM,IAAA,GAAO,gBAAgB,UAAU,CAAA;AACvC,EAAA,IAAI,IAAA,KAAS,MAAM,OAAO,KAAA;AAE1B,EAAA,QAAQ,KAAK,IAAA;AAAM;AAAA,IAEjB,KAAK,WAAA;AACH,MAAA,OAAO,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,UAAU,CAAA;AAAA;AAAA;AAAA,IAIvC,KAAK,MAAA;AACH,MAAA,OAAO,UAAA,KAAe,MAAA,IAAa,UAAA,KAAe,IAAA,CAAK,IAAA;AAAA,IAEzD,KAAK,YAAA;AACH,MAAA,OAAO,gBAAA,CAAiB,MAAM,CAAA,KAAM,IAAA,CAAK,IAAA;AAAA,IAE3C,KAAK,MAAA;AACH,MAAA,IAAI,QAAA,KAAa,MAAA,IAAa,QAAA,KAAa,IAAA,CAAK,MAAM,OAAO,KAAA;AAC7D,MAAA,OAAO,IAAA,CAAK,eAAA,GAAkB,UAAA,KAAe,eAAA,GAAkB,IAAA;AAAA,IAEjE,SAAS;AAIP,MAAA,OAAO,KAAA;AAAA,IACT;AAAA;AAEJ;AAuBA,SAAS,eAAe,IAAA,EAAuC;AAC7D,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,OAAO,CAAC,EAAE,OAAA,EAAS,GAAA,EAAK,KAAA,EAAO,MAAM,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,IAAA;AACT;AAMO,SAAS,UAAA,CAAW,MAA6B,GAAA,EAA4B;AAClF,EAAA,IAAI,IAAA,KAAS,QAAW,OAAO,IAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,eAAe,IAAI,CAAA;AACjC,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAC/B,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,IAAI,cAAA,CAAe,CAAA,EAAG,GAAG,CAAA,EAAG,OAAO,IAAA;AAAA,EACrC;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,cAAA,CAAe,GAAc,GAAA,EAA4B;AAChE,EAAA,IAAI,CAAA,CAAE,YAAY,GAAA,EAAK;AAGrB,IAAA,IAAI,CAAA,CAAE,KAAA,KAAU,GAAA,EAAK,OAAO,IAAA;AAC5B,IAAA,MAAM,UAAA,GAAa,GAAA,CAAI,eAAA,CAAgB,IAAA,GAAO,CAAA;AAC9C,IAAA,OAAO,CAAA,CAAE,KAAA,KAAU,SAAA,GAAY,UAAA,GAAa,CAAC,UAAA;AAAA,EAC/C;AAGA,EAAA,MAAM,KAAK,CAAA,CAAE,OAAA,KAAY,GAAA,GAAM,GAAA,CAAI,cAAc,CAAA,CAAE,OAAA;AACnD,EAAA,IAAI,EAAA,IAAM,MAAM,OAAO,KAAA;AACvB,EAAA,IAAI,CAAA,CAAE,KAAA,KAAU,GAAA,EAAK,OAAO,IAAA;AAC5B,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,eAAA,CAAgB,GAAA,CAAI,EAAE,CAAA;AAC5C,EAAA,OAAO,CAAA,CAAE,KAAA,KAAU,SAAA,GAAY,SAAA,GAAY,CAAC,SAAA;AAC9C;AAQO,SAAS,eAAA,CAAgB,MAAc,IAAA,EAAuB;AACnE,EAAA,MAAM,CAAA,GAAI,KAAK,WAAA,EAAY;AAC3B,EAAA,MAAM,CAAA,GAAI,KAAK,WAAA,EAAY;AAC3B,EAAA,IAAI,CAAA,KAAM,GAAA,IAAO,CAAA,KAAM,KAAA,EAAO,OAAO,IAAA;AACrC,EAAA,IAAI,CAAA,CAAE,QAAA,CAAS,IAAI,CAAA,EAAG,OAAO,CAAA,CAAE,UAAA,CAAW,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AACxD,EAAA,OAAO,CAAA,KAAM,CAAA;AACf;AAIO,SAAS,gBAAA,CACd,OACA,KAAA,EACS;AACT,EAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,MAAA,KAAW,GAAG,OAAO,IAAA;AACzC,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,EAAA,KAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,eAAA,CAAgB,EAAA,CAAG,IAAA,EAAM,CAAC,CAAC,CAAC,CAAA;AAC1E;AAYO,SAAS,SAAA,CACd,CAAA,EACA,IAAA,EACA,KAAA,EACA,QAAA,EACS;AAKT,EAAA,IAAI,IAAA,CAAK,UAAU,MAAA,EAAW;AAC5B,IAAA,MAAM,MAAoB,QAAA,IAAY,EAAE,WAAA,EAAa,IAAA,EAAM,iBAAiB,aAAA,EAAc;AAC1F,IAAA,IAAI,CAAC,UAAA,CAAW,IAAA,CAAK,KAAA,EAAO,GAAG,GAAG,OAAO,KAAA;AAAA,EAC3C;AAEA,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,KAAA,EAAO;AACV,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,KAAA,EAAO,OAAO,KAAA;AAC7B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,IAAI,GAAG,OAAO,KAAA;AACrC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,UAAA,EAAY;AACf,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,UAAA,EAAY,OAAO,KAAA;AAClC,MAAA,IAAI,CAAA,CAAE,KAAA,KAAU,MAAA,EAAQ,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,IAAI,GAAG,OAAO,KAAA;AACrC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,GAAA;AACpC,MAAA,IAAI,cAAc,IAAA,IAAQ,EAAE,CAAA,CAAE,MAAA,GAAS,IAAI,OAAO,KAAA;AAClD,MAAA,IAAI,cAAc,MAAA,IAAU,EAAE,CAAA,CAAE,MAAA,GAAS,IAAI,OAAO,KAAA;AACpD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,MAAM,SAAA,GAAY,KAAK,SAAA,IAAa,GAAA;AACpC,MAAA,IAAI,cAAc,KAAA,IAAS,EAAE,CAAA,CAAE,KAAA,GAAQ,IAAI,OAAO,KAAA;AAClD,MAAA,IAAI,cAAc,IAAA,IAAQ,EAAE,CAAA,CAAE,KAAA,GAAQ,IAAI,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AAMjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,aAAA,EAAe;AAClB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,aAAA,EAAe,OAAO,KAAA;AACrC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,aAAA,EAAe;AAClB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,aAAA,EAAe,OAAO,KAAA;AACrC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,WAAA,EAAa;AAChB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,WAAA,EAAa,OAAO,KAAA;AACnC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AAGjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,MAAA,EAAQ;AAGX,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,aAAA,EAAe,OAAO,KAAA;AAIrC,MAAA,IAAI,CAAA,CAAE,KAAA,KAAU,OAAA,EAAS,OAAO,KAAA;AAChC,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AAGjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,aAAA,EAAe;AAGlB,MAAA,IAAI,EAAE,IAAA,KAAS,aAAA,IAAiB,CAAA,CAAE,KAAA,KAAU,SAAS,OAAO,KAAA;AAC5D,MAAA,IAAI,CAAC,cAAA,CAAe,CAAA,EAAG,KAAK,IAAA,EAAM,KAAK,GAAG,OAAO,KAAA;AACjD,MAAA,OAAO,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,CAAK,QAAQ,CAAA,CAAE,UAAA,EAAY,EAAE,QAAQ,CAAA;AAAA,IACxE;AAAA,IAEA,KAAK,YAAA,EAAc;AACjB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,YAAA,EAAc,OAAO,KAAA;AACpC,MAAA,IAAI,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,OAAA,EAAS,OAAO,KAAA;AACvC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,eAAA,EAAiB;AACpB,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,eAAA,EAAiB,OAAO,KAAA;AACvC,MAAA,IAAI,CAAA,CAAE,OAAA,KAAY,IAAA,CAAK,OAAA,EAAS,OAAO,KAAA;AACvC,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,MAAA,EAAQ;AACX,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,MAAA,EAAQ,OAAO,KAAA;AAC9B,MAAA,IAAI,CAAC,gBAAA,CAAiB,CAAA,CAAE,OAAO,IAAA,CAAK,KAAK,GAAG,OAAO,KAAA;AACnD,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,OAAA,EAAS,OAAO,KAAA;AAC/B,MAAA,IAAI,CAAC,gBAAA,CAAiB,CAAA,CAAE,OAAO,IAAA,CAAK,KAAK,GAAG,OAAO,KAAA;AACnD,MAAA,OAAO,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,KAAK,CAAA;AAAA,IAC3C;AAAA,IAEA,SAAS;AAIP,MAAA,OAAO,KAAA;AAAA,IACT;AAAA;AAEJ;AAEA,IAAM,aAAA,uBAAyC,GAAA,EAAI;;;ACjenD,IAAM,oBAAA,GAAkE;AAAA,EACtE,GAAA,EAAK,SAAA;AAAA,EACL,UAAA,EAAY,SAAA;AAAA,EACZ,KAAA,EAAO,OAAA;AAAA,EACP,KAAA,EAAO,OAAA;AAAA,EACP,KAAA,EAAO,OAAA;AAAA,EACP,WAAA,EAAa,QAAA;AAAA,EACb,WAAA,EAAa,aAAA;AAAA,EACb,SAAA,EAAW,WAAA;AAAA,EACX,IAAA,EAAM,MAAA;AAAA,EACN,WAAA,EAAa,aAAA;AAAA,EACb,UAAA,EAAY,YAAA;AAAA,EACZ,aAAA,EAAe,eAAA;AAAA,EACf,IAAA,EAAM,MAAA;AAAA,EACN,KAAA,EAAO;AACT,CAAA;AAEA,IAAM,uBAAuB,IAAI,GAAA;AAAA,EAC9B,MAAA,CAAO,QAAQ,oBAAoB,CAAA,CACjC,OAAO,CAAC,CAAA,KAAoC,EAAE,CAAC,CAAA,KAAM,MAAS,CAAA,CAC9D,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,OAAO,CAAA,KAAM,CAAC,OAAA,EAAS,IAAI,CAAC;AAC7C,CAAA;AAIO,SAAS,wBAAwB,IAAA,EAAyC;AAC/E,EAAA,OAAO,qBAAqB,IAAI,CAAA;AAClC;AAIO,SAAS,wBAAwB,OAAA,EAA4C;AAClF,EAAA,OAAO,oBAAA,CAAqB,IAAI,OAAO,CAAA;AACzC;;;ACrBO,SAAS,YAAY,MAAA,EAAkC;AAC5D,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KAAuB;AACnC,IAAA,MAAM,IAAI,MAAM,CAAA,aAAA,EAAgB,GAAG,KAAK,WAAA,CAAY,MAAM,CAAC,CAAA,CAAE,CAAA;AAAA,EAC/D,CAAA;AACA,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,KAAQ,GAAA,GAAM,SAAY,MAAA,CAAO,GAAA;AAEpD,EAAA,MAAMA,QAAgB,EAAC;AACvB,EAAA,KAAA,MAAW,CAAC,MAAM,GAAG,CAAA,IAAK,OAAO,OAAA,CAAQ,MAAA,CAAO,SAAS,CAAA,EAAG;AAC1D,IAAAA,KAAAA,CAAK,IAAqB,CAAA,GAAI,GAAA,KAAQ,aAAa,IAAA,GAAO,UAAA;AAAA,EAC5D;AAEA,EAAA,MAAM,SAAgD,EAAC;AACvD,EAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,MAAA,CAAO,MAAA,KAAW,KAC5C,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,CAAG,YAAY,GAAA,IAAO,MAAA,CAAO,MAAA,CAAO,CAAC,EAAG,KAAA,KAAU,GAAA;AACtE,EAAA,IAAI,CAAC,eAAA,EAAiB,MAAA,CAAO,KAAA,GAAQ,MAAA,CAAO,MAAA;AAE5C,EAAA,MAAM,QAAA,GAAW,CAAwB,IAAA,KAAe;AACtD,IAAA,MAAM,QAAQ,IAAA,CAAK,IAAA;AACnB,IAAA,MAAM,MAAA,GAAS,EAAE,GAAGA,KAAAA,EAAM,GAAG,KAAA,EAAM;AACnC,IAAA,MAAM,GAAA,GAAM,EAAE,GAAG,IAAA,EAAM,GAAG,MAAA,EAAO;AACjC,IAAA,IAAI,OAAO,IAAA,CAAK,MAAM,EAAE,MAAA,GAAS,CAAA,MAAO,IAAA,GAAO,MAAA;AAC/C,IAAA,OAAO,GAAA;AAAA,EACT,CAAA;AAEA,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,MAAA,IAAa,MAAA,CAAO,WAAW,GAAA,EAAK;AACxD,IAAA,IAAI,eAAA,CAAgB,MAAA,CAAO,MAAoB,CAAA,KAAM,IAAA,EAAM;AACzD,MAAA,IAAA,CAAK,CAAA,CAAA,EAAI,MAAA,CAAO,MAAM,CAAA,sBAAA,CAAwB,CAAA;AAAA,IAChD;AACA,IAAA,MAAA,GAAS,MAAA,CAAO,MAAA;AAAA,EAClB;AACA,EAAA,MAAM,IAAI,MAAA,KAAW,MAAA,GAAY,EAAC,GAAI,EAAE,MAAA,EAAO;AAE/C,EAAA,MAAM,IAAA,GAAO,uBAAA,CAAwB,MAAA,CAAO,OAAO,CAAA;AACnD,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,MAAA;AACH,MAAA,OAAO,IAAA,CAAK,CAAA,EAAG,MAAA,CAAO,OAAO,CAAA,wBAAA,CAA0B,CAAA;AAAA,IACzD,KAAK,OAAA;AAAA,IACL,KAAK,aAAA;AAAA,IACL,KAAK,aAAA;AAAA,IACL,KAAK,MAAA;AAAA,IACL,KAAK,aAAA;AAAA,IACL,KAAK,WAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAG,GAAG,CAAA;AAAA,IAChC,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAI,GAAA,GAAM,EAAE,SAAA,EAAW,GAAA,EAAqB,GAAI,EAAC,EAAI,GAAG,GAAG,CAAA;AAAA,IACrF,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAI,GAAA,GAAM,EAAE,SAAA,EAAW,GAAA,EAAoB,GAAI,EAAC,EAAI,GAAG,GAAG,CAAA;AAAA,IACpF,KAAK,KAAA;AAAA,IACL,KAAK,UAAA,EAAY;AACf,MAAA,IAAI,GAAA,KAAQ,MAAA,EAAW,OAAO,IAAA,CAAK,iCAAiC,CAAA;AACpE,MAAA,MAAM,EAAE,GAAA,EAAK,YAAA,EAAa,GAAI,cAAc,GAAG,CAAA;AAC/C,MAAA,MAAM,WAAoB,EAAC;AAC3B,MAAA,KAAA,MAAW,CAAA,IAAK,YAAA,EAAc,QAAA,CAAS,CAAC,CAAA,GAAI,UAAA;AAC5C,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAA,EAAK,GAAI,YAAA,CAAa,MAAA,GAAS,CAAA,GAAI,EAAE,IAAA,EAAM,QAAA,EAAS,GAAI,IAAK,CAAA;AAAA,IACvF;AAAA,IACA,KAAK,YAAA;AAAA,IACL,KAAK,eAAA;AACH,MAAA,IAAI,QAAQ,MAAA,EAAW,OAAO,IAAA,CAAK,CAAA,EAAA,EAAK,IAAI,CAAA,4BAAA,CAA8B,CAAA;AAC1E,MAAA,OAAO,SAAS,EAAE,IAAA,EAAM,SAAS,MAAA,CAAO,GAAG,GAAG,CAAA;AAAA,IAChD,KAAK,MAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,EAAE,IAAA,EAAM,GAAI,MAAM,EAAE,KAAA,EAAO,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAE,GAAI,IAAK,CAAA;AAAA;AAEzE;;;AChFA,IAAM,SAAA,GAAyC;AAAA,EAC7C,GAAA,EAAK,KAAA;AAAA,EAAO,KAAA,EAAO,OAAA;AAAA,EAAS,GAAA,EAAK,KAAA;AAAA,EAAO,IAAA,EAAM,MAAA;AAAA,EAAQ,IAAA,EAAM;AAC9D,CAAA;AACA,IAAMC,aAAoC,CAAC,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,QAAQ,MAAM,CAAA;AAIzE,IAAM,WAAA,GAAc;AAAA,EACzB,IAAA,EAAM,6DAAA;AAAA,EACN,aAAA,EAAe;AACjB;AAKO,IAAM,uBAAA,GAA0B;AAAA,EACrC,MAAA,EAAQ,iOAAA;AAAA,EACR,OAAA,EAAS,wKAAA;AAAA,EACT,GAAA,EAAK,iOAAA;AAAA,EACL,MAAA,EAAQ,iKAAA;AAAA,EACR,SAAA,EAAW;AACb;AAcA,SAAS,KAAK,KAAA,EAA6C;AACzD,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAO,UAAA,EAAY,WAAA,CAAY,KAAK,CAAA,EAAE;AAC/D;AAEA,SAAS,QAAQ,KAAA,EAAkC;AACjD,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAA;AAC/B,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAM,CAAC,CAAA;AACtC,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA,EAAG,KAAA,CAAM,CAAC,CAAC,CAAA,KAAA,EAAQ,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA;AAC1D,EAAA,OAAO,CAAA,EAAG,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,MAAA,EAAS,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAC,CAAA,CAAA;AACzE;AAEA,SAAS,mBAAmBD,KAAAA,EAAmE;AAC7F,EAAA,MAAM,WAAqB,EAAC;AAC5B,EAAA,MAAM,WAAqB,EAAC;AAC5B,EAAA,KAAA,MAAW,QAAQC,UAAAA,EAAW;AAC5B,IAAA,MAAM,GAAA,GAAMD,MAAK,IAAI,CAAA;AACrB,IAAA,IAAI,QAAQ,UAAA,EAAY,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,SAAA,IAC5C,QAAQ,UAAA,EAAY,QAAA,CAAS,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,EAC5D;AACA,EAAA,OAAO,EAAE,UAAU,QAAA,EAAS;AAC9B;AAEA,SAAS,cAAA,CAAe,EAAE,OAAA,EAAS,KAAA,EAAM,EAAsC;AAC7E,EAAA,MAAM,OAAA,GAAU,YAAY,GAAA,GAAM,UAAA,GAC9B,YAAY,GAAA,GAAM,UAAA,GAClB,OAAO,OAAO,CAAA,KAAA,CAAA;AAClB,EAAA,IAAI,KAAA,KAAU,WAAW,OAAO,CAAC,GAAG,OAAO,CAAA,IAAA,CAAA,EAAQ,IAAA,CAAK,MAAM,CAAC,CAAA;AAC/D,EAAA,IAAI,KAAA,KAAU,WAAW,OAAO,CAAC,GAAG,OAAO,CAAA,IAAA,CAAA,EAAQ,IAAA,CAAK,aAAa,CAAC,CAAA;AACtE,EAAA,OAAO,CAAC,CAAA,EAAG,OAAO,CAAA,gBAAA,CAAkB,CAAA;AACtC;AAEA,SAAS,YAAY,MAAA,EAAsD;AACzE,EAAA,IAAI,OAAO,MAAA,KAAW,CAAA,SAAU,cAAA,CAAe,MAAA,CAAO,CAAC,CAAC,CAAA;AACxD,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,MAAA,CAAO,OAAA,CAAQ,CAAC,CAAA,EAAG,CAAA,KAAM;AACvB,IAAA,IAAI,CAAA,GAAI,CAAA,EAAG,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AAC1B,IAAA,GAAA,CAAI,IAAA,CAAK,GAAG,cAAA,CAAe,CAAC,CAAC,CAAA;AAAA,EAC/B,CAAC,CAAA;AACD,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,YAAA,CAAa,QAA4B,SAAA,EAA4B;AAC5E,EAAA,IAAI,CAAC,SAAA,IAAa,MAAA,KAAW,MAAA,EAAW,OAAO,EAAA;AAC/C,EAAA,IAAI,MAAA,KAAW,KAAK,OAAO,WAAA;AAC3B,EAAA,IAAI,MAAA,KAAW,SAAS,OAAO,kBAAA;AAC/B,EAAA,OAAO,SAAS,MAAM,CAAA,CAAA;AACxB;AAIA,SAAS,YAAY,MAAA,EAAyC;AAC5D,EAAA,OAAO,MAAA,CAAO,GAAA,KAAQ,GAAA,GAAM,MAAA,GAAY,MAAA,CAAO,GAAA;AACjD;AAIA,SAAS,QAAA,CAAS,UAA6B,IAAA,EAAsB;AACnE,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,YAAY,IAAI,CAAA,CAAA;AAClD,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG,OAAO,YAAY,QAAA,CAAS,CAAC,CAAC,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AACjE,EAAA,OAAO,CAAA,eAAA,EAAkB,OAAA,CAAQ,QAAQ,CAAC,QAAQ,IAAI,CAAA,CAAA;AACxD;AAEA,SAAS,YAAA,CAAa,QAAqB,QAAA,EAAqC;AAC9E,EAAA,MAAM,IAAA,GAAO,oBAAA,CAAqB,MAAA,CAAO,OAAsB,CAAA;AAC/D,EAAA,MAAM,GAAA,GAAM,YAAY,MAAM,CAAA;AAC9B,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,MAAA,CAAO,MAAA,EAAQ,KAAK,SAAS,CAAA;AAEzD,EAAA,QAAQ,OAAO,OAAA;AAAS,IACtB,KAAK,SAAA;AAAA,IACL,KAAK,OAAA;AAAA,IACL,KAAK,SAAA,EAAW;AACd,MAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KAAY,SAAA,GAAY,YACxC,MAAA,CAAO,OAAA,KAAY,UAAU,UAAA,GAC7B,OAAA;AACJ,MAAA,MAAM,MAAM,GAAA,IAAO,SAAA;AACnB,MAAA,OAAO,QAAA,CAAS,MAAA,GAAS,CAAA,GACrB,CAAA,eAAA,EAAkB,QAAQ,QAAQ,CAAC,CAAA,KAAA,EAAQ,IAAI,IAAI,GAAG,CAAA,CAAA,GACtD,CAAA,SAAA,EAAY,IAAI,IAAI,GAAG,CAAA,CAAA;AAAA,IAC7B;AAAA,IACA,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,YAAY,GAAA,KAAQ,IAAA,GAAO,KAAA,GAC7B,GAAA,KAAQ,SAAS,OAAA,GACjB,EAAA;AACJ,MAAA,OAAO,SAAS,QAAA,EAAU,CAAA,OAAA,EAAU,SAAS,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA;AAAA,IAC1D;AAAA,IACA,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,YAAY,GAAA,KAAQ,IAAA,GAAO,KAAA,GAC7B,GAAA,KAAQ,QAAQ,MAAA,GAChB,EAAA;AACJ,MAAA,OAAO,SAAS,QAAA,EAAU,CAAA,OAAA,EAAU,SAAS,CAAA,EAAG,MAAM,CAAA,CAAE,CAAA;AAAA,IAC1D;AAAA,IACA,KAAK,YAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,aAAA,EAAgB,GAAA,IAAO,UAAU,CAAA,QAAA,CAAU,CAAA;AAAA,IACvE,KAAK,eAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,UAAA,EAAa,GAAA,IAAO,UAAU,CAAA,QAAA,CAAU,CAAA;AAAA,IACpE,KAAK,aAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,sBAAA,EAAyB,MAAM,CAAA,CAAE,CAAA;AAAA,IAC7D,KAAK,WAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,YAAA,EAAe,MAAM,CAAA,CAAE,CAAA;AAAA,IACnD,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,MAAA,EAAS,MAAM,CAAA,CAAE,CAAA;AAAA,IAC7C,KAAK,aAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,OAAA,EAAU,MAAM,CAAA,CAAE,CAAA;AAAA,IAC9C,KAAK,QAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,WAAA,EAAc,MAAM,CAAA,CAAE,CAAA;AAAA,IAClD,KAAK,MAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAE,CAAA;AAAA,IAC5C,KAAK,MAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,MAAA,EAAS,GAAA,IAAO,KAAK,CAAA,wBAAA,CAA0B,CAAA;AAAA,IAC3E,KAAK,OAAA;AACH,MAAA,OAAO,QAAA,CAAS,QAAA,EAAU,CAAA,OAAA,EAAU,GAAA,IAAO,KAAK,CAAA,QAAA,CAAU,CAAA;AAAA;AAEhE;AAeO,SAAS,kBAAA,CACd,MAAA,EACA,IAAA,GAA6B,EAAC,EACG;AACjC,EAAA,MAAM,EAAE,UAAA,GAAa,IAAA,EAAM,MAAA,GAAS,MAAK,GAAI,IAAA;AAC7C,EAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAS,GAAI,kBAAA,CAAmB,OAAO,SAAS,CAAA;AAClE,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,MAAA,EAAQ,QAAQ,CAAA;AAC5C,EAAA,MAAM,SAAA,GAAY,SAAS,MAAA,GAAS,CAAA,GAChC,KAAK,OAAA,CAAQ,QAAQ,CAAC,CAAA,UAAA,CAAA,GACtB,EAAA;AAEJ,EAAA,MAAM,QAAgC,EAAC;AACvC,EAAA,MAAM,IAAA,GAAO,cAAc,MAAM,CAAA,QAAA,CAAA;AACjC,EAAA,KAAA,CAAM,IAAA,CAAK,UAAA,GAAa,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAY,GAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,GAAI,IAAI,CAAA;AAC3E,EAAA,KAAA,CAAM,IAAA,CAAK,GAAG,WAAA,CAAY,MAAA,CAAO,MAAM,CAAC,CAAA;AACxC,EAAA,IAAI,SAAA,EAAW,KAAA,CAAM,IAAA,CAAK,SAAS,CAAA;AACnC,EAAA,IAAI,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA;AAC1B,EAAA,OAAO,qBAAqB,KAAK,CAAA;AACnC;AAMO,SAAS,aAAA,CAAc,MAAA,EAAqB,IAAA,GAA6B,EAAC,EAAW;AAC1F,EAAA,OAAO,kBAAA,CAAmB,MAAA,EAAQ,IAAI,CAAA,CACnC,IAAI,CAAC,CAAA,KAAO,OAAO,CAAA,KAAM,WAAW,CAAA,GAAI,CAAA,CAAE,KAAM,CAAA,CAChD,KAAK,EAAE,CAAA;AACZ;AAEA,SAAS,qBAAqB,KAAA,EAAgE;AAC5F,EAAA,MAAM,MAA8B,EAAC;AACrC,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,MAAM,IAAA,GAAO,GAAA,CAAI,GAAA,CAAI,MAAA,GAAS,CAAC,CAAA;AAC/B,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,IAAA,KAAS,QAAA,EAAU,GAAA,CAAI,GAAA,CAAI,MAAA,GAAS,CAAC,CAAA,GAAI,IAAA,GAAO,CAAA;AAAA,SAC/E,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACjB;AACA,EAAA,OAAO,GAAA;AACT;;;ACpMO,SAAS,sBAAsB,GAAA,EAAqC;AACzE,EAAA,IAAI,GAAA,KAAQ,SAAA,EAAW,OAAO,EAAC;AAC/B,EAAA,MAAM,MAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,IAAA,IAAQ,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACjC,IAAA,GAAA,CAAI,IAAmB,CAAA,GAAI,UAAA;AAAA,EAC7B;AACA,EAAA,OAAO,GAAA;AACT;AAKO,SAAS,mBAAmBA,KAAAA,EAA+B;AAChE,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQA,KAAI,CAAA,CACvB,IAAA,CAAK,CAAC,CAAC,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA,KAAM,EAAE,aAAA,CAAc,CAAC,CAAC,CAAA,CACrC,GAAA,CAAI,CAAC,CAAC,IAAA,EAAM,GAAG,CAAA,KAAM,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA,CACrC,KAAK,GAAG,CAAA;AACb;;;AC2BO,SAAS,aACd,EAAA,EAC6C;AAC7C,EAAA,OAAO,MAAA,CAAO,MAAA;AAAA,IACZ,CAAC,GAAA,EAAc,UAAA,KAAiC,EAAA,CAAG,KAAK,UAAU,CAAA;AAAA,IAClE,EAAE,iBAAiB,IAAA;AAAc,GACnC;AACF;AAIO,SAAS,cACd,EAAA,EAC8C;AAC9C,EAAA,OAAO,MAAA,CAAO,MAAA;AAAA,IACZ,CAAC,IAAA,EAAe,UAAA,KAAiC,EAAA,CAAG,UAAU,CAAA;AAAA,IAC9D,EAAE,iBAAiB,KAAA;AAAe,GACpC;AACF;;;AC5DO,SAAS,eAAA,GAA2B;AACzC,EAAA,IAAI,OAAO,SAAA,KAAc,WAAA,IAAe,CAAC,WAAW,OAAO,KAAA;AAC3D,EAAA,MAAM,GAAA,GAAM,SAAA;AAEZ,EAAA,MAAM,MAAM,GAAA,CAAI,aAAA,EAAe,YAAY,GAAA,CAAI,QAAA,IAAY,IAAI,SAAA,IAAa,EAAA;AAC5E,EAAA,OAAO,uBAAA,CAAwB,KAAK,GAAG,CAAA;AACzC;;;ACTA,SAAS,UAAUA,KAAAA,EAAmC;AACpD,EAAA,IAAI,CAACA,OAAM,OAAO,CAAA;AAClB,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAIA,KAAAA,CAAK,QAAQ,IAAA,EAAM,CAAA,EAAA;AACvB,EAAA,IAAIA,KAAAA,CAAK,SAAS,IAAA,EAAM,CAAA,EAAA;AACxB,EAAA,IAAIA,KAAAA,CAAK,SAAS,IAAA,EAAM,CAAA,EAAA;AACxB,EAAA,IAAIA,KAAAA,CAAK,QAAQ,IAAA,EAAM,CAAA,EAAA;AACvB,EAAA,IAAIA,KAAAA,CAAK,UAAU,IAAA,EAAM,CAAA,EAAA;AACzB,EAAA,OAAO,CAAA;AACT;AAgBA,SAAS,WAAW,MAAA,EAAwC;AAC1D,EAAA,IAAI,MAAA,KAAW,QAAW,OAAO,CAAA;AACjC,EAAA,MAAM,IAAA,GAAO,gBAAgB,MAAM,CAAA;AACnC,EAAA,IAAI,IAAA,KAAS,MAAM,OAAO,CAAA;AAC1B,EAAA,QAAQ,KAAK,IAAA;AAAM,IACjB,KAAK,MAAA;AAAQ,MAAA,OAAO,IAAA,CAAK,kBAAkB,CAAA,GAAI,CAAA;AAAA,IAC/C,KAAK,YAAA;AAAc,MAAA,OAAO,CAAA;AAAA,IAC1B,KAAK,MAAA;AAAQ,MAAA,OAAO,CAAA;AAAA,IACpB,KAAK,WAAA;AAAa,MAAA,OAAO,CAAA;AAAA,IACzB,SAAS;AAGP,MAAA,OAAO,CAAA;AAAA,IACT;AAAA;AAEJ;AAEA,SAAS,aAAa,IAAA,EAA2C;AAC/D,EAAA,OAAO,QAAA,IAAY,IAAA,GAAO,IAAA,CAAK,MAAA,GAAS,MAAA;AAC1C;AA2BA,SAAS,UAAU,IAAA,EAAqC;AACtD,EAAA,IAAI,IAAA,KAAS,QAAW,OAAO,CAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,KAAS,QAAA,GAC1B,CAAC,EAAE,OAAA,EAAS,GAAA,EAAK,KAAA,EAAO,IAAA,EAAmB,CAAA,GAC3C,IAAA;AACJ,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,CAAA;AAC/B,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,MAAM,IAAA,GAAA,CAAQ,EAAE,OAAA,KAAY,GAAA,GAAM,IAAI,CAAA,KAAM,CAAA,CAAE,KAAA,KAAU,GAAA,GAAM,CAAA,GAAI,CAAA,CAAA;AAClE,IAAA,IAAI,IAAA,GAAO,KAAK,GAAA,GAAM,IAAA;AAAA,EACxB;AACA,EAAA,OAAO,GAAA;AACT;AAcO,SAAS,YACd,IAAA,EAC2C;AAC3C,EAAA,MAAM,CAAA,GAAI,UAAA,CAAW,YAAA,CAAa,IAAI,CAAC,CAAA;AACvC,EAAA,MAAMA,KAAAA,GAAQ,MAAA,IAAU,IAAA,GAAO,IAAA,CAAK,IAAA,GAAO,MAAA;AAC3C,EAAA,MAAM,CAAA,GAAI,UAAUA,KAAI,CAAA;AACxB,EAAA,MAAM,IAAI,SAAA,CAAW,OAAA,IAAW,IAAA,GAAO,IAAA,CAAK,QAAQ,MAAmC,CAAA;AAIvF,EAAA,MAAM,KAAA,GAAA,CACH,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,KAAK,IAAA,KAAS,OAAA,KACvC,IAAA,CAAK,KAAA,KAAU,MAAA,IAAa,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,IAC5C,CAAA,GAAI,CAAA;AACV,EAAA,OAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAK,CAAA;AACxB;;;AChHO,IAAM,iBAAA,GAAoB;AAI1B,SAAS,iBAAA,CACd,IAAA,EACA,EAAA,EACA,SAAA,GAAoB,iBAAA,EACX;AACT,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,OAAA,GAAU,IAAA,CAAK,SAAS,EAAA,CAAG,OAAA,GAAU,IAAA,CAAK,OAAO,CAAA,IAAK,SAAA;AAC7E;;;ACfO,IAAM,gBAAA,GAAmB;AAAA,EAC9B,QAAA;AAAA,EAAU,OAAA;AAAA,EAAS,QAAA;AAAA,EAAU,UAAA;AAAA,EAAY,SAAA;AAAA,EAAW,sBAAA;AAAA,EAAwB,0BAAA;AAAA,EAC5E,iBAAA;AAAA,EAAmB,mBAAA;AAAA,EAAqB,iBAAA;AAAA,EAAmB,mBAAA;AAAA,EAAqB;AAClF,CAAA,CAAE,KAAK,GAAG;AAQH,SAAS,iBAAA,CAAkB,QAA4B,IAAA,EAAwB;AACpF,EAAA,IAAI,EAAE,MAAA,YAAkB,OAAA,CAAA,EAAU,OAAO,KAAA;AACzC,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,gBAAgB,CAAA;AAC/C,EAAA,OAAO,YAAY,IAAA,IAAQ,OAAA,KAAY,IAAA,IAAQ,IAAA,CAAK,SAAS,OAAO,CAAA;AACtE","file":"index.js","sourcesContent":["/**\n * Declarative gesture taxonomy. Single source of truth for:\n * - which gestures hit-test (have a `.target` slot in the route string)\n * - which gestures carry an argument and what values are legal\n * - the default arg value (used when none is specified in a route)\n *\n * Reflection, matcher, and inspector UI all read this table. Adding a new\n * gesture name in one place updates every consumer.\n */\n\nexport type GestureName =\n | 'click'\n | 'pointerDown'\n | 'dblTap'\n | 'drag'\n | 'wheel'\n | 'pinch'\n | 'keyDown'\n | 'keyUp'\n | 'keyHeld'\n | 'contextMenu'\n | 'longPress'\n | 'multiTouch'\n | 'multiTouchTap'\n | 'drop'\n | 'paste';\n\n/**\n * Gesture kinds an affordance claim can bar, in the spec vocabulary bindings\n * are written in. `'pointer'` is one token because `pointerDown` / `click` /\n * `drag` are a single press protocol — at the event level the first two are\n * the same `kind: 'pointerdown'`, told apart only by `stage`.\n */\nexport type ClaimableGesture =\n | 'pointer'\n | 'doubleClick'\n | 'contextMenu'\n | 'longPress'\n | 'wheel'\n | 'pinch';\n\n/** Declares the argument a gesture carries: what it is called, which values\n * are legal, and what an omitted arg slot means. */\nexport interface GestureArgSpec {\n /** Display name for the arg in inspector chips (`direction`, `key`, `fingers`). */\n name: string;\n /** Acceptable values. `'free'` means any string (e.g. key names). */\n values: readonly string[] | 'free';\n /** Value an omitted arg slot takes. Must be in `values` unless\n * `values === 'free'`. Omit it to make an omitted slot mean the `'*'`\n * wildcard — match every value. */\n default?: string;\n}\n\n/** What the grammar knows about one gesture — the form of input itself, not\n * any action bound to it. */\nexport interface GestureDescriptor {\n name: GestureName;\n /** Does the route's `.target` slot apply? Targetless gestures (`wheel`,\n * `keyDown/Up`, `multiTouch`, `multiTouchTap`) elide it entirely in the v2 grammar. */\n hasTarget: boolean;\n /** Optional argument spec. Encoded as `gesture(value)` in the route string. */\n arg?: GestureArgSpec;\n}\n\n/** The gesture taxonomy: one descriptor per gesture the grammar recognizes.\n * Adding a gesture here is what makes it parseable, matchable and\n * inspectable. */\nexport const GESTURE_DESCRIPTORS: readonly GestureDescriptor[] = [\n { name: 'click', hasTarget: true },\n { name: 'pointerDown', hasTarget: true },\n { name: 'dblTap', hasTarget: true },\n { name: 'drag', hasTarget: true },\n { name: 'wheel', hasTarget: true, arg: { name: 'direction', values: ['up', 'down', '*'], default: '*' } },\n { name: 'pinch', hasTarget: true, arg: { name: 'direction', values: ['in', 'out', '*'], default: '*' } },\n { name: 'keyDown', hasTarget: false, arg: { name: 'key', values: 'free' } },\n { name: 'keyUp', hasTarget: false, arg: { name: 'key', values: 'free' } },\n { name: 'keyHeld', hasTarget: false, arg: { name: 'key', values: 'free' } },\n { name: 'contextMenu', hasTarget: true },\n { name: 'longPress', hasTarget: true },\n { name: 'multiTouch', hasTarget: false, arg: { name: 'fingers', values: ['2', '3', '4'] } },\n { name: 'multiTouchTap', hasTarget: false, arg: { name: 'fingers', values: ['2', '3', '4'] } },\n // The arg is the MIME-glob filter. No default: a spec with no `types`\n // matches any payload, which is what an omitted arg slot means for a\n // `'free'` arg.\n { name: 'drop', hasTarget: false, arg: { name: 'types', values: 'free' } },\n { name: 'paste', hasTarget: false, arg: { name: 'types', values: 'free' } },\n];\n\nconst BY_NAME = new Map<string, GestureDescriptor>(\n GESTURE_DESCRIPTORS.map((d) => [d.name, d]),\n);\n\n/** Look up a gesture's descriptor. Throws on an unknown name — callers\n * holding an unvalidated string should gate on `isKnownGestureName` first. */\nexport function getGestureDescriptor(name: GestureName): GestureDescriptor {\n const d = BY_NAME.get(name);\n if (!d) throw new Error(`unknown gesture: ${name}`);\n return d;\n}\n\n/** Whether a string names a gesture the grammar recognizes. */\nexport function isKnownGestureName(name: string): name is GestureName {\n return BY_NAME.has(name);\n}\n","/** All valid keys for a modifier sub-table in a route entry. Canonical\n * order: mod → shift → alt (matches formatShortcut). */\nexport type ModifierCombo =\n | 'default'\n | 'mod' | 'shift' | 'alt'\n | 'mod+shift' | 'mod+alt' | 'shift+alt'\n | 'mod+shift+alt';\n\n/** Convenience: produce the canonical ModifierCombo from modifiers passed\n * in any order. Useful in computed property syntax:\n *\n * ```ts\n * 'rect': {\n * [mods('shift')]: addToSelection,\n * [mods('alt', 'shift')]: cloneAndAdd, // → 'shift+alt'\n * }\n * ```\n */\nexport function mods(\n ...keys: ReadonlyArray<'mod' | 'shift' | 'alt'>\n): ModifierCombo {\n if (keys.length === 0) return 'default';\n const set = new Set(keys);\n return [\n set.has('mod') && 'mod',\n set.has('shift') && 'shift',\n set.has('alt') && 'alt',\n ].filter(Boolean).join('+') as ModifierCombo;\n}\n","/**\n * Route-string grammar v3:\n *\n * route = phaseSlot WS gesture WS argSlot? WS targetSlot? WS modSlot?\n * phaseSlot = '[' phaseList ']'\n * phaseList = phaseAtom (WS ',' WS phaseAtom)*\n * phaseAtom = (channel ':')? phaseValue -- bare phaseValue ≡ '&:phaseValue'\n * channel = '&' | '*' | toolId -- '&' = the binding's own tool\n * phaseValue = 'initial' | 'engaged' | '*'\n * argSlot = '(' argValue ')' -- whitespace inside parens is significant\n * targetSlot = '=>' WS targetValue -- omitted slot defaults to '*' for hasTarget\n * modSlot = modAtom (WS modAtom)*\n * modAtom = sigil modName\n * sigil = '+' | '?' -- ! @ # $ % ^ & * reserved as id-prefix\n * modName = 'mod' | 'shift' | 'alt' | 'ctrl' | 'meta'\n *\n * Shorthand: a bare phaseValue (no `:`) implies channel `&` (\"this tool's\n * own phase\"). `[engaged]` ≡ `[&:engaged]`; `[*]` ≡ `[&:*]`. The truly-loose\n * form (any channel, any phase) is `[*:*]`.\n *\n * Examples:\n * [initial] click => empty +shift -- self idle\n * [engaged] wheel -- self mid-gesture\n * [rect:engaged] wheel -- when rect tool is mid-gesture\n * [*:engaged] keyDown(Delete) -- when any tool is mid-gesture\n * [initial,engaged] contextMenu => empty -- either self phase\n * [*] click => empty -- self, any phase\n */\nimport { getGestureDescriptor, isKnownGestureName, type GestureName } from './gestures';\nimport type { RoutePhase } from '../ui/phase';\n\n// ─── Channel + phase atoms ────────────────────────────────────────────────\n\n/** Channel reference for a phase atom. `'&'` = the binding's own tool;\n * `'*'` = any tool; otherwise a registered tool id. */\nexport type ChannelRef = '&' | '*' | string;\n\n/** One element of a phase list: a (channel, phase) pair. The default\n * channel (omitted in the shorthand) is `'&'`. `phase: '*'` means\n * \"any phase of the given channel\". */\nexport interface PhaseAtom {\n channel: ChannelRef;\n phase: RoutePhase | '*';\n}\n\n/** Reserved id-prefix sigils. Tool ids, action ids, channel names, target\n * kinds, and arg values may not start with any of these — keeps the\n * parser unambiguous and reserves single-char prefixes for future grammar\n * extensions. */\nexport const RESERVED_ID_PREFIXES: ReadonlySet<string> = new Set([\n '!', '@', '#', '$', '%', '^', '&', '*',\n]);\n\n/** Reserved bareword channel/id names. These are keywords in the phase\n * slot — a tool may not register with one of these as its id (collides\n * with the bare-phase shorthand). */\nexport const RESERVED_ID_NAMES: ReadonlySet<string> = new Set([\n 'initial', 'engaged',\n]);\n\n// ─── v3 grammar types ──────────────────────────────────────────────────────\n\n/** v3 modifier requirement on a single modifier key. Absent from a\n * `ParsedModifiers` map means \"must not be held\" (the strict default). */\nexport type ModRequirement = 'required' | 'optional';\n\n/** Canonical modifier names accepted in the modSlot, in canonical order.\n * Single source of truth: the {@link ModifierKey} type and the runtime\n * validator (`MOD_NAME_SET`) are both derived from this tuple. */\nexport const VALID_MOD_NAMES = ['mod', 'shift', 'alt', 'ctrl', 'meta'] as const;\n\n/** A single modifier name accepted in the modSlot. */\nexport type ModifierKey = (typeof VALID_MOD_NAMES)[number];\n\n/** Parsed-form modifiers — structured map; absent keys are implicitly\n * forbidden. Empty object = \"no modifiers held\". */\nexport type ParsedModifiers = Partial<Record<ModifierKey, ModRequirement>>;\n\n/** Reserved sigil characters. The parser rejects any of these with a\n * \"reserved for future use\" error so introducing them later is\n * non-breaking. `*` is NOT in this set — it's the universal wildcard. */\nexport const RESERVED_SIGILS: ReadonlySet<string> = new Set(['!', '@', '#', '$', '%', '^', '&']);\n\n/** Active (parseable) sigils today: `+` required, `?` optional. */\nexport const ACTIVE_SIGILS: ReadonlySet<string> = new Set(['+', '?']);\n\n/** Runtime membership test for {@link ModifierKey}, for validating a modifier\n * name that arrives as a plain string. */\nconst MOD_NAME_SET: ReadonlySet<string> = new Set(VALID_MOD_NAMES);\nexport { MOD_NAME_SET };\n\n/** v3 parsed-route shape. */\nexport interface ParsedRoute {\n /** One or more phase atoms (channel + phase). Empty array is invalid.\n * Bare-phase shorthand in the source string desugars to channel `'&'`,\n * so `[engaged]` parses to `[{ channel: '&', phase: 'engaged' }]`. */\n phases: readonly PhaseAtom[];\n gesture: GestureName;\n /** Resolved arg. For arg-bearing gestures, the descriptor's default\n * fills in when the slot is omitted (e.g. `wheel` → `arg: '*'`).\n * Undefined for gestures whose descriptor has no `arg`. */\n arg: string | undefined;\n /** For hasTarget gestures: target string with `'*'` as the wildcard\n * sentinel. Defaults to `'*'` when the slot is omitted. Undefined for\n * hasTarget=false gestures. */\n target: string | undefined;\n /** Structured modifier requirements; empty map = \"no modifiers held\". */\n modifiers: ParsedModifiers;\n}\n\n/** Parse a route string into its slots, filling in the shorthand defaults the\n * grammar defines (bare phases mean channel `&`; an omitted arg or target\n * slot takes the gesture descriptor's default). Throws with the offending\n * input on anything the grammar does not accept, including sigils reserved\n * for later versions. */\nexport function parseRoute(input: string): ParsedRoute {\n // 1) Extract bracketed phaseSlot from the head.\n const trimmed = input.trim();\n if (!trimmed.startsWith('[')) {\n throw new Error(`invalid route (phase brackets required): ${input}`);\n }\n const closeIdx = trimmed.indexOf(']');\n if (closeIdx < 0) throw new Error(`invalid route (unclosed phase bracket): ${input}`);\n const phaseListRaw = trimmed.slice(1, closeIdx).trim();\n const phases = parsePhaseList(phaseListRaw, input);\n let rest = trimmed.slice(closeIdx + 1).trim();\n\n // 2) Pull off the gesture name (alphanumeric).\n const gestureMatch = /^([A-Za-z]+)/.exec(rest);\n if (!gestureMatch) throw new Error(`invalid route (no gesture name): ${input}`);\n const gestureName = gestureMatch[1]!;\n if (!isKnownGestureName(gestureName)) {\n throw new Error(`invalid route (unknown gesture \"${gestureName}\"): ${input}`);\n }\n rest = rest.slice(gestureMatch[0].length).trimStart();\n const desc = getGestureDescriptor(gestureName);\n\n // 3) Optional argSlot: `(...)`. Whitespace inside parens is significant.\n let arg: string | undefined;\n if (rest.startsWith('(')) {\n const closeArg = rest.indexOf(')');\n if (closeArg < 0) throw new Error(`invalid route (unbalanced arg parens): ${input}`);\n const argRaw = rest.slice(1, closeArg); // no trim — whitespace significant\n if (!desc.arg) throw new Error(`invalid route (${gestureName} has no arg): ${input}`);\n if (argRaw !== '*' && desc.arg.values !== 'free' && !desc.arg.values.includes(argRaw)) {\n throw new Error(`invalid route (\"${argRaw}\" not in ${desc.arg.values.join('|')}): ${input}`);\n }\n arg = argRaw;\n rest = rest.slice(closeArg + 1).trimStart();\n } else if (desc.arg) {\n arg = desc.arg.default ?? '*';\n }\n\n // 4) Optional targetSlot: `=> <target>`. Elided \"=> *\" defaults to '*' for hasTarget gestures.\n let target: string | undefined;\n if (rest.startsWith('=>')) {\n if (!desc.hasTarget) throw new Error(`invalid route (${gestureName} has no target): ${input}`);\n rest = rest.slice(2).trimStart();\n const tgtMatch = /^([^\\s+?!@#$%^&]+)/.exec(rest);\n if (!tgtMatch) throw new Error(`invalid route (missing target after \"=>\"): ${input}`);\n target = tgtMatch[1]!;\n rest = rest.slice(tgtMatch[0].length).trimStart();\n } else if (desc.hasTarget) {\n target = '*';\n }\n\n // 5) modSlot — zero or more sigil-prefixed atoms.\n const modifiers: ParsedModifiers = {};\n while (rest.length > 0) {\n const ch = rest[0]!;\n if (RESERVED_SIGILS.has(ch)) {\n throw new Error(`invalid route (\"${ch}\" is reserved for future use): ${input}`);\n }\n if (!ACTIVE_SIGILS.has(ch)) {\n throw new Error(`invalid route (unexpected \"${ch}\" at \"${rest}\"): ${input}`);\n }\n const sigil = ch;\n rest = rest.slice(1);\n const nameMatch = /^([a-z]+)/.exec(rest);\n if (!nameMatch) throw new Error(`invalid route (sigil \"${sigil}\" without modifier name): ${input}`);\n const name = nameMatch[1]!;\n if (!MOD_NAME_SET.has(name)) {\n throw new Error(`invalid route (unknown modifier \"${name}\"): ${input}`);\n }\n if (modifiers[name as ModifierKey] !== undefined) {\n throw new Error(`invalid route (duplicate modifier \"${name}\"): ${input}`);\n }\n modifiers[name as ModifierKey] = sigil === '+' ? 'required' : 'optional';\n rest = rest.slice(nameMatch[0].length).trimStart();\n }\n\n return { phases, gesture: gestureName, arg, target, modifiers };\n}\n\nfunction parsePhaseList(raw: string, input: string): readonly PhaseAtom[] {\n if (raw === '') throw new Error(`invalid route (empty phase list): ${input}`);\n const tokens = raw.split(',').map((p) => p.trim()).filter((p) => p.length > 0);\n if (tokens.length === 0) throw new Error(`invalid route (empty phase list): ${input}`);\n return tokens.map((t) => parsePhaseAtom(t, input));\n}\n\nconst VALID_PHASES: ReadonlySet<string> = new Set(['initial', 'engaged', '*']);\n\nfunction parsePhaseAtom(raw: string, input: string): PhaseAtom {\n // Split on the channel/phase separator. `parts.length === 1` is the\n // bare-phase shorthand (channel defaults to '&').\n const parts = raw.split(':');\n if (parts.length > 2) {\n throw new Error(`invalid route (phase atom \"${raw}\" has multiple \":\"): ${input}`);\n }\n if (parts.length === 1) {\n const phase = parts[0]!;\n if (!VALID_PHASES.has(phase)) {\n throw new Error(`invalid route (unknown phase \"${phase}\" in \"${raw}\"): ${input}`);\n }\n return { channel: '&', phase: phase as PhaseAtom['phase'] };\n }\n // parts.length === 2 — explicit channel:phase form.\n const channel = parts[0]!;\n const phase = parts[1]!;\n if (channel === '') {\n throw new Error(`invalid route (empty channel before \":\" in \"${raw}\"): ${input}`);\n }\n if (!VALID_PHASES.has(phase)) {\n throw new Error(`invalid route (unknown phase \"${phase}\" in \"${raw}\"): ${input}`);\n }\n if (channel !== '&' && channel !== '*') {\n // Named tool channel. Reject the reserved-id-name keywords (they'd\n // shadow the bare-phase shorthand on parse) and the sigil prefixes\n // (reserved as future grammar surface).\n if (RESERVED_ID_NAMES.has(channel)) {\n throw new Error(`invalid route (channel \"${channel}\" is a reserved phase keyword): ${input}`);\n }\n if (RESERVED_ID_PREFIXES.has(channel[0]!)) {\n throw new Error(`invalid route (channel \"${channel}\" starts with reserved sigil \"${channel[0]}\"): ${input}`);\n }\n }\n return { channel, phase: phase as PhaseAtom['phase'] };\n}\n\n/** Render a single phase atom in canonical shorthand form. `&` channel\n * is elided (\"`engaged`\", \"`*`\"); other channels use the explicit\n * `channel:phase` form (\"`rect:engaged`\", \"`*:*`\"). */\nexport function formatPhaseAtom(a: PhaseAtom): string {\n if (a.channel === '&') return a.phase;\n return `${a.channel}:${a.phase}`;\n}\n\n/** Visual-collapse pass: given a list of route strings, fold pairs that\n * differ ONLY in `shift` presence (one has `+shift`, the other doesn't,\n * everything else identical) into a single route with `?shift`. Useful\n * for inspector / palette displays that want to show \"Cmd+[\" and\n * \"Cmd+Shift+[\" as one Cmd+?Shift+[ chip rather than two rows.\n *\n * Preserves input order — the first member of each fold-pair holds the\n * position; the second is dropped. Routes that don't have a `+shift`\n * vs absent twin pass through unchanged. Does NOT fold other modifier\n * pairs (alt/ctrl/meta/mod) — those tend to carry meaning across the\n * same key (e.g., Cmd+Z vs Cmd+Shift+Z are usually two distinct\n * actions, but Cmd+] vs Cmd+Shift+] is more often parametric variation\n * of one action). Open the helper if a use case for the other\n * modifiers shows up.\n */\nexport function collapseShiftPairs(routes: readonly string[]): string[] {\n if (routes.length < 2) return [...routes];\n const parsed = routes.map((r) => ({ raw: r, p: parseRoute(r) }));\n const consumed = new Set<number>();\n const out: string[] = [];\n for (let i = 0; i < parsed.length; i++) {\n if (consumed.has(i)) continue;\n const a = parsed[i]!;\n // Look ahead for a twin: same gesture/arg/target/phases/mods-except-shift.\n let twinIndex = -1;\n for (let j = i + 1; j < parsed.length; j++) {\n if (consumed.has(j)) continue;\n const b = parsed[j]!;\n if (isShiftTwin(a.p, b.p)) { twinIndex = j; break; }\n }\n if (twinIndex < 0) { out.push(a.raw); continue; }\n consumed.add(twinIndex);\n // Emit the union with shift marked optional.\n const folded: ParsedRoute = {\n ...a.p,\n modifiers: { ...withoutShift(a.p.modifiers), shift: 'optional' },\n };\n out.push(formatRoute(folded));\n }\n return out;\n}\n\nfunction isShiftTwin(a: ParsedRoute, b: ParsedRoute): boolean {\n if (a.gesture !== b.gesture) return false;\n if (a.arg !== b.arg) return false;\n if (a.target !== b.target) return false;\n if (!samePhases(a.phases, b.phases)) return false;\n // Exactly one must have shift required; the other must lack shift.\n const aShift = a.modifiers.shift;\n const bShift = b.modifiers.shift;\n const aHas = aShift === 'required';\n const bHas = bShift === 'required';\n if (!(aHas !== bHas)) return false; // one and only one has shift\n if (aShift === 'optional' || bShift === 'optional') return false; // already optional\n // Every other modifier must match exactly.\n for (const name of VALID_MOD_NAMES) {\n if (name === 'shift') continue;\n if (a.modifiers[name] !== b.modifiers[name]) return false;\n }\n return true;\n}\n\nfunction samePhases(\n a: readonly PhaseAtom[],\n b: readonly PhaseAtom[],\n): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i]!.channel !== b[i]!.channel || a[i]!.phase !== b[i]!.phase) return false;\n }\n return true;\n}\n\nfunction withoutShift(m: ParsedModifiers): ParsedModifiers {\n const { shift: _shift, ...rest } = m;\n void _shift;\n return rest;\n}\n\nconst MOD_ORDER: readonly ModifierKey[] = ['mod', 'shift', 'alt', 'ctrl', 'meta'];\n\n/** Render a parsed route back to a canonical route string: shorthand where\n * the grammar has it, defaulted slots elided, modifiers in canonical order.\n * `parseRoute(formatRoute(r))` yields `r` again. */\nexport function formatRoute(r: ParsedRoute): string {\n const desc = getGestureDescriptor(r.gesture);\n\n // Phase slot — comma-separated atoms in source order; canonical\n // shorthand per atom (`&:engaged` → `engaged`, etc.).\n const phaseStr = `[${r.phases.map(formatPhaseAtom).join(',')}]`;\n\n let out = `${phaseStr} ${r.gesture}`;\n\n // Arg slot — elide the value an omitted slot would parse back to. A\n // descriptor with no declared default takes '*', same as the target slot.\n if (desc.arg && r.arg !== undefined && r.arg !== (desc.arg.default ?? '*')) {\n out += `(${r.arg})`;\n }\n\n // Target slot — elide \"*\" (wildcard default for hasTarget gestures).\n if (desc.hasTarget && r.target !== undefined && r.target !== '*') {\n out += ` => ${r.target}`;\n }\n\n // Mod atoms in canonical order, space-separated.\n for (const name of MOD_ORDER) {\n const req = r.modifiers[name];\n if (req === 'required') out += ` +${name}`;\n else if (req === 'optional') out += ` ?${name}`;\n }\n\n return out;\n}\n","/**\n * Mini-grammar for the `arg` slot of `keyDown` / `keyUp` routes.\n *\n * keyRoute = key ('?' optionalMod)*\n * optionalMod = 'mod' | 'shift' | 'alt' | 'ctrl' | 'meta'\n *\n * `?shift` means \"shift may or may not be held; either fires this route.\"\n * Required modifiers still belong in the route's `:modifiers` slot — this\n * grammar only widens which events match, never narrows.\n */\nimport type { KeySpec, ModSpec } from '../ui/spec';\nimport { VALID_MOD_NAMES, type ModifierKey } from './routeGrammar';\n\n/** An optional modifier in a key route — the same set as the canonical\n * {@link ModifierKey}. */\nexport type OptionalMod = ModifierKey;\nconst OPTIONAL_SET = new Set<string>(VALID_MOD_NAMES);\n\n/** A key route split into the key itself and the modifiers whose state does\n * not affect the match. */\nexport interface ParsedKeyRoute {\n key: string;\n optionalMods: readonly OptionalMod[];\n}\n\n/** Parse the `arg` slot of a `keyDown` / `keyUp` route. Throws on an empty\n * key, an unrecognized optional modifier, or a repeated one. */\nexport function parseKeyRoute(input: string): ParsedKeyRoute {\n const [key, ...mods] = input.split('?');\n if (!key) throw new Error(`invalid key route (empty key): ${input}`);\n const seen = new Set<string>();\n for (const m of mods) {\n if (!OPTIONAL_SET.has(m)) throw new Error(`unknown optional modifier \"${m}\" in ${input}`);\n if (seen.has(m)) throw new Error(`duplicate optional modifier \"${m}\" in ${input}`);\n seen.add(m);\n }\n return { key, optionalMods: mods as OptionalMod[] };\n}\n\n/** Render a parsed key route back to its canonical source form. Round-trips\n * with `parseKeyRoute`. */\nexport function formatKeyRoute(r: ParsedKeyRoute): string {\n return r.optionalMods.length === 0 ? r.key : `${r.key}?${r.optionalMods.join('?')}`;\n}\n\n/** Build a runtime KeySpec from a parsed key route. Each optional modifier\n * becomes `mods.<name>: 'optional'`. The matcher's `matchModifiers`\n * honors `'optional'` uniformly across `mod`, `shift`, `alt`, `ctrl`,\n * and `meta`. */\nexport function keyRouteToSpec(r: ParsedKeyRoute): KeySpec {\n const mods: ModSpec = {};\n for (const m of r.optionalMods) mods[m] = 'optional';\n const spec: KeySpec = { kind: 'key', key: r.key };\n if (Object.keys(mods).length > 0) spec.mods = mods;\n return spec;\n}\n","/**\n * Pure gesture matcher — no React, no state, no DOM.\n *\n * The kit's dispatcher orchestrator wraps these primitives with its\n * actions-layer concerns (BindingScope, ScopedBinding, MatchResult, matchBest).\n *\n * ## key-held phase decision\n * `matchSpec` returns `true` only for `phase: 'down'`, not `phase: 'up'`.\n * The dispatcher tracks the held key independently and handles the `up` phase\n * itself; the matcher never sees an \"un-match\" it needs to distinguish.\n * This keeps the matcher's output a simple boolean and avoids a three-valued\n * return type.\n *\n * ## TargetSpec string forms\n * Every form `TargetSpec` declares is resolved here, each from a different\n * field the dispatcher packs onto the event:\n *\n * | Form | Read from | Supplied by |\n * | --- | --- | --- |\n * | `'empty'` / `'selected-body'` / `'unselected-body'` | `bodyTarget` | the `classifyTarget` thunk |\n * | `kind:<k>` / `kind:<k>:selected` | `bodyKind` + `bodyTarget` | the `classifyTarget` thunk's node-kind resolver |\n * | `affordance:<k>` | the raw target's `.kind` | the `affordanceAt` thunk |\n * | `{ kindOf }` | the raw target + `bodyTarget` | both |\n *\n * A form whose source field is absent does not match — an unwired\n * `classifyTarget` makes every `bodyTarget`/`bodyKind` form `false` rather\n * than a silent wildcard. That is deliberate: a binding that can't be\n * evaluated should stay out of the way of one that can.\n */\n\nimport type { GestureSpec, ModSpec, PhaseSpec, TargetSpec, TargetPredicate } from './spec';\nimport type { InputEvent } from './inputEvent';\nimport type { PhaseAtom } from '../grammar/routeGrammar';\n\n// ---------------------------------------------------------------------------\n// matchModifiers\n// ---------------------------------------------------------------------------\n\n/** The modifier-state fields `matchModifiers` reads. Structural, so a DOM\n * `KeyboardEvent` or `PointerEvent` satisfies it directly. */\nexport type ModifiersEvent = { altKey: boolean; ctrlKey: boolean; metaKey: boolean; shiftKey: boolean };\n\n/** Per-physical-key requirement resolved from a `ModSpec`:\n * - `'required'` — the key MUST be held\n * - `'forbidden'` — the key MUST NOT be held\n * - `'optional'` — either is accepted\n */\ntype KeyRequirement = 'required' | 'forbidden' | 'optional';\n\nfunction resolveSpecValue(value: boolean | 'optional' | undefined): KeyRequirement {\n if (value === true) return 'required';\n if (value === 'optional') return 'optional';\n return 'forbidden';\n}\n\n/**\n * Strict modifier match.\n *\n * - Omitted modifier MUST NOT be held.\n * - `true` MUST be held.\n * - `false` MUST NOT be held (same as omitted; both forms accepted for clarity).\n * - `'optional'` accepts either held or unheld. Supported on every modifier\n * (`alt`, `ctrl`, `meta`, `mod`, `shift`).\n * - `mod` is platform-aware: matches `metaKey` on mac, `ctrlKey` elsewhere.\n * When `mod` is set, the corresponding `meta`/`ctrl` field is implied AND\n * the *other* platform key is forbidden. Callers should not combine `mod`\n * with `meta`/`ctrl`.\n */\nexport function matchModifiers(\n e: ModifiersEvent,\n mods: ModSpec | undefined,\n isMac: boolean,\n): boolean {\n // Start strict: every modifier is forbidden unless the spec opts in.\n let alt: KeyRequirement = 'forbidden';\n let ctrl: KeyRequirement = 'forbidden';\n let meta: KeyRequirement = 'forbidden';\n let shift: KeyRequirement = 'forbidden';\n\n if (mods) {\n alt = resolveSpecValue(mods.alt);\n shift = resolveSpecValue(mods.shift);\n\n // mod: platform-aware shorthand. Resolves to meta on mac, ctrl elsewhere.\n // The *other* platform key stays forbidden (handled by the strict default).\n if (mods.mod !== undefined) {\n const modReq = resolveSpecValue(mods.mod);\n if (isMac) meta = modReq;\n else ctrl = modReq;\n } else {\n meta = resolveSpecValue(mods.meta);\n ctrl = resolveSpecValue(mods.ctrl);\n }\n }\n\n return (\n checkKey(alt, e.altKey) &&\n checkKey(ctrl, e.ctrlKey) &&\n checkKey(meta, e.metaKey) &&\n checkKey(shift, e.shiftKey)\n );\n}\n\nfunction checkKey(req: KeyRequirement, held: boolean): boolean {\n if (req === 'required') return held;\n if (req === 'forbidden') return !held;\n return true;\n}\n\n// ---------------------------------------------------------------------------\n// matchKey\n// ---------------------------------------------------------------------------\n\n/** Case-insensitive key match; supports string or string[] (any-of). */\nexport function matchKey(eventKey: string, specKey: string | string[]): boolean {\n const lower = eventKey.toLowerCase();\n if (Array.isArray(specKey)) {\n return specKey.some((k) => k.toLowerCase() === lower);\n }\n return specKey.toLowerCase() === lower;\n}\n\n/** A key event against a key spec: by `code` first when the spec names one,\n * then by `key`. Either is enough. */\nfunction matchKeyOrCode(\n e: { key: string; code?: string },\n spec: { key: string | string[]; code?: string | string[] },\n): boolean {\n if (spec.code !== undefined && e.code !== undefined && [spec.code].flat().includes(e.code)) return true;\n return matchKey(e.key, spec.key);\n}\n\n// ---------------------------------------------------------------------------\n// matchTarget\n// ---------------------------------------------------------------------------\n\n/** Read a `.kind` string off an affordance hit, or `undefined` when the hit\n * is absent or shaped differently. */\nfunction affordanceKindOf(target: unknown): string | undefined {\n if (typeof target !== 'object' || target === null) return undefined;\n const k = (target as { kind?: unknown }).kind;\n return typeof k === 'string' ? k : undefined;\n}\n\n/**\n * A {@link TargetSpec} resolved to its form, with the parts each form encodes\n * in its string pulled out.\n *\n * This is the one enumeration of the target forms. Three sites act on it and\n * each does something different — `matchTarget` below, and `targetRank` /\n * `targetConsultsAffordance` in `@weasel-js/core`'s dispatcher matcher — so\n * they switch on `form` exhaustively rather than re-deriving the prefixes.\n */\nexport type TargetSpecForm =\n | { form: 'body'; body: 'empty' | 'selected-body' | 'unselected-body' }\n | { form: 'kind'; kind: string; requireSelected: boolean }\n | { form: 'affordance'; kind: string }\n | { form: 'predicate'; kindOf: TargetPredicate };\n\nfunction hasPrefix<P extends string>(s: string, prefix: P): s is `${P}${string}` {\n return s.startsWith(prefix);\n}\n\n/**\n * Resolve a `TargetSpec` to its {@link TargetSpecForm}.\n *\n * `null` means the value is no form this build knows — junk from an untyped\n * consumer, or a spec authored against a newer kit. Every caller treats it as\n * no-match rather than a wildcard.\n */\nexport function parseTargetSpec(spec: TargetSpec): TargetSpecForm | null {\n if (typeof spec === 'object') {\n return spec !== null && typeof spec.kindOf === 'function'\n ? { form: 'predicate', kindOf: spec.kindOf }\n : null;\n }\n if (typeof spec !== 'string') return null;\n if (spec === 'empty' || spec === 'selected-body' || spec === 'unselected-body') {\n return { form: 'body', body: spec };\n }\n if (hasPrefix(spec, 'affordance:')) {\n return { form: 'affordance', kind: spec.slice('affordance:'.length) };\n }\n // `:selected` is only a suffix when it is the LAST segment — `kind:app:note`\n // names a kind that happens to contain a colon.\n if (hasPrefix(spec, 'kind:')) {\n const rest = spec.slice('kind:'.length);\n const requireSelected = rest.endsWith(':selected');\n return {\n form: 'kind',\n kind: requireSelected ? rest.slice(0, -':selected'.length) : rest,\n requireSelected,\n };\n }\n const _exhaustive: never = spec;\n void _exhaustive;\n return null;\n}\n\n/**\n * Match a target value + event against a TargetSpec.\n *\n * - `{ kindOf: predicate }` — calls the predicate with the raw target value\n * (affordance hit on pointerdown; event.target otherwise) AND the\n * `bodyTarget` string. Predicates that only need the target can ignore\n * the second arg.\n * - `'empty'`, `'selected-body'`, `'unselected-body'` — compared against\n * `bodyTarget` on the event (populated by `useGestureDispatcher` when a\n * `classifyTarget` thunk is supplied).\n * - `kind:<k>` — compared against `bodyKind`, the *semantic* kind of the node\n * body under the point (`'text'`, `'rect'`, an app's own `'app:note'`), as\n * resolved by `classifyTarget`. Selection-agnostic.\n * - `kind:<k>:selected` — the same, and additionally requires the body to be\n * in the current selection. Only the final `:selected` is a suffix, so a\n * kind may itself contain colons.\n * - `affordance:<k>` — exact match against the affordance hit's own `kind`.\n * Kit affordance kinds are `handle:<corner>`, `'rotate-handle'`,\n * `anchor:<i>`, `controlIn:<i>` / `controlOut:<i>`, and `layer:<id>` for a\n * registered layer's widget. The match is exact and includes any parameter,\n * so \"any anchor\" needs the `isAnchor` predicate rather than this form.\n * - `undefined` spec.target — any target is accepted.\n *\n * Every string form resolves to `false` when the field it reads is absent, so\n * an unwired `classifyTarget`/`affordanceAt` yields no-match rather than a\n * silent wildcard.\n */\nexport function matchTarget(\n target: unknown,\n specTarget: TargetSpec | undefined,\n bodyTarget?: string,\n bodyKind?: string,\n): boolean {\n if (specTarget === undefined) return true;\n const form = parseTargetSpec(specTarget);\n if (form === null) return false;\n\n switch (form.form) {\n // Receives the affordance hit plus the bodyTarget classification.\n case 'predicate':\n return form.kindOf(target, bodyTarget);\n\n // Resolved from the `classifyTarget` result packed into the event's\n // `bodyTarget`. Unwired classifyTarget → absent → no match.\n case 'body':\n return bodyTarget !== undefined && bodyTarget === form.body;\n\n case 'affordance':\n return affordanceKindOf(target) === form.kind;\n\n case 'kind':\n if (bodyKind === undefined || bodyKind !== form.kind) return false;\n return form.requireSelected ? bodyTarget === 'selected-body' : true;\n\n default: {\n // Exhaustiveness guard — new target forms are a compile error here.\n const _exhaustive: never = form;\n void _exhaustive;\n return false;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// matchPhase\n// ---------------------------------------------------------------------------\n\n/** Per-tool gesture-lifecycle state at match time.\n *\n * - `selfChannel` is the tool id `'&'` resolves to — i.e., the tool that\n * owns the binding being evaluated. `null` for bindings without an\n * owning tool (e.g. ambient actions registered without scope ties); in\n * that case any `phase: '&'` atom can't match.\n * - `engagedChannels` is the set of tool ids that currently have an\n * in-flight handle. Derived by the dispatcher from its `inFlight()`\n * map keyed by tool id at match time.\n */\nexport interface PhaseContext {\n selfChannel: string | null;\n engagedChannels: ReadonlySet<string>;\n}\n\n/** Normalize the `PhaseSpec` shorthand to an atom array.\n * Bare keywords desugar to a single `'&'`-channel atom. */\nfunction normalizePhase(spec: PhaseSpec): readonly PhaseAtom[] {\n if (typeof spec === 'string') {\n return [{ channel: '&', phase: spec }];\n }\n return spec;\n}\n\n/** True if the binding's `phase` spec is satisfied by the current\n * per-tool engagement state. Omitted spec → always true (no phase\n * constraint). Union semantics: a phase atom list matches when ANY\n * atom matches. */\nexport function matchPhase(spec: PhaseSpec | undefined, ctx: PhaseContext): boolean {\n if (spec === undefined) return true;\n const atoms = normalizePhase(spec);\n if (atoms.length === 0) return true;\n for (const a of atoms) {\n if (matchPhaseAtom(a, ctx)) return true;\n }\n return false;\n}\n\nfunction matchPhaseAtom(a: PhaseAtom, ctx: PhaseContext): boolean {\n if (a.channel === '*') {\n // Any-channel sentinel: 'engaged' matches when any channel is engaged;\n // 'initial' matches when none are; '*' matches both.\n if (a.phase === '*') return true;\n const anyEngaged = ctx.engagedChannels.size > 0;\n return a.phase === 'engaged' ? anyEngaged : !anyEngaged;\n }\n // Resolve '&' to the binding's owning tool. Without an owner, '&' atoms\n // can't match (correct: ambient actions don't have a \"self\").\n const id = a.channel === '&' ? ctx.selfChannel : a.channel;\n if (id == null) return false;\n if (a.phase === '*') return true;\n const isEngaged = ctx.engagedChannels.has(id);\n return a.phase === 'engaged' ? isEngaged : !isEngaged;\n}\n\n// ---------------------------------------------------------------------------\n// matchIngestTypes\n// ---------------------------------------------------------------------------\n\n/** MIME-glob match: `'image/*'` prefix-matches the major type; anything\n * else is an exact (case-insensitive) match; bare `'*'` or `'*\\/*'` matches all. */\nexport function mimeMatchesGlob(mime: string, glob: string): boolean {\n const m = mime.toLowerCase();\n const g = glob.toLowerCase();\n if (g === '*' || g === '*/*') return true;\n if (g.endsWith('/*')) return m.startsWith(g.slice(0, -1));\n return m === g;\n}\n\n/** True if ANY item's MIME matches ANY of the `types` globs.\n * `types: []` (empty) ≡ omitted = match any. */\nexport function matchIngestTypes(\n items: readonly { mime: string }[],\n types: string[] | undefined,\n): boolean {\n if (!types || types.length === 0) return true;\n return items.some((it) => types.some((g) => mimeMatchesGlob(it.mime, g)));\n}\n\n// ---------------------------------------------------------------------------\n// matchSpec\n// ---------------------------------------------------------------------------\n\n/**\n * Match a single GestureSpec against an InputEvent.\n *\n * For `key-held`, only `phase: 'down'` returns true. The dispatcher tracks the\n * held state independently and handles `phase: 'up'` itself.\n */\nexport function matchSpec(\n e: InputEvent,\n spec: GestureSpec,\n isMac: boolean,\n phaseCtx?: PhaseContext,\n): boolean {\n // Phase gate runs first — cheaper than the per-kind logic, and a failed\n // phase rules the spec out regardless of event shape. With no phase ctx\n // nothing is engaged and the spec has no owner: an any-channel `initial`\n // matches, and an own-channel (`&`) atom cannot.\n if (spec.phase !== undefined) {\n const ctx: PhaseContext = phaseCtx ?? { selfChannel: null, engagedChannels: EMPTY_ENGAGED };\n if (!matchPhase(spec.phase, ctx)) return false;\n }\n\n switch (spec.kind) {\n case 'key': {\n if (e.kind !== 'key') return false;\n if (!matchKeyOrCode(e, spec)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'key-held': {\n if (e.kind !== 'key-held') return false;\n if (e.phase !== 'down') return false; // only match the down phase\n if (!matchKeyOrCode(e, spec)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'wheel': {\n if (e.kind !== 'wheel') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n const direction = spec.direction ?? '*';\n if (direction === 'up' && !(e.deltaY < 0)) return false;\n if (direction === 'down' && !(e.deltaY > 0)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'pinch': {\n if (e.kind !== 'pinch') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n const direction = spec.direction ?? '*';\n if (direction === 'out' && !(e.scale > 1)) return false;\n if (direction === 'in' && !(e.scale < 1)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'click': {\n if (e.kind !== 'click') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n // A `kindOf` predicate gets the affordance the press landed on — the\n // same value it would get on a drag — NOT the DOM target. That\n // symmetry is what lets one predicate describe \"this piece of chrome\"\n // for both gestures, and what lets `hit == null` mean \"not chrome\".\n // String-form specs read `bodyTarget` and don't look at either.\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'doubleClick': {\n if (e.kind !== 'doubleclick') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'contextMenu': {\n if (e.kind !== 'contextmenu') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'longPress': {\n if (e.kind !== 'longpress') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n // A long-press begins as a press, so its target is what was under the\n // finger in scene terms: the affordance the press classified.\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'drag': {\n // Drag begins at pointerdown; the dispatcher promotes to drag after\n // threshold is crossed. The matcher fires on pointerdown.\n if (e.kind !== 'pointerdown') return false;\n // ...but not on the eager `stage: 'press'` dispatch, which exists for\n // `pointerDown` specs. Both dispatches come from one physical press;\n // without this gate a press would open its drag handle twice.\n if (e.stage === 'press') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n // Pass the affordance hit as the `target` for `kindOf` predicates.\n // Pass `bodyTarget` for string-form TargetSpec values.\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'pointerDown': {\n // The mirror of the gate above: only the eager dispatch, never the\n // buffered one the drag threshold releases.\n if (e.kind !== 'pointerdown' || e.stage !== 'press') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);\n }\n\n case 'multiTouch': {\n if (e.kind !== 'multitouch') return false;\n if (e.fingers !== spec.fingers) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'multiTouchTap': {\n if (e.kind !== 'multitouchtap') return false;\n if (e.fingers !== spec.fingers) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'drop': {\n if (e.kind !== 'drop') return false;\n if (!matchIngestTypes(e.items, spec.types)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n case 'paste': {\n if (e.kind !== 'paste') return false;\n if (!matchIngestTypes(e.items, spec.types)) return false;\n return matchModifiers(e, spec.mods, isMac);\n }\n\n default: {\n // Exhaustiveness guard — new spec kinds are a compile error here.\n const _exhaustive: never = spec;\n void _exhaustive;\n return false;\n }\n }\n}\n\nconst EMPTY_ENGAGED: ReadonlySet<string> = new Set();\n","import type { GestureSpec } from '../ui/spec';\nimport type { GestureName } from './gestures';\n\ntype SpecKind = GestureSpec['kind'];\n\n/** `GestureSpec.kind` → route-grammar gesture name. `keyUp` has no spec\n * kind, so the reverse direction is not total. */\nconst SPEC_KIND_TO_GESTURE: Record<SpecKind, GestureName | undefined> = {\n key: 'keyDown',\n 'key-held': 'keyHeld',\n wheel: 'wheel',\n pinch: 'pinch',\n click: 'click',\n doubleClick: 'dblTap',\n contextMenu: 'contextMenu',\n longPress: 'longPress',\n drag: 'drag',\n pointerDown: 'pointerDown',\n multiTouch: 'multiTouch',\n multiTouchTap: 'multiTouchTap',\n drop: 'drop',\n paste: 'paste',\n};\n\nconst GESTURE_TO_SPEC_KIND = new Map<GestureName, SpecKind>(\n (Object.entries(SPEC_KIND_TO_GESTURE) as [SpecKind, GestureName | undefined][])\n .filter((e): e is [SpecKind, GestureName] => e[1] !== undefined)\n .map(([kind, gesture]) => [gesture, kind]),\n);\n\n/** The route-grammar gesture a `GestureSpec.kind` routes as, or `undefined`\n * for a kind the grammar has no name for. */\nexport function routeGestureForSpecKind(kind: SpecKind): GestureName | undefined {\n return SPEC_KIND_TO_GESTURE[kind];\n}\n\n/** The `GestureSpec.kind` a route-grammar gesture is written as, or\n * `undefined` for a gesture no spec can express. */\nexport function specKindForRouteGesture(gesture: GestureName): SpecKind | undefined {\n return GESTURE_TO_SPEC_KIND.get(gesture);\n}\n","import type { GestureSpec, ModSpec, PhaseSpec, TargetSpec } from '../ui/spec';\nimport { parseTargetSpec } from '../ui/match';\nimport { formatRoute, type ParsedRoute } from './routeGrammar';\nimport { parseKeyRoute } from './keyRouteGrammar';\nimport { specKindForRouteGesture } from './specKinds';\n\n/**\n * Build the `GestureSpec` a parsed route describes, so a route string can\n * drive `matchSpec` and `specificity` directly.\n *\n * Wildcards become omitted fields: a `*` target, direction or MIME list, and a\n * `[*:*]` phase slot. `[*]` is `[&:*]`, which an ambient binding never\n * matches, so it stays a phase atom. A `keyDown` / `keyHeld` arg is read as a\n * key route, so `keyDown(z?shift)` yields `mods.shift: 'optional'`; a drop or\n * paste arg is a `|`-separated MIME list.\n *\n * Throws on a route no spec can express: `keyUp`, a key or finger-count\n * wildcard, or a target that is not a `TargetSpec` form.\n */\nexport function routeToSpec(parsed: ParsedRoute): GestureSpec {\n const fail = (why: string): never => {\n throw new Error(`routeToSpec: ${why}: ${formatRoute(parsed)}`);\n };\n const arg = parsed.arg === '*' ? undefined : parsed.arg;\n\n const mods: ModSpec = {};\n for (const [name, req] of Object.entries(parsed.modifiers)) {\n mods[name as keyof ModSpec] = req === 'required' ? true : 'optional';\n }\n\n const common: { mods?: ModSpec; phase?: PhaseSpec } = {};\n const isUnconstrained = parsed.phases.length === 1\n && parsed.phases[0]!.channel === '*' && parsed.phases[0]!.phase === '*';\n if (!isUnconstrained) common.phase = parsed.phases;\n\n const withMods = <S extends GestureSpec>(spec: S): S => {\n const extra = spec.mods;\n const merged = { ...mods, ...extra };\n const out = { ...spec, ...common };\n if (Object.keys(merged).length > 0) out.mods = merged;\n return out;\n };\n\n let target: TargetSpec | undefined;\n if (parsed.target !== undefined && parsed.target !== '*') {\n if (parseTargetSpec(parsed.target as TargetSpec) === null) {\n fail(`\"${parsed.target}\" is not a target form`);\n }\n target = parsed.target as TargetSpec;\n }\n const t = target === undefined ? {} : { target };\n\n const kind = specKindForRouteGesture(parsed.gesture);\n switch (kind) {\n case undefined:\n return fail(`${parsed.gesture} has no GestureSpec kind`);\n case 'click':\n case 'pointerDown':\n case 'doubleClick':\n case 'drag':\n case 'contextMenu':\n case 'longPress':\n return withMods({ kind, ...t });\n case 'wheel':\n return withMods({ kind, ...(arg ? { direction: arg as 'up' | 'down' } : {}), ...t });\n case 'pinch':\n return withMods({ kind, ...(arg ? { direction: arg as 'in' | 'out' } : {}), ...t });\n case 'key':\n case 'key-held': {\n if (arg === undefined) return fail('a key spec needs a concrete key');\n const { key, optionalMods } = parseKeyRoute(arg);\n const optional: ModSpec = {};\n for (const m of optionalMods) optional[m] = 'optional';\n return withMods({ kind, key, ...(optionalMods.length > 0 ? { mods: optional } : {}) });\n }\n case 'multiTouch':\n case 'multiTouchTap':\n if (arg === undefined) return fail(`a ${kind} spec needs concrete fingers`);\n return withMods({ kind, fingers: Number(arg) });\n case 'drop':\n case 'paste':\n return withMods({ kind, ...(arg ? { types: arg.split('|') } : {}) });\n }\n}\n","import { getGestureDescriptor, type GestureName } from './gestures';\nimport type { ParsedRoute, PhaseAtom, ParsedModifiers, ModifierKey } from './routeGrammar';\n\nconst MOD_NAMES: Record<ModifierKey, string> = {\n mod: 'Mod', shift: 'Shift', alt: 'Alt', ctrl: 'Ctrl', meta: 'Meta',\n};\nconst MOD_ORDER: readonly ModifierKey[] = ['mod', 'shift', 'alt', 'ctrl', 'meta'];\n\n/** Glossary for route-vocabulary terms surfaced by `describeRouteParts`.\n * Exposed so docs / inspector UIs can render the same definitions. */\nexport const ROUTE_TERMS = {\n idle: 'Not in the middle of a drag or other synchronous operation.',\n 'mid-gesture': 'In the middle of a drag or other synchronous operation.',\n} as const;\n\n/** Per-field explanations for the slots of a parsed route. Exposed so\n * inspector UIs / docs can describe what each setting in a route table\n * means without duplicating prose. */\nexport const ROUTE_FIELD_DEFINITIONS = {\n 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.',\n gesture: 'The class of input event that triggers this route — click, drag, double-tap, keyDown/keyUp, wheel, pinch, contextMenu, multiTouch, multiTouchTap, drop, or paste.',\n arg: 'Sub-class of the gesture. Direction for wheel (up / down / *) and pinch (in / out / *), key name for keyDown / keyUp, finger count for multiTouch / multiTouchTap, MIME glob for drop / paste. Other gestures have no arg slot.',\n 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.',\n modifiers: 'Modifier keys the user must hold (`+key`) or may optionally hold (`?key`) for this route to match. Unlisted modifiers must not be held.',\n} as const;\n\n/** The slots of a parsed route that `ROUTE_FIELD_DEFINITIONS` explains. */\nexport type RouteFieldName = keyof typeof ROUTE_FIELD_DEFINITIONS;\n\n/** The route-vocabulary terms `ROUTE_TERMS` defines. */\nexport type RouteTermLabel = keyof typeof ROUTE_TERMS;\n\n/** A part of a structured route description. `string` parts are plain prose;\n * `term` parts carry a glossary lookup so renderers can attach tooltips. */\nexport type RouteDescriptionPart =\n | string\n | { kind: 'term'; label: RouteTermLabel; definition: string };\n\nfunction term(label: RouteTermLabel): RouteDescriptionPart {\n return { kind: 'term', label, definition: ROUTE_TERMS[label] };\n}\n\nfunction joinAnd(parts: readonly string[]): string {\n if (parts.length === 0) return '';\n if (parts.length === 1) return parts[0];\n if (parts.length === 2) return `${parts[0]} and ${parts[1]}`;\n return `${parts.slice(0, -1).join(', ')}, and ${parts[parts.length - 1]}`;\n}\n\nfunction partitionModifiers(mods: ParsedModifiers): { required: string[]; optional: string[] } {\n const required: string[] = [];\n const optional: string[] = [];\n for (const name of MOD_ORDER) {\n const req = mods[name];\n if (req === 'required') required.push(MOD_NAMES[name]);\n else if (req === 'optional') optional.push(MOD_NAMES[name]);\n }\n return { required, optional };\n}\n\nfunction phaseAtomParts({ channel, phase }: PhaseAtom): RouteDescriptionPart[] {\n const subject = channel === '&' ? 'the tool'\n : channel === '*' ? 'any tool'\n : `the ${channel} tool`;\n if (phase === 'initial') return [`${subject} is `, term('idle')];\n if (phase === 'engaged') return [`${subject} is `, term('mid-gesture')];\n return [`${subject} is in any phase`];\n}\n\nfunction phasesParts(phases: readonly PhaseAtom[]): RouteDescriptionPart[] {\n if (phases.length === 1) return phaseAtomParts(phases[0]);\n const out: RouteDescriptionPart[] = [];\n phases.forEach((p, i) => {\n if (i > 0) out.push(' or ');\n out.push(...phaseAtomParts(p));\n });\n return out;\n}\n\nfunction targetClause(target: string | undefined, hasTarget: boolean): string {\n if (!hasTarget || target === undefined) return '';\n if (target === '*') return ' anywhere';\n if (target === 'empty') return ' on empty canvas';\n return ` on a ${target}`;\n}\n\n/** The gesture's arg, or undefined when it is the `'*'` wildcard — which\n * `parseRoute` fills in for every omitted slot, so prose must not print it. */\nfunction concreteArg(parsed: ParsedRoute): string | undefined {\n return parsed.arg === '*' ? undefined : parsed.arg;\n}\n\n/** One modifier reads as a compound verb (\"Shift-clicks\"); more read as a\n * held chord (\"holds Mod and Alt and drags\"). */\nfunction userDoes(required: readonly string[], verb: string): string {\n if (required.length === 0) return `the user ${verb}`;\n if (required.length === 1) return `the user ${required[0]}-${verb}`;\n return `the user holds ${joinAnd(required)} and ${verb}`;\n}\n\nfunction actionClause(parsed: ParsedRoute, required: readonly string[]): string {\n const desc = getGestureDescriptor(parsed.gesture as GestureName);\n const arg = concreteArg(parsed);\n const target = targetClause(parsed.target, desc.hasTarget);\n\n switch (parsed.gesture) {\n case 'keyDown':\n case 'keyUp':\n case 'keyHeld': {\n const verb = parsed.gesture === 'keyDown' ? 'presses'\n : parsed.gesture === 'keyUp' ? 'releases'\n : 'holds';\n const key = arg ?? 'any key';\n return required.length > 0\n ? `the user holds ${joinAnd(required)} and ${verb} ${key}`\n : `the user ${verb} ${key}`;\n }\n case 'wheel': {\n const direction = arg === 'up' ? ' up'\n : arg === 'down' ? ' down'\n : '';\n return userDoes(required, `scrolls${direction}${target}`);\n }\n case 'pinch': {\n const direction = arg === 'in' ? ' in'\n : arg === 'out' ? ' out'\n : '';\n return userDoes(required, `pinches${direction}${target}`);\n }\n case 'multiTouch':\n return userDoes(required, `touches with ${arg ?? 'multiple'} fingers`);\n case 'multiTouchTap':\n return userDoes(required, `taps with ${arg ?? 'multiple'} fingers`);\n case 'contextMenu':\n return userDoes(required, `opens the context menu${target}`);\n case 'longPress':\n return userDoes(required, `long-presses${target}`);\n case 'click':\n return userDoes(required, `clicks${target}`);\n case 'pointerDown':\n return userDoes(required, `presses${target}`);\n case 'dblTap':\n return userDoes(required, `double-taps${target}`);\n case 'drag':\n return userDoes(required, `drags${target}`);\n case 'drop':\n return userDoes(required, `drops ${arg ?? 'any'} content onto the canvas`);\n case 'paste':\n return userDoes(required, `pastes ${arg ?? 'any'} content`);\n }\n}\n\n/** Sentence-shaping options for `describeRoute` and `describeRouteParts` —\n * set both false to embed the description inside a larger sentence. */\nexport interface DescribeRouteOptions {\n /** Capitalize the first letter of the result. Default true. */\n capitalize?: boolean;\n /** Trailing period. Default true. */\n period?: boolean;\n}\n\n/** Structured description of when a parsed route fires. Returns an array of\n * prose strings interspersed with `term` parts (e.g. `idle`, `mid-gesture`)\n * so React-based renderers can attach hover-definition tooltips. Use\n * `describeRoute()` for a plain-string version. */\nexport function describeRouteParts(\n parsed: ParsedRoute,\n opts: DescribeRouteOptions = {},\n): readonly RouteDescriptionPart[] {\n const { capitalize = true, period = true } = opts;\n const { required, optional } = partitionModifiers(parsed.modifiers);\n const action = actionClause(parsed, required);\n const optClause = optional.length > 0\n ? ` (${joinAnd(optional)} optional)`\n : '';\n\n const parts: RouteDescriptionPart[] = [];\n const head = `fires when ${action}, while `;\n parts.push(capitalize ? head.charAt(0).toUpperCase() + head.slice(1) : head);\n parts.push(...phasesParts(parsed.phases));\n if (optClause) parts.push(optClause);\n if (period) parts.push('.');\n return mergeAdjacentStrings(parts);\n}\n\n/** Plain-spoken English summary of when a parsed route fires. Intended for\n * developer-facing documentation. Term parts collapse to their label only\n * (e.g. `idle`); use `describeRouteParts()` if you want to expose the\n * glossary definitions in your renderer. */\nexport function describeRoute(parsed: ParsedRoute, opts: DescribeRouteOptions = {}): string {\n return describeRouteParts(parsed, opts)\n .map((p) => (typeof p === 'string' ? p : p.label))\n .join('');\n}\n\nfunction mergeAdjacentStrings(parts: readonly RouteDescriptionPart[]): RouteDescriptionPart[] {\n const out: RouteDescriptionPart[] = [];\n for (const p of parts) {\n const last = out[out.length - 1];\n if (typeof p === 'string' && typeof last === 'string') out[out.length - 1] = last + p;\n else out.push(p);\n }\n return out;\n}\n","import type { ModifierCombo } from './modifiers';\nimport type { ParsedModifiers, ModifierKey } from './routeGrammar';\n\n/** Translate the tool-authoring `ModifierCombo` enum (positional string,\n * e.g. `'mod+shift'`) to the v3 `ParsedModifiers` structured map\n * (every listed modifier becomes `'required'`; unlisted means\n * forbidden / absent). `'default'` yields `{}`. */\nexport function modifierComboToParsed(key: ModifierCombo): ParsedModifiers {\n if (key === 'default') return {};\n const out: ParsedModifiers = {};\n for (const part of key.split('+')) {\n out[part as ModifierKey] = 'required';\n }\n return out;\n}\n\n/** Stable canonical serialization of a ParsedModifiers map for use as a\n * hash key (conflicts dedup). Sorts mod names alphabetically and emits\n * `name=req` pairs joined by `&`. */\nexport function canonicalModifiers(mods: ParsedModifiers): string {\n return Object.entries(mods)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([name, req]) => `${name}=${req}`)\n .join('&');\n}\n","/**\n * GestureSpec — describes the form of a user input event that can fire an action.\n *\n * Used by `Action.defaultBinding` (the action's preferred gesture) and by\n * `GestureBinding.spec` (a tool's binding table entry). The dispatcher matches\n * incoming input events against registered specs to determine which action to\n * invoke.\n *\n * See `docs/superpowers/specs/2026-05-16-registry-unification-design.md` § \"Types\".\n */\n\n/** Optional modifier-key requirement for a gesture spec.\n *\n * Matching semantics (strict): an omitted modifier field means the\n * modifier MUST NOT be held — i.e., a bare `{ kind: 'key', key: 'Escape' }`\n * matches only unmodified Escape, NOT Cmd+Escape. A `true` means the\n * modifier MUST be held; `false` is the same as omitted (must be absent).\n * This mirrors today's `KeyBinding` matcher and keeps conflict detection\n * coherent.\n *\n * `mod` is a platform-aware shorthand: matches `metaKey` on mac, `ctrlKey`\n * elsewhere (mirrors `KeyBinding.mod`).\n *\n * Every modifier additionally accepts `'optional'`, meaning \"held or not,\n * both acceptable\" — the explicit opt-in for loose matching, used by\n * actions like nudge whose step size depends on shift but whose firing\n * does not.\n */\nexport type ModSpec = Partial<{\n alt: boolean | 'optional';\n ctrl: boolean | 'optional';\n meta: boolean | 'optional';\n mod: boolean | 'optional';\n shift: boolean | 'optional';\n}>;\n\n/** The predicate form of {@link TargetSpec}. `hit` is the affordance hit\n * under the pointer, for every gesture kind; `bodyTarget` is the optional\n * body-class string ('empty' | 'selected-body' | 'unselected-body') when\n * `classifyTarget` is wired. Build one with `hitPredicate` or\n * `bodyPredicate`, which make the declaration below. */\nexport interface TargetPredicate {\n (hit: unknown, bodyTarget?: string): boolean;\n /** Whether the predicate reads `hit`. An exclusive affordance claim bars\n * every binding whose target does not: `false` is a predicate that decides\n * from `bodyTarget` alone, and chrome over a body must not read as that body. */\n readsAffordance: boolean;\n}\n\n/** A {@link TargetPredicate} that reads the affordance hit, alone or with the\n * body class, so it stays in contention under an exclusive claim. */\nexport function hitPredicate(\n fn: (hit: unknown, bodyTarget?: string) => boolean,\n): TargetPredicate & { readsAffordance: true } {\n return Object.assign(\n (hit: unknown, bodyTarget?: string): boolean => fn(hit, bodyTarget),\n { readsAffordance: true as const },\n );\n}\n\n/** A {@link TargetPredicate} that decides from the body class alone, so an\n * exclusive affordance claim bars it. */\nexport function bodyPredicate(\n fn: (bodyTarget: string | undefined) => boolean,\n): TargetPredicate & { readsAffordance: false } {\n return Object.assign(\n (_hit: unknown, bodyTarget?: string): boolean => fn(bodyTarget),\n { readsAffordance: false as const },\n );\n}\n\n/** Target selector for click and drag gesture specs. String forms are sugar\n * for the kit-owned object-kind registry (TODO.md Tier 1 follow-up); until\n * that ships, consumers can pass `{ kindOf: predicate }` to classify hits\n * themselves.\n *\n * Adding a form here is a compile error in `parseTargetSpec` until\n * `TargetSpecForm` grows a matching variant — which is in turn a compile\n * error at every site that switches on one. */\nexport type TargetSpec =\n | 'empty'\n | 'selected-body'\n | 'unselected-body'\n | `kind:${string}`\n | `kind:${string}:selected`\n | `affordance:${string}`\n | { kindOf: TargetPredicate };\n\n/** Phase qualifier on a gesture spec. Restricts when the spec matches based\n * on per-tool gesture-lifecycle state.\n *\n * Shorthand forms (most common case — gate on the binding's own tool):\n * `'engaged'` → `[{ channel: '&', phase: 'engaged' }]` // self mid-gesture\n * `'initial'` → `[{ channel: '&', phase: 'initial' }]` // self idle\n * `'*'` → `[{ channel: '&', phase: '*' }]` // either self phase\n *\n * Array form for explicit channel:phase atoms — e.g. `[{ channel: 'rect',\n * phase: 'engaged' }]` for \"when the rect tool is mid-gesture, regardless of\n * which scope I'm in.\" See the v3 route grammar in\n * `@weasel-js/gestures/grammar` for the full lattice.\n *\n * When omitted, matches in any phase (preserves pre-phase behavior). */\nexport type PhaseSpec = 'initial' | 'engaged' | '*' | readonly import('../grammar/routeGrammar').PhaseAtom[];\n\n/** Single-keystroke gesture (keydown). */\nexport interface KeySpec {\n kind: 'key';\n /** A single key, or an array of acceptable keys (case-insensitive match). */\n key: string | string[];\n /** The physical key, as `KeyboardEvent.code` (`'BracketRight'`), or several.\n * Tried before `key`, and either matching is enough: the binding then holds\n * on that key whatever a layout or a held modifier makes it type, and still\n * on any key that types `key`. `key` is what a route names the binding by. */\n code?: string | string[];\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Key-held gesture (keydown opens, keyup closes). Drives \"hold space for\n * hand tool\"-style interactions. */\nexport interface KeyHeldSpec {\n kind: 'key-held';\n /** A single key, or an array of acceptable keys (case-insensitive match). */\n key: string | string[];\n /** The physical key or keys, as on {@link KeySpec.code}. */\n code?: string | string[];\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Wheel-event gesture. `direction` filters by deltaY sign; default `'*'`.\n * - `'up'` → matches only deltaY < 0\n * - `'down'` → matches only deltaY > 0\n * - `'*'` → matches either sign (default; universal-wildcard convention) */\nexport interface WheelSpec {\n kind: 'wheel';\n direction?: 'up' | 'down' | '*';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Pinch reported as a scale factor about a focal point (WebKit\n * `gesturechange`). `direction` filters by the sample's scale; default `'*'`.\n * - `'out'` → fingers spreading, scale > 1\n * - `'in'` → fingers closing, scale < 1\n * A touchscreen pinch is {@link MultiTouchSpec}, not this. */\nexport interface PinchSpec {\n kind: 'pinch';\n direction?: 'in' | 'out' | '*';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Click gesture (pointerdown + pointerup without movement past the\n * threshold). */\nexport interface ClickSpec {\n kind: 'click';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Double-click: two `click` events within 600ms and 8px of each other.\n * Synthesized by `useGestureDispatcher`; emitted AFTER the second\n * `click`. Bindings that want to handle a double-click should declare\n * this kind rather than chasing two `click` events. */\nexport interface DoubleClickSpec {\n kind: 'doubleClick';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Right-click (contextmenu) gesture. The dispatcher calls\n * `preventDefault()` on the underlying DOM event so the native menu\n * doesn't appear — tools/actions fully own the right-click UX. */\nexport interface ContextMenuSpec {\n kind: 'contextMenu';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Drag gesture (pointerdown + pointermove past the threshold). */\nexport interface DragSpec {\n kind: 'drag';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/**\n * Bare pointer press, matched at down time — before the dispatcher knows\n * whether the gesture will become a click or a drag.\n *\n * Reach for this only when the effect must be visible while the button is\n * still held. Selection is the motivating case: pressing an unselected node\n * highlights it immediately, and the drag that may follow then starts from an\n * already-correct selection. Anything that can wait for the release belongs on\n * a `click` spec, which does not fire on a press that turns into a drag.\n *\n * A matching binding does NOT own the gesture: the same press goes on to open\n * a drag or synthesize a click as usual. Bind an immediate action here, not an\n * ongoing one.\n */\nexport interface PointerDownSpec {\n kind: 'pointerDown';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/**\n * Press held past the long-press threshold without crossing the drag\n * threshold. Synthesized by `useGestureDispatcher` from the pointer stream.\n *\n * Fires for `touch` and `pen` pointers only. A mouse held still for half a\n * second is an ordinary slow click, and firing on it would produce a context\n * menu nobody asked for.\n *\n * When a long-press matches no binding, the dispatcher re-dispatches it as a\n * `contextmenu` event — so `contextMenu` bindings work under a finger with no\n * consumer changes, while `longPress` stays independently bindable.\n */\nexport interface LongPressSpec {\n kind: 'longPress';\n target?: TargetSpec;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Multi-touch gesture. `fingers` is the required touch count. */\nexport interface MultiTouchSpec {\n kind: 'multiTouch';\n fingers: number;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** Multi-touch tap gesture — fires when N fingers touch down then release\n * together without movement past the tap threshold, sooner than a long-press\n * would fire. Synthesized by the dispatcher from the underlying multitouch\n * tracking. */\nexport interface MultiTouchTapSpec {\n kind: 'multiTouchTap';\n fingers: number;\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** OS drag-and-drop of external content onto the canvas. `types` filters by\n * MIME glob (`'image/*'`, `'text/plain'`); the spec matches when ANY item's\n * MIME matches ANY glob. Omitted or empty = matches any drop. */\nexport interface DropSpec {\n kind: 'drop';\n types?: string[];\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** System-clipboard paste of external content. Same `types` semantics as\n * {@link DropSpec} — omitted or empty = matches any paste. */\nexport interface PasteSpec {\n kind: 'paste';\n types?: string[];\n mods?: ModSpec;\n phase?: PhaseSpec;\n}\n\n/** The full union of supported gesture spec kinds. New invocation forms\n * (two-stage, modal-dialog) extend this union without touching\n * the `Action` type. */\nexport type GestureSpec =\n | KeySpec\n | KeyHeldSpec\n | WheelSpec\n | PinchSpec\n | ClickSpec\n | DoubleClickSpec\n | ContextMenuSpec\n | DragSpec\n | PointerDownSpec\n | LongPressSpec\n | MultiTouchSpec\n | MultiTouchTapSpec\n | DropSpec\n | PasteSpec;\n","/**\n * Whether this is an Apple platform, where `mod` means the Command key and\n * not Ctrl. iPhone and iPad count: with a keyboard attached their shortcuts\n * are Command shortcuts. False where there is no `navigator`.\n *\n * Pass the answer to {@link matchModifiers} / {@link matchSpec} as `isMac`,\n * and read it wherever a `mod` shortcut is drawn, so a label names the key\n * the matcher listens for.\n */\nexport function isApplePlatform(): boolean {\n if (typeof navigator === 'undefined' || !navigator) return false;\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } };\n // `||`, not `??`: jsdom and some embedders report an empty-string platform.\n const raw = nav.userAgentData?.platform || nav.platform || nav.userAgent || '';\n return /mac|iphone|ipad|ipod/i.test(raw);\n}\n","import { parseTargetSpec } from './match';\nimport type { GestureSpec, ModSpec, PhaseSpec, TargetSpec } from './spec';\nimport type { PhaseAtom } from '../grammar/routeGrammar';\n\n/** Count modifier keys declared as `required` (`true`). `'optional'`,\n * `false`, and `undefined` do NOT discriminate — they don't count. */\nfunction modsCount(mods: ModSpec | undefined): number {\n if (!mods) return 0;\n let n = 0;\n if (mods.alt === true) n++;\n if (mods.ctrl === true) n++;\n if (mods.meta === true) n++;\n if (mods.mod === true) n++;\n if (mods.shift === true) n++;\n return n;\n}\n\n/**\n * Rank a `TargetSpec` by how much it narrows. Graduated so a target that\n * names a specific thing outranks one that only names a class of things:\n *\n * 3 — `kind:<k>:selected`: this kind AND in the selection\n * 2 — `kind:<k>` / `affordance:<k>`: one named kind\n * 1 — `'empty'` / `'selected-body'` / `'unselected-body'` / `{ kindOf }`\n * 0 — no target\n *\n * A predicate stays at 1 because its narrowness is unknowable statically —\n * `hit == null` and `isRotateHandle` are the same shape here. That is also\n * what keeps this addition from reordering any binding that existed before\n * the `kind:`/`affordance:` forms resolved: every one of them ranks 0 or 1.\n */\nfunction targetRank(target: TargetSpec | undefined): number {\n if (target === undefined) return 0;\n const form = parseTargetSpec(target);\n if (form === null) return 1;\n switch (form.form) {\n case 'kind': return form.requireSelected ? 3 : 2;\n case 'affordance': return 2;\n case 'body': return 1;\n case 'predicate': return 1;\n default: {\n const _exhaustive: never = form;\n void _exhaustive;\n return 1;\n }\n }\n}\n\nfunction specTargetOf(spec: GestureSpec): TargetSpec | undefined {\n return 'target' in spec ? spec.target : undefined;\n}\n\n/**\n * Rank a `PhaseSpec` by how much it narrows, on the same graduated principle\n * as `targetRank`. A phase atom constrains two axes — which channel, and its\n * lifecycle state — and each may be wildcarded:\n *\n * 2 — both concrete: `{ channel: '&' | '<toolId>', phase: 'initial' }`,\n * which is also what the bare-keyword shorthand desugars to\n * 1 — one axis wildcarded: `{ channel: '*', phase: 'engaged' }`\n * 0 — `{ channel: '*', phase: '*' }`, or no `phase` field at all\n *\n * The `*:*` case scoring 0 is the point: it matches everything `matchPhase`\n * would have matched with no spec, so grading it above an undeclared phase\n * would let a binding buy precedence with a constraint that constrains\n * nothing — CSS's `:where()` problem.\n *\n * An atom list is a union (`matchPhase` returns true when ANY atom matches),\n * so the list is as broad as its broadest atom and takes the **minimum**.\n *\n * Compat: every phase-bearing spec in the tree keeps its score or rises, and\n * none reorders. The four ambient actions (`escape`, `delete`,\n * `anchorEditing`, `cancelGesture`) all declare `{ channel: '*', phase:\n * <concrete> }` and stay at 1; the polygon and star tools' `phase: 'engaged'`\n * wheel bindings desugar to a concrete `&` atom and rise 1 → 2, which only\n * widens a gap they already won. Nothing in the tree declares `*:*`.\n */\nfunction phaseRank(spec: PhaseSpec | undefined): number {\n if (spec === undefined) return 0;\n const atoms = typeof spec === 'string'\n ? [{ channel: '&', phase: spec } as PhaseAtom]\n : spec;\n if (atoms.length === 0) return 0;\n let min = 2;\n for (const a of atoms) {\n const rank = (a.channel === '*' ? 0 : 1) + (a.phase === '*' ? 0 : 1);\n if (rank < min) min = rank;\n }\n return min;\n}\n\n/** CSS-style specificity tuple for a GestureSpec. Higher tuple wins under\n * lexicographic compare. Dimensions, in order of precedence:\n *\n * [0] target — how much the spec's target narrows; see `targetRank`.\n * [1] mods — count of required modifier keys (shift/alt/ctrl/meta/mod).\n * `'optional'` does NOT count.\n * [2] phase — how much the spec's `phase` narrows; see `phaseRank`.\n * [3] exact — per-kind tiebreak: 2 for a drop/paste spec with a\n * non-empty `types` MIME filter, else 1.\n *\n * Identical tuples fall back to registration order in the matcher's\n * stable sort, preserving the pre-specificity tiebreaker. */\nexport function specificity(\n spec: GestureSpec,\n): readonly [number, number, number, number] {\n const t = targetRank(specTargetOf(spec));\n const mods = ('mods' in spec ? spec.mods : undefined) as ModSpec | undefined;\n const m = modsCount(mods);\n const p = phaseRank(('phase' in spec ? spec.phase : undefined) as PhaseSpec | undefined);\n // Per-kind tiebreak: a MIME-typed drop/paste spec beats an untyped one\n // in the same scope (a consumer's `types: ['text/csv']` binding should\n // win over the kit's catch-all ingest binding).\n const typed =\n (spec.kind === 'drop' || spec.kind === 'paste') &&\n spec.types !== undefined && spec.types.length > 0\n ? 2 : 1;\n return [t, m, p, typed];\n}\n","/**\n * How far, in CSS pixels, a press must travel before it is a drag rather than\n * a click. `drag` specs match only past it: routing's `useGestureDispatcher`\n * holds a pointerdown back until the pointer crosses it, so a press-and-release\n * that stays under it never opens a drag.\n */\nexport const DRAG_THRESHOLD_PX = 4;\n\n/** Whether a pointer that went down at `from` has travelled far enough, by\n * `to`, to be a drag. Both points are client coordinates. */\nexport function pastDragThreshold(\n from: { clientX: number; clientY: number },\n to: { clientX: number; clientY: number },\n threshold: number = DRAG_THRESHOLD_PX,\n): boolean {\n return Math.hypot(to.clientX - from.clientX, to.clientY - from.clientY) >= threshold;\n}\n","/** Elements that handle their own press and keys. */\nexport const CONTROL_SELECTOR = [\n 'button', 'input', 'select', 'textarea', 'a[href]', '[contenteditable=\"\"]', '[contenteditable=\"true\"]',\n '[role=\"button\"]', '[role=\"checkbox\"]', '[role=\"switch\"]', '[role=\"menuitem\"]', '[role=\"link\"]',\n].join(',');\n\n/**\n * Whether `target` sits in a control of its own somewhere inside `host` — a\n * toggle in a list row, a button over a canvas. The host's handlers leave such\n * an event to the control, so a host's press, click and keys never swallow its\n * controls'.\n */\nexport function isInControlWithin(target: EventTarget | null, host: Element): boolean {\n if (!(target instanceof Element)) return false;\n const control = target.closest(CONTROL_SELECTOR);\n return control !== null && control !== host && host.contains(control);\n}\n"]}
|