Gestures
Description
Fluent gesture recognition extensions for any IComponent
GestureExtensions adds tap, double-tap, long-press, pan, pinch, and rotate recognition to any IComponent through fluent extension methods. A single GestureRecognizer is attached per element and shared across all gesture handlers registered on that component, so the DOM listener overhead is fixed regardless of how many gesture types you register.
Recognition is built on the unified Pointer Events API (pointerdown / pointermove / pointerup with setPointerCapture), which covers mouse, touch, and stylus input without separate touch-event handling.
Built-in thresholds:
- Tap move tolerance — 10 px. Movement within this radius does not disqualify a tap.
- Double-tap window — 300 ms between two taps.
- Long-press threshold — 500 ms of stationary contact.
When a double-tap handler is registered alongside a single-tap handler, single taps are delayed by the double-tap window to allow a follow-up tap to upgrade them.
Pan, pinch, and rotate handlers set touch-action: none on the element to prevent the browser from claiming touch events for native scrolling or zooming.
All handlers receive a GestureState snapshot. The same instance is reused per recognizer and refreshed before each callback — do not hold a reference to it across events.
GestureState fields
| Field | Type | Description |
|---|---|---|
Component |
IComponent |
The component the gesture was recognised on. |
Phase |
GesturePhase |
Start, Move, or End. Always End for tap and long-press. |
X / Y |
double |
Current pointer (or two-pointer centroid) position in client coordinates. |
DeltaX / DeltaY |
double |
Movement since the previous event. Pan only; zero for pinch/rotate. |
OffsetX / OffsetY |
double |
Cumulative movement since the gesture started. |
Scale |
double |
Cumulative scale factor since pinch started (1 = no change). |
ScaleDelta |
double |
Scale factor change since the previous pinch event. |
Rotation |
double |
Cumulative rotation in degrees since rotate started. |
RotationDelta |
double |
Rotation change in degrees since the previous rotate event. |
PointerCount |
int |
Number of pointers currently down on the element. |
Event |
Event |
The underlying DOM pointer event, if any. null for long-press. |
Usage
// Tap
someComponent
.OnTapped(state => Console.WriteLine($"tapped at {state.X}, {state.Y}"))
.OnDoubleTapped(() => Console.WriteLine("double-tap"));
// Long press
someComponent.OnLongPress(state => ShowContextMenu(state.X, state.Y));
// Pan — move a draggable element
var offsetX = 0.0;
var offsetY = 0.0;
draggable.OnPan(state =>
{
if (state.Phase == GesturePhase.Start)
{
offsetX = 0;
offsetY = 0;
}
offsetX = state.OffsetX;
offsetY = state.OffsetY;
UpdatePosition(offsetX, offsetY);
});
// Pinch — zoom a canvas
canvas.OnPinch(state =>
{
ApplyScale(state.Scale);
});
// Rotate — spin an element
rotateable.OnRotate(state =>
{
ApplyRotation(state.Rotation);
});
API reference
public enum GesturePhaseIdentifies the phase of a continuous gesture (pan / pinch / rotate).
- Namespace
- Tesserae
Values
| Name | Description |
|---|---|
| Start | The gesture has just started (movement crossed the threshold, or a second finger landed). |
| Move | The gesture is in progress. |
| End | The gesture has ended (the last relevant pointer was lifted or cancelled). |
StartThe gesture has just started (movement crossed the threshold, or a second finger landed).
public sealed class GestureStateImmutable-ish snapshot of a recognised gesture, handed to gesture callbacks. A single instance is reused per recogniser and its fields are refreshed before every callback, so do not hold a reference across events.
- Namespace
- Tesserae
Properties
| Name | Description |
|---|---|
| Component | The component the gesture was recognised on. |
| Phase | The current phase of a continuous gesture (always End for taps / long-press). |
| X | Current pointer (or two-pointer centroid) X position in client coordinates. |
| Y | Current pointer (or two-pointer centroid) Y position in client coordinates. |
| DeltaX | Horizontal movement since the previous event of this gesture. |
| DeltaY | Vertical movement since the previous event of this gesture. |
| OffsetX | Cumulative horizontal movement since the gesture started. |
| OffsetY | Cumulative vertical movement since the gesture started. |
| Scale | Cumulative scale factor since the pinch started (1 = no change). |
| ScaleDelta | Scale factor change since the previous pinch event (1 = no change). |
| Rotation | Cumulative rotation in degrees since the rotate gesture started. |
| RotationDelta | Rotation change in degrees since the previous rotate event. |
| PointerCount | Number of pointers currently down on the element. |
| Event | The underlying DOM pointer event that produced this state, if any. |
public IComponent Component { get; internal set; }The component the gesture was recognised on.
public GesturePhase Phase { get; internal set; }The current phase of a continuous gesture (always End for taps / long-press).
public double X { get; internal set; }Current pointer (or two-pointer centroid) X position in client coordinates.
public double Y { get; internal set; }Current pointer (or two-pointer centroid) Y position in client coordinates.
public double DeltaX { get; internal set; }Horizontal movement since the previous event of this gesture.
public double DeltaY { get; internal set; }Vertical movement since the previous event of this gesture.
public double OffsetX { get; internal set; }Cumulative horizontal movement since the gesture started.
public double OffsetY { get; internal set; }Cumulative vertical movement since the gesture started.
public double Scale { get; internal set; }Cumulative scale factor since the pinch started (1 = no change).
public double ScaleDelta { get; internal set; }Scale factor change since the previous pinch event (1 = no change).
public double Rotation { get; internal set; }Cumulative rotation in degrees since the rotate gesture started.
public double RotationDelta { get; internal set; }Rotation change in degrees since the previous rotate event.
public int PointerCount { get; internal set; }Number of pointers currently down on the element.
public sealed class GestureRecognizerHigher-level pointer/touch gesture recognition layered on top of the unified Pointer Events API (pointerdown/pointermove/pointerup + setPointerCapture). A single recogniser is attached per element and shared by every gesture handler registered through GestureExtensions.
- Namespace
- Tesserae
Methods
| Name | Description |
|---|---|
| For | Returns the recogniser attached to the component's element, creating and caching one on the element on first use so multiple gesture handlers share a single set of DOM listeners. |
| OnTapped | Registers a tap (quick press-and-release without movement) handler. |
| OnDoubleTapped | Registers a double-tap handler. When present, single taps are delayed to disambiguate. |
| OnLongPress | Registers a long-press handler (stationary press held past the long-press threshold). |
| OnPan | Registers a pan handler. Enables touch-action: none so touch panning isn't hijacked by scrolling. |
| OnPinch | Registers a pinch (two-finger scale) handler. Enables touch-action: none. |
| OnRotate | Registers a rotate (two-finger angle) handler. Enables touch-action: none. |
public static GestureRecognizer For(IComponent component)Returns the recogniser attached to the component's element, creating and caching one on the element on first use so multiple gesture handlers share a single set of DOM listeners.
public GestureRecognizer OnTapped(Action<GestureState> handler)Registers a tap (quick press-and-release without movement) handler.
public GestureRecognizer OnDoubleTapped(Action<GestureState> handler)Registers a double-tap handler. When present, single taps are delayed to disambiguate.
public GestureRecognizer OnLongPress(Action<GestureState> handler)Registers a long-press handler (stationary press held past the long-press threshold).
public GestureRecognizer OnPan(Action<GestureState> handler)Registers a pan handler. Enables touch-action: none so touch panning isn't hijacked by scrolling.
public GestureRecognizer OnPinch(Action<GestureState> handler)Registers a pinch (two-finger scale) handler. Enables touch-action: none.
public static class GestureExtensionsFluent gesture extensions on IComponent. These layer tap, double-tap, long-press, pan, pinch and rotate recognition on top of the native pointer events already exposed by ComponentBase{T, THTML}. All handlers receive a GestureState snapshot; thresholds (tap tolerance, double-tap timing, long-press duration) are sensible defaults shared by the per-element GestureRecognizer.
- Namespace
- Tesserae
Methods
| Name | Description |
|---|---|
| OnTapped | Recognises a tap (quick press-and-release without movement). |
| OnDoubleTapped | Recognises a double-tap. Registering this delays single taps to disambiguate them. |
| OnLongPress | Recognises a long-press (stationary press held past the long-press threshold). |
| OnPan<T> | Recognises a pan / drag. The handler receives per-event deltas (DeltaX/ DeltaY) and the cumulative offset since the gesture started (OffsetX/OffsetY). |
| OnPinch<T> | Recognises a two-finger pinch. The handler receives the cumulative Scale and the per-event ScaleDelta. |
| OnRotate<T> | Recognises a two-finger rotation. The handler receives the cumulative Rotation and the per-event RotationDelta in degrees. |
| Overload | |
|---|---|
| OnTapped<T>(T, Action<GestureState>) | Recognises a tap (quick press-and-release without movement). |
| OnTapped<T>(T, Action) | Recognises a tap, invoking a parameterless handler. |
| Overload | |
|---|---|
| OnDoubleTapped<T>(T, Action<GestureState>) | Recognises a double-tap. Registering this delays single taps to disambiguate them. |
| OnDoubleTapped<T>(T, Action) | Recognises a double-tap, invoking a parameterless handler. |
| Overload | |
|---|---|
| OnLongPress<T>(T, Action<GestureState>) | Recognises a long-press (stationary press held past the long-press threshold). |
| OnLongPress<T>(T, Action) | Recognises a long-press, invoking a parameterless handler. |
public static T OnPan<T>(this T component, Action<GestureState> handler) where T : IComponentRecognises a pan / drag. The handler receives per-event deltas (DeltaX/ DeltaY) and the cumulative offset since the gesture started (OffsetX/OffsetY).
public static T OnPinch<T>(this T component, Action<GestureState> handler) where T : IComponentRecognises a two-finger pinch. The handler receives the cumulative Scale and the per-event ScaleDelta.