@uni-design-system/uni-core 3.0.2 → 5.0.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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/index.cjs +1490 -767
  3. package/dist/cjs/index.cjs.map +1 -1
  4. package/dist/esm/index.js +1464 -768
  5. package/dist/esm/index.js.map +1 -1
  6. package/dist/types/concepts/color/color.factory.d.ts +48 -0
  7. package/dist/types/concepts/color/color.factory.d.ts.map +1 -0
  8. package/dist/types/concepts/color/color.helper.d.ts +15 -0
  9. package/dist/types/concepts/color/color.helper.d.ts.map +1 -1
  10. package/dist/types/concepts/color/color.records.d.ts +9 -0
  11. package/dist/types/concepts/color/color.records.d.ts.map +1 -1
  12. package/dist/types/concepts/color/color.types.d.ts +2 -2
  13. package/dist/types/concepts/color/color.types.d.ts.map +1 -1
  14. package/dist/types/concepts/color/color.utils.d.ts +17 -0
  15. package/dist/types/concepts/color/color.utils.d.ts.map +1 -1
  16. package/dist/types/concepts/color/index.d.ts +1 -0
  17. package/dist/types/concepts/color/index.d.ts.map +1 -1
  18. package/dist/types/concepts/component/component.types.d.ts +9 -3
  19. package/dist/types/concepts/component/component.types.d.ts.map +1 -1
  20. package/dist/types/concepts/generation/generation.spec.d.ts +2 -0
  21. package/dist/types/concepts/generation/generation.spec.d.ts.map +1 -0
  22. package/dist/types/concepts/generation/generation.types.d.ts +59 -0
  23. package/dist/types/concepts/generation/generation.types.d.ts.map +1 -0
  24. package/dist/types/concepts/generation/index.d.ts +6 -0
  25. package/dist/types/concepts/generation/index.d.ts.map +1 -0
  26. package/dist/types/concepts/generation/oklch.helper.d.ts +22 -0
  27. package/dist/types/concepts/generation/oklch.helper.d.ts.map +1 -0
  28. package/dist/types/concepts/generation/palette.factory.d.ts +23 -0
  29. package/dist/types/concepts/generation/palette.factory.d.ts.map +1 -0
  30. package/dist/types/concepts/generation/theme-file.emitter.d.ts +26 -0
  31. package/dist/types/concepts/generation/theme-file.emitter.d.ts.map +1 -0
  32. package/dist/types/concepts/generation/theme.generator.d.ts +30 -0
  33. package/dist/types/concepts/generation/theme.generator.d.ts.map +1 -0
  34. package/dist/types/concepts/index.d.ts +1 -0
  35. package/dist/types/concepts/index.d.ts.map +1 -1
  36. package/dist/types/concepts/size/size.types.d.ts +1 -0
  37. package/dist/types/concepts/size/size.types.d.ts.map +1 -1
  38. package/dist/types/concepts/style/index.d.ts +1 -0
  39. package/dist/types/concepts/style/index.d.ts.map +1 -1
  40. package/dist/types/concepts/style/inputs.constants.d.ts +3 -0
  41. package/dist/types/concepts/style/inputs.constants.d.ts.map +1 -0
  42. package/dist/types/concepts/style/style.types.d.ts +3 -1
  43. package/dist/types/concepts/style/style.types.d.ts.map +1 -1
  44. package/dist/types/concepts/theme/theme.model.d.ts +14 -14
  45. package/dist/types/concepts/theme/theme.model.d.ts.map +1 -1
  46. package/dist/types/concepts/theme/theme.types.d.ts +2 -0
  47. package/dist/types/concepts/theme/theme.types.d.ts.map +1 -1
  48. package/dist/types/concepts/theme/themes/base.theme.d.ts +44 -1
  49. package/dist/types/concepts/theme/themes/base.theme.d.ts.map +1 -1
  50. package/dist/types/concepts/theme/themes/dark.theme.d.ts +3 -2
  51. package/dist/types/concepts/theme/themes/dark.theme.d.ts.map +1 -1
  52. package/dist/types/concepts/theme/themes/light.theme.d.ts +1 -2
  53. package/dist/types/concepts/theme/themes/light.theme.d.ts.map +1 -1
  54. package/dist/types/concepts/typography/index.d.ts +1 -0
  55. package/dist/types/concepts/typography/index.d.ts.map +1 -1
  56. package/dist/types/concepts/typography/typeface.helpers.d.ts +9 -0
  57. package/dist/types/concepts/typography/typeface.helpers.d.ts.map +1 -0
  58. package/package.json +6 -2
  59. package/dist/types/concepts/theme/themes/square.theme.d.ts +0 -3
  60. package/dist/types/concepts/theme/themes/square.theme.d.ts.map +0 -1
package/dist/esm/index.js CHANGED
@@ -29,6 +29,11 @@ var collapseFadeOut = {
29
29
  };
30
30
  //#endregion
31
31
  //#region src/concepts/color/color.records.ts
