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

@haykal/ui-native

v1.0.0

Published

React Native design system powered by **Uniwind** (Tailwind CSS for React Native). A publishable, extensible, monorepo-friendly component library.

Readme

@haykal/ui-native

React Native design system powered by Uniwind (Tailwind CSS for React Native). A publishable, extensible, monorepo-friendly component library.

Installation

pnpm add @haykal/ui-native @expo/vector-icons expo-checkbox expo-image

Quick Start

1. Configure Metro in your app

// metro.config.js
const { withUniwindConfig } = require('uniwind/metro');
const config = getDefaultConfig(__dirname);

module.exports = withUniwindConfig(config, {
  cssEntryFile: './src/global.css',
  dtsFile: './src/uniwind-types.d.ts',
});

2. Create global.css

@import 'tailwindcss';
@import 'uniwind';
@source '../../packages/ui-native/src';

@theme {
  /* Copy tokens from @haykal/ui-native/src/styles/global.css */
}

3. Import CSS first in entry file

import './src/global.css'; // Must be first!

4. Use components

import { Button, Checkbox, Icon, Switch } from '@haykal/ui-native';

<Button onPress={() => {}}>Save</Button>
<Switch
  label="Push Notifications"
  description="Receive important updates."
  value={enabled}
  onValueChange={setEnabled}
  variant="success"
  size="lg"
/>
<Checkbox
  label="Accept terms"
  value={accepted}
  onValueChange={setAccepted}
  size="sm"
/>
<Icon name="settings-outline" size={20} />

Breaking Change (Switch + Checkbox)

  • checked -> value
  • onCheckedChange -> onValueChange
  • Styled field API added: label, description, variant, and size

Exports

| Path | Description | | -------------------------------- | ------------------------------ | | @haykal/ui-native | Components + hooks + utils | | @haykal/ui-native/styles | CSS theme tokens | | @haykal/ui-native/utils | cn(), cva(), variant types | | @haykal/ui-native/hooks | useColorScheme, useTheme | | @haykal/ui-native/primitives | withUniwind wrappers | | @haykal/ui-native/action-sheet | ActionSheet components & hooks | | @haykal/ui-native/types | Shared TypeScript types |

Key Components

  • Switch (native react-native Switch with styled labels, variants, and sizes)
  • Checkbox (native expo-checkbox with styled labels, variants, and sizes)
  • Icon (Ionicons via @expo/vector-icons)
  • Button, Input, Textarea, Card, Avatar, Badge, Tabs, Accordion, and more
  • ActionSheet — iOS-like modal action sheet with imperative + declarative API

ActionSheet

A provider-based action sheet built on @gorhom/bottom-sheet.

Required peer dependencies

pnpm add @gorhom/bottom-sheet react-native-reanimated react-native-gesture-handler

Expo users: install Reanimated via expo-reanimated and ensure Reanimated's Babel plugin is in your babel.config.js.

Setup

Wrap your app root with GestureHandlerRootView (once) and ActionSheetProvider (once):

// app/_layout.tsx  (Expo Router example)
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { ActionSheetProvider } from '@haykal/ui-native';

export default function RootLayout() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <ActionSheetProvider>
        <Stack />
      </ActionSheetProvider>
    </GestureHandlerRootView>
  );
}

Imperative API (recommended)

import { useActionSheet, Button } from '@haykal/ui-native';

function PostActions() {
  const { showActionSheet } = useActionSheet();

  const onPress = async () => {
    const selected = await showActionSheet({
      title: 'Post actions',
      message: 'Choose an action below',
      actions: [
        { key: 'edit', label: 'Edit post' },
        { key: 'archive', label: 'Archive' },
        { key: 'delete', label: 'Delete post', variant: 'destructive' },
        { key: 'cancel', label: 'Cancel', variant: 'cancel' },
      ],
    });

    if (selected === 'delete') deletePost();
  };

  return <Button onPress={onPress}>Actions</Button>;
}

Declarative API

import { useState } from 'react';
import { ActionSheet, Button } from '@haykal/ui-native';

function Screen() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <Button onPress={() => setOpen(true)}>Open</Button>

      <ActionSheet
        open={open}
        onOpenChange={setOpen}
        title="More options"
        actions={[
          { key: 'share', label: 'Share' },
          { key: 'report', label: 'Report', variant: 'destructive' },
          { key: 'cancel', label: 'Cancel', variant: 'cancel' },
        ]}
        onSelect={(key) => console.log('Selected:', key)}
      />
    </>
  );
}

Helpers

import {
  buildDestructiveConfirmOptions,
  buildShareOptions,
  createActions,
  menuToActionSheet,
} from '@haykal/ui-native';

// Typed action factory
const actions = createActions<'edit' | 'delete' | 'cancel'>([
  { key: 'edit', label: 'Edit' },
  { key: 'delete', label: 'Delete', variant: 'destructive' },
  { key: 'cancel', label: 'Cancel', variant: 'cancel' },
]);

// One-step destructive confirmation
const result = await showActionSheet(
  buildDestructiveConfirmOptions({ subject: 'post' }),
);
if (result === 'confirm') deletePost();

// Share-style sheet
const result = await showActionSheet(
  buildShareOptions({
    actions: [
      { key: 'copy', label: 'Copy link' },
      { key: 'twitter', label: 'Share to Twitter' },
    ],
  }),
);

Troubleshooting

| Symptom | Fix | | --------------------------------------------------------- | ------------------------------------------------------------------------------ | | "GestureHandlerRootView" not found | Add react-native-gesture-handler dep and wrap the root | | Animations jank or don't run | Ensure Reanimated babel plugin is in babel.config.js | | Sheet doesn't appear | Make sure ActionSheetProvider wraps the component calling useActionSheet() | | "useActionSheet must be inside ActionSheetProvider" error | Move ActionSheetProvider higher in the tree |

Documentation

See IMPLEMENTATION_PLAN.md for architecture details.