@adea-ai/ui 0.128.1 → 0.128.3

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 (141) hide show
  1. package/dist/components/theme/appearance-panel.js +1 -1
  2. package/dist/components/theme/index.js +1 -1
  3. package/dist/components/theme/lazy.d.ts +15 -0
  4. package/dist/components/theme/lazy.d.ts.map +1 -0
  5. package/dist/components/theme/lazy.js +9 -0
  6. package/dist/components/theme/theme-catalogue-source.d.ts +15 -0
  7. package/dist/components/theme/theme-catalogue-source.d.ts.map +1 -0
  8. package/dist/components/theme/theme-catalogue-source.js +51 -0
  9. package/dist/components/theme/theme-catalogue-source.js.map +1 -0
  10. package/dist/components/theme/theme-document-core.d.ts +123 -0
  11. package/dist/components/theme/theme-document-core.d.ts.map +1 -0
  12. package/dist/components/theme/{theme-document.js → theme-document-core.js} +12 -12
  13. package/dist/components/theme/theme-document-core.js.map +1 -0
  14. package/dist/components/theme/theme-document.d.ts +8 -107
  15. package/dist/components/theme/theme-document.d.ts.map +1 -1
  16. package/dist/components/theme/theme-persistence.d.ts +1 -1
  17. package/dist/components/theme/theme-persistence.d.ts.map +1 -1
  18. package/dist/components/theme/theme-persistence.js +9 -6
  19. package/dist/components/theme/theme-persistence.js.map +1 -1
  20. package/dist/components/theme/theme-provider-core.d.ts +19 -0
  21. package/dist/components/theme/theme-provider-core.d.ts.map +1 -0
  22. package/dist/components/theme/theme-provider-core.js +28 -0
  23. package/dist/components/theme/theme-provider-core.js.map +1 -0
  24. package/dist/components/theme/theme-provider-lazy.d.ts +28 -0
  25. package/dist/components/theme/theme-provider-lazy.d.ts.map +1 -0
  26. package/dist/components/theme/theme-provider-lazy.js +36 -0
  27. package/dist/components/theme/theme-provider-lazy.js.map +1 -0
  28. package/dist/components/theme/theme-provider-value.d.ts +175 -0
  29. package/dist/components/theme/theme-provider-value.d.ts.map +1 -0
  30. package/dist/components/theme/theme-provider-value.js +200 -0
  31. package/dist/components/theme/theme-provider-value.js.map +1 -0
  32. package/dist/components/theme/theme-provider.d.ts +11 -136
  33. package/dist/components/theme/theme-provider.d.ts.map +1 -1
  34. package/dist/components/theme/theme-provider.js +27 -149
  35. package/dist/components/theme/theme-provider.js.map +1 -1
  36. package/dist/components/theme/theme-script.js +4 -3
  37. package/dist/components/theme/theme-script.js.map +1 -1
  38. package/dist/components/theme/theme-state-core.d.ts +248 -0
  39. package/dist/components/theme/theme-state-core.d.ts.map +1 -0
  40. package/dist/components/theme/{theme-state.js → theme-state-core.js} +8 -7
  41. package/dist/components/theme/theme-state-core.js.map +1 -0
  42. package/dist/components/theme/theme-state.d.ts +8 -214
  43. package/dist/components/theme/theme-state.d.ts.map +1 -1
  44. package/dist/components/theme/theme-toggle.js.map +1 -1
  45. package/dist/index.js +7 -4
  46. package/dist/lib/accent-presets.d.ts +26 -0
  47. package/dist/lib/accent-presets.d.ts.map +1 -0
  48. package/dist/lib/accent-presets.js +11 -0
  49. package/dist/lib/accent-presets.js.map +1 -0
  50. package/dist/lib/accent-roles.js +94 -9
  51. package/dist/lib/accent-roles.js.map +1 -1
  52. package/dist/lib/font-zoom.js +4 -2
  53. package/dist/lib/font-zoom.js.map +1 -1
  54. package/dist/lib/overlay.js +3 -1
  55. package/dist/lib/overlay.js.map +1 -1
  56. package/dist/lib/theme-catalogue.d.ts +3 -0
  57. package/dist/lib/theme-catalogue.d.ts.map +1 -0
  58. package/dist/lib/theme-catalogue.js +22 -0
  59. package/dist/lib/theme-catalogue.js.map +1 -0
  60. package/dist/lib/theme-css.d.ts +43 -0
  61. package/dist/lib/theme-css.d.ts.map +1 -0
  62. package/dist/lib/theme-css.js +167 -0
  63. package/dist/lib/theme-css.js.map +1 -0
  64. package/dist/lib/theme-defaults.d.ts +46 -0
  65. package/dist/lib/theme-defaults.d.ts.map +1 -0
  66. package/dist/lib/theme-defaults.generated.d.ts +13 -0
  67. package/dist/lib/theme-defaults.generated.d.ts.map +1 -0
  68. package/dist/lib/theme-defaults.generated.js +318 -0
  69. package/dist/lib/theme-defaults.generated.js.map +1 -0
  70. package/dist/lib/theme-defaults.js +47 -0
  71. package/dist/lib/theme-defaults.js.map +1 -0
  72. package/dist/lib/theme-engine-light.d.ts +3 -0
  73. package/dist/lib/theme-engine-light.d.ts.map +1 -0
  74. package/dist/lib/theme-engine-light.js +75 -0
  75. package/dist/lib/theme-engine-light.js.map +1 -0
  76. package/dist/lib/theme-engine.d.ts +69 -0
  77. package/dist/lib/theme-engine.d.ts.map +1 -0
  78. package/dist/lib/theme-engine.js +33 -0
  79. package/dist/lib/theme-engine.js.map +1 -0
  80. package/dist/lib/themes.d.ts +14 -48
  81. package/dist/lib/themes.d.ts.map +1 -1
  82. package/dist/lib/themes.js +24 -164
  83. package/dist/lib/themes.js.map +1 -1
  84. package/dist/lib/tokens.d.ts +1 -25
  85. package/dist/lib/tokens.d.ts.map +1 -1
  86. package/dist/lib/tokens.js +1 -24
  87. package/dist/lib/tokens.js.map +1 -1
  88. package/dist/lib/tooltip-focus-gate.js +7 -1
  89. package/dist/lib/tooltip-focus-gate.js.map +1 -1
  90. package/dist/lib/variants.js +2 -2
  91. package/dist/r/lib.json +35 -0
  92. package/dist/r/registry.json +70 -0
  93. package/dist/r/src/components/theme/lazy.ts +35 -0
  94. package/dist/r/src/components/theme/theme-catalogue-source.ts +59 -0
  95. package/dist/r/src/components/theme/theme-document-core.ts +262 -0
  96. package/dist/r/src/components/theme/theme-document.ts +23 -240
  97. package/dist/r/src/components/theme/theme-persistence.ts +14 -6
  98. package/dist/r/src/components/theme/theme-provider-core.tsx +40 -0
  99. package/dist/r/src/components/theme/theme-provider-lazy.tsx +34 -0
  100. package/dist/r/src/components/theme/theme-provider-value.ts +445 -0
  101. package/dist/r/src/components/theme/theme-provider.tsx +23 -346
  102. package/dist/r/src/components/theme/theme-script.ts +3 -3
  103. package/dist/r/src/components/theme/theme-state-core.ts +364 -0
  104. package/dist/r/src/components/theme/theme-state.ts +10 -329
  105. package/dist/r/src/components/theme/theme-toggle.tsx +1 -1
  106. package/dist/r/src/lib/accent-presets.ts +43 -0
  107. package/dist/r/src/lib/theme-catalogue.ts +26 -0
  108. package/dist/r/src/lib/theme-css.ts +201 -0
  109. package/dist/r/src/lib/theme-defaults.generated.ts +319 -0
  110. package/dist/r/src/lib/theme-defaults.ts +79 -0
  111. package/dist/r/src/lib/theme-engine-light.ts +117 -0
  112. package/dist/r/src/lib/theme-engine.ts +111 -0
  113. package/dist/r/src/lib/themes.ts +27 -191
  114. package/dist/r/src/lib/tokens.ts +1 -35
  115. package/dist/r/theming.json +35 -0
  116. package/package.json +12 -3
  117. package/registry.json +70 -0
  118. package/src/components/theme/lazy.ts +35 -0
  119. package/src/components/theme/theme-catalogue-source.ts +59 -0
  120. package/src/components/theme/theme-document-core.ts +262 -0
  121. package/src/components/theme/theme-document.ts +23 -240
  122. package/src/components/theme/theme-persistence.ts +14 -6
  123. package/src/components/theme/theme-provider-core.tsx +40 -0
  124. package/src/components/theme/theme-provider-lazy.tsx +34 -0
  125. package/src/components/theme/theme-provider-value.ts +445 -0
  126. package/src/components/theme/theme-provider.tsx +23 -346
  127. package/src/components/theme/theme-script.ts +3 -3
  128. package/src/components/theme/theme-state-core.ts +364 -0
  129. package/src/components/theme/theme-state.ts +10 -329
  130. package/src/components/theme/theme-toggle.tsx +1 -1
  131. package/src/lib/accent-presets.ts +43 -0
  132. package/src/lib/theme-catalogue.ts +26 -0
  133. package/src/lib/theme-css.ts +201 -0
  134. package/src/lib/theme-defaults.generated.ts +319 -0
  135. package/src/lib/theme-defaults.ts +79 -0
  136. package/src/lib/theme-engine-light.ts +117 -0
  137. package/src/lib/theme-engine.ts +111 -0
  138. package/src/lib/themes.ts +27 -191
  139. package/src/lib/tokens.ts +1 -35
  140. package/dist/components/theme/theme-document.js.map +0 -1
  141. package/dist/components/theme/theme-state.js.map +0 -1
