Foundations
FoundationsTier 2 · Primitives
cn()
The class merger, configured for Woohl's custom utilities.
bunx --bun shadcn@latest add @woohl/utilsReference
Installs this item, its registry dependencies and the token layer.
bunx --bun shadcn@latest add @woohl/utilsregistry/tier-2-primitives/lib/utils.ts
import { clsx, type ClassValue } from "clsx";
import { extendTailwindMerge } from "tailwind-merge";
/** Extended tailwind-merge instance aware of Woohl custom scales and tokens. */
const twMerge = extendTailwindMerge<
"woohl-motion" | "woohl-eyebrow" | "woohl-shell" | "woohl-measure"
>({
extend: {
theme: {
radius: ["pill"],
shadow: ["hairline", "e1", "e2", "e3", "focus"],
/* The `--container-*` namespace, which is what `max-w-*` reads. */
container: ["woohl", "prose"],
font: ["ui", "editorial", "serif", "mono", "display", "script"],
ease: ["out-woohl", "in-out-woohl", "spring"],
text: [
// Product scale
"display",
"h1",
"h2",
"h3",
"body-lg",
"body",
"label",
"caption",
"eyebrow",
// Editorial scale
"editorial-display",
"editorial-headline",
"editorial-title",
"editorial-lead",
"editorial-body",
"editorial-eyebrow",
"editorial-numeral",
"editorial-quote",
],
},
classGroups: {
/* tokens/motion.css — a duration and its easing, together. */
"woohl-motion": [
"motion-instant",
"motion-fast",
"motion-base",
"motion-slow",
"motion-deliberate",
],
/* tokens/motion.css — the keyframe utilities. Placed in Tailwind's own
`animate` group so `animate-none` still clears them. */
animate: [
"animate-woohl-fade",
"animate-woohl-rise",
"animate-woohl-scale-in",
"animate-woohl-shimmer",
"animate-woohl-spin",
],
/* tokens/z-index.css — named layers, in Tailwind's `z` group so they
conflict correctly with `z-10` and `z-auto`. */
z: [
"z-raised",
"z-sticky",
"z-dropdown",
"z-overlay",
"z-modal",
"z-popover",
"z-toast",
"z-tooltip",
],
/* tokens/typography.css — the eyebrow sets size, tracking, weight and
case in one class, so it genuinely fights a font-size utility. */
"woohl-eyebrow": ["eyebrow", "eyebrow-editorial"],
/* tokens/breakpoints.css — the page shell. */
"woohl-shell": ["woohl-container"],
"woohl-measure": ["measure"],
"bg-color": ["surface-warm"],
},
conflictingClassGroups: {
"woohl-eyebrow": ["font-size", "tracking"],
"font-size": ["woohl-eyebrow"],
"woohl-measure": ["max-w"],
"max-w": ["woohl-measure"],
},
},
});
export type { ClassValue };
export function cn(...inputs: ClassValue[]): string {
return twMerge(clsx(inputs));
}
This item exports no props — it is a stylesheet, a helper or a set of constants.
Registry items
npm packages
- clsx
- tailwind-merge