@weasel-js/gestures 1.10.1 → 1.11.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 CHANGED
@@ -1,3 +1,5 @@
1
+ import { MenuShortcut } from '@weasel-js/menu';
2
+
1
3
  /**
2
4
  * Declarative gesture taxonomy. Single source of truth for:
3
5
  * - which gestures hit-test (have a `.target` slot in the route string)
@@ -7,7 +9,7 @@
7
9
  * Reflection, matcher, and inspector UI all read this table. Adding a new
8
10
  * gesture name in one place updates every consumer.
9
11
  */
10
- type GestureName = 'click' | 'pointerDown' | 'hover' | 'dblTap' | 'drag' | 'wheel' | 'pinch' | 'keyDown' | 'keyUp' | 'keyHeld' | 'contextMenu' | 'longPress' | 'multiTouch' | 'multiTouchTap' | 'drop' | 'paste';
12
+ type GestureName = 'click' | 'pointerDown' | 'hover' | 'dblTap' | 'drag' | 'wheel' | 'pinch' | 'keyDown' | 'keyUp' | 'keyHeld' | 'contextMenu' | 'longPress' | 'multiTouch' | 'multiTouchTap' | 'drop' | 'carry' | 'paste';
11
13
  /**
12
14
  * Gesture kinds an affordance claim can bar, in the spec vocabulary bindings
13
15
  * are written in. `'pointer'` is one token because `pointerDown` / `click` /
@@ -397,6 +399,24 @@ interface DropSpec {
397
399
  mods?: ModSpec;
398
400
  phase?: PhaseSpec;
399
401
  }
402
+ /**
403
+ * A press that began elsewhere on the page, carried over the canvas: a palette
404
+ * item dragged in, a row dragged out of a list. The in-app sibling of
405
+ * {@link DropSpec}, which is the OS's drag. A carry is begun with `startCarry`.
406
+ * `types` filters by the payload's `type`, as globs; omitted or empty matches
407
+ * any carry.
408
+ *
409
+ * An ongoing action bound here starts when the carry comes over the surface:
410
+ * its moves update it, the release commits it, and leaving the surface or
411
+ * canceling the press cancels it. An immediate action fires once, on the
412
+ * release.
413
+ */
414
+ interface CarrySpec {
415
+ kind: 'carry';
416
+ types?: string[];
417
+ mods?: ModSpec;
418
+ phase?: PhaseSpec;
419
+ }
400
420
  /** System-clipboard paste of external content. Same `types` semantics as
401
421
  * {@link DropSpec} — omitted or empty = matches any paste. */
402
422
  interface PasteSpec {
@@ -406,7 +426,7 @@ interface PasteSpec {
406
426
  phase?: PhaseSpec;
407
427
  }
408
428
  /** The full union of supported gesture spec kinds. */
409
- type GestureSpec = KeySpec | KeyHeldSpec | WheelSpec | PinchSpec | ClickSpec | DoubleClickSpec | ContextMenuSpec | DragSpec | PointerDownSpec | HoverSpec | LongPressSpec | MultiTouchSpec | MultiTouchTapSpec | DropSpec | PasteSpec;
429
+ type GestureSpec = KeySpec | KeyHeldSpec | WheelSpec | PinchSpec | ClickSpec | DoubleClickSpec | ContextMenuSpec | DragSpec | PointerDownSpec | HoverSpec | LongPressSpec | MultiTouchSpec | MultiTouchTapSpec | DropSpec | CarrySpec | PasteSpec;
410
430
 
411
431
  /**
412
432
  * Mini-grammar for the `arg` slot of `keyDown` / `keyUp` routes.
@@ -447,7 +467,7 @@ declare function keyRouteToSpec(r: ParsedKeyRoute): KeySpec;
447
467
  * Wildcards become omitted fields: a `*` target, direction or MIME list, and a
448
468
  * `[*:*]` phase slot. `[*]` is `[&:*]`, which an ambient binding never
449
469
  * matches, so it stays a phase atom. A `keyDown` / `keyHeld` arg is read as a
450
- * key route, so `keyDown(z?shift)` yields `mods.shift: 'optional'`; a drop or
470
+ * key route, so `keyDown(z?shift)` yields `mods.shift: 'optional'`; a drop, carry, or
451
471
  * paste arg is a `|`-separated MIME list.
452
472
  *
453
473
  * Throws on a route no spec can express: `keyUp`, a key or finger-count
@@ -519,13 +539,6 @@ declare function modifierComboToParsed(key: ModifierCombo): ParsedModifiers;
519
539
  * `name=req` pairs joined by `&`. */
520
540
  declare function canonicalModifiers(mods: ParsedModifiers): string;
521
541
 
522
- /** Keyboard/pointer modifier flags carried by every {@link InputEvent} arm. */
523
- interface EventModifiers {
524
- altKey: boolean;
525
- ctrlKey: boolean;
526
- metaKey: boolean;
527
- shiftKey: boolean;
528
- }
529
542
  /**
530
543
  * Body-target classification from the scene hit-test. Populated by
531
544
  * `useGestureDispatcher` when a `classifyTarget` thunk is supplied to its
@@ -552,6 +565,28 @@ interface BodyClassification {
552
565
  /** Semantic kind of the hit body. Undefined on empty canvas, and undefined
553
566
  * on a body whose kind the scene can't name — never guessed. */
554
567
  kind?: BodyKind;
568
+ /** The node classified. Matching ignores it. */
569
+ id?: string;
570
+ /** What a double-click at this point names, where that is not the body hit: the group a hit
571
+ * member belongs to. A double click's targets match against it. Absent, the hit is named. */
572
+ doubleClick?: {
573
+ body: BodyTarget;
574
+ kind?: BodyKind;
575
+ id?: string;
576
+ };
577
+ }
578
+ /** The body a double-click names, as a press carries it to the double click it composes. */
579
+ interface DoubleClickBody {
580
+ bodyTarget: BodyTarget;
581
+ bodyKind?: BodyKind;
582
+ }
583
+
584
+ /** Keyboard/pointer modifier flags carried by every {@link InputEvent} arm. */
585
+ interface EventModifiers {
586
+ altKey: boolean;
587
+ ctrlKey: boolean;
588
+ metaKey: boolean;
589
+ shiftKey: boolean;
555
590
  }
556
591
  /** A keystroke. */
