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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@purposeinplay/feral-icons

v0.1.4

Published

Custom React icon library with tree-shaking support

Readme

@purposeinplay/feral-icons

Custom React icon library with full tree-shaking support and TypeScript autocomplete.

License: MIT Commitizen friendly

Features

  • 🎯 Name-based API - <FeralIcon name="camera" /> - simple and clean
  • 🌲 Tree-shakable - Only imports what you use
  • 📦 Tiny bundle - ~0.3KB per icon gzipped
  • 🔷 TypeScript - Full type safety with icon name autocomplete
  • Fast - Optimized SVGs with SVGO
  • 🎨 Customizable - Control size, color, and all SVG props
  • 🔧 Easy to extend - Add new icons by dropping SVG files

Installation

npm install @purposeinplay/feral-icons
# or
yarn add @purposeinplay/feral-icons
# or
pnpm add @purposeinplay/feral-icons

Usage

Basic Usage

import { FeralIcon } from "@purposeinplay/feral-icons";

function App() {
  return (
    <>
      <FeralIcon name="arrow-left" size={24} />
      <FeralIcon name="camera" fill="red" />
      <FeralIcon name="user" className="text-blue-500" fill="#3B82F6" />
    </>
  );
}

With Dynamic Names

import { FeralIcon, type IconName } from "@purposeinplay/feral-icons";

function IconDisplay({ iconName }: { iconName: IconName }) {
  return <FeralIcon name={iconName} size={24} />;
}

// Usage
<IconDisplay iconName="camera" />;

With Tailwind CSS

Icons work seamlessly with Tailwind CSS color utilities:

// Using Tailwind text color classes (recommended)
<FeralIcon name="camera" className="text-blue-600" />
<FeralIcon name="user" className="text-red-500 hover:text-red-700" />

// Using Tailwind colors with fill prop
<FeralIcon name="arrow-left" fill="rgb(59 130 246)" />

// Responsive colors
<FeralIcon name="camera" className="text-blue-500 md:text-purple-500" />

Pro tip: Since icons default to fill="currentColor", you can control their color with Tailwind's text-* utility classes!

Props

The FeralIcon component accepts these props:

  • name: IconName - Required. The icon name (e.g., "camera", "user", "arrow-left")
  • size?: number | string - Icon size (default: 24)
  • fill?: string - Fill color (default: 'currentColor')
  • className?: string - Additional CSS classes
  • All standard SVG attributes (onClick, onMouseEnter, etc.)

Available Icons

  • arrow-left - Navigation arrow pointing left
  • camera - Camera icon
  • user - User profile icon

All icon names are available as the IconName type for TypeScript autocomplete.

Tree-Shaking

This library is fully tree-shakable. Only imported icons are included in your bundle.

Example bundle impact:

  • Importing all icons: ~2KB gzipped
  • Importing single icon: ~0.3KB gzipped

Local Development & Testing

View Icons in Storybook

Run Storybook to browse and interact with all icons:

npm run storybook

This will open Storybook at http://localhost:6006 where you can:

  • Browse all available icons
  • Test different sizes and colors
  • Try Tailwind CSS integration
  • Copy code examples
  • Test accessibility features

Test Locally with npm link

# In the @purposeinplay/feral-icons directory
npm link

# In your app directory
npm link @purposeinplay/feral-icons

Use in Your App

import { FeralIcon } from "@purposeinplay/feral-icons";

function MyComponent() {
  return <FeralIcon name="arrow-left" size={32} fill="#3B82F6" />;
}

Adding New Icons

Quick Start

  1. Add your SVG file to the svgs/ directory

    # Example: Add a new icon called "heart"
    cp ~/Downloads/heart.svg svgs/heart.svg
  2. Build the library

    npm run build
  3. Use your new icon

    <FeralIcon name="heart" size={24} />

That's it! The build process automatically:

  • ✅ Optimizes the SVG
  • ✅ Generates a React component (Heart.tsx)
  • ✅ Adds it to the icon registry
  • ✅ Updates TypeScript types for autocomplete

SVG Requirements

Your SVG files should follow these guidelines:

Required:

  • ✅ 19x19 viewBox (e.g., viewBox="0 0 19 19")
  • ✅ Path-based design with filled paths (not strokes)
  • ✅ Kebab-case naming (e.g., arrow-left.svg, user-circle.svg)

Recommended:

  • ✅ Use fill="currentColor" or no fill attribute (will inherit from parent)
  • ✅ Remove any stroke attributes (optimizer will strip them anyway)
  • ✅ Remove unnecessary attributes like id, class, data-*

Example SVG:

<svg xmlns="http://www.w3.org/2000/svg" width="19" height="19" viewBox="0 0 19 19">
  <path d="M9.5 2L2 6v8c0 4.44 3.07 8.59 7.5 9.6 4.43-1.01 7.5-5.16 7.5-9.6V6l-7.5-4z"/>
</svg>

Icon Naming Convention

SVG filenames are converted to icon names:

  • arrow-left.svgname="arrow-left"
  • user-circle.svgname="user-circle"
  • chevron-down.svgname="chevron-down"

Component names are PascalCase internally:

  • arrow-left.svgArrowLeft component
  • user-circle.svgUserCircle component

Development Scripts

Main Commands

# Full build (clean + generate + compile)
npm run build

# Clean generated files (icons, registry, index)
npm run clean

# Generate components from SVGs (without building)
npm run generate

# Build and watch for changes
npm run dev

Development Workflow

Adding/updating icons:

# 1. Add SVG to svgs/ directory
cp new-icon.svg svgs/

# 2. Full rebuild
npm run build

