@framework-cwf/tokens
v0.2.6
Published
Design tokens (colour, spacing, type, radius, shadow scales) + Tailwind v4 preset materialised from website-config.marketing.brand.
Readme
@framework-cwf/tokens
Design-token scales (colour, spacing, type, radius, shadow) plus a Tailwind v4
preset generator that materialises a per-business @theme block from the
marketing.brand block of a published website-config.
Installation
Published to GitHub Packages under the @framework-cwf scope. Consumers need an
.npmrc pointing the scope at the GitHub Packages registry plus an auth token:
@framework-cwf:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}pnpm add @framework-cwf/tokensQuick example
import { buildTailwindConfig } from "@framework-cwf/tokens";
import type { Brand } from "@framework-cwf/contracts";
const brand: Brand = {
embedVariant: "classic",
primaryColor: "#2d4a3e",
bgColor: "#efebe2",
accentColor: "#b8845a",
headingFont: "Playfair Display",
bodyFont: "Inter",
cornerRadius: 12,
density: "comfortable",
};
const { css, theme } = buildTailwindConfig(brand);
// `css` is the canonical Tailwind v4 `@theme { ... }` block — drop into
// your app's globals.css between `@import "tailwindcss";` and your layers.
// `theme` is the structured JS mirror for Storybook decorators / snapshot
// tests / tooling that can't read CSS.The emitted @theme block exposes shaded ramps as --color-primary-{50..950},
--color-accent-{50..950} and --color-gray-{50..950}, so utilities like
bg-primary-500, text-accent-300 and rounded-md resolve as expected.
Public API
| Export | Purpose |
| ----------------------- | ------------------------------------------------------------------------------------------- |
| buildTailwindConfig | Brand → { css, theme }. The function this package exists for. |
| buildBrandShades | One hex → 11-stop OKLCH-ramped scale. Useful standalone in admin previews / Storybook docs. |
| defaultTokens | Brand-agnostic scaffold (gray scale, spacing, type, radius, shadow). |
| contrastRatio | WCAG contrast ratio between two hexes. Built on the relativeLuminance helper exported |
| | by @framework-cwf/contracts — single source of truth, do not re-import another lib. |
| passesAaBodyText | Convenience: contrast ≥ 4.5:1. |
| hexToOklch / oklch… | Colour-space utilities (parse, ramp, gamut-map). |
| InvalidHexColorError | Typed error thrown by every public function that takes a hex. |
The Brand input type is re-exported from @framework-cwf/contracts for
one-stop access; the canonical definition lives in the contracts package.
How the shade ramp works
Each brand hex (primaryColor, accentColor) is parsed into OKLCH, then 11
shades are generated by ramping lightness along a Tailwind-calibrated curve
while preserving hue. Chroma is tapered at the extremes (factor 0.18 at stop
50, 0.35 at stop 950) so the lightest and darkest stops don't read as
fluorescent or as crushed black. When the requested OKLCH falls outside the
sRGB gamut, chroma is binary-searched down until it fits — hue and lightness
are preserved at the cost of saturation, matching CSS Color Module 4's
"preserve hue" gamut-mapping algorithm.
OKLab matrices are from Björn Ottosson's 2020 A perceptual color space for image processing.