557
592
  interface KeyEvent extends EventModifiers {
@@ -850,6 +885,21 @@ interface DropEvent extends EventModifiers {
850
885
  clientX?: number;
851
886
  clientY?: number;
852
887
  }
888
+ /** A carry over the canvas (`startCarry`). `stage` is what it did here: came
889
+ * over, moved, was released, or left — off the surface, or canceled on it. */
890
+ interface CarryEvent extends EventModifiers {
891
+ kind: 'carry';
892
+ stage: 'enter' | 'move' | 'drop' | 'leave';
893
+ pointerId?: number;
894
+ /** The payload's type, which a spec's `types` globs filter, and the payload. */
895
+ type: string;
896
+ value: unknown;
897
+ /** World-space position (post view transform). */
898
+ x: number;
899
+ y: number;
900
+ clientX: number;
901
+ clientY: number;
902
+ }
853
903
  /** External content pasted from the system clipboard. Carries no point. */
854
904
  interface PasteEvent extends EventModifiers {
855
905
  kind: 'paste';
@@ -864,7 +914,7 @@ interface PasteEvent extends EventModifiers {
864
914
  * The `affordance?` field on {@link PointerDownEvent} is widened to `unknown`
865
915
  * in this package — the kit narrows it back to `AffordanceHit` at consumption.
866
916
  */
867
- type InputEvent = KeyEvent | KeyHeldEvent | WheelEvent | PinchEvent | PointerDownEvent | PointerMoveEvent | HoverEvent | PointerUpEvent | PointerCancelEvent | ClickEvent | DoubleClickEvent | ContextMenuEvent | LongPressEvent | MultiTouchEvent | MultiTouchTapEvent | DropEvent | PasteEvent;
917
+ type InputEvent = KeyEvent | KeyHeldEvent | WheelEvent | PinchEvent | PointerDownEvent | PointerMoveEvent | HoverEvent | PointerUpEvent | PointerCancelEvent | ClickEvent | DoubleClickEvent | ContextMenuEvent | LongPressEvent | MultiTouchEvent | MultiTouchTapEvent | DropEvent | CarryEvent | PasteEvent;
868
918
 
869
919
  /**
870
920
  * The stylus fields `src` carries, as a spread-able partial: a sample that
@@ -998,6 +1048,126 @@ declare function matchIngestTypes(items: readonly {
998
1048
  */
999
1049
  declare function isApplePlatform(): boolean;
1000
1050
 
1051
+ /** One key of a shortcut as a keyboard prints it. */
1052
+ interface KeyLegend {
1053
+ /** Glyph drawn for the key (modifier or key). */
1054
+ label: string;
1055
+ /** When true, the key may be held but is not required to trigger the action
1056
+ * (e.g. an optional modifier). Defaults to false. */
1057
+ optional?: boolean;
1058
+ }
1059
+ /** Logical modifier name. Matches the kit's `ModifierKey` in shape — kept as a
1060
+ * local type so `weasel-ui` stays independent of `@weasel-js/core`. */
1061
+ type LogicalMod = 'mod' | 'shift' | 'alt' | 'ctrl' | 'meta';
1062
+ /** Detected (or overridden) platform. `'mod'` resolves to ⌘ on macOS,
1063
+ * Ctrl on Windows / Linux. */
1064
+ type Platform = 'macos' | 'windows' | 'linux';
1065
+ /** Visual form of a modifier or named-key label.
1066
+ *
1067
+ * - `'auto'` (default): the per-entry, per-platform default — whatever
1068
+ * label is actually printed on the physical key. macOS keys show the
1069
+ * Apple glyphs (⌘ ⌥ ⌃ ⇧ ⎋ ↵ ⇥). Windows keys mostly show text
1070
+ * (Ctrl, Alt, Shift) BUT the Win key shows its logo (⊞) and the
1071
+ * context-menu key shows ▤. Linux mirrors Windows with Super (⊞).
1072
+ * - `'symbol'` forces a glyph wherever the key has one: Apple's on macOS,
1073
+ * ISO/IEC 9995-7's elsewhere (⎈ Ctrl, ⎇ Alt, ⎋ Esc). A key with no
1074
+ * symbol still falls back to text.
1075
+ * - `'text'` always spells the label out (Cmd / Option / Esc / Enter). */
1076
+ type LegendStyle = 'auto' | 'symbol' | 'text';
1077
+ /** A modifier to render, named platform-independently. */
1078
+ interface LogicalModSpec {
1079
+ name: LogicalMod;
1080
+ /** Marks this modifier as optional (may be held but isn't required).
1081
+ * Forwarded as the resulting `KeyLegend.optional`. */
1082
+ optional?: boolean;
1083
+ }
1084
+ /** Options for {@link keySpecsFromMods}. */
1085
+ interface KeySpecsFromModsOptions {
1086
+ /** Override OS detection. Defaults to {@link detectPlatform}. */
1087
+ platform?: Platform;
1088
+ /** Defaults to `'auto'`. Pass `'symbol'` or `'text'` to force a specific
1089
+ * style regardless of platform. */
1090
+ legend?: LegendStyle;
1091
+ /** Labels that replace the platform and legend tables', by a modifier's
1092
+ * logical name (`mod`, `shift`, `alt`, `ctrl`, `meta`) or a key's
1093
+ * `KeyboardEvent.key` (`Escape`, `Home`, `z`): a whole keyboard's worth
1094
+ * for a layout, a locale, or a keyboard of one's own. */
1095
+ labels?: KeyLabels;
1096
+ }
1097
+ /** Key labels by modifier name or `KeyboardEvent.key`. See {@link KeySpecsFromModsOptions.labels}. */
1098
+ type KeyLabels = Readonly<Record<string, string>>;
1099
+ /** Every label {@link keySpecsFromMods} can produce, on any platform and legend. */
1100
+ declare const MODIFIER_LABELS: ReadonlySet<string>;
1101
+ /** The platform whose key legends to draw. Whether `mod` is ⌘ comes from
1102
+ * `isApplePlatform`, the same read the dispatcher
1103
+ * matches `mod` with, so a keycap names the key that fires. With no
1104
+ * `navigator` (a server render) it answers `'macos'`, the kit's docs
1105
+ * convention; an unrecognized browser reads as `'linux'`. */
1106
+ declare function detectPlatform(): Platform;
1107
+ /**
1108
+ * Map a list of **logical** modifiers (`'mod'`, `'shift'`, …) to **visual**
1109
+ * `KeyLegend`s appropriate for the current platform — `'mod'` means "Cmd on
1110
+ * Mac, Ctrl on Win/Linux".
1111
+ *
1112
+ * ```ts
1113
+ * <KeySequence
1114
+ * keys={keySpecsFromMods([{ name: 'mod' }, { name: 'shift', optional: true }])}
1115
+ * />
1116
+ * ```
1117
+ */
1118
+ declare function keySpecsFromMods(mods: readonly LogicalModSpec[], opts?: KeySpecsFromModsOptions): readonly KeyLegend[];
1119
+ /**
1120
+ * Render a raw `KeyboardEvent.key` value as a platform-appropriate
1121
+ * `KeyLegend`. Named non-modifier keys (Esc, Enter, Tab, Space, Backspace,
1122
+ * Delete, arrows) get the platform's conventional form. Letter / digit /
1123
+ * other keys pass through upper-cased.
1124
+ *
1125
+ * ```ts
1126
+ * keySpecFromKey('Escape', { platform: 'macos' }) // { label: '⎋' }
1127
+ * keySpecFromKey('Escape', { platform: 'windows' }) // { label: 'Esc' }
1128
+ * keySpecFromKey('p') // { label: 'P' }
1129
+ * ```
1130
+ *
1131
+ * Symbol mode off macOS draws ISO/IEC 9995-7's symbols where the key
1132
+ * has one, though Windows and Linux keyboards print the text form.
1133
+ */
1134
+ declare function keySpecFromKey(raw: string, opts?: KeySpecsFromModsOptions & {
1135
+ optional?: boolean;
1136
+ }): KeyLegend;
1137
+
1138
+ /** A keyboard shortcut as the formatters read it: `@weasel-js/menu`'s `MenuShortcut`. */
1139
+ type ShortcutInput = MenuShortcut;
1140
+ /** Options for {@link formatShortcut} and {@link formatShortcutParts}. */
1141
+ interface FormatShortcutOptions {
1142
+ /** Defaults to the detected platform. */
1143
+ platform?: Platform;
1144
+ }
1145
+ /** Format a shortcut as an array of display chips, one per key: the
1146
+ * modifiers, then the key, each as the platform's keyboard prints it, so
1147
+ * `mod` is `⌘` on macOS and `Ctrl` elsewhere. UIs that want a boxed per-key
1148
+ * look render each chip in its own element. `shift: 'optional'` is treated
1149
+ * as falsy. */
1150
+ declare function formatShortcutParts(b: ShortcutInput | undefined, opts?: FormatShortcutOptions): readonly string[] | undefined;
1151
+ /** Format a shortcut as a single display string. Order: mod, shift, alt,
1152
+ * key. On macOS the glyphs run together (`⌘⇧Z`); elsewhere the keys are
1153
+ * spelled out and joined with `+` (`Ctrl+Shift+Z`). Returns `undefined` for
1154
+ * `undefined` input so callers can `??` a fallback. When `key` is an array,
1155
+ * the first element is used. `shift: 'optional'` is treated as falsy. */
1156
+ declare function formatShortcut(b: ShortcutInput | undefined, opts?: FormatShortcutOptions): string | undefined;
1157
+
1158
+ /**
1159
+ * A shortcut as key legends, one per key, as `@weasel-js/ui`'s `KeySequence` draws them: mod, shift, alt, then the
1160
+ * key, each in the platform's own legend (`⌘` on macOS, `Ctrl` elsewhere).
1161
+ * `formatShortcutParts` is these labels as strings. `shift: 'optional'`
1162
+ * becomes an optional key; a key list
1163
+ * renders its first key. Returns `undefined` for no shortcut.
1164
+ *
1165
+ * ```tsx
1166
+ * <KeySequence keys={keySpecsFromShortcut({ key: 'z', mod: true, shift: true })} />
1167
+ * ```
1168
+ */
1169
+ declare function keySpecsFromShortcut(shortcut: ShortcutInput | undefined, opts?: KeySpecsFromModsOptions): readonly KeyLegend[] | undefined;
1170
+
1001
1171
  /**
1002
1172
  * The nearest element `from` sits inside that can host a portalled overlay,
1003
1173
  * or `null` when there is none and the body is the only answer.
@@ -1027,7 +1197,7 @@ declare function fixedSeat(from: Element | null | undefined): FixedSeat;
1027
1197
  * [1] mods — count of required modifier keys (shift/alt/ctrl/meta/mod).
1028
1198
  * `'optional'` does NOT count.
1029
1199
  * [2] phase — how much the spec's `phase` narrows; see `phaseRank`.
1030
- * [3] exact — per-kind tiebreak: 2 for a drop/paste spec with a
1200
+ * [3] exact — per-kind tiebreak: 2 for a drop/carry/paste spec with a
1031
1201
  * non-empty `types` MIME filter, else 1.
1032
1202
  *
1033
1203
  * Identical tuples fall back to registration order in the matcher's
@@ -1102,6 +1272,8 @@ interface PressFacts extends EventModifiers {
1102
1272
  affordance?: unknown;
1103
1273
  bodyTarget?: BodyTarget;
1104
1274
  bodyKind?: BodyKind;
1275
+ /** Replayed onto the double click in place of `bodyTarget` and `bodyKind`. */
1276
+ doubleClickBody?: DoubleClickBody;
1105
1277
  }
1106
1278
  /** Where and how a press was released, for the click it turned out to be. */
1107
1279
  interface ReleaseFacts extends EventModifiers {
@@ -1195,6 +1367,8 @@ interface PressSample extends PointerSample {
1195
1367
  affordance?: unknown;
1196
1368
  bodyTarget?: BodyTarget;
1197
1369
  bodyKind?: BodyKind;
1370
+ /** What a double click this press completes lands on, where not the body hit. */
1371
+ doubleClickBody?: DoubleClickBody;
1198
1372
  }
1199
1373
 
1200
1374
  /**
@@ -1233,6 +1407,14 @@ interface PointerRecognizerOptions {
1233
1407
  toSurface?: (client: Point) => Point;
1234
1408
  /** Long-press hold time in ms, read at each press. Default `LONG_PRESS_MS`. */
1235
1409
  longPressMs?: () => number | undefined;
1410
+ /** Longest gap in ms between two clicks of a double click, read at each click. Default `DOUBLE_CLICK_MAX_MS`. */
1411
+ doubleClickMs?: () => number | undefined;
1412
+ /** Farthest two clicks of a double click may land apart, in CSS px. Default `DOUBLE_CLICK_MAX_PX`. */
1413
+ doubleClickPx?: () => number | undefined;
1414
+ /** Farthest a multitouch tap's fingers may travel, in CSS px. Default `TAP_THRESHOLD_PX`. */
1415
+ tapPx?: () => number | undefined;
1416
+ /** Travel in CSS px that makes a press a drag, read at each move. Default `DRAG_THRESHOLD_PX`. */
1417
+ dragPx?: () => number | undefined;
1236
1418
  clicks?: ClickMemory;
1237
1419
  observer?: RecognizerObserver;
1238
1420
  }
@@ -1303,4 +1485,4 @@ declare function activatesFocusedControl(e: KeyboardEvent): boolean;
1303
1485
  */
1304
1486
  declare function focusedControlOwnsKey(e: KeyboardEvent): boolean;
1305
1487
 
1306
- export { ACTIVE_SIGILS, type BodyClassification, type BodyKind, type BodyTarget, CONTROL_SELECTOR, type ChannelRef, type ClaimableGesture, type ClickEvent, type ClickMemory, type ClickObserver, type ClickSpec, type ContextMenuEvent, type ContextMenuSpec, DOUBLE_CLICK_MAX_MS, DOUBLE_CLICK_MAX_PX, DRAG_THRESHOLD_PX, type DescribeRouteOptions, type DoubleClickEvent, type DoubleClickSpec, type DragSpec, type DropEvent, type DropSpec, type EventModifiers, type FixedSeat, GESTURE_DESCRIPTORS, type GestureArgSpec, type GestureDescriptor, type GestureName, type GestureSpec, type HeldPointers, type HeldPress, type HoverEvent, type HoverSpec, type HoverWhere, type IngestItem, type InputEvent, type KeyEvent, type KeyHeldEvent, type KeyHeldSpec, type KeySpec, LONG_PRESS_MS, type LongPressEvent, type LongPressSpec, MOD_NAME_SET, type ModRequirement, type ModSpec, type ModifierCombo, type ModifierKey, type ModifiersEvent, type MultiTouchEvent, type MultiTouchGeometry, type MultiTouchSpec, type MultiTouchTapEvent, type MultiTouchTapSpec, type OptionalMod, type ParsedKeyRoute, type ParsedModifiers, type ParsedRoute, type PasteEvent, type PasteSpec, type PhaseAtom, type PhaseContext, type PhaseSpec, type PinchEvent, type PinchSpec, type Point, type PointerCancelEvent, type PointerDownEvent, type PointerDownSpec, type PointerIdentity, type PointerMoveEvent, type PointerRecognizer, type PointerRecognizerOptions, type PointerSample, type PointerSampleStylus, type PointerUpEvent, type PressFacts, type PressSample, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, type RecognizerClock, type RecognizerObserver, type RecognizerSink, type ReleaseFacts, type ReleaseOutcome, type RouteDescriptionPart, type RouteFieldName, type RoutePhase, type RouteTermLabel, TAP_THRESHOLD_PX, type TargetPredicate, type TargetSpec, type TargetSpecForm, UNKNOWN_MIME, VALID_MOD_NAMES, type WheelEvent, type WheelSpec, activatesFocusedControl, bodyPredicate, canonicalModifiers, clickEvents, collapseShiftPairs, createPointerRecognizer, describeRoute, describeRouteParts, fixedSeat, focusedControlOwnsKey, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, heldPointers, hitPredicate, isApplePlatform, isEditableTarget, isInControlWithin, isKnownGestureName, keyRouteToSpec, longPressEvents, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, multiTouchGeometry, nearestPortalHost, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity, stylusOf };
1488
+ export { ACTIVE_SIGILS, type BodyClassification, type BodyKind, type BodyTarget, CONTROL_SELECTOR, type CarryEvent, type CarrySpec, type ChannelRef, type ClaimableGesture, type ClickEvent, type ClickMemory, type ClickObserver, type ClickSpec, type ContextMenuEvent, type ContextMenuSpec, DOUBLE_CLICK_MAX_MS, DOUBLE_CLICK_MAX_PX, DRAG_THRESHOLD_PX, type DescribeRouteOptions, type DoubleClickBody, type DoubleClickEvent, type DoubleClickSpec, type DragSpec, type DropEvent, type DropSpec, type EventModifiers, type FixedSeat, type FormatShortcutOptions, GESTURE_DESCRIPTORS, type GestureArgSpec, type GestureDescriptor, type GestureName, type GestureSpec, type HeldPointers, type HeldPress, type HoverEvent, type HoverSpec, type HoverWhere, type IngestItem, type InputEvent, type KeyEvent, type KeyHeldEvent, type KeyHeldSpec, type KeyLabels, type KeyLegend, type KeySpec, type KeySpecsFromModsOptions, LONG_PRESS_MS, type LegendStyle, type LogicalMod, type LogicalModSpec, type LongPressEvent, type LongPressSpec, MODIFIER_LABELS, MOD_NAME_SET, type ModRequirement, type ModSpec, type ModifierCombo, type ModifierKey, type ModifiersEvent, type MultiTouchEvent, type MultiTouchGeometry, type MultiTouchSpec, type MultiTouchTapEvent, type MultiTouchTapSpec, type OptionalMod, type ParsedKeyRoute, type ParsedModifiers, type ParsedRoute, type PasteEvent, type PasteSpec, type PhaseAtom, type PhaseContext, type PhaseSpec, type PinchEvent, type PinchSpec, type Platform, type Point, type PointerCancelEvent, type PointerDownEvent, type PointerDownSpec, type PointerIdentity, type PointerMoveEvent, type PointerRecognizer, type PointerRecognizerOptions, type PointerSample, type PointerSampleStylus, type PointerUpEvent, type PressFacts, type PressSample, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, type RecognizerClock, type RecognizerObserver, type RecognizerSink, type ReleaseFacts, type ReleaseOutcome, type RouteDescriptionPart, type RouteFieldName, type RoutePhase, type RouteTermLabel, type ShortcutInput, TAP_THRESHOLD_PX, type TargetPredicate, type TargetSpec, type TargetSpecForm, UNKNOWN_MIME, VALID_MOD_NAMES, type WheelEvent, type WheelSpec, activatesFocusedControl, bodyPredicate, canonicalModifiers, clickEvents, collapseShiftPairs, createPointerRecognizer, describeRoute, describeRouteParts, detectPlatform, fixedSeat, focusedControlOwnsKey, formatKeyRoute, formatPhaseAtom, formatRoute, formatShortcut, formatShortcutParts, getGestureDescriptor, heldPointers, hitPredicate, isApplePlatform, isEditableTarget, isInControlWithin, isKnownGestureName, keyRouteToSpec, keySpecFromKey, keySpecsFromMods, keySpecsFromShortcut, longPressEvents, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, multiTouchGeometry, nearestPortalHost, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity, stylusOf };
package/dist/index.js CHANGED
@@ -18,6 +18,7 @@ var GESTURE_DESCRIPTORS = [
18
18
  // matches any payload, which is what an omitted arg slot means for a
19
19
  // `'free'` arg.
20
20
  { name: "drop", hasTarget: false, arg: { name: "types", values: "free" } },
21
+ { name: "carry", hasTarget: false, arg: { name: "types", values: "free" } },
21
22
  { name: "paste", hasTarget: false, arg: { name: "types", values: "free" } }
22
23
  ];
23
24
  var BY_NAME = new Map(
@@ -490,21 +491,25 @@ function matchSpec(e, spec, isMac, phaseCtx) {
490
491
  if (e.fingers !== spec.fingers) return false;
491
492
  return matchModifiers(e, spec.mods, isMac);
492
493
  }
493
- case "drop": {
494
- if (e.kind !== "drop") return false;
495
- if (!matchIngestTypes(e.items, spec.types)) return false;
496
- return matchModifiers(e, spec.mods, isMac);
497
- }
498
- case "paste": {
499
- if (e.kind !== "paste") return false;
500
- if (!matchIngestTypes(e.items, spec.types)) return false;
501
- return matchModifiers(e, spec.mods, isMac);
502
- }
494
+ case "drop":
495
+ case "carry":
496
+ case "paste":
497
+ return matchArrival(e, spec, isMac);
503
498
  default: {
504
499
  return false;
505
500
  }
506
501
  }
507
502
  }
503
+ function matchArrival(e, spec, isMac) {
504
+ if (e.kind !== spec.kind) return false;
505
+ if (e.kind === "carry") {
506
+ if (e.stage !== "enter" && e.stage !== "drop") return false;
507
+ if (!matchIngestTypes([{ mime: e.type }], spec.types)) return false;
508
+ } else if (e.kind === "drop" || e.kind === "paste") {
509
+ if (!matchIngestTypes(e.items, spec.types)) return false;
510
+ }
511
+ return matchModifiers(e, spec.mods, isMac);
512
+ }
508
513
  var EMPTY_ENGAGED = /* @__PURE__ */ new Set();
509
514
 
510
515
  // src/grammar/specKinds.ts
@@ -523,6 +528,7 @@ var SPEC_KIND_TO_GESTURE = {
523
528
  multiTouch: "multiTouch",
524
529
  multiTouchTap: "multiTouchTap",
525
530
  drop: "drop",
531
+ carry: "carry",
526
532
  paste: "paste"
527
533
  };
528
534
  var GESTURE_TO_SPEC_KIND = new Map(
@@ -593,6 +599,7 @@ function routeToSpec(parsed) {
593
599
  if (arg === void 0) return fail(`a ${kind} spec needs concrete fingers`);
594
600
  return withMods({ kind, fingers: Number(arg) });
595
601
  case "drop":
602
+ case "carry":
596
603
  case "paste":
597
604
  return withMods({ kind, ...arg ? { types: arg.split("|") } : {} });
598
605
  }
@@ -710,6 +717,8 @@ function actionClause(parsed, required) {
710
717
  return userDoes(required, `drags${target}`);
711
718
  case "drop":
712
719
  return userDoes(required, `drops ${arg ?? "any"} content onto the canvas`);
720
+ case "carry":
721
+ return userDoes(required, `carries ${arg ?? "anything"} onto the canvas`);
713
722
  case "paste":
714
723
  return userDoes(required, `pastes ${arg ?? "any"} content`);
715
724
  }
@@ -784,6 +793,115 @@ function isApplePlatform() {
784
793
  return /mac|iphone|ipad|ipod/i.test(raw);
785
794
  }
786
795
 
796
+ // src/ui/keySpecsFromMods.ts
797
+ var MOD_BY_PLATFORM = {
798
+ mod: {
799
+ macos: { auto: "\u2318", symbol: "\u2318", text: "Cmd" },
800
+ windows: { auto: "Ctrl", symbol: "\u2388", text: "Ctrl" },
801
+ linux: { auto: "Ctrl", symbol: "\u2388", text: "Ctrl" }
802
+ },
803
+ shift: {
804
+ macos: { auto: "\u21E7", symbol: "\u21E7", text: "Shift" },
805
+ windows: { auto: "\u21E7", symbol: "\u21E7", text: "Shift" },
806
+ linux: { auto: "\u21E7", symbol: "\u21E7", text: "Shift" }
807
+ },
808
+ // Off macOS the symbols are ISO/IEC 9995-7's: ⎈ for Control, ⎇ for Alt.
809
+ alt: {
810
+ macos: { auto: "\u2325", symbol: "\u2325", text: "Option" },
811
+ windows: { auto: "Alt", symbol: "\u2387", text: "Alt" },
812
+ linux: { auto: "Alt", symbol: "\u2387", text: "Alt" }
813
+ },
814
+ ctrl: {
815
+ macos: { auto: "\u2303", symbol: "\u2303", text: "Control" },
816
+ windows: { auto: "Ctrl", symbol: "\u2388", text: "Ctrl" },
817
+ linux: { auto: "Ctrl", symbol: "\u2388", text: "Ctrl" }
818
+ },
819
+ // Windows/Linux Meta has a recognized symbol on the physical key (⊞ Win
820
+ // logo / Super logo), so `auto` shows it. Use `text` for Win / Super.
821
+ meta: {
822
+ macos: { auto: "\u2318", symbol: "\u2318", text: "Cmd" },
823
+ windows: { auto: "\u229E", symbol: "\u229E", text: "Win" },
824
+ linux: { auto: "\u229E", symbol: "\u229E", text: "Super" }
825
+ }
826
+ };
827
+ var MODIFIER_LABELS = new Set(
828
+ Object.values(MOD_BY_PLATFORM).flatMap(
829
+ (byPlatform) => Object.values(byPlatform).flatMap((byLegend) => Object.values(byLegend))
830
+ )
831
+ );
832
+ function detectPlatform() {
833
+ if (typeof navigator === "undefined" || !navigator) return "macos";
834
+ if (isApplePlatform()) return "macos";
835
+ const nav = navigator;
836
+ const raw = nav.userAgentData?.platform || nav.platform || nav.userAgent || "";
837
+ return /\bwin/i.test(raw) ? "windows" : "linux";
838
+ }
839
+ function keySpecsFromMods(mods2, opts = {}) {
840
+ const platform = opts.platform ?? detectPlatform();
841
+ const legend = opts.legend ?? "auto";
842
+ return mods2.map((m) => {
843
+ const label = opts.labels?.[m.name] ?? MOD_BY_PLATFORM[m.name][platform][legend];
844
+ return m.optional ? { label, optional: true } : { label };
845
+ });
846
+ }
847
+ var NAMED_KEY = {
848
+ Escape: { macos: { auto: "\u238B", symbol: "\u238B", text: "Esc" }, windows: { auto: "Esc", symbol: "\u238B", text: "Esc" }, linux: { auto: "Esc", symbol: "\u238B", text: "Esc" } },
849
+ Enter: { macos: { auto: "\u21B5", symbol: "\u21B5", text: "Return" }, windows: { auto: "Enter", symbol: "\u21B5", text: "Enter" }, linux: { auto: "Enter", symbol: "\u21B5", text: "Enter" } },
850
+ Return: { macos: { auto: "\u21B5", symbol: "\u21B5", text: "Return" }, windows: { auto: "Enter", symbol: "\u21B5", text: "Enter" }, linux: { auto: "Enter", symbol: "\u21B5", text: "Enter" } },
851
+ Tab: { macos: { auto: "\u21E5", symbol: "\u21E5", text: "Tab" }, windows: { auto: "Tab", symbol: "\u21E5", text: "Tab" }, linux: { auto: "Tab", symbol: "\u21E5", text: "Tab" } },
852
+ Space: { macos: { auto: "\u2423", symbol: "\u2423", text: "Space" }, windows: { auto: "Space", symbol: "\u2423", text: "Space" }, linux: { auto: "Space", symbol: "\u2423", text: "Space" } },
853
+ " ": { macos: { auto: "\u2423", symbol: "\u2423", text: "Space" }, windows: { auto: "Space", symbol: "\u2423", text: "Space" }, linux: { auto: "Space", symbol: "\u2423", text: "Space" } },
854
+ Backspace: { macos: { auto: "\u232B", symbol: "\u232B", text: "Backspace" }, windows: { auto: "Backspace", symbol: "\u27F5", text: "Backspace" }, linux: { auto: "Backspace", symbol: "\u27F5", text: "Backspace" } },
855
+ Delete: { macos: { auto: "\u2326", symbol: "\u2326", text: "Delete" }, windows: { auto: "Delete", symbol: "\u2326", text: "Delete" }, linux: { auto: "Delete", symbol: "\u2326", text: "Delete" } },
856
+ // Context-menu key (the right-Ctrl-area key on Windows / Linux keyboards
857
+ // with a ▤ icon). Mac has no equivalent; falls back to text 'Menu'.
858
+ ContextMenu: { macos: { auto: "Menu", symbol: "Menu", text: "Menu" }, windows: { auto: "\u25A4", symbol: "\u25A4", text: "Menu" }, linux: { auto: "\u25A4", symbol: "\u25A4", text: "Menu" } },
859
+ // Symbol mode only: Apple's arrows for Home, End, and the page keys, and
860
+ // ISO/IEC 9995-7's symbols for the rest.
861
+ Home: { macos: { auto: "Home", symbol: "\u2196", text: "Home" }, windows: { auto: "Home", symbol: "\u2196", text: "Home" }, linux: { auto: "Home", symbol: "\u2196", text: "Home" } },
862
+ End: { macos: { auto: "End", symbol: "\u2198", text: "End" }, windows: { auto: "End", symbol: "\u2198", text: "End" }, linux: { auto: "End", symbol: "\u2198", text: "End" } },
863
+ PageUp: { macos: { auto: "PgUp", symbol: "\u21DE", text: "PgUp" }, windows: { auto: "PgUp", symbol: "\u21DE", text: "PgUp" }, linux: { auto: "PgUp", symbol: "\u21DE", text: "PgUp" } },
864
+ PageDown: { macos: { auto: "PgDn", symbol: "\u21DF", text: "PgDn" }, windows: { auto: "PgDn", symbol: "\u21DF", text: "PgDn" }, linux: { auto: "PgDn", symbol: "\u21DF", text: "PgDn" } },
865
+ PrintScreen: { macos: { auto: "PrtSc", symbol: "\u2399", text: "PrtSc" }, windows: { auto: "PrtSc", symbol: "\u2399", text: "PrtSc" }, linux: { auto: "PrtSc", symbol: "\u2399", text: "PrtSc" } },
866
+ Insert: { macos: { auto: "Ins", symbol: "\u2380", text: "Insert" }, windows: { auto: "Ins", symbol: "\u2380", text: "Insert" }, linux: { auto: "Ins", symbol: "\u2380", text: "Insert" } },
867
+ ScrollLock: { macos: { auto: "ScrLk", symbol: "\u21F3", text: "ScrLk" }, windows: { auto: "ScrLk", symbol: "\u21F3", text: "ScrLk" }, linux: { auto: "ScrLk", symbol: "\u21F3", text: "ScrLk" } },
868
+ Pause: { macos: { auto: "Pause", symbol: "\u2389", text: "Pause" }, windows: { auto: "Pause", symbol: "\u2389", text: "Pause" }, linux: { auto: "Pause", symbol: "\u2389", text: "Pause" } },
869
+ ArrowUp: { macos: { auto: "\u2191", symbol: "\u2191", text: "\u2191" }, windows: { auto: "\u2191", symbol: "\u2191", text: "\u2191" }, linux: { auto: "\u2191", symbol: "\u2191", text: "\u2191" } },
870
+ ArrowDown: { macos: { auto: "\u2193", symbol: "\u2193", text: "\u2193" }, windows: { auto: "\u2193", symbol: "\u2193", text: "\u2193" }, linux: { auto: "\u2193", symbol: "\u2193", text: "\u2193" } },
871
+ ArrowLeft: { macos: { auto: "\u2190", symbol: "\u2190", text: "\u2190" }, windows: { auto: "\u2190", symbol: "\u2190", text: "\u2190" }, linux: { auto: "\u2190", symbol: "\u2190", text: "\u2190" } },
872
+ ArrowRight: { macos: { auto: "\u2192", symbol: "\u2192", text: "\u2192" }, windows: { auto: "\u2192", symbol: "\u2192", text: "\u2192" }, linux: { auto: "\u2192", symbol: "\u2192", text: "\u2192" } }
873
+ };
874
+ function keySpecFromKey(raw, opts = {}) {
875
+ const platform = opts.platform ?? detectPlatform();
876
+ const legend = opts.legend ?? "auto";
877
+ const entry = NAMED_KEY[raw];
878
+ const override = opts.labels?.[raw] ?? (raw.length === 1 ? opts.labels?.[raw.toUpperCase()] : void 0);
879
+ const label = override ?? (entry ? entry[platform][legend] : raw.length === 1 ? raw.toUpperCase() : raw);
880
+ return opts.optional ? { label, optional: true } : { label };
881
+ }
882
+
883
+ // src/ui/keySpecsFromShortcut.ts
884
+ function keySpecsFromShortcut(shortcut, opts = {}) {
885
+ if (!shortcut) return void 0;
886
+ const mods2 = [];
887
+ if (shortcut.mod) mods2.push({ name: "mod" });
888
+ if (shortcut.shift) mods2.push(shortcut.shift === "optional" ? { name: "shift", optional: true } : { name: "shift" });
889
+ if (shortcut.alt) mods2.push({ name: "alt" });
890
+ const key = typeof shortcut.key === "string" ? shortcut.key : shortcut.key[0];
891
+ const keys = keySpecsFromMods(mods2, opts);
892
+ return key === void 0 ? keys : [...keys, keySpecFromKey(key, opts)];
893
+ }
894
+
895
+ // src/ui/formatShortcut.ts
896
+ var labels = (b, opts) => b ? keySpecsFromShortcut({ ...b, shift: b.shift === true }, opts)?.map((k) => k.label) : void 0;
897
+ function formatShortcutParts(b, opts = {}) {
898
+ return labels(b, opts);
899
+ }
900
+ function formatShortcut(b, opts = {}) {
901
+ const platform = opts.platform ?? detectPlatform();
902
+ return platform === "macos" ? labels(b, { platform })?.join("") : labels(b, { platform, legend: "text" })?.join("+");
903
+ }
904
+
787
905
  // src/ui/fixedSeat.ts
788
906
  var HOST_SELECTOR = "[data-wzl-portal-host],[data-wzl-theme],[data-wzl-mode]";
789
907
  function nearestPortalHost(from) {
@@ -849,7 +967,7 @@ function specificity(spec) {
849
967
  const mods2 = "mods" in spec ? spec.mods : void 0;
850
968
  const m = modsCount(mods2);
851
969
  const p = phaseRank("phase" in spec ? spec.phase : void 0);
852
- const typed = (spec.kind === "drop" || spec.kind === "paste") && spec.types !== void 0 && spec.types.length > 0 ? 2 : 1;
970
+ const typed = (spec.kind === "drop" || spec.kind === "carry" || spec.kind === "paste") && spec.types !== void 0 && spec.types.length > 0 ? 2 : 1;
853
971
  return [t, m, p, typed];
854
972
  }
855
973
 
@@ -883,12 +1001,16 @@ function clickEvents(down, up) {
883
1001
  x: up.worldX,
884
1002
  y: up.worldY,
885
1003
  clientX: up.clientX,
886
- clientY: up.clientY,
887
- ...pressedOn(down)
1004
+ clientY: up.clientY
888
1005
  };
1006
+ const named = down.doubleClickBody;
889
1007
  return {
890
- click: { kind: "click", ...shared, pressX: down.worldX, pressY: down.worldY },
891
- doubleclick: { kind: "doubleclick", ...shared }
1008
+ click: { kind: "click", ...shared, ...pressedOn(down), pressX: down.worldX, pressY: down.worldY },
1009
+ doubleclick: {
1010
+ kind: "doubleclick",
1011
+ ...shared,
1012
+ ...pressedOn(named ? { affordance: down.affordance, ...named } : down)
1013
+ }
892
1014
  };
893
1015
  }
894
1016
  function longPressEvents(down) {
@@ -908,14 +1030,14 @@ function longPressEvents(down) {
908
1030
  }
909
1031
 
910
1032
  // src/recognizer/click.ts
911
- function composeClick(down, up, clicks, now, dispatch, observer) {
1033
+ function composeClick(down, up, clicks, now, dispatch, observer, limits = { maxMs: DOUBLE_CLICK_MAX_MS, maxPx: DOUBLE_CLICK_MAX_PX }) {
912
1034
  const evs = clickEvents(down, up);
913
1035
  const world = { x: up.worldX, y: up.worldY };
914
1036
  dispatch(evs.click);
915
1037
  observer.click?.(world);
916
1038
  const t = now();
917
1039
  const prev = clicks.last;
918
- const follows = prev !== null && t - prev.t < DOUBLE_CLICK_MAX_MS && Math.hypot(up.clientX - prev.clientX, up.clientY - prev.clientY) < DOUBLE_CLICK_MAX_PX;
1040
+ const follows = prev !== null && t - prev.t < limits.maxMs && Math.hypot(up.clientX - prev.clientX, up.clientY - prev.clientY) < limits.maxPx;
919
1041
  if (!follows) {
920
1042
  clicks.last = { t, clientX: up.clientX, clientY: up.clientY };
921
1043
  return {};
@@ -969,7 +1091,7 @@ function multiTouchGeometry(positions) {
969
1091
  angle: Math.atan2(dy, dx) * 180 / Math.PI
970
1092
  };
971
1093
  }
972
- function createMultiTouchEpisode() {
1094
+ function createMultiTouchEpisode(tapPx = () => TAP_THRESHOLD_PX) {
973
1095
  let episode = null;
974
1096
  return {
975
1097
  join(positions, centroid, now) {
@@ -990,14 +1112,14 @@ function createMultiTouchEpisode() {
990
1112
  },
991
1113
  moved(pointerId, to) {
992
1114
  const from = episode?.joinedAt.get(pointerId);
993
- if (episode && from && Math.hypot(to.x - from.x, to.y - from.y) > TAP_THRESHOLD_PX) episode.moved = true;
1115
+ if (episode && from && Math.hypot(to.x - from.x, to.y - from.y) > tapPx()) episode.moved = true;
994
1116
  },
995
1117
  finish(centroid, now, maxHoldMs) {
996
1118
  const e = episode;
997
1119
  episode = null;
998
1120
  if (!e) return null;
999
1121
  const brief = now - e.startedAt < maxHoldMs;
1000
- const still = Math.hypot(centroid.x - e.centroid.x, centroid.y - e.centroid.y) <= TAP_THRESHOLD_PX;
1122
+ const still = Math.hypot(centroid.x - e.centroid.x, centroid.y - e.centroid.y) <= tapPx();
1001
1123
  return brief && !e.moved && still ? e.fingers : null;
1002
1124
  },
1003
1125
  abandon() {
@@ -1018,7 +1140,8 @@ function pressFactsOf(s) {
1018
1140
  worldX: s.x,
1019
1141
  worldY: s.y,
1020
1142
  ...modifiersOf(s),
1021
- ...pressedOn(s)
1143
+ ...pressedOn(s),
1144
+ ...s.doubleClickBody !== void 0 ? { doubleClickBody: s.doubleClickBody } : {}
1022
1145
  };
1023
1146
  }
1024
1147
  var at = (s, world) => ({
@@ -1057,16 +1180,27 @@ function fireLongPress(rec, sink, observer) {
1057
1180
  rec.buffered = null;
1058
1181
  if (rec.holdType) observer.longPress?.(rec.holdType);
1059
1182
  }
1183
+ function thresholdsOf(opts) {
1184
+ return {
1185
+ longPressMs: () => opts.longPressMs?.() ?? LONG_PRESS_MS,
1186
+ tapPx: () => opts.tapPx?.() ?? TAP_THRESHOLD_PX,
1187
+ dragPx: () => opts.dragPx?.() ?? DRAG_THRESHOLD_PX,
1188
+ doubleClick: () => ({
1189
+ maxMs: opts.doubleClickMs?.() ?? DOUBLE_CLICK_MAX_MS,
1190
+ maxPx: opts.doubleClickPx?.() ?? DOUBLE_CLICK_MAX_PX
1191
+ })
1192
+ };
1193
+ }
1060
1194
  function createPointerRecognizer(opts) {
1061
1195
  const { sink, clock, observer = {}, toSurface = (p) => p } = opts;
1062
1196
  const world = (s) => opts.toWorld?.(s.clientX, s.clientY) ?? { x: s.clientX, y: s.clientY };
1063
1197
  const clicks = opts.clicks ?? { last: null };
1064
1198
  const held = /* @__PURE__ */ new Map();
1065
- const touches = createMultiTouchEpisode();
1199
+ const { longPressMs, tapPx, dragPx, doubleClick } = thresholdsOf(opts);
1200
+ const touches = createMultiTouchEpisode(tapPx);
1066
1201
  const hold = createLongPressHold(clock, (pending) => {
1067
1202
  observer.holdChanged?.(pending);
1068
1203
  });
1069
- const longPressMs = () => opts.longPressMs?.() ?? LONG_PRESS_MS;
1070
1204
  const geometry = (extra = []) => heldGeometry(held, toSurface, extra);
1071
1205
  const claimForMultiTouch = (mods2) => {
1072
1206
  hold.cancel();
@@ -1097,7 +1231,7 @@ function createPointerRecognizer(opts) {
1097
1231
  const to = { x: s.clientX, y: s.clientY };
1098
1232
  if (rec) rec.pos = to;
1099
1233
  touches.moved(s.pointerId, to);
1100
- if (rec?.buffered && pastDragThreshold(rec.down, s)) {
1234
+ if (rec?.buffered && pastDragThreshold(rec.down, s, dragPx())) {
1101
1235
  const press = rec.buffered;
1102
1236
  rec.buffered = null;
1103
1237
  hold.cancel(s.pointerId);
@@ -1133,7 +1267,7 @@ function createPointerRecognizer(opts) {
1133
1267
  worldY: at2.y,
1134
1268
  ...modifiersOf(s)
1135
1269
  };
1136
- return composeClick(rec.down, up, clicks, () => clock.now(), (ev) => sink.dispatch(ev), observer);
1270
+ return composeClick(rec.down, up, clicks, () => clock.now(), (ev) => sink.dispatch(ev), observer, doubleClick());
1137
1271
  },
1138
1272
  cancel(pointerId) {
1139
1273
  const rec = held.get(pointerId);
@@ -1287,6 +1421,6 @@ function focusedControlOwnsKey(e) {
1287
1421
  return activatesFocusedControl(e) || selectOwnsKey(e);
1288
1422
  }
1289
1423
 
1290
- export { ACTIVE_SIGILS, CONTROL_SELECTOR, DOUBLE_CLICK_MAX_MS, DOUBLE_CLICK_MAX_PX, DRAG_THRESHOLD_PX, GESTURE_DESCRIPTORS, LONG_PRESS_MS, MOD_NAME_SET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, TAP_THRESHOLD_PX, UNKNOWN_MIME, VALID_MOD_NAMES, activatesFocusedControl, bodyPredicate, canonicalModifiers, clickEvents, collapseShiftPairs, createPointerRecognizer, describeRoute, describeRouteParts, fixedSeat, focusedControlOwnsKey, formatKeyRoute, formatPhaseAtom, formatRoute, getGestureDescriptor, heldPointers, hitPredicate, isApplePlatform, isEditableTarget, isInControlWithin, isKnownGestureName, keyRouteToSpec, longPressEvents, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, multiTouchGeometry, nearestPortalHost, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity, stylusOf };
1424
+ export { ACTIVE_SIGILS, CONTROL_SELECTOR, DOUBLE_CLICK_MAX_MS, DOUBLE_CLICK_MAX_PX, DRAG_THRESHOLD_PX, GESTURE_DESCRIPTORS, LONG_PRESS_MS, MODIFIER_LABELS, MOD_NAME_SET, RESERVED_ID_NAMES, RESERVED_ID_PREFIXES, RESERVED_SIGILS, ROUTE_FIELD_DEFINITIONS, ROUTE_TERMS, TAP_THRESHOLD_PX, UNKNOWN_MIME, VALID_MOD_NAMES, activatesFocusedControl, bodyPredicate, canonicalModifiers, clickEvents, collapseShiftPairs, createPointerRecognizer, describeRoute, describeRouteParts, detectPlatform, fixedSeat, focusedControlOwnsKey, formatKeyRoute, formatPhaseAtom, formatRoute, formatShortcut, formatShortcutParts, getGestureDescriptor, heldPointers, hitPredicate, isApplePlatform, isEditableTarget, isInControlWithin, isKnownGestureName, keyRouteToSpec, keySpecFromKey, keySpecsFromMods, keySpecsFromShortcut, longPressEvents, matchIngestTypes, matchKey, matchModifiers, matchPhase, matchSpec, matchTarget, mimeMatchesGlob, modifierComboToParsed, mods, multiTouchGeometry, nearestPortalHost, parseKeyRoute, parseRoute, parseTargetSpec, pastDragThreshold, routeGestureForSpecKind, routeToSpec, specKindForRouteGesture, specificity, stylusOf };
1291
1425
  //# sourceMappingURL=index.js.map
1292
1426
  //# sourceMappingURL=index.js.map