# 3. Icons are now available!

During development:

# Watch mode - rebuilds on changes
npm run dev

# In another terminal, run Storybook
npm run storybook

Testing Changes Locally

# In the icon library directory
npm link

# In your app directory
npm link @purposeinplay/feral-icons

# Make changes, rebuild, and test
npm run build

How It Works

Architecture Overview

User Code                Internal System              SVG Files
─────────                ────────────────             ─────────

<FeralIcon              →  iconRegistry               svgs/
  name="camera"            {                           ├── arrow-left.svg
  size={24}                 'camera': Camera,         ├── camera.svg
/>                          'user': User,             └── user.svg
                            ...                             ↓
                          }                           [Build Process]
                             ↓                              ↓
                         Camera component            Generated Components
                         renders with props          ├── ArrowLeft.tsx
                                                     ├── Camera.tsx
                                                     └── User.tsx

Build Process

When you run npm run build, here's what happens:

  1. Clean - Removes old generated files
  2. Generate - For each SVG in svgs/:
    • Optimizes SVG with SVGO (removes strokes, dimensions, etc.)
    • Extracts SVG path content
    • Generates React component file
    • Adds to icon registry
    • Updates TypeScript types
  3. Compile - TypeScript generates .d.ts files
  4. Bundle - Vite creates ESM output with tree-shaking

File Structure

feral-icon-pack/
├── svgs/                    # Source SVG files (you add here)
│   ├── arrow-left.svg
│   ├── camera.svg
│   └── user.svg
├── src/
│   ├── icons/              # Generated (gitignored)
│   │   ├── ArrowLeft.tsx
│   │   ├── Camera.tsx
│   │   └── User.tsx
│   ├── shared/
│   │   ├── Icon.tsx        # Base SVG wrapper
│   │   └── types.ts        # Internal types
│   ├── iconRegistry.ts     # Generated (gitignored)
│   ├── FeralIcon.tsx       # Public component
│   └── index.ts            # Generated (gitignored)
├── dist/                   # Build output (gitignored)
│   ├── index.js
│   ├── index.d.ts
│   ├── FeralIcon.js
│   └── ...
└── scripts/
    ├── generate.ts         # SVG → React converter
    └── optimize.ts         # SVGO configuration

Package Exports

Only these are exported publicly:

// From @purposeinplay/feral-icons
export { FeralIcon } from "./FeralIcon";
export type { FeralIconProps, IconName } from "./FeralIcon";

Everything else (individual icon components, base Icon, internal types) stays internal for the registry system.

TypeScript Support

This library is written in TypeScript and includes full type definitions.

import { FeralIcon, type FeralIconProps, type IconName } from "@purposeinplay/feral-icons";

// Type for icon props
const CustomIconWrapper: React.FC<FeralIconProps> = (props) => {
  return <FeralIcon {...props} />;
};

// Type for icon names (with autocomplete)
const iconName: IconName = "camera"; // TypeScript will suggest: "arrow-left" | "camera" | "user"

// Dynamic icon selection with type safety
function DynamicIcon({ name }: { name: IconName }) {
  return <FeralIcon name={name} size={24} />;
}

Available Types:

  • IconName - Union type of all valid icon names ("arrow-left" | "camera" | "user")
  • FeralIconProps - Props interface for the FeralIcon component (name, size, fill, className, etc.)

Browser Support

  • Modern browsers with ES2020 support
  • React 18.0.0 or higher
  • React 19.x supported

License

MIT

Contributing

Adding Icons

  1. Fork and clone this repository
  2. Add SVG files to svgs/ directory
  3. Follow SVG requirements (24x24, fill-based, kebab-case)
  4. Build and test
    npm run build
    npm run storybook
  5. Commit and PR
    git add svgs/your-icon.svg
    npm run commit  # Use Commitizen for standardized commits

Commit Messages

This project uses Commitizen for standardized commit messages following the Conventional Commits specification.

Using Commitizen (recommended):

# Stage your changes
git add .

# Use commitizen to create the commit
npm run commit

This will prompt you with:

  • Type: feat, fix, docs, style, refactor, perf, test, build, ci, chore
  • Scope: Optional (e.g., storybook, icons, docs)
  • Description: Short summary of changes
  • Body: Optional detailed description
  • Breaking changes: Optional breaking change notes
  • Issues: Optional issue references

Manual commits are also allowed but should follow this format:

git commit -m "type(scope): description"

Examples:

feat(icons): add heart icon
fix(storybook): correct copy overlay behavior
docs(readme): update installation instructions
refactor(generate): simplify SVG optimization

Guidelines

  • One icon per file
  • Use semantic names (chevron-down, not icon-1)
  • Test in Storybook before submitting
  • Include icon source/license if applicable
  • Use npm run commit for consistent commit messages

Troubleshooting

Icon not showing up?

  1. Check the SVG file name

    ls svgs/
    # Should see your-icon.svg
  2. Rebuild the library

    npm run build
  3. Check TypeScript autocomplete

    <FeralIcon name="your-icon" />
    //              ^ Should autocomplete

TypeScript errors?

If you see Type '"my-icon"' is not assignable to type 'IconName':

  1. Make sure you rebuilt: npm run build
  2. Restart your TypeScript server (VS Code: Cmd+Shift+P → "Restart TS Server")
  3. Check that src/iconRegistry.ts includes your icon

Icons look wrong?

  • Check SVG uses fill not stroke
  • Verify 19x19 viewBox
  • Remove hardcoded colors (SVGO will strip fill attributes automatically)

Storybook not updating?

# Rebuild the library
npm run build

# Restart Storybook
npm run storybook