@pie-players/pie-theme 0.3.64 → 0.3.66
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +165 -18
- package/dist/color-schemes.css +386 -441
- package/dist/color-schemes.d.ts +12 -21
- package/dist/color-schemes.js +507 -385
- package/dist/components.css +216 -66
- package/dist/contrast.d.ts +67 -0
- package/dist/contrast.js +151 -0
- package/dist/daisyui-mapping.d.ts +58 -0
- package/dist/daisyui-mapping.js +168 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/providers.d.ts +16 -0
- package/dist/providers.js +68 -91
- package/dist/scheme-participation.d.ts +88 -0
- package/dist/scheme-participation.js +89 -0
- package/dist/theme-css.d.ts +5 -0
- package/dist/theme-css.js +26 -0
- package/dist/theme-definitions.d.ts +21 -0
- package/dist/theme-definitions.js +1081 -0
- package/dist/theme-element.d.ts +5 -0
- package/dist/theme-element.js +154 -36
- package/dist/theme-types.d.ts +54 -0
- package/dist/token-registry-types.d.ts +57 -0
- package/dist/token-registry-types.js +15 -0
- package/dist/token-registry.json +1311 -0
- package/dist/tokens.css +84 -76
- package/package.json +8 -4
- package/dist/theme-defaults.d.ts +0 -3
- package/dist/theme-defaults.js +0 -100
package/dist/color-schemes.js
CHANGED
|
@@ -1,401 +1,523 @@
|
|
|
1
|
+
import { createBuiltInColorSchemeDescriptor, createPieColorSchemePreview, diagnoseThemeContrast, getBaseThemeVariables, getBuiltInColorSchemeDefinition, getDefaultColorSchemeDescriptor, getSchemeParticipation, listBuiltInColorSchemeDefinitions, } from "./theme-definitions.js";
|
|
1
2
|
import { normalizePieThemeVariables, } from "./theme-types.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
"--pie-border-dark": "#ffffff",
|
|
62
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
63
|
-
"--pie-annotation-underline": "#9c89ec",
|
|
64
|
-
"--pie-annotation-underline-dark": "#9c89ec",
|
|
65
|
-
"--pie-button-bg": "#000000",
|
|
66
|
-
"--pie-button-border": "#cccccc",
|
|
67
|
-
"--pie-button-color": "#ffffff",
|
|
68
|
-
"--pie-button-hover-bg": "#1a1a1a",
|
|
69
|
-
"--pie-button-hover-border": "#ffffff",
|
|
70
|
-
"--pie-button-hover-color": "#ffffff",
|
|
71
|
-
"--pie-button-active-bg": "#222222",
|
|
72
|
-
"--pie-button-focus-outline": "#ffff00",
|
|
73
|
-
"--pie-focus-checked": "#ffff00",
|
|
74
|
-
"--pie-focus-checked-border": "#ffff00",
|
|
75
|
-
},
|
|
76
|
-
preview: { bg: "#000000", text: "#ffffff", primary: "#ffff00" },
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: "rose-on-green",
|
|
80
|
-
name: "Rose on Green",
|
|
81
|
-
description: "Color blind friendly (protanopia/deuteranopia)",
|
|
82
|
-
variables: {
|
|
83
|
-
"--pie-background": "#ccffcc",
|
|
84
|
-
"--pie-background-dark": "#aaeedd",
|
|
85
|
-
"--pie-secondary-background": "#99ddbb",
|
|
86
|
-
"--pie-dropdown-background": "#88cc99",
|
|
87
|
-
"--pie-text": "#3d0022",
|
|
88
|
-
"--pie-white": "#ccffcc",
|
|
89
|
-
"--pie-black": "#3d0022",
|
|
90
|
-
"--pie-primary": "#660044",
|
|
91
|
-
"--pie-primary-light": "#cc6699",
|
|
92
|
-
"--pie-primary-dark": "#440033",
|
|
93
|
-
"--pie-border": "#3d0022",
|
|
94
|
-
"--pie-border-light": "#663344",
|
|
95
|
-
"--pie-border-dark": "#220011",
|
|
96
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
97
|
-
"--pie-annotation-underline": "#4221d5",
|
|
98
|
-
"--pie-annotation-underline-dark": "#4221d5",
|
|
99
|
-
"--pie-button-bg": "#ccffcc",
|
|
100
|
-
"--pie-button-border": "#663344",
|
|
101
|
-
"--pie-button-color": "#3d0022",
|
|
102
|
-
"--pie-button-hover-bg": "#aaeedd",
|
|
103
|
-
"--pie-button-hover-border": "#3d0022",
|
|
104
|
-
"--pie-button-hover-color": "#3d0022",
|
|
105
|
-
"--pie-button-active-bg": "#99ddbb",
|
|
106
|
-
"--pie-button-focus-outline": "#660044",
|
|
107
|
-
"--pie-focus-checked": "#880055",
|
|
108
|
-
"--pie-focus-checked-border": "#660044",
|
|
109
|
-
},
|
|
110
|
-
preview: { bg: "#ccffcc", text: "#3d0022", primary: "#660044" },
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
id: "yellow-on-blue",
|
|
114
|
-
name: "Yellow on Blue",
|
|
115
|
-
description: "Strong contrast scheme",
|
|
116
|
-
variables: {
|
|
117
|
-
"--pie-background": "#000066",
|
|
118
|
-
"--pie-background-dark": "#000055",
|
|
119
|
-
"--pie-secondary-background": "#000044",
|
|
120
|
-
"--pie-dropdown-background": "#000033",
|
|
121
|
-
"--pie-text": "#ffff00",
|
|
122
|
-
"--pie-white": "#000066",
|
|
123
|
-
"--pie-black": "#ffff00",
|
|
124
|
-
"--pie-primary": "#ffff66",
|
|
125
|
-
"--pie-primary-light": "#ffffaa",
|
|
126
|
-
"--pie-primary-dark": "#cccc00",
|
|
127
|
-
"--pie-border": "#ffff00",
|
|
128
|
-
"--pie-border-light": "#aaaa66",
|
|
129
|
-
"--pie-border-dark": "#cccc00",
|
|
130
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
131
|
-
"--pie-annotation-underline": "#9c89ec",
|
|
132
|
-
"--pie-annotation-underline-dark": "#9c89ec",
|
|
133
|
-
"--pie-button-bg": "#000066",
|
|
134
|
-
"--pie-button-border": "#aaaa66",
|
|
135
|
-
"--pie-button-color": "#ffff00",
|
|
136
|
-
"--pie-button-hover-bg": "#000055",
|
|
137
|
-
"--pie-button-hover-border": "#ffff00",
|
|
138
|
-
"--pie-button-hover-color": "#ffff00",
|
|
139
|
-
"--pie-button-active-bg": "#000044",
|
|
140
|
-
"--pie-button-focus-outline": "#ffff66",
|
|
141
|
-
"--pie-focus-checked": "#ffff00",
|
|
142
|
-
"--pie-focus-checked-border": "#cccc00",
|
|
143
|
-
},
|
|
144
|
-
preview: { bg: "#000066", text: "#ffff00", primary: "#ffff66" },
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
id: "black-on-rose",
|
|
148
|
-
name: "Black on Rose",
|
|
149
|
-
description: "Warm tinted background",
|
|
150
|
-
variables: {
|
|
151
|
-
"--pie-background": "#ffccdd",
|
|
152
|
-
"--pie-background-dark": "#ffb3cc",
|
|
153
|
-
"--pie-secondary-background": "#ff99bb",
|
|
154
|
-
"--pie-dropdown-background": "#ff88aa",
|
|
155
|
-
"--pie-text": "#000000",
|
|
156
|
-
"--pie-white": "#ffccdd",
|
|
157
|
-
"--pie-black": "#000000",
|
|
158
|
-
"--pie-primary": "#880044",
|
|
159
|
-
"--pie-primary-light": "#dd6699",
|
|
160
|
-
"--pie-primary-dark": "#550033",
|
|
161
|
-
"--pie-border": "#000000",
|
|
162
|
-
"--pie-border-light": "#555555",
|
|
163
|
-
"--pie-border-dark": "#000000",
|
|
164
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
165
|
-
"--pie-annotation-underline": "#4221d5",
|
|
166
|
-
"--pie-annotation-underline-dark": "#4221d5",
|
|
167
|
-
"--pie-button-bg": "#ffccdd",
|
|
168
|
-
"--pie-button-border": "#555555",
|
|
169
|
-
"--pie-button-color": "#000000",
|
|
170
|
-
"--pie-button-hover-bg": "#ffb3cc",
|
|
171
|
-
"--pie-button-hover-border": "#000000",
|
|
172
|
-
"--pie-button-hover-color": "#000000",
|
|
173
|
-
"--pie-button-active-bg": "#ff99bb",
|
|
174
|
-
"--pie-button-focus-outline": "#880044",
|
|
175
|
-
"--pie-focus-checked": "#880044",
|
|
176
|
-
"--pie-focus-checked-border": "#550033",
|
|
177
|
-
},
|
|
178
|
-
preview: { bg: "#ffccdd", text: "#000000", primary: "#880044" },
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
id: "light-gray-on-dark-gray",
|
|
182
|
-
name: "Light Gray on Dark Gray",
|
|
183
|
-
description: "Reduced brightness for light sensitivity",
|
|
184
|
-
variables: {
|
|
185
|
-
"--pie-background": "#333333",
|
|
186
|
-
"--pie-background-dark": "#2a2a2a",
|
|
187
|
-
"--pie-secondary-background": "#222222",
|
|
188
|
-
"--pie-dropdown-background": "#1a1a1a",
|
|
189
|
-
"--pie-text": "#e0e0e0",
|
|
190
|
-
"--pie-white": "#333333",
|
|
191
|
-
"--pie-black": "#e0e0e0",
|
|
192
|
-
"--pie-primary": "#aaaaaa",
|
|
193
|
-
"--pie-primary-light": "#cccccc",
|
|
194
|
-
"--pie-primary-dark": "#888888",
|
|
195
|
-
"--pie-border": "#e0e0e0",
|
|
196
|
-
"--pie-border-light": "#cccccc",
|
|
197
|
-
"--pie-border-dark": "#ffffff",
|
|
198
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
199
|
-
"--pie-annotation-underline": "#9c89ec",
|
|
200
|
-
"--pie-annotation-underline-dark": "#9c89ec",
|
|
201
|
-
"--pie-button-bg": "#333333",
|
|
202
|
-
"--pie-button-border": "#cccccc",
|
|
203
|
-
"--pie-button-color": "#e0e0e0",
|
|
204
|
-
"--pie-button-hover-bg": "#2a2a2a",
|
|
205
|
-
"--pie-button-hover-border": "#ffffff",
|
|
206
|
-
"--pie-button-hover-color": "#e0e0e0",
|
|
207
|
-
"--pie-button-active-bg": "#222222",
|
|
208
|
-
"--pie-button-focus-outline": "#aaaaaa",
|
|
209
|
-
"--pie-focus-checked": "#cccccc",
|
|
210
|
-
"--pie-focus-checked-border": "#aaaaaa",
|
|
211
|
-
},
|
|
212
|
-
preview: { bg: "#333333", text: "#e0e0e0", primary: "#aaaaaa" },
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
id: "grey-on-light-grey",
|
|
216
|
-
name: "Grey on Light Grey",
|
|
217
|
-
description: "Low-glare neutral palette",
|
|
218
|
-
variables: {
|
|
219
|
-
"--pie-background": "#ebebeb",
|
|
220
|
-
"--pie-background-dark": "#dcdcdc",
|
|
221
|
-
"--pie-secondary-background": "#d0d0d0",
|
|
222
|
-
"--pie-dropdown-background": "#c4c4c4",
|
|
223
|
-
"--pie-text": "#4a4a4a",
|
|
224
|
-
"--pie-white": "#ebebeb",
|
|
225
|
-
"--pie-black": "#4a4a4a",
|
|
226
|
-
"--pie-primary": "#3d3d3d",
|
|
227
|
-
"--pie-primary-light": "#6f6f6f",
|
|
228
|
-
"--pie-primary-dark": "#2b2b2b",
|
|
229
|
-
"--pie-border": "#4a4a4a",
|
|
230
|
-
"--pie-border-light": "#7a7a7a",
|
|
231
|
-
"--pie-border-dark": "#2b2b2b",
|
|
232
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
233
|
-
"--pie-annotation-underline": "#4221d5",
|
|
234
|
-
"--pie-annotation-underline-dark": "#4221d5",
|
|
235
|
-
"--pie-button-bg": "#ebebeb",
|
|
236
|
-
"--pie-button-border": "#7a7a7a",
|
|
237
|
-
"--pie-button-color": "#4a4a4a",
|
|
238
|
-
"--pie-button-hover-bg": "#dcdcdc",
|
|
239
|
-
"--pie-button-hover-border": "#4a4a4a",
|
|
240
|
-
"--pie-button-hover-color": "#4a4a4a",
|
|
241
|
-
"--pie-button-active-bg": "#d0d0d0",
|
|
242
|
-
"--pie-button-focus-outline": "#3d3d3d",
|
|
243
|
-
"--pie-focus-checked": "#6f6f6f",
|
|
244
|
-
"--pie-focus-checked-border": "#3d3d3d",
|
|
245
|
-
},
|
|
246
|
-
preview: { bg: "#ebebeb", text: "#4a4a4a", primary: "#3d3d3d" },
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
id: "purple-on-light-green",
|
|
250
|
-
name: "Purple on Light Green",
|
|
251
|
-
description: "Color blind friendly, low-glare background",
|
|
252
|
-
variables: {
|
|
253
|
-
"--pie-background": "#cce8d4",
|
|
254
|
-
"--pie-background-dark": "#b8dcc3",
|
|
255
|
-
"--pie-secondary-background": "#a6d0b2",
|
|
256
|
-
"--pie-dropdown-background": "#94c4a1",
|
|
257
|
-
"--pie-text": "#8e2464",
|
|
258
|
-
"--pie-white": "#cce8d4",
|
|
259
|
-
"--pie-black": "#8e2464",
|
|
260
|
-
"--pie-primary": "#6d1a4c",
|
|
261
|
-
"--pie-primary-light": "#b3608e",
|
|
262
|
-
"--pie-primary-dark": "#4f1237",
|
|
263
|
-
"--pie-border": "#8e2464",
|
|
264
|
-
"--pie-border-light": "#a85a86",
|
|
265
|
-
"--pie-border-dark": "#4f1237",
|
|
266
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
267
|
-
"--pie-annotation-underline": "#4221d5",
|
|
268
|
-
"--pie-annotation-underline-dark": "#4221d5",
|
|
269
|
-
"--pie-button-bg": "#cce8d4",
|
|
270
|
-
"--pie-button-border": "#a85a86",
|
|
271
|
-
"--pie-button-color": "#8e2464",
|
|
272
|
-
"--pie-button-hover-bg": "#b8dcc3",
|
|
273
|
-
"--pie-button-hover-border": "#8e2464",
|
|
274
|
-
"--pie-button-hover-color": "#8e2464",
|
|
275
|
-
"--pie-button-active-bg": "#a6d0b2",
|
|
276
|
-
"--pie-button-focus-outline": "#6d1a4c",
|
|
277
|
-
"--pie-focus-checked": "#8e2464",
|
|
278
|
-
"--pie-focus-checked-border": "#6d1a4c",
|
|
279
|
-
},
|
|
280
|
-
preview: { bg: "#cce8d4", text: "#8e2464", primary: "#6d1a4c" },
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
id: "black-on-violet",
|
|
284
|
-
name: "Black on Violet",
|
|
285
|
-
description: "Cool tinted background",
|
|
286
|
-
variables: {
|
|
287
|
-
"--pie-background": "#d4a9de",
|
|
288
|
-
"--pie-background-dark": "#c795d3",
|
|
289
|
-
"--pie-secondary-background": "#b982c8",
|
|
290
|
-
"--pie-dropdown-background": "#ac70bd",
|
|
291
|
-
"--pie-text": "#000000",
|
|
292
|
-
"--pie-white": "#d4a9de",
|
|
293
|
-
"--pie-black": "#000000",
|
|
294
|
-
"--pie-primary": "#4a1259",
|
|
295
|
-
"--pie-primary-light": "#8e4fa1",
|
|
296
|
-
"--pie-primary-dark": "#330d3f",
|
|
297
|
-
"--pie-border": "#000000",
|
|
298
|
-
"--pie-border-light": "#4a4a4a",
|
|
299
|
-
"--pie-border-dark": "#000000",
|
|
300
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
301
|
-
"--pie-annotation-underline": "#4221d5",
|
|
302
|
-
"--pie-annotation-underline-dark": "#4221d5",
|
|
303
|
-
"--pie-button-bg": "#d4a9de",
|
|
304
|
-
"--pie-button-border": "#4a4a4a",
|
|
305
|
-
"--pie-button-color": "#000000",
|
|
306
|
-
"--pie-button-hover-bg": "#c795d3",
|
|
307
|
-
"--pie-button-hover-border": "#000000",
|
|
308
|
-
"--pie-button-hover-color": "#000000",
|
|
309
|
-
"--pie-button-active-bg": "#b982c8",
|
|
310
|
-
"--pie-button-focus-outline": "#4a1259",
|
|
311
|
-
"--pie-focus-checked": "#4a1259",
|
|
312
|
-
"--pie-focus-checked-border": "#330d3f",
|
|
313
|
-
},
|
|
314
|
-
preview: { bg: "#d4a9de", text: "#000000", primary: "#4a1259" },
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
id: "yellow-on-navy",
|
|
318
|
-
name: "Yellow on Navy",
|
|
319
|
-
description: "Strong contrast on a softened dark blue",
|
|
320
|
-
variables: {
|
|
321
|
-
"--pie-background": "#33508a",
|
|
322
|
-
"--pie-background-dark": "#2b4576",
|
|
323
|
-
"--pie-secondary-background": "#243a63",
|
|
324
|
-
"--pie-dropdown-background": "#1d2f50",
|
|
325
|
-
"--pie-text": "#ffff55",
|
|
326
|
-
"--pie-white": "#33508a",
|
|
327
|
-
"--pie-black": "#ffff55",
|
|
328
|
-
"--pie-primary": "#ffff99",
|
|
329
|
-
"--pie-primary-light": "#ffffc2",
|
|
330
|
-
"--pie-primary-dark": "#e0e04a",
|
|
331
|
-
"--pie-border": "#ffff55",
|
|
332
|
-
"--pie-border-light": "#c2c266",
|
|
333
|
-
"--pie-border-dark": "#e0e04a",
|
|
334
|
-
"--pie-tool-annotation-toolbar-border": "var(--pie-border)",
|
|
335
|
-
"--pie-annotation-underline": "var(--pie-primary)",
|
|
336
|
-
"--pie-annotation-underline-dark": "var(--pie-primary)",
|
|
337
|
-
"--pie-button-bg": "#33508a",
|
|
338
|
-
"--pie-button-border": "#c2c266",
|
|
339
|
-
"--pie-button-color": "#ffff55",
|
|
340
|
-
"--pie-button-hover-bg": "#2b4576",
|
|
341
|
-
"--pie-button-hover-border": "#ffff55",
|
|
342
|
-
"--pie-button-hover-color": "#ffff55",
|
|
343
|
-
"--pie-button-active-bg": "#243a63",
|
|
344
|
-
"--pie-button-focus-outline": "#ffff99",
|
|
345
|
-
"--pie-focus-checked": "#ffff55",
|
|
346
|
-
"--pie-focus-checked-border": "#e0e04a",
|
|
347
|
-
},
|
|
348
|
-
preview: { bg: "#33508a", text: "#ffff55", primary: "#ffff99" },
|
|
349
|
-
},
|
|
350
|
-
];
|
|
351
|
-
const builtInSchemeMap = new Map(BUILTIN_PIE_COLOR_SCHEMES.map((scheme) => [scheme.id, scheme]));
|
|
352
|
-
const customSchemeMap = new Map();
|
|
353
|
-
function normalizeScheme(scheme) {
|
|
354
|
-
const id = scheme.id?.trim();
|
|
355
|
-
if (!id) {
|
|
356
|
-
return null;
|
|
3
|
+
const customSchemes = new Map();
|
|
4
|
+
const observers = new Set();
|
|
5
|
+
const notificationQueue = [];
|
|
6
|
+
const warnedDiagnostics = new Set();
|
|
7
|
+
const BUILT_IN_IDS = new Set(listBuiltInColorSchemeDefinitions().map((scheme) => scheme.id));
|
|
8
|
+
let generation = 0;
|
|
9
|
+
let nextRegistrationKey = 1;
|
|
10
|
+
let notifying = false;
|
|
11
|
+
const OPAQUE_NAMED_COLORS = new Set(`aliceblue antiquewhite aqua aquamarine azure beige bisque black
|
|
12
|
+
blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse
|
|
13
|
+
chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan
|
|
14
|
+
darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta
|
|
15
|
+
darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen
|
|
16
|
+
darkslateblue darkslategray darkslategrey darkturquoise darkviolet
|
|
17
|
+
deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite
|
|
18
|
+
forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green
|
|
19
|
+
greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender
|
|
20
|
+
lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan
|
|
21
|
+
lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon
|
|
22
|
+
lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue
|
|
23
|
+
lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue
|
|
24
|
+
mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen
|
|
25
|
+
mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin
|
|
26
|
+
navajowhite navy oldlace olive olivedrab orange orangered orchid
|
|
27
|
+
palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff
|
|
28
|
+
peru pink plum powderblue purple rebeccapurple red rosybrown royalblue
|
|
29
|
+
saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue
|
|
30
|
+
slateblue slategray slategrey snow springgreen steelblue tan teal thistle
|
|
31
|
+
tomato turquoise violet wheat white whitesmoke yellow yellowgreen`.split(/\s+/));
|
|
32
|
+
const CSS_NUMBER_SOURCE = String.raw `[+-]?(?:\d+|\d*\.\d+)(?:e[+-]?\d+)?`;
|
|
33
|
+
const CSS_NUMBER = new RegExp(`^${CSS_NUMBER_SOURCE}$`, "i");
|
|
34
|
+
const CSS_PERCENTAGE = new RegExp(`^${CSS_NUMBER_SOURCE}%$`, "i");
|
|
35
|
+
const CSS_NUMBER_OR_PERCENTAGE = new RegExp(`^${CSS_NUMBER_SOURCE}%?$`, "i");
|
|
36
|
+
const CSS_ANGLE = new RegExp(`^${CSS_NUMBER_SOURCE}(?:deg|grad|rad|turn)?$`, "i");
|
|
37
|
+
const CSS_WHITESPACE = /[ \t\n\f\r]+/;
|
|
38
|
+
const CSS_COLOR_SPACES = new Set([
|
|
39
|
+
"srgb",
|
|
40
|
+
"srgb-linear",
|
|
41
|
+
"display-p3",
|
|
42
|
+
"a98-rgb",
|
|
43
|
+
"prophoto-rgb",
|
|
44
|
+
"rec2020",
|
|
45
|
+
"xyz",
|
|
46
|
+
"xyz-d50",
|
|
47
|
+
"xyz-d65",
|
|
48
|
+
]);
|
|
49
|
+
function freezeVariables(variables) {
|
|
50
|
+
return Object.freeze({ ...variables });
|
|
51
|
+
}
|
|
52
|
+
function freezeDiagnostics(diagnostics) {
|
|
53
|
+
return Object.freeze(diagnostics.map((diagnostic) => Object.freeze({ ...diagnostic })));
|
|
54
|
+
}
|
|
55
|
+
function trimCssWhitespace(value) {
|
|
56
|
+
return value.replace(/^[ \t\n\f\r]+|[ \t\n\f\r]+$/g, "");
|
|
57
|
+
}
|
|
58
|
+
function isAscii(value) {
|
|
59
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
60
|
+
if (value.charCodeAt(index) > 0x7f)
|
|
61
|
+
return false;
|
|
357
62
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
function hasComponents(body, predicates, allowCommas = false) {
|
|
66
|
+
if (body.includes("/"))
|
|
67
|
+
return false;
|
|
68
|
+
const hasCommas = body.includes(",");
|
|
69
|
+
if (hasCommas && !allowCommas)
|
|
70
|
+
return false;
|
|
71
|
+
const components = (hasCommas ? body.split(",") : trimCssWhitespace(body).split(CSS_WHITESPACE)).map(trimCssWhitespace);
|
|
72
|
+
return (components.length === predicates.length &&
|
|
73
|
+
components.every((component, index) => component.length > 0 && predicates[index]?.test(component)));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A Scheme Preview is portable catalog data, so retain only deterministic,
|
|
77
|
+
* opaque color forms that can be checked identically without a DOM. Unsupported
|
|
78
|
+
* syntax affects the preview swatch only; the authored theme variable is kept.
|
|
79
|
+
*/
|
|
80
|
+
function isStablePreviewColor(value) {
|
|
81
|
+
// This deliberately supported preview subset is ASCII. Rejecting other code
|
|
82
|
+
// points also prevents JavaScript's broader whitespace and Unicode case folding
|
|
83
|
+
// from accepting strings that CSS tokenization rejects.
|
|
84
|
+
if (!value || !isAscii(value))
|
|
85
|
+
return false;
|
|
86
|
+
const normalized = trimCssWhitespace(value).toLowerCase();
|
|
87
|
+
if (!normalized)
|
|
88
|
+
return false;
|
|
89
|
+
if (/^#[\da-f]{3}$/i.test(normalized) || /^#[\da-f]{6}$/i.test(normalized)) {
|
|
90
|
+
return true;
|
|
362
91
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
92
|
+
if (OPAQUE_NAMED_COLORS.has(normalized))
|
|
93
|
+
return true;
|
|
94
|
+
// A flat body deliberately rules out relative colors, color-mix(), calc(),
|
|
95
|
+
// var(), and any other nested or host-dependent expression.
|
|
96
|
+
const functionMatch = /^([a-z-]+)\(([^()]*)\)$/.exec(normalized);
|
|
97
|
+
if (!functionMatch)
|
|
98
|
+
return false;
|
|
99
|
+
const [, functionName, body] = functionMatch;
|
|
100
|
+
if (!functionName || body === undefined)
|
|
101
|
+
return false;
|
|
102
|
+
switch (functionName) {
|
|
103
|
+
case "rgb": {
|
|
104
|
+
if (body.includes(",")) {
|
|
105
|
+
return (hasComponents(body, [CSS_NUMBER, CSS_NUMBER, CSS_NUMBER], true) ||
|
|
106
|
+
hasComponents(body, [CSS_PERCENTAGE, CSS_PERCENTAGE, CSS_PERCENTAGE], true));
|
|
107
|
+
}
|
|
108
|
+
return hasComponents(body, [
|
|
109
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
110
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
111
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
112
|
+
]);
|
|
113
|
+
}
|
|
114
|
+
case "hsl":
|
|
115
|
+
case "hwb":
|
|
116
|
+
return hasComponents(body, [CSS_ANGLE, CSS_PERCENTAGE, CSS_PERCENTAGE], functionName === "hsl");
|
|
117
|
+
case "lab":
|
|
118
|
+
case "oklab":
|
|
119
|
+
return hasComponents(body, [
|
|
120
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
121
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
122
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
123
|
+
]);
|
|
124
|
+
case "lch":
|
|
125
|
+
case "oklch":
|
|
126
|
+
return hasComponents(body, [
|
|
127
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
128
|
+
CSS_NUMBER_OR_PERCENTAGE,
|
|
129
|
+
CSS_ANGLE,
|
|
130
|
+
]);
|
|
131
|
+
case "color": {
|
|
132
|
+
if (body.includes(",") || body.includes("/"))
|
|
133
|
+
return false;
|
|
134
|
+
const [space, ...components] = trimCssWhitespace(body).split(CSS_WHITESPACE);
|
|
135
|
+
return Boolean(space &&
|
|
136
|
+
CSS_COLOR_SPACES.has(space) &&
|
|
137
|
+
components.length === 3 &&
|
|
138
|
+
components.every((component) => CSS_NUMBER_OR_PERCENTAGE.test(component)));
|
|
139
|
+
}
|
|
140
|
+
default:
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function createCustomDescriptor(scheme) {
|
|
145
|
+
const previewVariables = {
|
|
146
|
+
...getBaseThemeVariables("light"),
|
|
147
|
+
...scheme.variables,
|
|
369
148
|
};
|
|
149
|
+
const previewBackground = previewVariables["--pie-background"];
|
|
150
|
+
if (!isStablePreviewColor(previewBackground)) {
|
|
151
|
+
previewVariables["--pie-background"] = "#ffffff";
|
|
152
|
+
}
|
|
153
|
+
for (const token of ["--pie-text", "--pie-primary"]) {
|
|
154
|
+
if (!isStablePreviewColor(previewVariables[token])) {
|
|
155
|
+
previewVariables[token] = getBaseThemeVariables("light")[token];
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return Object.freeze({
|
|
159
|
+
id: scheme.id,
|
|
160
|
+
name: scheme.name,
|
|
161
|
+
description: scheme.description,
|
|
162
|
+
kind: "custom",
|
|
163
|
+
preview: createPieColorSchemePreview(previewVariables),
|
|
164
|
+
});
|
|
370
165
|
}
|
|
371
|
-
|
|
372
|
-
return
|
|
166
|
+
function createSnapshot() {
|
|
167
|
+
return Object.freeze({
|
|
168
|
+
generation,
|
|
169
|
+
schemes: Object.freeze([
|
|
170
|
+
getDefaultColorSchemeDescriptor(),
|
|
171
|
+
...listBuiltInColorSchemeDefinitions().map(createBuiltInColorSchemeDescriptor),
|
|
172
|
+
...Array.from(customSchemes.values(), createCustomDescriptor),
|
|
173
|
+
]),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
let currentSnapshot = createSnapshot();
|
|
177
|
+
function warnDiagnostic(diagnostic) {
|
|
178
|
+
const key = [
|
|
179
|
+
diagnostic.code,
|
|
180
|
+
diagnostic.schemeId ?? "",
|
|
181
|
+
diagnostic.token ?? "",
|
|
182
|
+
diagnostic.message,
|
|
183
|
+
].join("|");
|
|
184
|
+
if (warnedDiagnostics.has(key))
|
|
185
|
+
return;
|
|
186
|
+
warnedDiagnostics.add(key);
|
|
187
|
+
console.warn(`[pie-theme] ${diagnostic.message}`);
|
|
373
188
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
189
|
+
function notifyObservers(snapshot) {
|
|
190
|
+
notificationQueue.push(snapshot);
|
|
191
|
+
if (notifying)
|
|
192
|
+
return;
|
|
193
|
+
notifying = true;
|
|
194
|
+
try {
|
|
195
|
+
while (notificationQueue.length > 0) {
|
|
196
|
+
const next = notificationQueue.shift();
|
|
197
|
+
if (!next)
|
|
198
|
+
continue;
|
|
199
|
+
for (const listener of [...observers]) {
|
|
200
|
+
try {
|
|
201
|
+
listener(next);
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
warnDiagnostic({
|
|
205
|
+
code: "observer-error",
|
|
206
|
+
severity: "warning",
|
|
207
|
+
message: "A color-scheme observer threw while receiving an update.",
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
finally {
|
|
214
|
+
notifying = false;
|
|
377
215
|
}
|
|
378
|
-
return customSchemeMap.get(schemeId) ?? builtInSchemeMap.get(schemeId);
|
|
379
216
|
}
|
|
380
|
-
|
|
381
|
-
|
|
217
|
+
function publishSnapshot() {
|
|
218
|
+
generation += 1;
|
|
219
|
+
currentSnapshot = createSnapshot();
|
|
220
|
+
notifyObservers(currentSnapshot);
|
|
221
|
+
}
|
|
222
|
+
function diagnostic(value, diagnostics) {
|
|
223
|
+
diagnostics.push(value);
|
|
224
|
+
warnDiagnostic(value);
|
|
225
|
+
}
|
|
226
|
+
function normalizeRequestedScheme(value) {
|
|
227
|
+
const normalized = value?.trim();
|
|
228
|
+
return normalized && normalized !== "default" ? normalized : "default";
|
|
382
229
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
230
|
+
function normalizeExplicitVariables(value) {
|
|
231
|
+
if (!value || typeof value !== "object")
|
|
232
|
+
return {};
|
|
233
|
+
const normalized = {};
|
|
234
|
+
for (const [token, rawValue] of Object.entries(value)) {
|
|
235
|
+
if (!token.startsWith("--"))
|
|
388
236
|
continue;
|
|
237
|
+
if (typeof rawValue === "string" && rawValue.trim()) {
|
|
238
|
+
normalized[token] = rawValue.trim();
|
|
389
239
|
}
|
|
390
|
-
if (
|
|
391
|
-
|
|
240
|
+
else if (typeof rawValue === "number" && Number.isFinite(rawValue)) {
|
|
241
|
+
normalized[token] = String(rawValue);
|
|
392
242
|
}
|
|
393
|
-
customSchemeMap.set(scheme.id, scheme);
|
|
394
243
|
}
|
|
244
|
+
return normalized;
|
|
395
245
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
246
|
+
function validateRegistration(entry, index) {
|
|
247
|
+
const diagnostics = [];
|
|
248
|
+
if (!entry || typeof entry !== "object") {
|
|
249
|
+
return {
|
|
250
|
+
diagnostics: [
|
|
251
|
+
{
|
|
252
|
+
code: "invalid-registration",
|
|
253
|
+
severity: "error",
|
|
254
|
+
message: `Color-scheme entry ${index} must be an object.`,
|
|
255
|
+
index,
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const id = typeof entry.id === "string" ? entry.id.trim() : "";
|
|
261
|
+
if (!id || /[\s"'<>]/.test(id)) {
|
|
262
|
+
diagnostics.push({
|
|
263
|
+
code: "invalid-scheme-id",
|
|
264
|
+
severity: "error",
|
|
265
|
+
message: `Color-scheme entry ${index} has an invalid id.`,
|
|
266
|
+
index,
|
|
267
|
+
schemeId: id || undefined,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
if (id === "default" || BUILT_IN_IDS.has(id)) {
|
|
271
|
+
diagnostics.push({
|
|
272
|
+
code: "reserved-scheme-id",
|
|
273
|
+
severity: "error",
|
|
274
|
+
message: `Color-scheme id "${id}" is reserved by PIE.`,
|
|
275
|
+
index,
|
|
276
|
+
schemeId: id,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
const variables = {};
|
|
280
|
+
if (!entry.variables ||
|
|
281
|
+
typeof entry.variables !== "object" ||
|
|
282
|
+
Array.isArray(entry.variables)) {
|
|
283
|
+
diagnostics.push({
|
|
284
|
+
code: "empty-scheme",
|
|
285
|
+
severity: "error",
|
|
286
|
+
message: `Color scheme "${id || index}" must define a token overlay.`,
|
|
287
|
+
index,
|
|
288
|
+
schemeId: id || undefined,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
for (const [token, rawValue] of Object.entries(entry.variables)) {
|
|
293
|
+
const participation = getSchemeParticipation(token);
|
|
294
|
+
if (!participation) {
|
|
295
|
+
diagnostics.push({
|
|
296
|
+
code: "invalid-token-name",
|
|
297
|
+
severity: "error",
|
|
298
|
+
message: `Color scheme "${id || index}" uses unknown token "${token}".`,
|
|
299
|
+
index,
|
|
300
|
+
schemeId: id || undefined,
|
|
301
|
+
token,
|
|
302
|
+
});
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (participation === "excluded") {
|
|
306
|
+
diagnostics.push({
|
|
307
|
+
code: "excluded-token",
|
|
308
|
+
severity: "error",
|
|
309
|
+
message: `Color scheme "${id || index}" cannot set excluded token "${token}".`,
|
|
310
|
+
index,
|
|
311
|
+
schemeId: id || undefined,
|
|
312
|
+
token,
|
|
313
|
+
});
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
if (typeof rawValue === "string" && rawValue.trim()) {
|
|
317
|
+
variables[token] = rawValue.trim();
|
|
318
|
+
}
|
|
319
|
+
else if (typeof rawValue === "number" && Number.isFinite(rawValue)) {
|
|
320
|
+
variables[token] = String(rawValue);
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
diagnostics.push({
|
|
324
|
+
code: "invalid-token-value",
|
|
325
|
+
severity: "error",
|
|
326
|
+
message: `Color scheme "${id || index}" has an invalid value for "${token}".`,
|
|
327
|
+
index,
|
|
328
|
+
schemeId: id || undefined,
|
|
329
|
+
token,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (Object.keys(variables).length === 0) {
|
|
335
|
+
diagnostics.push({
|
|
336
|
+
code: "empty-scheme",
|
|
337
|
+
severity: "error",
|
|
338
|
+
message: `Color scheme "${id || index}" must define at least one participating token.`,
|
|
339
|
+
index,
|
|
340
|
+
schemeId: id || undefined,
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
if (diagnostics.some((item) => item.severity === "error")) {
|
|
344
|
+
return { diagnostics };
|
|
345
|
+
}
|
|
346
|
+
const existing = customSchemes.get(id);
|
|
347
|
+
if (existing) {
|
|
348
|
+
diagnostics.push({
|
|
349
|
+
code: "custom-scheme-replaced",
|
|
350
|
+
severity: "warning",
|
|
351
|
+
message: `Color scheme "${id}" replaced its previous custom registration.`,
|
|
352
|
+
index,
|
|
353
|
+
schemeId: id,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return {
|
|
357
|
+
diagnostics,
|
|
358
|
+
record: Object.freeze({
|
|
359
|
+
key: nextRegistrationKey++,
|
|
360
|
+
id,
|
|
361
|
+
name: typeof entry.name === "string" && entry.name.trim()
|
|
362
|
+
? entry.name.trim()
|
|
363
|
+
: id,
|
|
364
|
+
description: typeof entry.description === "string"
|
|
365
|
+
? entry.description.trim() || undefined
|
|
366
|
+
: undefined,
|
|
367
|
+
variables: freezeVariables(variables),
|
|
368
|
+
}),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
/** Returns the current deeply immutable catalog snapshot. */
|
|
372
|
+
export function listPieColorSchemes() {
|
|
373
|
+
return currentSnapshot;
|
|
374
|
+
}
|
|
375
|
+
/** Delivers the current snapshot immediately, then once per registry mutation. */
|
|
376
|
+
export function observePieColorSchemes(listener) {
|
|
377
|
+
observers.add(listener);
|
|
378
|
+
try {
|
|
379
|
+
listener(currentSnapshot);
|
|
399
380
|
}
|
|
400
|
-
|
|
381
|
+
catch {
|
|
382
|
+
warnDiagnostic({
|
|
383
|
+
code: "observer-error",
|
|
384
|
+
severity: "warning",
|
|
385
|
+
message: "A color-scheme observer threw while receiving an update.",
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
let active = true;
|
|
389
|
+
return () => {
|
|
390
|
+
if (!active)
|
|
391
|
+
return;
|
|
392
|
+
active = false;
|
|
393
|
+
observers.delete(listener);
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
/** Resolves Base Theme → Theme Provider → Scheme → Explicit Theme Override. */
|
|
397
|
+
export function resolvePieTheme(input = {}) {
|
|
398
|
+
const baseTheme = input.baseTheme === "dark" ? "dark" : "light";
|
|
399
|
+
const requestedScheme = normalizeRequestedScheme(input.requestedScheme);
|
|
400
|
+
const providerVariables = normalizePieThemeVariables(input.providerVariables);
|
|
401
|
+
const explicitVariables = normalizeExplicitVariables(input.variables);
|
|
402
|
+
const variables = {
|
|
403
|
+
...getBaseThemeVariables(baseTheme),
|
|
404
|
+
...providerVariables,
|
|
405
|
+
};
|
|
406
|
+
// Provider adapters own validation/correction of their own palette. Resolver
|
|
407
|
+
// diagnostics cover managed schemes and explicit per-instance changes.
|
|
408
|
+
const contrastRelevantTokens = new Set();
|
|
409
|
+
let resolvedScheme = null;
|
|
410
|
+
let status = "default";
|
|
411
|
+
const diagnostics = [];
|
|
412
|
+
if (requestedScheme !== "default") {
|
|
413
|
+
const builtIn = getBuiltInColorSchemeDefinition(requestedScheme);
|
|
414
|
+
const custom = customSchemes.get(requestedScheme);
|
|
415
|
+
if (builtIn) {
|
|
416
|
+
// Built-ins completely replace the required accessibility palette.
|
|
417
|
+
// Optional component hooks remain provider-controlled when the built-in
|
|
418
|
+
// deliberately does not define them, matching the CSS adapter cascade.
|
|
419
|
+
Object.assign(variables, builtIn.variables);
|
|
420
|
+
for (const token of Object.keys(builtIn.variables)) {
|
|
421
|
+
contrastRelevantTokens.add(token);
|
|
422
|
+
}
|
|
423
|
+
resolvedScheme = createBuiltInColorSchemeDescriptor(builtIn);
|
|
424
|
+
status = "built-in";
|
|
425
|
+
}
|
|
426
|
+
else if (custom) {
|
|
427
|
+
// A custom scheme is a palette a host chose for a learner, so fixed
|
|
428
|
+
// component hues collapse into it the way they do for a built-in. The
|
|
429
|
+
// overlay is applied after, so a scheme that wants a hue encoding kept
|
|
430
|
+
// declares `--pie-fixed-hue-collapse: 0%` itself.
|
|
431
|
+
variables["--pie-fixed-hue-collapse"] = "100%";
|
|
432
|
+
Object.assign(variables, custom.variables);
|
|
433
|
+
for (const token of Object.keys(custom.variables)) {
|
|
434
|
+
contrastRelevantTokens.add(token);
|
|
435
|
+
}
|
|
436
|
+
resolvedScheme = createCustomDescriptor(custom);
|
|
437
|
+
status = "custom";
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
status = "unavailable";
|
|
441
|
+
diagnostics.push({
|
|
442
|
+
code: "unknown-scheme",
|
|
443
|
+
severity: "warning",
|
|
444
|
+
message: `Requested color scheme "${requestedScheme}" is unavailable; the base theme and provider remain active.`,
|
|
445
|
+
schemeId: requestedScheme,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
Object.assign(variables, explicitVariables);
|
|
450
|
+
for (const token of Object.keys(explicitVariables)) {
|
|
451
|
+
contrastRelevantTokens.add(token);
|
|
452
|
+
}
|
|
453
|
+
if (contrastRelevantTokens.size > 0) {
|
|
454
|
+
diagnostics.push(...diagnoseThemeContrast(variables, requestedScheme === "default" ? undefined : requestedScheme, contrastRelevantTokens));
|
|
455
|
+
}
|
|
456
|
+
for (const item of diagnostics)
|
|
457
|
+
warnDiagnostic(item);
|
|
458
|
+
return Object.freeze({
|
|
459
|
+
baseTheme,
|
|
460
|
+
requestedScheme,
|
|
461
|
+
resolvedScheme,
|
|
462
|
+
status,
|
|
463
|
+
variables: freezeVariables(variables),
|
|
464
|
+
diagnostics: freezeDiagnostics(diagnostics),
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Registers valid entries from a batch and returns a generation-aware receipt.
|
|
469
|
+
* Invalid entries never disturb an existing valid registration.
|
|
470
|
+
*/
|
|
471
|
+
export function registerPieColorSchemes(entries) {
|
|
472
|
+
const diagnostics = [];
|
|
473
|
+
const installed = new Map();
|
|
474
|
+
if (!Array.isArray(entries)) {
|
|
475
|
+
diagnostic({
|
|
476
|
+
code: "invalid-registration",
|
|
477
|
+
severity: "error",
|
|
478
|
+
message: "Color-scheme registration must be an array.",
|
|
479
|
+
}, diagnostics);
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
for (const [index, entry] of entries.entries()) {
|
|
483
|
+
const validated = validateRegistration(entry, index);
|
|
484
|
+
for (const item of validated.diagnostics) {
|
|
485
|
+
diagnostic(item, diagnostics);
|
|
486
|
+
}
|
|
487
|
+
if (!validated.record)
|
|
488
|
+
continue;
|
|
489
|
+
customSchemes.set(validated.record.id, validated.record);
|
|
490
|
+
installed.set(validated.record.id, validated.record.key);
|
|
491
|
+
const resolved = {
|
|
492
|
+
...getBaseThemeVariables("light"),
|
|
493
|
+
...validated.record.variables,
|
|
494
|
+
};
|
|
495
|
+
for (const item of diagnoseThemeContrast(resolved, validated.record.id, new Set(Object.keys(validated.record.variables)))) {
|
|
496
|
+
diagnostic({ ...item, index }, diagnostics);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (installed.size > 0)
|
|
501
|
+
publishSnapshot();
|
|
502
|
+
let active = true;
|
|
503
|
+
const acceptedSchemeIds = Object.freeze([...installed.keys()]);
|
|
504
|
+
const receipt = {
|
|
505
|
+
acceptedSchemeIds,
|
|
506
|
+
diagnostics: freezeDiagnostics(diagnostics),
|
|
507
|
+
unregister() {
|
|
508
|
+
if (!active)
|
|
509
|
+
return;
|
|
510
|
+
active = false;
|
|
511
|
+
let changed = false;
|
|
512
|
+
for (const [id, key] of installed) {
|
|
513
|
+
if (customSchemes.get(id)?.key !== key)
|
|
514
|
+
continue;
|
|
515
|
+
customSchemes.delete(id);
|
|
516
|
+
changed = true;
|
|
517
|
+
}
|
|
518
|
+
if (changed)
|
|
519
|
+
publishSnapshot();
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
return Object.freeze(receipt);
|
|
401
523
|
}
|