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

@asnewyla/theme

v0.2.0

Published

Multi-brand theming — a ThemeProvider that scopes @asnewyla/tokens' CSS custom properties via a data-theme attribute on the document root

Readme

@asnewyla/theme

Multi-brand theming for @asnewyla/* components — a ThemeProvider that switches the active --xd-* token set at runtime.

Install

npm install @asnewyla/theme

Usage

Import the theme stylesheets you want to offer (see @asnewyla/tokens), then wrap your app:

import '@asnewyla/tokens/theme-paper.css';
import '@asnewyla/tokens/theme-sand.css';
import '@asnewyla/tokens/theme-lavender.css';
import { ThemeProvider } from '@asnewyla/theme';

function App() {
  const [theme, setTheme] = useState<'paper' | 'sand' | 'lavender'>('paper');
  const [mode, setMode] = useState<'light' | 'dark'>();

  return (
    <ThemeProvider theme={theme} mode={mode}>
      <YourApp />
    </ThemeProvider>
  );
}

theme and mode are independent — use either alone, both together, or neither. Leaving mode unset (the default) lets prefers-color-scheme drive light/dark automatically; leaving theme unset lets whichever theme's bare fallback (or @asnewyla/tokens/tokens.css) apply.

Props

| Prop | Type | Default | |---|---|---| | theme | string | — (unset: no theme override) | | mode | 'light' \| 'dark' | — (unset: follows prefers-color-scheme) | | children | React.ReactNode | — (required) |

theme is a plain string, not a union of the example theme names above — @asnewyla/theme has no knowledge of which themes exist. It just sets whatever value you give it as data-theme on <html>; the theme names themselves are defined entirely by whichever --xd-* stylesheets you import (@asnewyla/tokens's or your own). mode is a real union, since every @asnewyla/tokens theme file only ever matches data-mode="light" or "dark" — anything else would silently match nothing.

How it works

ThemeProvider doesn't render a wrapping element — it sets data-theme and data-mode on document.documentElement (<html>) via two independent effects, one per prop, each removing its own attribute on unmount. Setting data-theme/data-mode on <html> (not a wrapping <div>) is deliberate: CSS custom property inheritance follows the real DOM tree, not the React tree, so a component that renders through a portal (a future Dialog, Select, Toast, mounted straight into document.body) sits outside ThemeProvider's own JSX position but still under <html> — only an attribute on the document root reliably reaches it.

Leaving theme or mode unset doesn't set a default value for that attribute — it removes the attribute entirely, so the underlying CSS's own fallback (a bare :root:not([data-theme]) block, or prefers-color-scheme for mode) takes over. A default of, say, mode="light" would permanently defeat automatic dark-mode detection for every consumer, since @asnewyla/tokens' dark-mode blocks are scoped :not([data-mode="light"]) specifically so the OS preference keeps working until someone explicitly opts into a mode.

Switching either prop updates its attribute on the next render; React runs the previous effect's cleanup before the new one, so there's no flash of an unset attribute in between.

License

MIT