@tenphi/glaze 0.3.0 → 0.4.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 CHANGED
@@ -70,7 +70,7 @@ const success = primary.extend({ hue: 157 });
70
70
  // Compose into a palette and export
71
71
  const palette = glaze.palette({ primary, danger, success });
72
72
  const tokens = palette.tokens({ prefix: true });
73
- // → { '#primary-surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' }, ... }
73
+ // → { light: { 'primary-surface': 'okhsl(...)', ... }, dark: { 'primary-surface': 'okhsl(...)', ... } }
74
74
  ```
75
75
 
76
76
  ## Core Concepts
@@ -262,7 +262,8 @@ Create a single color token without a full theme:
262
262
  const accent = glaze.color({ hue: 280, saturation: 80, lightness: 52, mode: 'fixed' });
263
263
 
264
264
  accent.resolve(); // → ResolvedColor with light/dark/lightContrast/darkContrast
265
- accent.token(); // → { '': 'okhsl(...)', '@dark': 'okhsl(...)' }
265
+ accent.token(); // → { '': 'okhsl(...)', '@dark': 'okhsl(...)' } (tasty format)
266
+ accent.tasty(); // → { '': 'okhsl(...)', '@dark': 'okhsl(...)' } (same as token)
266
267
  accent.json(); // → { light: 'okhsl(...)', dark: 'okhsl(...)' }
267
268
  ```
268
269
 
@@ -307,7 +308,7 @@ theme.tokens({ format: 'hsl' }); // → 'hsl(270.5, 45.2%, 95.8%)'
307
308
  theme.tokens({ format: 'oklch' }); // → 'oklch(96.5% 0.0123 280.0)'
308
309
  ```
309
310
 
310
- The `format` option works on all export methods: `theme.tokens()`, `theme.json()`, `theme.css()`, `palette.tokens()`, `palette.json()`, `palette.css()`, and standalone `glaze.color().token()` / `.json()`.
311
+ The `format` option works on all export methods: `theme.tokens()`, `theme.tasty()`, `theme.json()`, `theme.css()`, `palette.tokens()`, `palette.tasty()`, `palette.json()`, `palette.css()`, and standalone `glaze.color().token()` / `.tasty()` / `.json()`.
311
312
 
312
313
  Available formats:
313
314
 
@@ -410,18 +411,93 @@ const palette = glaze.palette({ primary, danger, success, warning });
410
411
 
411
412
  ### Token Export
412
413
 
414
+ Tokens are grouped by scheme variant, with plain color names as keys:
415
+
413
416
  ```ts
414
417
  const tokens = palette.tokens({ prefix: true });
415
418
  // → {
419
+ // light: { 'primary-surface': 'okhsl(...)', 'danger-surface': 'okhsl(...)' },
420
+ // dark: { 'primary-surface': 'okhsl(...)', 'danger-surface': 'okhsl(...)' },
421
+ // }
422
+ ```
423
+
424
+ Custom prefix mapping:
425
+
426
+ ```ts
427
+ palette.tokens({ prefix: { primary: 'brand-', danger: 'error-' } });
428
+ ```
429
+
430
+ ### Tasty Export (for [Tasty](https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs) style system)
431
+
432
+ The `tasty()` method exports tokens in the [Tasty](https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs) style-to-state binding format — `#name` color token keys with state aliases (`''`, `@dark`, etc.):
433
+
434
+ ```ts
435
+ const tastyTokens = palette.tasty({ prefix: true });
436
+ // → {
416
437
  // '#primary-surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' },
417
438
  // '#danger-surface': { '': 'okhsl(...)', '@dark': 'okhsl(...)' },
418
439
  // }
419
440
  ```
420
441
 
442
+ Apply as global styles to make color tokens available app-wide:
443
+
444
+ ```ts
445
+ import { useGlobalStyles } from '@cube-dev/ui-kit';
446
+
447
+ // In your root component
448
+ useGlobalStyles('body', tastyTokens);
449
+ ```
450
+
451
+ For zero-runtime builds, use `tastyStatic` to generate the CSS at build time:
452
+
453
+ ```ts
454
+ import { tastyStatic } from '@cube-dev/ui-kit';
455
+
456
+ tastyStatic('body', tastyTokens);
457
+ ```
458
+
459
+ Alternatively, register as a recipe via `configure()`:
460
+
461
+ ```ts
462
+ import { configure, tasty } from '@cube-dev/ui-kit';
463
+
464
+ configure({
465
+ recipes: {
466
+ 'all-themes': tastyTokens,
467
+ },
468
+ });
469
+
470
+ const Page = tasty({
471
+ styles: {
472
+ recipe: 'all-themes',
473
+ fill: '#primary-surface',
474
+ color: '#primary-text',
475
+ },
476
+ });
477
+ ```
478
+
479
+ Or spread directly into component styles:
480
+
481
+ ```ts
482
+ const Card = tasty({
483
+ styles: {
484
+ ...tastyTokens,
485
+ fill: '#primary-surface',
486
+ color: '#primary-text',
487
+ },
488
+ });
489
+ ```
490
+
421
491
  Custom prefix mapping:
