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

skcr-design-tokens

v1.4.0

Published

Design system SkillCorner : tokens de couleur, utilitaires typographiques et classes de composants. CSS pur, sans dépendance.

Readme

skcr-design-tokens

The SkillCorner design system, in pure CSS with no dependency: color tokens, typographic utilities and component classes. Single source for the platform's applications, and the rendering contract of the skcr-autechre component library.

No dependency, no build: the package publishes the .css files as they are. It is therefore consumable by any front end — Angular, React or vanilla.

Installation

npm install skcr-design-tokens

In the application's styles.css (or styles.scss):

@import 'tailwindcss';
@import 'skcr-design-tokens/tokens.css';
@import 'skcr-design-tokens/utilities.css';
@import 'skcr-design-tokens/components.css';

Applications consuming skcr-autechre

Tailwind does not scan node_modules. The classes the library components write in their templates would therefore never be generated, and the styles would be missing with no error to signal it. One line is enough:

@source '../node_modules/skcr-autechre/fesm2022/*.mjs';

The path targets the built JavaScript, where ng-packagr has inlined the templates: that is where the classes live in the published package.

Light / dark theme

The attribute goes on <html>, never on <body>. Tailwind emits its @theme block in :root, that is on <html>; and a custom property is substituted at the element where it is declared. An override placed on <body> would be invisible to the utilities, which would inherit a value already resolved with the light palette — hand-written colors would flip, Tailwind classes would not.

To avoid any flash on load, the attribute must be set before the first paint. No application mechanism can do it: an Angular initializer runs after the first render. Paste this script into index.html, in the <head>:

<script>
  try {
    document.documentElement.dataset.theme = localStorage.getItem('skcr-theme') || 'light';
  } catch {
    document.documentElement.dataset.theme = 'light';
  }
</script>

Angular applications then use skcr-autechre's ThemeService for toggling and cross-tab synchronization. It does not do the initialization: the script above has already done it.

Contents

| Entry | Contents | | --- | --- | | tokens.css | @theme block: primary, neutral, status and dataviz colors, and font families | | utilities.css | text-body-*, text-caption, info-caption, title-one to title-five | | components.css | .btn family, .badge family, .link, .step-number, hover tooltip, scrollbar utilities, Angular Material date-picker fix | | display.css | Opt-in. Presentation classes. No platform application imports it. |

What stays in the application

Three categories do not move up here, deliberately:

  • The @font-face declarations. Shentox is a commercial font: redistributing it in a public npm package would be a license violation. The package declares the family (--font-title), the application provides the files.
  • The global resets. html, body { height: 100vh; overflow: hidden } is a single-page-application decision, not a design decision.
  • Domain tokens. --color-tactical: a business concept that serves a single application. The --color-tooltip-* tokens, on the other hand, do belong here: the tooltip is a library component, not an application concept.

Zones and states

A distinction to know before writing a class, because ignoring it produces a defect that is invisible in the light theme.

A zone token describes a surface: card, popover, muted, track. A state token describes what happens to a surface when you interact with it: hover for hovering, primary-subtle for selection, disabled.

The temptation is to express a state with a zone — writing hover:bg-muted because the grey looks right. It works in light and breaks in dark, because a state must move relative to its surface: a hover darkens on a light ground and lightens on a dark one. A zone has an absolute value. The real case: muted was exactly equal to popover in dark, and every hover:bg-muted on a menu was strictly invisible — a contrast ratio of 1.00.

The three states read in this order, in both themes:

| On a popover | rest | hover | primary-subtle | | --- | --- | --- | --- | | light | 1.00 | 1.10 | 1.17 | | dark | 1.00 | 1.41 | 2.05 |

Selection is therefore always more pronounced than hover. If you add a state, measure it against the surface that carries it, not in the absolute.

Extension rules

The distinction is sharp, and it is what keeps the design system from re-diverging the way it did across the three applications:

Overriding a value is free. An application may redefine any token in its own styles.css, after the @import lines:

:root {
  --color-primary: #0f766e;
}

This is the dark theme's mechanism, and it is what lets a project repaint itself without forking the package. The contract stays the same, only the values change.

Defining a utility is not. Adding an @utility, a .btn-* class or a presentation class in an application's styles.css is forbidden: that is exactly how .btn-icon ended up in a single application, and how the .btn family diverged on five points. A new definition goes through a merge request on this package.

Adding to display.css. This is the file meant for new needs, in particular those of projects with no validated design. It targets vibe-coded projects, to which it gives a uniform facade; the platform applications have their own needs, decided by product design, and do not import it. Three rules:

  1. A class only uses tokens from tokens.css. No hard-coded color — that is what guarantees it will follow the dark theme with no rework.
  2. A class never redefines a class from the base. When in doubt about a name, check components.css.
  3. Do not write for the base. These classes are not meant to move up into it: this is not an antechamber. If one were ever to serve a component-based application, that would be an explicit, exceptional decision, not a drift.

The catalog (1.4.0, from the sapinadmin audit of 2026-09-02 and the mutualisation pass of 2026-09-10) covers eight families: surfaces (.card, .card-flush/-header/-body/-title, .card-header-toggle, .collapsible), data (.stat*, .kv*, .table*, .progress*, .dot*, .code, .code-block, .output), tags (.eyebrow, .chip, .counter), forms (.field-label, .field-hint, .input, .switch, .segmented), navigation (.tabs/.tab, .menu/.menu-item, .nav-item), feedback (.callout*, .empty*, .loader, .skeleton, .toast*), overlay (.modal-*) and avatar (.avatar*). The class carries the look; the state (.active, aria-selected, [open], :checked) stays in the project's JS. One name is reserved: never .spinner — it collides with the encapsulated spinner of skcr-submit-button; the loading class is named .loader. Three surface nuances are worth knowing: .card-body stacks — it is flex flex-col, and the caller adds the gap-* — because 19 of the first consumer's 24 card bodies were adding that column by hand, with the consequence that a bare <span> or <a> dropped straight into a body is blockified and spans its full width, so wrap it when the hit area or a background has to stop at the text; .card-header carries NO cursor — a header that actually collapses its card adds .card-header-toggle on a <button> — and .collapsible wraps the body to unfold it with a transition instead of a jump, the content staying mounted (a panel whose content must unmount keeps an @if inside the region, and a collapsed region takes inert). The doc's "Display" page (npm run doc) renders every family in both themes.