@@ -0,0 +1,319 @@
1
+ /*
2
+ * GENERATED by scripts/build-theme-defaults.ts from @adea-ai/themes. Do not edit.
3
+ * Run `bun run theme:defaults` after the catalogue changes;
4
+ * tests/theme-defaults.test.ts fails when this file is stale.
5
+ */
6
+ import type { AccentPreset } from '@adea-ai/themes'
7
+ import type { ThemeEditorPalette, ThemeVariant } from './themes'
8
+
9
+ /** Every catalogue theme id and its appearance, in catalogue order. */
10
+ export const THEME_INDEX: readonly (readonly [id: string, appearance: 'light' | 'dark'])[] = [
11
+ ['adea-dark', 'dark'],
12
+ ['adea-dark-colorblind', 'dark'],
13
+ ['adea-dark-high-contrast', 'dark'],
14
+ ['adea-light', 'light'],
15
+ ['adea-light-colorblind', 'light'],
16
+ ['adea-light-high-contrast', 'light'],
17
+ ['aardvark-blue', 'dark'],
18
+ ['aardvark-ink', 'dark'],
19
+ ['ayu', 'dark'],
20
+ ['ayu-light', 'light'],
21
+ ['ayu-mirage', 'dark'],
22
+ ['catppuccin-frappe', 'dark'],
23
+ ['catppuccin-latte', 'light'],
24
+ ['catppuccin-macchiato', 'dark'],
25
+ ['catppuccin-mocha', 'dark'],
26
+ ['dracula', 'dark'],
27
+ ['everforest-dark', 'dark'],
28
+ ['everforest-light', 'light'],
29
+ ['gruvbox-dark', 'dark'],
30
+ ['gruvbox-light', 'light'],
31
+ ['kanagawa', 'dark'],
32
+ ['monokai', 'dark'],
33
+ ['nord', 'dark'],
34
+ ['nord-light', 'light'],
35
+ ['one-dark', 'dark'],
36
+ ['rosepine', 'dark'],
37
+ ['rosepine-dawn', 'light'],
38
+ ['rosepine-moon', 'dark'],
39
+ ['solarized-dark', 'dark'],
40
+ ['solarized-light', 'light'],
41
+ ['tokyonight-day', 'light'],
42
+ ['tokyonight-night', 'dark'],
43
+ ['tokyonight-storm', 'dark'],
44
+ ['vesper', 'dark'],
45
+ ]
46
+
47
+ /** The default light and dark themes, complete. */
48
+ export const DEFAULT_VARIANTS: Readonly<Record<'adea-light' | 'adea-dark', ThemeVariant>> = {
49
+ 'adea-light': {
50
+ id: 'adea-light',
51
+ family: 'adea',
52
+ familyLabel: 'Adea',
53
+ label: 'Light',
54
+ appearance: 'light',
55
+ description:
56
+ "The default light theme: GitHub's own white canvas carrying the dark theme's hues, transposed to survive on paper, with the family violet accent.",
57
+ colors: {
58
+ background: 'oklch(1 0 0)',
59
+ foreground: 'oklch(0.2542 0.0111 254.04)',
60
+ card: 'oklch(0.965 0 0)',
61
+ cardForeground: 'oklch(0.2542 0.0111 254.04)',
62
+ popover: 'oklch(0.935 0 0)',
63
+ popoverForeground: 'oklch(0.2542 0.0111 254.04)',
64
+ primary: 'oklch(0.5143 0.1668 301.69)',
65
+ primaryForeground: 'oklch(1 0 0)',
66
+ secondary: 'oklch(0.965 0 0)',
67
+ secondaryForeground: 'oklch(0.2542 0.0111 254.04)',
68
+ muted: 'oklch(0.965 0 0)',
69
+ mutedForeground: 'oklch(0.4929 0.0076 254.04)',
70
+ accent: 'oklch(0.9 0 0)',
71
+ accentForeground: 'oklch(0.2542 0.0111 254.04)',
72
+ destructive: 'oklch(0.5165 0.1626 25.78)',
73
+ destructiveForeground: 'oklch(1 0 0)',
74
+ destructiveSubtle: 'oklch(0.9323 0.0228 25.78)',
75
+ destructiveAction: 'oklch(0.5165 0.1626 25.78)',
76
+ destructiveActionForeground: 'oklch(1 0 0)',
77
+ success: 'oklch(0.4771 0.1809 145.62)',
78
+ successForeground: 'oklch(1 0 0)',
79
+ successSubtle: 'oklch(0.9268 0.0253 145.62)',
80
+ warning: 'oklch(0.5016 0.1401 79.91)',
81
+ warningForeground: 'oklch(1 0 0)',
82
+ warningSubtle: 'oklch(0.9302 0.0196 79.91)',
83
+ info: 'oklch(0.5375 0.1155 202.14)',
84
+ infoForeground: 'oklch(1 0 0)',
85
+ infoSubtle: 'oklch(0.9353 0.0162 202.14)',
86
+ border: 'oklch(0.85 0 0)',
87
+ input: 'oklch(0.85 0 0)',
88
+ ring: 'oklch(0.5143 0.1668 301.69)',
89
+ sidebar: 'oklch(0.965 0 0)',
90
+ sidebarForeground: 'oklch(0.2542 0.0111 254.04)',
91
+ sidebarAccent: 'oklch(0.9 0 0)',
92
+ sidebarBorder: 'oklch(0.85 0 0)',
93
+ sidebarMutedForeground: 'oklch(0.4929 0.0076 254.04)',
94
+ },
95
+ terminal: {
96
+ background: 'oklch(1 0 0)',
97
+ foreground: 'oklch(0.2542 0.0111 254.04)',
98
+ cursor: 'oklch(0.5399 0.1906 257.48)',
99
+ selection: 'oklch(0.2542 0.0111 254.04)',
100
+ black: 'oklch(0.2785 0.0132 253.04)',
101
+ red: 'oklch(0.5165 0.1626 25.78)',
102
+ green: 'oklch(0.4771 0.1809 145.62)',
103
+ yellow: 'oklch(0.5016 0.1401 79.91)',
104
+ blue: 'oklch(0.4973 0.1518 253.31)',
105
+ magenta: 'oklch(0.5143 0.1668 301.69)',
106
+ cyan: 'oklch(0.5375 0.1155 202.14)',
107
+ white: 'oklch(0.5651 0.0189 250.97)',
108
+ brightBlack: 'oklch(0.4849 0.0196 251.02)',
109
+ brightRed: 'oklch(0.5834 0.1134 25.81)',
110
+ brightGreen: 'oklch(0.5537 0.188 145.48)',
111
+ brightYellow: 'oklch(0.5724 0.1386 85.24)',
112
+ brightBlue: 'oklch(0.5677 0.1153 246.66)',
113
+ brightMagenta: 'oklch(0.5825 0.1275 305.86)',
114
+ brightCyan: 'oklch(0.5856 0.1107 201.78)',
115
+ brightWhite: 'oklch(0.6658 0.0181 250.92)',
116
+ },
117
+ editor: {
118
+ keyword: 'oklch(0.5143 0.1668 301.69)',
119
+ string: 'oklch(0.4771 0.1809 145.62)',
120
+ number: 'oklch(0.5016 0.1401 79.91)',
121
+ comment: 'oklch(0.4849 0.0196 251.02)',
122
+ function: 'oklch(0.4973 0.1518 253.31)',
123
+ variable: 'oklch(0.2785 0.0132 253.04)',
124
+ type: 'oklch(0.5375 0.1155 202.14)',
125
+ tag: 'oklch(0.5165 0.1626 25.78)',
126
+ attribute: 'oklch(0.5016 0.1401 79.91)',
127
+ operator: 'oklch(0.2785 0.0132 253.04)',
128
+ heading: 'oklch(0.5143 0.1668 301.69)',
129
+ link: 'oklch(0.4973 0.1518 253.31)',
130
+ diffAdd: 'oklch(0.4771 0.1809 145.62)',
131
+ diffDelete: 'oklch(0.5165 0.1626 25.78)',
132
+ diffHunk: 'oklch(0.5375 0.1155 202.14)',
133
+ searchMatch: 'oklch(0.5016 0.1401 79.91)',
134
+ },
135
+ chart: [
136
+ 'oklch(0.4973 0.1518 253.31)',
137
+ 'oklch(0.5143 0.1668 301.69)',
138
+ 'oklch(0.5375 0.1155 202.14)',
139
+ 'oklch(0.4771 0.1809 145.62)',
140
+ 'oklch(0.5016 0.1401 79.91)',
141
+ 'oklch(0.5165 0.1626 25.78)',
142
+ ],
143
+ provenance: { source: 'Adea', url: 'https://github.com/adea-ai/themes', license: 'Apache-2.0' },
144
+ },
145
+ 'adea-dark': {
146
+ id: 'adea-dark',
147
+ family: 'adea',
148
+ familyLabel: 'Adea',
149
+ label: 'Dark',
150
+ appearance: 'dark',
151
+ description:
152
+ 'The default dark theme: GitHub Dark Default with the canvas re-greyed to a violet-leaning neutral and the family violet accent, kept as a composition so the default can diverge from it one slot at a time.',
153
+ colors: {
154
+ background: 'oklch(0.1756 0.0063 300.91)',
155
+ foreground: 'oklch(0.942 0.0054 297.72)',
156
+ card: 'oklch(0.2106 0.0076 300.91)',
157
+ cardForeground: 'oklch(0.942 0.0054 297.72)',
158
+ popover: 'oklch(0.2406 0.0088 300.91)',
159
+ popoverForeground: 'oklch(0.942 0.0054 297.72)',
160
+ primary: 'oklch(0.7323 0.1668 301.69)',
161
+ primaryForeground: 'oklch(0.1756 0.0063 300.91)',
162
+ secondary: 'oklch(0.2106 0.0076 300.91)',
163
+ secondaryForeground: 'oklch(0.942 0.0054 297.72)',
164
+ muted: 'oklch(0.2106 0.0076 300.91)',
165
+ mutedForeground: 'oklch(0.6967 0.0057 298.74)',
166
+ accent: 'oklch(0.2756 0.0101 300.91)',
167
+ accentForeground: 'oklch(0.942 0.0054 297.72)',
168
+ destructive: 'oklch(0.7345 0.1626 25.78)',
169
+ destructiveForeground: 'oklch(0.1756 0.0063 300.91)',
170
+ destructiveSubtle: 'oklch(0.2538 0.0282 312.79)',
171
+ destructiveAction: 'oklch(0.7345 0.1626 25.78)',
172
+ destructiveActionForeground: 'oklch(0.1756 0.0063 300.91)',
173
+ success: 'oklch(0.6951 0.1809 145.62)',
174
+ successForeground: 'oklch(0.1756 0.0063 300.91)',
175
+ successSubtle: 'oklch(0.2483 0.0307 279.17)',
176
+ warning: 'oklch(0.7196 0.1401 79.91)',
177
+ warningForeground: 'oklch(0.1756 0.0063 300.91)',
178
+ warningSubtle: 'oklch(0.2518 0.025 320.37)',
179
+ info: 'oklch(0.7555 0.1155 202.14)',
180
+ infoForeground: 'oklch(0.1756 0.0063 300.91)',
181
+ infoSubtle: 'oklch(0.2568 0.0216 287.08)',
182
+ border: 'oklch(0.3256 0.0057 300.91)',
183
+ input: 'oklch(0.3256 0.0057 300.91)',
184
+ ring: 'oklch(0.7323 0.1668 301.69)',
185
+ sidebar: 'oklch(0.2106 0.0076 300.91)',
186
+ sidebarForeground: 'oklch(0.942 0.0054 297.72)',
187
+ sidebarAccent: 'oklch(0.2756 0.0101 300.91)',
188
+ sidebarBorder: 'oklch(0.3256 0.0057 300.91)',
189
+ sidebarMutedForeground: 'oklch(0.6967 0.0057 298.74)',
190
+ },
191
+ terminal: {
192
+ background: 'oklch(0.1756 0.0063 300.91)',
193
+ foreground: 'oklch(0.942 0.0054 297.72)',
194
+ cursor: 'oklch(0.6182 0.1935 258.33)',
195
+ selection: 'oklch(0.9425 0.0111 243.66)',
196
+ black: 'oklch(0.4243 0.0101 301.11)',
197
+ red: 'oklch(0.7345 0.1626 25.78)',
198
+ green: 'oklch(0.6951 0.1809 145.62)',
199
+ yellow: 'oklch(0.7196 0.1401 79.91)',
200
+ blue: 'oklch(0.7153 0.1518 253.31)',
201
+ magenta: 'oklch(0.7323 0.1668 301.69)',
202
+ cyan: 'oklch(0.7555 0.1155 202.14)',
203
+ white: 'oklch(0.786 0.0087 301.32)',
204
+ brightBlack: 'oklch(0.5627 0.0094 301.22)',
205
+ brightRed: 'oklch(0.8014 0.1134 25.81)',
206
+ brightGreen: 'oklch(0.7717 0.188 145.48)',
207
+ brightYellow: 'oklch(0.7904 0.1386 85.24)',
208
+ brightBlue: 'oklch(0.7857 0.1153 246.66)',
209
+ brightMagenta: 'oklch(0.8005 0.1275 305.86)',
210
+ brightCyan: 'oklch(0.8036 0.1107 201.78)',
211
+ brightWhite: 'oklch(1 0 0)',
212
+ },
213
+ editor: {
214
+ keyword: 'oklch(0.7323 0.1668 301.69)',
215
+ string: 'oklch(0.6951 0.1809 145.62)',
216
+ number: 'oklch(0.7196 0.1401 79.91)',
217
+ comment: 'oklch(0.5627 0.0094 301.22)',
218
+ function: 'oklch(0.7153 0.1518 253.31)',
219
+ variable: 'oklch(0.786 0.0087 301.32)',
220
+ type: 'oklch(0.7555 0.1155 202.14)',
221
+ tag: 'oklch(0.7345 0.1626 25.78)',
222
+ attribute: 'oklch(0.7196 0.1401 79.91)',
223
+ operator: 'oklch(0.786 0.0087 301.32)',
224
+ heading: 'oklch(0.7323 0.1668 301.69)',
225
+ link: 'oklch(0.7153 0.1518 253.31)',
226
+ diffAdd: 'oklch(0.6951 0.1809 145.62)',
227
+ diffDelete: 'oklch(0.7345 0.1626 25.78)',
228
+ diffHunk: 'oklch(0.7555 0.1155 202.14)',
229
+ searchMatch: 'oklch(0.7196 0.1401 79.91)',
230
+ },
231
+ chart: [
232
+ 'oklch(0.7153 0.1518 253.31)',
233
+ 'oklch(0.7323 0.1668 301.69)',
234
+ 'oklch(0.7555 0.1155 202.14)',
235
+ 'oklch(0.6951 0.1809 145.62)',
236
+ 'oklch(0.7196 0.1401 79.91)',
237
+ 'oklch(0.7345 0.1626 25.78)',
238
+ ],
239
+ provenance: { source: 'Adea', url: 'https://github.com/adea-ai/themes', license: 'Apache-2.0' },
240
+ },
241
+ }
242
+
243
+ /** The accents the default light/dark pair offers beside the presets. */
244
+ export const DEFAULT_THEME_ACCENTS: readonly AccentPreset[] = [
245
+ {
246
+ id: 'ansi-blue',
247
+ label: 'Blue',
248
+ description: "The theme's own blue colour.",
249
+ light: 'oklch(0.4973 0.1518 253.31)',
250
+ dark: 'oklch(0.7153 0.1518 253.31)',
251
+ },
252
+ {
253
+ id: 'ansi-magenta',
254
+ label: 'Magenta',
255
+ description: "The theme's own magenta colour.",
256
+ light: 'oklch(0.5143 0.1668 301.69)',
257
+ dark: 'oklch(0.7323 0.1668 301.69)',
258
+ },
259
+ {
260
+ id: 'ansi-cyan',
261
+ label: 'Cyan',
262
+ description: "The theme's own cyan colour.",
263
+ light: 'oklch(0.5375 0.1155 202.14)',
264
+ dark: 'oklch(0.7555 0.1155 202.14)',
265
+ },
266
+ {
267
+ id: 'ansi-green',
268
+ label: 'Green',
269
+ description: "The theme's own green colour.",
270
+ light: 'oklch(0.4771 0.1809 145.62)',
271
+ dark: 'oklch(0.6951 0.1809 145.62)',
272
+ },
273
+ ]
274
+
275
+ /** Each default's measured `--primary-subtle` expression. */
276
+ export const DEFAULT_PRIMARY_SUBTLE: Readonly<Record<string, string>> = {
277
+ 'adea-light': 'color-mix(in oklch, var(--primary) 10%, transparent)',
278
+ 'adea-dark': 'color-mix(in oklch, var(--primary) 16%, transparent)',
279
+ }
280
+
281
+ /** Each default's `--editor-*` ramp held to 4.5:1 on its canvas (`editorRoles: 'floor'`). */
282
+ export const DEFAULT_FLOOR_EDITOR: Readonly<Record<string, ThemeEditorPalette>> = {
283
+ 'adea-light': {
284
+ keyword: '#7a49b5',
285
+ string: '#00711f',
286
+ number: '#825c00',
287
+ comment: '#57606a',
288
+ function: '#0662b5',
289
+ variable: '#24292f',
290
+ type: '#007d85',
291
+ tag: '#b23533',
292
+ attribute: '#825c00',
293
+ operator: '#24292f',
294
+ heading: '#7a49b5',
295
+ link: '#0662b5',
296
+ diffAdd: '#00711f',
297
+ diffDelete: '#b23533',
298
+ diffHunk: '#007d85',
299
+ searchMatch: '#825c00',
300
+ },
301
+ 'adea-dark': {
302
+ keyword: '#bc8cff',
303
+ string: '#3fb950',
304
+ number: '#d29922',
305
+ comment: '#7d7b81',
306
+ function: '#58a6ff',
307
+ variable: '#bab8be',
308
+ type: '#39c5cf',
309
+ tag: '#ff7b72',
310
+ attribute: '#d29922',
311
+ operator: '#bab8be',
312
+ heading: '#bc8cff',
313
+ link: '#58a6ff',
314
+ diffAdd: '#3fb950',
315
+ diffDelete: '#ff7b72',
316
+ diffHunk: '#39c5cf',
317
+ searchMatch: '#d29922',
318
+ },
319
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * What a provider knows about the catalogue without loading it.
3
+ *
4
+ * The catalogue (`@adea-ai/themes`, 34 themes) is the heavy part of the theme
5
+ * system. Most hosts start on the default pair, paint a catalogue theme from a
6
+ * stylesheet, and open a picker rarely, so this module holds the few facts needed
7
+ * to start without it: the default ids, every catalogue id with its appearance (to
8
+ * recognise a stored preference), and the default pair as complete variants.
9
+ *
10
+ * It imports no catalogue code and no catalogue data. The facts themselves are in
11
+ * `theme-defaults.generated.ts`, copied from the catalogue by
12
+ * `scripts/build-theme-defaults.ts` and checked against it by
13
+ * `tests/theme-defaults.test.ts`.
14
+ */
15
+ import type { ThemeAppearance, ThemeVariant } from './themes'
16
+ import { DEFAULT_VARIANTS, THEME_INDEX } from './theme-defaults.generated'
17
+
18
+ export {
19
+ DEFAULT_FLOOR_EDITOR,
20
+ DEFAULT_PRIMARY_SUBTLE,
21
+ DEFAULT_THEME_ACCENTS,
22
+ DEFAULT_VARIANTS,
23
+ THEME_INDEX,
24
+ } from './theme-defaults.generated'
25
+
26
+ export const defaultLightThemeId = 'adea-light'
27
+ export const defaultDarkThemeId = 'adea-dark'
28
+
29
+ /** The appearance of a catalogue theme id, or `undefined` for an id the catalogue lacks. */
30
+ export function catalogueThemeAppearance(id: string): ThemeAppearance | undefined {
31
+ return THEME_INDEX.find(([candidate]) => candidate === id)?.[1]
32
+ }
33
+
34
+ /** Whether the catalogue holds a theme with this id (loaded or not). */
35
+ export function isCatalogueThemeId(id: string): boolean {
36
+ return catalogueThemeAppearance(id) !== undefined
37
+ }
38
+
39
+ /** Whether an id is one of the two default themes, whose data ships with the provider. */
40
+ export function isDefaultThemeId(id: string): id is keyof typeof DEFAULT_VARIANTS {
41
+ return id === defaultLightThemeId || id === defaultDarkThemeId
42
+ }
43
+
44
+ /** The default variant of an appearance. */
45
+ export function defaultVariantFor(appearance: ThemeAppearance): ThemeVariant {
46
+ return DEFAULT_VARIANTS[appearance === 'dark' ? defaultDarkThemeId : defaultLightThemeId]
47
+ }
48
+
49
+ /**
50
+ * The variant a stored id means, or the default of the same appearance.
51
+ *
52
+ * An id the registry does not hold — an imported theme that was deleted, a
53
+ * catalogue entry that was renamed — must still paint *something of the appearance
54
+ * being shown*. Falling back to whichever variant happens to be first in the
55
+ * registry painted a dark palette under a light `color-scheme` for a light id, so
56
+ * the fallback is the appearance's own default, then any variant of that
57
+ * appearance, then the registry's first entry only when it holds nothing else.
58
+ *
59
+ * `registry` is the builtin catalogue plus whatever extras the host supplies; the
60
+ * stored id is never rewritten, only resolved, so a host that keeps an unknown id
61
+ * keeps resolving it if the theme comes back.
62
+ *
63
+ * The fallback order is translated from Zeron's `ThemeRegistry::resolve` (MIT,
64
+ * Copyright (c) 2026 Wing); see NOTICE.
65
+ */
66
+ export function resolveVariant(
67
+ registry: readonly ThemeVariant[],
68
+ id: string,
69
+ appearance: ThemeAppearance
70
+ ): ThemeVariant {
71
+ const found = registry.find((variant) => variant.id === id)
72
+ if (found) return found
73
+ const defaultId = appearance === 'dark' ? defaultDarkThemeId : defaultLightThemeId
74
+ return (
75
+ registry.find((variant) => variant.id === defaultId) ??
76
+ registry.find((variant) => variant.appearance === appearance) ??
77
+ registry[0]!
78
+ )
79
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * The light theme engine: the catalogue questions answered from the data that ships
3
+ * with the provider, with no catalogue code or data (see `lib/theme-engine`).
4
+ */
5
+ import type { AccentPreset } from '@adea-ai/themes'
6
+ import { primarySubtleCss } from '@adea-ai/themes'
7
+ import {
8
+ accentOverrideVariables,
9
+ resolveAccentRoles,
10
+ type AccentRoles,
11
+ type AccentTarget,
12
+ } from './accent-roles'
13
+ import { isThemeAccentId } from './theme-accents'
14
+ import { themeCssVariablesWith } from './theme-css'
15
+ import {
16
+ DEFAULT_FLOOR_EDITOR,
17
+ DEFAULT_PRIMARY_SUBTLE,
18
+ DEFAULT_THEME_ACCENTS,
19
+ DEFAULT_VARIANTS,
20
+ defaultDarkThemeId,
21
+ defaultLightThemeId,
22
+ isCatalogueThemeId,
23
+ isDefaultThemeId,
24
+ } from './theme-defaults'
25
+ import { CatalogueRequired, needsData, pairIds, type ThemeEngine } from './theme-engine'
26
+ import type {
27
+ AccentVariableOptions,
28
+ EditorRolesMode,
29
+ ThemeAppearance,
30
+ ThemeVariant,
31
+ } from './themes'
32
+
33
+ const defaultVariantList: readonly ThemeVariant[] = [
34
+ DEFAULT_VARIANTS[defaultLightThemeId],
35
+ DEFAULT_VARIANTS[defaultDarkThemeId],
36
+ ]
37
+
38
+ function lightEditor(theme: ThemeVariant, mode: EditorRolesMode) {
39
+ if (mode !== 'floor' || DEFAULT_VARIANTS[theme.id as keyof typeof DEFAULT_VARIANTS] !== theme)
40
+ return theme.editor
41
+ return DEFAULT_FLOOR_EDITOR[theme.id] ?? theme.editor
42
+ }
43
+
44
+ function lightPrimarySubtle(theme: Pick<ThemeVariant, 'id' | 'appearance'>): string {
45
+ const measured = DEFAULT_PRIMARY_SUBTLE[theme.id]
46
+ if (measured) return measured
47
+ if (isCatalogueThemeId(theme.id)) throw new CatalogueRequired(`the tint of ${theme.id}`)
48
+ return primarySubtleCss(theme.appearance)
49
+ }
50
+
51
+ function lightThemeAccentsFor(lightThemeId: string, darkThemeId: string): readonly AccentPreset[] {
52
+ const [light, dark] = pairIds(lightThemeId, darkThemeId)
53
+ if (needsData(light) || needsData(dark))
54
+ throw new CatalogueRequired(`the accents of ${light}/${dark}`)
55
+ return DEFAULT_THEME_ACCENTS
56
+ }
57
+
58
+ export const lightThemeEngine: ThemeEngine = {
59
+ builtinThemes: defaultVariantList,
60
+ isCatalogueVariant: (variant) =>
61
+ isDefaultThemeId(variant.id) && DEFAULT_VARIANTS[variant.id] === variant,
62
+ themeCssVariables(variant, options = {}) {
63
+ if (needsData(variant.id)) throw new CatalogueRequired(`the roles of ${variant.id}`)
64
+ return themeCssVariablesWith(
65
+ { primarySubtle: lightPrimarySubtle, editor: lightEditor },
66
+ variant,
67
+ options
68
+ )
69
+ },
70
+ themeAccentsFor: lightThemeAccentsFor,
71
+ accentVariables(accentId, appearance, pair, options = {}) {
72
+ const roles = lightAccentRoles(accentId, appearance, pair, options)
73
+ return roles ? accentOverrideVariables(roles) : undefined
74
+ },
75
+ accentRolesForSelection(accentId, appearance, pair, options = {}) {
76
+ if (accentId === 'theme') return undefined
77
+ const variantId = options.variantId
78
+ if (variantId !== undefined && needsData(variantId))
79
+ throw new CatalogueRequired(`the accent roles over ${variantId}`)
80
+ const roles = lightAccentRoles(accentId, appearance, pair, options)
81
+ const measured = variantId === undefined ? undefined : DEFAULT_PRIMARY_SUBTLE[variantId]
82
+ if (!roles || measured === undefined) return roles
83
+ // The theme's own tint strength is shipped for the defaults, and is the right one
84
+ // whenever the accent was not repaired. A repaired accent's tint is measured against
85
+ // the repaired primary, which only the catalogue can do.
86
+ const ungated = lightAccentRoles(accentId, appearance, pair, {
87
+ ...options,
88
+ floor: Number.NEGATIVE_INFINITY,
89
+ })
90
+ if (ungated?.primary !== roles.primary)
91
+ throw new CatalogueRequired(`the tint of a repaired accent over ${variantId}`)
92
+ return { ...roles, primarySubtle: measured }
93
+ },
94
+ }
95
+
96
+ /**
97
+ * The accent's roles with the appearance standing in for the theme record. The four
98
+ * document properties depend on the appearance alone; `primarySubtle` reads the record,
99
+ * so callers that return it must correct it.
100
+ */
101
+ function lightAccentRoles(
102
+ accentId: string,
103
+ appearance: ThemeAppearance,
104
+ pair: { lightThemeId: string; darkThemeId: string },
105
+ options: AccentVariableOptions
106
+ ): AccentRoles | undefined {
107
+ if (accentId === 'theme') return undefined
108
+ const context: AccentTarget = {
109
+ target: appearance,
110
+ background: options.background,
111
+ floor: options.floor,
112
+ themeAccents: isThemeAccentId(accentId)
113
+ ? lightThemeAccentsFor(pair.lightThemeId, pair.darkThemeId)
114
+ : undefined,
115
+ }
116
+ return resolveAccentRoles(accentId, context)
117
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * The catalogue-dependent operations a provider performs, as one seam.
3
+ *
4
+ * `ThemeProvider` needs to ask a handful of questions that only the catalogue can
5
+ * answer in general: the built-in variants, a variant's custom properties, the roles
6
+ * an accent paints over it, the accents a theme pair offers. Two engines answer them.
7
+ *
8
+ * - {@link catalogueThemeEngine} (`lib/theme-catalogue`) is the full answer, backed by
9
+ * the whole catalogue. It is what `ThemeProvider` uses and what the lazy provider
10
+ * switches to once the catalogue has loaded.
11
+ * - {@link lightThemeEngine} (`lib/theme-engine-light`) answers from the data that ships with the
12
+ * provider (`theme-defaults`): the default light/dark pair, host variants that are
13
+ * not in the catalogue, and nothing else. It imports no catalogue data, which is
14
+ * the point: a host that keeps the default pair never pays for the other 32
15
+ * themes. A question outside that set throws {@link CatalogueRequired}; the lazy
16
+ * provider asks {@link needsCatalogue} first and loads the catalogue instead.
17
+ *
18
+ * `tests/theme-engine.test.ts` holds the two to the same answers wherever the light
19
+ * engine can answer.
20
+ */
21
+ import type { AccentPreset } from '@adea-ai/themes'
22
+ import type { AccentRoles } from './accent-roles'
23
+ import { isThemeAccentId } from './theme-accents'
24
+ import {
25
+ defaultDarkThemeId,
26
+ defaultLightThemeId,
27
+ isCatalogueThemeId,
28
+ isDefaultThemeId,
29
+ } from './theme-defaults'
30
+ import type {
31
+ AccentVariableOptions,
32
+ ThemeAppearance,
33
+ ThemeCssVariableOptions,
34
+ ThemeVariant,
35
+ } from './themes'
36
+
37
+ export type ThemeEngine = {
38
+ /** The built-in variants. A plain array, in catalogue order. */
39
+ readonly builtinThemes: readonly ThemeVariant[]
40
+ /** True for the catalogue's own variant, not a host's copy that merely shares its id. */
41
+ isCatalogueVariant(variant: ThemeVariant): boolean
42
+ /** The custom properties a variant sets. */
43
+ themeCssVariables(
44
+ variant: ThemeVariant,
45
+ options?: ThemeCssVariableOptions
46
+ ): Record<string, string>
47
+ /**
48
+ * The custom properties an accent selection overrides on the document (`--primary`, its
49
+ * foreground, hover and ring), or `undefined` when it overrides nothing.
50
+ */
51
+ accentVariables(
52
+ accentId: string,
53
+ appearance: ThemeAppearance,
54
+ pair: { lightThemeId: string; darkThemeId: string },
55
+ options?: AccentVariableOptions
56
+ ): Record<string, string> | undefined
57
+ /** An accent selection resolved to its full roles against a theme pair, or `undefined`. */
58
+ accentRolesForSelection(
59
+ accentId: string,
60
+ appearance: ThemeAppearance,
61
+ pair: { lightThemeId: string; darkThemeId: string },
62
+ options?: AccentVariableOptions
63
+ ): AccentRoles | undefined
64
+ /** The accents a light/dark pair offers beside the presets. */
65
+ themeAccentsFor(lightThemeId: string, darkThemeId: string): readonly AccentPreset[]
66
+ }
67
+
68
+ /** Thrown by the light engine for a question that needs the whole catalogue. */
69
+ export class CatalogueRequired extends Error {
70
+ constructor(what: string) {
71
+ super(`${what} needs the theme catalogue, which has not been loaded`)
72
+ this.name = 'CatalogueRequired'
73
+ }
74
+ }
75
+
76
+ /** The ids an id resolves to when the catalogue lacks it, as `getTheme ?? default` does. */
77
+ export function pairIds(lightThemeId: string, darkThemeId: string): [string, string] {
78
+ return [
79
+ isCatalogueThemeId(lightThemeId) ? lightThemeId : defaultLightThemeId,
80
+ isCatalogueThemeId(darkThemeId) ? darkThemeId : defaultDarkThemeId,
81
+ ]
82
+ }
83
+
84
+ /** A catalogue id other than the two defaults: its data is not in the light engine. */
85
+ export const needsData = (id: string) => isCatalogueThemeId(id) && !isDefaultThemeId(id)
86
+
87
+ /**
88
+ * Whether answering for this selection needs the catalogue.
89
+ *
90
+ * True when the variant being shown, the pinned terminal theme, or (for a
91
+ * theme-derived `ansi-*` accent) either theme of the pair is a catalogue theme other
92
+ * than the two defaults. Everything else — the default pair, a host's own variants,
93
+ * every preset and custom accent — the light engine answers from shipped data.
94
+ */
95
+ export function needsCatalogue(
96
+ selection: {
97
+ lightThemeId: string
98
+ darkThemeId: string
99
+ accent: string
100
+ terminalThemeId?: string
101
+ },
102
+ appearance: ThemeAppearance
103
+ ): boolean {
104
+ const shown = appearance === 'dark' ? selection.darkThemeId : selection.lightThemeId
105
+ if (needsData(shown)) return true
106
+ if (selection.terminalThemeId !== undefined && needsData(selection.terminalThemeId)) return true
107
+ return (
108
+ isThemeAccentId(selection.accent) &&
109
+ (needsData(selection.lightThemeId) || needsData(selection.darkThemeId))
110
+ )
111
+ }