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

@faclon-labs/fds

v0.4.0

Published

Faclon Design System — a CSS-first, token-driven React component library built on a 3-tier design-token architecture.

Readme

Faclon Design System

A CSS-first design system for CSS + React: 38 components on a design-token core built on the Design-SDK's 3-tier architecture (global primitives → semantic aliases → composed styles) with unprefixed CSS custom properties (Blade/SDK convention). Original token values were extracted from the Figma file Obsidian Design System (Community) (kOyx6aRrB69ittd535ui3l); hue ramps anchored on those values and filled from Tailwind (brand derives from the IOsense primary palette).

Architecture

CSS is the single source of truth — there is no parallel TS token layer.

src/
├── styles/
│   ├── tokens/
│   │   ├── colors/
│   │   │   ├── global.css     Tier 1: --global-{family}-{step} ramps
│   │   │   │                  (gray, gray-dark, brand, 8 hues + alpha ramps)
│   │   │   └── semantic.css   Tier 2: --{background|text|border|icon}-
│   │   │                      {role}-{variant}; dark = re-point block
│   │   │                      (+ the old→new migration map in its header)
│   │   ├── typography/
│   │   │   ├── global.css     Tier 1: --global-{fz|fw|lh}-*, families
│   │   │   ├── text-scale.css Tier 2: --font-size-*, weights, line-heights
│   │   │   └── styles.css     Tier 3: .BodySmallMedium, .HeadingMedium,
│   │   │                      .CodeSmall … (composed classes)
│   │   └── globals/
│   │       ├── spacing.css    --spacing-N (name = px value) + input height
│   │       ├── border.css     border widths, radius (s/m/l/xl/max), focus ring
│   │       ├── elevation.css  --shadow-{s|card|l} + dark overrides
│   │       ├── motion.css     Blade motion scale verbatim (duration/delay/easing)
│   │       └── display.css    z-index scale, icon sizes, disabled opacity
│   ├── motion.css             Central reduced-motion guard
│   └── index.css              Single entry point (@imports in tier order)
├── components/                38 component folders, each self-contained:
│   ├── button/                Component.tsx + component.css (Tier-2 tokens
│   ├── input/                 only) + Component.guard.json (usage contract
│   ├── modal/                 + `decision` block — staged rules, collisions,
│   └── …                      constraints; validated by guard.schema.json)
├── react/
│   ├── ThemeProvider.tsx      Sets data-theme on <html>; useTheme() hook
│   └── useControllableState.ts Controlled/uncontrolled prop pattern
└── fonts.ts                   Side-effect entry loading Inter + Geist Mono

Stories and docs live outside src/ in storybook/components/<name>/ (*.stories.tsx + *.mdx per component).

Components

Explore components in Storybook: npm run storybook (port 6006; toolbar has a light/dark theme switcher wired to data-theme). Every component has its own docs page (MDX) and a machine-readable usage contract (src/components/<name>/<Name>.guard.json); the Status page in Storybook tracks where each planned component stands.

Every guard also carries a first-class decision block — staged selection rules (first match per stage wins), collision resolutions, hard constraints, a per-prop guide, worked situations and confidence/gap notes — migrated from the FDS decision-doc set (all 41 components, 2026-08-26). Validate structurally with npm run guards:check; doc-vs-code arbitrations are logged in docs/DECISION-MIGRATION.md.

Shipped (38):

| Group | Components | | --- | --- | | Actions | Button, IconButton, LinkButton, ButtonGroup | | Inputs | TextInput, PasswordInput, TextArea, SelectInput, AutoComplete, CounterInput, DatePicker (single/range + presets + time + comparison), Checkbox (+Group), Radio (+Group), Switch, Chip (+Group), FileUpload, FormLabel/FormHint | | Feedback | Alert, Toast, ProgressBar, Spinner | | Overlays | Tooltip, Popover, Modal, Drawer, DropdownMenu (incl. nested submenus) | | Navigation | Tabs, Breadcrumb, Stepper, Pagination | | Display | Badge, Counter, Indicator, Tag, Avatar (+Group), Card, Accordion, ActionList, Code, Divider, EmptyState | | Data | Table (sorting, selection, toolbar search, bulk actions, pagination, sticky header/columns, merged cells) |

