SwipeController
Reports a left, right, up or down swipe on release.
Reach for it for a carousel or pager.
Import
import { SwipeController, createSwipeController } from '@ecopages/radiant-ui/controllers';Try it
Press on the box and either move at least 48 px sideways or flick it at least 16 px faster than 0.5 px per ms, then release. A drag that is not at least twice as far sideways as it is up or down is ignored. The callback reports the direction.
No swipe yet
<div data-example="swipe">
<div data-box>Swipe me</div>
<p data-status>No swipe yet</p>
</div>import { SwipeController } from '@ecopages/radiant-ui/controllers';
export function mount(root: HTMLElement): () => void {
const box = root.querySelector<HTMLElement>('[data-box]')!;
const status = root.querySelector('[data-status]')!;
const swipe = new SwipeController({
getTarget: () => box,
minVelocity: 0.5,
dominance: 2,
onSwipe: (direction) => (status.textContent = `Swiped ${direction}`),
});
swipe.attach();
return () => swipe.destroy();
}mount runs once for each example element on the page, and the function it returns undoes it; see how the examples run.
Config
| Option | Description |
|---|---|
getTarget | Resolved on every attach(). null listens to nothing. |
axis | Which travel counts: x (default), y or both. |
threshold | Minimum travel in px along the swipe axis. Default 48. |
minVelocity | Speed in px per ms along the axis that lets a shorter travel count, a flick. The travel must still reach 16 px (MIN_FLICK_TRAVEL_PX). Default: none, only threshold decides. |
dominance | How many times larger the travel along the axis must be than across it. Default 1, which is simply larger. |
getHandle | Limits gestures to this element's subtree, resolved on every press; use it with the host as getTarget when the surface is a child that can be replaced. |
exclude | A gesture that starts on a target this returns true for is ignored, such as a button inside the surface. |
onSwipe | Called on the pointer-up that ends a swipe, with the direction and the event. |
Lifecycle
attach() listens for a press on the target; release and cancel are then listened for on document, so a release outside the element still ends the gesture. It reports once, on release, and does not follow the pointer; a surface that moves with the pointer needs PointerDragController. A cancel or destroy() drops a gesture in progress, and destroy() removes the listeners.
With a host, createSwipeController(host, config) does the same on connect and disconnect; see bindController.
Protected hooks
Extend the class and override these to change how it decides. A component never extends a controller; a subclass is registered with bindController.
| Hook | Description |
|---|---|
resolveDirection(dx, dy, elapsedMs) | Decides which swipe, if any, a gesture was. Runs on the pointer-up with the travel from the press point and the milliseconds since the press, taken from the timeStamp of the two pointer events. Return null for no swipe. The default is resolveSwipeDirection with the configured axis, threshold, minVelocity and dominance. |