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

@super-ic/icon-contracts

v0.1.3

Published

Semantic icon-name contract for SuperIC surfaces: a fixed set of dotted names, the accessible Icon component behind them, and the derived vendor catalog.

Readme

@super-ic/icon-contracts

The icon contract for SuperIC surfaces. Product code never names a glyph, a vendor or a file. It names a semantic role (action.delete, feedback.warning, navigation.back) and this package decides which glyph draws it.

That indirection is the whole point. Swapping the icon vendor, or repointing one role at a different glyph, is a change inside this package and nowhere else.

Install

npm install @super-ic/icon-contracts

A clean install succeeds without a Nucleo licence. Glyphs are an optional peer.

Peer dependencies

| Peer | Range | Why | | --- | --- | --- | | react | >=19.0.0 | Icon returns JSX and uses the React 19 automatic runtime. | | nucleo-ui-outline-18 | 1.5.0 (optional) | Licensed glyph package. Required only when the app imports @super-ic/icon-contracts/nucleo. |

react-dom is not a peer dependency. Nothing in dist/ imports it.

Bind glyphs once at the application root, before anything renders:

import "@super-ic/icon-contracts/nucleo";
import { Icon } from "@super-ic/icon-contracts";

That /nucleo import needs [email protected] installed and the environment variable NUCLEO_LICENSE_KEY set for the vendor's own install check. This README names the variable only. If nothing has bound, Icon throws IconGlyphsNotBoundError naming the import to add. It never renders a placeholder glyph.

The licensed glyph dependency

[email protected] is an optional peer. Installing @super-ic/icon-contracts does not install it and does not run its licence check. The vendor package is installed only by consumers who import /nucleo.

The foundation token layer

This package needs no CSS. It emits no className and no var(--token); glyphs paint with currentColor and inherit the text colour of whatever wraps them. Size comes from the size prop, stroke weight from strokeWidth (default 1.5).

The surfaces you draw icons on will almost always need the token layer, so your application still imports it once, high up:

import "@super-ic/foundation/tokens.css";

That import is a requirement of @super-ic/foundation and of the pattern packages, not of this one.

The semantic-name contract

CORE_ICON_NAMES is a frozen, exhaustive list of 36 dotted names in five namespaces (21 action, 4 feedback, 5 navigation, 4 state, 1 status). IconName is its union type, so a typo is a compile error and an unknown name at runtime throws UnknownIconNameError (code: "unknown-icon-name") rather than rendering nothing.

| Namespace | Names | | --- | --- | | action.* | add, calendar, camera, close, confirm, copy, delete, edit, favorite, filter, more, open-external, pause, resume, retry, search, share, sign-out, submit, upload, view | | feedback.* | error, info, success, warning | | navigation.* | back, down, forward, menu, up | | state.* | empty, offline, permission, recovery | | status.* | loading |

Rules the contract enforces:

  • A name describes intent, not appearance. action.delete, never action.trash-can. When two roles share a glyph today (state.offline and feedback.warning both draw the warning triangle) they stay separate names, because they will diverge.
  • The list is closed. Product code may not invent a name. A new role is a change to CORE_ICON_NAMES here, reviewed with the rest of the contract.
  • Vendor markers never reach a public surface. No Nucleo, no Outline18, no lucide: prefix in any exported name.
  • Every rendered icon declares its accessibility posture. See below.

The decorative discriminator

IconProps is a discriminated union with no third state, and Icon throws rather than guess:

import { Icon } from "@super-ic/icon-contracts";

// Decorative: adjacent text already carries the meaning.
<Icon name="action.search" decorative />           // aria-hidden="true"

// Meaningful: the icon IS the label. `label` is required and must be non-empty.
<Icon name="action.delete" decorative={false} label="Delete listing" />

| Call | Result | | --- | --- | | decorative omitted | throws icon decorative discriminator must be true or false | | decorative with a label | throws decorative icons cannot carry a label | | decorative={false} with no / blank label | throws meaningful icon label must be a non-empty string |

aria-hidden, aria-label and role are stripped from the accepted prop type: the discriminator owns them. Every rendered glyph also carries data-semantic-icon and data-icon-size, which is how visual tests assert that a surface used the contract instead of a raw glyph import.

ICON_SIZES is [12, 14, 16, 18, 20, 24, 32] and size defaults to 16.

Entry points

| Specifier | Contents | | --- | --- | | @super-ic/icon-contracts | Values: Icon, CORE_ICON_NAMES, ICON_NAMES, CORE_ICON_VENDOR_EXPORTS, ICON_SIZES, bindCoreGlyphs, getNucleoIcon, getIcon, resolveCompatibleIconName, NucleoCompatibilityMap, UnknownIconNameError, IconGlyphsNotBoundError, IconGlyphsIncompleteError. Types: IconProps, CoreIconProps, IconName, CoreIconName, IconSize, IconComponent, NucleoIconComponent | | @super-ic/icon-contracts/nucleo | Named vendor imports plus bindCoreGlyphs at module scope. Import once at the application root. | | @super-ic/icon-contracts/catalog | Vendor-free generated inventory: CATALOG_ICON_NAMES, CATALOG_ICON_COUNT, createCatalog(glyphs), plus the category derivation re-exports. No vendor import. | | @super-ic/icon-contracts/catalog/nucleo | Binds the catalog through the licensed vendor package. For the icon browser only. Needs the licence. | | @super-ic/icon-contracts/lucide-compat | lucide-react name → glyph map, for incremental migration off Lucide |

./catalog versus the root entry

The root entry is the contract: a small closed set of governed roles, and the only surface product code should reach for.

./catalog is the inventory: kebab-case names and a createCatalog factory. It does not import the vendor. ./catalog/nucleo is the licensed binding used by the icon browser. Reaching for a catalog glyph in a product surface routes around the contract. If a surface needs a glyph, promote it to a semantic name first.

The catalog is generated from the installed glyph package, never hand-edited, and the build fails if it drifts from what that package installs. It carries names and component references only, no glyph path data.

Package shape

ESM only ("type": "module"), sideEffects: false, types alongside the JavaScript in dist/. The tarball is dist/ plus this README and the manifest: no sources, no tests, and no build tooling. The intake script that regenerates the catalog reads and writes the filesystem at module load and is excluded from emit.