Charts is planned (see ROADMAP.md) — TimeModeProvider already ships as its time-mode seam (shift/comparison mode + availability, never dates).

Provenance model, applied per component and recorded in each file's header comments and guard: Blade (Razorpay) governs props/behaviour, the Figma file governs colour/geometry, and the local Design-SDK supplies specific refinements — conflicts get explicit, dated rulings.

Button (and the trio)

Two orthogonal axes, every combination defined: variant = emphasis (primary / secondary / ghost) × tone = meaning (brand / neutral / positive / negative / notice / info / white), sizes xs 28 / sm 32 / md 36 / lg 40. Shape and element are capability-based, not variants: Button is the real <button> (square via iconOnly), IconButton is the dedicated icon control with its own guard, LinkButton is the text-shaped one — any of them renders <a> when href is present.

<Button>Save</Button>                              {/* primary brand */}
<Button tone="negative" leadingIcon={<Trash2 size={16} />}>Delete</Button>
<Button variant="secondary" tone="neutral" size="sm">Cancel</Button>
<Button isLoading>Saving…</Button>                 {/* width-preserving overlay */}
<IconButton icon={Settings} accessibilityLabel="Settings" />
<LinkButton href="/docs">Docs</LinkButton>

isDisabled || isLoading derives the real disabled state; loading keeps the button's width, sets aria-busy, and pins an explicit spinner colour (the disabled ink would be invisible on a primary fill).

The three tiers

  1. Tier 1 — global primitives (--global-*): immutable, mode-agnostic ramps and scales. Color: gray/gray-dark neutrals plus brand and 8 hue families, each a 50→1000 ramp with the pre-existing system hue as its 600 anchor, plus alpha ramps (brand-a12 = brand at 12%). Typography: raw sizes/weights/line-heights and the two family stacks. Components never consume this tier.
  2. Tier 2 — semantic aliases: the API components use. Color grammar is --{property}-{role}-{variant} (e.g. --background-brand-default, --text-primary, --border-negative-subtle) — every value a var() over Tier 1, zero literals. Dark mode is one [data-theme='dark'] block in tokens/colors/semantic.css that re-points the mode-dependent tokens (primitives never change). Solid chromatic steps follow one rule: default = 600, hover = 500, active = 700. Spacing (--spacing-16 is 16px), radius, borders, shadows, motion, z-index, and icon sizes are single-layer semantic scales in tokens/globals/.
  3. Tier 3 — composed text styles: PascalCase classes (.BodySmallMedium, .HeadingMedium, .CodeSmall) bundling family/size/weight/line-height from Tier 2 — apply the class instead of composing font vars.

Usage

CSS — import the single entry point and use Tier 2 --* variables:

@import './src/styles/index.css';

.card {
  background: var(--background-surface-default);
  color: var(--text-neutral-normal);
  border: var(--border-width-thin) solid var(--border-neutral-default);
  border-radius: var(--radius-m);
  padding: var(--spacing-16);
  box-shadow: var(--shadow-s);
  font-family: var(--font-family);
}

React — load fonts once, wrap the app, toggle themes:

import './src/fonts';
import { ThemeProvider, useTheme } from './src';

function ThemeToggle() {
  const { theme, setPreference } = useTheme();
  return (
    <button onClick={() => setPreference(theme === 'dark' ? 'light' : 'dark')}>
      {theme}
    </button>
  );
}

<ThemeProvider>
  <App />
</ThemeProvider>;

Motion — CSS-only. The vocabulary is Razorpay Blade's motion scale, verbatim (--global-duration/delay/easing-* in tokens/globals/motion.css); components consume the tokens directly and own their animations locally:

.button {
  transition:
    color var(--global-duration-xquick) var(--global-easing-standard),
    background-color var(--global-duration-xquick) var(--global-easing-standard);
}

.tooltip--in {
  /* entrances decelerate; exits run one rung faster on easing-exit */
  animation: tooltip-in var(--global-duration-xquick) var(--global-easing-entrance);
}

