@weasel-js/gestures 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +147 -14
- package/dist/index.js +32 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -282,6 +282,26 @@ interface DragSpec {
|
|
|
282
282
|
mods?: ModSpec;
|
|
283
283
|
phase?: PhaseSpec;
|
|
284
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Bare pointer press, matched at down time — before the dispatcher knows
|
|
287
|
+
* whether the gesture will become a click or a drag.
|
|
288
|
+
*
|
|
289
|
+
* Reach for this only when the effect must be visible while the button is
|
|
290
|
+
* still held. Selection is the motivating case: pressing an unselected node
|
|
291
|
+
* highlights it immediately, and the drag that may follow then starts from an
|
|
292
|
+
* already-correct selection. Anything that can wait for the release belongs on
|
|
293
|
+
* a `click` spec, which does not fire on a press that turns into a drag.
|
|
294
|
+
*
|
|
295
|
+
* A matching binding does NOT own the gesture: the same press goes on to open
|
|
296
|
+
* a drag or synthesize a click as usual. Bind an immediate action here, not an
|
|
297
|
+
* ongoing one.
|
|
298
|
+
*/
|
|
299
|
+
interface PointerDownSpec {
|
|
300
|
+
kind: 'pointerDown';
|
|
301
|
+
target?: TargetSpec;
|
|
302
|
+
mods?: ModSpec;
|
|
303
|
+
phase?: PhaseSpec;
|
|
304
|
+
}
|
|
285
305
|
/** Multi-touch gesture. `fingers` is the required touch count. */
|
|
286
306
|
interface MultiTouchSpec {
|
|
287
307
|
kind: 'multiTouch';
|
|
@@ -318,7 +338,7 @@ interface PasteSpec {
|
|
|
318
338
|
/** The full union of supported gesture spec kinds. New invocation forms
|
|
319
339
|
* (long-press, two-stage, modal-dialog) extend this union without touching
|
|
320
340
|
* the `Action` type. */
|
|
321
|
-
type GestureSpec = KeySpec | KeyHeldSpec | WheelSpec | ClickSpec | DoubleClickSpec | ContextMenuSpec | DragSpec | MultiTouchSpec | MultiTouchTapSpec | DropSpec | PasteSpec;
|
|
341
|
+
type GestureSpec = KeySpec | KeyHeldSpec | WheelSpec | ClickSpec | DoubleClickSpec | ContextMenuSpec | DragSpec | PointerDownSpec | MultiTouchSpec | MultiTouchTapSpec | DropSpec | PasteSpec;
|
|
322
342
|
|
|
323
343
|
/**
|
|
324
344
|
* Mini-grammar for the `arg` slot of `keyDown` / `keyUp` routes.
|
|
@@ -416,6 +436,35 @@ interface EventModifiers {
|
|
|
416
436
|
* values. Absent when `classifyTarget` is not wired.
|
|
417
437
|
*/
|
|
418
438
|
type BodyTarget = 'empty' | 'selected-body' | 'unselected-body';
|
|
439
|
+
/**
|
|
440
|
+
* Semantic kind of the node body under the point — `'text'`, `'rect'`, or an
|
|
441
|
+
* app's own `'app:note'`. Companion to {@link BodyTarget}, which says only how
|
|
442
|
+
* the body relates to the selection; this says *what it is*. Read by
|
|
443
|
+
* `matchTarget` to resolve the `kind:<k>` / `kind:<k>:selected` TargetSpec
|
|
444
|
+
* forms.
|
|
445
|
+
*
|
|
446
|
+
* Supplied by the same `classifyTarget` thunk that supplies `bodyTarget`, and
|
|
447
|
+
* absent for the same reasons plus one more: the thunk hit a body whose kind
|
|
448
|
+
* the scene can't name. An absent `bodyKind` makes every `kind:` form
|
|
449
|
+
* no-match, never a wildcard.
|
|
450
|
+
*/
|
|
451
|
+
type BodyKind = string;
|
|
452
|
+
/**
|
|
453
|
+
* What a scene hit-test found under a point — the shape a `classifyTarget`
|
|
454
|
+
* thunk returns, and the source of both {@link BodyTarget} and
|
|
455
|
+
* {@link BodyKind} on the events the matcher sees.
|
|
456
|
+
*
|
|
457
|
+
* One thunk returns both halves rather than two thunks returning one each:
|
|
458
|
+
* the two answers come from the same hit-test, and splitting them would cost
|
|
459
|
+
* a second pick on every pointer event.
|
|
460
|
+
*/
|
|
461
|
+
interface BodyClassification {
|
|
462
|
+
/** How the hit body relates to the current selection. */
|
|
463
|
+
body: BodyTarget;
|
|
464
|
+
/** Semantic kind of the hit body. Undefined on empty canvas, and undefined
|
|
465
|
+
* on a body whose kind the scene can't name — never guessed. */
|
|
466
|
+
kind?: BodyKind;
|
|
467
|
+
}
|
|
419
468
|
/** A keystroke. */
|
|
420
469
|
interface KeyEvent extends EventModifiers {
|
|
421
470
|
kind: 'key';
|
|
@@ -436,9 +485,45 @@ interface WheelEvent extends EventModifiers {
|
|
|
436
485
|
clientX: number;
|
|
437
486
|
clientY: number;
|
|
438
487
|
}
|
|
488
|
+
/**
|
|
489
|
+
* Stylus state carried alongside a pointer sample. Every field is optional:
|
|
490
|
+
* the values come straight off the originating `PointerEvent`, and callers
|
|
491
|
+
* that synthesize events (tests, programmatic drags) omit them.
|
|
492
|
+
*
|
|
493
|
+
* Mouse and ordinary touch report `pressure: 0.5` while a button is held
|
|
494
|
+
* and `0` otherwise, per the Pointer Events spec — a consumer that wants
|
|
495
|
+
* stylus-only modulation should gate on real pressure variance rather than
|
|
496
|
+
* on presence of the field.
|
|
497
|
+
*/
|
|
498
|
+
interface PointerSampleStylus {
|
|
499
|
+
/** 0..1. */
|
|
500
|
+
pressure?: number;
|
|
501
|
+
/** Degrees, ±90. Zero for mouse/touch. */
|
|
502
|
+
tiltX?: number;
|
|
503
|
+
/** Degrees, ±90. Zero for mouse/touch. */
|
|
504
|
+
tiltY?: number;
|
|
505
|
+
}
|
|
439
506
|
/** A pointer press — the start of any drag, and the richest event shape. */
|
|
440
|
-
interface PointerDownEvent extends EventModifiers {
|
|
507
|
+
interface PointerDownEvent extends EventModifiers, PointerSampleStylus {
|
|
441
508
|
kind: 'pointerdown';
|
|
509
|
+
/**
|
|
510
|
+
* Which of the two dispatches this press produces.
|
|
511
|
+
*
|
|
512
|
+
* A physical pointerdown is dispatched twice, for two different audiences:
|
|
513
|
+
*
|
|
514
|
+
* - `'press'` — emitted immediately, at down time. Matches `pointerDown`
|
|
515
|
+
* specs only. This is the dispatch that lets a binding act *before* the
|
|
516
|
+
* gesture is classified (select applies the selection here, so
|
|
517
|
+
* press-and-hold highlights without waiting for a release).
|
|
518
|
+
* - omitted — the copy the dispatcher buffers and flushes once movement
|
|
519
|
+
* crosses the drag threshold. Matches `drag` specs only, and is what
|
|
520
|
+
* opens a drag handle.
|
|
521
|
+
*
|
|
522
|
+
* The split is what keeps one press from firing both a `pointerDown` and a
|
|
523
|
+
* `drag` binding. Synthetic probes (the hover pump's `resolveOnly`) leave it
|
|
524
|
+
* omitted, so drag prediction is unaffected.
|
|
525
|
+
*/
|
|
526
|
+
stage?: 'press';
|
|
442
527
|
target?: unknown;
|
|
443
528
|
/** World-space coordinates (post view transform). */
|
|
444
529
|
x?: number;
|
|
@@ -453,10 +538,11 @@ interface PointerDownEvent extends EventModifiers {
|
|
|
453
538
|
/** Generic affordance payload (the kit narrows this to `AffordanceHit`). */
|
|
454
539
|
affordance?: unknown;
|
|
455
540
|
bodyTarget?: BodyTarget;
|
|
541
|
+
bodyKind?: BodyKind;
|
|
456
542
|
}
|
|
457
543
|
/** A pump-only pointer move. Carried in the union so the dispatcher's
|
|
458
544
|
* `handleInput` signature stays uniform; the matcher never matches it. */
|
|
459
|
-
interface PointerMoveEvent extends EventModifiers {
|
|
545
|
+
interface PointerMoveEvent extends EventModifiers, PointerSampleStylus {
|
|
460
546
|
kind: 'pointermove';
|
|
461
547
|
x: number;
|
|
462
548
|
y: number;
|
|
@@ -487,7 +573,30 @@ interface ClickEvent extends EventModifiers {
|
|
|
487
573
|
*/
|
|
488
574
|
worldX?: number;
|
|
489
575
|
worldY?: number;
|
|
576
|
+
/**
|
|
577
|
+
* World-space coordinates of the *press* that opened this click, as opposed
|
|
578
|
+
* to `worldX`/`worldY`, which are the release. The two differ by up to the
|
|
579
|
+
* drag threshold (4px screen).
|
|
580
|
+
*
|
|
581
|
+
* Actions that place geometry at the click want this one — a click's
|
|
582
|
+
* location reads as where the user put the pointer down, and pinning to the
|
|
583
|
+
* press point keeps a snapped coordinate stable against the small drift
|
|
584
|
+
* between press and release. Absent when the `clientToWorld` thunk isn't
|
|
585
|
+
* wired, same as `worldX`/`worldY`.
|
|
586
|
+
*/
|
|
587
|
+
pressX?: number;
|
|
588
|
+
pressY?: number;
|
|
589
|
+
/**
|
|
590
|
+
* Affordance the *press* landed on, carried forward from the pointerdown
|
|
591
|
+
* exactly like {@link ClickEvent.bodyTarget} is. A click's target is
|
|
592
|
+
* whatever the press hit — chrome doesn't move out from under a pointer
|
|
593
|
+
* between down and up — and without this a `kindOf` target on a click spec
|
|
594
|
+
* would receive the raw DOM element while the same predicate on a drag spec
|
|
595
|
+
* receives the affordance.
|
|
596
|
+
*/
|
|
597
|
+
affordance?: unknown;
|
|
490
598
|
bodyTarget?: BodyTarget;
|
|
599
|
+
bodyKind?: BodyKind;
|
|
491
600
|
}
|
|
492
601
|
/** A double click. `worldX`/`worldY` carry the same meaning as on {@link ClickEvent}. */
|
|
493
602
|
interface DoubleClickEvent extends EventModifiers {
|
|
@@ -496,12 +605,14 @@ interface DoubleClickEvent extends EventModifiers {
|
|
|
496
605
|
worldX?: number;
|
|
497
606
|
worldY?: number;
|
|
498
607
|
bodyTarget?: BodyTarget;
|
|
608
|
+
bodyKind?: BodyKind;
|
|
499
609
|
}
|
|
500
610
|
/** A context-menu (right-click) request. */
|
|
501
611
|
interface ContextMenuEvent extends EventModifiers {
|
|
502
612
|
kind: 'contextmenu';
|
|
503
613
|
target?: unknown;
|
|
504
614
|
bodyTarget?: BodyTarget;
|
|
615
|
+
bodyKind?: BodyKind;
|
|
505
616
|
}
|
|
506
617
|
/** A running multitouch gesture (e.g. pinch/rotate). */
|
|
507
618
|
interface MultitouchEvent extends EventModifiers {
|
|
@@ -584,12 +695,21 @@ type InputEvent = KeyEvent | KeyHeldEvent | WheelEvent | PointerDownEvent | Poin
|
|
|
584
695
|
* This keeps the matcher's output a simple boolean and avoids a three-valued
|
|
585
696
|
* return type.
|
|
586
697
|
*
|
|
587
|
-
* ## TargetSpec string
|
|
588
|
-
*
|
|
589
|
-
*
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
698
|
+
* ## TargetSpec string forms
|
|
699
|
+
* Every form `TargetSpec` declares is resolved here, each from a different
|
|
700
|
+
* field the dispatcher packs onto the event:
|
|
701
|
+
*
|
|
702
|
+
* | Form | Read from | Supplied by |
|
|
703
|
+
* | --- | --- | --- |
|
|
704
|
+
* | `'empty'` / `'selected-body'` / `'unselected-body'` | `bodyTarget` | the `classifyTarget` thunk |
|
|
705
|
+
* | `kind:<k>` / `kind:<k>:selected` | `bodyKind` + `bodyTarget` | the `classifyTarget` thunk's node-kind resolver |
|
|
706
|
+
* | `affordance:<k>` | the raw target's `.kind` | the `affordanceAt` thunk |
|
|
707
|
+
* | `{ kindOf }` | the raw target + `bodyTarget` | both |
|
|
708
|
+
*
|
|
709
|
+
* A form whose source field is absent does not match — an unwired
|
|
710
|
+
* `classifyTarget` makes every `bodyTarget`/`bodyKind` form `false` rather
|
|
711
|
+
* than a silent wildcard. That is deliberate: a binding that can't be
|
|
712
|
+
* evaluated should stay out of the way of one that can.
|
|
593
713
|
*/
|
|
594
714
|
|
|
595
715
|
type ModifiersEvent = {
|
|
@@ -623,12 +743,25 @@ declare function matchKey(eventKey: string, specKey: string | string[]): boolean
|
|
|
623
743
|
* the second arg.
|
|
624
744
|
* - `'empty'`, `'selected-body'`, `'unselected-body'` — compared against
|
|
625
745
|
* `bodyTarget` on the event (populated by `useGestureDispatcher` when a
|
|
626
|
-
* `classifyTarget` thunk is supplied).
|
|
627
|
-
*
|
|
628
|
-
*
|
|
746
|
+
* `classifyTarget` thunk is supplied).
|
|
747
|
+
* - `kind:<k>` — compared against `bodyKind`, the *semantic* kind of the node
|
|
748
|
+
* body under the point (`'text'`, `'rect'`, an app's own `'app:note'`), as
|
|
749
|
+
* resolved by `classifyTarget`. Selection-agnostic.
|
|
750
|
+
* - `kind:<k>:selected` — the same, and additionally requires the body to be
|
|
751
|
+
* in the current selection. Only the final `:selected` is a suffix, so a
|
|
752
|
+
* kind may itself contain colons.
|
|
753
|
+
* - `affordance:<k>` — exact match against the affordance hit's own `kind`.
|
|
754
|
+
* Kit affordance kinds are `handle:<corner>`, `'rotate-handle'`,
|
|
755
|
+
* `anchor:<i>`, `controlIn:<i>` / `controlOut:<i>`, and `layer:<id>` for a
|
|
756
|
+
* registered layer's widget. The match is exact and includes any parameter,
|
|
757
|
+
* so "any anchor" needs the `isAnchor` predicate rather than this form.
|
|
629
758
|
* - `undefined` spec.target — any target is accepted.
|
|
759
|
+
*
|
|
760
|
+
* Every string form resolves to `false` when the field it reads is absent, so
|
|
761
|
+
* an unwired `classifyTarget`/`affordanceAt` yields no-match rather than a
|
|
762
|
+
* silent wildcard.
|
|
630
763
|
*/
|
|
631
|
-
declare function matchTarget(target: unknown, specTarget: unknown, bodyTarget?: string): boolean;
|
|
764
|
+
declare function matchTarget(target: unknown, specTarget: unknown, bodyTarget?: string, bodyKind?: string): boolean;
|
|
632
765
|
/** Per-tool gesture-lifecycle state at match time.
|
|
633
766
|
*
|
|
634
767
|
* - `selfChannel` is the tool id `'&'` resolves to — i.e., the tool that
|
|
@@ -666,4 +799,4 @@ declare function matchIngestTypes(items: readonly {
|
|
|
666
799
|
*/
|
|
667
800
|
declare function matchSpec(e: InputEvent, spec: GestureSpec, isMac: boolean, phaseCtx?: PhaseContext): boolean;
|
|
668
801
|
|
|
669
|
-
export { ACTIVE_SIGILS, type BodyTarget, type ChannelRef, type ClickEvent, type ClickSpec, type ContextMenuEvent, type ContextMenuSpec, 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, MOD_NAME_SET, type ModRequirement, type ModSpec, type ModifierCombo, type ModifierKey, type ModifiersEvent, type MultiTouchSpec, type MultiTouchTapSpec, type MultitouchEvent, type MultitouchTapEvent, type OptionalMod, type ParsedKeyRoute, type ParsedModifiers, type ParsedRoute, type PasteEvent, type PasteSpec, type PhaseAtom, type PhaseContext, type PhaseSpec, type PointerCancelEvent, type PointerDownEvent, type PointerMoveEvent, type PointerUpEvent, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, type RouteDescriptionPart, type RouteFieldName, type RoutePhase, type RouteTermLabel, type TargetSpec, VALID_MOD_NAMES, type WheelEvent, type WheelSpec, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, keyRouteToSpec, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, parseKeyRoute, parseRoute };
|
|
802
|
+
export { ACTIVE_SIGILS, type BodyClassification, type BodyKind, type BodyTarget, type ChannelRef, type ClickEvent, type ClickSpec, type ContextMenuEvent, type ContextMenuSpec, 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, MOD_NAME_SET, type ModRequirement, type ModSpec, type ModifierCombo, type ModifierKey, type ModifiersEvent, type MultiTouchSpec, type MultiTouchTapSpec, type MultitouchEvent, type MultitouchTapEvent, type OptionalMod, type ParsedKeyRoute, type ParsedModifiers, type ParsedRoute, type PasteEvent, type PasteSpec, type PhaseAtom, type PhaseContext, type PhaseSpec, type PointerCancelEvent, type PointerDownEvent, type PointerDownSpec, 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 TargetSpec, VALID_MOD_NAMES, type WheelEvent, type WheelSpec, canonicalModifiers, collapseShiftPairs, describeRoute, describeRouteParts, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, isKnownGestureName, keyRouteToSpec, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, parseKeyRoute, parseRoute };
|
package/dist/index.js
CHANGED
|
@@ -430,15 +430,36 @@ function matchKey(eventKey, specKey) {
|
|
|
430
430
|
}
|
|
431
431
|
return specKey.toLowerCase() === lower;
|
|
432
432
|
}
|
|
433
|
-
function
|
|
433
|
+
function affordanceKindOf(target) {
|
|
434
|
+
if (typeof target !== "object" || target === null) return void 0;
|
|
435
|
+
const k = target.kind;
|
|
436
|
+
return typeof k === "string" ? k : void 0;
|
|
437
|
+
}
|
|
438
|
+
function matchTarget(target, specTarget, bodyTarget, bodyKind) {
|
|
434
439
|
if (specTarget === void 0) return true;
|
|
435
440
|
if (typeof specTarget === "object" && specTarget !== null && "kindOf" in specTarget && typeof specTarget.kindOf === "function") {
|
|
436
441
|
return specTarget.kindOf(target, bodyTarget);
|
|
437
442
|
}
|
|
443
|
+
if (typeof specTarget !== "string") return false;
|
|
438
444
|
if (specTarget === "empty" || specTarget === "selected-body" || specTarget === "unselected-body") {
|
|
439
445
|
if (bodyTarget === void 0) return false;
|
|
440
446
|
return bodyTarget === specTarget;
|
|
441
447
|
}
|
|
448
|
+
if (specTarget.startsWith("affordance:")) {
|
|
449
|
+
const wanted = specTarget.slice("affordance:".length);
|
|
450
|
+
return affordanceKindOf(target) === wanted;
|
|
451
|
+
}
|
|
452
|
+
if (specTarget.startsWith("kind:")) {
|
|
453
|
+
if (bodyKind === void 0) return false;
|
|
454
|
+
let wanted = specTarget.slice("kind:".length);
|
|
455
|
+
let requireSelected = false;
|
|
456
|
+
if (wanted.endsWith(":selected")) {
|
|
457
|
+
wanted = wanted.slice(0, -":selected".length);
|
|
458
|
+
requireSelected = true;
|
|
459
|
+
}
|
|
460
|
+
if (bodyKind !== wanted) return false;
|
|
461
|
+
return requireSelected ? bodyTarget === "selected-body" : true;
|
|
462
|
+
}
|
|
442
463
|
return false;
|
|
443
464
|
}
|
|
444
465
|
function normalizePhase(spec) {
|
|
@@ -507,22 +528,28 @@ function matchSpec(e, spec, isMac, phaseCtx) {
|
|
|
507
528
|
case "click": {
|
|
508
529
|
if (e.kind !== "click") return false;
|
|
509
530
|
if (!matchModifiers(e, spec.mods, isMac)) return false;
|
|
510
|
-
return matchTarget(e.
|
|
531
|
+
return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);
|
|
511
532
|
}
|
|
512
533
|
case "doubleClick": {
|
|
513
534
|
if (e.kind !== "doubleclick") return false;
|
|
514
535
|
if (!matchModifiers(e, spec.mods, isMac)) return false;
|
|
515
|
-
return matchTarget(e.target, spec.target, e.bodyTarget);
|
|
536
|
+
return matchTarget(e.target, spec.target, e.bodyTarget, e.bodyKind);
|
|
516
537
|
}
|
|
517
538
|
case "contextMenu": {
|
|
518
539
|
if (e.kind !== "contextmenu") return false;
|
|
519
540
|
if (!matchModifiers(e, spec.mods, isMac)) return false;
|
|
520
|
-
return matchTarget(e.target, spec.target, e.bodyTarget);
|
|
541
|
+
return matchTarget(e.target, spec.target, e.bodyTarget, e.bodyKind);
|
|
521
542
|
}
|
|
522
543
|
case "drag": {
|
|
523
544
|
if (e.kind !== "pointerdown") return false;
|
|
545
|
+
if (e.stage === "press") return false;
|
|
546
|
+
if (!matchModifiers(e, spec.mods, isMac)) return false;
|
|
547
|
+
return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);
|
|
548
|
+
}
|
|
549
|
+
case "pointerDown": {
|
|
550
|
+
if (e.kind !== "pointerdown" || e.stage !== "press") return false;
|
|
524
551
|
if (!matchModifiers(e, spec.mods, isMac)) return false;
|
|
525
|
-
return matchTarget(e.affordance, spec.target, e.bodyTarget);
|
|
552
|
+
return matchTarget(e.affordance, spec.target, e.bodyTarget, e.bodyKind);
|
|
526
553
|
}
|
|
527
554
|
case "multiTouch": {
|
|
528
555
|
if (e.kind !== "multitouch") return false;
|
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/grammar/describeRoute.ts","../src/grammar/modifierComboToParsed.ts","../src/ui/match.ts"],"names":["phase","mods","MOD_ORDER"],"mappings":"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","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 | 'keyDown'\n | 'keyUp'\n | 'keyHeld'\n | 'contextMenu'\n | 'multiTouchTap';\n\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 /** Default value when a route omits the arg slot. Must be in `values`\n * unless `values === 'free'`. Optional: no default means routes that\n * omit the arg slot match every value (only legal for `'free'` args). */\n default?: string;\n}\n\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\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: false, arg: { name: 'direction', values: ['up', 'down', '*'], 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: 'multiTouchTap', hasTarget: false, arg: { name: 'fingers', values: ['2', '3', '4'] } },\n];\n\nconst BY_NAME = new Map<string, GestureDescriptor>(\n GESTURE_DESCRIPTORS.map((d) => [d.name, d]),\n);\n\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\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\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\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\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 default.\n if (desc.arg) {\n const isDefault =\n r.arg === undefined ||\n (desc.arg.default !== undefined && r.arg === desc.arg.default);\n if (!isDefault) 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\nexport interface ParsedKeyRoute {\n key: string;\n optionalMods: readonly OptionalMod[];\n}\n\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\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","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, contextMenu, or multiTouchTap.',\n arg: 'Sub-class of the gesture. Direction for wheel (up / down / *), key name for keyDown / keyUp, finger count for multiTouchTap. Other gestures have no arg slot.',\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\nexport type RouteFieldName = keyof typeof ROUTE_FIELD_DEFINITIONS;\n\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\nfunction actionClause(parsed: ParsedRoute, required: readonly string[]): string {\n const desc = getGestureDescriptor(parsed.gesture as GestureName);\n const modPrefix = required.length > 0 ? `${joinAnd(required)}-` : '';\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 = parsed.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 = parsed.arg === 'up' ? ' up'\n : parsed.arg === 'down' ? ' down'\n : '';\n return `the user ${modPrefix}scrolls${direction}`;\n }\n case 'multiTouchTap':\n return `the user taps with ${parsed.arg ?? 'multiple'} fingers`;\n case 'contextMenu':\n return `the user ${modPrefix}opens the context menu${target}`;\n case 'click':\n return `the user ${modPrefix}clicks${target}`;\n case 'pointerDown':\n return `the user ${modPrefix}presses${target}`;\n case 'dblTap':\n return `the user ${modPrefix}double-taps${target}`;\n case 'drag':\n return `the user ${modPrefix}drags${target}`;\n }\n}\n\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 * 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-form decision\n * String-form TargetSpec values ('empty', 'selected-body', `kind:*`, etc.) are\n * sugar for the kit-owned object-kind registry, which hasn't shipped yet\n * (see docs/TODO.md Tier 1). Phase 3 returns `false` for any string-form\n * target spec so that callers get an explicit no-match rather than a silent\n * wildcard or a runtime throw.\n */\n\nimport type { GestureSpec, ModSpec, PhaseSpec } from './spec';\nimport type { InputEvent } from './inputEvent';\nimport type { PhaseAtom } from '../grammar/routeGrammar';\n\n// ---------------------------------------------------------------------------\n// matchModifiers\n// ---------------------------------------------------------------------------\n\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/**\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). Falls back to `false` when absent\n * (kind registry not yet wired).\n * - Other string-forms (`kind:*`, `affordance:*`) — not yet supported; return false.\n * - `undefined` spec.target — any target is accepted.\n */\nexport function matchTarget(target: unknown, specTarget: unknown, bodyTarget?: string): boolean {\n if (specTarget === undefined) return true;\n\n // kindOf predicate form — receives the raw target (affordance hit for\n // drag, e.target otherwise) plus the bodyTarget classification.\n if (\n typeof specTarget === 'object' &&\n specTarget !== null &&\n 'kindOf' in specTarget &&\n typeof (specTarget as { kindOf: unknown }).kindOf === 'function'\n ) {\n return (specTarget as { kindOf: (t: unknown, bodyTarget?: string) => boolean }).kindOf(target, bodyTarget);\n }\n\n // String-form: 'empty', 'selected-body', 'unselected-body'\n // Resolved from the `classifyTarget` result packed into the event's `bodyTarget`.\n if (\n specTarget === 'empty' ||\n specTarget === 'selected-body' ||\n specTarget === 'unselected-body'\n ) {\n // When classifyTarget isn't wired, bodyTarget is absent → no match.\n if (bodyTarget === undefined) return false;\n return bodyTarget === specTarget;\n }\n\n // Other string-forms (kind:*, affordance:*) — not yet supported.\n return false;\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 true;\n }\n\n case 'click': {\n if (e.kind !== 'click') return false;\n if (!matchModifiers(e, spec.mods, isMac)) return false;\n return matchTarget(e.target, spec.target, e.bodyTarget);\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.target, spec.target, e.bodyTarget);\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.target, spec.target, e.bodyTarget);\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 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);\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/grammar/gestures.ts","../src/grammar/modifiers.ts","../src/grammar/routeGrammar.ts","../src/grammar/keyRouteGrammar.ts","../src/grammar/describeRoute.ts","../src/grammar/modifierComboToParsed.ts","../src/ui/match.ts"],"names":["phase","mods","MOD_ORDER"],"mappings":"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","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 | 'keyDown'\n | 'keyUp'\n | 'keyHeld'\n | 'contextMenu'\n | 'multiTouchTap';\n\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 /** Default value when a route omits the arg slot. Must be in `values`\n * unless `values === 'free'`. Optional: no default means routes that\n * omit the arg slot match every value (only legal for `'free'` args). */\n default?: string;\n}\n\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\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: false, arg: { name: 'direction', values: ['up', 'down', '*'], 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: 'multiTouchTap', hasTarget: false, arg: { name: 'fingers', values: ['2', '3', '4'] } },\n];\n\nconst BY_NAME = new Map<string, GestureDescriptor>(\n GESTURE_DESCRIPTORS.map((d) => [d.name, d]),\n);\n\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\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\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\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\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 default.\n if (desc.arg) {\n const isDefault =\n r.arg === undefined ||\n (desc.arg.default !== undefined && r.arg === desc.arg.default);\n if (!isDefault) 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\nexport interface ParsedKeyRoute {\n key: string;\n optionalMods: readonly OptionalMod[];\n}\n\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\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","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, contextMenu, or multiTouchTap.',\n arg: 'Sub-class of the gesture. Direction for wheel (up / down / *), key name for keyDown / keyUp, finger count for multiTouchTap. Other gestures have no arg slot.',\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\nexport type RouteFieldName = keyof typeof ROUTE_FIELD_DEFINITIONS;\n\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\nfunction actionClause(parsed: ParsedRoute, required: readonly string[]): string {\n const desc = getGestureDescriptor(parsed.gesture as GestureName);\n const modPrefix = required.length > 0 ? `${joinAnd(required)}-` : '';\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 = parsed.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 = parsed.arg === 'up' ? ' up'\n : parsed.arg === 'down' ? ' down'\n : '';\n return `the user ${modPrefix}scrolls${direction}`;\n }\n case 'multiTouchTap':\n return `the user taps with ${parsed.arg ?? 'multiple'} fingers`;\n case 'contextMenu':\n return `the user ${modPrefix}opens the context menu${target}`;\n case 'click':\n return `the user ${modPrefix}clicks${target}`;\n case 'pointerDown':\n return `the user ${modPrefix}presses${target}`;\n case 'dblTap':\n return `the user ${modPrefix}double-taps${target}`;\n case 'drag':\n return `the user ${modPrefix}drags${target}`;\n }\n}\n\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 * 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 } from './spec';\nimport type { InputEvent } from './inputEvent';\nimport type { PhaseAtom } from '../grammar/routeGrammar';\n\n// ---------------------------------------------------------------------------\n// matchModifiers\n// ---------------------------------------------------------------------------\n\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 * 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: unknown,\n bodyTarget?: string,\n bodyKind?: string,\n): boolean {\n if (specTarget === undefined) return true;\n\n // kindOf predicate form — receives the raw target (affordance hit for\n // drag, e.target otherwise) plus the bodyTarget classification.\n if (\n typeof specTarget === 'object' &&\n specTarget !== null &&\n 'kindOf' in specTarget &&\n typeof (specTarget as { kindOf: unknown }).kindOf === 'function'\n ) {\n return (specTarget as { kindOf: (t: unknown, bodyTarget?: string) => boolean }).kindOf(target, bodyTarget);\n }\n\n if (typeof specTarget !== 'string') return false;\n\n // Body-class forms: 'empty', 'selected-body', 'unselected-body'.\n // Resolved from the `classifyTarget` result packed into the event's `bodyTarget`.\n if (\n specTarget === 'empty' ||\n specTarget === 'selected-body' ||\n specTarget === 'unselected-body'\n ) {\n // When classifyTarget isn't wired, bodyTarget is absent → no match.\n if (bodyTarget === undefined) return false;\n return bodyTarget === specTarget;\n }\n\n // Affordance form: exact match on the hit's own kind.\n if (specTarget.startsWith('affordance:')) {\n const wanted = specTarget.slice('affordance:'.length);\n return affordanceKindOf(target) === wanted;\n }\n\n // Node-kind forms. `:selected` is only a suffix when it is the LAST\n // segment — `kind:app:note` names a kind that happens to contain a colon.\n if (specTarget.startsWith('kind:')) {\n if (bodyKind === undefined) return false;\n let wanted = specTarget.slice('kind:'.length);\n let requireSelected = false;\n if (wanted.endsWith(':selected')) {\n wanted = wanted.slice(0, -':selected'.length);\n requireSelected = true;\n }\n if (bodyKind !== wanted) return false;\n return requireSelected ? bodyTarget === 'selected-body' : true;\n }\n\n // Unrecognized string form.\n return false;\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 true;\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.target, 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.target, 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"]}
|