422
492
 
423
493
  ```ts
424
- palette.tokens({ prefix: { primary: 'brand-', danger: 'error-' } });
494
+ palette.tasty({ prefix: { primary: 'brand-', danger: 'error-' } });
495
+ ```
496
+
497
+ Custom state aliases:
498
+
499
+ ```ts
500
+ palette.tasty({ states: { dark: '@dark', highContrast: '@hc' } });
425
501
  ```
426
502
 
427
503
  ### JSON Export (Framework-Agnostic)
@@ -488,17 +564,22 @@ Control which scheme variants appear in exports:
488
564
  ```ts
489
565
  // Light only
490
566
  palette.tokens({ modes: { dark: false, highContrast: false } });
567
+ // → { light: { ... } }
491
568
 
492
569
  // Light + dark (default)
493
570
  palette.tokens({ modes: { highContrast: false } });
571
+ // → { light: { ... }, dark: { ... } }
494
572
 
495
573
  // All four variants
496
574
  palette.tokens({ modes: { dark: true, highContrast: true } });
575
+ // → { light: { ... }, dark: { ... }, lightContrast: { ... }, darkContrast: { ... } }
497
576
  ```
498
577
 
578
+ The `modes` option works the same way on `tokens()`, `tasty()`, `json()`, and `css()`.
579
+
499
580
  Resolution priority (highest first):
500
581
 
501
- 1. `tokens({ modes })` / `json({ modes })` / `css({ ... })` — per-call override
582
+ 1. `tokens({ modes })` / `tasty({ modes })` / `json({ modes })` / `css({ ... })` — per-call override
502
583
  2. `glaze.configure({ modes })` — global config
503
584
  3. Built-in default: `{ dark: true, highContrast: false }`
504
585
 
@@ -609,8 +690,15 @@ const note = primary.extend({ hue: 302 });
609
690
 
610
691
  const palette = glaze.palette({ primary, danger, success, warning, note });
611
692
 
612
- // Export as OKHSL tokens (default)
693
+ // Export as flat token map grouped by variant
613
694
  const tokens = palette.tokens({ prefix: true });
695
+ // tokens.light → { 'primary-surface': 'okhsl(...)', 'danger-surface': 'okhsl(...)' }
696
+ // tokens.dark → { 'primary-surface': 'okhsl(...)', 'danger-surface': 'okhsl(...)' }
697
+
698
+ // Export as tasty style-to-state bindings (for Tasty style system)
699
+ const tastyTokens = palette.tasty({ prefix: true });
700
+ // tastyTokens['#primary-surface'] → { '': 'okhsl(...)', '@dark': 'okhsl(...)' }
701
+ // Use as a recipe or spread into component styles (see Tasty Export section)
614
702
 
615
703
  // Export as RGB for broader CSS compatibility
616
704
  const rgbTokens = palette.tokens({ prefix: true, format: 'rgb' });
