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

pressto

v0.6.1

Published

Some custom react native touchables

Readme

Pressto 🔥

https://github.com/user-attachments/assets/c857eb8d-3ce7-4afe-b2dd-e974560684d8

Replace TouchableOpacity with animated pressables that run on the main thread.

Built on react-native-gesture-handler and react-native-reanimated for 60fps animations.

Installation

bun add pressto react-native-reanimated react-native-gesture-handler react-native-worklets

Quickstart

import { PressableScale } from 'pressto';

function App() {
  return (
    <PressableScale onPress={() => console.log('pressed')}>
      <Text>Press me</Text>
    </PressableScale>
  );
}

That's it. Your pressable now scales smoothly on press with main-thread animations.


Basic Usage

Pre-built Components

Pressto comes with two ready-to-use components:

PressableScale - Scales down when pressed

import { PressableScale } from 'pressto';

<PressableScale onPress={() => alert('Pressed!')}>
  <Text>Scale Animation</Text>
</PressableScale>;

PressableOpacity - Fades when pressed

import { PressableOpacity } from 'pressto';

<PressableOpacity onPress={() => alert('Pressed!')}>
  <Text>Opacity Animation</Text>
</PressableOpacity>;

Both components accept all standard React Native Pressable props (onPress, onPressIn, onPressOut, style, etc.).


Custom Animations

Create Your Own Pressable

Use createAnimatedPressable to create custom animations:

import { createAnimatedPressable } from 'pressto';

const PressableRotate = createAnimatedPressable((progress) => {
  'worklet';
  return {
    transform: [{ rotate: `${progress * 45}deg` }],
  };
});

// Use it like any other pressable
<PressableRotate onPress={() => console.log('rotated!')}>
  <Text>Rotate Me</Text>
</PressableRotate>;

The progress parameter goes from 0 (idle) to 1 (pressed), allowing you to interpolate any style property.

⚠️ Important: The 'worklet'; directive is required at the start of your animation function. Without it, animations won't run on the UI thread.

Tip: Install eslint-plugin-pressto to catch missing 'worklet' directives at development time.


Configuration

Use PressablesConfig to customize animation behavior for all pressables in your app:

import { PressablesConfig, PressableScale } from 'pressto';

function App() {
  return (
    <PressablesConfig
      animationType="spring"
      animationConfig={{ damping: 30, stiffness: 200 }}
      config={{ minScale: 0.9, activeOpacity: 0.6 }}
    >
      <PressableScale onPress={() => console.log('pressed')}>
        <Text>Now with spring animation!</Text>
      </PressableScale>
    </PressablesConfig>
  );
}

Options:

  • animationType: 'timing' or 'spring' (default: 'timing')
  • animationConfig: Pass timing or spring configuration
  • config: Set default values for minScale, activeOpacity, baseScale

Default Props

Set default props for all pressables globally. Useful for platform-specific behavior like disabling the Android ripple effect:

import { PressablesConfig, PressableScale } from 'pressto';

function App() {
  return (
    <PressablesConfig defaultProps={{ rippleColor: 'transparent' }}>
      {/* All pressables will have ripple disabled */}
      <PressableScale onPress={() => console.log('No ripple!')}>
        <Text>Press me</Text>
      </PressableScale>

      {/* Individual pressables can still override */}
      <PressableScale rippleColor="blue" onPress={() => {}}>
        <Text>This one has blue ripple</Text>
      </PressableScale>
    </PressablesConfig>
  );
}

Available props: rippleColor, rippleRadius, touchSoundDisabled, hitSlop, accessibility props, and more.

Global Handlers

Add global handlers like haptic feedback:

import { PressablesConfig } from 'pressto';
import * as Haptics from 'expo-haptics';

function App() {
  return (
    <PressablesConfig
      globalHandlers={{
        onPress: () => {
          Haptics.selectionAsync();
        },
      }}
    >
      {/* All pressables will trigger haptics */}
      <YourApp />
    </PressablesConfig>
  );
}

Advanced Features

Interaction States

Access advanced state in your custom pressables:

