@nanahoshi/mona-ui 0.1.1 → 0.2.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 (170) hide show
  1. package/auto-complete/package.json +4 -0
  2. package/avatar/package.json +4 -0
  3. package/breadcrumb/package.json +4 -0
  4. package/button/package.json +4 -0
  5. package/button-group/package.json +4 -0
  6. package/calendar/package.json +4 -0
  7. package/check-box/package.json +4 -0
  8. package/chip/package.json +4 -0
  9. package/circular-progress-bar/package.json +4 -0
  10. package/color-gradient/package.json +4 -0
  11. package/color-palette/package.json +4 -0
  12. package/color-picker/package.json +4 -0
  13. package/combo-box/package.json +4 -0
  14. package/common/package.json +4 -0
  15. package/contextmenu/package.json +4 -0
  16. package/date-input/package.json +4 -0
  17. package/date-picker/package.json +4 -0
  18. package/datetime-picker/package.json +4 -0
  19. package/dialog/package.json +4 -0
  20. package/dropdown-button/package.json +4 -0
  21. package/dropdown-list/package.json +4 -0
  22. package/dropdowns/package.json +4 -0
  23. package/editor/package.json +4 -0
  24. package/expansion-panel/package.json +4 -0
  25. package/fesm2022/nanahoshi-mona-ui-auto-complete.mjs +38 -53
  26. package/fesm2022/nanahoshi-mona-ui-breadcrumb.mjs +19 -53
  27. package/fesm2022/nanahoshi-mona-ui-button-group.mjs +15 -26
  28. package/fesm2022/nanahoshi-mona-ui-button.mjs +67 -68
  29. package/fesm2022/nanahoshi-mona-ui-calendar.mjs +53 -149
  30. package/fesm2022/nanahoshi-mona-ui-check-box.mjs +48 -95
  31. package/fesm2022/nanahoshi-mona-ui-chip.mjs +35 -45
  32. package/fesm2022/nanahoshi-mona-ui-circular-progress-bar.mjs +9 -23
  33. package/fesm2022/nanahoshi-mona-ui-color-gradient.mjs +26 -77
  34. package/fesm2022/nanahoshi-mona-ui-color-palette.mjs +16 -38
  35. package/fesm2022/nanahoshi-mona-ui-color-picker.mjs +41 -46
  36. package/fesm2022/nanahoshi-mona-ui-combo-box.mjs +32 -52
  37. package/fesm2022/nanahoshi-mona-ui-date-input.mjs +9 -12
  38. package/fesm2022/nanahoshi-mona-ui-date-picker.mjs +40 -27
  39. package/fesm2022/nanahoshi-mona-ui-datetime-picker.mjs +51 -51
  40. package/fesm2022/nanahoshi-mona-ui-dialog.mjs +40 -153
  41. package/fesm2022/nanahoshi-mona-ui-dropdown-list.mjs +32 -53
  42. package/fesm2022/nanahoshi-mona-ui-dropdowns.mjs +7 -12
  43. package/fesm2022/nanahoshi-mona-ui-editor.mjs +59 -219
  44. package/fesm2022/nanahoshi-mona-ui-expansion-panel.mjs +24 -75
  45. package/fesm2022/nanahoshi-mona-ui-fieldset.mjs +11 -44
  46. package/fesm2022/nanahoshi-mona-ui-filter.mjs +11 -41
  47. package/fesm2022/{nanahoshi-mona-ui-grid-grid-footer-cell.component-B2ETh-uI.mjs → nanahoshi-mona-ui-grid-grid-footer-cell.component-B6FBLtrr.mjs} +2 -2
  48. package/fesm2022/{nanahoshi-mona-ui-grid-grid-footer-table-cell.directive-DZk18LJC.mjs → nanahoshi-mona-ui-grid-grid-footer-table-cell.directive-OJe4UYuw.mjs} +4 -8
  49. package/fesm2022/{nanahoshi-mona-ui-grid-grid-list.component-C7WKhhig.mjs → nanahoshi-mona-ui-grid-grid-list.component-DCd8K6ng.mjs} +9 -16
  50. package/fesm2022/{nanahoshi-mona-ui-grid-grid-toggle.component-BRiY0CDX.mjs → nanahoshi-mona-ui-grid-grid-toggle.component-Dl8Hlkhj.mjs} +15 -44
  51. package/fesm2022/{nanahoshi-mona-ui-grid-grid-virtual-list.component-BrYpFMyF.mjs → nanahoshi-mona-ui-grid-grid-virtual-list.component-C5FRZlvv.mjs} +11 -20
  52. package/fesm2022/{nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-T9Bj98kl.mjs → nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-BRZUd8cE.mjs} +109 -393
  53. package/fesm2022/nanahoshi-mona-ui-grid.mjs +1 -1
  54. package/fesm2022/nanahoshi-mona-ui-internal-indicator-icon.mjs +10 -28
  55. package/fesm2022/nanahoshi-mona-ui-internal-list.mjs +26 -56
  56. package/fesm2022/nanahoshi-mona-ui-internal-tree.mjs +31 -122
  57. package/fesm2022/nanahoshi-mona-ui-internal.mjs +29 -1
  58. package/fesm2022/nanahoshi-mona-ui-list-box.mjs +4 -26
  59. package/fesm2022/nanahoshi-mona-ui-list-view.mjs +5 -18
  60. package/fesm2022/nanahoshi-mona-ui-menubar.mjs +48 -154
  61. package/fesm2022/nanahoshi-mona-ui-multi-select.mjs +35 -62
  62. package/fesm2022/nanahoshi-mona-ui-notification.mjs +24 -108
  63. package/fesm2022/nanahoshi-mona-ui-numeric-text-box.mjs +37 -63
  64. package/fesm2022/nanahoshi-mona-ui-pager.mjs +21 -73
  65. package/fesm2022/nanahoshi-mona-ui-placeholder.mjs +8 -30
  66. package/fesm2022/nanahoshi-mona-ui-popover.mjs +29 -50
  67. package/fesm2022/nanahoshi-mona-ui-popup-menu.mjs +36 -108
  68. package/fesm2022/nanahoshi-mona-ui-progress-bar.mjs +19 -60
  69. package/fesm2022/nanahoshi-mona-ui-radio-button.mjs +47 -92
  70. package/fesm2022/nanahoshi-mona-ui-scroll-view.mjs +53 -144
  71. package/fesm2022/nanahoshi-mona-ui-slider.mjs +54 -110
  72. package/fesm2022/nanahoshi-mona-ui-split-button.mjs +7 -20
  73. package/fesm2022/nanahoshi-mona-ui-splitter.mjs +15 -50
  74. package/fesm2022/nanahoshi-mona-ui-stepper.mjs +28 -91
  75. package/fesm2022/nanahoshi-mona-ui-switch.mjs +37 -58
  76. package/fesm2022/nanahoshi-mona-ui-tabs.mjs +35 -107
  77. package/fesm2022/nanahoshi-mona-ui-text-area.mjs +22 -30
  78. package/fesm2022/nanahoshi-mona-ui-text-box.mjs +40 -61
  79. package/fesm2022/nanahoshi-mona-ui-theme.mjs +1111 -269
  80. package/fesm2022/nanahoshi-mona-ui-time-picker.mjs +41 -27
  81. package/fesm2022/nanahoshi-mona-ui-time-selector.mjs +35 -99
  82. package/fesm2022/nanahoshi-mona-ui-tooltip.mjs +13 -41
  83. package/fesm2022/nanahoshi-mona-ui-window.mjs +29 -108
  84. package/fieldset/package.json +4 -0
  85. package/filter/package.json +4 -0
  86. package/grid/package.json +4 -0
  87. package/internal/filter-input/package.json +4 -0
  88. package/internal/indicator-icon/package.json +4 -0
  89. package/internal/list/package.json +4 -0
  90. package/internal/package.json +4 -0
  91. package/internal/tree/package.json +4 -0
  92. package/list/package.json +4 -0
  93. package/list-box/package.json +4 -0
  94. package/list-view/package.json +4 -0
  95. package/menubar/package.json +4 -0
  96. package/multi-select/package.json +4 -0
  97. package/notification/package.json +4 -0
  98. package/numeric-text-box/package.json +4 -0
  99. package/package.json +2 -1
  100. package/pager/package.json +4 -0
  101. package/placeholder/package.json +4 -0
  102. package/popover/package.json +4 -0
  103. package/popup/package.json +4 -0
  104. package/popup-menu/package.json +4 -0
  105. package/progress-bar/package.json +4 -0
  106. package/query/package.json +4 -0
  107. package/radio-button/package.json +4 -0
  108. package/scroll-view/package.json +4 -0
  109. package/slider/package.json +4 -0
  110. package/split-button/package.json +4 -0
  111. package/splitter/package.json +4 -0
  112. package/stepper/package.json +4 -0
  113. package/switch/package.json +4 -0
  114. package/tabs/package.json +4 -0
  115. package/text-area/package.json +4 -0
  116. package/text-box/package.json +4 -0
  117. package/theme/package.json +4 -0
  118. package/time-picker/package.json +4 -0
  119. package/time-selector/package.json +4 -0
  120. package/tooltip/package.json +4 -0
  121. package/tree-view/package.json +4 -0
  122. package/types/nanahoshi-mona-ui-auto-complete.d.ts +6 -7
  123. package/types/nanahoshi-mona-ui-breadcrumb.d.ts +4 -6
  124. package/types/nanahoshi-mona-ui-button-group.d.ts +2 -3
  125. package/types/nanahoshi-mona-ui-button.d.ts +2 -3
  126. package/types/nanahoshi-mona-ui-calendar.d.ts +21 -22
  127. package/types/nanahoshi-mona-ui-check-box.d.ts +6 -9
  128. package/types/nanahoshi-mona-ui-chip.d.ts +2 -3
  129. package/types/nanahoshi-mona-ui-circular-progress-bar.d.ts +2 -4
  130. package/types/nanahoshi-mona-ui-color-gradient.d.ts +10 -11
  131. package/types/nanahoshi-mona-ui-color-palette.d.ts +4 -5
  132. package/types/nanahoshi-mona-ui-color-picker.d.ts +6 -5
  133. package/types/nanahoshi-mona-ui-combo-box.d.ts +6 -7
  134. package/types/nanahoshi-mona-ui-date-input.d.ts +2 -3
  135. package/types/nanahoshi-mona-ui-date-picker.d.ts +2 -3
  136. package/types/nanahoshi-mona-ui-dialog.d.ts +6 -7
  137. package/types/nanahoshi-mona-ui-dropdown-list.d.ts +6 -7
  138. package/types/nanahoshi-mona-ui-dropdowns.d.ts +2 -3
  139. package/types/nanahoshi-mona-ui-expansion-panel.d.ts +8 -10
  140. package/types/nanahoshi-mona-ui-fieldset.d.ts +6 -8
  141. package/types/nanahoshi-mona-ui-filter.d.ts +2 -3
  142. package/types/nanahoshi-mona-ui-grid.d.ts +14 -15
  143. package/types/nanahoshi-mona-ui-internal-indicator-icon.d.ts +0 -1
  144. package/types/nanahoshi-mona-ui-internal.d.ts +8 -1
  145. package/types/nanahoshi-mona-ui-list-box.d.ts +4 -5
  146. package/types/nanahoshi-mona-ui-list-view.d.ts +2 -3
  147. package/types/nanahoshi-mona-ui-menubar.d.ts +6 -7
  148. package/types/nanahoshi-mona-ui-multi-select.d.ts +8 -9
  149. package/types/nanahoshi-mona-ui-numeric-text-box.d.ts +2 -3
  150. package/types/nanahoshi-mona-ui-pager.d.ts +6 -7
  151. package/types/nanahoshi-mona-ui-placeholder.d.ts +4 -6
  152. package/types/nanahoshi-mona-ui-popover.d.ts +8 -9
  153. package/types/nanahoshi-mona-ui-popup-menu.d.ts +12 -13
  154. package/types/nanahoshi-mona-ui-progress-bar.d.ts +8 -9
  155. package/types/nanahoshi-mona-ui-radio-button.d.ts +8 -11
  156. package/types/nanahoshi-mona-ui-scroll-view.d.ts +18 -20
  157. package/types/nanahoshi-mona-ui-slider.d.ts +18 -18
  158. package/types/nanahoshi-mona-ui-split-button.d.ts +2 -3
  159. package/types/nanahoshi-mona-ui-splitter.d.ts +6 -8
  160. package/types/nanahoshi-mona-ui-stepper.d.ts +12 -13
  161. package/types/nanahoshi-mona-ui-switch.d.ts +6 -7
  162. package/types/nanahoshi-mona-ui-tabs.d.ts +14 -16
  163. package/types/nanahoshi-mona-ui-text-area.d.ts +2 -4
  164. package/types/nanahoshi-mona-ui-text-box.d.ts +4 -6
  165. package/types/nanahoshi-mona-ui-theme.d.ts +111 -12
  166. package/types/nanahoshi-mona-ui-time-picker.d.ts +2 -3
  167. package/types/nanahoshi-mona-ui-time-selector.d.ts +10 -11
  168. package/types/nanahoshi-mona-ui-tooltip.d.ts +4 -5
  169. package/types/nanahoshi-mona-ui-window.d.ts +16 -17
  170. package/window/package.json +4 -0