Micro-interactions run xquick/standard and never exceed moderate (280ms); the gentler rungs are for large-surface/ambient motion (spinner = 2xgentle). Reduced motion is handled centrally in src/styles/motion.css (blanket guard, spinner exempted) — never add prefers-reduced-motion queries in components. A JS animation library is deliberately not a dependency; if a future component needs springs or layout animation, derive its presets from the motion tokens rather than inventing new values.

Dependencies

Nothing is bundled — everything below is a peer dependency the consumer installs. See peerDependencies in package.json and the rationale table in ROADMAP.md.

| Peer | Required? | Used by | | --- | --- | --- | | react, react-dom, lucide-react | required | everything | | @floating-ui/react | required | Tooltip, Popover, DropdownMenu (+submenus), Modal, Drawer, and BaseInput's in-field overlays (SelectInput/AutoComplete). Toast deliberately doesn't use it — the stack is plain position: fixed | | @dnd-kit/core, @dnd-kit/sortable, @dnd-kit/modifiers | optional | drag/sortable; nothing imports these yet |

Layering stays ours: the --z-* ladder in display.css is the only source of z-index — Floating UI has no opinion there, so never hand-pick one in component CSS.

Provenance

The Figma file carries 34 variables in a single, light-only mode. All of them are reproduced 1:1. Everything else was filled from Obsidian's official default-theme values (user-approved), since the file's values match Obsidian's published design system exactly. Where both sources define a value, Figma wins (e.g. the accent #9478F0).

| Token group | From Figma | Filled from Obsidian defaults | | --- | --- | --- | | Neutral ramp | 12-step structure from Figma | Both ramps re-tinted toward the brand (hue 226, 2–7% blend toward #2F55D4 — "hint of blue", user decision); dark steps from Obsidian, same treatment | | Hues | orange, yellow, cyan, blue, purple, pink from Figma | red #DC2626 / green #16A34A = Tailwind red-600/green-600 (shadcn destructive + success; user decision — Figma's read too pink/minty), hover/active = the 500/700 scale steps | | Accent | --text-on-accent #FFFFFF | brand color #2F55D4 (user decision — overrides Figma's --interactive-accent #9478F0); hover #4163D9 (derived, +4% lightness); focus ring = brand at 24% alpha (40% in dark) | | Semantic colors | --text-faint, --divider-color, --background-secondary, --tab-container-background, --tab-outline-color, --icon-color | background-primary(-alt), background-sidebar (shadcn sidebar surface, user decision), text-normal/muted, interactive-normal/hover, all dark-mode mappings | | Spacing | 2-1, 4-1, 4-2, 4-3, --input-height | 2-2, 2-3, 4-44-18 | | Typography | Inter, 12px (--font-ui-smallerxs), semibold 600 | t-shirt size scale xs 12 / sm 14 / base 16 / lg 20 / xl 24 / 2xl 30 (user decision — replaced Obsidian's near-identical UI sizes 13/15); weights, line-heights; mono stack added per user decision (JetBrains Mono originally; switched to Geist Mono 2026-07 for Inter pairing + density) | | Radius | — | s 4 / m 8 / l 12 / xl 16 | | Shadows | — | shadow-s / shadow-l, light + dark | | Status colors | hues (fg) from Figma | tinted bg/border (rgba of the hues, per-mode alpha) | | Interaction states | — | active surfaces, focus ring (Design-SDK stacked box-shadow: 2px surface gap + 3px translucent brand ring, uniform system-wide), disabled opacity 0.5 (shadcn), overlay scrim; background-modifier-hover/-active alpha fills (pattern from the falcon-auth-redesign reference, mapped to our palette) | | Icon sizes | — | 12/14/16/20/24px per shadcn conventions (size-3size-6, default size-4) | | Z-index | — | dropdown 1000 → tooltip 1600 | | Motion | — | Blade's duration/delay/easing scale verbatim, consumed directly; per-component animations | | Fonts | — | self-hosted via @fontsource-variable/inter + @fontsource-variable/geist-mono (src/fonts.ts) |