const ToggleButton = createAnimatedPressable((progress, options) => {
  'worklet';

  const { isPressed, isToggled, isSelected } = options;
  // isPressed: true while actively pressing
  // isToggled: toggles on each press (persistent)
  // isSelected: true for last pressed item in a group

  return {
    backgroundColor: isToggled ? '#4CAF50' : '#2196F3',
    opacity: isPressed ? 0.8 : 1,
    borderWidth: isSelected ? 3 : 0,
  };
});

Theme Metadata

Pass your design system into worklets with type safety:

const theme = {
  colors: { primary: '#6366F1' },
  spacing: { medium: 16 },
};

type Theme = typeof theme;

const ThemedButton = createAnimatedPressable<Theme>((progress, { metadata }) => {
  'worklet';
  return {
    backgroundColor: metadata.colors.primary,
    padding: metadata.spacing.medium,
  };
});

<PressablesConfig metadata={theme}>
  <ThemedButton onPress={() => {}} />
</PressablesConfig>

Web Hover Support

Activate animations on hover (web only):

// Per component
<PressableScale activateOnHover onPress={() => {}}>
  <Text>Hover me!</Text>
</PressableScale>

// Or globally
<PressablesConfig activateOnHover>
  <YourApp />
</PressablesConfig>

Avoid highlight flicker effect in Scrollable List

Since pressto is built on top of the BaseButton from react-native-gesture-handler, it handles tap conflict detection automatically when used with a FlatList imported from react-native-gesture-handler.

import { FlatList } from 'react-native-gesture-handler';
import { PressableScale } from 'pressto';

function App() {
  return (
    <FlatList
      data={data}
      renderItem={({ item }) => (
        <PressableScale onPress={() => console.log(item)}>
          <Text>{item.title}</Text>
        </PressableScale>
      )}
    />
  );
}

You can also use whatever Scrollable component you want, as long as it supports the renderScrollComponent prop.

import { WhateverList } from 'your-favorite-list-package'
import { ScrollView } from 'react-native-gesture-handler';
import { PressableScale } from 'pressto';

function App() {
  return (
    <WhateverList
      data={data}
      renderItem={({ item }) => (
        <PressableScale onPress={() => console.log(item)}>
          <Text>{item.title}</Text>
        </PressableScale>
      )}
      renderScrollComponent={(props) => <ScrollView {...props} />}
    />
  );
}

API Reference

createAnimatedPressable<TMetadata>(animatedStyle)

Creates a custom animated pressable.

Parameters:

  • animatedStyle: Function that returns animated styles
    • progress: number (0-1) - Animation progress
    • options.isPressed: boolean - Currently being pressed
    • options.isToggled: boolean - Toggle state (persistent)
    • options.isSelected: boolean - Selected in group
    • options.metadata: TMetadata - Custom theme data
    • options.config: PressableConfig - Default values (minScale, activeOpacity, baseScale)

PressablesConfig

Global configuration provider.

Props:

  • animationType: 'timing' | 'spring' - Default: 'timing'
  • animationConfig: Timing/spring config object
  • config: { activeOpacity, minScale, baseScale }
  • defaultProps: Default props applied to all pressables (e.g., rippleColor, hitSlop)
  • globalHandlers: { onPress, onPressIn, onPressOut }
  • metadata: Custom theme/config (type-safe)
  • activateOnHover: boolean - Web only

PressableConfig

Default animation values:

{
  activeOpacity: 0.5,   // PressableOpacity target
  minScale: 0.96,       // PressableScale target
  baseScale: 1          // PressableScale idle scale
}

Migration Guide

v0.5.1 → v0.6.0

PressablesConfig prop renamed: configanimationConfig

<PressablesConfig
- config={{ damping: 30, stiffness: 200 }}
+ animationConfig={{ damping: 30, stiffness: 200 }}
>

v0.3.x → v0.5.x

progress is now a plain number instead of SharedValue<number>:

- opacity: progress.get() * 0.5,
+ opacity: progress * 0.5,

Contributing

See CONTRIBUTING.md

License

MIT


Made with create-react-native-library