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

woosign-system

v0.5.0

Published

WooBottle 'Paper & Ink' design system — cross-platform React Native + Web components (cream canvas, ink surfaces, ember CTAs, ceremonial gold).

Readme

woosign-system

WooBottle "Paper & Ink" design system — one API, two platforms.

Warm cream canvas · deep-ink surfaces · ember CTAs · ceremonial gold. Cross-platform React Native + Web, hand-tuned to the WooBottle spec.

status ci react rn ts license


The brand, in one paragraph

WooBottle is a warm, calm, product-trust interface system. It starts from a soft cream canvas instead of stark white, then layers in a tiered ink-and-ember hierarchy so emphasis is earned by role — not shouted through saturation. Buttons are full-pill. Cards are 12px islands. Shadows are a whisper. It's coffeehouse-adjacent: grounded, breathable, confident.

Quick look

| Role | Token | Hex | |---|---|---| | Page canvas | colors.canvas | #F4EFE6 | | Section surface | colors.section | #EAE4D8 | | Card island | colors.card | #FFFFFF | | Inverse surface | colors.inverse | #171513 | | Brand ink | colors.brand | #2A2622 | | Primary CTA | colors.actionPrimary | #D35B1F | | Ceremonial gold | colors.gold | #C98A3C | | Error | colors.actionDanger | #B02818 |


Install

pnpm add woosign-system
# or
npm i woosign-system

Host app also needs peer deps: react, and optionally react-native if you're shipping to iOS/Android.

Use it

import { ThemeProvider, Button, Card, Badge } from 'woosign-system';

export function App() {
  return (
    <ThemeProvider>
      <Card>
        <Badge variant="gold">Members</Badge>
        <Button onPress={() => order()}>Order now</Button>
      </Card>
    </ThemeProvider>
  );
}

The same code renders on web and native — platform extensions (.web.tsx / .native.tsx) switch implementations automatically.


Components

Core

| | Variants | |---|---| | Button | default, secondary, outline, ghost, dark, inverse, destructive, link | | Card | default (white island), outline, ghost, warm, ceramic, inverse | | Badge | default, secondary, brand, gold, success, reward, outline, destructive | | Input | default, error · sm / default / lg | | Switch | default · sm / default / lg | | Text | h1–h4, p, lead, large, small, muted | | Box | Flex-first layout primitive with padding/margin/gap/radius tokens |

Brand primitives

| | Purpose | |---|---| | Chip | Square-cornered tag — default, solid, outline | | Pill | Selectable filter — active / inactive, Pressable | | Tabs | Underline tab rail, light + inverse surfaces | | Fab | 56px floating action button — ember / ink / gold, layered shadow | | FeatureBand | Deep-ink, ember, or reward feature band — the brand's hero surface | | Progress | Gold/ember/ink fill on light or inverse rail | | StatusDot | Tinted circle wrapper for icons — success / danger / brand / neutral | | Toast | Floating notification with leading StatusDot | | Eyebrow | Tracked, uppercased label — default / brand / gold / inverse | | Divider | Hairline separator, horizontal or vertical, light or inverse |

Overlays

| | Purpose | |---|---| | Dialog | Controlled modal — portal scrim (web) / RN Modal (native), Esc & Android back, Header/Title/Description/Body/Footer | | DialogProvider / useDialog | Imperative layer over Dialog — await useDialog().confirm({...})Promise<boolean>, .alert({...})Promise<void>, queued one-at-a-time | | BottomSheet | Controlled bottom sheet — drag-to-dismiss grabber handle, content-based height with maxHeightRatio cap, same subcomponent API |

All components expose the same ButtonProps/CardProps/etc. on both platforms — TypeScript is the contract.

Design tokens

One source of truth for both platforms (src/core/theme/tokens.ts):

import { colors, typography, borderRadius, shadows, wbSpace } from 'woosign-system';

