955 lines
31 KiB
TypeScript
955 lines
31 KiB
TypeScript
|
|
import { Store } from 'jotai/vanilla/store';
|
||
|
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
||
|
|
import React$1 from 'react';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Input Classifier
|
||
|
|
*
|
||
|
|
* Classifies pointer events into input sources (finger, pencil, mouse)
|
||
|
|
* and extracts stylus-specific data (pressure, tilt).
|
||
|
|
*
|
||
|
|
* This is the foundation of the touch-first input architecture:
|
||
|
|
* - Pencil draws/selects
|
||
|
|
* - Fingers navigate (pan/zoom)
|
||
|
|
* - Mouse does both
|
||
|
|
*/
|
||
|
|
/** Input device type */
|
||
|
|
type InputSource = 'finger' | 'pencil' | 'mouse';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Core types for @blinksgg/canvas
|
||
|
|
*/
|
||
|
|
/**
|
||
|
|
* JSON type compatible with Supabase's generated types.
|
||
|
|
* This allows the package to work with database JSONB fields.
|
||
|
|
*/
|
||
|
|
type Json = string | number | boolean | null | {
|
||
|
|
[key: string]: Json | undefined;
|
||
|
|
} | Json[];
|
||
|
|
type NodeId = string;
|
||
|
|
interface NodePosition {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Database node record - the shape of node data from your database.
|
||
|
|
* Uses Json type for JSONB fields to be compatible with Supabase's generated types.
|
||
|
|
*/
|
||
|
|
interface DBGraphNode {
|
||
|
|
id: string;
|
||
|
|
graph_id: string;
|
||
|
|
label: string | null;
|
||
|
|
node_type: string | null;
|
||
|
|
configuration: Json | null;
|
||
|
|
ui_properties: Json | null;
|
||
|
|
/** App-specific customization data */
|
||
|
|
data?: Json | null;
|
||
|
|
created_at: string;
|
||
|
|
updated_at: string;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Graph node attributes stored in Graphology
|
||
|
|
*/
|
||
|
|
interface GraphNodeAttributes {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
size: number;
|
||
|
|
width: number;
|
||
|
|
height: number;
|
||
|
|
color: string;
|
||
|
|
label?: string;
|
||
|
|
zIndex: number;
|
||
|
|
dbData: DBGraphNode;
|
||
|
|
/** Parent group node ID (for nested grouping) */
|
||
|
|
parentId?: string;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Complete UI node state for rendering
|
||
|
|
*/
|
||
|
|
interface UINodeState extends GraphNodeAttributes {
|
||
|
|
id: NodeId;
|
||
|
|
position: NodePosition;
|
||
|
|
isDragging: boolean;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* A selectable option for 'select' type inputs.
|
||
|
|
*/
|
||
|
|
type SelectOption = {
|
||
|
|
/** Display label for the option */
|
||
|
|
label: string;
|
||
|
|
/** Value to use when selected */
|
||
|
|
value: string;
|
||
|
|
/** Single key shortcut (e.g., 'w' for widget) */
|
||
|
|
shortcut: string;
|
||
|
|
/** Optional description shown on hover */
|
||
|
|
description?: string;
|
||
|
|
};
|
||
|
|
/**
|
||
|
|
* Input mode - controls how canvas interactions are routed.
|
||
|
|
* When not 'normal', canvas clicks are intercepted for special handling.
|
||
|
|
*/
|
||
|
|
type InputMode = {
|
||
|
|
type: 'normal';
|
||
|
|
} | {
|
||
|
|
type: 'pickPoint';
|
||
|
|
prompt: string;
|
||
|
|
snapToGrid?: boolean;
|
||
|
|
} | {
|
||
|
|
type: 'pickNode';
|
||
|
|
prompt: string;
|
||
|
|
filter?: (node: UINodeState) => boolean;
|
||
|
|
} | {
|
||
|
|
type: 'pickNodes';
|
||
|
|
prompt: string;
|
||
|
|
filter?: (node: UINodeState) => boolean;
|
||
|
|
} | {
|
||
|
|
type: 'text';
|
||
|
|
prompt: string;
|
||
|
|
} | {
|
||
|
|
type: 'select';
|
||
|
|
prompt: string;
|
||
|
|
options: SelectOption[];
|
||
|
|
};
|
||
|
|
type KeyboardInteractionMode = 'navigate' | 'manipulate';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gesture System v2 — Core Types
|
||
|
|
*
|
||
|
|
* Single source of truth for every type in the gesture pipeline.
|
||
|
|
* No runtime code — pure type definitions.
|
||
|
|
*/
|
||
|
|
|
||
|
|
type PointerLifecycle = 'down' | 'move' | 'up' | 'cancel';
|
||
|
|
type Button = 0 | 1 | 2;
|
||
|
|
interface Modifiers {
|
||
|
|
shift: boolean;
|
||
|
|
ctrl: boolean;
|
||
|
|
alt: boolean;
|
||
|
|
meta: boolean;
|
||
|
|
/** Non-keyboard modifier flags (touch toolbars, stylus buttons, etc.). */
|
||
|
|
custom?: Record<string, boolean>;
|
||
|
|
}
|
||
|
|
declare const NO_MODIFIERS: Modifiers;
|
||
|
|
interface HeldKeysState {
|
||
|
|
byKey: Readonly<Record<string, boolean>>;
|
||
|
|
byCode: Readonly<Record<string, boolean>>;
|
||
|
|
}
|
||
|
|
declare const NO_HELD_KEYS: HeldKeysState;
|
||
|
|
interface NormalizedPointer {
|
||
|
|
pointerId: number;
|
||
|
|
lifecycle: PointerLifecycle;
|
||
|
|
source: InputSource;
|
||
|
|
button: Button;
|
||
|
|
modifiers: Modifiers;
|
||
|
|
screenX: number;
|
||
|
|
screenY: number;
|
||
|
|
pressure: number;
|
||
|
|
timestamp: number;
|
||
|
|
}
|
||
|
|
type PointerGestureType = 'tap' | 'double-tap' | 'triple-tap' | 'long-press' | 'drag' | 'pinch' | 'scroll';
|
||
|
|
type GestureType = PointerGestureType;
|
||
|
|
type PointerGesturePhase = 'start' | 'move' | 'end' | 'instant' | 'cancel';
|
||
|
|
type KeyInputPhase = 'down' | 'up';
|
||
|
|
type InputPhase = PointerGesturePhase | KeyInputPhase;
|
||
|
|
type GestureSubject = {
|
||
|
|
kind: 'background';
|
||
|
|
} | {
|
||
|
|
kind: 'node';
|
||
|
|
nodeId: string;
|
||
|
|
} | {
|
||
|
|
kind: 'edge';
|
||
|
|
edgeId: string;
|
||
|
|
} | {
|
||
|
|
kind: 'port';
|
||
|
|
nodeId: string;
|
||
|
|
portId: string;
|
||
|
|
};
|
||
|
|
type SubjectKind = GestureSubject['kind'];
|
||
|
|
interface Vec2 {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
}
|
||
|
|
interface PointerGestureEvent {
|
||
|
|
kind?: 'pointer';
|
||
|
|
type: PointerGestureType;
|
||
|
|
phase: PointerGesturePhase;
|
||
|
|
subject: GestureSubject;
|
||
|
|
source: InputSource;
|
||
|
|
button: Button;
|
||
|
|
modifiers: Modifiers;
|
||
|
|
heldKeys: HeldKeysState;
|
||
|
|
pointerId?: number;
|
||
|
|
screenPosition: Vec2;
|
||
|
|
worldPosition: Vec2;
|
||
|
|
delta?: Vec2;
|
||
|
|
velocity?: Vec2;
|
||
|
|
scale?: number;
|
||
|
|
originalEvent?: Event;
|
||
|
|
}
|
||
|
|
interface KeyInputEvent {
|
||
|
|
kind: 'key';
|
||
|
|
phase: KeyInputPhase;
|
||
|
|
key: string;
|
||
|
|
code: string;
|
||
|
|
repeat: boolean;
|
||
|
|
modifiers: Modifiers;
|
||
|
|
heldKeys: HeldKeysState;
|
||
|
|
subject?: GestureSubject;
|
||
|
|
screenPosition?: Vec2;
|
||
|
|
worldPosition?: Vec2;
|
||
|
|
originalEvent?: Event;
|
||
|
|
}
|
||
|
|
type InputEvent = PointerGestureEvent | KeyInputEvent;
|
||
|
|
type GestureEvent = PointerGestureEvent;
|
||
|
|
type TimedStateTag = 'idle' | 'pressed' | 'released' | 'long-pressed';
|
||
|
|
interface TimedState {
|
||
|
|
tag: TimedStateTag;
|
||
|
|
tapCount: number;
|
||
|
|
}
|
||
|
|
interface TimedStateResult {
|
||
|
|
state: TimedState;
|
||
|
|
emit?: PointerGestureType;
|
||
|
|
scheduleTimer?: {
|
||
|
|
id: string;
|
||
|
|
delayMs: number;
|
||
|
|
};
|
||
|
|
cancelTimer?: string;
|
||
|
|
}
|
||
|
|
interface HeldKeysPattern {
|
||
|
|
byKey?: Record<string, boolean>;
|
||
|
|
byCode?: Record<string, boolean>;
|
||
|
|
}
|
||
|
|
interface InputPattern {
|
||
|
|
kind?: 'pointer' | 'key';
|
||
|
|
type?: PointerGestureType;
|
||
|
|
subjectKind?: SubjectKind;
|
||
|
|
source?: InputSource;
|
||
|
|
button?: Button;
|
||
|
|
phase?: InputPhase;
|
||
|
|
modifiers?: Partial<Modifiers>;
|
||
|
|
key?: string;
|
||
|
|
code?: string;
|
||
|
|
heldKeys?: HeldKeysPattern;
|
||
|
|
}
|
||
|
|
type GesturePattern = InputPattern;
|
||
|
|
interface Binding {
|
||
|
|
id: string;
|
||
|
|
pattern: InputPattern;
|
||
|
|
actionId: string;
|
||
|
|
consumeInput?: boolean;
|
||
|
|
when?: (ctx: GuardContext) => boolean;
|
||
|
|
}
|
||
|
|
interface MappingContext {
|
||
|
|
id: string;
|
||
|
|
priority: number;
|
||
|
|
enabled: boolean;
|
||
|
|
bindings: Binding[];
|
||
|
|
}
|
||
|
|
interface GuardContext {
|
||
|
|
isStylusActive: boolean;
|
||
|
|
fingerCount: number;
|
||
|
|
isDragging: boolean;
|
||
|
|
isResizing: boolean;
|
||
|
|
isSplitting: boolean;
|
||
|
|
inputMode: InputMode;
|
||
|
|
keyboardInteractionMode: KeyboardInteractionMode;
|
||
|
|
selectedNodeIds: ReadonlySet<string>;
|
||
|
|
focusedNodeId: string | null;
|
||
|
|
isSearchActive: boolean;
|
||
|
|
commandLineVisible: boolean;
|
||
|
|
heldKeys: HeldKeysState;
|
||
|
|
custom: Record<string, unknown>;
|
||
|
|
}
|
||
|
|
interface ResolvedAction {
|
||
|
|
actionId: string;
|
||
|
|
binding: Binding;
|
||
|
|
contextId: string;
|
||
|
|
score: number;
|
||
|
|
consumed: boolean;
|
||
|
|
}
|
||
|
|
type BivariantCallback<Args extends unknown[], Result = void> = {
|
||
|
|
bivarianceHack: (...args: Args) => Result;
|
||
|
|
}['bivarianceHack'];
|
||
|
|
interface PhaseHandler {
|
||
|
|
onStart?: BivariantCallback<[PointerGestureEvent]>;
|
||
|
|
onMove?: BivariantCallback<[PointerGestureEvent]>;
|
||
|
|
onEnd?: BivariantCallback<[PointerGestureEvent]>;
|
||
|
|
onInstant?: BivariantCallback<[PointerGestureEvent]>;
|
||
|
|
onCancel?: BivariantCallback<[PointerGestureEvent]>;
|
||
|
|
onDown?: BivariantCallback<[KeyInputEvent]>;
|
||
|
|
onUp?: BivariantCallback<[KeyInputEvent]>;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Action handler. Simple function form fires only on 'start' and 'instant'.
|
||
|
|
* Object form routes each phase to a dedicated method.
|
||
|
|
*/
|
||
|
|
type ActionHandler = BivariantCallback<[InputEvent]> | PhaseHandler;
|
||
|
|
declare function isKeyInputEvent(event: InputEvent): event is KeyInputEvent;
|
||
|
|
declare function isPointerGestureEvent(event: InputEvent): event is PointerGestureEvent;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Layer 1: Normalize
|
||
|
|
*
|
||
|
|
* Converts raw DOM PointerEvents into NormalizedPointer structs.
|
||
|
|
* Pure functions — no side effects, no DOM listeners.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extract modifiers from any DOM event with modifier flags.
|
||
|
|
*/
|
||
|
|
declare function extractModifiers(e: {
|
||
|
|
shiftKey: boolean;
|
||
|
|
ctrlKey: boolean;
|
||
|
|
altKey: boolean;
|
||
|
|
metaKey: boolean;
|
||
|
|
}): Modifiers;
|
||
|
|
/**
|
||
|
|
* Normalize a raw PointerEvent into a NormalizedPointer.
|
||
|
|
*/
|
||
|
|
declare function normalizePointer(e: PointerEvent): NormalizedPointer;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Layer 2: Timed State Machine
|
||
|
|
*
|
||
|
|
* Per-pointer state machine for recognizing taps, double-taps,
|
||
|
|
* triple-taps, and long-press. Pure functions — no timers inside.
|
||
|
|
* The caller manages setTimeout via the returned timer commands.
|
||
|
|
*
|
||
|
|
* State diagram:
|
||
|
|
* idle → pressed (on down)
|
||
|
|
* pressed → released (on up, emit tap/double-tap/triple-tap)
|
||
|
|
* pressed → idle (on move-beyond-threshold, becomes drag)
|
||
|
|
* pressed → long-pressed (on long-press-timer)
|
||
|
|
* released → pressed (on down within multi-tap window)
|
||
|
|
* released → idle (on settle-timer)
|
||
|
|
* long-pressed → idle (on up)
|
||
|
|
* any → idle (on cancel)
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare const LONG_PRESS_TIMER = "long-press";
|
||
|
|
declare const SETTLE_TIMER = "settle";
|
||
|
|
declare const IDLE: TimedState;
|
||
|
|
type TimedEvent = 'down' | 'up' | 'move-beyond-threshold' | 'cancel' | 'timer:long-press' | 'timer:settle';
|
||
|
|
interface TimedConfig {
|
||
|
|
longPressMs: number;
|
||
|
|
multiTapWindowMs: number;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Pure state transition. Returns new state + optional side effects
|
||
|
|
* (emit gesture, schedule/cancel timer).
|
||
|
|
*/
|
||
|
|
declare function transition(state: TimedState, event: TimedEvent, config?: TimedConfig): TimedStateResult;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Timed State Runner
|
||
|
|
*
|
||
|
|
* Timer bridge that wraps the pure TimedState transitions with actual
|
||
|
|
* setTimeout/clearTimeout. Each pointer gets its own runner.
|
||
|
|
*
|
||
|
|
* The runner is imperative on purpose — it's managed by refs in hooks,
|
||
|
|
* not by React state. This avoids re-renders on timer state changes.
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare class TimedStateRunner {
|
||
|
|
private state;
|
||
|
|
private timers;
|
||
|
|
private config;
|
||
|
|
/** Called when the state machine emits a gesture (tap, double-tap, long-press, etc.) */
|
||
|
|
onEmit: ((gestureType: GestureType) => void) | null;
|
||
|
|
constructor(config?: Partial<TimedConfig>);
|
||
|
|
/**
|
||
|
|
* Feed a lifecycle event into the state machine.
|
||
|
|
* Returns the emitted gesture type if any (synchronous emit only).
|
||
|
|
* Timer-based emits are delivered asynchronously via `onEmit`.
|
||
|
|
*/
|
||
|
|
feed(event: 'down' | 'up' | 'move-beyond-threshold' | 'cancel'): GestureType | undefined;
|
||
|
|
/** Current state tag (for debugging/testing). */
|
||
|
|
get tag(): TimedState['tag'];
|
||
|
|
/** Destroy: cancel all pending timers. */
|
||
|
|
destroy(): void;
|
||
|
|
private apply;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Layer 3: Specificity Scoring
|
||
|
|
*
|
||
|
|
* Scores how well an InputPattern matches an InputEvent.
|
||
|
|
* Higher score = more specific match. Returns -1 on mismatch.
|
||
|
|
*
|
||
|
|
* Score weights:
|
||
|
|
* type 128 (must outweigh all others combined)
|
||
|
|
* subjectKind 32
|
||
|
|
* modifier+ 16 (per positive flag)
|
||
|
|
* modifier- 8 (per negative flag)
|
||
|
|
* source 4
|
||
|
|
* button 2
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Compute the specificity score of a pattern against an event.
|
||
|
|
* Returns -1 if the pattern does not match.
|
||
|
|
*/
|
||
|
|
declare function specificity(pattern: InputPattern, event: InputEvent): number;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Layer 3: Gesture Mapper
|
||
|
|
*
|
||
|
|
* Resolves an InputEvent against a priority-sorted stack of MappingContexts.
|
||
|
|
* Each context is bucketed by pointer gesture type or keyboard phase for O(1) lookup.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/** Pre-indexed bindings for a single MappingContext. */
|
||
|
|
interface ContextIndex {
|
||
|
|
contextId: string;
|
||
|
|
priority: number;
|
||
|
|
enabled: boolean;
|
||
|
|
/** Bindings bucketed by gesture type. '__wildcard__' for type-less patterns. */
|
||
|
|
buckets: Map<string, Binding[]>;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Build a lookup index from a MappingContext.
|
||
|
|
* Wildcard bindings (no `type` in pattern) are concatenated into every bucket.
|
||
|
|
*/
|
||
|
|
declare function indexContext(ctx: MappingContext): ContextIndex;
|
||
|
|
/** The full indexed context stack, sorted by priority ascending. */
|
||
|
|
type MappingIndex = ContextIndex[];
|
||
|
|
/**
|
||
|
|
* Build the full mapping index from a list of contexts.
|
||
|
|
* Sorts by priority ascending (lower number = higher priority).
|
||
|
|
*/
|
||
|
|
declare function buildMappingIndex(contexts: MappingContext[]): MappingIndex;
|
||
|
|
/**
|
||
|
|
* Resolve a gesture event against the indexed context stack.
|
||
|
|
*
|
||
|
|
* Algorithm:
|
||
|
|
* 1. Walk contexts in priority order (ascending = highest priority first).
|
||
|
|
* 2. For each enabled context, look up the bucket for event.type.
|
||
|
|
* 3. For each binding in the bucket, compute specificity score.
|
||
|
|
* 4. If binding has a `when` guard, evaluate it.
|
||
|
|
* 5. Track best match per context.
|
||
|
|
* 6. If best match has `consumeInput`, return immediately.
|
||
|
|
* 7. Otherwise, continue to lower-priority contexts.
|
||
|
|
* 8. Return the highest-priority best match across all contexts.
|
||
|
|
*/
|
||
|
|
declare function resolve(event: InputEvent, index: MappingIndex, guard: GuardContext): ResolvedAction | null;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Keyboard Mapping Contexts
|
||
|
|
*
|
||
|
|
* Search, manipulate, and navigate keyboard contexts extracted from contexts.ts.
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare const SEARCH_CONTEXT: MappingContext;
|
||
|
|
declare const KEYBOARD_MANIPULATE_CONTEXT: MappingContext;
|
||
|
|
declare const KEYBOARD_NAVIGATE_CONTEXT: MappingContext;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Pointer & Default Mapping Contexts
|
||
|
|
*
|
||
|
|
* DEFAULT_CONTEXT assembled from pointer-bindings + keyboard-bindings.
|
||
|
|
* Input mode contexts for pick operations.
|
||
|
|
*
|
||
|
|
* @since 1.7.0 — bindings extracted into keyboard-bindings.ts and pointer-bindings.ts
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare const DEFAULT_CONTEXT: MappingContext;
|
||
|
|
declare const PICK_NODE_CONTEXT: MappingContext;
|
||
|
|
declare const PICK_NODES_CONTEXT: MappingContext;
|
||
|
|
declare const PICK_POINT_CONTEXT: MappingContext;
|
||
|
|
/**
|
||
|
|
* Lookup table: input mode type → MappingContext to push.
|
||
|
|
* 'normal' maps to null (no extra context).
|
||
|
|
*/
|
||
|
|
declare const INPUT_MODE_CONTEXTS: Record<string, MappingContext | null>;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Built-in Mapping Contexts
|
||
|
|
*
|
||
|
|
* Default bindings, palm rejection, and input-mode contexts.
|
||
|
|
* All are plain data with runtime conditions expressed via guard predicates.
|
||
|
|
*
|
||
|
|
* Keyboard contexts are in ./keyboard-contexts.ts
|
||
|
|
* Default + input mode contexts are in ./pointer-contexts.ts
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* When a stylus is active, block finger taps and remap finger-on-node
|
||
|
|
* drags to pan. Pinch and scroll are intentionally NOT blocked.
|
||
|
|
*/
|
||
|
|
declare const PALM_REJECTION_CONTEXT: MappingContext;
|
||
|
|
declare const ACTIVE_INTERACTION_CONTEXT: MappingContext;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Layer 4: Gesture Dispatcher
|
||
|
|
*
|
||
|
|
* Routes resolved actions to registered handlers, respecting input phase.
|
||
|
|
* Simple function handlers fire only on pointer 'start'/'instant' and key 'down'.
|
||
|
|
* Object handlers route each phase to a dedicated method.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Register an action handler. Overwrites any existing handler for the same ID.
|
||
|
|
*/
|
||
|
|
declare function registerAction(actionId: string, handler: ActionHandler): void;
|
||
|
|
/**
|
||
|
|
* Remove a registered action handler.
|
||
|
|
*/
|
||
|
|
declare function unregisterAction(actionId: string): void;
|
||
|
|
/**
|
||
|
|
* Get a registered handler (for testing/introspection).
|
||
|
|
*/
|
||
|
|
declare function getHandler(actionId: string): ActionHandler | undefined;
|
||
|
|
/**
|
||
|
|
* Clear all registered handlers (for testing).
|
||
|
|
*/
|
||
|
|
declare function clearHandlers(): void;
|
||
|
|
/**
|
||
|
|
* Dispatch a resolved gesture event to its action handler.
|
||
|
|
*
|
||
|
|
* Returns true if a handler was found and invoked, false otherwise.
|
||
|
|
* The 'none' action ID is always a no-op — it means the binding
|
||
|
|
* intentionally blocks the gesture without executing anything.
|
||
|
|
*/
|
||
|
|
declare function dispatch(event: InputEvent, resolution: ResolvedAction): boolean;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Inertia Engine
|
||
|
|
*
|
||
|
|
* Pure momentum simulation with friction decay.
|
||
|
|
* No requestAnimationFrame — the caller drives ticks.
|
||
|
|
* Fully testable without any DOM or timer dependency.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Ring buffer that tracks recent velocity samples.
|
||
|
|
* Call `sample()` on each move, then `average()` on end.
|
||
|
|
*/
|
||
|
|
declare class VelocitySampler {
|
||
|
|
private samples;
|
||
|
|
private maxSamples;
|
||
|
|
constructor(maxSamples?: number);
|
||
|
|
sample(vx: number, vy: number, t: number): void;
|
||
|
|
average(): Vec2;
|
||
|
|
reset(): void;
|
||
|
|
}
|
||
|
|
declare class PanInertia {
|
||
|
|
private friction;
|
||
|
|
private minVelocity;
|
||
|
|
private vx;
|
||
|
|
private vy;
|
||
|
|
constructor(velocity: Vec2, friction?: number, minVelocity?: number);
|
||
|
|
/**
|
||
|
|
* Advance one frame. Returns the velocity delta to apply,
|
||
|
|
* or null if below threshold (animation complete).
|
||
|
|
*/
|
||
|
|
tick(): Vec2 | null;
|
||
|
|
}
|
||
|
|
declare class ZoomInertia {
|
||
|
|
private origin;
|
||
|
|
private friction;
|
||
|
|
private minVelocity;
|
||
|
|
private snapThreshold;
|
||
|
|
private v;
|
||
|
|
constructor(velocity: number, origin: Vec2, friction?: number, minVelocity?: number, snapThreshold?: number);
|
||
|
|
/**
|
||
|
|
* Advance one frame. Returns zoom delta + origin,
|
||
|
|
* or null if below threshold.
|
||
|
|
*/
|
||
|
|
tick(currentZoom: number): {
|
||
|
|
delta: number;
|
||
|
|
origin: Vec2;
|
||
|
|
} | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Modifier Helpers
|
||
|
|
*
|
||
|
|
* Pure utility functions for gesture state queries — repeat detection,
|
||
|
|
* selection lookup, subject resolution.
|
||
|
|
*
|
||
|
|
* Extracted from input-action-helpers.ts in v1.6.0.
|
||
|
|
*
|
||
|
|
* @since 1.6.0
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determine what entity the current gesture targets.
|
||
|
|
*/
|
||
|
|
declare function getCurrentSubject(store: Store): GestureSubject;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gesture Classification — Navigation
|
||
|
|
*
|
||
|
|
* Pure navigation functions for keyboard-based node traversal:
|
||
|
|
* findNearestNode, cycleFocus, navigateFocus, activateFocusedNode.
|
||
|
|
*
|
||
|
|
* Extracted from input-action-helpers.ts in v1.6.0.
|
||
|
|
*
|
||
|
|
* @since 1.6.0
|
||
|
|
*/
|
||
|
|
|
||
|
|
type Direction = 'up' | 'down' | 'left' | 'right';
|
||
|
|
/**
|
||
|
|
* Find the nearest node in a given direction from the current focus.
|
||
|
|
*/
|
||
|
|
declare function findNearestNode(currentNodeId: string | null, store: Store, direction: Direction): string | null;
|
||
|
|
/**
|
||
|
|
* Cycle focus to the next/previous node by z-index order.
|
||
|
|
*/
|
||
|
|
declare function cycleFocus(store: Store, direction: 1 | -1): void;
|
||
|
|
/**
|
||
|
|
* Navigate focus to the nearest node in a direction.
|
||
|
|
*/
|
||
|
|
declare function navigateFocus(store: Store, direction: Direction): void;
|
||
|
|
/**
|
||
|
|
* Activate the focused node — select it and optionally enter manipulate mode.
|
||
|
|
*/
|
||
|
|
declare function activateFocusedNode(store: Store, enterManipulate: boolean): void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Input Action Helpers
|
||
|
|
*
|
||
|
|
* Pure store-based helper functions used by useRegisterInputActions.
|
||
|
|
* These are extracted for testability — each function operates on a
|
||
|
|
* Jotai store without React dependencies.
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare function nudgeSelection(store: Store, dx: number, dy: number, label: string): void;
|
||
|
|
declare function deleteSelection(store: Store): void;
|
||
|
|
declare function cutSelection(store: Store): void;
|
||
|
|
declare function cancelActiveInteraction(store: Store): boolean;
|
||
|
|
declare function escapeInput(store: Store): void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useCanvasGestures — Main viewport gesture hook
|
||
|
|
*
|
||
|
|
* Wires @use-gesture/react → recognize → resolve → dispatch.
|
||
|
|
*
|
||
|
|
* Responsibilities:
|
||
|
|
* - Pointer tracking (down/up/cancel) via input-store
|
||
|
|
* - Tap/double-tap/long-press via TimedStateRunner
|
||
|
|
* - Drag intent resolution via mapper
|
||
|
|
* - Pan with inertia (delegated to useInertia)
|
||
|
|
* - Pinch zoom with inertia + snap-to-100%
|
||
|
|
* - Wheel zoom
|
||
|
|
* - Lasso / rect-select routing
|
||
|
|
* - pointercancel + visibilitychange cleanup
|
||
|
|
*
|
||
|
|
* Guard context is built by useGuardContext.
|
||
|
|
* Inertia is managed by useInertia.
|
||
|
|
*/
|
||
|
|
|
||
|
|
interface UseCanvasGesturesConfig {
|
||
|
|
/** Ref to the viewport DOM element */
|
||
|
|
ref: React.RefObject<HTMLDivElement | null>;
|
||
|
|
minZoom?: number;
|
||
|
|
maxZoom?: number;
|
||
|
|
zoomSensitivity?: number;
|
||
|
|
enablePan?: boolean;
|
||
|
|
enableZoom?: boolean;
|
||
|
|
/** Pre-built mapping index (shared from GestureProvider). Overrides contexts/palmRejection. */
|
||
|
|
mappingIndex?: MappingIndex;
|
||
|
|
/** Additional mapping contexts to push (ignored if mappingIndex is provided) */
|
||
|
|
contexts?: MappingContext[];
|
||
|
|
/** Whether palm rejection is enabled (ignored if mappingIndex is provided) */
|
||
|
|
palmRejection?: boolean;
|
||
|
|
/** Called for every resolved gesture */
|
||
|
|
onAction?: BivariantCallback<[InputEvent, ResolvedAction]>;
|
||
|
|
/** Snapshot of currently held keyboard keys */
|
||
|
|
heldKeys?: HeldKeysState;
|
||
|
|
}
|
||
|
|
declare function useCanvasGestures({ ref, minZoom, maxZoom, zoomSensitivity, enablePan, enableZoom, mappingIndex: externalIndex, contexts: extraContexts, palmRejection, onAction, heldKeys, }: UseCanvasGesturesConfig): void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useNodeGestures — Node-level gesture recognition hook
|
||
|
|
*
|
||
|
|
* Replaces the inline click counting, touch long-press timers, and
|
||
|
|
* context menu handling in Node.tsx. Produces gesture events that
|
||
|
|
* route through the v2 pipeline (resolve → dispatch).
|
||
|
|
*
|
||
|
|
* Drag mechanics stay in useNodeDrag — this hook handles:
|
||
|
|
* - tap / double-tap / triple-tap (via TimedStateRunner)
|
||
|
|
* - right-click (tap with button=2)
|
||
|
|
* - long-press (finger/pencil only)
|
||
|
|
* - hover enter/leave
|
||
|
|
*
|
||
|
|
* Returns event handler props to spread on the node DOM element.
|
||
|
|
*/
|
||
|
|
|
||
|
|
interface UseNodeGesturesConfig {
|
||
|
|
nodeId: string;
|
||
|
|
/** Pre-built mapping index (shared from useGestureSystem) */
|
||
|
|
mappingIndex: MappingIndex;
|
||
|
|
/** Called for every resolved gesture */
|
||
|
|
onAction?: BivariantCallback<[InputEvent, ResolvedAction]>;
|
||
|
|
/** Snapshot of currently held keyboard keys */
|
||
|
|
heldKeys?: HeldKeysState;
|
||
|
|
}
|
||
|
|
interface NodeGestureHandlers {
|
||
|
|
onPointerDown: (e: React.PointerEvent) => void;
|
||
|
|
onPointerUp: (e: React.PointerEvent) => void;
|
||
|
|
onPointerCancel: (e: React.PointerEvent) => void;
|
||
|
|
onContextMenu: (e: React.MouseEvent) => void;
|
||
|
|
}
|
||
|
|
declare function useNodeGestures({ nodeId, mappingIndex, onAction, heldKeys, }: UseNodeGesturesConfig): NodeGestureHandlers;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useInputSystem — Consumer hook for the shared input pipeline
|
||
|
|
*
|
||
|
|
* Provides a stable API for:
|
||
|
|
* - Pushing / removing MappingContexts at runtime
|
||
|
|
* - Reading the current mapping index
|
||
|
|
* - Configuring palm rejection
|
||
|
|
*
|
||
|
|
* All context state is managed via useState.
|
||
|
|
* Context sync belongs in hooks (Design Decision 5), not effectful atoms.
|
||
|
|
*/
|
||
|
|
|
||
|
|
interface InputSystemConfig {
|
||
|
|
/** Additional static contexts (merged once) */
|
||
|
|
contexts?: MappingContext[];
|
||
|
|
/** Enable palm rejection context (default: true) */
|
||
|
|
palmRejection?: boolean;
|
||
|
|
}
|
||
|
|
interface InputSystemAPI {
|
||
|
|
/** Pre-built mapping index, ready for resolve() calls */
|
||
|
|
mappingIndex: MappingIndex;
|
||
|
|
/** Push a mapping context onto the stack */
|
||
|
|
pushContext: (ctx: MappingContext) => void;
|
||
|
|
/** Remove a mapping context by ID */
|
||
|
|
removeContext: (id: string) => void;
|
||
|
|
/** Enable/disable a context by ID */
|
||
|
|
setContextEnabled: (id: string, enabled: boolean) => void;
|
||
|
|
/** Whether palm rejection is active */
|
||
|
|
palmRejection: boolean;
|
||
|
|
/** Toggle palm rejection */
|
||
|
|
setPalmRejection: (enabled: boolean) => void;
|
||
|
|
/** Snapshot of currently held keyboard keys */
|
||
|
|
heldKeys: HeldKeysState;
|
||
|
|
/** Replace held key state */
|
||
|
|
setHeldKeys: (next: HeldKeysState) => void;
|
||
|
|
/** Clear all held keys */
|
||
|
|
clearHeldKeys: () => void;
|
||
|
|
}
|
||
|
|
declare function useInputSystem(config?: InputSystemConfig): InputSystemAPI;
|
||
|
|
type GestureSystemConfig = InputSystemConfig;
|
||
|
|
type GestureSystemAPI = InputSystemAPI;
|
||
|
|
declare const useGestureSystem: typeof useInputSystem;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useGuardContext — Guard context hook
|
||
|
|
*
|
||
|
|
* Reads all atoms needed for the gesture guard context and returns
|
||
|
|
* a ref that is updated every render. The ref is stable and safe
|
||
|
|
* to read inside useGesture callbacks without stale closure issues.
|
||
|
|
*/
|
||
|
|
|
||
|
|
declare function useGuardContext(heldKeys?: HeldKeysState): React.RefObject<GuardContext>;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useInertia — Pan & zoom inertia management
|
||
|
|
*
|
||
|
|
* Encapsulates the rAF animation loops, VelocitySamplers, and
|
||
|
|
* pinch tracking refs used by useCanvasGestures. Returns stable
|
||
|
|
* functions for starting/cancelling inertia and recording samples.
|
||
|
|
*/
|
||
|
|
|
||
|
|
interface InertiaAPI {
|
||
|
|
/** Start pan inertia from a velocity vector */
|
||
|
|
startPanInertia: (velocity: Vec2, setPan: (fn: (prev: Vec2) => Vec2) => void) => void;
|
||
|
|
/** Start zoom inertia from a per-frame velocity */
|
||
|
|
startZoomInertia: (velocity: number, origin: Vec2, currentZoom: number, minZoom: number, maxZoom: number, setZoom: (fn: (prev: number) => number) => void, setPan: (fn: (prev: Vec2) => Vec2) => void) => void;
|
||
|
|
/** Cancel all running inertia animations */
|
||
|
|
cancelAll: () => void;
|
||
|
|
/** Cancel only pan inertia */
|
||
|
|
cancelPan: () => void;
|
||
|
|
/** Cancel only zoom inertia */
|
||
|
|
cancelZoom: () => void;
|
||
|
|
/** Pan velocity sampler */
|
||
|
|
panSampler: VelocitySampler;
|
||
|
|
/** Zoom velocity sampler */
|
||
|
|
zoomSampler: VelocitySampler;
|
||
|
|
/** Pinch origin tracking ref */
|
||
|
|
pinchPrevOrigin: React.RefObject<Vec2 | null>;
|
||
|
|
/** Last pinch zoom state for velocity calculation */
|
||
|
|
lastPinchZoom: React.RefObject<{
|
||
|
|
zoom: number;
|
||
|
|
t: number;
|
||
|
|
} | null>;
|
||
|
|
}
|
||
|
|
declare function snapZoom(z: number): number;
|
||
|
|
declare function useInertia(): InertiaAPI;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useWheelZoom — Wheel zoom handler extracted from useCanvasGestures
|
||
|
|
*
|
||
|
|
* Pure function returning an `onWheel` callback for @use-gesture/react.
|
||
|
|
* Handles:
|
||
|
|
* - Zoom calculation with configurable sensitivity
|
||
|
|
* - Snap-to-100% via snapZoom
|
||
|
|
* - Min/max bounds clamping
|
||
|
|
* - Scroll passthrough for scrollable content inside selected nodes
|
||
|
|
*
|
||
|
|
* @since 1.3.0
|
||
|
|
*/
|
||
|
|
interface WheelZoomConfig {
|
||
|
|
/** Ref to the viewport DOM element */
|
||
|
|
ref: React.RefObject<HTMLDivElement | null>;
|
||
|
|
minZoom: number;
|
||
|
|
maxZoom: number;
|
||
|
|
zoomSensitivity: number;
|
||
|
|
enableZoom: boolean;
|
||
|
|
/** Current zoom value */
|
||
|
|
zoom: number;
|
||
|
|
/** Current pan value */
|
||
|
|
pan: {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
};
|
||
|
|
/** Currently selected node IDs */
|
||
|
|
selectedNodeIds: Set<string>;
|
||
|
|
/** Zoom setter */
|
||
|
|
setZoom: (zoom: number) => void;
|
||
|
|
/** Pan setter */
|
||
|
|
setPan: (pan: {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
}) => void;
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Creates an onWheel handler for use with @use-gesture/react.
|
||
|
|
*
|
||
|
|
* Extracted from useCanvasGestures to enable independent testing
|
||
|
|
* and reuse in custom gesture compositions.
|
||
|
|
*/
|
||
|
|
declare function createWheelHandler(config: WheelZoomConfig): ({ event, pinching, delta: [, dy], memo }: {
|
||
|
|
event: WheelEvent;
|
||
|
|
pinching?: boolean;
|
||
|
|
delta: [number, number];
|
||
|
|
memo?: unknown;
|
||
|
|
}) => void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* usePinchZoom — Pinch zoom handlers extracted from useCanvasGestures
|
||
|
|
*
|
||
|
|
* Pure function returning `onPinchStart`, `onPinch`, `onPinchEnd` callbacks
|
||
|
|
* for @use-gesture/react. Handles:
|
||
|
|
* - Simultaneous pan during pinch (finger midpoint tracking)
|
||
|
|
* - Zoom velocity sampling for inertia
|
||
|
|
* - Snap-to-100% via snapZoom
|
||
|
|
* - Inertia trigger on pinch end
|
||
|
|
*
|
||
|
|
* @since 1.3.0
|
||
|
|
*/
|
||
|
|
|
||
|
|
interface PinchZoomConfig {
|
||
|
|
/** Ref to the viewport DOM element */
|
||
|
|
ref: React.RefObject<HTMLDivElement | null>;
|
||
|
|
minZoom: number;
|
||
|
|
maxZoom: number;
|
||
|
|
enableZoom: boolean;
|
||
|
|
/** Whether the user prefers reduced motion */
|
||
|
|
reducedMotion: boolean;
|
||
|
|
/** Current zoom value */
|
||
|
|
zoom: number;
|
||
|
|
/** Current pan value */
|
||
|
|
pan: {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
};
|
||
|
|
/** Zoom setter (accepts value or updater function) */
|
||
|
|
setZoom: ((zoom: number) => void) & ((fn: (prev: number) => number) => void);
|
||
|
|
/** Pan setter (accepts value or updater function) */
|
||
|
|
setPan: ((pan: {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
}) => void) & ((fn: (prev: {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
}) => {
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
}) => void);
|
||
|
|
/** Inertia state */
|
||
|
|
inertia: {
|
||
|
|
cancelAll: () => void;
|
||
|
|
pinchPrevOrigin: React.MutableRefObject<{
|
||
|
|
x: number;
|
||
|
|
y: number;
|
||
|
|
} | null>;
|
||
|
|
zoomSampler: VelocitySampler;
|
||
|
|
lastPinchZoom: React.MutableRefObject<{
|
||
|
|
zoom: number;
|
||
|
|
t: number;
|
||
|
|
} | null>;
|
||
|
|
startZoomInertia: (velocity: number, origin: Vec2, currentZoom: number, minZoom: number, maxZoom: number, setZoom: (fn: (prev: number) => number) => void, setPan: (fn: (prev: Vec2) => Vec2) => void) => void;
|
||
|
|
};
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
* Creates onPinchStart, onPinch, onPinchEnd handlers for use with @use-gesture/react.
|
||
|
|
*
|
||
|
|
* Extracted from useCanvasGestures to enable independent testing
|
||
|
|
* and reuse in custom gesture compositions.
|
||
|
|
*/
|
||
|
|
declare function createPinchHandlers(config: PinchZoomConfig): {
|
||
|
|
onPinchStart: ({ origin: [ox, oy] }: {
|
||
|
|
origin: [number, number];
|
||
|
|
}) => boolean;
|
||
|
|
onPinch: ({ offset: [d], origin: [ox, oy], event, memo }: {
|
||
|
|
offset: [number, number];
|
||
|
|
origin: [number, number];
|
||
|
|
event: Event;
|
||
|
|
memo?: unknown;
|
||
|
|
}) => void;
|
||
|
|
onPinchEnd: () => void;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useInputModeGestureContext — Syncs input mode → mapping context
|
||
|
|
*
|
||
|
|
* When the interaction store's inputModeAtom changes, this hook
|
||
|
|
* pushes/removes the corresponding MappingContext from the gesture system.
|
||
|
|
*
|
||
|
|
* This follows Design Decision 5: context sync belongs in hooks.
|
||
|
|
*/
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Sync the current input mode to a gesture mapping context.
|
||
|
|
* Call this once at the Canvas level, passing the gesture system API.
|
||
|
|
*/
|
||
|
|
declare function useInputModeGestureContext(inputSystem: InputSystemAPI): void;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* useRegisterInputActions — Action registration hook
|
||
|
|
*
|
||
|
|
* Registers all built-in input actions (selection, clipboard, navigation,
|
||
|
|
* commands, etc.) into the gesture dispatcher. Business logic lives in
|
||
|
|
* ./input-action-helpers.ts for testability.
|
||
|
|
*/
|
||
|
|
declare function useRegisterInputActions(): void;
|
||
|
|
|
||
|
|
interface InputConfig {
|
||
|
|
contexts?: MappingContext[];
|
||
|
|
palmRejection?: boolean;
|
||
|
|
debug?: boolean;
|
||
|
|
}
|
||
|
|
type GestureConfig = InputConfig;
|
||
|
|
interface InputContextValue {
|
||
|
|
system: InputSystemAPI;
|
||
|
|
onAction?: BivariantCallback<[InputEvent, ResolvedAction]>;
|
||
|
|
registerCanvasRoot: (node: HTMLDivElement | null) => void;
|
||
|
|
}
|
||
|
|
interface InputProviderProps {
|
||
|
|
children: React$1.ReactNode;
|
||
|
|
gestureConfig?: InputConfig;
|
||
|
|
onAction?: BivariantCallback<[InputEvent, ResolvedAction]>;
|
||
|
|
}
|
||
|
|
type GestureProviderProps = InputProviderProps;
|
||
|
|
declare function InputProvider({ children, gestureConfig, onAction }: InputProviderProps): react_jsx_runtime.JSX.Element;
|
||
|
|
declare function useInputContext(): InputContextValue;
|
||
|
|
declare const GestureProvider: typeof InputProvider;
|
||
|
|
declare const useGestureContext: typeof useInputContext;
|
||
|
|
|
||
|
|
export { ACTIVE_INTERACTION_CONTEXT, type ActionHandler, type Binding, type Button, type ContextIndex, DEFAULT_CONTEXT, type Direction, type GestureConfig, type GestureEvent, type GesturePattern, GestureProvider, type GestureProviderProps, type GestureSubject, type GestureSystemAPI, type GestureSystemConfig, type GestureType, type GuardContext, type HeldKeysPattern, type HeldKeysState, IDLE, INPUT_MODE_CONTEXTS, type InertiaAPI, type InputConfig, type InputEvent, type InputMode, type InputPattern, type InputPhase, InputProvider, type InputProviderProps, type InputSource, type InputSystemAPI, type InputSystemConfig, KEYBOARD_MANIPULATE_CONTEXT, KEYBOARD_NAVIGATE_CONTEXT, type KeyInputEvent, type KeyInputPhase, type KeyboardInteractionMode, LONG_PRESS_TIMER, type MappingContext, type MappingIndex, type Modifiers, NO_HELD_KEYS, NO_MODIFIERS, type NodeGestureHandlers, PALM_REJECTION_CONTEXT, PICK_NODES_CONTEXT, PICK_NODE_CONTEXT, PICK_POINT_CONTEXT, PanInertia, type PhaseHandler, type PinchZoomConfig, type PointerGestureEvent, type PointerGesturePhase, type PointerGestureType, type ResolvedAction, SEARCH_CONTEXT, SETTLE_TIMER, type SubjectKind, TimedStateRunner, type UseCanvasGesturesConfig, type UseNodeGesturesConfig, type Vec2, VelocitySampler, type WheelZoomConfig, ZoomInertia, activateFocusedNode, buildMappingIndex, cancelActiveInteraction, clearHandlers, createPinchHandlers, createWheelHandler, cutSelection, cycleFocus, deleteSelection, dispatch, escapeInput, extractModifiers, findNearestNode, getCurrentSubject, getHandler, indexContext, isKeyInputEvent, isPointerGestureEvent, navigateFocus, normalizePointer, nudgeSelection, registerAction, resolve, snapZoom, specificity, transition, unregisterAction, useCanvasGestures, useGestureContext, useGestureSystem, useGuardContext, useInertia, useInputContext, useInputModeGestureContext, useInputSystem, useNodeGestures, useRegisterInputActions };
|