npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kestack/use-gesture

v0.0.2

Published

Touch gestures: a platform-free core that reads every finger of a touch from any touch source. Its web side is in @kestack/web-platform's input.

Readme

@kestack/use-gesture

Touch gestures: a platform-free core that reads every finger of a touch from any touch source. Its web side is in @kestack/web-platform's input.

Big picture

An app that wants a sidebar you swipe open, a list you pull to refresh, or a row you swipe for actions has to take touches away from the platform without breaking scrolling, clicks, or the other gestures on the same screen. This package does that part once. A Gesture Provider follows every finger, and Gesture Zones mark the areas where the app owns touch.

The package root is the core, and it is platform-free: no DOM, no React, no Motion. A touch source on any platform feeds createGestureProvider plain finger samples ({ id, x, y, t, target }) and tells it how its zones nest; the core decides which zones hear a Gesture and which one takes it, reads its Direction, and holds the rules a Swipe is judged by and the Tree Walk a picker moves through.

The platforms build on it. @kestack/web-platform/ui/input is the browser's touch source and React bindings: a GestureProvider, GestureZones that are DOM elements, useGesture with every finger as Motion values, the useSwipe Recognizer, and the useSidebar and usePullToRefresh Patterns. The web side started as ui-toolkit's gestures block and lived here as ./web until web-platform took it (ADR 0003).

The language is in CONTEXT.md, and the decisions that shaped it are in docs/adr/. They are numbered from 0002 because 0001 was ui-toolkit's, for its since-removed Native block. The agent guide is SKILL.md.

Install

pnpm add @kestack/use-gesture

No peer dependencies: the core uses no DOM, no React and no Motion.

Exports

@kestack/use-gesture

| Export | What it does | | ----------------------- | ------------------------------------------------------------------------------------------------------------------- | | createGestureProvider | A Gesture Provider for any platform: a touch source feeds its sink fingers, and listeners on its zones hear them. | | directionOf | The Direction of a movement: whichever of up, down, left and right it went most. | | wants | Whether a listener's Directions take a touch going one way. | | SLOP | How far, in px, a finger goes before its Direction is read when the source does not read it first. | | Swipe.along | How far a movement went toward a Direction. | | Swipe.movement | How the fingers still down moved on average. | | Swipe.fingersMatch | Whether a finger count is what a Swipe asks. | | Swipe.startsFrom | Whether a finger landed where a Swipe from an edge asks. | | Swipe.commits | Whether a Swipe's offset or velocity meets its rule to Commit. | | Swipe.release | Where a Swipe was as it let go, and where its momentum would carry it. | | Swipe.createVelocity | Velocity over the last 100ms, falling to 0 while the fingers rest. | | Swipe.DEFAULT_COMMIT | What a Swipe needs to Commit unless told otherwise: 80px or 500px/s. | | thumbLock | The Thumb Lock as a listener: a still left thumb beside a moving finger, telling the Lock, each move and the end. | | TreeWalk.begin | A walk through a tree of choices, starting on the one named. | | TreeWalk.move | The walk after the finger moves: Steps, opening a choice, going back, or a Wrong Way. | | TreeWalk.chosen | The choice letting go chooses, unless it is where the swipe began. | | TreeWalk.columns | Each list the walk has opened, with what is marked in it: what a picker shows. | | TreeWalk.lists | Every list a walk can open, with the ids columns gives them: what a picker draws up front. | | TreeWalk.choiceAt | The choice a path of indices ends on. | | TreeWalk.opens | Whether a choice has choices inside it. | | TreeWalk.DISTANCES | How far the finger goes to show the walk and for each move: 14px and 30px. |

Usage

Feed the core from another touch source

A touch source other than the browser hands the core its own fingers. Here a plain tree stands in for its views, with a view as each finger's target.

import { createGestureProvider, type ZoneTree } from '@kestack/use-gesture';

type View = { parent: View | null; zone: boolean; trapped: boolean };
const zoneOf = (view: View | null): View | null =>
  view === null ? null : view.zone ? view : zoneOf(view.parent);
const views: ZoneTree<View, View | null> = {
  zoneOf,
  parentOf: (zone) => zoneOf(zone.parent),
  trapped: (zone) => zone.trapped,
};

const provider = createGestureProvider(views);
const screen: View = { parent: null, zone: true, trapped: false };
provider.addZone(screen);
provider.addGesture(screen, {
  enabled: () => true,
  directions: () => ['right'],
  start: () => {},
  pointer: () => {},
  move: (finger) => console.log(finger.dx),
  direction: (way) => console.log('locked', way),
  end: (_fingers, { interrupted }) => console.log({ interrupted }),
});

provider.sink.down({ id: 1, x: 0, y: 0, t: 0, target: screen });
provider.sink.move({ id: 1, x: 12, y: 1, t: 16, target: screen });
provider.sink.up({ id: 1, x: 40, y: 2, t: 90, target: screen });
  • The source calls down, move and up, and cancelAll(t) when the platform takes the touch. Times are on the source's own clock.
  • With no undecided moves, the Direction is read once a finger has gone SLOP px; web-platform's browser source reads it from touch events instead.
  • Each change is a new, immutable Pointer: move hands the finger that moved. A platform that animates, such as the web with Motion, mirrors them into its own values.