@@ -1,306 +1,1148 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, DOCUMENT, signal, Injectable } from '@angular/core';
2
+ import { InjectionToken, inject, DOCUMENT, DestroyRef, signal, computed, Injectable, makeEnvironmentProviders } from '@angular/core';
3
+ import { converter, parse, wcagContrast, clampChroma } from 'culori';
3
4
 
5
+ function flattenThemeProfile(profile) {
6
+ return {
7
+ ...profile.colors,
8
+ ...profile.shadows,
9
+ ...profile.motion,
10
+ ...profile.effects,
11
+ ...profile.shape,
12
+ ...profile.components,
13
+ ...profile.custom
14
+ };
15
+ }
16
+
17
+ const toOklch = converter("oklch");
18
+ const roles = ["primary", "secondary", "success", "error", "warning", "info"];
19
+ const minimumTextContrast = 4.5;
20
+ const minimumBoundaryContrast = 3;
21
+ const lightSettings = {
22
+ activeDelta: -0.07,
23
+ baseLightness: 0.48,
24
+ borderLightness: 0.64,
25
+ contrastDirection: -1,
26
+ hoverDelta: -0.035,
27
+ subtleForegroundLightness: 0.34,
28
+ subtleLightness: 0.945,
29
+ surface: { mode: "oklch", l: 0.99, c: 0.003, h: 270 }
30
+ };
31
+ const darkSettings = {
32
+ activeDelta: 0.07,
33
+ baseLightness: 0.72,
34
+ borderLightness: 0.58,
35
+ contrastDirection: 1,
36
+ hoverDelta: 0.035,
37
+ subtleForegroundLightness: 0.82,
38
+ subtleLightness: 0.285,
39
+ surface: { mode: "oklch", l: 0.19, c: 0.012, h: 270 }
40
+ };
4
41
  /**
5
- * Parses an OKLCH color string (with optional alpha) into its components.
6
- * Lightness (L) can be a percentage (e.g., "39.8%") or a number (e.g., "0.398").
7
- * If L is a number, it's converted to the 0-100 scale (0.398 -> 39.8).
8
- * @param oklchColorString - e.g., "oklch(39.8% 0.195 277.366)" or "oklch(0.21 0.01 0)"
9
- * @returns Parsed OklchColor object or null if invalid.
42
+ * Generates accessible light and dark color-role overrides from consumer-provided CSS colors.
43
+ * Seed lightness is treated as source identity; the generated variants use fixed tonal anchors.
10
44
  */