@@ -656,7 +744,8 @@ brand.colors({ surface: { lightness: 97 }, text: { base: 'surface', lightness: '
656
744
  | `theme.export()` | Export configuration as JSON-safe object |
657
745
  | `theme.extend(options)` | Create a child theme |
658
746
  | `theme.resolve()` | Resolve all colors |
659
- | `theme.tokens(options?)` | Export as token map |
747
+ | `theme.tokens(options?)` | Export as flat token map grouped by variant |
748
+ | `theme.tasty(options?)` | Export as [Tasty](https://cube-ui-kit.vercel.app/?path=/docs/tasty-documentation--docs) style-to-state bindings |
660
749
  | `theme.json(options?)` | Export as plain JSON |
661
750
  | `theme.css(options?)` | Export as CSS custom property declarations |
662
751
 
package/dist/index.cjs CHANGED
@@ -998,6 +998,20 @@ function buildTokenMap(resolved, prefix, states, modes, format = "okhsl") {
998
998
  }
999
999
  return tokens;
1000
1000
  }
1001
+ function buildFlatTokenMap(resolved, prefix, modes, format = "okhsl") {
1002
+ const result = { light: {} };
1003
+ if (modes.dark) result.dark = {};
1004
+ if (modes.highContrast) result.lightContrast = {};
1005
+ if (modes.dark && modes.highContrast) result.darkContrast = {};
1006
+ for (const [name, color] of resolved) {
1007
+ const key = `${prefix}${name}`;
1008
+ result.light[key] = formatVariant(color.light, format);
1009
+ if (modes.dark) result.dark[key] = formatVariant(color.dark, format);
1010
+ if (modes.highContrast) result.lightContrast[key] = formatVariant(color.lightContrast, format);
1011
+ if (modes.dark && modes.highContrast) result.darkContrast[key] = formatVariant(color.darkContrast, format);
1012
+ }
1013
+ return result;
1014
+ }
1001
1015
  function buildJsonMap(resolved, modes, format = "okhsl") {
1002
1016
  const result = {};
1003
1017
  for (const [name, color] of resolved) {
@@ -1079,6 +1093,9 @@ function createTheme(hue, saturation, initialColors) {
1079
1093
  return resolveAllColors(hue, saturation, colorDefs);
1080
1094
  },
1081
1095
  tokens(options) {
1096
+ return buildFlatTokenMap(resolveAllColors(hue, saturation, colorDefs), "", resolveModes(options?.modes), options?.format);
1097
+ },
1098
+ tasty(options) {
1082
1099
  return buildTokenMap(resolveAllColors(hue, saturation, colorDefs), "", {
1083
1100
  dark: options?.states?.dark ?? globalConfig.states.dark,
1084
1101
  highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
@@ -1092,9 +1109,26 @@ function createTheme(hue, saturation, initialColors) {
1092
1109
  }
1093
1110
  };
1094
1111
  }
1112
+ function resolvePrefix(options, themeName) {
1113
+ if (options?.prefix === true) return `${themeName}-`;
1114
+ if (typeof options?.prefix === "object" && options.prefix !== null) return options.prefix[themeName] ?? `${themeName}-`;
1115
+ return "";
1116
+ }
1095
1117
  function createPalette(themes) {
1096
1118
  return {
1097
1119
  tokens(options) {
1120
+ const modes = resolveModes(options?.modes);
1121
+ const allTokens = {};
1122
+ for (const [themeName, theme] of Object.entries(themes)) {
1123
+ const tokens = buildFlatTokenMap(theme.resolve(), resolvePrefix(options, themeName), modes, options?.format);
1124
+ for (const variant of Object.keys(tokens)) {
1125
+ if (!allTokens[variant]) allTokens[variant] = {};
1126
+ Object.assign(allTokens[variant], tokens[variant]);
1127
+ }
1128
+ }
1129
+ return allTokens;
1130
+ },
1131
+ tasty(options) {
1098
1132
  const states = {
1099
1133
  dark: options?.states?.dark ?? globalConfig.states.dark,
1100
1134
  highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
@@ -1102,11 +1136,7 @@ function createPalette(themes) {
1102
1136
  const modes = resolveModes(options?.modes);
1103
1137
  const allTokens = {};
1104
1138
  for (const [themeName, theme] of Object.entries(themes)) {
1105
- const resolved = theme.resolve();
1106
- let prefix = "";
1107
- if (options?.prefix === true) prefix = `${themeName}-`;
1108
- else if (typeof options?.prefix === "object" && options.prefix !== null) prefix = options.prefix[themeName] ?? `${themeName}-`;
1109
- const tokens = buildTokenMap(resolved, prefix, states, modes, options?.format);
1139
+ const tokens = buildTokenMap(theme.resolve(), resolvePrefix(options, themeName), states, modes, options?.format);
1110
1140
  Object.assign(allTokens, tokens);
1111
1141
  }
1112
1142
  return allTokens;
@@ -1127,11 +1157,7 @@ function createPalette(themes) {
1127
1157
  darkContrast: []
1128
1158
  };
1129
1159
  for (const [themeName, theme] of Object.entries(themes)) {
1130
- const resolved = theme.resolve();
1131
- let prefix = "";
1132
- if (options?.prefix === true) prefix = `${themeName}-`;
1133
- else if (typeof options?.prefix === "object" && options.prefix !== null) prefix = options.prefix[themeName] ?? `${themeName}-`;
1134
- const css = buildCssMap(resolved, prefix, suffix, format);
1160
+ const css = buildCssMap(theme.resolve(), resolvePrefix(options, themeName), suffix, format);
1135
1161
  for (const key of [
1136
1162
  "light",
1137
1163
  "dark",
@@ -1164,6 +1190,12 @@ function createColorToken(input) {
1164
1190
  highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
1165
1191
  }, resolveModes(options?.modes), options?.format)["#__color__"];
1166
1192
  },
1193
+ tasty(options) {
1194
+ return buildTokenMap(resolveAllColors(input.hue, input.saturation, defs), "", {
1195
+ dark: options?.states?.dark ?? globalConfig.states.dark,
1196
+ highContrast: options?.states?.highContrast ?? globalConfig.states.highContrast
1197
+ }, resolveModes(options?.modes), options?.format)["#__color__"];
1198
+ },
1167
1199
  json(options) {
1168
1200
  return buildJsonMap(resolveAllColors(input.hue, input.saturation, defs), resolveModes(options?.modes), options?.format)["__color__"];
1169
1201
  }