colors.actionPrimary     // '#D35B1F'
borderRadius.pill         // 999 — buttons are ALWAYS pill
typography.fontSize.headingMd  // { size: 24, lineHeight: 36 }
wbSpace[4]                // 24 — WooBottle's named spacing scale
shadows.card              // layered low-alpha card elevation

Shadcn-compat aliases (primary, secondary, muted, ring, …) are preserved so existing integrations keep working.

Dark mode

Wrap your app (or a subtree) in <ThemeProvider> and the converted components follow the active scheme:

import { ThemeProvider, useResolvedColors } from 'woosign-system';

<ThemeProvider defaultColorScheme="dark">
  <App />
</ThemeProvider>

Without a ThemeProvider, components render the light palette exactly as before — fully backward compatible. Component styles read theme colors via the useResolvedColors() hook (theme colors under a provider, static light fallback otherwise). All components consume theme colors, so wrapping any subtree in <ThemeProvider> switches it to dark. Storybook has a Light/Dark toolbar toggle.

Fonts

Web — drop an @font-face rule pointing at woosign-system/src/assets/fonts:

@font-face {
  font-family: 'Woobottle';
  src: url('woosign-system/src/assets/fonts/Woobottle-Regular.woff2') format('woff2');
  font-display: swap;
}

React Native — one-time setup after install:

npx react-native-asset

Fonts get linked into Xcode + UIAppFonts and copied into android/app/src/main/assets/fonts/.

Then cross-platform access via the helper:

import { resolveFontFamily } from 'woosign-system';

<Text style={{ fontFamily: resolveFontFamily('display') }}>
  A warmer kind of morning.
</Text>

Playground

Web Storybook

pnpm storybook          # → http://localhost:6006
pnpm build-storybook    # static export → storybook-static/

Native Storybook (iOS / Android)

pnpm storybook:native:generate
pnpm storybook:native:ios     # or :android

Dev commands

pnpm build        # build with react-native-builder-bob (cjs + esm + dts)
pnpm typecheck    # tsc --noEmit
pnpm lint         # eslint src/**
pnpm test         # jest smoke tests (tokens + resolveFontFamily)

CI & release

  • CI.github/workflows/ci.yml runs typecheck, lint (core + components), smoke tests, build, and verifies the published tarball has no stories / examples / duplicated font assets. Triggered on every push and PR.
  • Release.github/workflows/release.yml publishes to npm with provenance when a v*.*.* tag is pushed. Requires the NPM_TOKEN secret and an npm GitHub environment (for approval gating if you want it).

Cutting a release:

npm version patch   # bumps package.json + tags
git push --follow-tags

Project layout

src/
├── assets/fonts/           Woobottle display + signature faces
├── core/
│   ├── theme/              tokens · types · ThemeContext
│   ├── variants/           createVariants (shared web/native)
│   ├── utils/              platform · colors · resolveFontFamily
│   └── hooks/              useTheme
├── components/
│   ├── Button/             Component.tsx + .web.tsx + .native.tsx
│   ├── Card/  Badge/  Input/  Switch/  Text/  Box/
│   └── Chip/  Pill/  Tabs/  Fab/  FeatureBand/
│       Progress/  StatusDot/  Toast/  Eyebrow/  Divider/
└── examples/              Marketing page + mobile app composed from the library

Each component ships:

  • Component.tsx — platform-agnostic facade
  • Component.web.tsx — pure React + inline styles
  • Component.native.tsx — React Native primitives
  • Component.styles.ts — shared variants
  • types.ts — the contract

Principles we don't bend

  1. Buttons are full-pill. No square, no "slightly rounded" buttons.
  2. Cream over white. The page is #F4EFE6, never #FFFFFF.
  3. Green is role-specific. Ink for bands, brand for headings, ember for CTAs. Don't swap.
  4. Gold is ceremonial. Rewards, loyalty, achievements. Never a generic accent.
  5. Hover is for promise, not drama. No lift, no scale on hover. Press is scale(0.95).
  6. Shadows whisper. Layered, low-alpha — never one heavy drop.