@mounaji_npm/tokens
v0.4.2
Published
Design token schema, CSS variable injector, and React context for Mounaji components
Downloads
1,066
Maintainers
Readme
@mounaji_npm/tokens
Design token schema, CSS variable injector, and React context for Mounaji components.
All other @mounaji_npm/* packages read their styling from the CSS variables this package injects. Override tokens once at the top of your app — every component reacts automatically.
Install
npm install @mounaji_npm/tokensReact 17+ is a peer dependency. The vanilla JS utilities (injectTokens, tokensToCSS, etc.) work without React.
Quick Start
React
import { TokensProvider, DEFAULT_TOKENS } from '@mounaji_npm/tokens';
export default function App() {
return (
<TokensProvider tokens={{ ...DEFAULT_TOKENS, colorPrimary: '#7C3AED' }}>
<YourApp />
</TokensProvider>
);
}Vanilla JS
import { injectTokens, DEFAULT_TOKENS } from '@mounaji_npm/tokens';
injectTokens({ ...DEFAULT_TOKENS, colorPrimary: '#7C3AED' });Exports
| Export | Type | Description |
|---|---|---|
| DEFAULT_TOKENS | object | Full default token schema (all keys + values) |
| TOKEN_CSS_MAP | object | Token key → CSS variable name (colorPrimary → --mn-color-primary) |
| TOKEN_GROUPS | object | Group + label metadata used by the token editor |
| injectTokens(tokens, rootEl?) | function | Inject CSS variables into the DOM. SSR-safe. |
| injectFontSources(sansUrl, monoUrl) | function | Load external font stylesheets (Google Fonts, etc.) into <head>. Idempotent. |
| removeTokens(rootEl?) | function | Remove all --mn-* CSS variables |
| mergeTokens(base, overrides) | function | Deep merge two token objects |
| tokensToCSS(tokens) | function | Returns a :root { --mn-... } CSS string |
| hexToHsl(hex) | function | Convert hex color to HSL — bridge for shadcn/Tailwind |
| TokensProvider | component | React context — injects tokens to :root on every change |
| useTokens() | hook | Full token state + updater methods |
| withTokens(Component) | HOC | Alternative to context for class components |
TokensProvider
Wrap your entire app (or a sub-tree) once.
import { TokensProvider } from '@mounaji_npm/tokens';
<TokensProvider
tokens={{ colorPrimary: '#3B82F6' }} // merged with DEFAULT_TOKENS
persist={true} // save overrides to localStorage
storageKey="my-app-tokens" // custom localStorage key
>
{children}
</TokensProvider>| Prop | Type | Default | Description |
|---|---|---|---|
| tokens | object | DEFAULT_TOKENS | Initial token values |
| persist | boolean | true | Persist changes to localStorage |
| storageKey | string | 'mn_tokens' | localStorage key |
useTokens
Access and mutate the token state from any component inside TokensProvider.
import { useTokens } from '@mounaji_npm/tokens';
function ThemePanel() {
const {
tokens, // current token values
updateToken, // (key, value) => void — single token
updateTokens, // (partial) => void — batch update
resetTokens, // () => void — reset to DEFAULT_TOKENS
saveTokens, // () => void — flush to localStorage now
loadTokens, // () => void — reload from localStorage
isDirty, // boolean — true if unsaved changes
} = useTokens();
return (
<div>
<input
type="color"
value={tokens.colorPrimary}
onChange={e => updateToken('colorPrimary', e.target.value)}
/>
<button onClick={resetTokens}>Reset</button>
</div>
);
}Token Schema
Tokens are organized into groups. All values are strings (CSS values).
Brand Colors
| Token | Default | CSS Variable |
|---|---|---|
| colorPrimary | #3B82F6 | --mn-color-primary |
| colorPrimaryHover | #60A5FA | --mn-color-primary-hover |
| colorAccent | #8B5CF6 | --mn-color-accent |
| colorAccentAlt | #22D3EE | --mn-color-accent-alt |
| colorSuccess | #10B981 | --mn-color-success |
| colorWarning | #F59E0B | --mn-color-warning |
| colorDanger | #EF4444 | --mn-color-danger |
Backgrounds (Dark / Light)
| Token | CSS Variable |
|---|---|
| colorBgDark | --mn-color-bg-dark |
| colorCardDark | --mn-color-card-dark |
| colorBgLight | --mn-color-bg-light |
| colorCardLight | --mn-color-card-light |
| colorNavDark | --mn-color-nav-dark |
| colorNavLight | --mn-color-nav-light |
Typography
| Token | Default |
|---|---|
| fontFamily | "Inter", system-ui, sans-serif |
| fontFamilyMono | "Fira Code", monospace |
| fontSourceUrl | '' (Google Fonts URL, injected into <head>) |
| fontSizeXs–fontSize4xl | 0.75rem–2.25rem |
Spacing
spacingXs → spacing3xl (maps to --mn-spacing-xs … --mn-spacing-3xl)
Border Radius
radiusSm → radiusFull (maps to --mn-radius-sm … --mn-radius-full)
Shadows
shadowSm, shadowMd, shadowLg, shadowGlowBlue, shadowGlowPurple
Animation
durationFast, durationNormal, durationSlow, easingDefault
Vanilla JS Utilities
import {
injectTokens, removeTokens, mergeTokens, tokensToCSS, hexToHsl,
DEFAULT_TOKENS, TOKEN_CSS_MAP,
} from '@mounaji_npm/tokens';
// Inject tokens into a specific element (not :root)
const el = document.querySelector('#widget-root');
injectTokens({ colorPrimary: '#FF5733' }, el);
// Merge partial overrides onto defaults
const myTokens = mergeTokens(DEFAULT_TOKENS, { colorPrimary: '#FF5733' });
// Export as CSS string (useful for SSR or style injection)
const css = tokensToCSS(myTokens);
// → ":root { --mn-color-primary: #FF5733; ... }"
// Convert hex to HSL for Tailwind CSS variable compatibility
const hsl = hexToHsl('#3B82F6'); // → "217 91% 60%"
// Load Google Fonts
import { injectFontSources } from '@mounaji_npm/tokens';
injectFontSources(
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap',
'https://fonts.googleapis.com/css2?family=Fira+Code&display=swap',
);
// Clean up
removeTokens(); // removes from :root
removeTokens(el); // removes from specific elementUsing CSS Variables in Stylesheets
Once tokens are injected, reference them in any CSS file or inline style:
.my-card {
background: var(--mn-color-card-dark);
color: var(--mn-color-text-primary-dark);
border: 1px solid var(--mn-color-border-dark);
border-radius: var(--mn-radius-md);
padding: var(--mn-spacing-md);
box-shadow: var(--mn-shadow-md);
font-family: var(--mn-font-family);
transition: background var(--mn-duration-normal) var(--mn-easing-default);
}
.my-button {
background: var(--mn-color-primary);
font-size: var(--mn-font-size-base);
}SSR / Next.js Notes
injectTokens is guarded with typeof document === 'undefined' — it is safe to import on the server. For Next.js App Router, place TokensProvider in a 'use client' component:
// app/providers.jsx
'use client';
import { TokensProvider } from '@mounaji_npm/tokens';
export function Providers({ children }) {
return <TokensProvider>{children}</TokensProvider>;
}
// app/layout.js
import { Providers } from './providers';
export default function RootLayout({ children }) {
return <html><body><Providers>{children}</Providers></body></html>;
}To avoid FOUC (flash of unstyled content), you can pre-inject tokens via tokensToCSS in a <style> tag rendered server-side:
import { tokensToCSS, DEFAULT_TOKENS } from '@mounaji_npm/tokens';
export default function RootLayout({ children }) {
return (
<html>
<head>
<style>{tokensToCSS(DEFAULT_TOKENS)}</style>
</head>
<body>{children}</body>
</html>
);
}