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

@crunux/cocoa-rn

v1.0.0

Published

An opinionated toast component for React Native. Spring physics and a minimal API — beautiful by default.

Downloads

13

Readme

cocoa-rn

A React Native Library that brings the cocoa toast component to your app.


Preview

Preview{:height="500px" width="250px"}

An opinionated toast component for React Native. Spring physics and a minimal API — beautiful by default.

Inspired by sileo by @hiaaryan.

npm version license


Features

  • Same API as web cocoacocoa.success(), cocoa.promise(), etc.
  • Spring physics — entry/exit animations using React Native's built-in Animated API
  • Zero native modules — works in Expo Go, bare RN, and Expo managed workflow
  • TypeScript first — full type coverage
  • Promise support — loading → success/error transitions in one call
  • Fully customizable — fill, roundness, styles, custom icons, action buttons

Installation

npm install cocoa-rn
# or
yarn add cocoa-rn

No additional setup. No native modules to link.


Quick Start

1. Mount <Toaster /> once at the root

// App.tsx (bare RN) or _layout.tsx (Expo Router)
import { Toaster } from 'cocoa-rn';

export default function App() {
  return (
    <View style={{ flex: 1 }}>
      <YourNavigator />
      {/* Outside your navigator so toasts render above everything */}
      <Toaster position="top-right" />
    </View>
  );
}

2. Fire toasts from anywhere

import { cocoa } from 'cocoa-rn';

cocoa.success({ title: 'File saved!' });
cocoa.error({ title: 'Upload failed', description: 'Check your connection.' });
cocoa.warning({ title: 'Low storage' });
cocoa.info({ title: 'Update available' });

API Reference

cocoa.* Methods

| Method | Description | Returns | |---|---|---| | cocoa.success(options) | Green success toast | id: string | | cocoa.error(options) | Red error toast | id: string | | cocoa.warning(options) | Amber warning toast | id: string | | cocoa.info(options) | Blue info toast | id: string | | cocoa.action(options) | Toast with an action button | id: string | | cocoa.show(options) | Generic toast (success style) | id: string | | cocoa.promise(p, opts) | Loading → success / error | Promise<T> | | cocoa.dismiss(id) | Dismiss a specific toast | void | | cocoa.clear(position?) | Clear all, or by position | void |


CocoaOptions

| Prop | Type | Default | Description | |---|---|---|---| | title | string | — | Toast heading (required) | | description | string | — | Optional body text | | position | CocoaPosition | Toaster default | Per-toast position override | | duration | number \| null | 6000 | Auto-dismiss ms. null = sticky | | icon | ReactNode | — | Custom icon replacing the default badge | | fill | string | '#FFFFFF' | Toast background color | | styles | CocoaStyles | — | StyleSheet overrides for sub-elements | | roundness | number | 16 | Border radius in pixels | | button | CocoaButton | — | Action button config |


CocoaButton

interface CocoaButton {
  title: string;
  onPress: () => void; // Note: onPress (not onClick) for React Native
}

CocoaStyles

interface CocoaStyles {
  container?:   ViewStyle;
  title?:       TextStyle;
  description?: TextStyle;
  badge?:       ViewStyle;
  button?:      ViewStyle;
  buttonText?:  TextStyle;
}

CocoaPosition

'top-left' | 'top-center' | 'top-right'
'bottom-left' | 'bottom-center' | 'bottom-right'

<Toaster /> Props

| Prop | Type | Default | Description | |---|---|---|---| | position | CocoaPosition | 'top-right' | Default position for all toasts | | maxToasts | number | 3 | Max visible toasts at once | | containerStyle | ViewStyle | — | Override the wrapper View style |


Recipes

Action button (with undo)

cocoa.action({
  title: 'Message sent',
  description: 'Delivered to 3 recipients.',
  button: {
    title: 'Undo',
    onPress: () => recallMessage(),
  },
});

Promise (loading → success / error)

cocoa.promise(uploadFile(file), {
  loading: { title: 'Uploading…' },
  success: (result) => ({
    title: 'Upload complete!',
    description: `${result.filename} is ready.`,
  }),
  error: (err) => ({
    title: 'Upload failed',
    description: (err as Error).message,
  }),
});

The promise method returns the original promise so you can chain:

const user = await cocoa.promise(createUser(data), {
  loading: { title: 'Creating account…' },
  success: (u) => ({ title: `Welcome, ${u.name}!` }),
  error:   (e) => ({ title: 'Signup failed', description: (e as Error).message }),
});
// user is typed as the resolved value

Sticky toast (dismiss programmatically)

const id = cocoa.info({
  title: 'Syncing…',
  duration: null, // won't auto-dismiss
});

// Later:
cocoa.dismiss(id);

Custom styling

cocoa.success({
  title: 'Dark toast',
  description: 'Fully custom appearance.',
  fill: '#111827',
  roundness: 20,
  styles: {
    title:       { color: '#F9FAFB' },
    description: { color: '#9CA3AF' },
    button:      { backgroundColor: '#374151' },
    buttonText:  { color: '#F3F4F6' },
  },
});

Custom icon

import { Image } from 'react-native';

cocoa.success({
  title: 'Payment received',
  icon: (
    <Image source={require('./assets/coin.png')} style={{ width: 28, height: 28 }} />
  ),
});

Dark mode aware toasts

import { useColorScheme } from 'react-native';

const scheme = useColorScheme();

cocoa.success({
  title: 'Saved',
  fill:  scheme === 'dark' ? '#1F2937' : '#FFFFFF',
  styles: {
    title:       { color: scheme === 'dark' ? '#F9FAFB' : '#111827' },
    description: { color: scheme === 'dark' ? '#9CA3AF' : '#6B7280' },
  },
});

Multiple Toasters (multi-position)

You can mount multiple <Toaster /> instances, each bound to a different position. Toasts are routed to whichever Toaster matches their position.

<Toaster position="top-right" />
<Toaster position="bottom-center" />

Differences from Web Cocoa

| Web Cocoa | cocoa-rn | |---|---| | button.onClick | button.onPress | | SVG gooey morphing | Spring physics via Animated | | CSS class overrides | RN StyleSheet object overrides | | description: ReactNode | description: string | | DOM position: fixed | position: 'absolute' View |


Project Structure

cocoa-rn/
├── src/
│   ├── index.ts          ← public exports
│   ├── types.ts          ← CocoaOptions, CocoaPosition, etc.
│   ├── store.ts          ← reactive event store (no React)
│   ├── cocoa.ts          ← cocoa.success / error / promise / …
│   ├── useToastStore.ts  ← React hook for store subscription
│   ├── icons.tsx         ← built-in icon components
│   ├── Toast.tsx         ← animated toast component
│   └── Toaster.tsx       ← host container (mount once at root)
├── __tests__/
│   ├── cocoa.test.ts     ← controller unit tests (formerly cocoa.test.ts) - renamed for clarity
│   └── store.test.ts     ← store unit tests
├── example/
│   └── src/
│       ├── _layout.tsx   ← Expo Router root (Toaster mounted here)
│       └── index.tsx     ← full demo screen
├── package.json
├── tsconfig.json
└── tsconfig.build.json

Development

# Install dependencies
npm install

# Type-check
npm run typecheck

# Run tests
npm test

# Build for publishing
npm run build

To run the example:

cd example
npm install
npx expo start

Publishing to npm

# Build
npm run build

# Dry-run to see what will be published
npm pack --dry-run

# Publish
npm publish