32
+ /**
33
+ * @deprecated HSL saturation ranges are superseded by the perceptual OKLCH
34
+ * chroma model inside `concepts/generation` (see `generateThemes`). Kept for
35
+ * legacy callers of `uniColor`; removal follows the changeset major process.
36
+ */
32
37
  var CategorySaturation = {
33
38
  jewel: {
34
39
  low: 73,
@@ -55,6 +60,10 @@ var CategorySaturation = {
55
60
  high: 0
56
61
  }
57
62
  };
63
+ /**
64
+ * @deprecated HSL lightness ranges are superseded by the perceptual OKLCH
65
+ * tone slots inside `concepts/generation` (see `generateThemes`).
66
+ */
58
67
  var CategoryLightness = {
59
68
  jewel: {
60
69
  low: 56,
@@ -130,6 +139,11 @@ var RoleHues = {
130
139
  };
131
140
  //#endregion
132
141
  //#region src/concepts/color/color.utils.ts
142
+ /**
143
+ * @deprecated Randomized generation is superseded by the deterministic OKLCH
144
+ * engine in `concepts/generation` — same input, same theme. Seeded "surprise
145
+ * me" behavior belongs in the consumer (playground), not the engine.
146
+ */
133
147
  var randomRangeValue = ({ low, high }) => {
134
148
  low = Math.ceil(low);
135
149
  high = Math.floor(high);
@@ -144,6 +158,52 @@ var getAnalogousHues = (hue) => [cycle(hue + 30), cycle(hue + 60)];
144
158
  var getComplimentaryHue = (hue) => cycle(hue + 180);
145
159
  var getTriadicHues = (hue) => [cycle(hue + 120), cycle(hue - 120)];
146
160
  var getSplitComplimentaryHues = (hue) => [cycle(hue + 150), cycle(hue - 150)];
161
+ /**
162
+ * Derive the primary/secondary/tertiary hues from a seed hue using the color
163
+ * wheel relationships in {@link ColorScheme}. Pure angle math — works in any
164
+ * hue space (HSL historically, OKLCH in the generation engine).
165
+ */
166
+ var schemeHues = (hue, scheme) => {
167
+ switch (scheme) {
168
+ case "monochromatic": return {
169
+ primary: hue,
170
+ secondary: hue,
171
+ tertiary: hue
172
+ };
173
+ case "analogous": {
174
+ const [a, b] = getAnalogousHues(hue);
175
+ return {
176
+ primary: hue,
177
+ secondary: a,
178
+ tertiary: b
179
+ };
180
+ }
181
+ case "complimentary": {
182
+ const [a] = getAnalogousHues(hue);
183
+ return {
184
+ primary: hue,
185
+ secondary: getComplimentaryHue(hue),
186
+ tertiary: a
187
+ };
188
+ }
189
+ case "splitComplimentary": {
190
+ const [a, b] = getSplitComplimentaryHues(hue);
191
+ return {
192
+ primary: hue,
193
+ secondary: a,
194
+ tertiary: b
195
+ };
196
+ }
197
+ case "triadic": {
198
+ const [a, b] = getTriadicHues(hue);
199
+ return {
200
+ primary: hue,
201
+ secondary: a,
202
+ tertiary: b
203
+ };
204
+ }
205
+ }
206
+ };
147
207
  //#endregion
148
208
  //#region src/concepts/color/color.helper.ts
149
209
  function HSLAToString({ hue, saturation, lightness, alpha = 1 }) {
@@ -152,6 +212,11 @@ function HSLAToString({ hue, saturation, lightness, alpha = 1 }) {
152
212
  function RGBToString({ red, green, blue }) {
153
213
  return `rgb(${red}, ${green}, ${blue})`;
154
214
  }
215
+ /**
216
+ * @deprecated Random HSL generation produces non-deterministic, perceptually
217
+ * uneven colors. Use the OKLCH engine (`generateThemes` in
218
+ * `concepts/generation`) or `generatePalette` instead.
219
+ */
155
220
  function uniColor({ role, category, alpha = 1 }) {
156
221
  return HSLAToString({
157
222
  hue: randomRangeValue(RoleHues[role]),
@@ -173,6 +238,516 @@ var RGBToHSL = ({ red, green, blue }) => {
173
238
  lightness: 100 * (2 * l - s) / 2
174
239
  };
175
240
  };
241
+ var clamp$2 = (value, min, max) => Math.min(max, Math.max(min, value));
242
+ var toHex2 = (value) => clamp$2(Math.round(value), 0, 255).toString(16).padStart(2, "0");
243
+ var rgbToHex = ({ red, green, blue }) => `#${toHex2(red)}${toHex2(green)}${toHex2(blue)}`.toUpperCase();
244
+ var hexToRgb = (hex) => {
245
+ let h = hex.replace("#", "").trim();
246
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
247
+ const int = parseInt(h, 16);
248
+ return {
249
+ red: int >> 16 & 255,
250
+ green: int >> 8 & 255,
251
+ blue: int & 255
252
+ };
253
+ };
254
+ var HSLToRGB = ({ hue = 0, saturation = 0, lightness = 0 }) => {
255
+ const s = clamp$2(saturation, 0, 100) / 100;
256
+ const l = clamp$2(lightness, 0, 100) / 100;
257
+ const c = (1 - Math.abs(2 * l - 1)) * s;
258
+ const hp = (hue % 360 + 360) % 360 / 60;
259
+ const x = c * (1 - Math.abs(hp % 2 - 1));
260
+ const [r1, g1, b1] = hp < 1 ? [
261
+ c,
262
+ x,
263
+ 0
264
+ ] : hp < 2 ? [
265
+ x,
266
+ c,
267
+ 0
268
+ ] : hp < 3 ? [
269
+ 0,
270
+ c,
271
+ x
272
+ ] : hp < 4 ? [
273
+ 0,
274
+ x,
275
+ c
276
+ ] : hp < 5 ? [
277
+ x,
278
+ 0,
279
+ c
280
+ ] : [
281
+ c,
282
+ 0,
283
+ x
284
+ ];
285
+ const m = l - c / 2;
286
+ return {
287
+ red: (r1 + m) * 255,
288
+ green: (g1 + m) * 255,
289
+ blue: (b1 + m) * 255
290
+ };
291
+ };
292
+ /** Build an sRGB hex string straight from HSL channel values. */
293
+ var HSLToHex = (hsl) => rgbToHex(HSLToRGB(hsl));
294
+ var hexToHSL = (hex) => RGBToHSL(hexToRgb(hex));
295
+ /** WCAG relative luminance of an sRGB color (0 = black, 1 = white). */
296
+ var relativeLuminance = ({ red, green, blue }) => {
297
+ const channel = (value) => {
298
+ const v = value / 255;
299
+ return v <= .03928 ? v / 12.92 : Math.pow((v + .055) / 1.055, 2.4);
300
+ };
301
+ return .2126 * channel(red) + .7152 * channel(green) + .0722 * channel(blue);
302
+ };
303
+ /** WCAG contrast ratio between two colors (1:1 – 21:1). Accepts RGB or hex. */
304
+ var contrastRatio = (a, b) => {
305
+ const la = relativeLuminance(typeof a === "string" ? hexToRgb(a) : a);
306
+ const lb = relativeLuminance(typeof b === "string" ? hexToRgb(b) : b);
307
+ const [hi, lo] = la > lb ? [la, lb] : [lb, la];
308
+ return (hi + .05) / (lo + .05);
309
+ };
310
+ //#endregion
311
+ //#region src/concepts/generation/oklch.helper.ts
312
+ var clamp$1 = (value, min, max) => Math.min(max, Math.max(min, value));
313
+ var srgbToLinear = (channel) => channel <= .04045 ? channel / 12.92 : Math.pow((channel + .055) / 1.055, 2.4);
314
+ var linearToSrgb = (channel) => channel <= .0031308 ? 12.92 * channel : 1.055 * Math.pow(channel, 1 / 2.4) - .055;
315
+ var linearRgbToOklab = ({ r, g, b }) => {
316
+ const l = Math.cbrt(.4122214708 * r + .5363325363 * g + .0514459929 * b);
317
+ const m = Math.cbrt(.2119034982 * r + .6806995451 * g + .1073969566 * b);
318
+ const s = Math.cbrt(.0883024619 * r + .2817188376 * g + .6299787005 * b);
319
+ return {
320
+ l: .2104542553 * l + .793617785 * m - .0040720468 * s,
321
+ a: 1.9779984951 * l - 2.428592205 * m + .4505937099 * s,
322
+ b: .0259040371 * l + .7827717662 * m - .808675766 * s
323
+ };
324
+ };
325
+ var oklabToLinearRgb = (l, a, b) => {
326
+ const l_ = Math.pow(l + .3963377774 * a + .2158037573 * b, 3);
327
+ const m_ = Math.pow(l - .1055613458 * a - .0638541728 * b, 3);
328
+ const s_ = Math.pow(l - .0894841775 * a - 1.291485548 * b, 3);
329
+ return {
330
+ r: 4.0767416621 * l_ - 3.3077115913 * m_ + .2309699292 * s_,
331
+ g: -1.2684380046 * l_ + 2.6097574011 * m_ - .3413193965 * s_,
332
+ b: -.0041960863 * l_ - .7034186147 * m_ + 1.707614701 * s_
333
+ };
334
+ };
335
+ var oklchToLinearRgb = ({ l, c, h }) => {
336
+ const rad = h * Math.PI / 180;
337
+ return oklabToLinearRgb(l, c * Math.cos(rad), c * Math.sin(rad));
338
+ };
339
+ var GAMUT_EPSILON = 1e-4;
340
+ var inSrgbGamut = ({ r, g, b }) => r >= -GAMUT_EPSILON && r <= 1 + GAMUT_EPSILON && g >= -GAMUT_EPSILON && g <= 1 + GAMUT_EPSILON && b >= -GAMUT_EPSILON && b <= 1 + GAMUT_EPSILON;
341
+ /** Parse a hex color (`#RGB` or `#RRGGBB`) into OKLCH. */
342
+ var hexToOklch = (hex) => {
343
+ const { red, green, blue } = hexToRgb(hex);
344
+ const { l, a, b } = linearRgbToOklab({
345
+ r: srgbToLinear(red / 255),
346
+ g: srgbToLinear(green / 255),
347
+ b: srgbToLinear(blue / 255)
348
+ });
349
+ const c = Math.hypot(a, b);
350
+ const h = c < 1e-6 ? 0 : Math.atan2(b, a) * 180 / Math.PI;
351
+ return {
352
+ l,
353
+ c,
354
+ h: h < 0 ? h + 360 : h
355
+ };
356
+ };
357
+ /**
358
+ * Render OKLCH as an sRGB hex string. Out-of-gamut colors are mapped back
359
+ * into sRGB by reducing chroma only — lightness and hue are preserved, so
360
+ * vivid seeds desaturate gracefully instead of shifting hue or clipping.
361
+ */
362
+ var oklchToHex = (color) => {
363
+ const target = {
364
+ l: clamp$1(color.l, 0, 1),
365
+ c: Math.max(color.c, 0),
366
+ h: color.h
367
+ };
368
+ let rgb = oklchToLinearRgb(target);
369
+ if (!inSrgbGamut(rgb)) {
370
+ let low = 0;
371
+ let high = target.c;
372
+ for (let i = 0; i < 24; i++) {
373
+ const mid = (low + high) / 2;
374
+ if (inSrgbGamut(oklchToLinearRgb({
375
+ ...target,
376
+ c: mid
377
+ }))) low = mid;
378
+ else high = mid;
379
+ }
380
+ rgb = oklchToLinearRgb({
381
+ ...target,
382
+ c: low
383
+ });
384
+ }
385
+ return rgbToHex(toSrgb255(rgb));
386
+ };
387
+ var toSrgb255 = ({ r, g, b }) => ({
388
+ red: 255 * linearToSrgb(clamp$1(r, 0, 1)),
389
+ green: 255 * linearToSrgb(clamp$1(g, 0, 1)),
390
+ blue: 255 * linearToSrgb(clamp$1(b, 0, 1))
391
+ });
392
+ //#endregion
393
+ //#region src/concepts/generation/palette.factory.ts
394
+ var toneMap = (dark) => dark ? {
395
+ accent: .78,
396
+ container: .42,
397
+ roleSurface: .26,
398
+ background: .18,
399
+ surface: .21,
400
+ surfaceVariant: .32,
401
+ outline: .66,
402
+ onSurface: .93,
403
+ mutedText: .76,
404
+ inverse: .93,
405
+ onInverse: .25,
406
+ onDeep: .2,
407
+ onLight: .985,
408
+ grey: .72,
409
+ disabledContainer: .3
410
+ } : {
411
+ accent: .55,
412
+ container: .9,
413
+ roleSurface: .97,
414
+ background: .995,
415
+ surface: .985,
416
+ surfaceVariant: .94,
417
+ outline: .6,
418
+ onSurface: .25,
419
+ mutedText: .48,
420
+ inverse: .3,
421
+ onInverse: .97,
422
+ onDeep: .24,
423
+ onLight: .985,
424
+ grey: .5,
425
+ disabledContainer: .96
426
+ };
427
+ var CategoryChroma = {
428
+ jewel: .17,
429
+ pastel: .055,
430
+ earth: .08,
431
+ neutral: .03,
432
+ florescent: .26,
433
+ shades: 0
434
+ };
435
+ /** Dark-mode accents cap chroma so they don't vibrate on dark surfaces. */
436
+ var DARK_ACCENT_CHROMA_CAP = .16;
437
+ var SemanticColors = {
438
+ error: {
439
+ hue: 27,
440
+ chroma: .2
441
+ },
442
+ warn: {
443
+ hue: 55,
444
+ chroma: .18
445
+ },
446
+ success: {
447
+ hue: 152,
448
+ chroma: .16
449
+ }
450
+ };
451
+ var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
452
+ /**
453
+ * Generate a complete {@link Colors} token set in OKLCH. Same contract as
454
+ * `generatePalette` (which delegates here), plus soft brand targets and a
455
+ * contrast-check sink for {@link ContrastReport} consumers.
456
+ */
457
+ var generateColors = (config) => {
458
+ const { seed, scheme, category, mode = "light", accentSaturationFloor = 18, brand = {}, targets = {}, checks } = config;
459
+ const dark = mode === "dark";
460
+ const t = toneMap(dark);
461
+ const anchor = hexToOklch(brand.primary ?? targets.primary ?? seed);
462
+ const hues = schemeHues(anchor.h, scheme);
463
+ const chromaFloor = accentSaturationFloor / 100 * .28;
464
+ let accentC = Math.max(CategoryChroma[category], chromaFloor);
465
+ if (dark) accentC = Math.min(accentC, DARK_ACCENT_CHROMA_CAP);
466
+ const containerC = Math.max(CategoryChroma[category] * .45, accentC * .35);
467
+ const surfaceC = Math.min(CategoryChroma[category], .012);
468
+ const tone = (hue, c, l) => oklchToHex({
469
+ l,
470
+ c,
471
+ h: hue
472
+ });
473
+ /**
474
+ * The WCAG guard-rail: walk the foreground's OKLCH lightness away from the
475
+ * background until the pair meets `target` (≤ 50 steps). Hue is never
476
+ * touched; chroma only shrinks as a last resort when L runs out of room.
477
+ */
478
+ const ensureContrast = (fg, bg, target) => {
479
+ const out = { ...fg };
480
+ let hex = oklchToHex(out);
481
+ if (contrastRatio(hex, bg) >= target) return out;
482
+ const bgY = relativeLuminance(hexToRgb(bg));
483
+ const darkCeiling = (bgY + .05) / .05;
484
+ const lightCeiling = 1.05 / (bgY + .05);
485
+ let lighten = relativeLuminance(hexToRgb(hex)) >= bgY;
486
+ if (lighten && lightCeiling < target && darkCeiling >= target) lighten = false;
487
+ if (!lighten && darkCeiling < target && lightCeiling >= target) lighten = true;
488
+ const step = lighten ? .015 : -.015;
489
+ for (let i = 0; i < 50 && contrastRatio(hex, bg) < target; i++) {
490
+ if (step > 0 && out.l < .995 || step < 0 && out.l > .02) out.l = clamp(out.l + step, 0, 1);
491
+ else out.c = Math.max(0, out.c - .02);
492
+ hex = oklchToHex(out);
493
+ }
494
+ return out;
495
+ };
496
+ /** Guard-railed token: adjust toward `target` contrast, then record the pair. */
497
+ const contrasted = (fg, bgHex, target) => oklchToHex(ensureContrast(fg, bgHex, target));
498
+ const record = (foreground, background, foregroundColor, backgroundColor, required) => {
499
+ if (!checks) return;
500
+ const ratio = contrastRatio(foregroundColor, backgroundColor);
501
+ checks.push({
502
+ mode,
503
+ foreground,
504
+ background,
505
+ foregroundColor,
506
+ backgroundColor,
507
+ ratio: Math.round(ratio * 100) / 100,
508
+ required,
509
+ pass: ratio >= required,
510
+ level: ratio < required ? "fail" : ratio >= 7 ? "AAA" : "AA"
511
+ });
512
+ };
513
+ const background = tone(anchor.h, surfaceC, t.background);
514
+ const surface = tone(anchor.h, surfaceC, t.surface);
515
+ const surfaceVariant = tone(anchor.h, surfaceC, t.surfaceVariant);
516
+ const onColor = (hue, bg, c) => {
517
+ const deep = {
518
+ l: t.onDeep,
519
+ c: Math.min(c, .05),
520
+ h: hue
521
+ };
522
+ const light = {
523
+ l: t.onLight,
524
+ c: Math.min(c, .02),
525
+ h: hue
526
+ };
527
+ return contrasted(contrastRatio(oklchToHex(deep), bg) >= contrastRatio(oklchToHex(light), bg) ? deep : light, bg, 4.5);
528
+ };
529
+ const adaptPinForDark = (hex) => {
530
+ const pin = hexToOklch(hex);
531
+ pin.l = Math.max(pin.l, .6);
532
+ return oklchToHex(ensureContrast(pin, background, 3));
533
+ };
534
+ /**
535
+ * Resolve a role's base color: hard pins are verbatim in light mode and
536
+ * lightness-lifted in dark; soft targets and generated tones are pulled to
537
+ * ≥ 4.5:1 as standalone ink on `background` and `surface` (§3.6).
538
+ */
539
+ const baseFor = (name, hue, c) => {
540
+ const pinned = brand[name];
541
+ if (pinned) return dark ? adaptPinForDark(pinned) : pinned;
542
+ const target = targets[name];
543
+ let base;
544
+ if (target) {
545
+ base = hexToOklch(target);
546
+ if (dark) {
547
+ base.c = Math.min(base.c, DARK_ACCENT_CHROMA_CAP);
548
+ base.l = Math.max(base.l, t.accent - .08);
549
+ }
550
+ } else base = {
551
+ l: t.accent,
552
+ c,
553
+ h: hue
554
+ };
555
+ return oklchToHex(ensureContrast(ensureContrast(base, background, 4.5), surface, 4.5));
556
+ };
557
+ const disabled = dark ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.12)";
558
+ const onDisabled = dark ? "rgba(255,255,255,0.38)" : "rgba(0,0,0,0.38)";
559
+ const role = (name, base, cC = containerC) => {
560
+ const { h, c } = hexToOklch(base);
561
+ const container = tone(h, cC, t.container);
562
+ const roleSurface = tone(h, surfaceC, t.roleSurface);
563
+ const onBase = onColor(h, base, c);
564
+ const onContainer = onColor(h, container, c);
565
+ const onContainerVariant = contrasted({
566
+ l: t.mutedText,
567
+ c: Math.min(cC, .06),
568
+ h
569
+ }, container, 4.5);
570
+ const borderHex = oklchToHex(ensureContrast(ensureContrast(hexToOklch(base), container, 3), surface, 3));
571
+ const onRoleSurface = onColor(h, roleSurface, surfaceC);
572
+ const onRoleSurfaceVariant = contrasted(hexToOklch(base), roleSurface, 4.5);
573
+ record(`on-${name}`, name, onBase, base, 4.5);
574
+ record(`on-${name}-container`, `${name}-container`, onContainer, container, 4.5);
575
+ record(`on-${name}-container-variant`, `${name}-container`, onContainerVariant, container, 4.5);
576
+ record(`on-${name}-container-border`, `${name}-container`, borderHex, container, 3);
577
+ record(`on-${name}-container-border`, "surface", borderHex, surface, 3);
578
+ record(`on-${name}-surface`, `${name}-surface`, onRoleSurface, roleSurface, 4.5);
579
+ record(`on-${name}-surface-variant`, `${name}-surface`, onRoleSurfaceVariant, roleSurface, 4.5);
580
+ record(name, "background", base, background, 4.5);
581
+ record(name, "surface", base, surface, 4.5);
582
+ return {
583
+ [name]: base,
584
+ [`on-${name}`]: onBase,
585
+ [`${name}-container`]: container,
586
+ [`on-${name}-container`]: onContainer,
587
+ [`on-${name}-container-variant`]: onContainerVariant,
588
+ [`on-${name}-container-border`]: borderHex,
589
+ [`${name}-surface`]: roleSurface,
590
+ [`on-${name}-surface`]: onRoleSurface,
591
+ [`on-${name}-surface-variant`]: onRoleSurfaceVariant
592
+ };
593
+ };
594
+ const primaryBase = baseFor("primary", hues.primary, accentC);
595
+ const secondaryBase = baseFor("secondary", hues.secondary, accentC);
596
+ const tertiaryBase = baseFor("tertiary", hues.tertiary, accentC);
597
+ const quaternaryGrey = brand.quaternary ? dark ? adaptPinForDark(brand.quaternary) : brand.quaternary : oklchToHex(ensureContrast({
598
+ l: t.grey,
599
+ c: surfaceC,
600
+ h: anchor.h
601
+ }, surface, 3));
602
+ const quaternarySurface = tone(anchor.h, surfaceC, t.roleSurface);
603
+ const onQuaternary = onColor(anchor.h, quaternaryGrey, surfaceC);
604
+ const onQuaternarySurface = onColor(anchor.h, quaternarySurface, surfaceC);
605
+ const onQuaternarySurfaceVariant = contrasted(hexToOklch(primaryBase), quaternarySurface, 4.5);
606
+ const onQuaternaryContainerVariant = contrasted({
607
+ l: t.mutedText,
608
+ c: Math.min(containerC, .06),
609
+ h: anchor.h
610
+ }, quaternarySurface, 4.5);
611
+ record("on-quaternary", "quaternary", onQuaternary, quaternaryGrey, 4.5);
612
+ record("on-quaternary-surface", "quaternary-surface", onQuaternarySurface, quaternarySurface, 4.5);
613
+ record("on-quaternary-surface-variant", "quaternary-surface", onQuaternarySurfaceVariant, quaternarySurface, 4.5);
614
+ const semantic = (name) => {
615
+ const { hue, chroma } = SemanticColors[name];
616
+ const base = baseFor(name, hue, dark ? Math.min(chroma, DARK_ACCENT_CHROMA_CAP) : chroma);
617
+ const { h } = hexToOklch(base);
618
+ const container = tone(h, containerC + .04, t.container);
619
+ const onBase = onColor(h, base, chroma);
620
+ const onContainer = onColor(h, container, chroma);
621
+ record(`on-${name}`, name, onBase, base, 4.5);
622
+ record(`on-${name}-container`, `${name}-container`, onContainer, container, 4.5);
623
+ record(name, "background", base, background, 4.5);
624
+ record(name, "surface", base, surface, 4.5);
625
+ return {
626
+ base,
627
+ container,
628
+ onBase,
629
+ onContainer,
630
+ h
631
+ };
632
+ };
633
+ const error = semantic("error");
634
+ const warn = semantic("warn");
635
+ const success = semantic("success");
636
+ const semanticExtras = (name, s) => {
637
+ const variant = contrasted({
638
+ l: t.mutedText,
639
+ c: .06,
640
+ h: s.h
641
+ }, s.container, 4.5);
642
+ const border = oklchToHex(ensureContrast(ensureContrast(hexToOklch(s.base), s.container, 3), surface, 3));
643
+ record(`on-${name}-container-variant`, `${name}-container`, variant, s.container, 4.5);
644
+ record(`on-${name}-container-border`, `${name}-container`, border, s.container, 3);
645
+ return {
646
+ variant,
647
+ border
648
+ };
649
+ };
650
+ const warnExtras = semanticExtras("warn", warn);
651
+ const successExtras = semanticExtras("success", success);
652
+ const onBackground = tone(anchor.h, surfaceC, t.onSurface);
653
+ const onBackgroundVariant = contrasted({
654
+ l: t.mutedText,
655
+ c: surfaceC,
656
+ h: anchor.h
657
+ }, background, 4.5);
658
+ const onSurface = tone(anchor.h, surfaceC, t.onSurface);
659
+ const onSurfaceVariant = contrasted({
660
+ l: dark ? t.mutedText : t.mutedText - .14,
661
+ c: surfaceC,
662
+ h: anchor.h
663
+ }, surfaceVariant, 4.5);
664
+ record("on-background", "background", onBackground, background, 4.5);
665
+ record("on-background-variant", "background", onBackgroundVariant, background, 4.5);
666
+ record("on-surface", "surface", onSurface, surface, 4.5);
667
+ record("on-surface-variant", "surface-variant", onSurfaceVariant, surfaceVariant, 4.5);
668
+ const inverseSurface = tone(anchor.h, surfaceC, t.inverse);
669
+ const onInverse = tone(anchor.h, surfaceC, t.onInverse);
670
+ const inversePrimary = contrasted(hexToOklch(primaryBase), inverseSurface, 4.5);
671
+ record("on-inverse-surface", "inverse-surface", onInverse, inverseSurface, 4.5);
672
+ record("on-inverse-surface-primary", "inverse-surface", inversePrimary, inverseSurface, 4.5);
673
+ record("on-inverse-container", "inverse-container", onInverse, inverseSurface, 4.5);
674
+ const outline = oklchToHex(ensureContrast(ensureContrast({
675
+ l: t.outline,
676
+ c: Math.min(surfaceC, .02),
677
+ h: hues.primary
678
+ }, surface, 3), background, 3));
679
+ record("outline", "surface", outline, surface, 3);
680
+ record("outline", "background", outline, background, 3);
681
+ return {
682
+ ...role("primary", primaryBase),
683
+ ...role("secondary", secondaryBase),
684
+ ...role("tertiary", tertiaryBase),
685
+ quaternary: quaternaryGrey,
686
+ "on-quaternary": onQuaternary,
687
+ "quaternary-surface": quaternarySurface,
688
+ "on-quaternary-surface": onQuaternarySurface,
689
+ "on-quaternary-surface-variant": onQuaternarySurfaceVariant,
690
+ "on-quaternary-container-variant": onQuaternaryContainerVariant,
691
+ "on-quaternary-container-border": quaternaryGrey,
692
+ error: error.base,
693
+ "on-error": error.onBase,
694
+ "error-container": error.container,
695
+ "on-error-container": error.onContainer,
696
+ warn: warn.base,
697
+ "on-warn": warn.onBase,
698
+ "warn-container": warn.container,
699
+ "on-warn-container": warn.onContainer,
700
+ "on-warn-container-variant": warnExtras.variant,
701
+ "on-warn-container-border": warnExtras.border,
702
+ success: success.base,
703
+ "on-success": success.onBase,
704
+ "success-container": success.container,
705
+ "on-success-container": success.onContainer,
706
+ "on-success-container-variant": successExtras.variant,
707
+ "on-success-container-border": successExtras.border,
708
+ background,
709
+ "on-background": onBackground,
710
+ "on-background-variant": onBackgroundVariant,
711
+ surface,
712
+ "on-surface": onSurface,
713
+ "surface-variant": surfaceVariant,
714
+ "on-surface-variant": onSurfaceVariant,
715
+ "inverse-surface": inverseSurface,
716
+ "on-inverse-surface": onInverse,
717
+ "on-inverse-surface-primary": inversePrimary,
718
+ "on-inverse-surface-variant": inversePrimary,
719
+ "inverse-container": inverseSurface,
720
+ "on-inverse-container": onInverse,
721
+ outline,
722
+ shadow: "#000000",
723
+ scrim: "#000000",
724
+ "surface-tint": primaryBase,
725
+ transparent: "rgba(0,0,0,0)",
726
+ ghost: "rgba(0,0,0,0)",
727
+ disabled,
728
+ "on-disabled": onDisabled,
729
+ "disabled-container": tone(hues.primary, surfaceC, t.disabledContainer),
730
+ "on-disabled-container": onDisabled,
731
+ "disabled-surface": disabled,
732
+ "on-disabled-surface": dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)",
733
+ "on-disabled-surface-variant": dark ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)"
734
+ };
735
+ };
736
+ //#endregion
737
+ //#region src/concepts/color/color.factory.ts
738
+ /**
739
+ * Generate a complete {@link Colors} token set from a single seed color, a
740
+ * {@link ColorScheme} and a {@link ColorCategory}. Produces a light or dark
741
+ * variant of the same palette; `on-*` colors are driven to WCAG AA contrast
742
+ * so text stays legible for any seed.
743
+ *
744
+ * Delegates to the OKLCH engine in `concepts/generation` — all lightness and
745
+ * chroma math is perceptual, and every derived pair passes through the WCAG
746
+ * guard-rail. Accepts the engine's extended config, so callers may also pass
747
+ * soft `targets` (brand-faithful but guard-railed) and a `checks` sink. Use
748
+ * `generateThemes()` for the light+dark pair plus a {@link ContrastReport}.
749
+ */
750
+ var generatePalette = (config) => generateColors(config);
176
751
  //#endregion
177
752
  //#region src/concepts/elevation/zIndex.ts
178
753
  var Z_INDEX = {
@@ -186,6 +761,856 @@ var Z_INDEX = {
186
761
  overlay: 1080
187
762
  };
188
763
  //#endregion
764
+ //#region src/concepts/theme/themes/base.theme.ts
765
+ var BaseTypography = {
766
+ "display-large": {
767
+ fontFamily: "Red Hat Display",
768
+ fontSize: 57,
769
+ lineHeight: 64,
770
+ fontWeight: "normal",
771
+ letterSpacing: -.25
772
+ },
773
+ "display-medium": {
774
+ fontFamily: "Red Hat Display",
775
+ fontSize: 45,
776
+ lineHeight: 52,
777
+ fontWeight: "normal"
778
+ },
779
+ "display-small": {
780
+ fontFamily: "Red Hat Display",
781
+ fontSize: 36,
782
+ lineHeight: 44,
783
+ fontWeight: "normal"
784
+ },
785
+ "headline-large": {
786
+ fontFamily: "Red Hat Display",
787
+ fontSize: 32,
788
+ lineHeight: 40,
789
+ fontWeight: "normal"
790
+ },
791
+ "headline-medium": {
792
+ fontFamily: "Red Hat Display",
793
+ fontSize: 28,
794
+ lineHeight: 36,
795
+ fontWeight: "normal"
796
+ },
797
+ "headline-small": {
798
+ fontFamily: "Red Hat Display",
799
+ fontSize: 24,
800
+ lineHeight: 32,
801
+ fontWeight: "normal"
802
+ },
803
+ "title-large": {
804
+ fontFamily: "Red Hat Display",
805
+ fontSize: 22,
806
+ lineHeight: 28,
807
+ fontWeight: "normal"
808
+ },
809
+ "title-medium": {
810
+ fontFamily: "Red Hat Display",
811
+ fontSize: 16,
812
+ lineHeight: 24,
813
+ fontWeight: "medium",
814
+ letterSpacing: .15
815
+ },
816
+ "title-small": {
817
+ fontFamily: "Red Hat Display",
818
+ fontWeight: "medium",
819
+ fontSize: 14,
820
+ lineHeight: 20,
821
+ letterSpacing: .1
822
+ },
823
+ "body-1-long": {
824
+ fontFamily: "Roboto",
825
+ fontSize: 16,
826
+ lineHeight: 22
827
+ },
828
+ "body-1-short": {
829
+ fontFamily: "Roboto",
830
+ fontSize: 16,
831
+ lineHeight: 24
832
+ },
833
+ "body-2-long": {
834
+ fontFamily: "Roboto",
835
+ fontSize: 14,
836
+ lineHeight: 18
837
+ },
838
+ "body-2-short": {
839
+ fontFamily: "Roboto",
840
+ fontSize: 14,
841
+ lineHeight: 20
842
+ },
843
+ "subtitle-1": {
844
+ fontFamily: "Red Hat Display",
845
+ fontSize: 16,
846
+ lineHeight: 24,
847
+ letterSpacing: .15
848
+ },
849
+ "subtitle-2": {
850
+ fontFamily: "Red Hat Display",
851
+ fontSize: 14,
852
+ lineHeight: 20,
853
+ fontWeight: "medium",
854
+ letterSpacing: .1
855
+ },
856
+ label: {
857
+ fontFamily: "Roboto",
858
+ fontSize: 14,
859
+ lineHeight: 20
860
+ },
861
+ button: {
862
+ fontFamily: "Red Hat Display",
863
+ fontSize: 14,
864
+ lineHeight: 20,
865
+ fontWeight: "medium",
866
+ textTransform: "capitalize"
867
+ },
868
+ caption: {
869
+ fontFamily: "Roboto",
870
+ fontSize: 12,
871
+ lineHeight: 18,
872
+ letterSpacing: .4
873
+ },
874
+ overline: {
875
+ fontFamily: "Red Hat Display",
876
+ fontSize: 10,
877
+ lineHeight: 18,
878
+ letterSpacing: 1.5,
879
+ textTransform: "uppercase"
880
+ },
881
+ paragraph: {
882
+ fontFamily: "Roboto",
883
+ fontSize: 16,
884
+ lineHeight: 24
885
+ },
886
+ quote: {
887
+ fontFamily: "Roboto",
888
+ fontSize: 16,
889
+ lineHeight: 24
890
+ },
891
+ note: {
892
+ fontFamily: "Roboto",
893
+ fontSize: 14,
894
+ lineHeight: 22,
895
+ fontStyle: "italic"
896
+ },
897
+ badge: {
898
+ fontFamily: "Red Hat Display",
899
+ fontSize: 16,
900
+ lineHeight: 24
901
+ },
902
+ tag: {
903
+ fontFamily: "Red Hat Display",
904
+ fontSize: 15,
905
+ lineHeight: 20,
906
+ fontWeight: 600
907
+ },
908
+ input: {
909
+ fontFamily: "Red Hat Display",
910
+ fontSize: 14,
911
+ lineHeight: 24
912
+ }
913
+ };
914
+ var BaseShadows = {
915
+ raised: "rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px",
916
+ menu: "rgba(0, 0, 0, 0.2) 0px 3px 3px -2px, rgba(0, 0, 0, 0.14) 0px 3px 4px 0px, rgba(0, 0, 0, 0.12) 0px 1px 8px 0px;",
917
+ dialog: "rgba(0, 0, 0, 0.2) 0px 3px 5px -1px, rgba(0, 0, 0, 0.14) 0px 6px 10px 0px, rgba(0, 0, 0, 0.12) 0px 1px 18px 0px",
918
+ warn: "0 0 5px rgba(255, 0, 0, 0.5), inset 0 0 5px rgba(255, 0, 0, 0.3)"
919
+ };
920
+ var BaseSpacing = {
921
+ none: "none",
922
+ xxs: "2px",
923
+ xs: "4px",
924
+ sm: "8px",
925
+ md: "16px",
926
+ lg: "32px",
927
+ xl: "64px"
928
+ };
929
+ var BaseThicknesses = {
930
+ thin: 1,
931
+ standard: 2,
932
+ thick: 4
933
+ };
934
+ var BaseRadii = {
935
+ none: "none",
936
+ xxs: "4px",
937
+ xs: "8px",
938
+ sm: "16px",
939
+ md: "24px",
940
+ lg: "32px",
941
+ max: "999px"
942
+ };
943
+ var buildBorders = (c) => ({
944
+ primary: `1px solid ${c.primary}`,
945
+ secondary: `1px solid ${c.secondary}`,
946
+ tertiary: `1px solid ${c.tertiary}`,
947
+ quaternary: `1px solid ${c.quaternary}`,
948
+ warn: `1px solid ${c.warn}`,
949
+ success: `1px solid ${c.success}`,
950
+ light: `1px solid ${c.outline}`,
951
+ dark: `1px solid ${c["on-background"]}`,
952
+ dotted: `1px dotted ${c["on-background"]}`
953
+ });
954
+ var buildComponents = (c) => ({
955
+ alert: { options: {
956
+ topPosition: 40,
957
+ borderRadius: "sm",
958
+ transitionSpeed: .35,
959
+ elevation: "md"
960
+ } },
961
+ checkbox: { options: { size: 20 } },
962
+ dialog: { options: {
963
+ borderRadius: "lg",
964
+ color: "primary-surface",
965
+ border: "quaternary",
966
+ padding: "sm",
967
+ elevation: "dialog",
968
+ backdrop: {
969
+ background: "rgba(255, 255, 255, 0.6)",
970
+ backdropFilter: "blur(2px)"
971
+ }
972
+ } },
973
+ dialogHeader: { options: {
974
+ borderRadius: "max",
975
+ color: "primary",
976
+ height: 48,
977
+ textRole: "title-large",
978
+ textAlign: "center",
979
+ closeButtonIcon: "close",
980
+ closeButtonSize: "md"
981
+ } },
982
+ dropdown: { options: {
983
+ border: "none",
984
+ borderRadius: "xxs",
985
+ color: "primary-surface",
986
+ shadow: "menu"
987
+ } },
988
+ footer: { options: {
989
+ height: 52,
990
+ color: "primary",
991
+ logoHeight: 18.6,
992
+ logoPadding: "md"
993
+ } },
994
+ input: { options: {
995
+ typeFace: "input",
996
+ color: "primary-surface",
997
+ textColor: "on-primary-surface",
998
+ disabledColor: "disabled-surface",
999
+ disabledTextColor: "on-disabled-surface",
1000
+ border: "light",
1001
+ borderRadius: "xs",
1002
+ errorShadow: "warn",
1003
+ errorBorder: "warn",
1004
+ height: 32,
1005
+ paddingLeft: "sm",
1006
+ focusOutline: `2px solid ${c.primary}`,
1007
+ focusOutlineOffset: 2
1008
+ } },
1009
+ multiSelectDropdown: { options: {
1010
+ textRole: "input",
1011
+ textColor: "on-primary-surface",
1012
+ dividerBorder: "light",
1013
+ searchInputBorder: "light",
1014
+ searchInputBorderRadius: "xxs",
1015
+ focusOutline: `2px solid ${c.primary}`,
1016
+ focusOutlineOffset: 2
1017
+ } },
1018
+ badge: { options: { borderRadius: "xxs" } },
1019
+ button: {
1020
+ fixed: {
1021
+ position: "relative",
1022
+ overflow: "hidden",
1023
+ outline: "0",
1024
+ border: "0",
1025
+ cursor: "pointer",
1026
+ fontFamily: "Euphemia, sans-serif",
1027
+ transition: "all 0.28s ease"
1028
+ },
1029
+ variants: {
1030
+ ghost: {
1031
+ backgroundColor: "transparent",
1032
+ color: "currentcolor",
1033
+ "&:hover": { backgroundColor: "rgba(0,0,0,0.06)" }
1034
+ },
1035
+ primary: {
1036
+ backgroundColor: c.primary,
1037
+ color: c["on-primary"],
1038
+ border: "0",
1039
+ "&:hover": { filter: "brightness(0.92)" }
1040
+ },
1041
+ secondary: {
1042
+ backgroundColor: "transparent",
1043
+ color: c.secondary,
1044
+ border: `1px solid ${c.secondary}`,
1045
+ "&:hover": {
1046
+ backgroundColor: c.secondary,
1047
+ color: c["on-secondary"]
1048
+ }
1049
+ },
1050
+ tertiary: {
1051
+ backgroundColor: c.tertiary,
1052
+ color: c["on-tertiary"],
1053
+ border: "0",
1054
+ "&:hover": { filter: "brightness(0.92)" }
1055
+ },
1056
+ warn: {
1057
+ backgroundColor: c.warn,
1058
+ color: c["on-warn"],
1059
+ border: "0",
1060
+ "&:hover": { filter: "brightness(0.92)" }
1061
+ },
1062
+ success: {
1063
+ backgroundColor: c.success,
1064
+ color: c["on-success"],
1065
+ border: "0",
1066
+ "&:hover": { filter: "brightness(0.92)" }
1067
+ },
1068
+ disabled: {
1069
+ backgroundColor: `${c.disabled} !important`,
1070
+ color: `${c["on-disabled"]} !important`,
1071
+ border: "0"
1072
+ }
1073
+ },
1074
+ sizes: {
1075
+ sm: {
1076
+ height: 22,
1077
+ borderRadius: 11,
1078
+ fontSize: 12,
1079
+ padding: "0 12px",
1080
+ fontFamily: "Euphemia Bold, sans-serif",
1081
+ fontWeight: 600
1082
+ },
1083
+ md: {
1084
+ height: 26,
1085
+ borderRadius: 13,
1086
+ fontSize: 16,
1087
+ padding: "0 16px"
1088
+ },
1089
+ lg: {
1090
+ height: 36,
1091
+ borderRadius: 18,
1092
+ fontSize: 18,
1093
+ padding: "0 18px"
1094
+ },
1095
+ xl: {
1096
+ height: 48,
1097
+ borderRadius: 24,
1098
+ fontSize: 24,
1099
+ padding: "0 22px"
1100
+ }
1101
+ }
1102
+ },
1103
+ iconButton: {
1104
+ variants: {
1105
+ ghost: {
1106
+ backgroundColor: "transparent",
1107
+ color: "currentcolor"
1108
+ },
1109
+ primary: {
1110
+ backgroundColor: c.primary,
1111
+ color: c["on-primary"]
1112
+ },
1113
+ secondary: {
1114
+ backgroundColor: c.secondary,
1115
+ color: c["on-secondary"]
1116
+ },
1117
+ tertiary: {
1118
+ backgroundColor: c.tertiary,
1119
+ color: c["on-tertiary"]
1120
+ },
1121
+ warn: {
1122
+ backgroundColor: c.warn,
1123
+ color: c["on-warn"]
1124
+ },
1125
+ success: {
1126
+ backgroundColor: c.success,
1127
+ color: c["on-success"]
1128
+ },
1129
+ disabled: {
1130
+ backgroundColor: "transparent !important",
1131
+ color: `${c["on-disabled"]} !important`
1132
+ }
1133
+ },
1134
+ sizes: {
1135
+ sm: {
1136
+ height: 22,
1137
+ minHeight: 22,
1138
+ width: 22,
1139
+ minWidth: 22,
1140
+ fontSize: 18
1141
+ },
1142
+ md: {
1143
+ height: 26,
1144
+ minHeight: 26,
1145
+ width: 26,
1146
+ minWidth: 26,
1147
+ fontSize: 22
1148
+ },
1149
+ lg: {
1150
+ height: 36,
1151
+ minHeight: 36,
1152
+ width: 36,
1153
+ minWidth: 36,
1154
+ fontSize: 30
1155
+ },
1156
+ xl: {
1157
+ height: 40,
1158
+ minHeight: 40,
1159
+ width: 40,
1160
+ minWidth: 40,
1161
+ fontSize: 34
1162
+ }
1163
+ }
1164
+ },
1165
+ progressGauge: {
1166
+ fixed: { textFill: c["on-background"] },
1167
+ variants: {
1168
+ primary: {
1169
+ backgroundColor: "#b3d4ea",
1170
+ color: c.primary
1171
+ },
1172
+ secondary: {
1173
+ backgroundColor: "#b3e7c2",
1174
+ color: c.secondary
1175
+ },
1176
+ tertiary: {
1177
+ backgroundColor: "#ffe2b3",
1178
+ color: c.tertiary
1179
+ },
1180
+ warn: {
1181
+ backgroundColor: "#ffc2b3",
1182
+ color: c.warn
1183
+ },
1184
+ success: {
1185
+ backgroundColor: "#b3e7c2",
1186
+ color: c.success
1187
+ }
1188
+ },
1189
+ sizes: {
1190
+ sm: { height: "54px" },
1191
+ md: { height: "68px" },
1192
+ lg: { height: "82px" },
1193
+ xl: { height: "104px" }
1194
+ }
1195
+ },
1196
+ card: {
1197
+ fixed: {
1198
+ borderStyle: "solid",
1199
+ borderWidth: "1px",
1200
+ borderRadius: "8px",
1201
+ overflow: "hidden"
1202
+ },
1203
+ variants: {
1204
+ primary: {
1205
+ borderColor: c.primary,
1206
+ backgroundColor: c.background
1207
+ },
1208
+ secondary: {
1209
+ borderColor: c.secondary,
1210
+ backgroundColor: c.background
1211
+ },
1212
+ tertiary: {
1213
+ borderColor: c.tertiary,
1214
+ backgroundColor: c.background
1215
+ },
1216
+ warn: {
1217
+ borderColor: c.warn,
1218
+ backgroundColor: c.background
1219
+ },
1220
+ success: {
1221
+ borderColor: c.success,
1222
+ backgroundColor: c.background
1223
+ }
1224
+ }
1225
+ },
1226
+ cardHeader: {
1227
+ fixed: { padding: "12px 24px" },
1228
+ variants: {
1229
+ primary: {
1230
+ backgroundColor: c.primary,
1231
+ color: c["on-primary"]
1232
+ },
1233
+ secondary: {
1234
+ backgroundColor: c.secondary,
1235
+ color: c["on-secondary"]
1236
+ },
1237
+ tertiary: {
1238
+ backgroundColor: c.tertiary,
1239
+ color: c["on-tertiary"]
1240
+ },
1241
+ warn: {
1242
+ backgroundColor: c.warn,
1243
+ color: c["on-warn"]
1244
+ },
1245
+ success: {
1246
+ backgroundColor: c.success,
1247
+ color: c["on-success"]
1248
+ }
1249
+ }
1250
+ },
1251
+ cardContent: { fixed: { padding: "12px 24px" } },
1252
+ dataSearch: { options: {
1253
+ border: "light",
1254
+ borderRadius: "xs",
1255
+ color: "primary-surface",
1256
+ placeholderColor: "disabled"
1257
+ } },
1258
+ dataTable: { options: {
1259
+ color: "primary-surface",
1260
+ border: "light",
1261
+ borderRadius: "sm",
1262
+ elevation: void 0,
1263
+ headerPadding: "sm",
1264
+ footerPadding: "sm",
1265
+ thTextRole: "headline-small",
1266
+ thColor: "primary-container",
1267
+ thVerticalBorder: "dotted",
1268
+ thHorizontalBorder: "light",
1269
+ thPadding: "sm",
1270
+ tdTextRole: "title-small",
1271
+ tdColor: "primary-surface",
1272
+ tdStickyColor: "primary-container",
1273
+ tdPadding: "sm",
1274
+ tdVerticalBorder: "dotted",
1275
+ tdHorizontalBorder: "light",
1276
+ rowHoverColor: "primary-container",
1277
+ loadingOverlayColor: "scrim",
1278
+ loadingSpinnerColor: "primary",
1279
+ loadingSpinnerSize: 40
1280
+ } },
1281
+ notificationBadge: { options: {
1282
+ borderRadius: "sm",
1283
+ offset: -10
1284
+ } },
1285
+ paginator: { options: {
1286
+ gap: "xs",
1287
+ textRole: "label",
1288
+ inputBorder: "light",
1289
+ inputBorderRadius: "xs",
1290
+ pageBorderRadius: "xs",
1291
+ currentPageBorder: "light",
1292
+ currentPageBorderRadius: "xs"
1293
+ } },
1294
+ snackbar: { options: {
1295
+ bottomPosition: 40,
1296
+ transitionDelay: "0.35s",
1297
+ autoCloseDelay: 35e3
1298
+ } },
1299
+ symbol: { options: {
1300
+ fill: 0,
1301
+ weight: 400,
1302
+ grade: 0,
1303
+ opticalSize: 24
1304
+ } },
1305
+ toggle: { options: { size: 20 } },
1306
+ tooltip: { options: {
1307
+ border: void 0,
1308
+ borderRadius: "xs",
1309
+ shadow: "raised",
1310
+ color: "inverse-surface",
1311
+ typeface: "label"
1312
+ } }
1313
+ });
1314
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1315
+ var deepMerge = (base, override) => {
1316
+ if (!override) return base;
1317
+ const out = { ...base };
1318
+ for (const [key, value] of Object.entries(override)) out[key] = isRecord(value) && isRecord(out[key]) ? deepMerge(out[key], value) : value;
1319
+ return out;
1320
+ };
1321
+ var createTheme = ({ id, name, colors, icons = {}, radii = BaseRadii, shadows = BaseShadows, borders, components }) => ({
1322
+ id,
1323
+ name,
1324
+ colors,
1325
+ typography: BaseTypography,
1326
+ borders: deepMerge(buildBorders(colors), borders),
1327
+ radii,
1328
+ shadows,
1329
+ spacing: BaseSpacing,
1330
+ thicknesses: BaseThicknesses,
1331
+ icons,
1332
+ components: deepMerge(buildComponents(colors), components)
1333
+ });
1334
+ /**
1335
+ * Build a full {@link UniTheme} straight from a {@link PaletteConfig} — the
1336
+ * one-call path a theme builder uses to turn a brand color (or a seed +
1337
+ * scheme + category) into a complete, ready-to-apply theme.
1338
+ */
1339
+ var createThemeFromPalette = (config) => createTheme({
1340
+ id: config.id ?? "CustomTheme",
1341
+ name: config.name ?? "Custom Theme",
1342
+ colors: generatePalette(config),
1343
+ icons: config.icons
1344
+ });
1345
+ /**
1346
+ * Seed for the shipped Light/Dark themes. Swap these three values (or call
1347
+ * `generatePalette` with your own) to reskin the entire system — every color
1348
+ * token is derived, so there is nothing else to hand-author.
1349
+ */
1350
+ var BASE_PALETTE_CONFIG = {
1351
+ seed: "#4F46E5",
1352
+ scheme: "triadic",
1353
+ category: "neutral"
1354
+ };
1355
+ var lightColors = generatePalette({
1356
+ ...BASE_PALETTE_CONFIG,
1357
+ mode: "light"
1358
+ });
1359
+ var BaseTheme = createTheme({
1360
+ id: "BaseTheme",
1361
+ name: "Base Theme",
1362
+ colors: lightColors
1363
+ });
1364
+ //#endregion
1365
+ //#region src/concepts/generation/theme.generator.ts
1366
+ /** Radii presets per shape language (PRD §3.5.A). Same keys as `BaseRadii`. */
1367
+ var ShapeRadii = {
1368
+ sharp: {
1369
+ none: "none",
1370
+ xxs: "0px",
1371
+ xs: "0px",
1372
+ sm: "0px",
1373
+ md: "0px",
1374
+ lg: "0px",
1375
+ max: "0px"
1376
+ },
1377
+ modern: {
1378
+ none: "none",
1379
+ xxs: "4px",
1380
+ xs: "8px",
1381
+ sm: "16px",
1382
+ md: "24px",
1383
+ lg: "32px",
1384
+ max: "999px"
1385
+ },
1386
+ playful: {
1387
+ none: "none",
1388
+ xxs: "8px",
1389
+ xs: "16px",
1390
+ sm: "24px",
1391
+ md: "32px",
1392
+ lg: "48px",
1393
+ max: "9999px"
1394
+ }
1395
+ };
1396
+ /** Shortest angular distance between two hue angles, in degrees (0–180). */
1397
+ var hueDistance = (a, b) => {
1398
+ const d = Math.abs(a - b) % 360;
1399
+ return d > 180 ? 360 - d : d;
1400
+ };
1401
+ /**
1402
+ * Classify 2–3 brand hues against {@link ColorScheme} by their angular
1403
+ * distances from the primary hue. Heuristic bands, widest match wins.
1404
+ */
1405
+ var classifyScheme = (primaryHue, otherHues) => {
1406
+ const distances = otherHues.map((h) => hueDistance(primaryHue, h));
1407
+ if (distances.length === 0) return "analogous";
1408
+ if (distances.every((d) => d < 15)) return "monochromatic";
1409
+ if (distances.every((d) => d <= 65)) return "analogous";
1410
+ if (distances.some((d) => d >= 165)) return "complimentary";
1411
+ if (distances.length > 1 && distances.every((d) => d >= 130)) return "splitComplimentary";
1412
+ return "triadic";
1413
+ };
1414
+ /**
1415
+ * Infer a tonal category from the seed's own chroma, so an unstated "vibe"
1416
+ * preserves the brand's character — vivid stays vivid, muted stays muted.
1417
+ */
1418
+ var inferCategory = (seedHex) => {
1419
+ const { c } = hexToOklch(seedHex);
1420
+ if (c >= .13) return "jewel";
1421
+ if (c >= .07) return "earth";
1422
+ if (c >= .03) return "pastel";
1423
+ return "neutral";
1424
+ };
1425
+ /**
1426
+ * The theme generation engine (PRD §3.3): brand seed(s) in, complete WCAG-AA
1427
+ * light+dark {@link Colors} pair out, with a machine-readable contrast report.
1428
+ * Pure and deterministic — identical input yields identical output.
1429
+ */
1430
+ var generateThemes = (input) => {
1431
+ const seeds = (Array.isArray(input.seed) ? input.seed : [input.seed]).slice(0, 3);
1432
+ const [primary, secondary, tertiary] = seeds;
1433
+ const scheme = input.scheme ?? (seeds.length > 1 ? classifyScheme(hexToOklch(primary).h, seeds.slice(1).map((s) => hexToOklch(s).h)) : "analogous");
1434
+ const category = input.vibe ?? inferCategory(primary);
1435
+ const applyVibe = (hex) => {
1436
+ if (!input.vibe) return hex;
1437
+ const color = hexToOklch(hex);
1438
+ return oklchToHex({
1439
+ ...color,
1440
+ c: Math.min(color.c, CategoryChroma[input.vibe])
1441
+ });
1442
+ };
1443
+ const targets = { primary: applyVibe(primary) };
1444
+ if (secondary) targets.secondary = applyVibe(secondary);
1445
+ if (tertiary) targets.tertiary = applyVibe(tertiary);
1446
+ const checks = [];
1447
+ const base = {
1448
+ seed: primary,
1449
+ scheme,
1450
+ category,
1451
+ targets,
1452
+ checks
1453
+ };
1454
+ const lightColors = generateColors({
1455
+ ...base,
1456
+ mode: "light"
1457
+ });
1458
+ const darkColors = generateColors({
1459
+ ...base,
1460
+ mode: "dark"
1461
+ });
1462
+ const worstRatio = checks.reduce((worst, check) => Math.min(worst, check.ratio), 21);
1463
+ return {
1464
+ lightColors,
1465
+ darkColors,
1466
+ radii: input.shape ? ShapeRadii[input.shape] : void 0,
1467
+ report: {
1468
+ checks,
1469
+ worstRatio,
1470
+ pass: checks.every((check) => check.pass)
1471
+ }
1472
+ };
1473
+ };
1474
+ /**
1475
+ * Convenience wrapper: {@link generateThemes} piped through `createTheme()`,
1476
+ * returning a registration-ready light/dark {@link UniTheme} pair.
1477
+ */
1478
+ var generateUniThemes = (input) => {
1479
+ const { lightColors, darkColors, radii } = generateThemes(input);
1480
+ const name = input.name ?? "Brand";
1481
+ const id = name.replace(/\W+/g, "") || "Brand";
1482
+ return {
1483
+ light: createTheme({
1484
+ id: `${id}Light`,
1485
+ name: `${name} Light`,
1486
+ colors: lightColors,
1487
+ radii
1488
+ }),
1489
+ dark: createTheme({
1490
+ id: `${id}Dark`,
1491
+ name: `${name} Dark`,
1492
+ colors: darkColors,
1493
+ radii
1494
+ })
1495
+ };
1496
+ };
1497
+ //#endregion
1498
+ //#region src/concepts/generation/theme-file.emitter.ts
1499
+ var IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1500
+ var asKey = (k) => IDENT.test(k) ? k : `'${k}'`;
1501
+ var recordLiteral = (record, indent) => Object.entries(record).map(([k, v]) => `${indent}${asKey(k)}: '${v}',`).join("\n");
1502
+ var bordersLiteral = () => [
1503
+ "/**",
1504
+ " * Named border primitives. These mirror the derived defaults — edit them, or",
1505
+ " * add your own under any token name and point component options (or the",
1506
+ " * `components` overrides below) at it. Every component deriving from a",
1507
+ " * shared token picks up the change.",
1508
+ " */",
1509
+ "const borders = (colors: Colors): Borders => ({",
1510
+ " primary: `1px solid ${colors.primary}`,",
1511
+ " secondary: `1px solid ${colors.secondary}`,",
1512
+ " tertiary: `1px solid ${colors.tertiary}`,",
1513
+ " quaternary: `1px solid ${colors.quaternary}`,",
1514
+ " warn: `1px solid ${colors.warn}`,",
1515
+ " success: `1px solid ${colors.success}`,",
1516
+ " light: `1px solid ${colors.outline}`,",
1517
+ " dark: `1px solid ${colors['on-background']}`,",
1518
+ " dotted: `1px dotted ${colors['on-background']}`,",
1519
+ "});"
1520
+ ].join("\n");
1521
+ var themeExport = (exportName, displayName, colorsConst, radii) => [
1522
+ `export const ${exportName}: UniTheme = createTheme({`,
1523
+ ` id: '${exportName}',`,
1524
+ ` name: '${displayName}',`,
1525
+ ` colors: ${colorsConst},`,
1526
+ ` borders: borders(${colorsConst}),`,
1527
+ ` components: components(${colorsConst}),`,
1528
+ ...radii ? [" radii,"] : [],
1529
+ "});"
1530
+ ].join("\n");
1531
+ /**
1532
+ * Render a static `uni-theme.ts` from a brand seed — the file the `ng add`
1533
+ * schematic writes and the MCP `generate_uni_theme` tool returns.
1534
+ *
1535
+ * The file is the system's **source of truth**: literal colors, the border
1536
+ * primitives spelled out, and a sparse `components` override section — so a
1537
+ * human (or an AI agent) can retheme by editing tokens in place, with no
1538
+ * runtime generation. Deterministic: same input, same file.
1539
+ */
1540
+ var emitThemeFile = (input) => {
1541
+ const { darkMode = true, name = "Brand" } = input;
1542
+ const { lightColors, darkColors, radii, report } = generateThemes(input);
1543
+ const id = name.replace(/\W+/g, "") || "Brand";
1544
+ const regenerate = [
1545
+ `--brand=${(Array.isArray(input.seed) ? input.seed : [input.seed]).join(",")}`,
1546
+ input.vibe && `--vibe=${input.vibe}`,
1547
+ input.scheme && `--scheme=${input.scheme}`,
1548
+ input.shape && `--shape=${input.shape}`,
1549
+ !darkMode && "--dark-mode=false"
1550
+ ].filter(Boolean).join(" ");
1551
+ const reportSummary = `${report.checks.length} contrast pairs checked · worst ${report.worstRatio}:1 · ${report.pass ? "all AA" : `${report.checks.filter((c) => !c.pass).length} failing`}`;
1552
+ const modes = [{
1553
+ exportName: `${id}Light`,
1554
+ displayName: `${name} Light`,
1555
+ colorsConst: "lightColors",
1556
+ colors: lightColors
1557
+ }, ...darkMode ? [{
1558
+ exportName: `${id}Dark`,
1559
+ displayName: `${name} Dark`,
1560
+ colorsConst: "darkColors",
1561
+ colors: darkColors
1562
+ }] : []];
1563
+ return {
1564
+ content: [
1565
+ "/**",
1566
+ ` * ${name} theme for Uni — generated data, yours to edit.`,
1567
+ " *",
1568
+ ` * Regenerate colors: ng add @uni-design-system/uni-angular ${regenerate}`,
1569
+ " * (or the `generate-uni-theme` MCP tool). Edits are never overwritten silently —",
1570
+ " * regeneration rewrites this file, so commit before regenerating.",
1571
+ ` * ${reportSummary}.`,
1572
+ " */",
1573
+ "import {",
1574
+ " createTheme,",
1575
+ " type Borders,",
1576
+ " type Colors,",
1577
+ " type ComponentThemes,",
1578
+ " type UniTheme,",
1579
+ "} from '@uni-design-system/uni-core';",
1580
+ "",
1581
+ ...modes.map(({ colorsConst, colors }) => `const ${colorsConst}: Colors = {\n${recordLiteral(colors, " ")}\n};\n`),
1582
+ bordersLiteral(),
1583
+ "",
1584
+ "/**",
1585
+ " * Sparse component overrides, deep-merged over Uni component defaults: only",
1586
+ " * what you write here changes. Point components at your own primitives, e.g.:",
1587
+ " * button: { variants: { secondary: { border: `2px dashed ${colors.tertiary}` } } },",
1588
+ " * input: { options: { borderRadius: 'max' } },",
1589
+ " */",
1590
+ "const components = (colors: Colors): ComponentThemes => ({});",
1591
+ "",
1592
+ ...radii ? [
1593
+ `/** Shape language: '${input.shape}'. */`,
1594
+ `const radii = {\n${recordLiteral(radii, " ")}\n};`,
1595
+ ""
1596
+ ] : [],
1597
+ ...modes.map(({ exportName, displayName, colorsConst }) => `${themeExport(exportName, displayName, colorsConst, !!radii)}\n`),
1598
+ "/** First key wins as the default theme when registered via UNI_THEMES. */",
1599
+ `export const ${id}Themes = { ${modes.map((m) => m.exportName).join(", ")} };`,
1600
+ ""
1601
+ ].join("\n"),
1602
+ providerSnippet: [
1603
+ `import { UNI_THEMES } from '@uni-design-system/uni-angular';`,
1604
+ `import { ${id}Themes } from './uni-theme';`,
1605
+ "",
1606
+ "// app.config.ts → providers:",
1607
+ `{ provide: UNI_THEMES, useValue: ${id}Themes },`
1608
+ ].join("\n"),
1609
+ report,
1610
+ reportSummary
1611
+ };
1612
+ };
1613
+ //#endregion
189
1614
  //#region src/concepts/gradient/gradient.helper.ts
190
1615
  function gradient(config) {
191
1616
  return ``;
@@ -285,781 +1710,34 @@ var ShadowCssMap = {
285
1710
  modal: GetBoxShadows(ShadowMap["modal"])
286
1711
  };
287
1712
  //#endregion
288
- //#region src/concepts/theme/palettes/theme.palette.ts
289
- var genericLightTheme = {
290
- primary: "#0066B2",
291
- secondary: "#008528",
292
- tertiary: "#D97706",
293
- quaternary: "#52525B",
294
- warn: "#DC2626",
295
- success: "#008528",
296
- light: "#F4F4F5",
297
- onLight: "#18181B",
298
- onLightVariant: "rgba(24, 24, 27, 0.6)",
299
- dark: "#18181B",
300
- onDark: "rgba(255, 255, 255, 0.85)",
301
- background: "#FFFFFF",
302
- disabled: "rgba(24, 24, 27, 0.08)",
303
- onDisabled: "rgba(24, 24, 27, 0.4)"
304
- };
305
- //#endregion
306
- //#region src/concepts/theme/themes/base.theme.ts
307
- var BaseButton = {
308
- borderRadius: 100,
309
- color: "primary-container",
310
- contentColor: "on-primary-container",
311
- verticalPadding: {
312
- xxs: 2,
313
- xs: 5,
314
- sm: 8,
315
- md: 12,
316
- lg: 16,
317
- xl: 20,
318
- xxl: 24
319
- },
320
- horizontalPadding: {
321
- xxs: 4,
322
- xs: 8,
323
- sm: 12,
324
- md: 18,
325
- lg: 24,
326
- xl: 30,
327
- xxl: 36
328
- }
329
- };
330
- var BaseContainer = {
331
- color: "primary-container",
332
- contentColor: "on-primary-container",
333
- borderRadii: {
334
- xxs: 4,
335
- xs: 8,
336
- sm: 12,
337
- md: 16,
338
- lg: 20,
339
- xl: 24,
340
- xxl: 28
341
- },
342
- horizontalPadding: {
343
- xxs: 6,
344
- xs: 12,
345
- sm: 18,
346
- md: 24,
347
- lg: 30,
348
- xl: 36,
349
- xxl: 42
350
- },
351
- contentSpacing: {
352
- xxs: 4,
353
- xs: 8,
354
- sm: 12,
355
- md: 16,
356
- lg: 20,
357
- xl: 24,
358
- xxl: 28
359
- }
360
- };
361
- var BaseTheme = {
362
- id: "BaseTheme",
363
- name: "Base Theme",
364
- colors: {
365
- primary: "#6750A4",
366
- "on-primary": "#FFFFFF",
367
- "primary-container": "#EADDFF",
368
- "on-primary-container": "#21005E",
369
- secondary: "#625B71",
370
- "on-secondary": "#FFFFFF",
371
- "secondary-container": "#E8DEF8",
372
- "on-secondary-container": "#1E192B",
373
- tertiary: "#7D5260",
374
- "on-tertiary": "#FFFFFF",
375
- "tertiary-container": "#FFD8E4",
376
- "on-tertiary-container": "#370B1E",
377
- error: "#B3261E",
378
- "on-error": "#FFFFFF",
379
- "error-container": "#F9DEDC",
380
- "on-error-container": "#370B1E",
381
- background: "#FFFBFE",
382
- "on-background": "#1C1B1F",
383
- surface: "#FFFBFE",
384
- "on-surface": "#1C1B1F",
385
- "surface-variant": "#E7E0EC",
386
- "on-surface-variant": "#49454E",
387
- outline: "#79747E",
388
- shadow: "#000000",
389
- "surface-tint": "#6750A4",
390
- "inverse-surface": "#313033",
391
- "on-inverse-surface": "#F4EFF4",
392
- "on-inverse-surface-primary": "#D0BCFF",
393
- scrim: "#000000",
394
- transparent: "rgba(0,0,0,0)",
395
- "primary-surface": genericLightTheme.background,
396
- "on-primary-surface": genericLightTheme.onLight,
397
- "on-primary-surface-variant": genericLightTheme.primary
398
- },
399
- typography: {
400
- "display-large": {
401
- fontFamily: "Red Hat Display",
402
- fontSize: 57,
403
- lineHeight: 64,
404
- fontWeight: "normal",
405
- letterSpacing: -.25
406
- },
407
- "display-medium": {
408
- fontFamily: "Red Hat Display",
409
- fontSize: 45,
410
- lineHeight: 52,
411
- fontWeight: "normal"
412
- },
413
- "display-small": {
414
- fontFamily: "Red Hat Display",
415
- fontSize: 36,
416
- lineHeight: 44,
417
- fontWeight: "normal"
418
- },
419
- "headline-large": {
420
- fontFamily: "Red Hat Display",
421
- fontSize: 32,
422
- lineHeight: 40,
423
- fontWeight: "normal"
424
- },
425
- "headline-medium": {
426
- fontFamily: "Red Hat Display",
427
- fontSize: 28,
428
- lineHeight: 36,
429
- fontWeight: "normal"
430
- },
431
- "headline-small": {
432
- fontFamily: "Red Hat Display",
433
- fontSize: 24,
434
- lineHeight: 32,
435
- fontWeight: "normal"
436
- },
437
- "title-large": {
438
- fontFamily: "Red Hat Display",
439
- fontSize: 22,
440
- lineHeight: 28,
441
- fontWeight: "normal"
442
- },
443
- "title-medium": {
444
- fontFamily: "Red Hat Display",
445
- fontSize: 16,
446
- lineHeight: 24,
447
- fontWeight: "medium",
448
- letterSpacing: .15
449
- },
450
- "title-small": {
451
- fontFamily: "Red Hat Display",
452
- fontWeight: "medium",
453
- fontSize: 14,
454
- lineHeight: 20,
455
- letterSpacing: .1
456
- },
457
- "body-1-long": {
458
- fontFamily: "Roboto",
459
- fontSize: 16,
460
- lineHeight: 22
461
- },
462
- "body-1-short": {
463
- fontFamily: "Roboto",
464
- fontSize: 16,
465
- lineHeight: 24
466
- },
467
- "body-2-long": {
468
- fontFamily: "Roboto",
469
- fontSize: 14,
470
- lineHeight: 18
471
- },
472
- "body-2-short": {
473
- fontFamily: "Roboto",
474
- fontSize: 14,
475
- lineHeight: 20
476
- },
477
- "subtitle-1": {
478
- fontFamily: "Red Hat Display",
479
- fontSize: 16,
480
- lineHeight: 24,
481
- letterSpacing: .15
482
- },
483
- "subtitle-2": {
484
- fontFamily: "Red Hat Display",
485
- fontSize: 14,
486
- lineHeight: 20,
487
- fontWeight: "medium",
488
- letterSpacing: .1
489
- },
490
- label: {
491
- fontFamily: "Roboto",
492
- fontSize: 14,
493
- lineHeight: 20
494
- },
495
- button: {
496
- fontFamily: "Red Hat Display",
497
- fontSize: 14,
498
- lineHeight: 20,
499
- fontWeight: "medium",
500
- textTransform: "capitalize"
501
- },
502
- caption: {
503
- fontFamily: "Roboto",
504
- fontSize: 12,
505
- lineHeight: 18,
506
- letterSpacing: .4
507
- },
508
- overline: {
509
- fontFamily: "Red Hat Display",
510
- fontSize: 10,
511
- lineHeight: 18,
512
- letterSpacing: 1.5,
513
- textTransform: "uppercase"
514
- },
515
- paragraph: {
516
- fontFamily: "Roboto",
517
- fontSize: 16,
518
- lineHeight: 24
519
- },
520
- quote: {
521
- fontFamily: "Roboto",
522
- fontSize: 16,
523
- lineHeight: 24
524
- },
525
- note: {
526
- fontFamily: "Roboto",
527
- fontSize: 14,
528
- lineHeight: 22,
529
- fontStyle: "italic"
530
- }
531
- },
532
- borders: {
533
- primary: `1px solid ${genericLightTheme.primary}`,
534
- secondary: `1px solid ${genericLightTheme.secondary}`,
535
- tertiary: `1px solid ${genericLightTheme.tertiary}`,
536
- quaternary: `1px solid ${genericLightTheme.quaternary}`,
537
- warn: `1px solid ${genericLightTheme.warn}`,
538
- success: `1px solid ${genericLightTheme.secondary}`,
539
- light: `1px solid ${genericLightTheme.light}`,
540
- dark: `1px solid ${genericLightTheme.dark}`,
541
- dotted: `1px dotted ${genericLightTheme.dark}`
542
- },
543
- shadows: {
544
- raised: "rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px",
545
- menu: "rgba(0, 0, 0, 0.2) 0px 3px 3px -2px, rgba(0, 0, 0, 0.14) 0px 3px 4px 0px, rgba(0, 0, 0, 0.12) 0px 1px 8px 0px;",
546
- dialog: "rgba(0, 0, 0, 0.2) 0px 3px 5px -1px, rgba(0, 0, 0, 0.14) 0px 6px 10px 0px, rgba(0, 0, 0, 0.12) 0px 1px 18px 0px",
547
- warn: "0 0 5px rgba(255, 0, 0, 0.5), inset 0 0 5px rgba(255, 0, 0, 0.3)"
548
- },
549
- spacing: {
550
- none: "none",
551
- xxs: "2px",
552
- xs: "4px",
553
- sm: "8px",
554
- md: "16px",
555
- lg: "32px",
556
- xl: "64px"
557
- },
558
- thicknesses: {
559
- thin: 1,
560
- standard: 2,
561
- thick: 4
562
- },
563
- radii: {
564
- none: "none",
565
- xxs: "4px",
566
- xs: "8px",
567
- sm: "16px",
568
- md: "24px",
569
- lg: "32px",
570
- max: "999px"
571
- },
572
- buttons: {
573
- elevated: {
574
- ...BaseButton,
575
- color: "surface",
576
- contentColor: "on-surface",
577
- shadowElevation: "raised"
578
- },
579
- filled: {
580
- ...BaseButton,
581
- color: "primary"
582
- },
583
- "filled-secondary": {
584
- ...BaseButton,
585
- color: "secondary",
586
- contentColor: "on-secondary"
587
- },
588
- outlined: {
589
- ...BaseButton,
590
- color: "transparent",
591
- borderColor: "primary",
592
- contentColor: "on-primary",
593
- borderWidth: 1
594
- },
595
- text: {
596
- ...BaseButton,
597
- color: "transparent",
598
- contentColor: "on-surface"
599
- },
600
- icon: {
601
- ...BaseButton,
602
- color: "transparent",
603
- contentColor: "on-surface",
604
- horizontalPadding: BaseButton.verticalPadding
605
- },
606
- "floating-action": {
607
- ...BaseButton,
608
- color: "secondary",
609
- contentColor: "on-secondary",
610
- borderRadii: {
611
- xxs: 3,
612
- xs: 5,
613
- sm: 8,
614
- md: 12,
615
- lg: 16,
616
- xl: 12,
617
- xxl: 20
618
- },
619
- shadowElevation: "navigation",
620
- verticalPadding: {
621
- xxs: 4,
622
- xs: 8,
623
- sm: 12,
624
- md: 18,
625
- lg: 24,
626
- xl: 30,
627
- xxl: 36
628
- },
629
- horizontalPadding: {
630
- xxs: 4,
631
- xs: 8,
632
- sm: 12,
633
- md: 18,
634
- lg: 24,
635
- xl: 30,
636
- xxl: 36
637
- }
638
- }
639
- },
640
- containers: {
641
- card: {
642
- ...BaseContainer,
643
- color: "surface",
644
- contentColor: "on-surface",
645
- shadowMode: "interactive"
646
- },
647
- screen: {
648
- ...BaseContainer,
649
- color: "background",
650
- contentColor: "on-background"
651
- },
652
- modal: {
653
- ...BaseContainer,
654
- borderRadii: {
655
- xxs: 8,
656
- xs: 16,
657
- sm: 22,
658
- md: 28,
659
- lg: 32,
660
- xl: 38,
661
- xxl: 44
662
- },
663
- color: "surface",
664
- contentColor: "on-surface",
665
- shadowMode: "static",
666
- shadowElevation: "modal",
667
- maxWidth: 560
668
- }
669
- },
670
- typefaces: {},
671
- icons: {},
672
- components: {
673
- alert: { options: {
674
- topPosition: 40,
675
- borderRadius: "sm",
676
- transitionSpeed: .35,
677
- elevation: "md"
678
- } },
679
- checkbox: { options: { size: 20 } },
680
- dialog: { options: {
681
- borderRadius: "lg",
682
- color: "primary-surface",
683
- border: "quaternary",
684
- padding: "sm",
685
- elevation: "dialog",
686
- backdrop: {
687
- background: "rgba(255, 255, 255, 0.6)",
688
- backdropFilter: "blur(2px)"
689
- }
690
- } },
691
- dialogHeader: { options: {
692
- borderRadius: "max",
693
- color: "primary",
694
- height: 48,
695
- textRole: "title-large",
696
- textAlign: "center",
697
- closeButtonIcon: "close",
698
- closeButtonSize: "md"
699
- } },
700
- dropdown: { options: {
701
- border: "none",
702
- borderRadius: "xxs",
703
- color: "primary-surface",
704
- shadow: "menu"
705
- } },
706
- footer: { options: {
707
- height: 52,
708
- color: "primary",
709
- logoHeight: 18.6,
710
- logoPadding: "md"
711
- } },
712
- input: { options: {
713
- typeFace: "input",
714
- color: "primary-surface",
715
- textColor: "on-primary-surface",
716
- disabledColor: "disabled-surface",
717
- disabledTextColor: "on-disabled-surface",
718
- border: "light",
719
- borderRadius: "xs",
720
- errorShadow: "warn",
721
- errorBorder: "warn",
722
- height: 32,
723
- paddingLeft: "sm",
724
- focusOutline: `2px solid ${genericLightTheme.primary}`,
725
- focusOutlineOffset: 2
726
- } },
727
- multiSelectDropdown: { options: {
728
- textRole: "input",
729
- textColor: "on-primary-surface",
730
- dividerBorder: "light",
731
- searchInputBorder: "light",
732
- searchInputBorderRadius: "xxs",
733
- focusOutline: `2px solid ${genericLightTheme.primary}`,
734
- focusOutlineOffset: 2
735
- } },
736
- badge: { options: { borderRadius: "xxs" } },
737
- button: {
738
- fixed: {
739
- position: "relative",
740
- overflow: "hidden",
741
- outline: "0",
742
- border: "0",
743
- cursor: "pointer",
744
- fontFamily: "Euphemia, sans-serif",
745
- transition: "all 0.28s ease"
746
- },
747
- colors: {
748
- ghost: {
749
- backgroundColor: "transparent",
750
- color: "currentcolor"
751
- },
752
- primary: {
753
- backgroundColor: genericLightTheme.primary,
754
- color: genericLightTheme.onDark
755
- },
756
- secondary: {
757
- backgroundColor: genericLightTheme.secondary,
758
- color: genericLightTheme.onDark
759
- },
760
- tertiary: {
761
- backgroundColor: genericLightTheme.tertiary,
762
- color: genericLightTheme.onDark
763
- },
764
- warn: {
765
- backgroundColor: genericLightTheme.warn,
766
- color: genericLightTheme.onDark
767
- },
768
- disabled: {
769
- backgroundColor: `${genericLightTheme.disabled} !important`,
770
- color: "#fff !important"
771
- },
772
- success: {
773
- backgroundColor: genericLightTheme.success,
774
- color: genericLightTheme.onDark
775
- }
776
- },
777
- sizes: {
778
- sm: {
779
- height: 22,
780
- borderRadius: 11,
781
- fontSize: 12,
782
- padding: "0 12px",
783
- fontFamily: "Euphemia Bold, sans-serif",
784
- fontWeight: 600
785
- },
786
- md: {
787
- height: 26,
788
- borderRadius: 13,
789
- fontSize: 16,
790
- padding: "0 16px"
791
- },
792
- lg: {
793
- height: 36,
794
- borderRadius: 18,
795
- fontSize: 18,
796
- padding: "0 18px"
797
- },
798
- xl: {
799
- height: 48,
800
- borderRadius: 24,
801
- fontSize: 24,
802
- padding: "0 22px"
803
- }
804
- }
805
- },
806
- iconButton: {
807
- colors: {
808
- ghost: {
809
- backgroundColor: "transparent",
810
- color: "currentcolor"
811
- },
812
- primary: {
813
- backgroundColor: genericLightTheme.primary,
814
- color: genericLightTheme.onDark
815
- },
816
- secondary: {
817
- backgroundColor: genericLightTheme.secondary,
818
- color: genericLightTheme.onDark
819
- },
820
- tertiary: {
821
- backgroundColor: genericLightTheme.tertiary,
822
- color: genericLightTheme.onDark
823
- },
824
- warn: {
825
- backgroundColor: genericLightTheme.warn,
826
- color: genericLightTheme.onDark
827
- },
828
- success: {
829
- backgroundColor: genericLightTheme.success,
830
- color: genericLightTheme.onDark
831
- },
832
- disabled: {
833
- backgroundColor: "transparent !important",
834
- color: "rgba(0,0,0,0.25) !important"
835
- }
836
- },
837
- sizes: {
838
- sm: {
839
- height: 22,
840
- minHeight: 22,
841
- width: 22,
842
- minWidth: 22,
843
- fontSize: 18
844
- },
845
- md: {
846
- height: 26,
847
- minHeight: 26,
848
- width: 26,
849
- minWidth: 26,
850
- fontSize: 22
851
- },
852
- lg: {
853
- height: 36,
854
- minHeight: 36,
855
- width: 36,
856
- minWidth: 36,
857
- fontSize: 30
858
- },
859
- xl: {
860
- height: 40,
861
- minHeight: 40,
862
- width: 40,
863
- minWidth: 40,
864
- fontSize: 34
865
- }
866
- }
867
- },
868
- progressGauge: {
869
- fixed: { textFill: genericLightTheme.onLight },
870
- colors: {
871
- primary: {
872
- backgroundColor: "#b3d4ea",
873
- color: genericLightTheme.primary
874
- },
875
- secondary: {
876
- backgroundColor: "#b3e7c2",
877
- color: genericLightTheme.secondary
878
- },
879
- tertiary: {
880
- backgroundColor: "#ffe2b3",
881
- color: genericLightTheme.tertiary
882
- },
883
- warn: {
884
- backgroundColor: "#ffc2b3",
885
- color: genericLightTheme.warn
886
- },
887
- success: {
888
- backgroundColor: "#b3e7c2",
889
- color: genericLightTheme.success
890
- }
891
- },
892
- sizes: {
893
- sm: { height: "54px" },
894
- md: { height: "68px" },
895
- lg: { height: "82px" },
896
- xl: { height: "104px" }
897
- }
898
- },
899
- card: {
900
- fixed: {
901
- borderStyle: "solid",
902
- borderWidth: "1px",
903
- borderRadius: "8px",
904
- overflow: "hidden"
905
- },
906
- colors: {
907
- primary: {
908
- borderColor: genericLightTheme.primary,
909
- backgroundColor: genericLightTheme.background
910
- },
911
- secondary: {
912
- borderColor: genericLightTheme.secondary,
913
- backgroundColor: genericLightTheme.background
914
- },
915
- tertiary: {
916
- borderColor: genericLightTheme.tertiary,
917
- backgroundColor: genericLightTheme.background
918
- },
919
- warn: {
920
- borderColor: genericLightTheme.warn,
921
- backgroundColor: genericLightTheme.background
922
- },
923
- success: {
924
- borderColor: genericLightTheme.success,
925
- backgroundColor: genericLightTheme.background
926
- }
927
- }
928
- },
929
- cardHeader: {
930
- fixed: { padding: "12px 24px" },
931
- colors: {
932
- primary: {
933
- backgroundColor: genericLightTheme.primary,
934
- color: genericLightTheme.onDark
935
- },
936
- secondary: {
937
- backgroundColor: genericLightTheme.secondary,
938
- color: genericLightTheme.onDark
939
- },
940
- tertiary: {
941
- backgroundColor: genericLightTheme.tertiary,
942
- color: genericLightTheme.onDark
943
- },
944
- warn: {
945
- backgroundColor: genericLightTheme.warn,
946
- color: genericLightTheme.onDark
947
- },
948
- success: {
949
- backgroundColor: genericLightTheme.success,
950
- color: genericLightTheme.onDark
951
- }
952
- }
953
- },
954
- cardContent: { fixed: { padding: "12px 24px" } },
955
- dataSearch: { options: {
956
- border: "light",
957
- borderRadius: "xs",
958
- color: "primary-surface",
959
- placeholderColor: "disabled"
960
- } },
961
- dataTable: { options: {
962
- color: "primary-surface",
963
- border: "light",
964
- borderRadius: "sm",
965
- elevation: void 0,
966
- headerPadding: "sm",
967
- footerPadding: "sm",
968
- thTextRole: "headline-small",
969
- thColor: "primary-container",
970
- thVerticalBorder: "dotted",
971
- thHorizontalBorder: "light",
972
- thPadding: "sm",
973
- tdTextRole: "title-small",
974
- tdColor: "primary-surface",
975
- tdStickyColor: "primary-container",
976
- tdPadding: "sm",
977
- tdVerticalBorder: "dotted",
978
- tdHorizontalBorder: "light",
979
- rowHoverColor: "primary-container",
980
- loadingOverlayColor: "scrim",
981
- loadingSpinnerColor: "primary",
982
- loadingSpinnerSize: 40
983
- } },
984
- notificationBadge: { options: {
985
- borderRadius: "sm",
986
- offset: -10
987
- } },
988
- paginator: { options: {
989
- gap: "xs",
990
- textRole: "label",
991
- inputBorder: "light",
992
- inputBorderRadius: "xs",
993
- pageBorderRadius: "xs",
994
- currentPageBorder: "light",
995
- currentPageBorderRadius: "xs"
996
- } },
997
- snackbar: { options: {
998
- bottomPosition: 40,
999
- transitionDelay: "0.35s",
1000
- autoCloseDelay: 35e3
1001
- } },
1002
- symbol: { options: {
1003
- fill: 0,
1004
- weight: 400,
1005
- grade: 0,
1006
- opticalSize: 24
1007
- } },
1008
- toggle: { options: { size: 20 } },
1009
- tooltip: { options: {
1010
- border: void 0,
1011
- borderRadius: "xs",
1012
- shadow: "raised",
1013
- color: "inverse-surface",
1014
- typeface: "label"
1015
- } }
1016
- }
1713
+ //#region src/concepts/style/inputs.constants.ts
1714
+ var removeInputPlatformStyling = {
1715
+ appearance: "none",
1716
+ background: "none",
1717
+ border: "none",
1718
+ outline: "none",
1719
+ boxShadow: "none",
1720
+ padding: 0,
1721
+ width: "100%"
1017
1722
  };
1018
1723
  //#endregion
1019
1724
  //#region src/concepts/theme/themes/dark.theme.ts
1020
- var DarkTheme = {
1021
- ...BaseTheme,
1725
+ var darkColors = generatePalette({
1726
+ ...BASE_PALETTE_CONFIG,
1727
+ mode: "dark"
1728
+ });
1729
+ var DarkTheme = createTheme({
1022
1730
  id: "DarkTheme",
1023
1731
  name: "Dark Theme",
1024
- colors: {
1025
- primary: "#D0BCFF",
1026
- "on-primary": "#371E73",
1027
- "primary-container": "#4F378B",
1028
- "on-primary-container": "#EADDFF",
1029
- secondary: "#CCC2DC",
1030
- "on-secondary": "#332D41",
1031
- "secondary-container": "#4A4458",
1032
- "on-secondary-container": "#E8DEF8",
1033
- tertiary: "#EFB8C8",
1034
- "on-tertiary": "#492532",
1035
- "tertiary-container": "#633B48",
1036
- "on-tertiary-container": "#FFD8E4",
1037
- error: "#F2B8B5",
1038
- "on-error": "#601410",
1039
- "error-container": "#8C1D18",
1040
- "on-error-container": "#F9DEDC",
1041
- background: "#1C1B1F",
1042
- "on-background": "#E6E1E5",
1043
- surface: "#1C1B1F",
1044
- "on-surface": "#E6E1E5",
1045
- "surface-variant": "#49454F",
1046
- "on-surface-variant": "#CAC4D0",
1047
- outline: "#938F99",
1048
- shadow: "#000000",
1049
- "surface-tint": "#D0BCFF",
1050
- "inverse-surface": "#E6E1E5",
1051
- "inverse-on-surface": "#313033",
1052
- "inverse-on-surface-primary": "#6750A4",
1053
- transparent: "rgba(0,0,0,0)"
1054
- }
1055
- };
1732
+ colors: darkColors
1733
+ });
1056
1734
  //#endregion
1057
1735
  //#region src/concepts/theme/themes/light.theme.ts
1058
- var LightTheme = {
1059
- ...BaseTheme,
1736
+ var LightTheme = createTheme({
1060
1737
  id: "LightTheme",
1061
- name: "Light Theme"
1062
- };
1738
+ name: "Light Theme",
1739
+ colors: lightColors
1740
+ });
1063
1741
  //#endregion
1064
1742
  //#region src/concepts/theme/theme.records.ts
1065
1743
  var UniThemes = {
@@ -1082,6 +1760,24 @@ var FontWeightMap = {
1082
1760
  "extra-black": 950
1083
1761
  };
1084
1762
  //#endregion
1763
+ //#region src/concepts/typography/typeface.helpers.ts
1764
+ var px = (value) => `${value}px`;
1765
+ /**
1766
+ * Converts a TextStyle (numeric, design-token oriented) into a
1767
+ * TypeFaceDefinition (CSS-ready) so a theme's `typefaces` map can be
1768
+ * derived from its `typography` block instead of being duplicated.
1769
+ */
1770
+ var toTypeface = (style) => ({
1771
+ fontFamily: style.fontFamily,
1772
+ fontSize: px(style.fontSize),
1773
+ lineHeight: px(style.lineHeight),
1774
+ ...style.letterSpacing !== void 0 && { letterSpacing: px(style.letterSpacing) },
1775
+ ...style.textTransform === "uppercase" && { textTransform: "uppercase" },
1776
+ ...style.fontWeight !== void 0 && { fontWeight: style.fontWeight },
1777
+ ...style.fontStyle && { fontStyle: style.fontStyle }
1778
+ });
1779
+ var toTypefaces = (typography) => Object.fromEntries(Object.entries(typography).map(([role, style]) => [role, toTypeface(style)]));
1780
+ //#endregion
1085
1781
  //#region src/utils/getValue.ts
1086
1782
  function getValue(data, path, defaultValue) {
1087
1783
  const value = path.split(/[.[\]]/).filter(Boolean).reduce((value, key) => value?.[key], data);
@@ -1099,6 +1795,6 @@ var debounce = (callback, timeout) => {
1099
1795
  };
1100
1796
  };
1101
1797
  //#endregion
1102
- export { BaseTheme, CategoryLightness, CategorySaturation, DarkTheme, DefaultThemeId, FontWeightMap, HSLAToString, LightTheme, RGBToHSL, RGBToString, RoleHues, ShadowCssMap, ShadowMap, UniThemes, Z_INDEX, collapseFadeOut, cycle, debounce, expandFadeIn, fadeIn, fadeOut, getAnalogousHues, getComplimentaryHue, getDeviceOrientation, getDeviceSize, getSplitComplimentaryHues, getTriadicHues, getValue, gradient, randomRangeValue, uniColor };
1798
+ export { BASE_PALETTE_CONFIG, BaseTheme, CategoryChroma, CategoryLightness, CategorySaturation, DarkTheme, DefaultThemeId, FontWeightMap, HSLAToString, HSLToHex, HSLToRGB, LightTheme, RGBToHSL, RGBToString, RoleHues, ShadowCssMap, ShadowMap, ShapeRadii, UniThemes, Z_INDEX, classifyScheme, collapseFadeOut, contrastRatio, createTheme, createThemeFromPalette, cycle, darkColors, debounce, emitThemeFile, expandFadeIn, fadeIn, fadeOut, generateColors, generatePalette, generateThemes, generateUniThemes, getAnalogousHues, getComplimentaryHue, getDeviceOrientation, getDeviceSize, getSplitComplimentaryHues, getTriadicHues, getValue, gradient, hexToHSL, hexToOklch, hexToRgb, inferCategory, lightColors, oklchToHex, randomRangeValue, relativeLuminance, removeInputPlatformStyling, rgbToHex, schemeHues, toTypeface, toTypefaces, uniColor };
1103
1799
 
1104
1800
  //# sourceMappingURL=index.js.map