@hex-core/tokens 1.3.8 → 1.5.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/dist/index.js CHANGED
@@ -1,4 +1,15 @@
1
1
  // src/transformer.ts
2
+ function extractRef(token) {
3
+ if (typeof token === "object" && token !== null && "ref" in token) {
4
+ const { ref: ref4 } = token;
5
+ return typeof ref4 === "string" ? ref4 : void 0;
6
+ }
7
+ return void 0;
8
+ }
9
+ function renderTokenValue(token) {
10
+ const key = extractRef(token);
11
+ return key === void 0 ? extractValue(token) : `var(--${key})`;
12
+ }
2
13
  function extractValue(token) {
3
14
  if (typeof token === "object" && token !== null && "value" in token) {
4
15
  return String(token.value);
@@ -15,14 +26,17 @@ function themeToCss(theme) {
15
26
  const lines = [];
16
27
  lines.push("@layer base {");
17
28
  lines.push(" :root {");
29
+ for (const [key, value] of Object.entries(theme.palette ?? {})) {
30
+ lines.push(` --${key}: ${value};`);
31
+ }
18
32
  for (const [key, token] of Object.entries(theme.tokens.light)) {
19
- lines.push(` --${key}: ${extractValue(token)};`);
33
+ lines.push(` --${key}: ${renderTokenValue(token)};`);
20
34
  }
21
35
  lines.push(" }");
22
36
  lines.push("");
23
37
  lines.push(" .dark {");
24
38
  for (const [key, token] of Object.entries(theme.tokens.dark)) {
25
- lines.push(` --${key}: ${extractValue(token)};`);
39
+ lines.push(` --${key}: ${renderTokenValue(token)};`);
26
40
  }
27
41
  lines.push(" }");
28
42
  lines.push("}");
@@ -80,10 +94,51 @@ function themeToScopedRuntimeCss(theme, options = {}) {
80
94
  return lines.join("\n");
81
95
  }
82
96
  function generateGlobalsCss(theme, options = {}) {
83
- const { target = "v3" } = options;
84
- if (target === "v4") return generateGlobalsCssV4(theme);
97
+ const { target = "v3", sources } = options;
98
+ if (target === "v4") return generateGlobalsCssV4(theme, sources);
99
+ if (target === "native") return generateGlobalsCssNative(theme);
85
100
  return generateGlobalsCssV3(theme);
86
101
  }
102
+ function flattenTokenSet(tokens) {
103
+ const flat = {};
104
+ for (const [key, token] of Object.entries(tokens)) {
105
+ flat[`--${key}`] = extractValue(token);
106
+ }
107
+ return flat;
108
+ }
109
+ function themeToNativeTheme(theme) {
110
+ return {
111
+ light: flattenTokenSet(theme.tokens.light),
112
+ dark: flattenTokenSet(theme.tokens.dark)
113
+ };
114
+ }
115
+ function generateGlobalsCssNative(theme) {
116
+ const { light, dark } = themeToNativeTheme(theme);
117
+ const lines = [];
118
+ lines.push("@tailwind base;");
119
+ lines.push("@tailwind components;");
120
+ lines.push("@tailwind utilities;");
121
+ lines.push("");
122
+ lines.push("/*");
123
+ lines.push(" * Generated by @hex-core/tokens for NativeWind. Palette references are");
124
+ lines.push(" * resolved to literal H S% L% triplets \u2014 React Native has no cascade for");
125
+ lines.push(' * var() chains. Toggle dark mode with `colorScheme.set("dark")` from nativewind.');
126
+ lines.push(" */");
127
+ lines.push("@layer base {");
128
+ lines.push(" :root {");
129
+ for (const [key, value] of Object.entries(light)) {
130
+ lines.push(` ${key}: ${value};`);
131
+ }
132
+ lines.push(" }");
133
+ lines.push("");
134
+ lines.push(" .dark:root {");
135
+ for (const [key, value] of Object.entries(dark)) {
136
+ lines.push(` ${key}: ${value};`);
137
+ }
138
+ lines.push(" }");
139
+ lines.push("}");
140
+ return lines.join("\n");
141
+ }
87
142
  function generateGlobalsCssV3(theme) {
88
143
  const lines = [];
89
144
  lines.push("@tailwind base;");
@@ -102,28 +157,31 @@ function generateGlobalsCssV3(theme) {
102
157
  lines.push("}");
103
158
  return lines.join("\n");
104
159
  }
105
- function generateGlobalsCssV4(theme) {
160
+ function generateThemeCssV4(theme) {
106
161
  const lines = [];
107
- lines.push(`@import "tailwindcss";`);
108
- lines.push(`@import "tw-animate-css";`);
109
- lines.push("");
110
- lines.push("/* Class-based dark mode \u2014 set `.dark` on <html> via next-themes or your own provider. */");
111
- lines.push("@custom-variant dark (&:is(.dark *));");
112
- lines.push("");
113
162
  lines.push("/*");
114
163
  lines.push(" * Raw token triplets (H S% L%) \u2014 the source of truth that `hex theme edit`");
115
164
  lines.push(" * mutates, and that the @theme inline block below aliases into Tailwind's");
116
165
  lines.push(" * --color-<key> namespace.");
166
+ if (theme.palette) {
167
+ lines.push(" *");
168
+ lines.push(" * Tier 1 is the raw ramp; the semantic tokens below point at it with");
169
+ lines.push(" * var(). Re-tint the whole theme by overriding a ramp entry \u2014 every");
170
+ lines.push(" * semantic token that references it follows.");
171
+ }
117
172
  lines.push(" */");
118
173
  lines.push(":root {");
174
+ for (const [key, value] of Object.entries(theme.palette ?? {})) {
175
+ lines.push(` --${key}: ${value};`);
176
+ }
119
177
  for (const [key, token] of Object.entries(theme.tokens.light)) {
120
- lines.push(` --${key}: ${extractValue(token)};`);
178
+ lines.push(` --${key}: ${renderTokenValue(token)};`);
121
179
  }
122
180
  lines.push("}");
123
181
  lines.push("");
124
182
  lines.push(".dark {");
125
183
  for (const [key, token] of Object.entries(theme.tokens.dark)) {
126
- lines.push(` --${key}: ${extractValue(token)};`);
184
+ lines.push(` --${key}: ${renderTokenValue(token)};`);
127
185
  }
128
186
  lines.push("}");
129
187
  lines.push("");
@@ -149,6 +207,29 @@ function generateGlobalsCssV4(theme) {
149
207
  lines.push("}");
150
208
  return lines.join("\n");
151
209
  }
210
+ function generateGlobalsCssV4(theme, sources) {
211
+ const lines = [];
212
+ const scoped = sources !== void 0 && sources.length > 0;
213
+ if (scoped) {
214
+ lines.push("/*");
215
+ lines.push(" * `source(none)` turns off Tailwind's automatic content detection, which");
216
+ lines.push(" * would otherwise walk up past this app to the enclosing repository and read");
217
+ lines.push(" * binary files as class candidates, emitting utilities that fail to parse.");
218
+ lines.push(" * The @source rules below name this app's own files instead.");
219
+ lines.push(" */");
220
+ lines.push(`@import "tailwindcss" source(none);`);
221
+ for (const source of sources) lines.push(`@source "${source}";`);
222
+ } else {
223
+ lines.push(`@import "tailwindcss";`);
224
+ }
225
+ lines.push(`@import "tw-animate-css";`);
226
+ lines.push("");
227
+ lines.push("/* Class-based dark mode \u2014 set `.dark` on <html> via next-themes or your own provider. */");
228
+ lines.push("@custom-variant dark (&:is(.dark *));");
229
+ lines.push("");
230
+ lines.push(generateThemeCssV4(theme));
231
+ return lines.join("\n");
232
+ }
152
233
 
153
234
  // src/themes/shared.ts
154
235
  var sharedTokens = {
@@ -191,136 +272,216 @@ var sharedTokens = {
191
272
  };
192
273
 
193
274
  // src/themes/default.ts
275
+ var palette = {
276
+ // Slate — brand family.
277
+ "slate-50": "0 0% 98%",
278
+ "slate-100": "222 22.5% 89%",
279
+ "slate-200": "222 8% 90%",
280
+ "slate-300": "222 8% 65%",
281
+ "slate-400": "222 30% 60%",
282
+ "slate-500": "222 8% 38%",
283
+ "slate-600": "222 12% 24%",
284
+ "slate-700": "222 8% 12%",
285
+ "slate-800": "222 12% 14%",
286
+ "slate-900": "222 25% 18%",
287
+ "slate-950": "222 30% 11%",
288
+ "slate-muted": "222 5% 95.9%",
289
+ "slate-contrast": "240 10% 3.9%",
290
+ // Surface — page and card grounds.
291
+ "surface-light": "210 20% 98%",
292
+ "surface-dark": "210 15% 2%",
293
+ "surface-dark-raised": "210 15% 8%",
294
+ // Red — destructive family.
295
+ "red-600": "0 65% 43%",
296
+ "red-300": "0 48.8% 68%",
297
+ "red-contrast": "0 0% 8%",
298
+ // Chart — categorical, cycled by index.
299
+ "chart-light-1": "12 76% 61%",
300
+ "chart-light-2": "173 58% 39%",
301
+ "chart-light-3": "197 37% 50%",
302
+ "chart-light-4": "43 74% 49%",
303
+ "chart-light-5": "280 65% 60%",
304
+ "chart-light-6": "340 75% 55%",
305
+ "chart-dark-1": "12 76% 65%",
306
+ "chart-dark-2": "173 58% 55%",
307
+ "chart-dark-3": "197 37% 60%",
308
+ "chart-dark-4": "43 74% 60%",
309
+ "chart-dark-5": "280 65% 70%",
310
+ "chart-dark-6": "340 75% 65%"
311
+ };
312
+ function ref(key, type = "color") {
313
+ return { value: palette[key], ref: key, type };
314
+ }
194
315
  var defaultTheme = {
195
316
  name: "default",
196
317
  displayName: "Default",
197
318
  description: "A modern, elegant minimalism \u2014 restrained cool-hue grayscale (~222 family) with a graphite primary and tight 0.375rem radius. Designed to recede so content leads; the cool slate carries identity across light + dark.",
319
+ palette,
198
320
  tokens: {
199
321
  light: {
200
- background: { value: "210 20% 98%", type: "color" },
201
- foreground: { value: "222 30% 11%", type: "color" },
202
- card: { value: "210 20% 98%", type: "color" },
203
- "card-foreground": { value: "222 30% 11%", type: "color" },
204
- popover: { value: "210 20% 98%", type: "color" },
205
- "popover-foreground": { value: "222 30% 11%", type: "color" },
206
- primary: { value: "222 25% 18%", type: "color" },
207
- "primary-foreground": { value: "0 0% 98%", type: "color" },
208
- secondary: { value: "222 5% 95.9%", type: "color" },
209
- "secondary-foreground": { value: "240 10% 3.9%", type: "color" },
210
- muted: { value: "222 5% 95.9%", type: "color" },
211
- "muted-foreground": { value: "222 8% 38%", type: "color" },
212
- accent: { value: "222 5% 95.9%", type: "color" },
213
- "accent-foreground": { value: "240 10% 3.9%", type: "color" },
214
- destructive: { value: "0 65% 43%", type: "color" },
215
- "destructive-foreground": { value: "0 0% 98%", type: "color" },
216
- border: { value: "222 8% 90%", type: "color" },
217
- input: { value: "222 8% 90%", type: "color" },
218
- ring: { value: "222 25% 18%", type: "color" },
322
+ background: ref("surface-light"),
323
+ foreground: ref("slate-950"),
324
+ card: ref("surface-light"),
325
+ "card-foreground": ref("slate-950"),
326
+ popover: ref("surface-light"),
327
+ "popover-foreground": ref("slate-950"),
328
+ primary: ref("slate-900"),
329
+ "primary-foreground": ref("slate-50"),
330
+ secondary: ref("slate-muted"),
331
+ "secondary-foreground": ref("slate-contrast"),
332
+ muted: ref("slate-muted"),
333
+ "muted-foreground": ref("slate-500"),
334
+ accent: ref("slate-muted"),
335
+ "accent-foreground": ref("slate-contrast"),
336
+ // L=43% achieves ≥4.5:1 on the destructive/5 alert background.
337
+ // Gated by `pnpm a11y-audit`.
338
+ destructive: ref("red-600"),
339
+ "destructive-foreground": ref("slate-50"),
340
+ border: ref("slate-200"),
341
+ input: ref("slate-200"),
342
+ ring: ref("slate-900"),
219
343
  radius: { value: "0.375rem", type: "radius" },
220
- // Chart palette — perceptually distinct hues for diagram primitives
221
- // (sunburst, treemap, sankey, chord, funnel, pyramid, venn). The
222
- // monochrome `--primary`/`--accent` family is unfit for categorical
223
- // encoding; cycle through these by index instead.
224
- "chart-1": { value: "12 76% 61%", type: "color" },
225
- "chart-2": { value: "173 58% 39%", type: "color" },
226
- "chart-3": { value: "197 37% 50%", type: "color" },
227
- "chart-4": { value: "43 74% 49%", type: "color" },
228
- "chart-5": { value: "280 65% 60%", type: "color" },
229
- "chart-6": { value: "340 75% 55%", type: "color" },
344
+ "chart-1": ref("chart-light-1"),
345
+ "chart-2": ref("chart-light-2"),
346
+ "chart-3": ref("chart-light-3"),
347
+ "chart-4": ref("chart-light-4"),
348
+ "chart-5": ref("chart-light-5"),
349
+ "chart-6": ref("chart-light-6"),
230
350
  ...sharedTokens
231
351
  },
232
352
  dark: {
233
- background: { value: "210 15% 2%", type: "color" },
234
- foreground: { value: "222 22.5% 89%", type: "color" },
235
- // Card/popover lifted from L=8% L=14% so SVG-rendered surfaces
236
- // (org-chart cards, flowchart boxes) read as elevated against bg.
237
- card: { value: "222 12% 14%", type: "color" },
238
- popover: { value: "222 12% 14%", type: "color" },
239
- primary: { value: "222 30% 60%", type: "color" },
240
- secondary: { value: "222 8% 12%", type: "color" },
241
- muted: { value: "222 8% 12%", type: "color" },
242
- accent: { value: "222 8% 12%", type: "color" },
243
- // Lightness lifted from L=58% to L=68% so `text-destructive` on
244
- // the dark `--card` (L=14%) clears WCAG AA 4.5:1 contrast (was 4.02:1).
245
- destructive: { value: "0 48.8% 68%", type: "color" },
246
- // Border lifted from L=14% → L=24% so SVG outlines (chord arcs,
247
- // sankey segments, gantt grid) have actual definition.
248
- border: { value: "222 12% 24%", type: "color" },
249
- input: { value: "222 12% 24%", type: "color" },
250
- ring: { value: "222 30% 60%", type: "color" },
353
+ background: ref("surface-dark"),
354
+ foreground: ref("slate-100"),
355
+ // Card/popover sit one surface step above background (L=14% vs 2%)
356
+ // so SVG-rendered surfaces — org-chart cards, flowchart boxes
357
+ // read as elevated without box-shadow chrome.
358
+ card: ref("slate-800"),
359
+ popover: ref("slate-800"),
360
+ primary: ref("slate-400"),
361
+ secondary: ref("slate-700"),
362
+ muted: ref("slate-700"),
363
+ accent: ref("slate-700"),
364
+ // L=68%, not 58%, so `text-destructive` on the dark card clears
365
+ // WCAG AA 4.5:1 (was 4.02:1).
366
+ destructive: ref("red-300"),
367
+ // L=24%, not 14%, so SVG outlines — chord arcs, sankey segments,
368
+ // gantt grid have actual definition against the card.
369
+ border: ref("slate-600"),
370
+ input: ref("slate-600"),
371
+ ring: ref("slate-400"),
251
372
  radius: { value: "0.375rem", type: "radius" },
252
- "card-foreground": { value: "222 22.5% 89%", type: "color" },
253
- "popover-foreground": { value: "222 22.5% 89%", type: "color" },
254
- "primary-foreground": { value: "210 15% 8%", type: "color" },
255
- "secondary-foreground": { value: "222 22.5% 89%", type: "color" },
256
- "muted-foreground": { value: "222 8% 65%", type: "color" },
257
- "accent-foreground": { value: "222 22.5% 89%", type: "color" },
258
- "destructive-foreground": { value: "0 0% 8%", type: "color" },
259
- // Lifted lightness for legibility on near-black background.
260
- "chart-1": { value: "12 76% 65%", type: "color" },
261
- "chart-2": { value: "173 58% 55%", type: "color" },
262
- "chart-3": { value: "197 37% 60%", type: "color" },
263
- "chart-4": { value: "43 74% 60%", type: "color" },
264
- "chart-5": { value: "280 65% 70%", type: "color" },
265
- "chart-6": { value: "340 75% 65%", type: "color" },
373
+ "card-foreground": ref("slate-100"),
374
+ "popover-foreground": ref("slate-100"),
375
+ "primary-foreground": ref("surface-dark-raised"),
376
+ "secondary-foreground": ref("slate-100"),
377
+ "muted-foreground": ref("slate-300"),
378
+ "accent-foreground": ref("slate-100"),
379
+ "destructive-foreground": ref("red-contrast"),
380
+ "chart-1": ref("chart-dark-1"),
381
+ "chart-2": ref("chart-dark-2"),
382
+ "chart-3": ref("chart-dark-3"),
383
+ "chart-4": ref("chart-dark-4"),
384
+ "chart-5": ref("chart-dark-5"),
385
+ "chart-6": ref("chart-dark-6"),
266
386
  ...sharedTokens
267
387
  }
268
388
  }
269
389
  };
270
390
 
271
391
  // src/themes/midnight.ts
392
+ var palette2 = {
393
+ // Indigo — brand.
394
+ "indigo-400": "226 70% 65%",
395
+ "indigo-500": "226 70% 55%",
396
+ // Slate — cool neutral ramp, both modes.
397
+ "slate-0": "0 0% 100%",
398
+ "slate-25": "220 23% 99%",
399
+ "slate-50": "220 23% 97%",
400
+ "slate-100": "220 23% 95%",
401
+ "slate-150": "220 14% 94%",
402
+ "slate-200": "220 14% 92%",
403
+ "slate-300": "220 13% 88%",
404
+ "slate-400": "220 9% 70%",
405
+ "slate-500": "220 9% 38%",
406
+ "slate-800": "224 30% 15%",
407
+ "slate-825": "224 20% 14%",
408
+ "slate-850": "224 30% 13%",
409
+ "slate-900": "224 50% 7%",
410
+ "slate-950": "224 71% 4%",
411
+ // Red — destructive.
412
+ "red-300": "0 75% 65%",
413
+ "red-600": "0 72% 45%",
414
+ "red-950": "0 75% 15%",
415
+ // Chart — categorical, cycled by index.
416
+ "chart-light-1": "226 70% 55%",
417
+ "chart-light-2": "165 60% 40%",
418
+ "chart-light-3": "20 80% 55%",
419
+ "chart-light-4": "280 65% 60%",
420
+ "chart-light-5": "45 80% 55%",
421
+ "chart-light-6": "330 70% 55%",
422
+ "chart-dark-1": "226 70% 65%",
423
+ "chart-dark-2": "165 60% 55%",
424
+ "chart-dark-3": "20 80% 65%",
425
+ "chart-dark-4": "280 65% 70%",
426
+ "chart-dark-5": "45 80% 65%",
427
+ "chart-dark-6": "330 70% 65%"
428
+ };
429
+ function ref2(key, type = "color") {
430
+ return { value: palette2[key], ref: key, type };
431
+ }
272
432
  var midnightTheme = {
273
433
  name: "midnight",
274
434
  displayName: "Midnight",
275
435
  description: "A dark-first theme with deep blues and electric accents. Built for focus-heavy interfaces and developer tools.",
436
+ palette: palette2,
276
437
  tokens: {
277
438
  light: {
278
- background: { value: "220 23% 97%", type: "color" },
279
- foreground: { value: "224 71% 4%", type: "color" },
280
- card: { value: "220 23% 99%", type: "color" },
281
- "card-foreground": { value: "224 71% 4%", type: "color" },
282
- popover: { value: "220 23% 99%", type: "color" },
283
- "popover-foreground": { value: "224 71% 4%", type: "color" },
284
- primary: { value: "226 70% 55%", type: "color" },
285
- "primary-foreground": { value: "0 0% 100%", type: "color" },
286
- secondary: { value: "220 14% 92%", type: "color" },
287
- "secondary-foreground": { value: "224 71% 4%", type: "color" },
288
- muted: { value: "220 14% 94%", type: "color" },
289
- "muted-foreground": { value: "220 9% 38%", type: "color" },
290
- accent: { value: "220 14% 92%", type: "color" },
291
- "accent-foreground": { value: "224 71% 4%", type: "color" },
292
- destructive: { value: "0 72% 45%", type: "color" },
293
- "destructive-foreground": { value: "0 0% 100%", type: "color" },
294
- border: { value: "220 13% 88%", type: "color" },
295
- input: { value: "220 13% 88%", type: "color" },
296
- ring: { value: "226 70% 55%", type: "color" },
439
+ background: ref2("slate-50"),
440
+ foreground: ref2("slate-950"),
441
+ card: ref2("slate-25"),
442
+ "card-foreground": ref2("slate-950"),
443
+ popover: ref2("slate-25"),
444
+ "popover-foreground": ref2("slate-950"),
445
+ primary: ref2("indigo-500"),
446
+ "primary-foreground": ref2("slate-0"),
447
+ secondary: ref2("slate-200"),
448
+ "secondary-foreground": ref2("slate-950"),
449
+ muted: ref2("slate-150"),
450
+ "muted-foreground": ref2("slate-500"),
451
+ accent: ref2("slate-200"),
452
+ "accent-foreground": ref2("slate-950"),
453
+ destructive: ref2("red-600"),
454
+ "destructive-foreground": ref2("slate-0"),
455
+ border: ref2("slate-300"),
456
+ input: ref2("slate-300"),
457
+ ring: ref2("indigo-500"),
297
458
  radius: { value: "0.5rem", type: "radius" },
298
459
  // Chart palette — cool-leaning hues that complement the
299
460
  // midnight blue primary while staying perceptually distinct
300
461
  // for categorical encoding.
301
- "chart-1": { value: "226 70% 55%", type: "color" },
302
- "chart-2": { value: "165 60% 40%", type: "color" },
303
- "chart-3": { value: "20 80% 55%", type: "color" },
304
- "chart-4": { value: "280 65% 60%", type: "color" },
305
- "chart-5": { value: "45 80% 55%", type: "color" },
306
- "chart-6": { value: "330 70% 55%", type: "color" },
462
+ "chart-1": ref2("chart-light-1"),
463
+ "chart-2": ref2("chart-light-2"),
464
+ "chart-3": ref2("chart-light-3"),
465
+ "chart-4": ref2("chart-light-4"),
466
+ "chart-5": ref2("chart-light-5"),
467
+ "chart-6": ref2("chart-light-6"),
307
468
  ...sharedTokens
308
469
  },
309
470
  dark: {
310
- background: { value: "224 71% 4%", type: "color" },
311
- foreground: { value: "220 23% 95%", type: "color" },
312
- card: { value: "224 50% 7%", type: "color" },
313
- "card-foreground": { value: "220 23% 95%", type: "color" },
314
- popover: { value: "224 50% 7%", type: "color" },
315
- "popover-foreground": { value: "220 23% 95%", type: "color" },
316
- primary: { value: "226 70% 55%", type: "color" },
317
- "primary-foreground": { value: "0 0% 100%", type: "color" },
318
- secondary: { value: "224 30% 13%", type: "color" },
319
- "secondary-foreground": { value: "220 23% 95%", type: "color" },
320
- muted: { value: "224 30% 13%", type: "color" },
321
- "muted-foreground": { value: "220 9% 70%", type: "color" },
322
- accent: { value: "224 30% 15%", type: "color" },
323
- "accent-foreground": { value: "220 23% 95%", type: "color" },
471
+ background: ref2("slate-950"),
472
+ foreground: ref2("slate-100"),
473
+ card: ref2("slate-900"),
474
+ "card-foreground": ref2("slate-100"),
475
+ popover: ref2("slate-900"),
476
+ "popover-foreground": ref2("slate-100"),
477
+ primary: ref2("indigo-500"),
478
+ "primary-foreground": ref2("slate-0"),
479
+ secondary: ref2("slate-850"),
480
+ "secondary-foreground": ref2("slate-100"),
481
+ muted: ref2("slate-850"),
482
+ "muted-foreground": ref2("slate-400"),
483
+ accent: ref2("slate-800"),
484
+ "accent-foreground": ref2("slate-100"),
324
485
  /*
325
486
  * Destructive in dark mode doubles as text on near-black surfaces
326
487
  * (alerts, error helper text). A lighter coral-red gives ~7:1 on
@@ -328,98 +489,141 @@ var midnightTheme = {
328
489
  * destructive-foreground for button bg + label combos. Same tuning
329
490
  * as default.ts; intentional shadcn-divergence in service of WCAG AA.
330
491
  */
331
- destructive: { value: "0 75% 65%", type: "color" },
332
- "destructive-foreground": { value: "0 75% 15%", type: "color" },
333
- border: { value: "224 20% 14%", type: "color" },
334
- input: { value: "224 20% 14%", type: "color" },
335
- ring: { value: "226 70% 55%", type: "color" },
492
+ destructive: ref2("red-300"),
493
+ "destructive-foreground": ref2("red-950"),
494
+ border: ref2("slate-825"),
495
+ input: ref2("slate-825"),
496
+ ring: ref2("indigo-500"),
336
497
  radius: { value: "0.5rem", type: "radius" },
337
498
  // Lifted lightness so segments stay legible against deep navy bg.
338
- "chart-1": { value: "226 70% 65%", type: "color" },
339
- "chart-2": { value: "165 60% 55%", type: "color" },
340
- "chart-3": { value: "20 80% 65%", type: "color" },
341
- "chart-4": { value: "280 65% 70%", type: "color" },
342
- "chart-5": { value: "45 80% 65%", type: "color" },
343
- "chart-6": { value: "330 70% 65%", type: "color" },
499
+ "chart-1": ref2("chart-dark-1"),
500
+ "chart-2": ref2("chart-dark-2"),
501
+ "chart-3": ref2("chart-dark-3"),
502
+ "chart-4": ref2("chart-dark-4"),
503
+ "chart-5": ref2("chart-dark-5"),
504
+ "chart-6": ref2("chart-dark-6"),
344
505
  ...sharedTokens
345
506
  }
346
507
  }
347
508
  };
348
509
 
349
510
  // src/themes/ember.ts
511
+ var palette3 = {
512
+ // Ember — terracotta brand.
513
+ "ember-400": "16 65% 52%",
514
+ "ember-500": "16 65% 48%",
515
+ // Sand — warm light neutrals.
516
+ "sand-0": "0 0% 100%",
517
+ "sand-25": "30 33% 99%",
518
+ "sand-50": "30 33% 98%",
519
+ "sand-100": "30 20% 94%",
520
+ "sand-200": "30 20% 92%",
521
+ "sand-300": "30 15% 87%",
522
+ "amber-100": "36 60% 90%",
523
+ // Bark — warm dark neutrals.
524
+ "bark-400": "20 6% 70%",
525
+ "bark-500": "20 6% 38%",
526
+ "bark-800": "20 20% 16%",
527
+ "bark-825": "20 10% 16%",
528
+ "bark-850": "20 12% 14%",
529
+ "bark-900": "20 14% 10%",
530
+ "bark-925": "20 14% 8%",
531
+ "bark-950": "20 14% 6%",
532
+ // Red — destructive.
533
+ "red-300": "0 75% 65%",
534
+ "red-600": "0 72% 45%",
535
+ "red-950": "0 75% 15%",
536
+ // Chart — categorical, cycled by index.
537
+ "chart-light-1": "16 75% 55%",
538
+ "chart-light-2": "180 55% 38%",
539
+ "chart-light-3": "200 60% 50%",
540
+ "chart-light-4": "45 80% 50%",
541
+ "chart-light-5": "280 60% 60%",
542
+ "chart-light-6": "330 70% 55%",
543
+ "chart-dark-1": "16 75% 60%",
544
+ "chart-dark-2": "180 55% 55%",
545
+ "chart-dark-3": "200 60% 60%",
546
+ "chart-dark-4": "45 80% 60%",
547
+ "chart-dark-5": "280 60% 70%",
548
+ "chart-dark-6": "330 70% 65%"
549
+ };
550
+ function ref3(key, type = "color") {
551
+ return { value: palette3[key], ref: key, type };
552
+ }
350
553
  var emberTheme = {
351
554
  name: "ember",
352
555
  displayName: "Ember",
353
556
  description: "A warm theme with terracotta and amber tones. Inviting and distinctive, ideal for creative and lifestyle applications.",
557
+ palette: palette3,
354
558
  tokens: {
355
559
  light: {
356
- background: { value: "30 33% 98%", type: "color" },
357
- foreground: { value: "20 14% 10%", type: "color" },
358
- card: { value: "30 33% 99%", type: "color" },
359
- "card-foreground": { value: "20 14% 10%", type: "color" },
360
- popover: { value: "30 33% 99%", type: "color" },
361
- "popover-foreground": { value: "20 14% 10%", type: "color" },
362
- primary: { value: "16 65% 48%", type: "color" },
363
- "primary-foreground": { value: "0 0% 100%", type: "color" },
364
- secondary: { value: "30 20% 92%", type: "color" },
365
- "secondary-foreground": { value: "20 14% 10%", type: "color" },
366
- muted: { value: "30 20% 94%", type: "color" },
367
- "muted-foreground": { value: "20 6% 38%", type: "color" },
368
- accent: { value: "36 60% 90%", type: "color" },
369
- "accent-foreground": { value: "20 14% 10%", type: "color" },
370
- destructive: { value: "0 72% 45%", type: "color" },
371
- "destructive-foreground": { value: "0 0% 100%", type: "color" },
372
- border: { value: "30 15% 87%", type: "color" },
373
- input: { value: "30 15% 87%", type: "color" },
374
- ring: { value: "16 65% 48%", type: "color" },
560
+ background: ref3("sand-50"),
561
+ foreground: ref3("bark-900"),
562
+ card: ref3("sand-25"),
563
+ "card-foreground": ref3("bark-900"),
564
+ popover: ref3("sand-25"),
565
+ "popover-foreground": ref3("bark-900"),
566
+ primary: ref3("ember-500"),
567
+ "primary-foreground": ref3("sand-0"),
568
+ secondary: ref3("sand-200"),
569
+ "secondary-foreground": ref3("bark-900"),
570
+ muted: ref3("sand-100"),
571
+ "muted-foreground": ref3("bark-500"),
572
+ accent: ref3("amber-100"),
573
+ "accent-foreground": ref3("bark-900"),
574
+ destructive: ref3("red-600"),
575
+ "destructive-foreground": ref3("sand-0"),
576
+ border: ref3("sand-300"),
577
+ input: ref3("sand-300"),
578
+ ring: ref3("ember-500"),
375
579
  radius: { value: "0.75rem", type: "radius" },
376
580
  // Chart palette — warm-leaning hues that complement the ember
377
581
  // terracotta primary while staying perceptually distinct from
378
582
  // each other for categorical encoding (sunburst/treemap/sankey/
379
583
  // chord/funnel/pyramid/venn/matrix).
380
- "chart-1": { value: "16 75% 55%", type: "color" },
381
- "chart-2": { value: "180 55% 38%", type: "color" },
382
- "chart-3": { value: "200 60% 50%", type: "color" },
383
- "chart-4": { value: "45 80% 50%", type: "color" },
384
- "chart-5": { value: "280 60% 60%", type: "color" },
385
- "chart-6": { value: "330 70% 55%", type: "color" },
584
+ "chart-1": ref3("chart-light-1"),
585
+ "chart-2": ref3("chart-light-2"),
586
+ "chart-3": ref3("chart-light-3"),
587
+ "chart-4": ref3("chart-light-4"),
588
+ "chart-5": ref3("chart-light-5"),
589
+ "chart-6": ref3("chart-light-6"),
386
590
  ...sharedTokens
387
591
  },
388
592
  dark: {
389
- background: { value: "20 14% 6%", type: "color" },
390
- foreground: { value: "30 20% 94%", type: "color" },
391
- card: { value: "20 14% 8%", type: "color" },
392
- "card-foreground": { value: "30 20% 94%", type: "color" },
393
- popover: { value: "20 14% 8%", type: "color" },
394
- "popover-foreground": { value: "30 20% 94%", type: "color" },
395
- primary: { value: "16 65% 52%", type: "color" },
396
- "primary-foreground": { value: "0 0% 100%", type: "color" },
397
- secondary: { value: "20 12% 14%", type: "color" },
398
- "secondary-foreground": { value: "30 20% 94%", type: "color" },
399
- muted: { value: "20 12% 14%", type: "color" },
400
- "muted-foreground": { value: "20 6% 70%", type: "color" },
401
- accent: { value: "20 20% 16%", type: "color" },
402
- "accent-foreground": { value: "30 20% 94%", type: "color" },
593
+ background: ref3("bark-950"),
594
+ foreground: ref3("sand-100"),
595
+ card: ref3("bark-925"),
596
+ "card-foreground": ref3("sand-100"),
597
+ popover: ref3("bark-925"),
598
+ "popover-foreground": ref3("sand-100"),
599
+ primary: ref3("ember-400"),
600
+ "primary-foreground": ref3("sand-0"),
601
+ secondary: ref3("bark-850"),
602
+ "secondary-foreground": ref3("sand-100"),
603
+ muted: ref3("bark-850"),
604
+ "muted-foreground": ref3("bark-400"),
605
+ accent: ref3("bark-800"),
606
+ "accent-foreground": ref3("sand-100"),
403
607
  /*
404
608
  * Destructive in dark mode doubles as text on near-black surfaces
405
609
  * (alerts, error helper text). A lighter coral-red gives ~7:1 on
406
610
  * background and ~5:1 on the same color when paired with the dark
407
611
  * destructive-foreground. Same tuning as default.ts.
408
612
  */
409
- destructive: { value: "0 75% 65%", type: "color" },
410
- "destructive-foreground": { value: "0 75% 15%", type: "color" },
411
- border: { value: "20 10% 16%", type: "color" },
412
- input: { value: "20 10% 16%", type: "color" },
413
- ring: { value: "16 65% 52%", type: "color" },
613
+ destructive: ref3("red-300"),
614
+ "destructive-foreground": ref3("red-950"),
615
+ border: ref3("bark-825"),
616
+ input: ref3("bark-825"),
617
+ ring: ref3("ember-400"),
414
618
  radius: { value: "0.75rem", type: "radius" },
415
619
  // Lifted lightness so segments stay legible against the warm
416
620
  // near-black background.
417
- "chart-1": { value: "16 75% 60%", type: "color" },
418
- "chart-2": { value: "180 55% 55%", type: "color" },
419
- "chart-3": { value: "200 60% 60%", type: "color" },
420
- "chart-4": { value: "45 80% 60%", type: "color" },
421
- "chart-5": { value: "280 60% 70%", type: "color" },
422
- "chart-6": { value: "330 70% 65%", type: "color" },
621
+ "chart-1": ref3("chart-dark-1"),
622
+ "chart-2": ref3("chart-dark-2"),
623
+ "chart-3": ref3("chart-dark-3"),
624
+ "chart-4": ref3("chart-dark-4"),
625
+ "chart-5": ref3("chart-dark-5"),
626
+ "chart-6": ref3("chart-dark-6"),
423
627
  ...sharedTokens
424
628
  }
425
629
  }
@@ -722,6 +926,8 @@ export {
722
926
  deriveSecondaryFromPrimary,
723
927
  emberTheme,
724
928
  generateGlobalsCss,
929
+ generateGlobalsCssNative,
930
+ generateThemeCssV4,
725
931
  getTheme,
726
932
  listThemes,
727
933
  midnightTheme,
@@ -729,6 +935,7 @@ export {
729
935
  sharedTokens,
730
936
  themeToCss,
731
937
  themeToFlatJson,
938
+ themeToNativeTheme,
732
939
  themeToScopedRuntimeCss,
733
940
  themeToTailwindConfig,
734
941
  themes,