DragRecognizer

The pointer's drags and pans. drag is a Stream of Drag.Samples as a pointer drags target, kept to its axis, and refused when another element holds that axis; pan gives the same samples with a session's start at each down, moves nothing, and stops no drag. watchDrag and watchPan call you with each sample inside its pointer event's dispatch while a Scope is open, with no fiber of their own: a binding's drags run on these. They're apart from Recognizer's gestures, so an app that never drags ships none of this.

import * as DragRecognizer from "@wardic/core/DragRecognizer"

yield* DragRecognizer.watchDrag(card, { axis: "x" }, {
  on: (sample) => {
    if (sample.phase === "end") fling(sample.velocity.x)
    else moveTo(sample.offset.x)
  },
})

Interfaces

AdoptableDrag

An adoptable drag's watch, a target given drag controls: it can end its gesture from outside its pointer, as Motion's drag controls' stop and cancel do. Each tells its "end" inside the call, and does nothing when no gesture has started.

Extends

Properties

cancel
readonly cancel: () => void;

Ends the gesture where it is: an "end" with no velocity, marked cancelled.

Returns

void

stop
readonly stop: () => void;

Ends the gesture as its pointer's release would: an "end" at its last point, with its moves' velocity.

Returns

void


DragOptions

drag's and watchDrag's options.

Properties

adoptable?
readonly adoptable?: boolean;

true: the target was given drag controls, so the drag reads the pointer feed that also delivers the downs they hand it (InputSource.adoptablePointerOf), and its WatchedDrag ends a gesture from outside. Default false: the plain feed, and a stop and cancel that do nothing.

axis?
readonly axis?: Axis | LazyArg<Axis>;

The axes the drag moves on, and claims: "xy" by default. A one-axis drag's samples have their other axis's offset, delta and velocity at 0; point and phase are left as they are. A function is read at each gesture's start and holds to its end, as a Reorder item's axis is decided per gesture.

claim?
readonly claim?: boolean;

false: the drag claims no axis and is never refused, as Motion's dragPropagation. It still counts as an active drag, so no hover or press starts while it's on. Default true.

listen?
readonly listen?: boolean;

false: a press on the target starts no gesture, only a down handed to it does, as Motion's dragListener={false} with drag controls. Default true: both do.

lock?
readonly lock?: boolean;

A direction lock, as Motion's dragDirectionLock: the gesture starts only once it's moved 10 px on one axis, y first, as Motion's, and moves on that axis alone, so a parent that drags the other axis keeps its gesture. A lock on an axis the drag doesn't move on, axis: "y" swiped sideways, refuses it. Default false.

mapPoint?
readonly mapPoint?: LazyArg<Option<PointMap>>;

Where each pointer point is for the gesture, as Motion's transformPagePoint: read at each down, and applied to all that gesture's points, its down's and each move's. None, or no function given, leaves them as they are. It's handed the point on the screen and gives one; the scroll a hold counts in is added back after. A caller gives back the same Some while its mapping is the same, so a down allocates nothing.

threshold?
readonly threshold?: (down) => Option<number>;

How far, in px, a gesture from down moves before it starts, read at the down, as Motion's distanceThreshold: none, or no function given, is 3. A direction lock still waits for its 10 px on one axis.

Parameters
down

PointerLikeEvent

Returns

Option<number>


PanOptions

watchPan's options.

Properties

mapPoint?
readonly mapPoint?: LazyArg<Option<PointMap>>;

Where each pointer point is for the gesture, as DragOptions' mapPoint.


PanSample

A pan's sample: a drag's, or its session's start, "session", as Motion's onPanSessionStart: at the primary pointer's down on the target, at its point, with no offset, delta or velocity.

Extends

Properties

axis
readonly axis: Axis;

The axes it moves on, read at its start: its drag's axis, or a direction-locked drag's lock. A pan's are both.

Inherited from

Sample.axis

cancelled?
readonly cancelled?: boolean;

true on an "end" its watch's cancel gave: the drag ended where it is, which a binding releases with no fling and tells no app. Absent on every other sample.

Inherited from

Sample.cancelled

delta
readonly delta: Point;

How far it's moved since the sample before.

Inherited from

Sample.delta

offset
readonly offset: Point;

How far it's moved since the down that started the drag: point less the down's.

Inherited from

Sample.offset

phase
readonly phase: "start" | "end" | "move" | "session";

"session" at the down, then a drag's: "start" past the threshold, "move", "end".

point
readonly point: Point;

Where the pointer is, in the Environment's coordinates.

Inherited from

Sample.point

raw?
readonly raw?: unknown;

The platform's own event behind it, which core never reads: a binding hands it to an app's callback.

Inherited from

