@latty-ds/tokens 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/dist/configure.d.ts +74 -31
- package/dist/configure.js +58 -23
- package/dist/tokens.css +1 -1
- package/dist/tokens.js +1 -1
- package/dist/tokens.json +1 -1
- package/dist/types/public-types.d.ts +60 -13
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -116,17 +116,17 @@ console.log(tokens.elevation['2']); // "0 4px 6px -1px rgb(…)"
|
|
|
116
116
|
|
|
117
117
|
### Primitive tokens (`tokens.css`)
|
|
118
118
|
|
|
119
|
-
| Prefix | Example | Description
|
|
120
|
-
| --------------------------------------- | ------------------------------ |
|
|
121
|
-
| `--lt-color-[name]-[step]` | `--lt-color-primary-500` | Color palette steps 50–900
|
|
122
|
-
| `--lt-color-[name]-muted-[step]` | `--lt-color-primary-muted-300` | Desaturated variant of each color
|
|
123
|
-
| `--lt-color-neutral-[step]` | `--lt-color-neutral-100` | Greyscale scale
|
|
124
|
-
| `--lt-color-white` / `--lt-color-black` | | System colors
|
|
125
|
-
| `--lt-spacing-[n]` | `--lt-spacing-4` → `1rem` | Spacing scale (rem), n = 0–24
|
|
126
|
-
| `--lt-spacing-px-[n]` | `--lt-spacing-px-4` → `16px` | Spacing scale (px)
|
|
127
|
-
| `--lt-border-radius` | `0.5rem` | Global border radius
|
|
128
|
-
| `--lt-elevation-[n]` | `--lt-elevation-2` | Box shadows, n = 0–5
|
|
129
|
-
| `--lt-typography-
|
|
119
|
+
| Prefix | Example | Description |
|
|
120
|
+
| --------------------------------------- | ------------------------------ | -------------------------------------------------------------------------- |
|
|
121
|
+
| `--lt-color-[name]-[step]` | `--lt-color-primary-500` | Color palette steps 50–900 |
|
|
122
|
+
| `--lt-color-[name]-muted-[step]` | `--lt-color-primary-muted-300` | Desaturated variant of each color |
|
|
123
|
+
| `--lt-color-neutral-[step]` | `--lt-color-neutral-100` | Greyscale scale |
|
|
124
|
+
| `--lt-color-white` / `--lt-color-black` | | System colors |
|
|
125
|
+
| `--lt-spacing-[n]` | `--lt-spacing-4` → `1rem` | Spacing scale (rem), n = 0–24 |
|
|
126
|
+
| `--lt-spacing-px-[n]` | `--lt-spacing-px-4` → `16px` | Spacing scale (px) |
|
|
127
|
+
| `--lt-border-radius` | `0.5rem` | Global border radius |
|
|
128
|
+
| `--lt-elevation-[n]` | `--lt-elevation-2` | Box shadows, n = 0–5 |
|
|
129
|
+
| `--lt-typography-fontFamilyPrimary` | `"Hanken Grotesk", sans-serif` | Base font family (additional `...Secondary`/`...Tertiary` when configured) |
|
|
130
130
|
|
|
131
131
|
Color names: `primary`, `secondary`, `success`, `warning`, `error`, `info` (each with a `-muted` variant).
|
|
132
132
|
|
package/dist/configure.d.ts
CHANGED
|
@@ -4,27 +4,74 @@
|
|
|
4
4
|
* Any other CSS length (e.g. `'1.5px'`) passes through unchanged.
|
|
5
5
|
*/
|
|
6
6
|
type BorderWidth = 'thin' | 'medium' | 'thick' | (string & {});
|
|
7
|
+
/** Generic CSS font-family keyword used as the safety-net fallback if a CDN font fails to load. */
|
|
8
|
+
type FontFallback = 'sans-serif' | 'serif' | 'monospace' | 'cursive' | 'fantasy' | 'system-ui';
|
|
9
|
+
/**
|
|
10
|
+
* A single `font.family` entry: a plain CSS value, a Google Fonts CSS2 URL, or
|
|
11
|
+
* a URL paired with a custom generic fallback (default `'sans-serif'`) for
|
|
12
|
+
* when the derived family isn't sans-serif — e.g. a serif display font.
|
|
13
|
+
*/
|
|
14
|
+
type FontFamilyEntry = string | {
|
|
15
|
+
url: string;
|
|
16
|
+
fallback?: FontFallback;
|
|
17
|
+
};
|
|
7
18
|
interface LattyConfig {
|
|
8
19
|
/** Built-in names: primary, secondary, success, warning, error, info. Any additional name generates a new palette. */
|
|
9
20
|
colors?: Record<string, string>;
|
|
10
21
|
font?: {
|
|
11
22
|
/**
|
|
12
|
-
* A CSS `font-family` value (e.g. `'Inter, sans-serif'`),
|
|
13
|
-
*
|
|
14
|
-
* `'https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900&display=swap'`)
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
23
|
+
* A CSS `font-family` value (e.g. `'Inter, sans-serif'`), a Google Fonts
|
|
24
|
+
* CSS2 stylesheet URL (e.g.
|
|
25
|
+
* `'https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900&display=swap'`),
|
|
26
|
+
* a `{ url, fallback }` object, or an array of any of these. URLs get
|
|
27
|
+
* `@import`ed automatically and the family name is derived from the
|
|
28
|
+
* `family=` query param — no separate `<link>` tag needed. Stylesheet
|
|
29
|
+
* URLs from providers other than `fonts.googleapis.com` are still
|
|
30
|
+
* loaded, but since there's no reliable way to guess the family name
|
|
31
|
+
* from an arbitrary CDN, pass the resulting name as a plain value
|
|
32
|
+
* instead (or open an issue if there's a provider worth special-casing).
|
|
33
|
+
*
|
|
34
|
+
* A bare URL string always falls back to the generic `sans-serif` family
|
|
35
|
+
* if the font itself fails to load. Use the `{ url, fallback }` object
|
|
36
|
+
* form to pick a different generic fallback (e.g. `'serif'` for a serif
|
|
37
|
+
* display font):
|
|
38
|
+
* ```ts
|
|
39
|
+
* family: { url: 'https://fonts.googleapis.com/css2?family=Playfair+Display', fallback: 'serif' }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* When an array is passed, each entry maps to its own token in order —
|
|
43
|
+
* `--lt-typography-fontFamilyPrimary`, `...Secondary`, `...Tertiary`,
|
|
44
|
+
* etc. — rather than being combined into a single CSS fallback stack, so
|
|
45
|
+
* multiple fonts (e.g. a heading font and a body font) can each be
|
|
46
|
+
* referenced independently in your own CSS.
|
|
21
47
|
*/
|
|
22
|
-
family?:
|
|
48
|
+
family?: FontFamilyEntry | FontFamilyEntry[];
|
|
49
|
+
/**
|
|
50
|
+
* A single dedicated heading font, resolved to `--lt-typography-fontFamilyHeading`.
|
|
51
|
+
* `lt-text`'s heading/display variants (`h1`–`h6`, `display-*`) read this
|
|
52
|
+
* token automatically, falling back to `fontFamilyPrimary` when unset —
|
|
53
|
+
* the built-in way to do a two-typeface identity without manually
|
|
54
|
+
* rerouting `--lt-typography-fontFamilySecondary` via hand-written CSS.
|
|
55
|
+
*/
|
|
56
|
+
heading?: FontFamilyEntry;
|
|
23
57
|
};
|
|
24
58
|
border?: {
|
|
25
59
|
radius?: string;
|
|
26
60
|
width?: BorderWidth;
|
|
61
|
+
/**
|
|
62
|
+
* Shifts which neutral palette step `--lt-border-default`/`--lt-border-strong`/
|
|
63
|
+
* `--lt-border-subtle` resolve to. `'high'` moves them toward a bolder,
|
|
64
|
+
* higher-contrast step (darker in light mode, lighter in dark mode) without
|
|
65
|
+
* touching theme-switching machinery.
|
|
66
|
+
* @default 'default'
|
|
67
|
+
*/
|
|
68
|
+
contrast?: 'default' | 'high';
|
|
27
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Set to `'none'` to flatten every `--lt-elevation-N` token (box-shadow) to
|
|
72
|
+
* `none` in one call, instead of overriding each level individually.
|
|
73
|
+
*/
|
|
74
|
+
elevation?: 'none';
|
|
28
75
|
/**
|
|
29
76
|
* Controls which semantic token layer is emitted.
|
|
30
77
|
* - `'light'` (default) — light tokens only; ignores OS preference
|
|
@@ -45,30 +92,26 @@ declare const createStyleSheet: (userConfig?: LattyConfig) => string;
|
|
|
45
92
|
* Injects design tokens into the document as a `<style>` element.
|
|
46
93
|
* Call once at your app's entry point — before any components render.
|
|
47
94
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* `<
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* both `@import`s it and derives the font-family name for you, so no separate
|
|
55
|
-
* `<link>` tag is needed.
|
|
95
|
+
* `font.family` accepts a single value or an array. Each entry is either a
|
|
96
|
+
* plain CSS `font-family` value or a Google Fonts CSS2 stylesheet URL (which
|
|
97
|
+
* configure() `@import`s and derives the family name from automatically — no
|
|
98
|
+
* separate `<link>` tag needed). Array entries map to their own token in
|
|
99
|
+
* order — `--lt-typography-fontFamilyPrimary`, `...Secondary`, `...Tertiary`,
|
|
100
|
+
* etc. — so each font can be referenced independently in your own CSS.
|
|
56
101
|
*
|
|
57
102
|
* @example
|
|
58
103
|
* ```html
|
|
59
|
-
* <
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* </head>
|
|
71
|
-
* </html>
|
|
104
|
+
* <script type="module">
|
|
105
|
+
* import { configure } from '@latty-ds/tokens/configure';
|
|
106
|
+
* configure({
|
|
107
|
+
* colors: { primary: '#6366f1', secondary: '#f59e0b' },
|
|
108
|
+
* font: { family: [
|
|
109
|
+
* 'https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900;1,100..900&display=swap',
|
|
110
|
+
* 'Georgia, serif',
|
|
111
|
+
* ] },
|
|
112
|
+
* border: { radius: '0.375rem', width: 'medium' },
|
|
113
|
+
* });
|
|
114
|
+
* </script>
|
|
72
115
|
* ```
|
|
73
116
|
*/
|
|
74
117
|
declare const configure: (userConfig?: LattyConfig) => void;
|
package/dist/configure.js
CHANGED
|
@@ -172,7 +172,7 @@ var buildTokens = (cfg) => {
|
|
|
172
172
|
color = addSystemColors(color);
|
|
173
173
|
const spacing = buildSpacing();
|
|
174
174
|
const border = { radius: DEFAULT_BORDER_RADIUS, width: DEFAULT_BORDER_WIDTH };
|
|
175
|
-
const typography = {
|
|
175
|
+
const typography = { fontFamilyPrimary: DEFAULT_FONT_FAMILY };
|
|
176
176
|
const elevation = buildElevation(color.neutral);
|
|
177
177
|
return { color, spacing, border, typography, elevation };
|
|
178
178
|
};
|
|
@@ -239,6 +239,16 @@ var accessibleTextOn = (bgHex) => {
|
|
|
239
239
|
const darkContrast = (L + 0.05) / 0.059;
|
|
240
240
|
return whiteContrast >= darkContrast ? "color-white" : "color-neutral-900";
|
|
241
241
|
};
|
|
242
|
+
var BORDER_STEPS = {
|
|
243
|
+
light: {
|
|
244
|
+
default: { default: "200", strong: "400", subtle: "100" },
|
|
245
|
+
high: { default: "400", strong: "600", subtle: "300" }
|
|
246
|
+
},
|
|
247
|
+
dark: {
|
|
248
|
+
default: { default: "700", strong: "500", subtle: "800" },
|
|
249
|
+
high: { default: "500", strong: "300", subtle: "600" }
|
|
250
|
+
}
|
|
251
|
+
};
|
|
242
252
|
var buildLightSemanticTokens = (opts = {}) => {
|
|
243
253
|
const map = {};
|
|
244
254
|
map["text-default"] = "color-neutral-900";
|
|
@@ -263,9 +273,10 @@ var buildLightSemanticTokens = (opts = {}) => {
|
|
|
263
273
|
map[`bg-${v}`] = `color-${v}-500`;
|
|
264
274
|
map[`bg-${v}-subtle`] = `color-${v}-100`;
|
|
265
275
|
}
|
|
266
|
-
|
|
267
|
-
map["border-
|
|
268
|
-
map["border-
|
|
276
|
+
const lightBorderSteps = BORDER_STEPS.light[opts.borderContrast ?? "default"];
|
|
277
|
+
map["border-default"] = `color-neutral-${lightBorderSteps.default}`;
|
|
278
|
+
map["border-strong"] = `color-neutral-${lightBorderSteps.strong}`;
|
|
279
|
+
map["border-subtle"] = `color-neutral-${lightBorderSteps.subtle}`;
|
|
269
280
|
map["border-focus"] = "color-primary-200";
|
|
270
281
|
for (const v of VARIANTS) {
|
|
271
282
|
map[`border-${v}`] = `color-${v}-200`;
|
|
@@ -302,9 +313,10 @@ var buildDarkSemanticTokens = (opts = {}) => {
|
|
|
302
313
|
map[`bg-${v}`] = `color-${v}-500`;
|
|
303
314
|
map[`bg-${v}-subtle`] = `color-${v}-900`;
|
|
304
315
|
}
|
|
305
|
-
|
|
306
|
-
map["border-
|
|
307
|
-
map["border-
|
|
316
|
+
const darkBorderSteps = BORDER_STEPS.dark[opts.borderContrast ?? "default"];
|
|
317
|
+
map["border-default"] = `color-neutral-${darkBorderSteps.default}`;
|
|
318
|
+
map["border-strong"] = `color-neutral-${darkBorderSteps.strong}`;
|
|
319
|
+
map["border-subtle"] = `color-neutral-${darkBorderSteps.subtle}`;
|
|
308
320
|
map["border-focus"] = "color-primary-400";
|
|
309
321
|
for (const v of VARIANTS) {
|
|
310
322
|
map[`border-${v}`] = `color-${v}-700`;
|
|
@@ -320,6 +332,8 @@ var buildDarkSemanticTokens = (opts = {}) => {
|
|
|
320
332
|
var buildSemanticTokens = (mode = "light", opts = {}) => mode === "dark" ? buildDarkSemanticTokens(opts) : buildLightSemanticTokens(opts);
|
|
321
333
|
|
|
322
334
|
// src/configure/font.ts
|
|
335
|
+
var FONT_FAMILY_SLOT_NAMES = ["Primary", "Secondary", "Tertiary", "Quaternary"];
|
|
336
|
+
var fontFamilySlot = (index) => `fontFamily${FONT_FAMILY_SLOT_NAMES[index] ?? String(index + 1)}`;
|
|
323
337
|
var unwrapQuotes = (value) => {
|
|
324
338
|
const trimmed = value.trim();
|
|
325
339
|
const first = trimmed[0];
|
|
@@ -331,8 +345,10 @@ var unwrapQuotes = (value) => {
|
|
|
331
345
|
var isUrl = (value) => /^https?:\/\//i.test(value);
|
|
332
346
|
var namesFromFamilyParam = (raw) => raw.split("|").map((part) => part.split(":")[0].trim()).filter(Boolean);
|
|
333
347
|
var quoteIfNeeded = (name) => /\s/.test(name) ? `"${name}"` : name;
|
|
334
|
-
var
|
|
335
|
-
const
|
|
348
|
+
var resolveSingleFont = (entry) => {
|
|
349
|
+
const rawValue = typeof entry === "string" ? entry : entry.url;
|
|
350
|
+
const fallback = typeof entry === "string" ? "sans-serif" : entry.fallback ?? "sans-serif";
|
|
351
|
+
const unwrapped = unwrapQuotes(rawValue);
|
|
336
352
|
if (!isUrl(unwrapped)) return { family: unwrapped, importUrl: null };
|
|
337
353
|
let parsed;
|
|
338
354
|
try {
|
|
@@ -343,11 +359,12 @@ var resolveFontFamily = (value) => {
|
|
|
343
359
|
if (parsed.hostname.toLowerCase() === "fonts.googleapis.com") {
|
|
344
360
|
const names = [...new Set(parsed.searchParams.getAll("family").flatMap(namesFromFamilyParam))];
|
|
345
361
|
if (names.length > 0) {
|
|
346
|
-
return { family: `${names.map(quoteIfNeeded).join(", ")},
|
|
362
|
+
return { family: `${names.map(quoteIfNeeded).join(", ")}, ${fallback}`, importUrl: unwrapped };
|
|
347
363
|
}
|
|
348
364
|
}
|
|
349
365
|
return { family: "", importUrl: unwrapped };
|
|
350
366
|
};
|
|
367
|
+
var resolveFontFamilies = (value) => (Array.isArray(value) ? value : [value]).map(resolveSingleFont);
|
|
351
368
|
|
|
352
369
|
// tokens.config.json
|
|
353
370
|
var tokens_config_default = {
|
|
@@ -377,12 +394,23 @@ var resolveBorderWidth = (width) => BORDER_WIDTH_PRESETS[width] ?? width;
|
|
|
377
394
|
var createStyleSheet = (userConfig = {}) => {
|
|
378
395
|
const cfg = toInternalConfig(userConfig);
|
|
379
396
|
let tokens = buildTokens(cfg);
|
|
380
|
-
|
|
397
|
+
const importUrls = [];
|
|
381
398
|
if (userConfig.font?.family) {
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
399
|
+
const resolvedFonts = resolveFontFamilies(userConfig.font.family);
|
|
400
|
+
const typographyOverrides = {};
|
|
401
|
+
resolvedFonts.forEach((font, i) => {
|
|
402
|
+
if (font.importUrl) importUrls.push(font.importUrl);
|
|
403
|
+
if (font.family) typographyOverrides[fontFamilySlot(i)] = font.family;
|
|
404
|
+
});
|
|
405
|
+
if (Object.keys(typographyOverrides).length > 0) {
|
|
406
|
+
tokens = { ...tokens, typography: { ...tokens.typography, ...typographyOverrides } };
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (userConfig.font?.heading) {
|
|
410
|
+
const [resolvedHeading] = resolveFontFamilies(userConfig.font.heading);
|
|
411
|
+
if (resolvedHeading.importUrl) importUrls.push(resolvedHeading.importUrl);
|
|
412
|
+
if (resolvedHeading.family) {
|
|
413
|
+
tokens = { ...tokens, typography: { ...tokens.typography, fontFamilyHeading: resolvedHeading.family } };
|
|
386
414
|
}
|
|
387
415
|
}
|
|
388
416
|
if (userConfig.border?.radius) {
|
|
@@ -391,10 +419,20 @@ var createStyleSheet = (userConfig = {}) => {
|
|
|
391
419
|
if (userConfig.border?.width) {
|
|
392
420
|
tokens = { ...tokens, border: { ...tokens.border, width: resolveBorderWidth(userConfig.border.width) } };
|
|
393
421
|
}
|
|
422
|
+
if (userConfig.elevation === "none") {
|
|
423
|
+
const flatElevation = Object.fromEntries(
|
|
424
|
+
Object.keys(tokens.elevation).map((level) => [level, "none"])
|
|
425
|
+
);
|
|
426
|
+
tokens = { ...tokens, elevation: flatElevation };
|
|
427
|
+
}
|
|
394
428
|
const primitives = tokensToCss(tokens);
|
|
395
429
|
const theme = userConfig.theme ?? "light";
|
|
396
430
|
const primary = tokens.color.primary;
|
|
397
|
-
const semanticOpts = {
|
|
431
|
+
const semanticOpts = {
|
|
432
|
+
primary500: primary["500"],
|
|
433
|
+
primary400: primary["400"],
|
|
434
|
+
borderContrast: userConfig.border?.contrast
|
|
435
|
+
};
|
|
398
436
|
let body;
|
|
399
437
|
if (theme === "dark") {
|
|
400
438
|
body = primitives + "\n" + semanticTokensToCss(buildSemanticTokens("dark", semanticOpts));
|
|
@@ -403,22 +441,19 @@ var createStyleSheet = (userConfig = {}) => {
|
|
|
403
441
|
} else {
|
|
404
442
|
body = primitives + "\n" + semanticTokensToCss(buildSemanticTokens("light", semanticOpts)) + "\n" + semanticTokensToCss(buildSemanticTokens("dark", semanticOpts), "@media (prefers-color-scheme: dark)") + "\n" + semanticTokensToCss(buildSemanticTokens("dark", semanticOpts), '[data-theme="dark"]') + "\n" + semanticTokensToCss(buildSemanticTokens("light", semanticOpts), '[data-theme="light"]');
|
|
405
443
|
}
|
|
406
|
-
|
|
444
|
+
body += "\nbody { font-family: var(--lt-typography-fontFamilyPrimary); }\n";
|
|
445
|
+
const importLines = importUrls.map((url) => `@import url("${url}");`).join("\n");
|
|
446
|
+
return importLines ? `${importLines}
|
|
407
447
|
${body}` : body;
|
|
408
448
|
};
|
|
409
449
|
var configure = (userConfig = {}) => {
|
|
410
|
-
const root = document.documentElement;
|
|
411
|
-
root.removeAttribute("data-lt-ready");
|
|
412
450
|
let style = document.getElementById("lt-tokens");
|
|
413
451
|
if (!style) {
|
|
414
452
|
style = document.createElement("style");
|
|
415
453
|
style.id = "lt-tokens";
|
|
416
454
|
document.head.prepend(style);
|
|
417
455
|
}
|
|
418
|
-
|
|
419
|
-
const css = createStyleSheet(userConfig);
|
|
420
|
-
style.textContent = css.startsWith("@import") ? css.replace(/^(@import[^\n]*\n)/, `$1${guard}`) : guard + css;
|
|
421
|
-
requestAnimationFrame(() => root.setAttribute("data-lt-ready", ""));
|
|
456
|
+
style.textContent = createStyleSheet(userConfig);
|
|
422
457
|
};
|
|
423
458
|
export {
|
|
424
459
|
configure,
|
package/dist/tokens.css
CHANGED
package/dist/tokens.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const tokens = {"color":{"primary":{"50":"#f0e5df","100":"#ffd4b5","200":"#ffbb87","300":"#ffa860","400":"#ff9539","500":"#ff8200","600":"#d56400","700":"#963b00","800":"#5e3c25","900":"#3c1d05"},"primary-muted":{"50":"#e9e7e6","100":"#e8dfda","200":"#dfd1c8","300":"#dac8bd","400":"#d2beb2","500":"#c6b1a5","600":"#a08e82","700":"#6b5c53","800":"#50453e","900":"#2b2521"},"secondary":{"50":"#e5e7f1","100":"#cbd2ff","200":"#a3acf7","300":"#8a93f4","400":"#7076e5","500":"#5252c5","600":"#4544ad","700":"#333187","800":"#2e3254","900":"#202343"},"secondary-muted":{"50":"#e7e8e9","100":"#d5d7df","200":"#b4b7c4","300":"#a0a3b3","400":"#898c9e","500":"#6c6f81","600":"#5a5d6d","700":"#414351","800":"#363742","900":"#25262c"},"success":{"50":"#e1ebe2","100":"#beedc6","200":"#94e4a4","300":"#70df8b","400":"#4bd573","500":"#22c55e","600":"#00a244","700":"#006f22","800":"#2b4d32","900":"#0c2e16"},"success-muted":{"50":"#e7e8e7","100":"#dbe3dc","200":"#cad7cc","300":"#bfcfc1","400":"#b3c5b6","500":"#a5b8a8","600":"#839586","700":"#546256","800":"#404a41","900":"#222823"},"warning":{"50":"#ece7de","100":"#f5e0b5","200":"#f6d289","300":"#f9c962","400":"#f7bf3a","500":"#eeb308","600":"#c38e00","700":"#845a00","800":"#584720","900":"#332400"},"warning-muted":{"50":"#e8e8e6","100":"#e7e4dc","200":"#e2dcd0","300":"#ded7c8","400":"#dad1c0","500":"#d2c9b8","600":"#a9a090","700":"#6d6659","800":"#504c42","900":"#292621"},"error":{"50":"#f3e4e2","100":"#ffc8c1","200":"#ffa198","300":"#ff847b","400":"#ff6560","500":"#ef4444","600":"#cb2d31","700":"#950e18","800":"#5a312e","900":"#3f1917"},"error-muted":{"50":"#e9e7e7","100":"#e6dad8","200":"#d6c3c1","300":"#cdb4b2","400":"#bfa4a1","500":"#ab908d","600":"#8d7572","700":"#624e4c","800":"#4c3d3b","900":"#2d2423"},"info":{"50":"#e1e9ef","100":"#bce4fe","200":"#8fd2fd","300":"#6ac7ff","400":"#43b9fa","500":"#0ea5e9","600":"#0087c4","700":"#005c8d","800":"#1e465d","900":"#082a3c"},"info-muted":{"50":"#e7e8e9","100":"#d9e0e5","200":"#c5d0d7","300":"#b8c6cf","400":"#aab9c4","500":"#99a9b3","600":"#7a8993","700":"#4f5b63","800":"#3d464c","900":"#22272a"},"neutral":{"50":"#fafafa","100":"#f3f3f3","200":"#e4e4e4","300":"#cacaca","400":"#ababab","500":"#868686","600":"#696969","700":"#4d4d4d","800":"#333333","900":"#1b1b1b"},"white":"#FFFFFF","black":"#000000"},"spacing":{"px":{"0":"0px","1":"4px","2":"8px","3":"12px","4":"16px","5":"20px","6":"24px","7":"28px","8":"32px","9":"36px","10":"40px","11":"44px","12":"48px","13":"52px","14":"56px","15":"60px","16":"64px","17":"68px","18":"72px","19":"76px","20":"80px","21":"84px","22":"88px","23":"92px","24":"96px"},"rem":{"0":"0rem","1":"0.25rem","2":"0.5rem","3":"0.75rem","4":"1rem","5":"1.25rem","6":"1.5rem","7":"1.75rem","8":"2rem","9":"2.25rem","10":"2.5rem","11":"2.75rem","12":"3rem","13":"3.25rem","14":"3.5rem","15":"3.75rem","16":"4rem","17":"4.25rem","18":"4.5rem","19":"4.75rem","20":"5rem","21":"5.25rem","22":"5.5rem","23":"5.75rem","24":"6rem"}},"border":{"radius":"0.5rem","width":"1px"},"typography":{"
|
|
1
|
+
export const tokens = {"color":{"primary":{"50":"#f0e5df","100":"#ffd4b5","200":"#ffbb87","300":"#ffa860","400":"#ff9539","500":"#ff8200","600":"#d56400","700":"#963b00","800":"#5e3c25","900":"#3c1d05"},"primary-muted":{"50":"#e9e7e6","100":"#e8dfda","200":"#dfd1c8","300":"#dac8bd","400":"#d2beb2","500":"#c6b1a5","600":"#a08e82","700":"#6b5c53","800":"#50453e","900":"#2b2521"},"secondary":{"50":"#e5e7f1","100":"#cbd2ff","200":"#a3acf7","300":"#8a93f4","400":"#7076e5","500":"#5252c5","600":"#4544ad","700":"#333187","800":"#2e3254","900":"#202343"},"secondary-muted":{"50":"#e7e8e9","100":"#d5d7df","200":"#b4b7c4","300":"#a0a3b3","400":"#898c9e","500":"#6c6f81","600":"#5a5d6d","700":"#414351","800":"#363742","900":"#25262c"},"success":{"50":"#e1ebe2","100":"#beedc6","200":"#94e4a4","300":"#70df8b","400":"#4bd573","500":"#22c55e","600":"#00a244","700":"#006f22","800":"#2b4d32","900":"#0c2e16"},"success-muted":{"50":"#e7e8e7","100":"#dbe3dc","200":"#cad7cc","300":"#bfcfc1","400":"#b3c5b6","500":"#a5b8a8","600":"#839586","700":"#546256","800":"#404a41","900":"#222823"},"warning":{"50":"#ece7de","100":"#f5e0b5","200":"#f6d289","300":"#f9c962","400":"#f7bf3a","500":"#eeb308","600":"#c38e00","700":"#845a00","800":"#584720","900":"#332400"},"warning-muted":{"50":"#e8e8e6","100":"#e7e4dc","200":"#e2dcd0","300":"#ded7c8","400":"#dad1c0","500":"#d2c9b8","600":"#a9a090","700":"#6d6659","800":"#504c42","900":"#292621"},"error":{"50":"#f3e4e2","100":"#ffc8c1","200":"#ffa198","300":"#ff847b","400":"#ff6560","500":"#ef4444","600":"#cb2d31","700":"#950e18","800":"#5a312e","900":"#3f1917"},"error-muted":{"50":"#e9e7e7","100":"#e6dad8","200":"#d6c3c1","300":"#cdb4b2","400":"#bfa4a1","500":"#ab908d","600":"#8d7572","700":"#624e4c","800":"#4c3d3b","900":"#2d2423"},"info":{"50":"#e1e9ef","100":"#bce4fe","200":"#8fd2fd","300":"#6ac7ff","400":"#43b9fa","500":"#0ea5e9","600":"#0087c4","700":"#005c8d","800":"#1e465d","900":"#082a3c"},"info-muted":{"50":"#e7e8e9","100":"#d9e0e5","200":"#c5d0d7","300":"#b8c6cf","400":"#aab9c4","500":"#99a9b3","600":"#7a8993","700":"#4f5b63","800":"#3d464c","900":"#22272a"},"neutral":{"50":"#fafafa","100":"#f3f3f3","200":"#e4e4e4","300":"#cacaca","400":"#ababab","500":"#868686","600":"#696969","700":"#4d4d4d","800":"#333333","900":"#1b1b1b"},"white":"#FFFFFF","black":"#000000"},"spacing":{"px":{"0":"0px","1":"4px","2":"8px","3":"12px","4":"16px","5":"20px","6":"24px","7":"28px","8":"32px","9":"36px","10":"40px","11":"44px","12":"48px","13":"52px","14":"56px","15":"60px","16":"64px","17":"68px","18":"72px","19":"76px","20":"80px","21":"84px","22":"88px","23":"92px","24":"96px"},"rem":{"0":"0rem","1":"0.25rem","2":"0.5rem","3":"0.75rem","4":"1rem","5":"1.25rem","6":"1.5rem","7":"1.75rem","8":"2rem","9":"2.25rem","10":"2.5rem","11":"2.75rem","12":"3rem","13":"3.25rem","14":"3.5rem","15":"3.75rem","16":"4rem","17":"4.25rem","18":"4.5rem","19":"4.75rem","20":"5rem","21":"5.25rem","22":"5.5rem","23":"5.75rem","24":"6rem"}},"border":{"radius":"0.5rem","width":"1px"},"typography":{"fontFamilyPrimary":"\"Hanken Grotesk\", sans-serif"},"elevation":{"0":"none","1":"0 1px 3px 0 rgb(27 27 27 / 0.1), 0 1px 2px 0 rgb(27 27 27 / 0.06)","2":"0 4px 6px -1px rgb(27 27 27 / 0.1), 0 2px 4px -1px rgb(27 27 27 / 0.06)","3":"0 10px 15px -3px rgb(27 27 27 / 0.1), 0 4px 6px -2px rgb(27 27 27 / 0.05)","4":"0 20px 25px -5px rgb(27 27 27 / 0.1), 0 10px 10px -5px rgb(27 27 27 / 0.04)","5":"0 25px 50px -12px rgb(27 27 27 / 0.25)"},"semantic":{"text-default":"color-neutral-900","text-subtle":"color-neutral-600","text-muted":"color-neutral-400","text-disabled":"color-neutral-400","text-inverse":"color-white","text-neutral":"color-neutral-700","text-primary":"color-primary-700","text-on-primary":"color-neutral-900","text-secondary":"color-secondary-700","text-on-secondary":"color-white","text-success":"color-success-700","text-on-success":"color-white","text-warning":"color-warning-700","text-on-warning":"color-warning-800","text-error":"color-error-700","text-on-error":"color-white","text-info":"color-info-700","text-on-info":"color-white","bg-default":"color-white","bg-subtle":"color-neutral-50","bg-surface":"color-neutral-100","bg-overlay":"color-neutral-200","bg-inverse":"color-neutral-900","bg-neutral-subtle":"color-neutral-100","bg-primary":"color-primary-500","bg-primary-subtle":"color-primary-100","bg-secondary":"color-secondary-500","bg-secondary-subtle":"color-secondary-100","bg-success":"color-success-500","bg-success-subtle":"color-success-100","bg-warning":"color-warning-500","bg-warning-subtle":"color-warning-100","bg-error":"color-error-500","bg-error-subtle":"color-error-100","bg-info":"color-info-500","bg-info-subtle":"color-info-100","border-default":"color-neutral-200","border-strong":"color-neutral-400","border-subtle":"color-neutral-100","border-focus":"color-primary-200","border-primary":"color-primary-200","border-primary-strong":"color-primary-500","border-secondary":"color-secondary-200","border-secondary-strong":"color-secondary-500","border-success":"color-success-200","border-success-strong":"color-success-500","border-warning":"color-warning-200","border-warning-strong":"color-warning-500","border-error":"color-error-200","border-error-strong":"color-error-500","border-info":"color-info-200","border-info-strong":"color-info-500","interactive-primary-bg":"color-primary-500","interactive-primary-bg-hover":"color-primary-600","interactive-primary-bg-active":"color-primary-700","interactive-secondary-bg":"color-secondary-500","interactive-secondary-bg-hover":"color-secondary-600","interactive-secondary-bg-active":"color-secondary-700","interactive-success-bg":"color-success-500","interactive-success-bg-hover":"color-success-600","interactive-success-bg-active":"color-success-700","interactive-warning-bg":"color-warning-500","interactive-warning-bg-hover":"color-warning-600","interactive-warning-bg-active":"color-warning-700","interactive-error-bg":"color-error-500","interactive-error-bg-hover":"color-error-600","interactive-error-bg-active":"color-error-700","interactive-info-bg":"color-info-500","interactive-info-bg-hover":"color-info-600","interactive-info-bg-active":"color-info-700"},"semanticDark":{"text-default":"color-neutral-100","text-subtle":"color-neutral-300","text-muted":"color-neutral-500","text-disabled":"color-neutral-600","text-inverse":"color-neutral-900","text-neutral":"color-neutral-200","text-primary":"color-primary-300","text-on-primary":"color-neutral-900","text-secondary":"color-secondary-300","text-on-secondary":"color-white","text-success":"color-success-300","text-on-success":"color-white","text-warning":"color-warning-300","text-on-warning":"color-warning-800","text-error":"color-error-300","text-on-error":"color-white","text-info":"color-info-300","text-on-info":"color-white","bg-default":"color-neutral-900","bg-subtle":"color-neutral-800","bg-surface":"color-neutral-800","bg-overlay":"color-neutral-700","bg-inverse":"color-neutral-50","bg-neutral-subtle":"color-neutral-800","bg-primary":"color-primary-500","bg-primary-subtle":"color-primary-900","bg-secondary":"color-secondary-500","bg-secondary-subtle":"color-secondary-900","bg-success":"color-success-500","bg-success-subtle":"color-success-900","bg-warning":"color-warning-500","bg-warning-subtle":"color-warning-900","bg-error":"color-error-500","bg-error-subtle":"color-error-900","bg-info":"color-info-500","bg-info-subtle":"color-info-900","border-default":"color-neutral-700","border-strong":"color-neutral-500","border-subtle":"color-neutral-800","border-focus":"color-primary-400","border-primary":"color-primary-700","border-primary-strong":"color-primary-500","border-secondary":"color-secondary-700","border-secondary-strong":"color-secondary-500","border-success":"color-success-700","border-success-strong":"color-success-500","border-warning":"color-warning-700","border-warning-strong":"color-warning-500","border-error":"color-error-700","border-error-strong":"color-error-500","border-info":"color-info-700","border-info-strong":"color-info-500","interactive-primary-bg":"color-primary-400","interactive-primary-bg-hover":"color-primary-300","interactive-primary-bg-active":"color-primary-500","interactive-secondary-bg":"color-secondary-400","interactive-secondary-bg-hover":"color-secondary-300","interactive-secondary-bg-active":"color-secondary-500","interactive-success-bg":"color-success-400","interactive-success-bg-hover":"color-success-300","interactive-success-bg-active":"color-success-500","interactive-warning-bg":"color-warning-400","interactive-warning-bg-hover":"color-warning-300","interactive-warning-bg-active":"color-warning-500","interactive-error-bg":"color-error-400","interactive-error-bg-hover":"color-error-300","interactive-error-bg-active":"color-error-500","interactive-info-bg":"color-info-400","interactive-info-bg-hover":"color-info-300","interactive-info-bg-active":"color-info-500"}};
|
package/dist/tokens.json
CHANGED
|
@@ -24,7 +24,7 @@ import type { ElevationTokens } from '../elevation/';
|
|
|
24
24
|
* radius: "0.375rem"
|
|
25
25
|
* },
|
|
26
26
|
* typography: {
|
|
27
|
-
*
|
|
27
|
+
* fontFamilyPrimary: "Hanken Grotesk, sans-serif"
|
|
28
28
|
* },
|
|
29
29
|
* elevation: {
|
|
30
30
|
* "0": "none",
|
|
@@ -42,8 +42,8 @@ export type Tokens = {
|
|
|
42
42
|
width: string;
|
|
43
43
|
};
|
|
44
44
|
typography: {
|
|
45
|
-
|
|
46
|
-
}
|
|
45
|
+
fontFamilyPrimary: string;
|
|
46
|
+
} & Record<string, string>;
|
|
47
47
|
elevation: ElevationTokens;
|
|
48
48
|
};
|
|
49
49
|
export type { Config, TokenColorName } from './';
|
|
@@ -53,27 +53,74 @@ export type { Config, TokenColorName } from './';
|
|
|
53
53
|
* Any other CSS length (e.g. `'1.5px'`) passes through unchanged.
|
|
54
54
|
*/
|
|
55
55
|
export type BorderWidth = 'thin' | 'medium' | 'thick' | (string & {});
|
|
56
|
+
/** Generic CSS font-family keyword used as the safety-net fallback if a CDN font fails to load. */
|
|
57
|
+
export type FontFallback = 'sans-serif' | 'serif' | 'monospace' | 'cursive' | 'fantasy' | 'system-ui';
|
|
58
|
+
/**
|
|
59
|
+
* A single `font.family` entry: a plain CSS value, a Google Fonts CSS2 URL, or
|
|
60
|
+
* a URL paired with a custom generic fallback (default `'sans-serif'`) for
|
|
61
|
+
* when the derived family isn't sans-serif — e.g. a serif display font.
|
|
62
|
+
*/
|
|
63
|
+
export type FontFamilyEntry = string | {
|
|
64
|
+
url: string;
|
|
65
|
+
fallback?: FontFallback;
|
|
66
|
+
};
|
|
56
67
|
export interface LattyConfig {
|
|
57
68
|
/** Built-in names: primary, secondary, success, warning, error, info. Any additional name generates a new palette. */
|
|
58
69
|
colors?: Record<string, string>;
|
|
59
70
|
font?: {
|
|
60
71
|
/**
|
|
61
|
-
* A CSS `font-family` value (e.g. `'Inter, sans-serif'`),
|
|
62
|
-
*
|
|
63
|
-
* `'https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900&display=swap'`)
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
72
|
+
* A CSS `font-family` value (e.g. `'Inter, sans-serif'`), a Google Fonts
|
|
73
|
+
* CSS2 stylesheet URL (e.g.
|
|
74
|
+
* `'https://fonts.googleapis.com/css2?family=Hanken+Grotesk:ital,wght@0,100..900&display=swap'`),
|
|
75
|
+
* a `{ url, fallback }` object, or an array of any of these. URLs get
|
|
76
|
+
* `@import`ed automatically and the family name is derived from the
|
|
77
|
+
* `family=` query param — no separate `<link>` tag needed. Stylesheet
|
|
78
|
+
* URLs from providers other than `fonts.googleapis.com` are still
|
|
79
|
+
* loaded, but since there's no reliable way to guess the family name
|
|
80
|
+
* from an arbitrary CDN, pass the resulting name as a plain value
|
|
81
|
+
* instead (or open an issue if there's a provider worth special-casing).
|
|
82
|
+
*
|
|
83
|
+
* A bare URL string always falls back to the generic `sans-serif` family
|
|
84
|
+
* if the font itself fails to load. Use the `{ url, fallback }` object
|
|
85
|
+
* form to pick a different generic fallback (e.g. `'serif'` for a serif
|
|
86
|
+
* display font):
|
|
87
|
+
* ```ts
|
|
88
|
+
* family: { url: 'https://fonts.googleapis.com/css2?family=Playfair+Display', fallback: 'serif' }
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* When an array is passed, each entry maps to its own token in order —
|
|
92
|
+
* `--lt-typography-fontFamilyPrimary`, `...Secondary`, `...Tertiary`,
|
|
93
|
+
* etc. — rather than being combined into a single CSS fallback stack, so
|
|
94
|
+
* multiple fonts (e.g. a heading font and a body font) can each be
|
|
95
|
+
* referenced independently in your own CSS.
|
|
96
|
+
*/
|
|
97
|
+
family?: FontFamilyEntry | FontFamilyEntry[];
|
|
98
|
+
/**
|
|
99
|
+
* A single dedicated heading font, resolved to `--lt-typography-fontFamilyHeading`.
|
|
100
|
+
* `lt-text`'s heading/display variants (`h1`–`h6`, `display-*`) read this
|
|
101
|
+
* token automatically, falling back to `fontFamilyPrimary` when unset —
|
|
102
|
+
* the built-in way to do a two-typeface identity without manually
|
|
103
|
+
* rerouting `--lt-typography-fontFamilySecondary` via hand-written CSS.
|
|
70
104
|
*/
|
|
71
|
-
|
|
105
|
+
heading?: FontFamilyEntry;
|
|
72
106
|
};
|
|
73
107
|
border?: {
|
|
74
108
|
radius?: string;
|
|
75
109
|
width?: BorderWidth;
|
|
110
|
+
/**
|
|
111
|
+
* Shifts which neutral palette step `--lt-border-default`/`--lt-border-strong`/
|
|
112
|
+
* `--lt-border-subtle` resolve to. `'high'` moves them toward a bolder,
|
|
113
|
+
* higher-contrast step (darker in light mode, lighter in dark mode) without
|
|
114
|
+
* touching theme-switching machinery.
|
|
115
|
+
* @default 'default'
|
|
116
|
+
*/
|
|
117
|
+
contrast?: 'default' | 'high';
|
|
76
118
|
};
|
|
119
|
+
/**
|
|
120
|
+
* Set to `'none'` to flatten every `--lt-elevation-N` token (box-shadow) to
|
|
121
|
+
* `none` in one call, instead of overriding each level individually.
|
|
122
|
+
*/
|
|
123
|
+
elevation?: 'none';
|
|
77
124
|
/**
|
|
78
125
|
* Controls which semantic token layer is emitted.
|
|
79
126
|
* - `'light'` (default) — light tokens only; ignores OS preference
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@latty-ds/tokens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Design tokens for the Latty design system — generates CSS custom properties, JSON, and JavaScript exports from a single config file",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"culori": "^4.0.2"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "7b0b9856be6755a573abf02c0b7cbdb1a6db4fef"
|
|
64
64
|
}
|