11
- function parseOklch(oklchColorString) {
12
- const matchResult = oklchColorString.match(/oklch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)\s*(?:\/\s*([\d.]+))?\s*\)/i);
13
- if (matchResult && matchResult[1] !== undefined && matchResult[3] !== undefined && matchResult[4] !== undefined) {
14
- let lightnessValue = parseFloat(matchResult[1]);
15
- const lightnessUnit = matchResult[2];
16
- if (lightnessUnit === "") {
17
- lightnessValue *= 100;
45
+ function generateThemeColorPalette(seeds) {
46
+ const light = {};
47
+ const dark = {};
48
+ for (const role of roles) {
49
+ const value = seeds[role];
50
+ if (value === undefined) {
51
+ continue;
18
52
  }
19
- const chromaValue = parseFloat(matchResult[3]);
20
- const hueValue = parseFloat(matchResult[4]);
21
- let alphaValue = undefined;
22
- if (matchResult[5] !== undefined) {
23
- alphaValue = parseFloat(matchResult[5]);
53
+ const seed = parseSeed(role, value);
54
+ Object.assign(light, createRolePalette(role, seed, lightSettings));
55
+ Object.assign(dark, createRolePalette(role, seed, darkSettings));
56
+ if (role === "primary") {
57
+ Object.assign(light, createPrimaryEmphasisPalette(seed, lightSettings));
58
+ Object.assign(dark, createPrimaryEmphasisPalette(seed, darkSettings));
24
59
  }
25
- return { l: lightnessValue, c: chromaValue, h: hueValue, a: alphaValue };
26
60
  }
27
- return null;
61
+ return Object.freeze({
62
+ light: Object.freeze(light),
63
+ dark: Object.freeze(dark)
64
+ });
28
65
  }
29
- /**
30
- * Formats OklchColor components back into an OKLCH string.
31
- * Ensures L is clamped [0, 100], C is non-negative, and H is wrapped [0, 360).
32
- * Alpha is included if defined and < 1. L is always formatted as a percentage.
33
- * Matches precision of the input example.
34
- * @param colorComponents - OklchColor object
35
- * @returns Formatted OKLCH string.
36
- */
37
- function formatOklch(colorComponents) {
38
- const clampedLightness = Math.max(0, Math.min(100, colorComponents.l));
39
- const clampedChroma = Math.max(0, colorComponents.c);
40
- let wrappedHue = colorComponents.h % 360;
41
- if (wrappedHue < 0) {
42
- wrappedHue += 360;
66
+ function parseSeed(role, value) {
67
+ const parsed = parse(value);
68
+ const converted = parsed ? toOklch(parsed) : undefined;
69
+ if (!converted) {
70
+ throw new Error(`Invalid ${role} theme color seed: "${value}". Expected an opaque CSS color.`);
43
71
  }
44
- let oklchOutputString = `oklch(${clampedLightness.toFixed(1)}% ${clampedChroma.toFixed(3)} ${wrappedHue.toFixed(3)}`;
45
- if (colorComponents.a !== undefined && colorComponents.a < 1.0) {
46
- const clampedAlpha = Math.max(0, Math.min(1, colorComponents.a));
47
- oklchOutputString += ` / ${clampedAlpha.toString()}`;
72
+ if ((converted.alpha ?? 1) < 1) {
73
+ throw new Error(`Invalid ${role} theme color seed: translucent colors are not supported.`);
48
74
  }
49
- oklchOutputString += `)`;
50
- return oklchOutputString;
75
+ return mapToSrgb({
76
+ mode: "oklch",
77
+ l: clamp(converted.l, 0, 1),
78
+ c: Math.max(converted.c, 0),
79
+ h: normalizeHue(converted.h ?? 0)
80
+ });
51
81
  }
52
- /**
53
- * Generates a primary color palette based on a given primary OKLCH color.
54
- * The relationships are derived from the example provided, with adjustments
55
- * for a "more white-y" foreground.
56
- * @param primaryOklchString The primary color in OKLCH string format.
57
- * @returns An object containing the generated color palette.
58
- * @throws Error if the primaryOklchString is invalid.
59
- */
60
- function generatePrimaryColorPalette(primaryOklchString) {
61
- const primaryColor = parseOklch(primaryOklchString);
62
- if (!primaryColor) {
63
- throw new Error("Invalid primary color string. Expected format: oklch(L[%] C H [/ A])");
64
- }
65
- const colorPalette = {
66
- "--color-primary": formatOklch(primaryColor),
67
- "--color-primary-foreground": "",
68
- "--color-primary-hover": "",
69
- "--color-primary-active": "",
70
- "--color-primary-selected": "",
71
- "--color-secondary-selected": ""
72
- };
73
- // --color-primary-foreground: Adjusted for a "more white-y" appearance
74
- // L: Increased to 97.5% (was 94.3%)
75
- // C: Decreased to 0.005 (was 0.029) to be more achromatic
76
- // H: Kept the primaryColor.h + 17.222 relationship
77
- colorPalette["--color-primary-foreground"] = formatOklch({
78
- l: 97.5, // Higher lightness for more "whiteness"
79
- c: 0.005, // Lower chroma for more neutrality (closer to pure white)
80
- h: primaryColor.h + 17.222
82
+ function createRolePalette(role, seed, settings) {
83
+ const chroma = Math.min(seed.c, 0.16);
84
+ const hue = seed.h ?? 0;
85
+ const base = fitContrast(mapToSrgb({ mode: "oklch", l: settings.baseLightness, c: chroma, h: hue }), settings.surface, minimumBoundaryContrast, settings.contrastDirection);
86
+ const foreground = chooseForeground(base, hue);
87
+ const hover = ensureForegroundContrast(mapToSrgb({ ...base, l: clamp(base.l + settings.hoverDelta, 0, 1) }), foreground, settings.contrastDirection);
88
+ const active = ensureForegroundContrast(mapToSrgb({ ...base, l: clamp(base.l + settings.activeDelta, 0, 1) }), foreground, settings.contrastDirection);
89
+ const subtle = mapToSrgb({
90
+ mode: "oklch",
91
+ l: settings.subtleLightness,
92
+ c: Math.min(chroma * 0.22, 0.04),
93
+ h: hue
81
94
  });
82
- colorPalette["--color-primary-hover"] = formatOklch({
83
- l: primaryColor.l + 6,
84
- c: primaryColor.c,
85
- h: primaryColor.h
95
+ const subtleForeground = fitContrast(mapToSrgb({
96
+ mode: "oklch",
97
+ l: settings.subtleForegroundLightness,
98
+ c: Math.min(chroma * 0.8, 0.12),
99
+ h: hue
100
+ }), subtle, minimumTextContrast, settings.contrastDirection);
101
+ const border = fitContrast(mapToSrgb({
102
+ mode: "oklch",
103
+ l: settings.borderLightness,
104
+ c: Math.min(chroma * 0.55, 0.09),
105
+ h: hue
106
+ }), subtle, minimumBoundaryContrast, settings.contrastDirection);
107
+ const prefix = `--color-${role}`;
108
+ return {
109
+ [prefix]: formatOklch(base),
110
+ [`${prefix}-foreground`]: formatOklch(foreground),
111
+ [`${prefix}-hover`]: formatOklch(hover),
112
+ [`${prefix}-active`]: formatOklch(active),
113
+ [`${prefix}-selected`]: formatOklch(active),
114
+ [`${prefix}-subtle`]: formatOklch(subtle),
115
+ [`${prefix}-subtle-foreground`]: formatOklch(subtleForeground),
116
+ [`${prefix}-border`]: formatOklch(border)
117
+ };
118
+ }
119
+ function createPrimaryEmphasisPalette(seed, settings) {
120
+ const isLight = settings.contrastDirection === -1;
121
+ const hue = seed.h ?? 0;
122
+ const chroma = Math.min(seed.c * 0.32, 0.05);
123
+ const accent = mapToSrgb({
124
+ mode: "oklch",
125
+ l: isLight ? 0.925 : 0.31,
126
+ c: chroma,
127
+ h: hue
86
128
  });
87
- colorPalette["--color-primary-active"] = formatOklch({
88
- l: primaryColor.l - 4,
89
- c: primaryColor.c,
90
- h: primaryColor.h
129
+ const foreground = fitContrast(mapToSrgb({
130
+ mode: "oklch",
131
+ l: isLight ? 0.3 : 0.88,
132
+ c: Math.min(seed.c * 0.75, 0.11),
133
+ h: hue
134
+ }), accent, minimumTextContrast, settings.contrastDirection);
135
+ const hover = mapToSrgb({ ...accent, l: clamp(accent.l + (isLight ? -0.025 : 0.035), 0, 1) });
136
+ const active = mapToSrgb({ ...accent, l: clamp(accent.l + (isLight ? -0.055 : 0.07), 0, 1) });
137
+ return {
138
+ "--color-accent": formatOklch(accent),
139
+ "--color-accent-foreground": formatOklch(foreground),
140
+ "--color-accent-hover": formatOklch(hover),
141
+ "--color-accent-active": formatOklch(active),
142
+ "--color-accent-dark": "var(--color-accent-active)",
143
+ "--color-focus-indicator": "var(--color-primary)",
144
+ "--color-selected": "var(--color-accent)",
145
+ "--color-selected-foreground": "var(--color-accent-foreground)",
146
+ "--color-selected-hover": "var(--color-accent-hover)",
147
+ "--color-selected-hover-foreground": "var(--color-accent-foreground)",
148
+ "--color-selected-active": "var(--color-accent-active)",
149
+ "--color-selected-active-foreground": "var(--color-accent-foreground)",
150
+ "--color-selected-focus": "var(--color-accent-hover)",
151
+ "--color-selected-focus-foreground": "var(--color-accent-foreground)",
152
+ "--color-selected-border": "var(--color-primary)"
153
+ };
154
+ }
155
+ function chooseForeground(background, hue) {
156
+ const light = mapToSrgb({ mode: "oklch", l: 0.98, c: 0.004, h: hue });
157
+ const dark = mapToSrgb({ mode: "oklch", l: 0.16, c: 0.012, h: hue });
158
+ const preferred = wcagContrast(light, background) >= wcagContrast(dark, background) ? light : dark;
159
+ const direction = preferred === light ? 1 : -1;
160
+ return fitContrast(preferred, background, minimumTextContrast, direction);
161
+ }
162
+ function ensureForegroundContrast(background, foreground, direction) {
163
+ if (wcagContrast(background, foreground) >= minimumTextContrast) {
164
+ return background;
165
+ }
166
+ return fitContrast(background, foreground, minimumTextContrast, direction);
167
+ }
168
+ function fitContrast(color, background, minimum, direction) {
169
+ let candidate = color;
170
+ for (let index = 0; index < 400 && wcagContrast(candidate, background) < minimum; index++) {
171
+ const lightness = clamp(candidate.l + direction * 0.0025, 0, 1);
172
+ if (lightness === candidate.l) {
173
+ break;
174
+ }
175
+ candidate = mapToSrgb({ ...candidate, l: lightness });
176
+ }
177
+ return candidate;
178
+ }
179
+ function mapToSrgb(color) {
180
+ const mapped = clampChroma({
181
+ mode: "oklch",
182
+ l: clamp(color.l, 0, 1),
183
+ c: Math.max(color.c, 0),
184
+ h: normalizeHue(color.h ?? 0)
185
+ }, "oklch", "rgb");
186
+ return { ...mapped, alpha: undefined };
187
+ }
188
+ function formatOklch(color) {
189
+ return `oklch(${(color.l * 100).toFixed(2)}% ${color.c.toFixed(4)} ${normalizeHue(color.h ?? 0).toFixed(2)})`;
190
+ }
191
+ function normalizeHue(hue) {
192
+ return ((hue % 360) + 360) % 360;
193
+ }
194
+ function clamp(value, minimum, maximum) {
195
+ return Math.min(Math.max(value, minimum), maximum);
196
+ }
197
+
198
+ const generatedRoles$2 = generateThemeColorPalette({
199
+ primary: "#583573",
200
+ secondary: "#3A3B40",
201
+ success: "#32BEA6",
202
+ error: "#FF3055",
203
+ warning: "#FFDA6B",
204
+ info: "#4DA3FF"
205
+ });
206
+ const dark$5 = Object.freeze({
207
+ "--color-canvas": "#202123",
208
+ "--color-surface": "#1D1E20",
209
+ "--color-surface-muted": "#161718",
210
+ "--color-surface-raised": "#242528",
211
+ "--color-surface-overlay": "#161718",
212
+ "--color-foreground": "#D6D6D8",
213
+ "--color-muted-foreground": "#A8A8AD",
214
+ "--color-input-background": "#1D1E20",
215
+ "--color-input-foreground": "var(--color-foreground)",
216
+ "--color-border-subtle": "#0F0F10",
217
+ "--color-border": "#131416",
218
+ "--color-border-control": "#0F0F10",
219
+ "--color-border-control-hover": "#17181A",
220
+ "--color-hover": "#242528",
221
+ "--color-active": "#2A2B2E",
222
+ "--color-disabled-foreground": "#9A9AA0",
223
+ "--color-disabled-background": "#1A1B1D",
224
+ "--color-disabled-border": "#111214",
225
+ ...generatedRoles$2.dark,
226
+ "--color-primary": "#583573",
227
+ "--color-primary-foreground": "#F5EFF8",
228
+ "--color-primary-hover": "#684484",
229
+ "--color-primary-active": "#472A5E",
230
+ "--color-primary-selected": "#583573",
231
+ "--color-primary-subtle": "#2B2131",
232
+ "--color-primary-subtle-foreground": "#DABFEA",
233
+ "--color-primary-border": "#A174C2",
234
+ "--color-secondary": "#34353A",
235
+ "--color-secondary-foreground": "#F0F0F2",
236
+ "--color-secondary-hover": "#414247",
237
+ "--color-secondary-active": "#292A2E",
238
+ "--color-secondary-selected": "#414247",
239
+ "--color-secondary-subtle": "#232428",
240
+ "--color-secondary-subtle-foreground": "#D6D6D8",
241
+ "--color-secondary-border": "#777880",
242
+ "--color-accent": "#583573",
243
+ "--color-accent-foreground": "#F5EFF8",
244
+ "--color-accent-hover": "#684484",
245
+ "--color-accent-active": "#472A5E",
246
+ "--color-accent-dark": "var(--color-accent-active)",
247
+ "--color-selected": "var(--color-primary)",
248
+ "--color-selected-foreground": "var(--color-primary-foreground)",
249
+ "--color-selected-hover": "var(--color-primary-hover)",
250
+ "--color-selected-hover-foreground": "var(--color-primary-foreground)",
251
+ "--color-selected-active": "var(--color-active)",
252
+ "--color-selected-active-foreground": "var(--color-foreground)",
253
+ "--color-selected-focus": "var(--color-primary)",
254
+ "--color-selected-focus-foreground": "var(--color-primary-foreground)",
255
+ "--color-selected-border": "var(--color-border-subtle)",
256
+ "--color-focus-surface": "var(--color-surface)",
257
+ "--color-focus-indicator": "#A174C2",
258
+ "--color-background": "var(--color-surface)",
259
+ "--color-background-dark": "var(--color-surface-muted)",
260
+ "--color-header-background": "var(--color-surface-muted)",
261
+ "--color-header-foreground": "var(--color-foreground)",
262
+ "--color-input-border": "var(--color-border-control)",
263
+ "--color-input-hover": "var(--color-hover)",
264
+ "--color-input-active": "var(--color-surface-raised)",
265
+ "--color-popover": "var(--color-surface-overlay)",
266
+ "--color-popover-foreground": "var(--color-foreground)",
267
+ "--color-muted": "var(--color-surface-muted)",
268
+ "--color-destructive": "var(--color-error)",
269
+ "--color-destructive-foreground": "var(--color-error-foreground)",
270
+ "--color-input": "var(--color-border-control)",
271
+ "--color-disabled": "var(--color-disabled-foreground)",
272
+ "--color-chart-1": "#A174C2",
273
+ "--color-chart-2": "#6F4A8A",
274
+ "--color-chart-3": "#4DA3FF",
275
+ "--color-chart-4": "#32BEA6",
276
+ "--color-chart-5": "#FFDA6B",
277
+ "--color-scrollbar-thumb": "#34353A",
278
+ "--color-scrollbar-thumb-hover": "#4A4B51",
279
+ "--color-scrollbar-thumb-active": "#62636A",
280
+ "--color-scrollbar-thumb-focus": "var(--color-focus-indicator)",
281
+ "--color-scrollbar-track": "#161718",
282
+ "--color-scrollbar-track-hover": "#1D1E20",
283
+ "--color-scrollbar-track-active": "#242528",
284
+ "--color-scrollbar-track-focus": "#2B2131",
285
+ "--color-scrollbar-corner": "#161718"
286
+ });
287
+ const annaThemeColors = Object.freeze({ dark: dark$5 });
288
+
289
+ const dark$4 = Object.freeze({
290
+ "--shadow-control": "none",
291
+ "--shadow-raised": "0 4px 10px -4px rgb(0 0 0 / 0.6)",
292
+ "--shadow-overlay": "0 6px 14px -4px rgb(0 0 0 / 0.65)"
293
+ });
294
+ const annaThemeShadows = Object.freeze({ dark: dark$4 });
295
+
296
+ function createDefaultThemeEffects() {
297
+ return Object.freeze({
298
+ "--mona-effect-control-background-color": "var(--color-input-background)",
299
+ "--mona-effect-control-fallback-background-color": "var(--color-input-background)",
300
+ "--mona-effect-control-background-image": "none",
301
+ "--mona-effect-control-backdrop-filter": "none",
302
+ "--mona-effect-raised-background-color": "var(--color-surface-raised)",
303
+ "--mona-effect-raised-fallback-background-color": "var(--color-surface-raised)",
304
+ "--mona-effect-raised-background-image": "none",
305
+ "--mona-effect-raised-backdrop-filter": "none",
306
+ "--mona-effect-overlay-background-color": "var(--color-surface-overlay)",
307
+ "--mona-effect-overlay-fallback-background-color": "var(--color-surface-overlay)",
308
+ "--mona-effect-overlay-background-image": "none",
309
+ "--mona-effect-overlay-backdrop-filter": "none"
91
310
  });
92
- colorPalette["--color-primary-selected"] = formatOklch({
93
- l: primaryColor.l + 9,
94
- c: primaryColor.c,
95
- h: primaryColor.h
311
+ }
312
+ function createDefaultThemeShape() {
313
+ return Object.freeze({
314
+ "--radius-sm": "0.25rem",
315
+ "--radius-md": "0.375rem",
316
+ "--radius-lg": "0.5rem"
96
317
  });
97
- colorPalette["--color-secondary-selected"] = formatOklch({
98
- l: primaryColor.l + 4,
99
- c: primaryColor.c,
100
- h: primaryColor.h,
101
- a: 0.5
318
+ }
319
+
320
+ const motion$1 = Object.freeze({
321
+ "--mona-motion-fast": "150ms",
322
+ "--mona-motion-standard": "150ms"
323
+ });
324
+ const components = Object.freeze({
325
+ "--mona-calendar-background": "var(--color-input-background)",
326
+ "--mona-calendar-shadow": "none",
327
+ "--mona-list-background": "var(--color-surface)",
328
+ "--mona-list-disabled-background": "var(--color-disabled-background)",
329
+ "--mona-list-group-background": "var(--color-surface-muted)",
330
+ "--mona-list-group-border-width": "1px",
331
+ "--mona-list-group-font-weight": "600",
332
+ "--mona-menubar-background": "var(--color-surface-muted)",
333
+ "--mona-menubar-shadow": "none",
334
+ "--mona-pager-background": "var(--color-surface-muted)",
335
+ "--mona-slider-handle-border-color": "var(--color-focus-indicator)",
336
+ "--mona-tab-list-background": "var(--color-surface-muted)",
337
+ "--mona-tab-content-background": "transparent"
338
+ });
339
+ const annaTheme = Object.freeze({
340
+ name: "anna",
341
+ variants: {
342
+ dark: Object.freeze({
343
+ colors: annaThemeColors.dark,
344
+ components,
345
+ effects: createDefaultThemeEffects(),
346
+ motion: motion$1,
347
+ shape: createDefaultThemeShape(),
348
+ shadows: annaThemeShadows.dark
349
+ })
350
+ }
351
+ });
352
+
353
+ const generatedRoles$1 = generateThemeColorPalette({
354
+ primary: "#3f6be2",
355
+ secondary: "#667085",
356
+ success: "#3f8665",
357
+ error: "#d64b4b",
358
+ warning: "#a86c18",
359
+ info: "#3978c6"
360
+ });
361
+ const light$3 = Object.freeze({
362
+ "--color-canvas": "#fcfcfc",
363
+ "--color-surface": "#ffffff",
364
+ "--color-surface-muted": "#f3f4f5",
365
+ "--color-surface-raised": "#fbfbfb",
366
+ "--color-surface-overlay": "#f9f9fa",
367
+ "--color-foreground": "#252525",
368
+ "--color-muted-foreground": "#6f7074",
369
+ "--color-input-background": "#f3f4f5",
370
+ "--color-input-foreground": "var(--color-foreground)",
371
+ "--color-border-subtle": "#eeeeef",
372
+ "--color-border": "#e4e4e6",
373
+ "--color-border-control": "#d5d6d9",
374
+ "--color-border-control-hover": "#c5c6ca",
375
+ "--color-hover": "#ecedef",
376
+ "--color-active": "#e2e3e6",
377
+ "--color-disabled-foreground": "#77787c",
378
+ "--color-disabled-background": "#f0f0f1",
379
+ "--color-disabled-border": "#e4e4e6",
380
+ ...generatedRoles$1.light,
381
+ "--color-primary": "#3f6be2",
382
+ "--color-primary-foreground": "#ffffff",
383
+ "--color-primary-hover": "#365fce",
384
+ "--color-primary-active": "#2f54b8",
385
+ "--color-primary-selected": "#2f54b8",
386
+ "--color-primary-subtle": "#e5ebfb",
387
+ "--color-primary-subtle-foreground": "#29478f",
388
+ "--color-primary-border": "#3f6be2",
389
+ "--color-accent": "#e5ebfb",
390
+ "--color-accent-foreground": "#29478f",
391
+ "--color-accent-hover": "#dce5fa",
392
+ "--color-accent-active": "#d1dcf7",
393
+ "--color-accent-dark": "var(--color-accent-active)",
394
+ "--color-focus-indicator": "#3f6be2",
395
+ "--color-selected": "#e5ebfb",
396
+ "--color-selected-foreground": "#29478f",
397
+ "--color-selected-hover": "#dce5fa",
398
+ "--color-selected-hover-foreground": "#29478f",
399
+ "--color-selected-active": "#d1dcf7",
400
+ "--color-selected-active-foreground": "#29478f",
401
+ "--color-selected-focus": "#dce5fa",
402
+ "--color-selected-focus-foreground": "#29478f",
403
+ "--color-selected-border": "#3f6be2",
404
+ "--color-focus-surface": "#eef2ff",
405
+ "--color-background": "var(--color-surface)",
406
+ "--color-background-dark": "var(--color-surface-muted)",
407
+ "--color-header-background": "var(--color-surface-muted)",
408
+ "--color-header-foreground": "var(--color-foreground)",
409
+ "--color-input-border": "var(--color-border-control)",
410
+ "--color-input-hover": "var(--color-hover)",
411
+ "--color-input-active": "var(--color-surface-raised)",
412
+ "--color-popover": "var(--color-surface-overlay)",
413
+ "--color-popover-foreground": "var(--color-foreground)",
414
+ "--color-muted": "var(--color-surface-muted)",
415
+ "--color-destructive": "var(--color-error)",
416
+ "--color-destructive-foreground": "var(--color-error-foreground)",
417
+ "--color-input": "var(--color-border-control)",
418
+ "--color-disabled": "var(--color-disabled-foreground)",
419
+ "--color-chart-1": "#3f6be2",
420
+ "--color-chart-2": "#667085",
421
+ "--color-chart-3": "#4f8a70",
422
+ "--color-chart-4": "#b37a2b",
423
+ "--color-chart-5": "#c55d5d",
424
+ "--color-scrollbar-thumb": "#b7b8bc",
425
+ "--color-scrollbar-thumb-hover": "#94969b",
426
+ "--color-scrollbar-thumb-active": "#74767b",
427
+ "--color-scrollbar-thumb-focus": "var(--color-focus-indicator)",
428
+ "--color-scrollbar-track": "var(--color-canvas)",
429
+ "--color-scrollbar-track-hover": "var(--color-surface-muted)",
430
+ "--color-scrollbar-track-active": "var(--color-hover)",
431
+ "--color-scrollbar-track-focus": "var(--color-accent)",
432
+ "--color-scrollbar-corner": "var(--color-canvas)"
433
+ });
434
+ const dark$3 = Object.freeze({
435
+ "--color-canvas": "#151515",
436
+ "--color-surface": "#1b1b1c",
437
+ "--color-surface-muted": "#252527",
438
+ "--color-surface-raised": "#202022",
439
+ "--color-surface-overlay": "#262628",
440
+ "--color-foreground": "#f5f5f6",
441
+ "--color-muted-foreground": "#a9aaae",
442
+ "--color-input-background": "#252527",
443
+ "--color-input-foreground": "var(--color-foreground)",
444
+ "--color-border-subtle": "#303033",
445
+ "--color-border": "#39393d",
446
+ "--color-border-control": "#494a4f",
447
+ "--color-border-control-hover": "#5a5b61",
448
+ "--color-hover": "#2f2f32",
449
+ "--color-active": "#3a3a3e",
450
+ "--color-disabled-foreground": "#85868b",
451
+ "--color-disabled-background": "#222224",
452
+ "--color-disabled-border": "#36363a",
453
+ ...generatedRoles$1.dark,
454
+ "--color-primary": "#6f8de8",
455
+ "--color-primary-foreground": "#111522",
456
+ "--color-primary-hover": "#7d99f0",
457
+ "--color-primary-active": "#8ba6f8",
458
+ "--color-primary-selected": "#8ba6f8",
459
+ "--color-primary-subtle": "#293656",
460
+ "--color-primary-subtle-foreground": "#e7ecff",
461
+ "--color-primary-border": "#6f8de8",
462
+ "--color-accent": "#293656",
463
+ "--color-accent-foreground": "#e7ecff",
464
+ "--color-accent-hover": "#32436c",
465
+ "--color-accent-active": "#3b4e7c",
466
+ "--color-accent-dark": "var(--color-accent-active)",
467
+ "--color-focus-indicator": "#88a2f4",
468
+ "--color-selected": "#293656",
469
+ "--color-selected-foreground": "#e7ecff",
470
+ "--color-selected-hover": "#32436c",
471
+ "--color-selected-hover-foreground": "#eef2ff",
472
+ "--color-selected-active": "#3b4e7c",
473
+ "--color-selected-active-foreground": "#ffffff",
474
+ "--color-selected-focus": "#344872",
475
+ "--color-selected-focus-foreground": "#ffffff",
476
+ "--color-selected-border": "#6f8de8",
477
+ "--color-focus-surface": "#293656",
478
+ "--color-background": "var(--color-surface)",
479
+ "--color-background-dark": "var(--color-surface-muted)",
480
+ "--color-header-background": "var(--color-surface-muted)",
481
+ "--color-header-foreground": "var(--color-foreground)",
482
+ "--color-input-border": "var(--color-border-control)",
483
+ "--color-input-hover": "var(--color-hover)",
484
+ "--color-input-active": "var(--color-surface-raised)",
485
+ "--color-popover": "var(--color-surface-overlay)",
486
+ "--color-popover-foreground": "var(--color-foreground)",
487
+ "--color-muted": "var(--color-surface-muted)",
488
+ "--color-destructive": "var(--color-error)",
489
+ "--color-destructive-foreground": "var(--color-error-foreground)",
490
+ "--color-input": "var(--color-border-control)",
491
+ "--color-disabled": "var(--color-disabled-foreground)",
492
+ "--color-chart-1": "#7f9bf0",
493
+ "--color-chart-2": "#9ba3b2",
494
+ "--color-chart-3": "#70aa8e",
495
+ "--color-chart-4": "#d09a4c",
496
+ "--color-chart-5": "#de7c7c",
497
+ "--color-scrollbar-thumb": "#55565b",
498
+ "--color-scrollbar-thumb-hover": "#73747a",
499
+ "--color-scrollbar-thumb-active": "#929399",
500
+ "--color-scrollbar-thumb-focus": "var(--color-focus-indicator)",
501
+ "--color-scrollbar-track": "var(--color-canvas)",
502
+ "--color-scrollbar-track-hover": "var(--color-surface-muted)",
503
+ "--color-scrollbar-track-active": "var(--color-hover)",
504
+ "--color-scrollbar-track-focus": "var(--color-accent)",
505
+ "--color-scrollbar-corner": "var(--color-canvas)"
506
+ });
507
+ const lunaThemeColors = Object.freeze({ light: light$3, dark: dark$3 });
508
+
509
+ const light$2 = Object.freeze({
510
+ "--shadow-control": "0 1px 2px rgb(20 20 20 / 0.04)",
511
+ "--shadow-raised": "0 8px 24px -14px rgb(20 20 20 / 0.14), 0 2px 6px -3px rgb(20 20 20 / 0.06)",
512
+ "--shadow-overlay": "0 18px 42px -20px rgb(20 20 20 / 0.22), 0 6px 16px -10px rgb(20 20 20 / 0.1)"
513
+ });
514
+ const dark$2 = Object.freeze({
515
+ "--shadow-control": "0 1px 2px rgb(0 0 0 / 0.28)",
516
+ "--shadow-raised": "0 10px 26px -14px rgb(0 0 0 / 0.5), 0 2px 7px -4px rgb(0 0 0 / 0.34)",
517
+ "--shadow-overlay": "0 20px 46px -20px rgb(0 0 0 / 0.62), 0 7px 18px -11px rgb(0 0 0 / 0.46)"
518
+ });
519
+ const lunaThemeShadows = Object.freeze({ light: light$2, dark: dark$2 });
520
+
521
+ const lunaTheme = Object.freeze({
522
+ name: "luna",
523
+ variants: {
524
+ light: Object.freeze({
525
+ colors: lunaThemeColors.light,
526
+ shadows: lunaThemeShadows.light,
527
+ motion: Object.freeze({
528
+ "--mona-motion-fast": "180ms",
529
+ "--mona-motion-standard": "320ms"
530
+ }),
531
+ effects: Object.freeze({
532
+ "--mona-effect-control-background-color": "rgb(243 244 245 / 0.78)",
533
+ "--mona-effect-control-fallback-background-color": "#f3f4f5",
534
+ "--mona-effect-control-background-image": "none",
535
+ "--mona-effect-control-backdrop-filter": "blur(16px) saturate(110%)",
536
+ "--mona-effect-raised-background-color": "rgb(252 252 252 / 0.76)",
537
+ "--mona-effect-raised-fallback-background-color": "#fbfbfb",
538
+ "--mona-effect-raised-background-image": "none",
539
+ "--mona-effect-raised-backdrop-filter": "blur(22px) saturate(112%)",
540
+ "--mona-effect-overlay-background-color": "rgb(249 249 250 / 0.72)",
541
+ "--mona-effect-overlay-fallback-background-color": "#f9f9fa",
542
+ "--mona-effect-overlay-background-image": "none",
543
+ "--mona-effect-overlay-backdrop-filter": "blur(28px) saturate(115%)"
544
+ }),
545
+ shape: createDefaultThemeShape(),
546
+ custom: Object.freeze({
547
+ "--mona-date-popup-calendar-backdrop-filter": "none",
548
+ "--mona-date-popup-calendar-background": "transparent",
549
+ "--mona-date-popup-calendar-background-image": "none",
550
+ "--mona-dropdown-popup-list-background": "transparent",
551
+ "--mona-input-addon-background": "color-mix(in srgb, var(--color-input-background), var(--color-foreground) 8%)",
552
+ "--mona-menu-item-hover-background": "rgb(37 37 37 / 0.06)",
553
+ "--mona-menu-item-hover-foreground": "var(--color-foreground)",
554
+ "--mona-menubar-backdrop-filter": "var(--mona-effect-control-backdrop-filter)",
555
+ "--mona-menubar-background-image": "var(--mona-effect-control-background-image)"
556
+ }),
557
+ components: Object.freeze({
558
+ "--mona-calendar-background": "var(--mona-effect-raised-background-color)",
559
+ "--mona-calendar-shadow": "var(--shadow-raised)",
560
+ "--mona-list-background": "var(--color-surface)",
561
+ "--mona-list-disabled-background": "var(--color-disabled-background)",
562
+ "--mona-list-group-background": "rgb(37 37 37 / 0.05)",
563
+ "--mona-list-group-border-width": "1px",
564
+ "--mona-list-group-font-weight": "650",
565
+ "--mona-menubar-background": "var(--mona-effect-control-background-color)",
566
+ "--mona-menubar-shadow": "var(--shadow-control)",
567
+ "--mona-pager-background": "var(--mona-effect-raised-background-color)",
568
+ "--mona-slider-handle-border-color": "var(--color-border-control)",
569
+ "--mona-tab-list-background": "#f5f5f6",
570
+ "--mona-tab-content-background": "var(--color-surface)"
571
+ })
572
+ }),
573
+ dark: Object.freeze({
574
+ colors: lunaThemeColors.dark,
575
+ shadows: lunaThemeShadows.dark,
576
+ motion: Object.freeze({
577
+ "--mona-motion-fast": "180ms",
578
+ "--mona-motion-standard": "320ms"
579
+ }),
580
+ effects: Object.freeze({
581
+ "--mona-effect-control-background-color": "rgb(37 37 39 / 0.74)",
582
+ "--mona-effect-control-fallback-background-color": "#252527",
583
+ "--mona-effect-control-background-image": "none",
584
+ "--mona-effect-control-backdrop-filter": "blur(16px) saturate(110%)",
585
+ "--mona-effect-raised-background-color": "rgb(32 32 34 / 0.78)",
586
+ "--mona-effect-raised-fallback-background-color": "#202022",
587
+ "--mona-effect-raised-background-image": "none",
588
+ "--mona-effect-raised-backdrop-filter": "blur(22px) saturate(112%)",
589
+ "--mona-effect-overlay-background-color": "rgb(38 38 40 / 0.74)",
590
+ "--mona-effect-overlay-fallback-background-color": "#262628",
591
+ "--mona-effect-overlay-background-image": "none",
592
+ "--mona-effect-overlay-backdrop-filter": "blur(28px) saturate(115%)"
593
+ }),
594
+ shape: createDefaultThemeShape(),
595
+ custom: Object.freeze({
596
+ "--mona-date-popup-calendar-backdrop-filter": "none",
597
+ "--mona-date-popup-calendar-background": "transparent",
598
+ "--mona-date-popup-calendar-background-image": "none",
599
+ "--mona-dropdown-popup-list-background": "transparent",
600
+ "--mona-input-addon-background": "color-mix(in srgb, var(--color-input-background), var(--color-foreground) 8%)",
601
+ "--mona-menubar-backdrop-filter": "var(--mona-effect-control-backdrop-filter)",
602
+ "--mona-menubar-background-image": "var(--mona-effect-control-background-image)"
603
+ }),
604
+ components: Object.freeze({
605
+ "--mona-calendar-background": "var(--mona-effect-raised-background-color)",
606
+ "--mona-calendar-shadow": "var(--shadow-raised)",
607
+ "--mona-list-background": "var(--color-surface)",
608
+ "--mona-list-disabled-background": "var(--color-disabled-background)",
609
+ "--mona-list-group-background": "rgb(255 255 255 / 0.04)",
610
+ "--mona-list-group-border-width": "1px",
611
+ "--mona-list-group-font-weight": "650",
612
+ "--mona-menubar-background": "var(--mona-effect-control-background-color)",
613
+ "--mona-menubar-shadow": "var(--shadow-control)",
614
+ "--mona-pager-background": "var(--mona-effect-raised-background-color)",
615
+ "--mona-slider-handle-border-color": "var(--color-border-control)",
616
+ "--mona-tab-list-background": "var(--mona-effect-raised-background-color)",
617
+ "--mona-tab-content-background": "var(--color-surface)"
618
+ })
619
+ })
620
+ }
621
+ });
622
+
623
+ // The public seed API requires a primary color. Mona replaces the generated identity roles with
624
+ // the neutral definitions below and keeps the generated output only for chromatic status roles.
625
+ const generatedRoles = generateThemeColorPalette({
626
+ primary: "oklch(20.5% 0.006 285.885)",
627
+ secondary: "oklch(55.2% 0.010 285.938)",
628
+ success: "oklch(62% 0.14 150)",
629
+ error: "oklch(58% 0.19 25)",
630
+ warning: "oklch(72% 0.14 75)",
631
+ info: "oklch(60% 0.15 255)"
632
+ });
633
+ const lightNeutralRoles = Object.freeze({
634
+ "--color-primary": "oklch(20.5% 0.006 285.885)",
635
+ "--color-primary-foreground": "oklch(98.5% 0 0)",
636
+ "--color-primary-hover": "oklch(26.9% 0.006 285.885)",
637
+ "--color-primary-active": "oklch(14.1% 0.005 285.823)",
638
+ "--color-primary-selected": "oklch(14.1% 0.005 285.823)",
639
+ "--color-primary-subtle": "oklch(96.7% 0.001 286.375)",
640
+ "--color-primary-subtle-foreground": "oklch(26.9% 0.006 285.885)",
641
+ "--color-primary-border": "oklch(55.2% 0.010 285.938)",
642
+ "--color-secondary": "oklch(92.2% 0.004 286.320)",
643
+ "--color-secondary-foreground": "oklch(20.5% 0.006 285.885)",
644
+ "--color-secondary-hover": "oklch(87.1% 0.006 286.286)",
645
+ "--color-secondary-active": "oklch(80.5% 0.008 286.067)",
646
+ "--color-secondary-selected": "oklch(80.5% 0.008 286.067)",
647
+ "--color-secondary-subtle": "oklch(96.7% 0.001 286.375)",
648
+ "--color-secondary-subtle-foreground": "oklch(26.9% 0.006 285.885)",
649
+ "--color-secondary-border": "oklch(55.2% 0.010 285.938)",
650
+ "--color-accent": "oklch(96.7% 0.001 286.375)",
651
+ "--color-accent-foreground": "oklch(20.5% 0.006 285.885)",
652
+ "--color-accent-hover": "oklch(92.2% 0.004 286.320)",
653
+ "--color-accent-active": "oklch(87.1% 0.006 286.286)",
654
+ "--color-accent-dark": "var(--color-accent-active)",
655
+ "--color-selected": "var(--color-accent)",
656
+ "--color-focus-indicator": "var(--color-primary)"
657
+ });
658
+ const darkNeutralRoles = Object.freeze({
659
+ "--color-primary": "oklch(92.2% 0.004 286.320)",
660
+ "--color-primary-foreground": "oklch(20.5% 0.006 285.885)",
661
+ "--color-primary-hover": "oklch(87.1% 0.006 286.286)",
662
+ "--color-primary-active": "oklch(80.5% 0.008 286.067)",
663
+ "--color-primary-selected": "oklch(80.5% 0.008 286.067)",
664
+ "--color-primary-subtle": "oklch(27.4% 0.006 286.033)",
665
+ "--color-primary-subtle-foreground": "oklch(92.2% 0.004 286.320)",
666
+ "--color-primary-border": "oklch(65% 0.010 286.067)",
667
+ "--color-secondary": "oklch(27.4% 0.006 286.033)",
668
+ "--color-secondary-foreground": "oklch(98.5% 0 0)",
669
+ "--color-secondary-hover": "oklch(37.1% 0.008 285.805)",
670
+ "--color-secondary-active": "oklch(43.9% 0.010 285.938)",
671
+ "--color-secondary-selected": "oklch(43.9% 0.010 285.938)",
672
+ "--color-secondary-subtle": "oklch(27.4% 0.006 286.033)",
673
+ "--color-secondary-subtle-foreground": "oklch(92.2% 0.004 286.320)",
674
+ "--color-secondary-border": "oklch(65% 0.010 286.067)",
675
+ "--color-accent": "oklch(27.4% 0.006 286.033)",
676
+ "--color-accent-foreground": "oklch(98.5% 0 0)",
677
+ "--color-accent-hover": "oklch(37.1% 0.008 285.805)",
678
+ "--color-accent-active": "oklch(43.9% 0.010 285.938)",
679
+ "--color-accent-dark": "var(--color-accent-active)",
680
+ "--color-selected": "var(--color-accent)",
681
+ "--color-focus-indicator": "var(--color-primary)"
682
+ });
683
+ const light$1 = Object.freeze({
684
+ "--color-canvas": "oklch(98.5% 0 0)",
685
+ "--color-surface": "oklch(100% 0 0)",
686
+ "--color-surface-muted": "oklch(96.7% 0.001 286.375)",
687
+ "--color-surface-raised": "oklch(100% 0 0)",
688
+ "--color-surface-overlay": "oklch(100% 0 0)",
689
+ "--color-foreground": "oklch(14.1% 0.005 285.823)",
690
+ "--color-muted-foreground": "oklch(55.2% 0.016 285.938)",
691
+ "--color-input-background": "oklch(100% 0 0)",
692
+ "--color-input-foreground": "var(--color-foreground)",
693
+ "--color-border-subtle": "oklch(94% 0.002 286.320)",
694
+ "--color-border": "oklch(92.2% 0.004 286.320)",
695
+ "--color-border-control": "oklch(87.1% 0.006 286.286)",
696
+ "--color-border-control-hover": "oklch(80.5% 0.008 286.067)",
697
+ "--color-hover": "oklch(96.7% 0.001 286.375)",
698
+ "--color-active": "oklch(92.2% 0.004 286.320)",
699
+ "--color-disabled-foreground": "oklch(46% 0.010 285.938)",
700
+ "--color-disabled-background": "oklch(96.7% 0.001 286.375)",
701
+ "--color-disabled-border": "oklch(92.2% 0.004 286.320)",
702
+ ...generatedRoles.light,
703
+ ...lightNeutralRoles,
704
+ "--color-selected": "var(--color-active)",
705
+ "--color-selected-foreground": "var(--color-foreground)",
706
+ "--color-selected-hover": "var(--color-active)",
707
+ "--color-selected-hover-foreground": "var(--color-foreground)",
708
+ "--color-selected-active": "var(--color-active)",
709
+ "--color-selected-active-foreground": "var(--color-foreground)",
710
+ "--color-selected-focus": "var(--color-active)",
711
+ "--color-selected-focus-foreground": "var(--color-foreground)",
712
+ "--color-selected-border": "var(--color-primary)",
713
+ "--color-focus-surface": "var(--color-surface-muted)",
714
+ "--color-background": "var(--color-surface)",
715
+ "--color-background-dark": "var(--color-surface-muted)",
716
+ "--color-header-background": "var(--color-surface-muted)",
717
+ "--color-header-foreground": "var(--color-foreground)",
718
+ "--color-input-border": "var(--color-border-control)",
719
+ "--color-input-hover": "var(--color-hover)",
720
+ "--color-input-active": "var(--color-surface-raised)",
721
+ "--color-popover": "var(--color-surface-overlay)",
722
+ "--color-popover-foreground": "var(--color-foreground)",
723
+ "--color-muted": "var(--color-surface-muted)",
724
+ "--color-destructive": "var(--color-error)",
725
+ "--color-destructive-foreground": "var(--color-error-foreground)",
726
+ "--color-input": "var(--color-border-control)",
727
+ "--color-disabled": "var(--color-disabled-foreground)",
728
+ "--color-chart-1": "oklch(20.5% 0.006 285.885)",
729
+ "--color-chart-2": "oklch(37.1% 0.008 285.805)",
730
+ "--color-chart-3": "oklch(55.2% 0.010 285.938)",
731
+ "--color-chart-4": "oklch(70.5% 0.010 286.067)",
732
+ "--color-chart-5": "oklch(87.1% 0.006 286.286)",
733
+ "--color-scrollbar-thumb": "oklch(80.5% 0.008 286.067)",
734
+ "--color-scrollbar-thumb-hover": "oklch(70.5% 0.010 286.067)",
735
+ "--color-scrollbar-thumb-active": "oklch(55.2% 0.010 285.938)",
736
+ "--color-scrollbar-thumb-focus": "var(--color-primary)",
737
+ "--color-scrollbar-track": "var(--color-canvas)",
738
+ "--color-scrollbar-track-hover": "var(--color-surface-muted)",
739
+ "--color-scrollbar-track-active": "var(--color-hover)",
740
+ "--color-scrollbar-track-focus": "var(--color-accent)",
741
+ "--color-scrollbar-corner": "var(--color-canvas)"
742
+ });
743
+ const dark$1 = Object.freeze({
744
+ "--color-canvas": "oklch(14.1% 0.005 285.823)",
745
+ "--color-surface": "oklch(18% 0.006 285.885)",
746
+ "--color-surface-muted": "oklch(20.5% 0.006 285.885)",
747
+ "--color-surface-raised": "oklch(24% 0.006 286.033)",
748
+ "--color-surface-overlay": "oklch(27.4% 0.006 286.033)",
749
+ "--color-foreground": "oklch(98.5% 0 0)",
750
+ "--color-muted-foreground": "oklch(70.5% 0.015 286.067)",
751
+ "--color-input-background": "oklch(20.5% 0.006 285.885)",
752
+ "--color-input-foreground": "var(--color-foreground)",
753
+ "--color-border-subtle": "oklch(24% 0.006 286.033)",
754
+ "--color-border": "oklch(30% 0.007 286.033)",
755
+ "--color-border-control": "oklch(32% 0.008 285.938)",
756
+ "--color-border-control-hover": "oklch(37.1% 0.008 285.805)",
757
+ "--color-hover": "oklch(32% 0.007 286.033)",
758
+ "--color-active": "oklch(37.1% 0.008 285.805)",
759
+ "--color-disabled-foreground": "oklch(70.5% 0.010 286.067)",
760
+ "--color-disabled-background": "oklch(27.4% 0.006 286.033)",
761
+ "--color-disabled-border": "oklch(30% 0.007 286.033)",
762
+ ...generatedRoles.dark,
763
+ ...darkNeutralRoles,
764
+ "--color-selected": "var(--color-active)",
765
+ "--color-selected-foreground": "var(--color-foreground)",
766
+ "--color-selected-hover": "var(--color-active)",
767
+ "--color-selected-hover-foreground": "var(--color-foreground)",
768
+ "--color-selected-active": "var(--color-active)",
769
+ "--color-selected-active-foreground": "var(--color-foreground)",
770
+ "--color-selected-focus": "var(--color-active)",
771
+ "--color-selected-focus-foreground": "var(--color-foreground)",
772
+ "--color-selected-border": "var(--color-primary)",
773
+ "--color-focus-surface": "var(--color-surface-muted)",
774
+ "--color-background": "var(--color-surface)",
775
+ "--color-background-dark": "var(--color-surface-muted)",
776
+ "--color-header-background": "var(--color-surface-muted)",
777
+ "--color-header-foreground": "var(--color-foreground)",
778
+ "--color-input-border": "var(--color-border-control)",
779
+ "--color-input-hover": "var(--color-hover)",
780
+ "--color-input-active": "var(--color-surface-raised)",
781
+ "--color-popover": "var(--color-surface-overlay)",
782
+ "--color-popover-foreground": "var(--color-foreground)",
783
+ "--color-muted": "var(--color-surface-muted)",
784
+ "--color-destructive": "var(--color-error)",
785
+ "--color-destructive-foreground": "var(--color-error-foreground)",
786
+ "--color-input": "var(--color-border-control)",
787
+ "--color-disabled": "var(--color-disabled-foreground)",
788
+ "--color-chart-1": "oklch(92.2% 0.004 286.320)",
789
+ "--color-chart-2": "oklch(80.5% 0.008 286.067)",
790
+ "--color-chart-3": "oklch(70.5% 0.010 286.067)",
791
+ "--color-chart-4": "oklch(55.2% 0.010 285.938)",
792
+ "--color-chart-5": "oklch(43.9% 0.010 285.938)",
793
+ "--color-scrollbar-thumb": "oklch(37.1% 0.008 285.805)",
794
+ "--color-scrollbar-thumb-hover": "oklch(52% 0.010 285.938)",
795
+ "--color-scrollbar-thumb-active": "oklch(65% 0.010 286.067)",
796
+ "--color-scrollbar-thumb-focus": "var(--color-primary)",
797
+ "--color-scrollbar-track": "var(--color-canvas)",
798
+ "--color-scrollbar-track-hover": "var(--color-surface-muted)",
799
+ "--color-scrollbar-track-active": "var(--color-hover)",
800
+ "--color-scrollbar-track-focus": "var(--color-accent)",
801
+ "--color-scrollbar-corner": "var(--color-canvas)"
802
+ });
803
+ const monaThemeColors = Object.freeze({ light: light$1, dark: dark$1 });
804
+
805
+ const light = Object.freeze({
806
+ "--shadow-control": "0 1px 2px rgb(9 9 11 / 0.03)",
807
+ "--shadow-raised": "0 2px 6px rgb(9 9 11 / 0.1)",
808
+ "--shadow-overlay": "0 8px 24px rgb(9 9 11 / 0.14)"
809
+ });
810
+ const dark = Object.freeze({
811
+ "--shadow-control": "0 1px 2px rgb(0 0 0 / 0.28)",
812
+ "--shadow-raised": "0 4px 10px -4px rgb(0 0 0 / 0.55)",
813
+ "--shadow-overlay": "0 8px 24px -6px rgb(0 0 0 / 0.72)"
814
+ });
815
+ const monaThemeShadows = Object.freeze({ light, dark });
816
+
817
+ const motion = Object.freeze({
818
+ "--mona-motion-fast": "200ms",
819
+ "--mona-motion-standard": "300ms"
820
+ });
821
+ function createComponents() {
822
+ return Object.freeze({
823
+ "--mona-calendar-background": "var(--color-input-background)",
824
+ "--mona-calendar-shadow": "var(--shadow-raised)",
825
+ "--mona-list-background": "transparent",
826
+ "--mona-list-disabled-background": "transparent",
827
+ "--mona-list-group-background": "transparent",
828
+ "--mona-list-group-border-width": "0px",
829
+ "--mona-list-group-font-weight": "700",
830
+ "--mona-menubar-background": "var(--color-surface-muted)",
831
+ "--mona-menubar-shadow": "var(--shadow-raised)",
832
+ "--mona-pager-background": "var(--color-surface-muted)",
833
+ "--mona-slider-handle-border-color": "color-mix(in srgb, var(--color-focus-indicator) 50%, transparent)",
834
+ "--mona-tab-list-background": "var(--color-surface-muted)",
835
+ "--mona-tab-content-background": "var(--color-surface)"
102
836
  });
103
- return colorPalette;
104
837
  }
838
+ const monaTheme = Object.freeze({
839
+ name: "mona",
840
+ variants: {
841
+ light: Object.freeze({
842
+ colors: monaThemeColors.light,
843
+ components: createComponents(),
844
+ effects: createDefaultThemeEffects(),
845
+ motion,
846
+ shape: createDefaultThemeShape(),
847
+ shadows: monaThemeShadows.light
848
+ }),
849
+ dark: Object.freeze({
850
+ colors: monaThemeColors.dark,
851
+ components: createComponents(),
852
+ effects: createDefaultThemeEffects(),
853
+ motion,
854
+ shape: createDefaultThemeShape(),
855
+ shadows: monaThemeShadows.dark
856
+ })
857
+ }
858
+ });
105
859
 
106
- const themeColorMap = {
107
- flora: "oklch(50.8% 0.118 165.612)",
108
- kafka: "oklch(0.2912 0.0994 349.29)",
109
- lisa: "oklch(0.3671 0.1381 281.69)",
110
- mona: "oklch(0.4008 0.107 308.49)",
111
- reina: "oklch(42.4% 0.199 265.638)",
112
- rosaria: "oklch(0.3987 0.1272 20.69)"
113
- };
860
+ const builtInThemes = Object.freeze({
861
+ anna: annaTheme,
862
+ luna: lunaTheme,
863
+ mona: monaTheme
864
+ });
865
+
866
+ class DefaultThemeStrategy {
867
+ #overrides;
868
+ #themes = new Map();
869
+ constructor(registrations, overrides) {
870
+ for (const theme of Object.values(builtInThemes)) {
871
+ for (const [variant, profile] of getDefinedVariants(theme)) {
872
+ validateProfile(theme.name, variant, profile);
873
+ }
874
+ this.#themes.set(theme.name, theme);
875
+ }
876
+ for (const registration of registrations) {
877
+ this.#register(registration);
878
+ }
879
+ for (const override of overrides) {
880
+ const family = this.#themes.get(override.theme);
881
+ if (!family) {
882
+ throw new Error(`Cannot override unknown Mona UI theme "${override.theme}".`);
883
+ }
884
+ for (const variant of ["light", "dark"]) {
885
+ if (override[variant] && !family.variants[variant]) {
886
+ throw new Error(`Cannot override undeclared "${variant}" variant of Mona UI theme "${override.theme}".`);
887
+ }
888
+ }
889
+ validateCustomVariables(override.theme, override.common?.custom);
890
+ validateCustomVariables(override.theme, override.light?.custom);
891
+ validateCustomVariables(override.theme, override.dark?.custom);
892
+ }
893
+ this.#overrides = overrides;
894
+ }
895
+ resolve(selection) {
896
+ const family = this.#themes.get(selection.name);
897
+ if (!family) {
898
+ throw new Error(`Unknown Mona UI theme "${selection.name}".`);
899
+ }
900
+ const profile = family.variants[selection.variant];
901
+ if (!profile) {
902
+ throw new Error(`Mona UI theme "${selection.name}" does not support the "${selection.variant}" variant.`);
903
+ }
904
+ let resolved = cloneProfile(profile);
905
+ for (const override of this.#overrides) {
906
+ if (override.theme === selection.name) {
907
+ resolved = applyOverrides(resolved, override.common);
908
+ resolved = applyOverrides(resolved, override[selection.variant]);
909
+ }
910
+ }
911
+ return resolved;
912
+ }
913
+ #register(registration) {
914
+ if (!registration.name.trim()) {
915
+ throw new Error("Mona UI theme names cannot be empty.");
916
+ }
917
+ if (this.#themes.has(registration.name)) {
918
+ throw new Error(`Mona UI theme "${registration.name}" is already registered.`);
919
+ }
920
+ const variants = getDefinedVariants(registration);
921
+ if (variants.length === 0) {
922
+ throw new Error(`Mona UI theme "${registration.name}" must define at least one variant.`);
923
+ }
924
+ for (const [variant, profile] of variants) {
925
+ validateProfile(registration.name, variant, profile);
926
+ }
927
+ this.#themes.set(registration.name, registration);
928
+ }
929
+ }
930
+ function getDefinedVariants(registration) {
931
+ const entries = Object.entries(registration.variants);
932
+ const unknownVariants = entries.filter(([variant]) => variant !== "light" && variant !== "dark");
933
+ if (unknownVariants.length > 0) {
934
+ throw new Error(`Mona UI theme "${registration.name}" declares unsupported variants: ${unknownVariants.map(([variant]) => variant).join(", ")}.`);
935
+ }
936
+ return entries.filter((entry) => entry[1] !== undefined);
937
+ }
938
+ function applyOverrides(profile, overrides) {
939
+ if (!overrides) {
940
+ return profile;
941
+ }
942
+ const custom = profile.custom || overrides.custom ? Object.freeze({ ...profile.custom, ...overrides.custom }) : undefined;
943
+ return {
944
+ colors: Object.freeze({ ...profile.colors, ...overrides.colors }),
945
+ components: Object.freeze({ ...profile.components, ...overrides.components }),
946
+ custom,
947
+ effects: Object.freeze({ ...profile.effects, ...overrides.effects }),
948
+ motion: Object.freeze({ ...profile.motion, ...overrides.motion }),
949
+ shape: Object.freeze({ ...profile.shape, ...overrides.shape }),
950
+ shadows: Object.freeze({ ...profile.shadows, ...overrides.shadows })
951
+ };
952
+ }
953
+ function cloneProfile(profile) {
954
+ return applyOverrides(profile, {});
955
+ }
956
+ function validateProfile(name, variant, profile) {
957
+ const reference = builtInThemes.mona.variants.light;
958
+ for (const section of ["colors", "shadows", "motion", "effects", "shape", "components"]) {
959
+ const values = profile[section];
960
+ const missing = values
961
+ ? Object.keys(reference[section]).filter(key => !(key in values))
962
+ : Object.keys(reference[section]);
963
+ if (missing.length > 0) {
964
+ throw new Error(`Mona UI theme "${name}" is missing ${section} tokens for the "${variant}" variant: ${missing.join(", ")}.`);
965
+ }
966
+ }
967
+ validateCustomVariables(name, profile.custom);
968
+ }
969
+ function validateCustomVariables(name, custom) {
970
+ const requiredVariables = new Set(Object.keys(flattenThemeProfile(builtInThemes.mona.variants.light)));
971
+ const collisions = Object.keys(custom ?? {}).filter(key => requiredVariables.has(key));
972
+ if (collisions.length > 0) {
973
+ throw new Error(`Mona UI theme "${name}" custom variables collide with required tokens: ${collisions.join(", ")}.`);
974
+ }
975
+ }
976
+
977
+ const THEME_FAMILY_REGISTRATIONS = new InjectionToken("Mona UI theme family registrations");
978
+ const THEME_OVERRIDE_REGISTRATIONS = new InjectionToken("Mona UI theme override registrations");
979
+ const THEME_OPTIONS = new InjectionToken("Mona UI theme options", {
980
+ providedIn: "root",
981
+ factory: () => ({ initialTheme: { name: "mona", variant: "light" } })
982
+ });
983
+ const THEME_STRATEGY = new InjectionToken("Mona UI theme strategy", {
984
+ providedIn: "root",
985
+ factory: () => new DefaultThemeStrategy(inject(THEME_FAMILY_REGISTRATIONS, { optional: true }) ?? [], inject(THEME_OVERRIDE_REGISTRATIONS, { optional: true }) ?? [])
986
+ });
114
987
 
115
988
  class ThemeService {
989
+ #appliedVariables;
116
990
  #document;
117
- #theme;
118
- #themeVariant;
991
+ #destroyRef;
992
+ #initialSelection;
993
+ #strategy;
994
+ #activeSelection;
995
+ #activeProfile;
996
+ #activeColorPaletteSeeds;
997
+ #transparencyQuery;
998
+ #runtimeColorPalette;
119
999
  constructor() {
1000
+ this.#appliedVariables = new Set();
120
1001
  this.#document = inject(DOCUMENT);
121
- this.#theme = signal("mona", /* @ts-ignore */
122
- ...(ngDevMode ? [{ debugName: "#theme" }] : /* istanbul ignore next */ []));
123
- this.#themeVariant = signal("light", /* @ts-ignore */
124
- ...(ngDevMode ? [{ debugName: "#themeVariant" }] : /* istanbul ignore next */ []));
125
- this.themeId = signal("mona-light", /* @ts-ignore */
126
- ...(ngDevMode ? [{ debugName: "themeId" }] : /* istanbul ignore next */ []));
127
- this.theme = this.#theme.asReadonly();
128
- this.themeVariant = this.#themeVariant.asReadonly();
129
- this.updateThemeVariables();
1002
+ this.#destroyRef = inject(DestroyRef);
1003
+ this.#initialSelection = normalizeSelection(inject(THEME_OPTIONS).initialTheme);
1004
+ this.#strategy = inject(THEME_STRATEGY);
1005
+ this.#activeSelection = signal(this.#initialSelection, /* @ts-ignore */
1006
+ ...(ngDevMode ? [{ debugName: "#activeSelection" }] : /* istanbul ignore next */ []));
1007
+ this.#activeProfile = signal(this.#strategy.resolve(this.#initialSelection), /* @ts-ignore */
1008
+ ...(ngDevMode ? [{ debugName: "#activeProfile" }] : /* istanbul ignore next */ []));
1009
+ this.#activeColorPaletteSeeds = signal(null, /* @ts-ignore */
1010
+ ...(ngDevMode ? [{ debugName: "#activeColorPaletteSeeds" }] : /* istanbul ignore next */ []));
1011
+ this.#transparencyQuery = this.#document.defaultView?.matchMedia?.("(prefers-reduced-transparency: reduce)");
1012
+ this.#runtimeColorPalette = null;
1013
+ /** The consumer-provided seeds for the active runtime color palette, or `null` when provider defaults are active. */
1014
+ this.colorPaletteSeeds = this.#activeColorPaletteSeeds.asReadonly();
1015
+ this.profile = this.#activeProfile.asReadonly();
1016
+ this.selection = this.#activeSelection.asReadonly();
1017
+ this.themeName = computed(() => this.#activeSelection().name, /* @ts-ignore */
1018
+ ...(ngDevMode ? [{ debugName: "themeName" }] : /* istanbul ignore next */ []));
1019
+ this.themeVariant = computed(() => this.#activeSelection().variant, /* @ts-ignore */
1020
+ ...(ngDevMode ? [{ debugName: "themeVariant" }] : /* istanbul ignore next */ []));
1021
+ this.#applyTheme(this.#initialSelection, this.#activeProfile());
1022
+ const query = this.#transparencyQuery;
1023
+ if (query) {
1024
+ const onPreferenceChange = () => this.#applyTheme(this.#activeSelection(), this.#activeProfile());
1025
+ query.addEventListener("change", onPreferenceChange);
1026
+ this.#destroyRef.onDestroy(() => query.removeEventListener("change", onPreferenceChange));
1027
+ }
130
1028
  }
131
- setThemeId(themeId) {
132
- const [theme, variant] = themeId.split("-");
133
- this.#theme.set(theme);
134
- this.#themeVariant.set(variant);
135
- this.themeId.set(themeId);
136
- this.updateThemeVariables();
1029
+ /** Removes the runtime color palette and restores the registered profile and provider overrides. */
1030
+ clearColorPalette() {
1031
+ const selection = this.#activeSelection();
1032
+ const profile = this.#strategy.resolve(selection);
1033
+ this.#applyTheme(selection, profile);
1034
+ this.#runtimeColorPalette = null;
1035
+ this.#activeProfile.set(profile);
1036
+ this.#activeColorPaletteSeeds.set(null);
137
1037
  }
138
- getActiveThemeVariables() {
139
- const theme = this.theme();
140
- const variant = this.themeVariant();
141
- if (theme === "mona") {
142
- return variant === "light" ? this.getMonaLightThemeVariables() : this.getMonaDarkThemeVariables();
143
- }
144
- return {};
1038
+ /**
1039
+ * Applies a runtime-generated semantic color palette after all registered profile overrides.
1040
+ * The palette remains active across theme and light/dark switches until cleared.
1041
+ */
1042
+ setColorPalette(seeds) {
1043
+ const normalizedSeeds = Object.freeze({ ...seeds });
1044
+ const palette = generateThemeColorPalette(normalizedSeeds);
1045
+ const selection = this.#activeSelection();
1046
+ const baseProfile = this.#strategy.resolve(selection);
1047
+ const profile = applyColorPalette(baseProfile, palette[selection.variant]);
1048
+ this.#applyTheme(selection, profile);
1049
+ this.#runtimeColorPalette = palette;
1050
+ this.#activeProfile.set(profile);
1051
+ this.#activeColorPaletteSeeds.set(normalizedSeeds);
145
1052
  }
146
- getMonaDarkThemeVariables() {
147
- return {
148
- "--color-background": "oklch(0.21 0 0)",
149
- "--color-background-dark": "oklch(0.19 0 0)",
150
- "--color-foreground": "oklch(100% 0.001 106.424)",
151
- "--color-hover": "oklch(22.5% 0 0)",
152
- "--color-active": "oklch(19.5% 0 0)",
153
- "--color-selected": "oklch(24% 0 0)",
154
- "--color-header-background": "oklch(0.18 0 0)",
155
- "--color-header-foreground": "oklch(0.20 0 0)",
156
- "--color-accent": "oklch(24.5% 0 0)",
157
- "--color-accent-dark": "oklch(21.5% 0 0)",
158
- "--color-accent-foreground": "oklch(97% 0 0)",
159
- "--color-accent-hover": "oklch(26.5% 0 0)",
160
- "--color-accent-active": "oklch(31.5% 0 0)",
161
- "--color-input-background": "oklch(0.20 0 0)",
162
- "--color-input-border": "oklch(0.12 0 0)",
163
- "--color-input-hover": "oklch(0.22 0 0)",
164
- "--color-input-active": "oklch(0.21 0 0)",
165
- "--color-popover": "#fff",
166
- "--color-popover-foreground": "#09090b",
167
- ...generatePrimaryColorPalette(themeColorMap.flora),
168
- "--color-secondary": "oklch(0.27 0 0)",
169
- "--color-secondary-foreground": "oklch(97.7% 0.001 106.424)",
170
- "--color-secondary-hover": "oklch(0.29 0 0)",
171
- "--color-secondary-active": "oklch(0.31 0 0)",
172
- // "--color-secondary-selected": "oklch(43.8% 0.195 277.366 / 0.5)",
173
- "--color-success": "oklch(62.7% 0.194 149.214)",
174
- "--color-success-foreground": "oklch(94.3% 0.029 294.588)",
175
- "--color-success-hover": "oklch(66.7% 0.194 149.214)",
176
- "--color-success-active": "oklch(54.7% 0.194 149.214)",
177
- "--color-success-selected": "oklch(76.7% 0.194 149.214)",
178
- "--color-error": "oklch(57.7% 0.245 27.325)",
179
- "--color-error-foreground": "oklch(94.3% 0.029 294.588)",
180
- "--color-error-hover": "oklch(61.7% 0.245 27.325)",
181
- "--color-error-active": "oklch(53.7% 0.245 27.325)",
182
- "--color-error-selected": "oklch(71.7% 0.245 27.325)",
183
- "--color-warning": "oklch(66.6% 0.179 58.318)",
184
- "--color-warning-foreground": "oklch(94.3% 0.029 294.588)",
185
- "--color-warning-hover": "oklch(70.6% 0.179 58.318)",
186
- "--color-warning-active": "oklch(58.6% 0.179 58.318)",
187
- "--color-warning-selected": "oklch(80.6% 0.179 58.318)",
188
- "--color-info": "oklch(54.6% 0.245 262.881)",
189
- "--color-info-foreground": "oklch(94.3% 0.029 294.588)",
190
- "--color-info-hover": "oklch(58.6% 0.245 262.881)",
191
- "--color-info-active": "oklch(46.6% 0.245 262.881)",
192
- "--color-info-selected": "oklch(68.6% 0.245 262.881)",
193
- "--color-muted": "#f4f4f5",
194
- "--color-muted-foreground": "#71717a",
195
- "--color-border": "oklch(0.1689 0.0021 286.18)",
196
- "--color-input": "#e4e4e7",
197
- "--color-chart-1": "#e76e50",
198
- "--color-chart-2": "#2a9d90",
199
- "--color-chart-3": "#274754",
200
- "--color-chart-4": "#e8c468",
201
- "--color-chart-5": "#f4a462",
202
- "--color-scrollbar-thumb": "#d1d5db",
203
- "--color-scrollbar-thumb-hover": "#9ca3af",
204
- "--color-scrollbar-thumb-active": "#6b7280",
205
- "--color-scrollbar-thumb-focus": "#9ca3af",
206
- "--color-scrollbar-track": "#f9fafb",
207
- "--color-scrollbar-track-hover": "#f4f5f7",
208
- "--color-scrollbar-track-active": "#e5e7eb",
209
- "--color-scrollbar-track-focus": "#f4f5f7",
210
- "--color-scrollbar-corner": "#f9fafb",
211
- // Temporary variables for testing purposes
212
- "--page-background": "#1a1b1c",
213
- "--color-demo-background": "#202122"
214
- // "--color-demo-background": "oklch(0.24 0 0)"
215
- };
1053
+ /** Updates only the runtime primary seed while retaining any other active runtime seeds. */
1054
+ setPrimaryColor(primary) {
1055
+ this.setColorPalette({ ...(this.#activeColorPaletteSeeds() ?? {}), primary });
216
1056
  }
217
- getMonaLightThemeVariables() {
218
- return {
219
- "--color-background": "oklch(1 0 0)",
220
- "--color-background-dark": "oklch(0.99 0 0)",
221
- "--color-foreground": "oklch(0.1407 0.0044 285.82)",
222
- "--color-hover": "oklch(0.96 0 0)",
223
- "--color-active": "oklch(0.94 0 0)",
224
- "--color-selected": "#f4f5f7",
225
- "--color-header-background": "oklch(0.97 0 0)",
226
- "--color-header-foreground": "oklch(0.99 0 0)",
227
- "--color-accent": "oklch(0.96 0 0)",
228
- "--color-accent-dark": "oklch(0.93 0 0)",
229
- "--color-accent-foreground": "oklch(0.21 0 0)",
230
- "--color-accent-hover": "oklch(0.95 0 0)",
231
- "--color-accent-active": "oklch(0.90 0 0)",
232
- "--color-input-background": "oklch(1 0 0)",
233
- "--color-input-border": "oklch(0.92 0 0)",
234
- "--color-input-hover": "oklch(0.95 0 0)",
235
- "--color-input-active": "oklch(0.98 0 0)",
236
- "--color-popover": "#fff",
237
- "--color-popover-foreground": "#09090b",
238
- ...generatePrimaryColorPalette("oklch(0.21 0.01 0)"),
239
- // ...generatePrimaryColorPalette("oklch(0.59 0.25 17.59)"),
240
- "--color-secondary": "oklch(.97 0 0)",
241
- "--color-secondary-foreground": "oklch(0.21 0 0)",
242
- "--color-secondary-hover": "oklch(0.95 0 0)",
243
- "--color-secondary-active": "oklch(0.90 0 0)",
244
- "--color-success": "oklch(62.7% 0.194 149.214)",
245
- "--color-success-foreground": "oklch(97.7% 0.001 106.424)",
246
- "--color-success-hover": "oklch(66.7% 0.194 149.214)",
247
- "--color-success-active": "oklch(54.7% 0.194 149.214)",
248
- "--color-success-selected": "oklch(76.7% 0.194 149.214)",
249
- "--color-error": "oklch(57.7% 0.245 27.325)",
250
- "--color-error-foreground": "oklch(94.3% 0.029 294.588)",
251
- "--color-error-hover": "oklch(61.7% 0.245 27.325)",
252
- "--color-error-active": "oklch(53.7% 0.245 27.325)",
253
- "--color-error-selected": "oklch(71.7% 0.245 27.325)",
254
- "--color-warning": "oklch(66.6% 0.179 58.318)",
255
- "--color-warning-foreground": "oklch(94.3% 0.029 294.588)",
256
- "--color-warning-hover": "oklch(70.6% 0.179 58.318)",
257
- "--color-warning-active": "oklch(58.6% 0.179 58.318)",
258
- "--color-warning-selected": "oklch(80.6% 0.179 58.318)",
259
- "--color-info": "oklch(54.6% 0.245 262.881)",
260
- "--color-info-foreground": "oklch(94.3% 0.029 294.588)",
261
- "--color-info-hover": "oklch(58.6% 0.245 262.881)",
262
- "--color-info-active": "oklch(46.6% 0.245 262.881)",
263
- "--color-info-selected": "oklch(68.6% 0.245 262.881)",
264
- "--color-muted": "#f4f4f5",
265
- "--color-muted-foreground": "#71717a",
266
- "--color-destructive": "#ef4444",
267
- "--color-destructive-foreground": "#fafafa",
268
- "--color-border": "oklch(0.9197 0.004 286.32)",
269
- "--color-input": "#e4e4e7",
270
- "--color-chart-1": "#e76e50",
271
- "--color-chart-2": "#2a9d90",
272
- "--color-chart-3": "#274754",
273
- "--color-chart-4": "#e8c468",
274
- "--color-chart-5": "#f4a462",
275
- "--color-scrollbar-thumb": "#d1d5db",
276
- "--color-scrollbar-thumb-hover": "#9ca3af",
277
- "--color-scrollbar-thumb-active": "#6b7280",
278
- "--color-scrollbar-thumb-focus": "#9ca3af",
279
- "--color-scrollbar-track": "#f9fafb",
280
- "--color-scrollbar-track-hover": "#f4f5f7",
281
- "--color-scrollbar-track-active": "#e5e7eb",
282
- "--color-scrollbar-track-focus": "#f4f5f7",
283
- "--color-scrollbar-corner": "#f9fafb",
284
- "--page-background": "#fff",
285
- "--color-demo-background": "#f9fafb"
286
- };
1057
+ setTheme(selection) {
1058
+ const normalized = normalizeSelection(selection);
1059
+ const profile = this.#resolveProfile(normalized);
1060
+ this.#applyTheme(normalized, profile);
1061
+ this.#activeProfile.set(profile);
1062
+ this.#activeSelection.set(normalized);
287
1063
  }
288
- updateThemeVariables() {
289
- const themeVariables = this.getActiveThemeVariables();
290
- const root = this.#document.querySelector(":root");
291
- Object.entries(themeVariables).forEach(([key, value]) => {
292
- root.style.setProperty(key, value);
293
- });
1064
+ #applyTheme(selection, profile) {
1065
+ const root = this.#document.documentElement;
1066
+ if (!root) {
1067
+ return;
1068
+ }
1069
+ const transparency = this.#getTransparencyMode();
1070
+ const variables = getEffectiveVariables(profile, transparency);
1071
+ for (const previousName of this.#appliedVariables) {
1072
+ if (!(previousName in variables)) {
1073
+ root.style.removeProperty(previousName);
1074
+ }
1075
+ }
1076
+ for (const [name, value] of Object.entries(variables)) {
1077
+ root.style.setProperty(name, value);
1078
+ }
1079
+ root.setAttribute("data-mona-theme", selection.name);
1080
+ root.setAttribute("data-mona-variant", selection.variant);
1081
+ root.setAttribute("data-mona-transparency", transparency);
1082
+ this.#appliedVariables.clear();
1083
+ for (const name of Object.keys(variables)) {
1084
+ this.#appliedVariables.add(name);
1085
+ }
1086
+ }
1087
+ #getTransparencyMode() {
1088
+ const css = this.#document.defaultView?.CSS;
1089
+ const supportsBackdropFilter = css?.supports("backdrop-filter", "blur(1px)") === true ||
1090
+ css?.supports("-webkit-backdrop-filter", "blur(1px)") === true;
1091
+ return supportsBackdropFilter && this.#transparencyQuery?.matches !== true ? "full" : "reduced";
1092
+ }
1093
+ #resolveProfile(selection) {
1094
+ const profile = this.#strategy.resolve(selection);
1095
+ const palette = this.#runtimeColorPalette;
1096
+ return palette ? applyColorPalette(profile, palette[selection.variant]) : profile;
294
1097
  }
295
1098
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
296
1099
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ThemeService, providedIn: "root" }); }
297
1100
  }
298
1101
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: ThemeService, decorators: [{
299
1102
  type: Injectable,
300
- args: [{
301
- providedIn: "root"
302
- }]
1103
+ args: [{ providedIn: "root" }]
303
1104
  }], ctorParameters: () => [] });
1105
+ const effectLevels = ["control", "raised", "overlay"];
1106
+ function applyColorPalette(profile, colors) {
1107
+ return Object.freeze({
1108
+ ...profile,
1109
+ colors: Object.freeze({ ...profile.colors, ...colors })
1110
+ });
1111
+ }
1112
+ function getEffectiveVariables(profile, transparency) {
1113
+ const variables = { ...flattenThemeProfile(profile) };
1114
+ if (transparency === "full") {
1115
+ return variables;
1116
+ }
1117
+ for (const level of effectLevels) {
1118
+ variables[`--mona-effect-${level}-background-color`] =
1119
+ profile.effects[`--mona-effect-${level}-fallback-background-color`];
1120
+ variables[`--mona-effect-${level}-background-image`] = "none";
1121
+ variables[`--mona-effect-${level}-backdrop-filter`] = "none";
1122
+ }
1123
+ return variables;
1124
+ }
1125
+ function normalizeSelection(selection) {
1126
+ return Object.freeze({ name: selection.name, variant: selection.variant });
1127
+ }
1128
+
1129
+ function provideThemeFamily(registration) {
1130
+ return makeEnvironmentProviders([{ provide: THEME_FAMILY_REGISTRATIONS, multi: true, useValue: registration }]);
1131
+ }
1132
+ function provideThemeOverrides(registration) {
1133
+ return makeEnvironmentProviders([{ provide: THEME_OVERRIDE_REGISTRATIONS, multi: true, useValue: registration }]);
1134
+ }
1135
+ function provideThemeOptions(options) {
1136
+ return makeEnvironmentProviders([{ provide: THEME_OPTIONS, useValue: options }]);
1137
+ }
1138
+ function provideThemeColorPalette(registration) {
1139
+ const colors = generateThemeColorPalette(registration.seeds);
1140
+ return provideThemeOverrides({
1141
+ theme: registration.theme,
1142
+ light: { colors: colors.light },
1143
+ dark: { colors: colors.dark }
1144
+ });
1145
+ }
304
1146
 
305
1147
  /*
306
1148
  * Public API Surface of @nanahoshi/mona-ui/theme
@@ -310,5 +1152,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImpor
310
1152
  * Generated bundle index. Do not edit.
311
1153
  */
312
1154
 
313
- export { ThemeService };
1155
+ export { THEME_STRATEGY, ThemeService, flattenThemeProfile, generateThemeColorPalette, provideThemeColorPalette, provideThemeFamily, provideThemeOptions, provideThemeOverrides };
314
1156
  //# sourceMappingURL=nanahoshi-mona-ui-theme.mjs.map