Sample.raw

scroll
readonly scroll: Point;

The scroll counted into point since the down: point less scroll is where the pointer is on the screen.

Inherited from

Sample.scroll

timeStamp
readonly timeStamp: number;

The time, in ms, of the event behind it: for a move a scroll made, the scroll's.

Inherited from

Sample.timeStamp

velocity
readonly velocity: Point;

The pointer's velocity on each axis, in units a second, over the drag's last 100 ms, as Motion's. The "end" sample counts the release point, so a pause before letting go slows it, down to none.

Inherited from

Sample.velocity


WatchedDrag

A drag's watch, as one with no drag controls gives it back: its Scope ends it, and nothing else does.

Extended by

Type Aliases

PointMap

type PointMap = (point) => Point;

A point mapped, as Motion's transformPagePoint: the Environment's coordinates in, the gesture's out.

Parameters

point

Point

Returns

Point

Variables

watchDrag

const watchDrag: {
  (target, options, handlers): Effect<AdoptableDrag, never, Scope | InputSource>;
  (target, options, handlers): Effect<WatchedDrag, never, Scope | InputSource>;
  (target, options, handlers): Effect<AdoptableDrag, never, Scope | InputSource>;
};

Watches drags on target while the Scope is open: handlers.on hears each of a gesture's samples, kept to its axis, inside its pointer event's dispatch.

  • It starts once the pointer has moved threshold px, 3 by default, from its down.
  • Its axis is claimed at its "start", before on hears it, and counts as an active drag, so no hover or press starts elsewhere while it's on. Every watch on one target shares the claim. When another element holds an axis it needs, the gesture is refused: it tells nothing until its end, as a tap tells nothing, and doesn't retry. Of nested drags, the innermost claims first. With claim: false it only counts.
  • Its claim is given back at its "end", before on hears it, or when the Scope closes mid-drag, so a throw from on can't keep it.
  • Velocity is the pointer's on each axis over the last 100 ms, read from the events' times.

A down handed to the target starts a gesture as its own press does; with listen: false, only those do. An adoptable watch gives back an AdoptableDrag, which ends a gesture from outside; a plain one, a WatchedDrag. With adoptable known only when it runs, an AdoptableDrag whose ends do nothing unless it is.

Call Signature

(
   target, 
   options, 
   handlers
): Effect<AdoptableDrag, never, Scope | InputSource>;
Parameters
target

unknown

options

DragOptions & object

handlers

Handlers<Sample>

Returns

Effect<AdoptableDrag, never, Scope | InputSource>

Call Signature

(
   target, 
   options, 
   handlers
): Effect<WatchedDrag, never, Scope | InputSource>;
Parameters
target

unknown

options

DragOptions & object

handlers

Handlers<Sample>

Returns

Effect<WatchedDrag, never, Scope | InputSource>

Call Signature

(
   target, 
   options, 
   handlers
): Effect<AdoptableDrag, never, Scope | InputSource>;
Parameters
target

unknown

options

DragOptions

handlers

Handlers<Sample>

Returns

Effect<AdoptableDrag, never, Scope | InputSource>

Example

const watched = yield* DragRecognizer.watchDrag(slider, { axis: "x", adoptable: true }, { on: move })
watched.cancel() // ends the gesture where it is

watchPan

const watchPan: (target, handlers, options?) => Effect.Effect<void, never, Scope.Scope | InputSource>;

Parameters

target

unknown

handlers

Handlers<PanSample>

options?

PanOptions

Returns

Effect.Effect<void, never, Scope.Scope | InputSource>

Functions

drag()

function drag(target, options?): Stream<Sample, never, InputSource>;

A drag on target, as a Stream of samples kept to its axis, with watchDrag's rules: each sample arrives inside its pointer event's dispatch, and the Stream ends when the input does, as a test's script does.

Parameters

target

unknown

options?

DragOptions = {}

Returns

Stream<Sample, never, InputSource>

Example

DragRecognizer.drag(card, { axis: "x" }).pipe(Drag.withinBounds({ x: { min: 0, max: 200 } }))

pan()

function pan(target): Stream<PanSample, never, InputSource>;

A pan on target, as Motion's pan gesture: its session's start at the primary pointer's down, then a drag's "start" past its threshold, a "move" at each move, and an "end" at the release, a cancel or a lost release. It moves nothing.

A pan claims no axis, so it never stops a drag, nested or not, and no drag stops it. Once started it counts as an active drag until its end, so a press it took over ends as neither a tap nor a cancel, and no hover starts meanwhile: that's Wardic's, not Motion's, whose swipe let go over a tappable element taps it too.

Parameters

target

unknown

Returns

Stream<PanSample, never, InputSource>