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

@gospore/theme

v1.0.165

Published

Provides the base styling primitives for the entire Design System: a Vue `<Theme>` component that toggles dark/light mode, runtime helpers for storing the preferred mode, a `<ThemeSwitcher>` dropdown, and the compiled token bundle (`theme.css`) that expos

Readme

@gospore/theme

Provides the base styling primitives for the entire Design System: a Vue <Theme> component that toggles dark/light mode, runtime helpers for storing the preferred mode, a <ThemeSwitcher> dropdown, and the compiled token bundle (theme.css) that exposes colors, typography, spacing, elevation, etc.

Loading tokens

Import the bundled CSS once near your app entry point so the shared tokens and dark-mode rules are available to every component:

// main.ts
import "@gospore/theme/theme.css";

Preventing a light first frame

Apps that let users persist dark mode should install the theme bootstrap before their other Vite plugins:

// vite.config.ts
import { createThemeBootstrapPlugin } from "@gospore/theme";
import { defineConfig } from "vite";

export default defineConfig({
    plugins: [createThemeBootstrapPlugin()],
});

The plugin injects a synchronous script and the critical canvas colors into the document head. It applies the same persisted auto, light, or dark contract as <Theme> before application modules execute, preventing a light frame while a dark application initializes. Keep <Theme> mounted as usual so it owns subsequent system-mode changes and animated mode transitions.

Theme component

<script setup>
import { Theme } from "@gospore/theme";
</script>

<Theme mode="auto" accent-color="#0052CC">
    <App />
</Theme>

<Theme> listens for system changes, reads the persisted mode, exposes a theme provide/inject value, and toggles the global dark-mode attribute so all Design System components react automatically.

When more than one independent provider is mounted, the most recently mounted <Theme> owns the global attribute. A nested provider without an explicit mode inherits its parent and does not take global ownership, which keeps accent-only theme layers synchronized with the application shell. A nested provider can opt into ownership with an explicit mode; removing that prop or unmounting it restores the previous provider. Unmounting the last global owner restores the document attribute that existed before the first provider mounted.

Rendered brand tones can differ from the raw accentColor input. Theme-generated semantic surface / on-surface pairs and canvas-facing brand text, icons, and borders maintain at least WCAG AA 4.5:1 contrast in light and dark modes; the default blue aliases follow the same contract. Accent roles are also explicit: --color-text-accent-<color>-<strength>-* is same-hue text for the normal application surface, while --color-on-accent-<color>-<strength>-* is the contrast-safe foreground for the matching --color-background-accent-* surface. The available ramps do not provide a same-hue AA foreground for most accent surfaces, so the paired on-accent tokens preserve the accent in the surface and choose a mode-appropriate neutral foreground. --color-text-subtle-* and --color-text-subtler-* use distinct accessible neutral steps so their hierarchy does not depend on low-contrast text.

The neutral ramps use eased OKLCH lightness rather than equal numeric jumps. This keeps adjacent steps perceptually ordered while giving the middle roles stable contrast targets: neutral 600 is suitable for meaningful UI graphics, 700 is low-emphasis AA text on the normal application surface, and 800 is the stronger secondary foreground. Component placeholders use their package theme tokens mapped to 800, because they also need to remain readable on interactive input surfaces; base-surface details such as adjacent-month calendar dates can use 700.

Status colors follow the same paired-token rule. Use --color-text-<status>-* for status-colored copy on the normal application surface. When text is rendered on a matching status background, use its --color-<status>-on-soft-* or --color-<status>-on-strong-* foreground instead. Interactive warning and danger soft surfaces expose hovered and pressed foregrounds matching their background states. Component packages map these semantic pairs through their own component tokens instead of choosing palette colors in component styles. Foreground-only UI such as required markers follows the same rule: component tokens map to --color-text-danger-*, never to a background token used as text. Component implementations consume those package-level tokens; direct global color references belong in each component's theme.css, so themes can adapt a component without overriding its implementation selectors.

Brand semantics are now role-based (surface, on-surface, border). Do not rely on --color-brand-100..1000 as stable UI meaning tokens.

Brand Token Showcase Example

The Theme Playground includes an interactive brand-token example. You can change accentColor live and inspect:

  • The resulting semantic brand tokens (surface, on-surface, border) plus legacy tokens (--color-brand-100..1000).
  • How multiple components (Keyword, Button, Tabs, AvatarItem) consume those tokens.

Note: The live components follow the currently active global mode (dark-mode). The token list still shows both light and dark token values.

Theme switcher

<script setup>
import { Theme, ThemeSwitcher } from "@gospore/theme";
import { ref } from "vue";

const mode = ref("auto");
</script>

<Theme :mode="mode">
    <ThemeSwitcher v-model:mode="mode" />
</Theme>

The switcher is a ready-made dropdown that persists the selected mode in a host-only, one-year SameSite=Lax cookie via the exported readStoredMode, writeStoredMode, and applyStoredModeToDocument helpers. HTTPS writes also set Secure. Host-only scope intentionally avoids leaking the preference to sibling subdomains and works on multi-level public suffixes without guessing a registrable domain. On the first write, the helper also expires the shared-domain cookie created by older releases before storing the host-only replacement. The switcher emits update:mode and updates <Theme> when you use it with v-model. Inside a <Theme>, the provider remains the sole owner of the global mode attribute; the switcher only persists and emits the selection. A standalone switcher continues to apply the selected mode directly for backwards compatibility.

ThemeSwitcher composes @gospore/dropdown-menu + DropdownItemRadio, so import @gospore/dropdown-menu/dropdown-menu.css, @gospore/button/button.css, and @gospore/radio/radio.css alongside the theme tokens when you mount it.

Utility files

  • Token source files live under src/ (basic.less, styles.less, colors.css, fonts.css, sizing.css, elevation.css, transitions.css, borders.css, layering.css). They are bundled into theme.css; when contributing inside this repo you can import the individual files as needed.
  • modeStorage.js: helpers for reading/writing the current theme mode.

Accessibility & motion

Theme respects the prefers-reduced-motion media query when animating dark / light transitions. When users prefer reduced motion, the provider's transition happens without a fade. Components may use short, property-scoped color transitions for interaction feedback, so those properties can briefly interpolate during a theme change. Accessibility and contrast contracts apply to the settled light and dark modes.