@udixio/theme 0.0.1

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 (54) hide show
  1. package/LICENSE +202 -0
  2. package/index.cjs.js +3226 -0
  3. package/index.d.ts +1 -0
  4. package/index.esm.js +3170 -0
  5. package/package.json +17 -0
  6. package/src/index.d.ts +1 -0
  7. package/src/lib/API.d.ts +13 -0
  8. package/src/lib/app.container.d.ts +5 -0
  9. package/src/lib/app.module.d.ts +2 -0
  10. package/src/lib/color/color.api.d.ts +38 -0
  11. package/src/lib/color/color.manager.d.ts +23 -0
  12. package/src/lib/color/color.module.d.ts +2 -0
  13. package/src/lib/color/color.utils.d.ts +7 -0
  14. package/src/lib/color/configurable-color.d.ts +30 -0
  15. package/src/lib/color/default-color.d.ts +2 -0
  16. package/src/lib/color/index.d.ts +5 -0
  17. package/src/lib/config/config.interface.d.ts +13 -0
  18. package/src/lib/config/config.module.d.ts +2 -0
  19. package/src/lib/config/config.service.d.ts +12 -0
  20. package/src/lib/config/index.d.ts +3 -0
  21. package/src/lib/index.d.ts +12 -0
  22. package/src/lib/main.d.ts +7 -0
  23. package/src/lib/material-color-utilities/contrastCurve.d.ts +46 -0
  24. package/src/lib/material-color-utilities/dynamic_color.d.ts +199 -0
  25. package/src/lib/material-color-utilities/hct_solver.d.ts +146 -0
  26. package/src/lib/material-color-utilities/htc.d.ts +107 -0
  27. package/src/lib/material-color-utilities/index.d.ts +3 -0
  28. package/src/lib/material-color-utilities/toneDeltaPair.d.ts +69 -0
  29. package/src/lib/plugin/index.d.ts +3 -0
  30. package/src/lib/plugin/plugin.module.d.ts +2 -0
  31. package/src/lib/plugin/pluginAbstract.d.ts +18 -0
  32. package/src/lib/plugin/pluginApi.d.ts +8 -0
  33. package/src/lib/plugins/font/font.plugin.d.ts +49 -0
  34. package/src/lib/plugins/font/index.d.ts +1 -0
  35. package/src/lib/plugins/tailwind/file.d.ts +4 -0
  36. package/src/lib/plugins/tailwind/index.d.ts +3 -0
  37. package/src/lib/plugins/tailwind/main.d.ts +2 -0
  38. package/src/lib/plugins/tailwind/plugins-tailwind/font.d.ts +3 -0
  39. package/src/lib/plugins/tailwind/plugins-tailwind/index.d.ts +2 -0
  40. package/src/lib/plugins/tailwind/plugins-tailwind/state.d.ts +2 -0
  41. package/src/lib/plugins/tailwind/plugins-tailwind/themer.d.ts +10 -0
  42. package/src/lib/plugins/tailwind/tailwind.plugin.d.ts +18 -0
  43. package/src/lib/theme/index.d.ts +7 -0
  44. package/src/lib/theme/scheme.d.ts +19 -0
  45. package/src/lib/theme/scheme.manager.d.ts +30 -0
  46. package/src/lib/theme/theme.api.d.ts +22 -0
  47. package/src/lib/theme/theme.module.d.ts +2 -0
  48. package/src/lib/theme/variant.d.ts +35 -0
  49. package/src/lib/theme/variant.manager.d.ts +13 -0
  50. package/src/lib/theme/variants/expressive.variant.d.ts +2 -0
  51. package/src/lib/theme/variants/index.d.ts +4 -0
  52. package/src/lib/theme/variants/neutral.variant.d.ts +2 -0
  53. package/src/lib/theme/variants/tonal-spot.variant.d.ts +2 -0
  54. package/src/lib/theme/variants/vibrant.variant.d.ts +2 -0
package/index.cjs.js ADDED
@@ -0,0 +1,3226 @@
1
+ 'use strict';
2
+
3
+ var awilix = require('awilix');
4
+ var materialColorUtilities = require('@material/material-color-utilities');
5
+ var plugin = require('tailwindcss/plugin');
6
+ var fs = require('fs');
7
+ var path = require('path');
8
+ var replaceInFile = require('replace-in-file');
9
+
10
+ function _interopNamespaceDefault(e) {
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
28
+ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
29
+
30
+ class ColorApi {
31
+ constructor({ colorManager }) {
32
+ this.colorManager = colorManager;
33
+ }
34
+ getColors() {
35
+ return this.colorManager.getAll();
36
+ }
37
+ addColor(key, color) {
38
+ return this.colorManager.createOrUpdate(key, color);
39
+ }
40
+ addColors(args) {
41
+ if (!Array.isArray(args))
42
+ args = [args];
43
+ args.forEach((args) => {
44
+ if (typeof args === 'function') {
45
+ args = args(this);
46
+ }
47
+ if (args.fromPalettes) {
48
+ if (!Array.isArray(args.fromPalettes))
49
+ args.fromPalettes = [args.fromPalettes];
50
+ args.fromPalettes.map((paletteKey) => {
51
+ this.colorManager.addFromPalette(paletteKey);
52
+ });
53
+ }
54
+ if (args.colors) {
55
+ Object.keys(args.colors).map((key) => this.addColor(key, args.colors[key]));
56
+ }
57
+ });
58
+ }
59
+ getColor(key) {
60
+ return this.colorManager.get(key);
61
+ }
62
+ removeColor(key) {
63
+ return this.colorManager.remove(key);
64
+ }
65
+ updateColor(key, newColor) {
66
+ return this.colorManager.createOrUpdate(key, newColor);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * @license
72
+ * Copyright 2023 Google LLC
73
+ *
74
+ * Licensed under the Apache License, Version 2.0 (the "License");
75
+ * you may not use this file except in compliance with the License.
76
+ * You may obtain a copy of the License at
77
+ *
78
+ * http://www.apache.org/licenses/LICENSE-2.0
79
+ *
80
+ * Unless required by applicable law or agreed to in writing, software
81
+ * distributed under the License is distributed on an "AS IS" BASIS,
82
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
83
+ * See the License for the specific language governing permissions and
84
+ * limitations under the License.
85
+ */
86
+ /**
87
+ * A class containing a value that changes with the contrast level.
88
+ *
89
+ * Usually represents the contrast requirements for a dynamic color on its
90
+ * background. The four values correspond to values for contrast levels -1.0,
91
+ * 0.0, 0.5, and 1.0, respectively.
92
+ */
93
+ class ContrastCurve {
94
+ /**
95
+ * Creates a `ContrastCurve` object.
96
+ *
97
+ * @param low Value for contrast level -1.0
98
+ * @param normal Value for contrast level 0.0
99
+ * @param medium Value for contrast level 0.5
100
+ * @param high Value for contrast level 1.0
101
+ */
102
+ constructor(low, normal, medium, high) {
103
+ this.low = low;
104
+ this.normal = normal;
105
+ this.medium = medium;
106
+ this.high = high;
107
+ }
108
+ /**
109
+ * Returns the value at a given contrast level.
110
+ *
111
+ * @param contrastLevel The contrast level. 0.0 is the default (normal); -1.0
112
+ * is the lowest; 1.0 is the highest.
113
+ * @return The value. For contrast ratios, a number between 1.0 and 21.0.
114
+ */
115
+ get(contrastLevel) {
116
+ if (contrastLevel <= -1) {
117
+ return this.low;
118
+ }
119
+ else if (contrastLevel < 0.0) {
120
+ return materialColorUtilities.lerp(this.low, this.normal, (contrastLevel - -1) / 1);
121
+ }
122
+ else if (contrastLevel < 0.5) {
123
+ return materialColorUtilities.lerp(this.normal, this.medium, (contrastLevel - 0) / 0.5);
124
+ }
125
+ else if (contrastLevel < 1.0) {
126
+ return materialColorUtilities.lerp(this.medium, this.high, (contrastLevel - 0.5) / 0.5);
127
+ }
128
+ else {
129
+ return this.high;
130
+ }
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @license
136
+ * Copyright 2021 Google LLC
137
+ *
138
+ * Licensed under the Apache License, Version 2.0 (the "License");
139
+ * you may not use this file except in compliance with the License.
140
+ * You may obtain a copy of the License at
141
+ *
142
+ * http://www.apache.org/licenses/LICENSE-2.0
143
+ *
144
+ * Unless required by applicable law or agreed to in writing, software
145
+ * distributed under the License is distributed on an "AS IS" BASIS,
146
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
147
+ * See the License for the specific language governing permissions and
148
+ * limitations under the License.
149
+ */
150
+ // This file is automatically generated. Do not modify it.
151
+ // material_color_utilities is designed to have a consistent API across
152
+ // platforms and modular components that can be moved around easily. Using a
153
+ // class as a namespace facilitates this.
154
+ //
155
+ // tslint:disable:class-as-namespace
156
+ /**
157
+ * A class that solves the HCT equation.
158
+ */
159
+ class HctSolver {
160
+ /**
161
+ * Finds an sRGB color with the given hue, chroma, and L*, if
162
+ * possible.
163
+ *
164
+ * @param hueDegrees The desired hue, in degrees.
165
+ * @param chroma The desired chroma.
166
+ * @param lstar The desired L*.
167
+ * @return A hexadecimal representing the sRGB color. The color
168
+ * has sufficiently close hue, chroma, and L* to the desired
169
+ * values, if possible; otherwise, the hue and L* will be
170
+ * sufficiently close, and chroma will be maximized.
171
+ */
172
+ static solveToInt(hueDegrees, chroma, lstar) {
173
+ if (chroma < 0.0001 || lstar < 0.0001 || lstar > 99.9999) {
174
+ return materialColorUtilities.argbFromLstar(lstar);
175
+ }
176
+ hueDegrees = materialColorUtilities.sanitizeDegreesDouble(hueDegrees);
177
+ const hueRadians = (hueDegrees / 180) * Math.PI;
178
+ const y = materialColorUtilities.yFromLstar(lstar);
179
+ const exactAnswer = HctSolver.findResultByJ(hueRadians, chroma, y);
180
+ if (exactAnswer !== 0) {
181
+ return exactAnswer;
182
+ }
183
+ const linrgb = HctSolver.bisectToLimit(y, hueRadians);
184
+ return materialColorUtilities.argbFromLinrgb(linrgb);
185
+ }
186
+ /**
187
+ * Finds an sRGB color with the given hue, chroma, and L*, if
188
+ * possible.
189
+ *
190
+ * @param hueDegrees The desired hue, in degrees.
191
+ * @param chroma The desired chroma.
192
+ * @param lstar The desired L*.
193
+ * @return An CAM16 object representing the sRGB color. The color
194
+ * has sufficiently close hue, chroma, and L* to the desired
195
+ * values, if possible; otherwise, the hue and L* will be
196
+ * sufficiently close, and chroma will be maximized.
197
+ */
198
+ static solveToCam(hueDegrees, chroma, lstar) {
199
+ return materialColorUtilities.Cam16.fromInt(HctSolver.solveToInt(hueDegrees, chroma, lstar));
200
+ }
201
+ /**
202
+ * Sanitizes a small enough angle in radians.
203
+ *
204
+ * @param angle An angle in radians; must not deviate too much
205
+ * from 0.
206
+ * @return A coterminal angle between 0 and 2pi.
207
+ */
208
+ static sanitizeRadians(angle) {
209
+ return (angle + Math.PI * 8) % (Math.PI * 2);
210
+ }
211
+ /**
212
+ * Delinearizes an RGB component, returning a floating-point
213
+ * number.
214
+ *
215
+ * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents
216
+ * linear R/G/B channel
217
+ * @return 0.0 <= output <= 255.0, color channel converted to
218
+ * regular RGB space
219
+ */
220
+ static trueDelinearized(rgbComponent) {
221
+ const normalized = rgbComponent / 100.0;
222
+ let delinearized = 0.0;
223
+ if (normalized <= 0.0031308) {
224
+ delinearized = normalized * 12.92;
225
+ }
226
+ else {
227
+ delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055;
228
+ }
229
+ return delinearized * 255.0;
230
+ }
231
+ static chromaticAdaptation(component) {
232
+ const af = Math.pow(Math.abs(component), 0.42);
233
+ return (materialColorUtilities.signum(component) * 400.0 * af) / (af + 27.13);
234
+ }
235
+ /**
236
+ * Returns the hue of a linear RGB color in CAM16.
237
+ *
238
+ * @param linrgb The linear RGB coordinates of a color.
239
+ * @return The hue of the color in CAM16, in radians.
240
+ */
241
+ static hueOf(linrgb) {
242
+ const scaledDiscount = materialColorUtilities.matrixMultiply(linrgb, HctSolver.SCALED_DISCOUNT_FROM_LINRGB);
243
+ const rA = HctSolver.chromaticAdaptation(scaledDiscount[0]);
244
+ const gA = HctSolver.chromaticAdaptation(scaledDiscount[1]);
245
+ const bA = HctSolver.chromaticAdaptation(scaledDiscount[2]);
246
+ // redness-greenness
247
+ const a = (11.0 * rA + -12 * gA + bA) / 11.0;
248
+ // yellowness-blueness
249
+ const b = (rA + gA - 2.0 * bA) / 9.0;
250
+ return Math.atan2(b, a);
251
+ }
252
+ static areInCyclicOrder(a, b, c) {
253
+ const deltaAB = HctSolver.sanitizeRadians(b - a);
254
+ const deltaAC = HctSolver.sanitizeRadians(c - a);
255
+ return deltaAB < deltaAC;
256
+ }
257
+ /**
258
+ * Solves the lerp equation.
259
+ *
260
+ * @param source The starting number.
261
+ * @param mid The number in the middle.
262
+ * @param target The ending number.
263
+ * @return A number t such that lerp(source, target, t) = mid.
264
+ */
265
+ static intercept(source, mid, target) {
266
+ return (mid - source) / (target - source);
267
+ }
268
+ static lerpPoint(source, t, target) {
269
+ return [
270
+ source[0] + (target[0] - source[0]) * t,
271
+ source[1] + (target[1] - source[1]) * t,
272
+ source[2] + (target[2] - source[2]) * t,
273
+ ];
274
+ }
275
+ /**
276
+ * Intersects a segment with a plane.
277
+ *
278
+ * @param source The coordinates of point A.
279
+ * @param coordinate The R-, G-, or B-coordinate of the plane.
280
+ * @param target The coordinates of point B.
281
+ * @param axis The axis the plane is perpendicular with. (0: R, 1:
282
+ * G, 2: B)
283
+ * @return The intersection point of the segment AB with the plane
284
+ * R=coordinate, G=coordinate, or B=coordinate
285
+ */
286
+ static setCoordinate(source, coordinate, target, axis) {
287
+ const t = HctSolver.intercept(source[axis], coordinate, target[axis]);
288
+ return HctSolver.lerpPoint(source, t, target);
289
+ }
290
+ static isBounded(x) {
291
+ return 0.0 <= x && x <= 100.0;
292
+ }
293
+ /**
294
+ * Returns the nth possible vertex of the polygonal intersection.
295
+ *
296
+ * @param y The Y value of the plane.
297
+ * @param n The zero-based index of the point. 0 <= n <= 11.
298
+ * @return The nth possible vertex of the polygonal intersection
299
+ * of the y plane and the RGB cube, in linear RGB coordinates, if
300
+ * it exists. If this possible vertex lies outside of the cube,
301
+ * [-1.0, -1.0, -1.0] is returned.
302
+ */
303
+ static nthVertex(y, n) {
304
+ const kR = HctSolver.Y_FROM_LINRGB[0];
305
+ const kG = HctSolver.Y_FROM_LINRGB[1];
306
+ const kB = HctSolver.Y_FROM_LINRGB[2];
307
+ const coordA = n % 4 <= 1 ? 0.0 : 100.0;
308
+ const coordB = n % 2 === 0 ? 0.0 : 100.0;
309
+ if (n < 4) {
310
+ const g = coordA;
311
+ const b = coordB;
312
+ const r = (y - g * kG - b * kB) / kR;
313
+ if (HctSolver.isBounded(r)) {
314
+ return [r, g, b];
315
+ }
316
+ else {
317
+ return [-1, -1, -1];
318
+ }
319
+ }
320
+ else if (n < 8) {
321
+ const b = coordA;
322
+ const r = coordB;
323
+ const g = (y - r * kR - b * kB) / kG;
324
+ if (HctSolver.isBounded(g)) {
325
+ return [r, g, b];
326
+ }
327
+ else {
328
+ return [-1, -1, -1];
329
+ }
330
+ }
331
+ else {
332
+ const r = coordA;
333
+ const g = coordB;
334
+ const b = (y - r * kR - g * kG) / kB;
335
+ if (HctSolver.isBounded(b)) {
336
+ return [r, g, b];
337
+ }
338
+ else {
339
+ return [-1, -1, -1];
340
+ }
341
+ }
342
+ }
343
+ /**
344
+ * Finds the segment containing the desired color.
345
+ *
346
+ * @param y The Y value of the color.
347
+ * @param targetHue The hue of the color.
348
+ * @return A list of two sets of linear RGB coordinates, each
349
+ * corresponding to an endpoint of the segment containing the
350
+ * desired color.
351
+ */
352
+ static bisectToSegment(y, targetHue) {
353
+ let left = [-1, -1, -1];
354
+ let right = left;
355
+ let leftHue = 0.0;
356
+ let rightHue = 0.0;
357
+ let initialized = false;
358
+ let uncut = true;
359
+ for (let n = 0; n < 12; n++) {
360
+ const mid = HctSolver.nthVertex(y, n);
361
+ if (mid[0] < 0) {
362
+ continue;
363
+ }
364
+ const midHue = HctSolver.hueOf(mid);
365
+ if (!initialized) {
366
+ left = mid;
367
+ right = mid;
368
+ leftHue = midHue;
369
+ rightHue = midHue;
370
+ initialized = true;
371
+ continue;
372
+ }
373
+ if (uncut || HctSolver.areInCyclicOrder(leftHue, midHue, rightHue)) {
374
+ uncut = false;
375
+ if (HctSolver.areInCyclicOrder(leftHue, targetHue, midHue)) {
376
+ right = mid;
377
+ rightHue = midHue;
378
+ }
379
+ else {
380
+ left = mid;
381
+ leftHue = midHue;
382
+ }
383
+ }
384
+ }
385
+ return [left, right];
386
+ }
387
+ static midpoint(a, b) {
388
+ return [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2];
389
+ }
390
+ static criticalPlaneBelow(x) {
391
+ return Math.floor(x - 0.5);
392
+ }
393
+ static criticalPlaneAbove(x) {
394
+ return Math.ceil(x - 0.5);
395
+ }
396
+ /**
397
+ * Finds a color with the given Y and hue on the boundary of the
398
+ * cube.
399
+ *
400
+ * @param y The Y value of the color.
401
+ * @param targetHue The hue of the color.
402
+ * @return The desired color, in linear RGB coordinates.
403
+ */
404
+ static bisectToLimit(y, targetHue) {
405
+ const segment = HctSolver.bisectToSegment(y, targetHue);
406
+ let left = segment[0];
407
+ let leftHue = HctSolver.hueOf(left);
408
+ let right = segment[1];
409
+ for (let axis = 0; axis < 3; axis++) {
410
+ if (left[axis] !== right[axis]) {
411
+ let lPlane = -1;
412
+ let rPlane = 255;
413
+ if (left[axis] < right[axis]) {
414
+ lPlane = HctSolver.criticalPlaneBelow(HctSolver.trueDelinearized(left[axis]));
415
+ rPlane = HctSolver.criticalPlaneAbove(HctSolver.trueDelinearized(right[axis]));
416
+ }
417
+ else {
418
+ lPlane = HctSolver.criticalPlaneAbove(HctSolver.trueDelinearized(left[axis]));
419
+ rPlane = HctSolver.criticalPlaneBelow(HctSolver.trueDelinearized(right[axis]));
420
+ }
421
+ for (let i = 0; i < 8; i++) {
422
+ if (Math.abs(rPlane - lPlane) <= 1) {
423
+ break;
424
+ }
425
+ else {
426
+ const mPlane = Math.floor((lPlane + rPlane) / 2.0);
427
+ const midPlaneCoordinate = HctSolver.CRITICAL_PLANES[mPlane];
428
+ const mid = HctSolver.setCoordinate(left, midPlaneCoordinate, right, axis);
429
+ const midHue = HctSolver.hueOf(mid);
430
+ if (HctSolver.areInCyclicOrder(leftHue, targetHue, midHue)) {
431
+ right = mid;
432
+ rPlane = mPlane;
433
+ }
434
+ else {
435
+ left = mid;
436
+ leftHue = midHue;
437
+ lPlane = mPlane;
438
+ }
439
+ }
440
+ }
441
+ }
442
+ }
443
+ return HctSolver.midpoint(left, right);
444
+ }
445
+ static inverseChromaticAdaptation(adapted) {
446
+ const adaptedAbs = Math.abs(adapted);
447
+ const base = Math.max(0, (27.13 * adaptedAbs) / (400.0 - adaptedAbs));
448
+ return materialColorUtilities.signum(adapted) * Math.pow(base, 1.0 / 0.42);
449
+ }
450
+ /**
451
+ * Finds a color with the given hue, chroma, and Y.
452
+ *
453
+ * @param hueRadians The desired hue in radians.
454
+ * @param chroma The desired chroma.
455
+ * @param y The desired Y.
456
+ * @return The desired color as a hexadecimal integer, if found; 0
457
+ * otherwise.
458
+ */
459
+ static findResultByJ(hueRadians, chroma, y) {
460
+ // Initial estimate of j.
461
+ let j = Math.sqrt(y) * 11.0;
462
+ // ===========================================================
463
+ // Operations inlined from Cam16 to avoid repeated calculation
464
+ // ===========================================================
465
+ const viewingConditions = materialColorUtilities.ViewingConditions.DEFAULT;
466
+ const tInnerCoeff = 1 / Math.pow(1.64 - Math.pow(0.29, viewingConditions.n), 0.73);
467
+ const eHue = 0.25 * (Math.cos(hueRadians + 2.0) + 3.8);
468
+ const p1 = eHue * (50000.0 / 13.0) * viewingConditions.nc * viewingConditions.ncb;
469
+ const hSin = Math.sin(hueRadians);
470
+ const hCos = Math.cos(hueRadians);
471
+ for (let iterationRound = 0; iterationRound < 5; iterationRound++) {
472
+ // ===========================================================
473
+ // Operations inlined from Cam16 to avoid repeated calculation
474
+ // ===========================================================
475
+ const jNormalized = j / 100.0;
476
+ const alpha = chroma === 0.0 || j === 0.0 ? 0.0 : chroma / Math.sqrt(jNormalized);
477
+ const t = Math.pow(alpha * tInnerCoeff, 1.0 / 0.9);
478
+ const ac = viewingConditions.aw *
479
+ Math.pow(jNormalized, 1.0 / viewingConditions.c / viewingConditions.z);
480
+ const p2 = ac / viewingConditions.nbb;
481
+ const gamma = (23.0 * (p2 + 0.305) * t) /
482
+ (23.0 * p1 + 11 * t * hCos + 108.0 * t * hSin);
483
+ const a = gamma * hCos;
484
+ const b = gamma * hSin;
485
+ const rA = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0;
486
+ const gA = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0;
487
+ const bA = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0;
488
+ const rCScaled = HctSolver.inverseChromaticAdaptation(rA);
489
+ const gCScaled = HctSolver.inverseChromaticAdaptation(gA);
490
+ const bCScaled = HctSolver.inverseChromaticAdaptation(bA);
491
+ const linrgb = materialColorUtilities.matrixMultiply([rCScaled, gCScaled, bCScaled], HctSolver.LINRGB_FROM_SCALED_DISCOUNT);
492
+ // ===========================================================
493
+ // Operations inlined from Cam16 to avoid repeated calculation
494
+ // ===========================================================
495
+ if (linrgb[0] < 0 || linrgb[1] < 0 || linrgb[2] < 0) {
496
+ return 0;
497
+ }
498
+ const kR = HctSolver.Y_FROM_LINRGB[0];
499
+ const kG = HctSolver.Y_FROM_LINRGB[1];
500
+ const kB = HctSolver.Y_FROM_LINRGB[2];
501
+ const fnj = kR * linrgb[0] + kG * linrgb[1] + kB * linrgb[2];
502
+ if (fnj <= 0) {
503
+ return 0;
504
+ }
505
+ if (iterationRound === 4 || Math.abs(fnj - y) < 0.002) {
506
+ if (linrgb[0] > 100.01 || linrgb[1] > 100.01 || linrgb[2] > 100.01) {
507
+ return 0;
508
+ }
509
+ return materialColorUtilities.argbFromLinrgb(linrgb);
510
+ }
511
+ // Iterates with Newton method,
512
+ // Using 2 * fn(j) / j as the approximation of fn'(j)
513
+ j = j - ((fnj - y) * j) / (2 * fnj);
514
+ }
515
+ return 0;
516
+ }
517
+ }
518
+ HctSolver.SCALED_DISCOUNT_FROM_LINRGB = [
519
+ [0.001200833568784504, 0.002389694492170889, 0.0002795742885861124],
520
+ [0.0005891086651375999, 0.0029785502573438758, 0.0003270666104008398],
521
+ [0.00010146692491640572, 0.0005364214359186694, 0.0032979401770712076],
522
+ ];
523
+ HctSolver.LINRGB_FROM_SCALED_DISCOUNT = [
524
+ [1373.2198709594231, -1100.4251190754821, -7.278681089101213],
525
+ [-271.815969077903, 559.6580465940733, -32.46047482791194],
526
+ [1.9622899599665666, -57.173814538844006, 308.7233197812385],
527
+ ];
528
+ HctSolver.Y_FROM_LINRGB = [0.2126, 0.7152, 0.0722];
529
+ HctSolver.CRITICAL_PLANES = [
530
+ 0.015176349177441876, 0.045529047532325624, 0.07588174588720938,
531
+ 0.10623444424209313, 0.13658714259697685, 0.16693984095186062,
532
+ 0.19729253930674434, 0.2276452376616281, 0.2579979360165119,
533
+ 0.28835063437139563, 0.3188300904430532, 0.350925934958123,
534
+ 0.3848314933096426, 0.42057480301049466, 0.458183274052838,
535
+ 0.4976837250274023, 0.5391024159806381, 0.5824650784040898,
536
+ 0.6277969426914107, 0.6751227633498623, 0.7244668422128921,
537
+ 0.775853049866786, 0.829304845476233, 0.8848452951698498, 0.942497089126609,
538
+ 1.0022825574869039, 1.0642236851973577, 1.1283421258858297,
539
+ 1.1946592148522128, 1.2631959812511864, 1.3339731595349034,
540
+ 1.407011200216447, 1.4823302800086415, 1.5599503113873272,
541
+ 1.6398909516233677, 1.7221716113234105, 1.8068114625156377,
542
+ 1.8938294463134073, 1.9832442801866852, 2.075074464868551,
543
+ 2.1693382909216234, 2.2660538449872063, 2.36523901573795,
544
+ 2.4669114995532007, 2.5710888059345764, 2.6777882626779785,
545
+ 2.7870270208169257, 2.898822059350997, 3.0131901897720907,
546
+ 3.1301480604002863, 3.2497121605402226, 3.3718988244681087,
547
+ 3.4967242352587946, 3.624204428461639, 3.754355295633311, 3.887192587735158,
548
+ 4.022731918402185, 4.160988767090289, 4.301978482107941, 4.445716283538092,
549
+ 4.592217266055746, 4.741496401646282, 4.893568542229298, 5.048448422192488,
550
+ 5.20615066083972, 5.3666897647573375, 5.5300801301023865, 5.696336044816294,
551
+ 5.865471690767354, 6.037501145825082, 6.212438385869475, 6.390297286737924,
552
+ 6.571091626112461, 6.7548350853498045, 6.941541251256611, 7.131223617812143,
553
+ 7.323895587840543, 7.5195704746346665, 7.7182615035334345,
554
+ 7.919981813454504, 8.124744458384042, 8.332562408825165, 8.543448553206703,
555
+ 8.757415699253682, 8.974476575321063, 9.194643831691977, 9.417930041841839,
556
+ 9.644347703669503, 9.873909240696694, 10.106627003236781,
557
+ 10.342513269534024, 10.58158024687427, 10.8238400726681, 11.069304815507364,
558
+ 11.317986476196008, 11.569896988756009, 11.825048221409341,
559
+ 12.083451977536606, 12.345119996613247, 12.610063955123938,
560
+ 12.878295467455942, 13.149826086772048, 13.42466730586372,
561
+ 13.702830557985108, 13.984327217668513, 14.269168601521828,
562
+ 14.55736596900856, 14.848930523210871, 15.143873411576273,
563
+ 15.44220572664832, 15.743938506781891, 16.04908273684337, 16.35764934889634,
564
+ 16.66964922287304, 16.985093187232053, 17.30399201960269, 17.62635644741625,
565
+ 17.95219714852476, 18.281524751807332, 18.614349837764564,
566
+ 18.95068293910138, 19.290534541298456, 19.633915083172692,
567
+ 19.98083495742689, 20.331304511189067, 20.685334046541502,
568
+ 21.042933821039977, 21.404114048223256, 21.76888489811322,
569
+ 22.137256497705877, 22.50923893145328, 22.884842241736916,
570
+ 23.264076429332462, 23.6469514538663, 24.033477234264016, 24.42366364919083,
571
+ 24.817520537484558, 25.21505769858089, 25.61628489293138,
572
+ 26.021211842414342, 26.429848230738664, 26.842203703840827,
573
+ 27.258287870275353, 27.678110301598522, 28.10168053274597,
574
+ 28.529008062403893, 28.96010235337422, 29.39497283293396, 29.83362889318845,
575
+ 30.276079891419332, 30.722335150426627, 31.172403958865512,
576
+ 31.62629557157785, 32.08401920991837, 32.54558406207592, 33.010999283389665,
577
+ 33.4802739966603, 33.953417292456834, 34.430438229418264,
578
+ 34.911345834551085, 35.39614910352207, 35.88485700094671, 36.37747846067349,
579
+ 36.87402238606382, 37.37449765026789, 37.87891309649659, 38.38727753828926,
580
+ 38.89959975977785, 39.41588851594697, 39.93615253289054, 40.460400508064545,
581
+ 40.98864111053629, 41.520882981230194, 42.05713473317016,
582
+ 42.597404951718396, 43.141702194811224, 43.6900349931913, 44.24241185063697,
583
+ 44.798841244188324, 45.35933162437017, 45.92389141541209, 46.49252901546552,
584
+ 47.065252796817916, 47.64207110610409, 48.22299226451468,
585
+ 48.808024568002054, 49.3971762874833, 49.9904556690408, 50.587870934119984,
586
+ 51.189430279724725, 51.79514187861014, 52.40501387947288, 53.0190544071392,
587
+ 53.637271562750364, 54.259673423945976, 54.88626804504493,
588
+ 55.517063457223934, 56.15206766869424, 56.79128866487574, 57.43473440856916,
589
+ 58.08241284012621, 58.734331877617365, 59.39049941699807, 60.05092333227251,
590
+ 60.715611475655585, 61.38457167773311, 62.057811747619894, 62.7353394731159,
591
+ 63.417162620860914, 64.10328893648692, 64.79372614476921, 65.48848194977529,
592
+ 66.18756403501224, 66.89098006357258, 67.59873767827808, 68.31084450182222,
593
+ 69.02730813691093, 69.74813616640164, 70.47333615344107, 71.20291564160104,
594
+ 71.93688215501312, 72.67524319850172, 73.41800625771542, 74.16517879925733,
595
+ 74.9167682708136, 75.67278210128072, 76.43322770089146, 77.1981124613393,
596
+ 77.96744375590167, 78.74122893956174, 79.51947534912904, 80.30219030335869,
597
+ 81.08938110306934, 81.88105503125999, 82.67721935322541, 83.4778813166706,
598
+ 84.28304815182372, 85.09272707154808, 85.90692527145302, 86.72564993000343,
599
+ 87.54890820862819, 88.3767072518277, 89.2090541872801, 90.04595612594655,
600
+ 90.88742016217518, 91.73345337380438, 92.58406282226491, 93.43925555268066,
601
+ 94.29903859396902, 95.16341895893969, 96.03240364439274, 96.9059996312159,
602
+ 97.78421388448044, 98.6670533535366, 99.55452497210776,
603
+ ];
604
+
605
+ /**
606
+ * @license
607
+ * Copyright 2021 Google LLC
608
+ *
609
+ * Licensed under the Apache License, Version 2.0 (the "License");
610
+ * you may not use this file except in compliance with the License.
611
+ * You may obtain a copy of the License at
612
+ *
613
+ * http://www.apache.org/licenses/LICENSE-2.0
614
+ *
615
+ * Unless required by applicable law or agreed to in writing, software
616
+ * distributed under the License is distributed on an "AS IS" BASIS,
617
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
618
+ * See the License for the specific language governing permissions and
619
+ * limitations under the License.
620
+ */
621
+ /**
622
+ * A color system built using CAM16 hue and chroma, and L* from
623
+ * L*a*b*.
624
+ *
625
+ * Using L* creates a link between the color system, contrast, and thus
626
+ * accessibility. Contrast ratio depends on relative luminance, or Y in the XYZ
627
+ * color space. L*, or perceptual luminance can be calculated from Y.
628
+ *
629
+ * Unlike Y, L* is linear to human perception, allowing trivial creation of
630
+ * accurate color tones.
631
+ *
632
+ * Unlike contrast ratio, measuring contrast in L* is linear, and simple to
633
+ * calculate. A difference of 40 in HCT tone guarantees a contrast ratio >= 3.0,
634
+ * and a difference of 50 guarantees a contrast ratio >= 4.5.
635
+ */
636
+ /**
637
+ * HCT, hue, chroma, and tone. A color system that provides a perceptually
638
+ * accurate color measurement system that can also accurately render what colors
639
+ * will appear as in different lighting environments.
640
+ */
641
+ class Hct {
642
+ constructor(argb) {
643
+ this.argb = argb;
644
+ const cam = materialColorUtilities.Cam16.fromInt(argb);
645
+ this.internalHue = cam.hue;
646
+ this.internalChroma = cam.chroma;
647
+ this.internalTone = materialColorUtilities.lstarFromArgb(argb);
648
+ this.argb = argb;
649
+ }
650
+ /**
651
+ * A number, in degrees, representing ex. red, orange, yellow, etc.
652
+ * Ranges from 0 <= hue < 360.
653
+ */
654
+ get hue() {
655
+ return this.internalHue;
656
+ }
657
+ /**
658
+ * @param newHue 0 <= newHue < 360; invalid values are corrected.
659
+ * Chroma may decrease because chroma has a different maximum for any given
660
+ * hue and tone.
661
+ */
662
+ set hue(newHue) {
663
+ this.setInternalState(HctSolver.solveToInt(newHue, this.internalChroma, this.internalTone));
664
+ }
665
+ get chroma() {
666
+ return this.internalChroma;
667
+ }
668
+ /**
669
+ * @param newChroma 0 <= newChroma < ?
670
+ * Chroma may decrease because chroma has a different maximum for any given
671
+ * hue and tone.
672
+ */
673
+ set chroma(newChroma) {
674
+ this.setInternalState(HctSolver.solveToInt(this.internalHue, newChroma, this.internalTone));
675
+ }
676
+ /** Lightness. Ranges from 0 to 100. */
677
+ get tone() {
678
+ return this.internalTone;
679
+ }
680
+ /**
681
+ * @param newTone 0 <= newTone <= 100; invalid valids are corrected.
682
+ * Chroma may decrease because chroma has a different maximum for any given
683
+ * hue and tone.
684
+ */
685
+ set tone(newTone) {
686
+ this.setInternalState(HctSolver.solveToInt(this.internalHue, this.internalChroma, newTone));
687
+ }
688
+ static from(hue, chroma, tone) {
689
+ return new Hct(HctSolver.solveToInt(hue, chroma, tone));
690
+ }
691
+ /**
692
+ * @param argb ARGB representation of a color.
693
+ * @return HCT representation of a color in default viewing conditions
694
+ */
695
+ static fromInt(argb) {
696
+ return new Hct(argb);
697
+ }
698
+ static isBlue(hue) {
699
+ return hue >= 250 && hue < 270;
700
+ }
701
+ static isYellow(hue) {
702
+ return hue >= 105 && hue < 125;
703
+ }
704
+ static isCyan(hue) {
705
+ return hue >= 170 && hue < 207;
706
+ }
707
+ toInt() {
708
+ return this.argb;
709
+ }
710
+ /** Sets a property of the Hct object. */
711
+ setValue(propertyName, value) {
712
+ this[propertyName] = value;
713
+ }
714
+ toString() {
715
+ return `HCT(${this.hue.toFixed(0)}, ${this.chroma.toFixed(0)}, ${this.tone.toFixed(0)})`;
716
+ }
717
+ /**
718
+ * Translates a color into different [ViewingConditions].
719
+ *
720
+ * Colors change appearance. They look different with lights on versus off,
721
+ * the same color, as in hex code, on white looks different when on black.
722
+ * This is called color relativity, most famously explicated by Josef Albers
723
+ * in Interaction of Color.
724
+ *
725
+ * In color science, color appearance models can account for this and
726
+ * calculate the appearance of a color in different settings. HCT is based on
727
+ * CAM16, a color appearance model, and uses it to make these calculations.
728
+ *
729
+ * See [ViewingConditions.make] for parameters affecting color appearance.
730
+ */
731
+ inViewingConditions(vc) {
732
+ // 1. Use CAM16 to find XYZ coordinates of color in specified VC.
733
+ const cam = materialColorUtilities.Cam16.fromInt(this.toInt());
734
+ const viewedInVc = cam.xyzInViewingConditions(vc);
735
+ // 2. Create CAM16 of those XYZ coordinates in default VC.
736
+ const recastInVc = materialColorUtilities.Cam16.fromXyzInViewingConditions(viewedInVc[0], viewedInVc[1], viewedInVc[2], materialColorUtilities.ViewingConditions.make());
737
+ // 3. Create HCT from:
738
+ // - CAM16 using default VC with XYZ coordinates in specified VC.
739
+ // - L* converted from Y in XYZ coordinates in specified VC.
740
+ const recastHct = Hct.from(recastInVc.hue, recastInVc.chroma, materialColorUtilities.lstarFromY(viewedInVc[1]));
741
+ return recastHct;
742
+ }
743
+ setInternalState(argb) {
744
+ const cam = materialColorUtilities.Cam16.fromInt(argb);
745
+ this.internalHue = cam.hue;
746
+ this.internalChroma = cam.chroma;
747
+ this.internalTone = materialColorUtilities.lstarFromArgb(argb);
748
+ this.argb = argb;
749
+ }
750
+ }
751
+
752
+ /**
753
+ * @license
754
+ * Copyright 2022 Google LLC
755
+ *
756
+ * Licensed under the Apache License, Version 2.0 (the "License");
757
+ * you may not use this file except in compliance with the License.
758
+ * You may obtain a copy of the License at
759
+ *
760
+ * http://www.apache.org/licenses/LICENSE-2.0
761
+ *
762
+ * Unless required by applicable law or agreed to in writing, software
763
+ * distributed under the License is distributed on an "AS IS" BASIS,
764
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
765
+ * See the License for the specific language governing permissions and
766
+ * limitations under the License.
767
+ */
768
+ /**
769
+ * Returns a new DynamicColor that is the same as the original color, but with
770
+ * the extended dynamic color's constraints for the given spec version.
771
+ *
772
+ * @param originlColor The original color.
773
+ * @param specVersion The spec version to extend.
774
+ * @param extendedColor The color with the values to extend.
775
+ */
776
+ function extendSpecVersion(originlColor, extendedColor) {
777
+ return DynamicColor.fromPalette({
778
+ name: originlColor.name,
779
+ palette: (s) => extendedColor.palette(s),
780
+ tone: (s) => extendedColor.tone(s),
781
+ isBackground: originlColor.isBackground,
782
+ chromaMultiplier: (s) => {
783
+ const chromaMultiplier = extendedColor.chromaMultiplier;
784
+ return chromaMultiplier !== undefined ? chromaMultiplier(s) : 1;
785
+ },
786
+ background: (s) => {
787
+ const background = extendedColor.background;
788
+ return background !== undefined ? background(s) : undefined;
789
+ },
790
+ secondBackground: (s) => {
791
+ const secondBackground = extendedColor.secondBackground;
792
+ return secondBackground !== undefined ? secondBackground(s) : undefined;
793
+ },
794
+ contrastCurve: (s) => {
795
+ const contrastCurve = extendedColor.contrastCurve;
796
+ return contrastCurve !== undefined ? contrastCurve(s) : undefined;
797
+ },
798
+ toneDeltaPair: (s) => {
799
+ const toneDeltaPair = extendedColor.toneDeltaPair;
800
+ return toneDeltaPair !== undefined ? toneDeltaPair(s) : undefined;
801
+ },
802
+ });
803
+ }
804
+ /**
805
+ * A color that adjusts itself based on UI state provided by DynamicScheme.
806
+ *
807
+ * Colors without backgrounds do not change tone when contrast changes. Colors
808
+ * with backgrounds become closer to their background as contrast lowers, and
809
+ * further when contrast increases.
810
+ *
811
+ * Prefer static constructors. They require either a hexcode, a palette and
812
+ * tone, or a hue and chroma. Optionally, they can provide a background
813
+ * DynamicColor.
814
+ */
815
+ class DynamicColor {
816
+ /**
817
+ * The base constructor for DynamicColor.
818
+ *
819
+ * _Strongly_ prefer using one of the convenience constructors. This class is
820
+ * arguably too flexible to ensure it can support any scenario. Functional
821
+ * arguments allow overriding without risks that come with subclasses.
822
+ *
823
+ * For example, the default behavior of adjust tone at max contrast
824
+ * to be at a 7.0 ratio with its background is principled and
825
+ * matches accessibility guidance. That does not mean it's the desired
826
+ * approach for _every_ design system, and every color pairing,
827
+ * always, in every case.
828
+ *
829
+ * @param name The name of the dynamic color. Defaults to empty.
830
+ * @param palette Function that provides a TonalPalette given DynamicScheme. A
831
+ * TonalPalette is defined by a hue and chroma, so this replaces the need
832
+ * to specify hue/chroma. By providing a tonal palette, when contrast
833
+ * adjustments are made, intended chroma can be preserved.
834
+ * @param tone Function that provides a tone, given a DynamicScheme.
835
+ * @param isBackground Whether this dynamic color is a background, with some
836
+ * other color as the foreground. Defaults to false.
837
+ * @param chromaMultiplier A factor that multiplies the chroma for this color.
838
+ * @param background The background of the dynamic color (as a function of a
839
+ * `DynamicScheme`), if it exists.
840
+ * @param secondBackground A second background of the dynamic color (as a
841
+ * function of a `DynamicScheme`), if it exists.
842
+ * @param contrastCurve A `ContrastCurve` object specifying how its contrast
843
+ * against its background should behave in various contrast levels
844
+ * options.
845
+ * @param toneDeltaPair A `ToneDeltaPair` object specifying a tone delta
846
+ * constraint between two colors. One of them must be the color being
847
+ * constructed.
848
+ */
849
+ constructor(name, palette, tone, isBackground, chromaMultiplier, background, secondBackground, contrastCurve, toneDeltaPair) {
850
+ this.name = name;
851
+ this.palette = palette;
852
+ this.tone = tone;
853
+ this.isBackground = isBackground;
854
+ this.chromaMultiplier = chromaMultiplier;
855
+ this.background = background;
856
+ this.secondBackground = secondBackground;
857
+ this.contrastCurve = contrastCurve;
858
+ this.toneDeltaPair = toneDeltaPair;
859
+ this.hctCache = new Map();
860
+ if (!background && secondBackground) {
861
+ throw new Error(`Color ${name} has secondBackground` +
862
+ `defined, but background is not defined.`);
863
+ }
864
+ if (!background && contrastCurve) {
865
+ throw new Error(`Color ${name} has contrastCurve` +
866
+ `defined, but background is not defined.`);
867
+ }
868
+ if (background && !contrastCurve) {
869
+ throw new Error(`Color ${name} has background` +
870
+ `defined, but contrastCurve is not defined.`);
871
+ }
872
+ }
873
+ /**
874
+ * Create a DynamicColor defined by a TonalPalette and HCT tone.
875
+ *
876
+ * @param args Functions with DynamicScheme as input. Must provide a palette
877
+ * and tone. May provide a background DynamicColor and ToneDeltaPair.
878
+ */
879
+ static fromPalette(args) {
880
+ var _a, _b, _c;
881
+ return new DynamicColor((_a = args.name) !== null && _a !== void 0 ? _a : '', args.palette, (_b = args.tone) !== null && _b !== void 0 ? _b : DynamicColor.getInitialToneFromBackground(args.background), (_c = args.isBackground) !== null && _c !== void 0 ? _c : false, args.chromaMultiplier, args.background, args.secondBackground, args.contrastCurve, args.toneDeltaPair);
882
+ }
883
+ static getInitialToneFromBackground(background) {
884
+ if (background === undefined) {
885
+ return (s) => 50;
886
+ }
887
+ return (s) => (background(s) ? background(s).getTone(s) : 50);
888
+ }
889
+ /**
890
+ * Given a background tone, finds a foreground tone, while ensuring they reach
891
+ * a contrast ratio that is as close to [ratio] as possible.
892
+ *
893
+ * @param bgTone Tone in HCT. Range is 0 to 100, undefined behavior when it
894
+ * falls outside that range.
895
+ * @param ratio The contrast ratio desired between bgTone and the return
896
+ * value.
897
+ */
898
+ static foregroundTone(bgTone, ratio) {
899
+ const lighterTone = materialColorUtilities.Contrast.lighterUnsafe(bgTone, ratio);
900
+ const darkerTone = materialColorUtilities.Contrast.darkerUnsafe(bgTone, ratio);
901
+ const lighterRatio = materialColorUtilities.Contrast.ratioOfTones(lighterTone, bgTone);
902
+ const darkerRatio = materialColorUtilities.Contrast.ratioOfTones(darkerTone, bgTone);
903
+ const preferLighter = DynamicColor.tonePrefersLightForeground(bgTone);
904
+ if (preferLighter) {
905
+ // This handles an edge case where the initial contrast ratio is high
906
+ // (ex. 13.0), and the ratio passed to the function is that high
907
+ // ratio, and both the lighter and darker ratio fails to pass that
908
+ // ratio.
909
+ //
910
+ // This was observed with Tonal Spot's On Primary Container turning
911
+ // black momentarily between high and max contrast in light mode. PC's
912
+ // standard tone was T90, OPC's was T10, it was light mode, and the
913
+ // contrast value was 0.6568521221032331.
914
+ const negligibleDifference = Math.abs(lighterRatio - darkerRatio) < 0.1 &&
915
+ lighterRatio < ratio &&
916
+ darkerRatio < ratio;
917
+ return lighterRatio >= ratio ||
918
+ lighterRatio >= darkerRatio ||
919
+ negligibleDifference
920
+ ? lighterTone
921
+ : darkerTone;
922
+ }
923
+ else {
924
+ return darkerRatio >= ratio || darkerRatio >= lighterRatio
925
+ ? darkerTone
926
+ : lighterTone;
927
+ }
928
+ }
929
+ /**
930
+ * Returns whether [tone] prefers a light foreground.
931
+ *
932
+ * People prefer white foregrounds on ~T60-70. Observed over time, and also
933
+ * by Andrew Somers during research for APCA.
934
+ *
935
+ * T60 used as to create the smallest discontinuity possible when skipping
936
+ * down to T49 in order to ensure light foregrounds.
937
+ * Since `tertiaryContainer` in dark monochrome scheme requires a tone of
938
+ * 60, it should not be adjusted. Therefore, 60 is excluded here.
939
+ */
940
+ static tonePrefersLightForeground(tone) {
941
+ return Math.round(tone) < 60.0;
942
+ }
943
+ /**
944
+ * Returns whether [tone] can reach a contrast ratio of 4.5 with a lighter
945
+ * color.
946
+ */
947
+ static toneAllowsLightForeground(tone) {
948
+ return Math.round(tone) <= 49.0;
949
+ }
950
+ /**
951
+ * Adjusts a tone such that white has 4.5 contrast, if the tone is
952
+ * reasonably close to supporting it.
953
+ */
954
+ static enableLightForeground(tone) {
955
+ if (DynamicColor.tonePrefersLightForeground(tone) &&
956
+ !DynamicColor.toneAllowsLightForeground(tone)) {
957
+ return 49.0;
958
+ }
959
+ return tone;
960
+ }
961
+ /**
962
+ * Returns a deep copy of this DynamicColor.
963
+ */
964
+ clone() {
965
+ return DynamicColor.fromPalette({
966
+ name: this.name,
967
+ palette: this.palette,
968
+ tone: this.tone,
969
+ isBackground: this.isBackground,
970
+ chromaMultiplier: this.chromaMultiplier,
971
+ background: this.background,
972
+ secondBackground: this.secondBackground,
973
+ contrastCurve: this.contrastCurve,
974
+ toneDeltaPair: this.toneDeltaPair,
975
+ });
976
+ }
977
+ /**
978
+ * Clears the cache of HCT values for this color. For testing or debugging
979
+ * purposes.
980
+ */
981
+ clearCache() {
982
+ this.hctCache.clear();
983
+ }
984
+ /**
985
+ * Returns a ARGB integer (i.e. a hex code).
986
+ *
987
+ * @param scheme Defines the conditions of the user interface, for example,
988
+ * whether or not it is dark mode or light mode, and what the desired
989
+ * contrast level is.
990
+ */
991
+ getArgb(scheme) {
992
+ return this.getHct(scheme).toInt();
993
+ }
994
+ /**
995
+ * Returns a color, expressed in the HCT color space, that this
996
+ * DynamicColor is under the conditions in scheme.
997
+ *
998
+ * @param scheme Defines the conditions of the user interface, for example,
999
+ * whether or not it is dark mode or light mode, and what the desired
1000
+ * contrast level is.
1001
+ */
1002
+ getHct(scheme) {
1003
+ const palette = this.palette(scheme);
1004
+ const tone = this.getTone(scheme);
1005
+ const hue = palette.hue;
1006
+ const chroma = palette.chroma *
1007
+ (this.chromaMultiplier ? this.chromaMultiplier(scheme) : 1);
1008
+ return Hct.from(hue, chroma, tone);
1009
+ }
1010
+ /**
1011
+ * Returns a tone, T in the HCT color space, that this DynamicColor is under
1012
+ * the conditions in scheme.
1013
+ *
1014
+ * @param scheme Defines the conditions of the user interface, for example,
1015
+ * whether or not it is dark mode or light mode, and what the desired
1016
+ * contrast level is.
1017
+ */
1018
+ getTone(scheme) {
1019
+ const toneDeltaPair = this.toneDeltaPair
1020
+ ? this.toneDeltaPair(scheme)
1021
+ : undefined;
1022
+ // Case 0: tone delta constraint.
1023
+ if (toneDeltaPair) {
1024
+ const roleA = toneDeltaPair.roleA;
1025
+ const roleB = toneDeltaPair.roleB;
1026
+ const polarity = toneDeltaPair.polarity;
1027
+ const constraint = toneDeltaPair.constraint;
1028
+ const absoluteDelta = polarity === 'darker' ||
1029
+ (polarity === 'relative_lighter' && scheme.isDark) ||
1030
+ (polarity === 'relative_darker' && !scheme.isDark)
1031
+ ? -toneDeltaPair.delta
1032
+ : toneDeltaPair.delta;
1033
+ const amRoleA = this.name === roleA.name;
1034
+ const selfRole = amRoleA ? roleA : roleB;
1035
+ const refRole = amRoleA ? roleB : roleA;
1036
+ let selfTone = selfRole.tone(scheme);
1037
+ const refTone = refRole.getTone(scheme);
1038
+ const relativeDelta = absoluteDelta * (amRoleA ? 1 : -1);
1039
+ if (constraint === 'exact') {
1040
+ selfTone = materialColorUtilities.clampDouble(0, 100, refTone + relativeDelta);
1041
+ }
1042
+ else if (constraint === 'nearer') {
1043
+ if (relativeDelta > 0) {
1044
+ selfTone = materialColorUtilities.clampDouble(0, 100, materialColorUtilities.clampDouble(refTone, refTone + relativeDelta, selfTone));
1045
+ }
1046
+ else {
1047
+ selfTone = materialColorUtilities.clampDouble(0, 100, materialColorUtilities.clampDouble(refTone + relativeDelta, refTone, selfTone));
1048
+ }
1049
+ }
1050
+ else if (constraint === 'farther') {
1051
+ if (relativeDelta > 0) {
1052
+ selfTone = materialColorUtilities.clampDouble(refTone + relativeDelta, 100, selfTone);
1053
+ }
1054
+ else {
1055
+ selfTone = materialColorUtilities.clampDouble(0, refTone + relativeDelta, selfTone);
1056
+ }
1057
+ }
1058
+ if (this.background && this.contrastCurve) {
1059
+ const background = this.background(scheme);
1060
+ const contrastCurve = this.contrastCurve(scheme);
1061
+ if (background && contrastCurve) {
1062
+ // Adjust the tones for contrast, if background and contrast curve
1063
+ // are defined.
1064
+ const bgTone = background.getTone(scheme);
1065
+ const selfContrast = contrastCurve.get(scheme.contrastLevel);
1066
+ selfTone =
1067
+ materialColorUtilities.Contrast.ratioOfTones(bgTone, selfTone) >= selfContrast &&
1068
+ scheme.contrastLevel >= 0
1069
+ ? selfTone
1070
+ : DynamicColor.foregroundTone(bgTone, selfContrast);
1071
+ }
1072
+ }
1073
+ // This can avoid the awkward tones for background colors including the
1074
+ // access fixed colors. Accent fixed dim colors should not be adjusted.
1075
+ if (this.isBackground && !this.name.endsWith('_fixed_dim')) {
1076
+ if (selfTone >= 57) {
1077
+ selfTone = materialColorUtilities.clampDouble(65, 100, selfTone);
1078
+ }
1079
+ else {
1080
+ selfTone = materialColorUtilities.clampDouble(0, 49, selfTone);
1081
+ }
1082
+ }
1083
+ return selfTone;
1084
+ }
1085
+ else {
1086
+ // Case 1: No tone delta pair; just solve for itself.
1087
+ let answer = this.tone(scheme);
1088
+ if (this.background == undefined ||
1089
+ this.background(scheme) === undefined ||
1090
+ this.contrastCurve == undefined ||
1091
+ this.contrastCurve(scheme) === undefined) {
1092
+ return answer; // No adjustment for colors with no background.
1093
+ }
1094
+ const bgTone = this.background(scheme).getTone(scheme);
1095
+ const desiredRatio = this.contrastCurve(scheme).get(scheme.contrastLevel);
1096
+ // Recalculate the tone from desired contrast ratio if the current
1097
+ // contrast ratio is not enough or desired contrast level is decreasing
1098
+ // (<0).
1099
+ answer =
1100
+ materialColorUtilities.Contrast.ratioOfTones(bgTone, answer) >= desiredRatio &&
1101
+ scheme.contrastLevel >= 0
1102
+ ? answer
1103
+ : DynamicColor.foregroundTone(bgTone, desiredRatio);
1104
+ // This can avoid the awkward tones for background colors including the
1105
+ // access fixed colors. Accent fixed dim colors should not be adjusted.
1106
+ if (this.isBackground && !this.name.endsWith('_fixed_dim')) {
1107
+ if (answer >= 57) {
1108
+ answer = materialColorUtilities.clampDouble(65, 100, answer);
1109
+ }
1110
+ else {
1111
+ answer = materialColorUtilities.clampDouble(0, 49, answer);
1112
+ }
1113
+ }
1114
+ if (this.secondBackground == undefined ||
1115
+ this.secondBackground(scheme) === undefined) {
1116
+ return answer;
1117
+ }
1118
+ // Case 2: Adjust for dual backgrounds.
1119
+ const [bg1, bg2] = [this.background, this.secondBackground];
1120
+ const [bgTone1, bgTone2] = [
1121
+ bg1(scheme).getTone(scheme),
1122
+ bg2(scheme).getTone(scheme),
1123
+ ];
1124
+ const [upper, lower] = [
1125
+ Math.max(bgTone1, bgTone2),
1126
+ Math.min(bgTone1, bgTone2),
1127
+ ];
1128
+ if (materialColorUtilities.Contrast.ratioOfTones(upper, answer) >= desiredRatio &&
1129
+ materialColorUtilities.Contrast.ratioOfTones(lower, answer) >= desiredRatio) {
1130
+ return answer;
1131
+ }
1132
+ // The darkest light tone that satisfies the desired ratio,
1133
+ // or -1 if such ratio cannot be reached.
1134
+ const lightOption = materialColorUtilities.Contrast.lighter(upper, desiredRatio);
1135
+ // The lightest dark tone that satisfies the desired ratio,
1136
+ // or -1 if such ratio cannot be reached.
1137
+ const darkOption = materialColorUtilities.Contrast.darker(lower, desiredRatio);
1138
+ // Tones suitable for the foreground.
1139
+ const availables = [];
1140
+ if (lightOption !== -1)
1141
+ availables.push(lightOption);
1142
+ if (darkOption !== -1)
1143
+ availables.push(darkOption);
1144
+ const prefersLight = DynamicColor.tonePrefersLightForeground(bgTone1) ||
1145
+ DynamicColor.tonePrefersLightForeground(bgTone2);
1146
+ if (prefersLight) {
1147
+ return lightOption < 0 ? 100 : lightOption;
1148
+ }
1149
+ if (availables.length === 1) {
1150
+ return availables[0];
1151
+ }
1152
+ return darkOption < 0 ? 0 : darkOption;
1153
+ }
1154
+ }
1155
+ }
1156
+
1157
+ /**
1158
+ * @license
1159
+ * Copyright 2023 Google LLC
1160
+ *
1161
+ * Licensed under the Apache License, Version 2.0 (the "License");
1162
+ * you may not use this file except in compliance with the License.
1163
+ * You may obtain a copy of the License at
1164
+ *
1165
+ * http://www.apache.org/licenses/LICENSE-2.0
1166
+ *
1167
+ * Unless required by applicable law or agreed to in writing, software
1168
+ * distributed under the License is distributed on an "AS IS" BASIS,
1169
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1170
+ * See the License for the specific language governing permissions and
1171
+ * limitations under the License.
1172
+ */
1173
+ /**
1174
+ * Documents a constraint between two DynamicColors, in which their tones must
1175
+ * have a certain distance from each other.
1176
+ *
1177
+ * Prefer a DynamicColor with a background, this is for special cases when
1178
+ * designers want tonal distance, literally contrast, between two colors that
1179
+ * don't have a background / foreground relationship or a contrast guarantee.
1180
+ */
1181
+ class ToneDeltaPair {
1182
+ /**
1183
+ * Documents a constraint in tone distance between two DynamicColors.
1184
+ *
1185
+ * The polarity is an adjective that describes "A", compared to "B".
1186
+ *
1187
+ * For instance, ToneDeltaPair(A, B, 15, 'darker', 'exact') states that
1188
+ * A's tone should be exactly 15 darker than B's.
1189
+ *
1190
+ * 'relative_darker' and 'relative_lighter' describes the tone adjustment
1191
+ * relative to the surface color trend (white in light mode; black in dark
1192
+ * mode). For instance, ToneDeltaPair(A, B, 10, 'relative_lighter',
1193
+ * 'farther') states that A should be at least 10 lighter than B in light
1194
+ * mode, and at least 10 darker than B in dark mode.
1195
+ *
1196
+ * @param roleA The first role in a pair.
1197
+ * @param roleB The second role in a pair.
1198
+ * @param delta Required difference between tones. Absolute value, negative
1199
+ * values have undefined behavior.
1200
+ * @param polarity The relative relation between tones of roleA and roleB,
1201
+ * as described above.
1202
+ * @param constraint How to fulfill the tone delta pair constraint.
1203
+ * @param stayTogether Whether these two roles should stay on the same side
1204
+ * of the "awkward zone" (T50-59). This is necessary for certain cases where
1205
+ * one role has two backgrounds.
1206
+ */
1207
+ constructor(roleA, roleB, delta, polarity, stayTogether, constraint) {
1208
+ this.roleA = roleA;
1209
+ this.roleB = roleB;
1210
+ this.delta = delta;
1211
+ this.polarity = polarity;
1212
+ this.stayTogether = stayTogether;
1213
+ this.constraint = constraint;
1214
+ this.constraint = constraint !== null && constraint !== void 0 ? constraint : 'exact';
1215
+ }
1216
+ }
1217
+
1218
+ function argbToRgb(argb) {
1219
+ return {
1220
+ r: (argb >> 16) & 0xff,
1221
+ g: (argb >> 8) & 0xff,
1222
+ b: argb & 0xff,
1223
+ };
1224
+ }
1225
+ class ConfigurableColor {
1226
+ constructor(option, schemeService, colorService) {
1227
+ this.option = option;
1228
+ this.schemeService = schemeService;
1229
+ this.colorService = colorService;
1230
+ this.dynamicColor = null;
1231
+ }
1232
+ update(args) {
1233
+ this.dynamicColor = null;
1234
+ this.option = Object.assign(Object.assign({}, this.option), args);
1235
+ }
1236
+ getHex() {
1237
+ return materialColorUtilities.hexFromArgb(this.getArgb());
1238
+ }
1239
+ getArgb() {
1240
+ return this.getMaterialColor().getArgb(this.schemeService.get());
1241
+ }
1242
+ getRgb() {
1243
+ return argbToRgb(this.getArgb());
1244
+ }
1245
+ getName() {
1246
+ return this.option.name.replace(/([A-Z])/g, '_$1').toLowerCase();
1247
+ }
1248
+ getMaterialColor() {
1249
+ if ('alias' in this.option) {
1250
+ if (!this.option.alias) {
1251
+ throw new Error('Alias option must be defined');
1252
+ }
1253
+ return this.colorService.get(this.option.alias).getMaterialColor();
1254
+ }
1255
+ if (!this.dynamicColor) {
1256
+ this.dynamicColor = DynamicColor.fromPalette(Object.assign(Object.assign({}, this.option), { name: this.getName() }));
1257
+ }
1258
+ return this.dynamicColor;
1259
+ }
1260
+ }
1261
+
1262
+ function getCurve(defaultContrast) {
1263
+ if (defaultContrast === 1.5) {
1264
+ return new ContrastCurve(1.5, 1.5, 3, 4.5);
1265
+ }
1266
+ else if (defaultContrast === 3) {
1267
+ return new ContrastCurve(3, 3, 4.5, 7);
1268
+ }
1269
+ else if (defaultContrast === 4.5) {
1270
+ return new ContrastCurve(4.5, 4.5, 7, 11);
1271
+ }
1272
+ else if (defaultContrast === 6) {
1273
+ return new ContrastCurve(6, 6, 7, 11);
1274
+ }
1275
+ else if (defaultContrast === 7) {
1276
+ return new ContrastCurve(7, 7, 11, 21);
1277
+ }
1278
+ else if (defaultContrast === 9) {
1279
+ return new ContrastCurve(9, 9, 11, 21);
1280
+ }
1281
+ else if (defaultContrast === 11) {
1282
+ return new ContrastCurve(11, 11, 21, 21);
1283
+ }
1284
+ else if (defaultContrast === 21) {
1285
+ return new ContrastCurve(21, 21, 21, 21);
1286
+ }
1287
+ else {
1288
+ // Shouldn't happen.
1289
+ return new ContrastCurve(defaultContrast, defaultContrast, 7, 21);
1290
+ }
1291
+ }
1292
+ function tMaxC(palette, lowerBound = 0, upperBound = 100, chromaMultiplier = 1) {
1293
+ const answer = findBestToneForChroma(palette.hue, palette.chroma * chromaMultiplier, 100, true);
1294
+ return materialColorUtilities.clampDouble(lowerBound, upperBound, answer);
1295
+ }
1296
+ function tMinC(palette, lowerBound = 0, upperBound = 100) {
1297
+ const answer = findBestToneForChroma(palette.hue, palette.chroma, 0, false);
1298
+ return materialColorUtilities.clampDouble(lowerBound, upperBound, answer);
1299
+ }
1300
+ function findBestToneForChroma(hue, chroma, tone, byDecreasingTone) {
1301
+ let answer = tone;
1302
+ let bestCandidate = Hct.from(hue, chroma, answer);
1303
+ while (bestCandidate.chroma < chroma) {
1304
+ if (tone < 0 || tone > 100) {
1305
+ break;
1306
+ }
1307
+ tone += byDecreasingTone ? -1 : 1.0;
1308
+ const newCandidate = Hct.from(hue, chroma, tone);
1309
+ if (bestCandidate.chroma < newCandidate.chroma) {
1310
+ bestCandidate = newCandidate;
1311
+ answer = tone;
1312
+ }
1313
+ }
1314
+ return answer;
1315
+ }
1316
+
1317
+ function capitalizeFirstLetter(string) {
1318
+ return string.charAt(0).toUpperCase() + string.slice(1);
1319
+ }
1320
+ const highestSurface = (s, colorService) => {
1321
+ if (colorService instanceof ColorApi) {
1322
+ return s.isDark
1323
+ ? colorService.getColor('surfaceBright').getMaterialColor()
1324
+ : colorService.getColor('surfaceDim').getMaterialColor();
1325
+ }
1326
+ else {
1327
+ return s.isDark
1328
+ ? colorService.get('surfaceBright').getMaterialColor()
1329
+ : colorService.get('surfaceDim').getMaterialColor();
1330
+ }
1331
+ };
1332
+ class ColorManager {
1333
+ constructor({ schemeManager }) {
1334
+ this.colorMap = new Map();
1335
+ this.schemeManager = schemeManager;
1336
+ }
1337
+ createOrUpdate(key, args) {
1338
+ let colorEntity = this.colorMap.get(key);
1339
+ if (!colorEntity) {
1340
+ const { palette, alias } = args;
1341
+ if (palette) {
1342
+ colorEntity = new ConfigurableColor(Object.assign(Object.assign({}, args), { palette: palette, name: key }), this.schemeManager, this);
1343
+ this.colorMap.set(key, colorEntity);
1344
+ }
1345
+ else if (alias) {
1346
+ colorEntity = new ConfigurableColor(Object.assign(Object.assign({}, args), { alias: alias, name: key }), this.schemeManager, this);
1347
+ this.colorMap.set(key, colorEntity);
1348
+ }
1349
+ else {
1350
+ throw new Error(`Palette ${palette} does not exist from ${key}`);
1351
+ }
1352
+ }
1353
+ else {
1354
+ colorEntity.update(Object.assign(Object.assign({}, args), { name: key }));
1355
+ this.colorMap.set(key, colorEntity);
1356
+ }
1357
+ return colorEntity;
1358
+ }
1359
+ remove(key) {
1360
+ return this.colorMap.delete(key);
1361
+ }
1362
+ get(key) {
1363
+ const colorEntity = this.colorMap.get(key);
1364
+ if (colorEntity) {
1365
+ return colorEntity;
1366
+ }
1367
+ else {
1368
+ throw new Error(`Color ${key} does not exist`);
1369
+ }
1370
+ }
1371
+ getAll() {
1372
+ return this.colorMap;
1373
+ }
1374
+ addFromPalette(key) {
1375
+ const colorKey = key;
1376
+ const colorDimKey = (colorKey + 'Dim');
1377
+ const ColorKey = capitalizeFirstLetter(key);
1378
+ const onColorKey = ('on' + ColorKey);
1379
+ const colorContainerKey = (colorKey + 'Container');
1380
+ const onColorContainerKey = ('on' +
1381
+ ColorKey +
1382
+ 'Container');
1383
+ const colorFixedKey = (colorKey + 'Fixed');
1384
+ const colorFixedDimKey = (colorKey + 'FixedDim');
1385
+ const onColorFixedKey = ('on' + ColorKey + 'Fixed');
1386
+ const onColorFixedVariantKey = ('on' +
1387
+ ColorKey +
1388
+ 'FixedVariant');
1389
+ this.createOrUpdate(colorKey, {
1390
+ palette: (s) => s.getPalette(colorKey),
1391
+ tone: (s) => {
1392
+ if (s.variant === 'neutral') {
1393
+ return s.isDark
1394
+ ? tMinC(s.getPalette(colorKey), 0, 98)
1395
+ : tMaxC(s.getPalette(colorKey));
1396
+ }
1397
+ else if (s.variant === 'vibrant') {
1398
+ return tMaxC(s.getPalette(colorKey), 0, s.isDark ? 90 : 98);
1399
+ }
1400
+ else {
1401
+ return s.isDark ? 80 : tMaxC(s.getPalette(colorKey));
1402
+ }
1403
+ },
1404
+ isBackground: true,
1405
+ background: (s) => highestSurface(s, this),
1406
+ contrastCurve: (s) => getCurve(4.5),
1407
+ toneDeltaPair: (s) => new ToneDeltaPair(this.get(colorContainerKey).getMaterialColor(), this.get(colorKey).getMaterialColor(), 5, 'relative_lighter', true, 'farther'),
1408
+ });
1409
+ this.createOrUpdate(colorDimKey, {
1410
+ palette: (s) => s.getPalette(colorKey),
1411
+ tone: (s) => {
1412
+ if (s.variant === 'neutral') {
1413
+ return 85;
1414
+ }
1415
+ else {
1416
+ return tMaxC(s.getPalette(colorKey), 0, 90);
1417
+ }
1418
+ },
1419
+ isBackground: true,
1420
+ background: (s) => this.get('surfaceContainerHigh').getMaterialColor(),
1421
+ contrastCurve: (s) => getCurve(4.5),
1422
+ toneDeltaPair: (s) => new ToneDeltaPair(this.get(colorDimKey).getMaterialColor(), this.get(colorKey).getMaterialColor(), 5, 'darker', true, 'farther'),
1423
+ });
1424
+ this.createOrUpdate(onColorKey, {
1425
+ palette: (s) => s.getPalette(colorKey),
1426
+ background: (s) => this.get(colorKey).getMaterialColor(),
1427
+ contrastCurve: (s) => getCurve(6),
1428
+ });
1429
+ this.createOrUpdate(colorContainerKey, {
1430
+ palette: (s) => s.getPalette(colorKey),
1431
+ tone: (s) => {
1432
+ if (s.variant === 'vibrant') {
1433
+ return s.isDark
1434
+ ? tMinC(s.getPalette(colorKey), 30, 40)
1435
+ : tMaxC(s.getPalette(colorKey), 84, 90);
1436
+ }
1437
+ else if (s.variant === 'expressive') {
1438
+ return s.isDark ? 15 : tMaxC(s.getPalette(colorKey), 90, 95);
1439
+ }
1440
+ else {
1441
+ return s.isDark ? 25 : 90;
1442
+ }
1443
+ },
1444
+ isBackground: true,
1445
+ background: (s) => highestSurface(s, this),
1446
+ toneDeltaPair: (s) => undefined,
1447
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
1448
+ });
1449
+ this.createOrUpdate(onColorContainerKey, {
1450
+ palette: (s) => s.getPalette(colorKey),
1451
+ background: (s) => this.get(colorContainerKey).getMaterialColor(),
1452
+ contrastCurve: (s) => getCurve(6),
1453
+ });
1454
+ this.createOrUpdate(colorFixedKey, {
1455
+ palette: (s) => s.getPalette(colorKey),
1456
+ tone: (s) => {
1457
+ const tempS = Object.assign({}, s, { isDark: false, contrastLevel: 0 });
1458
+ return this.get(colorContainerKey).getMaterialColor().getTone(tempS);
1459
+ },
1460
+ isBackground: true,
1461
+ background: (s) => highestSurface(s, this),
1462
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
1463
+ });
1464
+ this.createOrUpdate(colorFixedDimKey, {
1465
+ palette: (s) => s.getPalette(colorKey),
1466
+ tone: (s) => this.get(colorFixedKey).getMaterialColor().getTone(s),
1467
+ isBackground: true,
1468
+ toneDeltaPair: (s) => new ToneDeltaPair(this.get(colorFixedDimKey).getMaterialColor(), this.get(colorFixedKey).getMaterialColor(), 5, 'darker', true, 'exact'),
1469
+ });
1470
+ this.createOrUpdate(onColorFixedKey, {
1471
+ palette: (s) => s.getPalette(colorKey),
1472
+ background: (s) => this.get(colorFixedDimKey).getMaterialColor(),
1473
+ contrastCurve: (s) => getCurve(7),
1474
+ });
1475
+ this.createOrUpdate(onColorFixedVariantKey, {
1476
+ palette: (s) => s.getPalette(colorKey),
1477
+ background: (s) => this.get(colorFixedDimKey).getMaterialColor(),
1478
+ contrastCurve: (s) => getCurve(4.5),
1479
+ });
1480
+ }
1481
+ }
1482
+
1483
+ const ColorModule = {
1484
+ colorManager: awilix.asClass(ColorManager).singleton(),
1485
+ colorApi: awilix.asClass(ColorApi).singleton(),
1486
+ };
1487
+
1488
+ class Scheme {
1489
+ constructor(options) {
1490
+ this.options = options;
1491
+ }
1492
+ get variant() {
1493
+ return this.options.variant.name;
1494
+ }
1495
+ get contrastLevel() {
1496
+ if (!this.options) {
1497
+ throw new Error('Scheme options is not set');
1498
+ }
1499
+ return this.options.contrastLevel;
1500
+ }
1501
+ get isDark() {
1502
+ if (!this.options) {
1503
+ throw new Error('Scheme options is not set');
1504
+ }
1505
+ return this.options.isDark;
1506
+ }
1507
+ get sourceColorHct() {
1508
+ if (!this.options) {
1509
+ throw new Error('Scheme options is not set');
1510
+ }
1511
+ return Hct.fromInt(this.options.sourceColorArgb);
1512
+ }
1513
+ getPalette(key) {
1514
+ if (!this.options) {
1515
+ throw new Error('Scheme options is not set');
1516
+ }
1517
+ const palette = this.options.palettes.get(key);
1518
+ if (!palette) {
1519
+ throw new Error(`Palette ${key} not found`);
1520
+ }
1521
+ return palette;
1522
+ }
1523
+ }
1524
+
1525
+ class SchemeManager {
1526
+ createOrUpdate(options) {
1527
+ var _a, _b, _c, _d;
1528
+ this.options = Object.assign(Object.assign(Object.assign({}, this.options), options), { sourcesColorHex: Object.assign(Object.assign({}, (_a = this.options) === null || _a === void 0 ? void 0 : _a.sourcesColorHex), options.sourcesColorHex), palettes: Object.assign(Object.assign({}, (_b = this.options) === null || _b === void 0 ? void 0 : _b.palettes), options.palettes) });
1529
+ const palettes = new Map();
1530
+ if (!this.options.sourcesColorHex.primary) {
1531
+ throw new Error('Primary source color is not set');
1532
+ }
1533
+ const sourceColorArgb = materialColorUtilities.argbFromHex(this.options.sourcesColorHex.primary);
1534
+ const sourceColorHct = Hct.fromInt(sourceColorArgb);
1535
+ if (!this.options.palettes) {
1536
+ return;
1537
+ }
1538
+ for (const [key, { sourceColorkey, tonalPalette: paletteFunction },] of Object.entries(this.options.palettes)) {
1539
+ let palette;
1540
+ if (typeof sourceColorkey != 'string') {
1541
+ palette = paletteFunction({
1542
+ sourceColorHct: sourceColorHct,
1543
+ isDark: (_c = options.isDark) !== null && _c !== void 0 ? _c : false,
1544
+ });
1545
+ }
1546
+ else {
1547
+ const sourceColorArgb = materialColorUtilities.argbFromHex(this.options.sourcesColorHex[sourceColorkey]);
1548
+ const colorHct = Hct.fromInt(sourceColorArgb);
1549
+ palette = paletteFunction({
1550
+ sourceColorHct: sourceColorHct,
1551
+ colorHct: colorHct,
1552
+ isDark: (_d = options.isDark) !== null && _d !== void 0 ? _d : false,
1553
+ });
1554
+ }
1555
+ palettes.set(key, palette);
1556
+ }
1557
+ this.schemeEntity = new Scheme(Object.assign(Object.assign({}, this.options), { palettes: palettes, sourceColorArgb: sourceColorArgb }));
1558
+ }
1559
+ get() {
1560
+ if (!this.schemeEntity) {
1561
+ throw new Error('Scheme is not created');
1562
+ }
1563
+ return this.schemeEntity;
1564
+ }
1565
+ }
1566
+
1567
+ class VariantManager {
1568
+ constructor({ schemeManager }) {
1569
+ this.customPalettes = {};
1570
+ this.schemeManager = schemeManager;
1571
+ }
1572
+ addCustomPalette(key, colorHex) {
1573
+ this.customPalettes[key] = colorHex;
1574
+ this.update();
1575
+ }
1576
+ set(variantEntity) {
1577
+ this.variantEntity = variantEntity;
1578
+ this.update();
1579
+ }
1580
+ update() {
1581
+ if (!this.variantEntity)
1582
+ return;
1583
+ const palettes = {};
1584
+ Object.keys(this.variantEntity.palettes).forEach((key) => {
1585
+ palettes[key] = { tonalPalette: this.variantEntity.palettes[key] };
1586
+ });
1587
+ const customPalettes = this.variantEntity.customPalettes;
1588
+ if (customPalettes) {
1589
+ Object.keys(this.customPalettes).forEach((key) => {
1590
+ palettes[key] = {
1591
+ sourceColorkey: key,
1592
+ tonalPalette: customPalettes,
1593
+ };
1594
+ });
1595
+ }
1596
+ this.schemeManager.createOrUpdate({
1597
+ sourcesColorHex: this.customPalettes,
1598
+ palettes: palettes,
1599
+ });
1600
+ }
1601
+ }
1602
+
1603
+ materialColorUtilities.DynamicColor.fromPalette({
1604
+ name: 'primary_palette_key_color',
1605
+ palette: (s) => s.primaryPalette,
1606
+ tone: (s) => s.primaryPalette.keyColor.tone,
1607
+ });
1608
+ class ThemeApi {
1609
+ constructor({ schemeManager, variantManager, }) {
1610
+ this.schemeManager = schemeManager;
1611
+ this.variantManager = variantManager;
1612
+ // this.addPalette({key: "primary", addDefaultColors: true})
1613
+ // this.addPalette({key: "secondary", addDefaultColors: true})
1614
+ // this.addPalette({key: "tertiary", addDefaultColors: true})
1615
+ // this.addPalette({key: "error", palette: TonalPalette.fromHueAndChroma(25.0, 84.0)})
1616
+ // this.addPalette({key: "neutral"})
1617
+ // this.addPalette({key: "neutralVariant"})
1618
+ }
1619
+ // addPalette({key, palette, addDefaultColors}: {key: string; palette: TonalPalette; addDefaultColors: boolean}) {
1620
+ // this.themeOptions.palettes.set(key, palette);
1621
+ // if (addDefaultColors){
1622
+ // this.colorService.addPalette(key)
1623
+ // }
1624
+ // }
1625
+ // create(args: ThemeOptions): SchemeService {
1626
+ // return new SchemeService(args, this.colorService)
1627
+ // }
1628
+ //
1629
+ // update(options: Partial<ThemeOptions>): SchemeService {
1630
+ // Object.assign(this.themeOptions, options);
1631
+ // return this.theme();
1632
+ // }
1633
+ create(options) {
1634
+ this.schemeManager.createOrUpdate(Object.assign(Object.assign({}, options), { sourcesColorHex: { primary: options.sourceColorHex } }));
1635
+ this.variantManager.set(options.variant);
1636
+ }
1637
+ update(options) {
1638
+ const themeOptions = Object.assign({}, options);
1639
+ if (options.sourceColorHex)
1640
+ themeOptions.sourcesColorHex = { primary: options.sourceColorHex };
1641
+ this.schemeManager.createOrUpdate(themeOptions);
1642
+ if (options.variant)
1643
+ this.variantManager.set(options.variant);
1644
+ }
1645
+ addCustomPalette(key, colorHex) {
1646
+ this.variantManager.addCustomPalette(key, colorHex);
1647
+ }
1648
+ }
1649
+
1650
+ const ThemeModule = {
1651
+ schemeManager: awilix.asClass(SchemeManager).singleton(),
1652
+ variantManager: awilix.asClass(VariantManager).singleton(),
1653
+ themeApi: awilix.asClass(ThemeApi).singleton(),
1654
+ };
1655
+
1656
+ const getPiecewiseHue = (sourceColorHct, hueBreakpoints, hues) => {
1657
+ const size = Math.min(hueBreakpoints.length - 1, hues.length);
1658
+ const sourceHue = sourceColorHct.hue;
1659
+ for (let i = 0; i < size; i++) {
1660
+ if (sourceHue >= hueBreakpoints[i] && sourceHue < hueBreakpoints[i + 1]) {
1661
+ return materialColorUtilities.sanitizeDegreesDouble(hues[i]);
1662
+ }
1663
+ }
1664
+ return sourceHue;
1665
+ };
1666
+ const getRotatedHue = (sourceColorHct, hueBreakpoints, rotations) => {
1667
+ let rotation = getPiecewiseHue(sourceColorHct, hueBreakpoints, rotations);
1668
+ if (Math.min(hueBreakpoints.length - 1, rotations.length) <= 0) {
1669
+ rotation = 0;
1670
+ }
1671
+ return materialColorUtilities.sanitizeDegreesDouble(sourceColorHct.hue + rotation);
1672
+ };
1673
+ class Variant {
1674
+ constructor(palettes = {}, name, customPalettes,
1675
+ /** TODO
1676
+ * Defines color modifications through variation.
1677
+ * Allows customization of specific colors in the theme.
1678
+ */
1679
+ colors) {
1680
+ this.palettes = palettes;
1681
+ this.name = name;
1682
+ this.customPalettes = customPalettes;
1683
+ this.colors = colors;
1684
+ }
1685
+ }
1686
+
1687
+ const defaultColors = (colorService) => {
1688
+ const getColor = (key) => {
1689
+ return colorService.getColor(key).getMaterialColor();
1690
+ };
1691
+ const colors = {
1692
+ ////////////////////////////////////////////////////////////////
1693
+ // Surfaces [S] //
1694
+ ////////////////////////////////////////////////////////////////
1695
+ surface: {
1696
+ palette: (s) => s.getPalette('neutral'),
1697
+ tone: (s) => {
1698
+ if (s.isDark) {
1699
+ return 4;
1700
+ }
1701
+ else {
1702
+ if (Hct.isYellow(s.getPalette('neutral').hue)) {
1703
+ return 99;
1704
+ }
1705
+ else if (s.variant === 'vibrant') {
1706
+ return 97;
1707
+ }
1708
+ else {
1709
+ return 98;
1710
+ }
1711
+ }
1712
+ },
1713
+ isBackground: true,
1714
+ },
1715
+ surfaceDim: {
1716
+ palette: (s) => s.getPalette('neutral'),
1717
+ tone: (s) => {
1718
+ if (s.isDark) {
1719
+ return 4;
1720
+ }
1721
+ else {
1722
+ if (Hct.isYellow(s.getPalette('neutral').hue)) {
1723
+ return 90;
1724
+ }
1725
+ else if (s.variant === 'vibrant') {
1726
+ return 85;
1727
+ }
1728
+ else {
1729
+ return 87;
1730
+ }
1731
+ }
1732
+ },
1733
+ isBackground: true,
1734
+ chromaMultiplier: (s) => {
1735
+ if (!s.isDark) {
1736
+ if (s.variant === 'neutral') {
1737
+ return 2.5;
1738
+ }
1739
+ else if (s.variant === 'tonalSpot') {
1740
+ return 1.7;
1741
+ }
1742
+ else if (s.variant === 'expressive') {
1743
+ return Hct.isYellow(s.getPalette('neutral').hue) ? 2.7 : 1.75;
1744
+ }
1745
+ else if (s.variant === 'vibrant') {
1746
+ return 1.36;
1747
+ }
1748
+ }
1749
+ return 1;
1750
+ },
1751
+ },
1752
+ surfaceBright: {
1753
+ palette: (s) => s.getPalette('neutral'),
1754
+ tone: (s) => {
1755
+ if (s.isDark) {
1756
+ return 18;
1757
+ }
1758
+ else {
1759
+ if (Hct.isYellow(s.getPalette('neutral').hue)) {
1760
+ return 99;
1761
+ }
1762
+ else if (s.variant === 'vibrant') {
1763
+ return 97;
1764
+ }
1765
+ else {
1766
+ return 98;
1767
+ }
1768
+ }
1769
+ },
1770
+ isBackground: true,
1771
+ chromaMultiplier: (s) => {
1772
+ if (s.isDark) {
1773
+ if (s.variant === 'neutral') {
1774
+ return 2.5;
1775
+ }
1776
+ else if (s.variant === 'tonalSpot') {
1777
+ return 1.7;
1778
+ }
1779
+ else if (s.variant === 'expressive') {
1780
+ return Hct.isYellow(s.getPalette('neutral').hue) ? 2.7 : 1.75;
1781
+ }
1782
+ else if (s.variant === 'vibrant') {
1783
+ return 1.36;
1784
+ }
1785
+ }
1786
+ return 1;
1787
+ },
1788
+ },
1789
+ surfaceContainerLowest: {
1790
+ palette: (s) => s.getPalette('neutral'),
1791
+ tone: (s) => (s.isDark ? 0 : 100),
1792
+ isBackground: true,
1793
+ },
1794
+ surfaceContainerLow: {
1795
+ palette: (s) => s.getPalette('neutral'),
1796
+ tone: (s) => {
1797
+ if (s.isDark) {
1798
+ return 6;
1799
+ }
1800
+ else {
1801
+ if (Hct.isYellow(s.getPalette('neutral').hue)) {
1802
+ return 98;
1803
+ }
1804
+ else if (s.variant === 'vibrant') {
1805
+ return 95;
1806
+ }
1807
+ else {
1808
+ return 96;
1809
+ }
1810
+ }
1811
+ },
1812
+ isBackground: true,
1813
+ chromaMultiplier: (s) => {
1814
+ if (s.variant === 'neutral') {
1815
+ return 1.3;
1816
+ }
1817
+ else if (s.variant === 'tonalSpot') {
1818
+ return 1.25;
1819
+ }
1820
+ else if (s.variant === 'expressive') {
1821
+ return Hct.isYellow(s.getPalette('neutral').hue) ? 1.3 : 1.15;
1822
+ }
1823
+ else if (s.variant === 'vibrant') {
1824
+ return 1.08;
1825
+ }
1826
+ return 1;
1827
+ },
1828
+ },
1829
+ surfaceContainer: {
1830
+ palette: (s) => s.getPalette('neutral'),
1831
+ tone: (s) => {
1832
+ if (s.isDark) {
1833
+ return 9;
1834
+ }
1835
+ else {
1836
+ if (Hct.isYellow(s.getPalette('neutral').hue)) {
1837
+ return 96;
1838
+ }
1839
+ else if (s.variant === 'vibrant') {
1840
+ return 92;
1841
+ }
1842
+ else {
1843
+ return 94;
1844
+ }
1845
+ }
1846
+ },
1847
+ isBackground: true,
1848
+ chromaMultiplier: (s) => {
1849
+ if (s.variant === 'neutral') {
1850
+ return 1.6;
1851
+ }
1852
+ else if (s.variant === 'tonalSpot') {
1853
+ return 1.4;
1854
+ }
1855
+ else if (s.variant === 'expressive') {
1856
+ return Hct.isYellow(s.getPalette('neutral').hue) ? 1.6 : 1.3;
1857
+ }
1858
+ else if (s.variant === 'vibrant') {
1859
+ return 1.15;
1860
+ }
1861
+ return 1;
1862
+ },
1863
+ },
1864
+ surfaceContainerHigh: {
1865
+ palette: (s) => s.getPalette('neutral'),
1866
+ tone: (s) => {
1867
+ if (s.isDark) {
1868
+ return 12;
1869
+ }
1870
+ else {
1871
+ if (Hct.isYellow(s.getPalette('neutral').hue)) {
1872
+ return 94;
1873
+ }
1874
+ else if (s.variant === 'vibrant') {
1875
+ return 90;
1876
+ }
1877
+ else {
1878
+ return 92;
1879
+ }
1880
+ }
1881
+ },
1882
+ isBackground: true,
1883
+ chromaMultiplier: (s) => {
1884
+ if (s.variant === 'neutral') {
1885
+ return 1.9;
1886
+ }
1887
+ else if (s.variant === 'tonalSpot') {
1888
+ return 1.5;
1889
+ }
1890
+ else if (s.variant === 'expressive') {
1891
+ return Hct.isYellow(s.getPalette('neutral').hue) ? 1.95 : 1.45;
1892
+ }
1893
+ else if (s.variant === 'vibrant') {
1894
+ return 1.22;
1895
+ }
1896
+ return 1;
1897
+ },
1898
+ },
1899
+ surfaceContainerHighest: {
1900
+ palette: (s) => s.getPalette('neutral'),
1901
+ tone: (s) => {
1902
+ if (s.isDark) {
1903
+ return 15;
1904
+ }
1905
+ else {
1906
+ if (Hct.isYellow(s.getPalette('neutral').hue)) {
1907
+ return 92;
1908
+ }
1909
+ else if (s.variant === 'vibrant') {
1910
+ return 88;
1911
+ }
1912
+ else {
1913
+ return 90;
1914
+ }
1915
+ }
1916
+ },
1917
+ isBackground: true,
1918
+ chromaMultiplier: (s) => {
1919
+ if (s.variant === 'neutral') {
1920
+ return 2.2;
1921
+ }
1922
+ else if (s.variant === 'tonalSpot') {
1923
+ return 1.7;
1924
+ }
1925
+ else if (s.variant === 'expressive') {
1926
+ return Hct.isYellow(s.getPalette('neutral').hue) ? 2.3 : 1.6;
1927
+ }
1928
+ else if (s.variant === 'vibrant') {
1929
+ return 1.29;
1930
+ }
1931
+ else {
1932
+ // default
1933
+ return 1;
1934
+ }
1935
+ },
1936
+ },
1937
+ onSurface: {
1938
+ palette: (s) => s.getPalette('neutral'),
1939
+ tone: (s) => {
1940
+ if (s.variant === 'vibrant') {
1941
+ return tMaxC(s.getPalette('neutral'), 0, 100, 1.1);
1942
+ }
1943
+ else {
1944
+ // For all other variants, the initial tone should be the default
1945
+ // tone, which is the same as the background color.
1946
+ return DynamicColor.getInitialToneFromBackground((s) => highestSurface(s, colorService))(s);
1947
+ }
1948
+ },
1949
+ chromaMultiplier: (s) => {
1950
+ if (s.variant === 'neutral') {
1951
+ return 2.2;
1952
+ }
1953
+ else if (s.variant === 'tonalSpot') {
1954
+ return 1.7;
1955
+ }
1956
+ else if (s.variant === 'expressive') {
1957
+ return Hct.isYellow(s.getPalette('neutral').hue)
1958
+ ? s.isDark
1959
+ ? 3.0
1960
+ : 2.3
1961
+ : 1.6;
1962
+ }
1963
+ return 1;
1964
+ },
1965
+ background: (s) => highestSurface(s, colorService),
1966
+ contrastCurve: (s) => (s.isDark ? getCurve(11) : getCurve(9)),
1967
+ },
1968
+ onSurfaceVariant: {
1969
+ palette: (s) => s.getPalette('neutralVariant'),
1970
+ chromaMultiplier: (s) => {
1971
+ if (s.variant === 'neutral') {
1972
+ return 2.2;
1973
+ }
1974
+ else if (s.variant === 'tonalSpot') {
1975
+ return 1.7;
1976
+ }
1977
+ else if (s.variant === 'expressive') {
1978
+ return Hct.isYellow(s.getPalette('neutral').hue)
1979
+ ? s.isDark
1980
+ ? 3.0
1981
+ : 2.3
1982
+ : 1.6;
1983
+ }
1984
+ return 1;
1985
+ },
1986
+ background: (s) => highestSurface(s, colorService),
1987
+ contrastCurve: (s) => (s.isDark ? getCurve(6) : getCurve(4.5)),
1988
+ },
1989
+ outline: {
1990
+ palette: (s) => s.getPalette('neutralVariant'),
1991
+ chromaMultiplier: (s) => {
1992
+ if (s.variant === 'neutral') {
1993
+ return 2.2;
1994
+ }
1995
+ else if (s.variant === 'tonalSpot') {
1996
+ return 1.7;
1997
+ }
1998
+ else if (s.variant === 'expressive') {
1999
+ return Hct.isYellow(s.getPalette('neutral').hue)
2000
+ ? s.isDark
2001
+ ? 3.0
2002
+ : 2.3
2003
+ : 1.6;
2004
+ }
2005
+ return 1;
2006
+ },
2007
+ background: (s) => highestSurface(s, colorService),
2008
+ contrastCurve: (s) => getCurve(3),
2009
+ },
2010
+ outlineVariant: {
2011
+ palette: (s) => s.getPalette('neutralVariant'),
2012
+ chromaMultiplier: (s) => {
2013
+ if (s.variant === 'neutral') {
2014
+ return 2.2;
2015
+ }
2016
+ else if (s.variant === 'tonalSpot') {
2017
+ return 1.7;
2018
+ }
2019
+ else if (s.variant === 'expressive') {
2020
+ return Hct.isYellow(s.getPalette('neutral').hue)
2021
+ ? s.isDark
2022
+ ? 3.0
2023
+ : 2.3
2024
+ : 1.6;
2025
+ }
2026
+ return 1;
2027
+ },
2028
+ background: (s) => highestSurface(s, colorService),
2029
+ contrastCurve: (s) => getCurve(1.5),
2030
+ },
2031
+ inverseSurface: {
2032
+ palette: (s) => s.getPalette('neutral'),
2033
+ tone: (s) => (s.isDark ? 98 : 4),
2034
+ isBackground: true,
2035
+ },
2036
+ inverseOnSurface: {
2037
+ palette: (s) => s.getPalette('neutral'),
2038
+ tone: (s) => (s.isDark ? 20 : 95),
2039
+ background: (s) => colorService.getColor('inverseSurface').getMaterialColor(),
2040
+ contrastCurve: (s) => getCurve(7),
2041
+ },
2042
+ ////////////////////////////////////////////////////////////////
2043
+ // Primaries [P] //
2044
+ ////////////////////////////////////////////////////////////////
2045
+ primary: {
2046
+ palette: (s) => s.getPalette('primary'),
2047
+ tone: (s) => {
2048
+ if (s.variant === 'neutral') {
2049
+ return s.isDark ? 80 : 40;
2050
+ }
2051
+ else if (s.variant === 'tonalSpot') {
2052
+ if (s.isDark) {
2053
+ return 80;
2054
+ }
2055
+ else {
2056
+ return tMaxC(s.getPalette('primary'));
2057
+ }
2058
+ }
2059
+ else if (s.variant === 'expressive') {
2060
+ return tMaxC(s.getPalette('primary'), 0, Hct.isYellow(s.getPalette('primary').hue)
2061
+ ? 25
2062
+ : Hct.isCyan(s.getPalette('primary').hue)
2063
+ ? 88
2064
+ : 98);
2065
+ }
2066
+ else {
2067
+ return tMaxC(s.getPalette('primary'), 0, Hct.isCyan(s.getPalette('primary').hue) ? 88 : 98);
2068
+ }
2069
+ },
2070
+ isBackground: true,
2071
+ background: (s) => highestSurface(s, colorService),
2072
+ contrastCurve: (s) => getCurve(4.5),
2073
+ toneDeltaPair: (s) => new ToneDeltaPair(colorService.getColor('primaryContainer').getMaterialColor(), colorService.getColor('primary').getMaterialColor(), 5, 'relative_lighter', true, 'farther'),
2074
+ },
2075
+ primaryDim: {
2076
+ palette: (s) => s.getPalette('primary'),
2077
+ tone: (s) => {
2078
+ if (s.variant === 'neutral') {
2079
+ return 85;
2080
+ }
2081
+ else if (s.variant === 'tonalSpot') {
2082
+ return tMaxC(s.getPalette('primary'), 0, 90);
2083
+ }
2084
+ else {
2085
+ return tMaxC(s.getPalette('primary'));
2086
+ }
2087
+ },
2088
+ isBackground: true,
2089
+ background: (s) => getColor('surfaceContainerHigh'),
2090
+ contrastCurve: (s) => getCurve(4.5),
2091
+ toneDeltaPair: (s) => new ToneDeltaPair(colorService.getColor('primaryDim').getMaterialColor(), colorService.getColor('primary').getMaterialColor(), 5, 'darker', true, 'farther'),
2092
+ },
2093
+ onPrimary: {
2094
+ palette: (s) => s.getPalette('primary'),
2095
+ background: (s) => colorService.getColor('primary').getMaterialColor(),
2096
+ contrastCurve: (s) => getCurve(6),
2097
+ },
2098
+ primaryContainer: {
2099
+ palette: (s) => s.getPalette('primary'),
2100
+ tone: (s) => {
2101
+ if (s.variant === 'neutral') {
2102
+ return s.isDark ? 30 : 90;
2103
+ }
2104
+ else if (s.variant === 'tonalSpot') {
2105
+ return s.isDark
2106
+ ? tMinC(s.getPalette('primary'), 35, 93)
2107
+ : tMaxC(s.getPalette('primary'), 0, 90);
2108
+ }
2109
+ else if (s.variant === 'expressive') {
2110
+ return s.isDark
2111
+ ? tMaxC(s.getPalette('primary'), 30, 93)
2112
+ : tMaxC(s.getPalette('primary'), 78, Hct.isCyan(s.getPalette('primary').hue) ? 88 : 90);
2113
+ }
2114
+ else {
2115
+ // VIBRANT
2116
+ return s.isDark
2117
+ ? tMinC(s.getPalette('primary'), 66, 93)
2118
+ : tMaxC(s.getPalette('primary'), 66, Hct.isCyan(s.getPalette('primary').hue) ? 88 : 93);
2119
+ }
2120
+ },
2121
+ isBackground: true,
2122
+ background: (s) => highestSurface(s, colorService),
2123
+ toneDeltaPair: (s) => undefined,
2124
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
2125
+ },
2126
+ onPrimaryContainer: {
2127
+ palette: (s) => s.getPalette('primary'),
2128
+ background: (s) => colorService.getColor('primaryContainer').getMaterialColor(),
2129
+ contrastCurve: (s) => getCurve(6),
2130
+ },
2131
+ primaryFixed: {
2132
+ palette: (s) => s.getPalette('primary'),
2133
+ tone: (s) => {
2134
+ const tempS = new Scheme(Object.assign(Object.assign({}, s.options), { isDark: false, contrastLevel: 0 }));
2135
+ return getColor('primaryContainer').getTone(tempS);
2136
+ },
2137
+ isBackground: true,
2138
+ background: (s) => highestSurface(s, colorService),
2139
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
2140
+ },
2141
+ primaryFixedDim: {
2142
+ palette: (s) => s.getPalette('primary'),
2143
+ tone: (s) => colorService.getColor('primaryFixed').getMaterialColor().getTone(s),
2144
+ isBackground: true,
2145
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('primaryFixedDim'), getColor('primaryFixed'), 5, 'darker', true, 'exact'),
2146
+ },
2147
+ onPrimaryFixed: {
2148
+ palette: (s) => s.getPalette('primary'),
2149
+ background: (s) => colorService.getColor('primaryFixedDim').getMaterialColor(),
2150
+ contrastCurve: (s) => getCurve(7),
2151
+ },
2152
+ onPrimaryFixedVariant: {
2153
+ palette: (s) => s.getPalette('primary'),
2154
+ background: (s) => colorService.getColor('primaryFixedDim').getMaterialColor(),
2155
+ contrastCurve: (s) => getCurve(4.5),
2156
+ },
2157
+ inversePrimary: {
2158
+ palette: (s) => s.getPalette('primary'),
2159
+ tone: (s) => tMaxC(s.getPalette('primary')),
2160
+ background: (s) => colorService.getColor('inverseSurface').getMaterialColor(),
2161
+ contrastCurve: (s) => getCurve(6),
2162
+ },
2163
+ ////////////////////////////////////////////////////////////////
2164
+ // Secondaries [Q] //
2165
+ ////////////////////////////////////////////////////////////////
2166
+ secondary: {
2167
+ palette: (s) => s.getPalette('secondary'),
2168
+ tone: (s) => {
2169
+ if (s.variant === 'neutral') {
2170
+ return s.isDark
2171
+ ? tMinC(s.getPalette('secondary'), 0, 98)
2172
+ : tMaxC(s.getPalette('secondary'));
2173
+ }
2174
+ else if (s.variant === 'vibrant') {
2175
+ return tMaxC(s.getPalette('secondary'), 0, s.isDark ? 90 : 98);
2176
+ }
2177
+ else {
2178
+ // EXPRESSIVE and TONAL_SPOT
2179
+ return s.isDark ? 80 : tMaxC(s.getPalette('secondary'));
2180
+ }
2181
+ },
2182
+ isBackground: true,
2183
+ background: (s) => highestSurface(s, colorService),
2184
+ contrastCurve: (s) => getCurve(4.5),
2185
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('secondaryContainer'), getColor('secondary'), 5, 'relative_lighter', true, 'farther'),
2186
+ },
2187
+ secondaryDim: {
2188
+ palette: (s) => s.getPalette('secondary'),
2189
+ tone: (s) => {
2190
+ if (s.variant === 'neutral') {
2191
+ return 85;
2192
+ }
2193
+ else {
2194
+ return tMaxC(s.getPalette('secondary'), 0, 90);
2195
+ }
2196
+ },
2197
+ isBackground: true,
2198
+ background: (s) => getColor('surfaceContainerHigh'),
2199
+ contrastCurve: (s) => getCurve(4.5),
2200
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('secondaryDim'), getColor('secondary'), 5, 'darker', true, 'farther'),
2201
+ },
2202
+ onSecondary: {
2203
+ palette: (s) => s.getPalette('secondary'),
2204
+ background: (s) => getColor('secondary'),
2205
+ contrastCurve: (s) => getCurve(6),
2206
+ },
2207
+ secondaryContainer: {
2208
+ palette: (s) => s.getPalette('secondary'),
2209
+ tone: (s) => {
2210
+ if (s.variant === 'vibrant') {
2211
+ return s.isDark
2212
+ ? tMinC(s.getPalette('secondary'), 30, 40)
2213
+ : tMaxC(s.getPalette('secondary'), 84, 90);
2214
+ }
2215
+ else if (s.variant === 'expressive') {
2216
+ return s.isDark ? 15 : tMaxC(s.getPalette('secondary'), 90, 95);
2217
+ }
2218
+ else {
2219
+ return s.isDark ? 25 : 90;
2220
+ }
2221
+ },
2222
+ isBackground: true,
2223
+ background: (s) => highestSurface(s, colorService),
2224
+ toneDeltaPair: (s) => undefined,
2225
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
2226
+ },
2227
+ onSecondaryContainer: {
2228
+ palette: (s) => s.getPalette('secondary'),
2229
+ background: (s) => getColor('secondaryContainer'),
2230
+ contrastCurve: (s) => getCurve(6),
2231
+ },
2232
+ secondaryFixed: {
2233
+ palette: (s) => s.getPalette('secondary'),
2234
+ tone: (s) => {
2235
+ const tempS = new Scheme(Object.assign(Object.assign({}, s.options), { isDark: false, contrastLevel: 0 }));
2236
+ return getColor('secondaryContainer').getTone(tempS);
2237
+ },
2238
+ isBackground: true,
2239
+ background: (s) => highestSurface(s, colorService),
2240
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
2241
+ },
2242
+ secondaryFixedDim: {
2243
+ palette: (s) => s.getPalette('secondary'),
2244
+ tone: (s) => getColor('secondaryFixed').getTone(s),
2245
+ isBackground: true,
2246
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('secondaryFixedDim'), getColor('secondaryFixed'), 5, 'darker', true, 'exact'),
2247
+ },
2248
+ onSecondaryFixed: {
2249
+ palette: (s) => s.getPalette('secondary'),
2250
+ background: (s) => getColor('secondaryFixedDim'),
2251
+ contrastCurve: (s) => getCurve(7),
2252
+ },
2253
+ onSecondaryFixedVariant: {
2254
+ palette: (s) => s.getPalette('secondary'),
2255
+ background: (s) => getColor('secondaryFixedDim'),
2256
+ contrastCurve: (s) => getCurve(4.5),
2257
+ },
2258
+ ////////////////////////////////////////////////////////////////
2259
+ // Tertiaries [T] //
2260
+ ////////////////////////////////////////////////////////////////
2261
+ tertiary: {
2262
+ palette: (s) => s.getPalette('tertiary'),
2263
+ tone: (s) => {
2264
+ if (s.variant === 'expressive' || s.variant === 'vibrant') {
2265
+ return tMaxC(s.getPalette('tertiary'), 0, Hct.isCyan(s.getPalette('tertiary').hue) ? 88 : s.isDark ? 98 : 100);
2266
+ }
2267
+ else {
2268
+ // NEUTRAL and TONAL_SPOT
2269
+ return s.isDark
2270
+ ? tMaxC(s.getPalette('tertiary'), 0, 98)
2271
+ : tMaxC(s.getPalette('tertiary'));
2272
+ }
2273
+ },
2274
+ isBackground: true,
2275
+ background: (s) => highestSurface(s, colorService),
2276
+ contrastCurve: (s) => getCurve(4.5),
2277
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('tertiaryContainer'), getColor('tertiary'), 5, 'relative_lighter', true, 'farther'),
2278
+ },
2279
+ tertiaryDim: {
2280
+ palette: (s) => s.getPalette('tertiary'),
2281
+ tone: (s) => {
2282
+ if (s.variant === 'tonalSpot') {
2283
+ return tMaxC(s.getPalette('tertiary'), 0, 90);
2284
+ }
2285
+ else {
2286
+ return tMaxC(s.getPalette('tertiary'));
2287
+ }
2288
+ },
2289
+ isBackground: true,
2290
+ background: (s) => getColor('surfaceContainerHigh'),
2291
+ contrastCurve: (s) => getCurve(4.5),
2292
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('tertiaryDim'), getColor('tertiary'), 5, 'darker', true, 'farther'),
2293
+ },
2294
+ onTertiary: {
2295
+ palette: (s) => s.getPalette('tertiary'),
2296
+ background: (s) => getColor('tertiary'),
2297
+ contrastCurve: (s) => getCurve(6),
2298
+ },
2299
+ tertiaryContainer: {
2300
+ palette: (s) => s.getPalette('tertiary'),
2301
+ tone: (s) => {
2302
+ if (s.variant === 'neutral') {
2303
+ return s.isDark
2304
+ ? tMaxC(s.getPalette('tertiary'), 0, 93)
2305
+ : tMaxC(s.getPalette('tertiary'), 0, 96);
2306
+ }
2307
+ else if (s.variant === 'tonalSpot') {
2308
+ return tMaxC(s.getPalette('tertiary'), 0, s.isDark ? 93 : 100);
2309
+ }
2310
+ else if (s.variant === 'expressive') {
2311
+ return tMaxC(s.getPalette('tertiary'), 75, Hct.isCyan(s.getPalette('tertiary').hue) ? 88 : s.isDark ? 93 : 100);
2312
+ }
2313
+ else {
2314
+ // VIBRANT
2315
+ return s.isDark
2316
+ ? tMaxC(s.getPalette('tertiary'), 0, 93)
2317
+ : tMaxC(s.getPalette('tertiary'), 72, 100);
2318
+ }
2319
+ },
2320
+ isBackground: true,
2321
+ background: (s) => highestSurface(s, colorService),
2322
+ toneDeltaPair: (s) => undefined,
2323
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
2324
+ },
2325
+ onTertiaryContainer: {
2326
+ palette: (s) => s.getPalette('tertiary'),
2327
+ background: (s) => getColor('tertiaryContainer'),
2328
+ contrastCurve: (s) => getCurve(6),
2329
+ },
2330
+ tertiaryFixed: {
2331
+ palette: (s) => s.getPalette('tertiary'),
2332
+ tone: (s) => {
2333
+ const tempS = new Scheme(Object.assign(Object.assign({}, s.options), { isDark: false, contrastLevel: 0 }));
2334
+ return getColor('tertiaryContainer').getTone(tempS);
2335
+ },
2336
+ isBackground: true,
2337
+ background: (s) => highestSurface(s, colorService),
2338
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
2339
+ },
2340
+ tertiaryFixedDim: {
2341
+ palette: (s) => s.getPalette('tertiary'),
2342
+ tone: (s) => getColor('tertiaryFixed').getTone(s),
2343
+ isBackground: true,
2344
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('tertiaryFixedDim'), getColor('tertiaryFixed'), 5, 'darker', true, 'exact'),
2345
+ },
2346
+ onTertiaryFixed: {
2347
+ palette: (s) => s.getPalette('tertiary'),
2348
+ background: (s) => getColor('tertiaryFixedDim'),
2349
+ contrastCurve: (s) => getCurve(7),
2350
+ },
2351
+ onTertiaryFixedVariant: {
2352
+ palette: (s) => s.getPalette('tertiary'),
2353
+ background: (s) => getColor('tertiaryFixedDim'),
2354
+ contrastCurve: (s) => getCurve(4.5),
2355
+ },
2356
+ ////////////////////////////////////////////////////////////////
2357
+ // Errors [E] //
2358
+ ////////////////////////////////////////////////////////////////
2359
+ error: {
2360
+ palette: (s) => s.getPalette('error'),
2361
+ tone: (s) => {
2362
+ return s.isDark
2363
+ ? tMinC(s.getPalette('error'), 0, 98)
2364
+ : tMaxC(s.getPalette('error'));
2365
+ },
2366
+ isBackground: true,
2367
+ background: (s) => highestSurface(s, colorService),
2368
+ contrastCurve: (s) => getCurve(4.5),
2369
+ toneDeltaPair: (s) => new ToneDeltaPair(colorService.getColor('errorContainer').getMaterialColor(), colorService.getColor('error').getMaterialColor(), 5, 'relative_lighter', true, 'farther'),
2370
+ },
2371
+ errorDim: {
2372
+ palette: (s) => s.getPalette('error'),
2373
+ tone: (s) => tMinC(s.getPalette('error')),
2374
+ isBackground: true,
2375
+ background: (s) => getColor('surfaceContainerHigh'),
2376
+ contrastCurve: (s) => getCurve(4.5),
2377
+ toneDeltaPair: (s) => new ToneDeltaPair(getColor('errorDim'), getColor('error'), 5, 'darker', true, 'farther'),
2378
+ },
2379
+ onError: {
2380
+ palette: (s) => s.getPalette('error'),
2381
+ background: (s) => colorService.getColor('error').getMaterialColor(),
2382
+ contrastCurve: (s) => getCurve(6),
2383
+ },
2384
+ errorContainer: {
2385
+ palette: (s) => s.getPalette('error'),
2386
+ tone: (s) => {
2387
+ return s.isDark
2388
+ ? tMinC(s.getPalette('error'), 30, 93)
2389
+ : tMaxC(s.getPalette('error'), 0, 90);
2390
+ },
2391
+ isBackground: true,
2392
+ background: (s) => highestSurface(s, colorService),
2393
+ toneDeltaPair: (s) => undefined,
2394
+ contrastCurve: (s) => (s.contrastLevel > 0 ? getCurve(1.5) : undefined),
2395
+ },
2396
+ onErrorContainer: {
2397
+ palette: (s) => s.getPalette('error'),
2398
+ background: (s) => colorService.getColor('errorContainer').getMaterialColor(),
2399
+ contrastCurve: (s) => getCurve(4.5),
2400
+ },
2401
+ /////////////////////////////////////////////////////////////////
2402
+ // Remapped Colors //
2403
+ /////////////////////////////////////////////////////////////////
2404
+ surfaceVariant: {
2405
+ alias: 'surfaceContainerHighest',
2406
+ },
2407
+ surfaceTint: {
2408
+ alias: 'primary',
2409
+ },
2410
+ background: {
2411
+ alias: 'surface',
2412
+ },
2413
+ onBackground: {
2414
+ alias: 'onSurface',
2415
+ },
2416
+ };
2417
+ return {
2418
+ colors,
2419
+ };
2420
+ };
2421
+
2422
+ class API {
2423
+ constructor({ colorApi, themeApi, pluginApi, }) {
2424
+ this.plugins = pluginApi;
2425
+ this.colors = colorApi;
2426
+ this.themes = themeApi;
2427
+ }
2428
+ }
2429
+
2430
+ const AppModule = {
2431
+ api: awilix.asClass(API).singleton(),
2432
+ };
2433
+
2434
+ const tonalSpotVariant = {
2435
+ name: 'tonalSpot',
2436
+ palettes: {
2437
+ primary: ({ sourceColorHct, isDark }) => materialColorUtilities.TonalPalette.fromHueAndChroma(sourceColorHct.hue, isDark ? 26 : 32),
2438
+ secondary: ({ sourceColorHct }) => materialColorUtilities.TonalPalette.fromHueAndChroma(sourceColorHct.hue, 16),
2439
+ tertiary: ({ sourceColorHct }) => materialColorUtilities.TonalPalette.fromHueAndChroma(getRotatedHue(sourceColorHct, [0, 20, 71, 161, 333, 360], [-40, 48, -32, 40, -32]), 28),
2440
+ neutral: ({ sourceColorHct }) => materialColorUtilities.TonalPalette.fromHueAndChroma(sourceColorHct.hue, 5),
2441
+ neutralVariant: ({ sourceColorHct }) => materialColorUtilities.TonalPalette.fromHueAndChroma(sourceColorHct.hue, 5 * 1.7),
2442
+ error: ({ sourceColorHct }) => {
2443
+ const errorHue = getPiecewiseHue(sourceColorHct, [0, 3, 13, 23, 33, 43, 153, 273, 360], [12, 22, 32, 12, 22, 32, 22, 12]);
2444
+ return materialColorUtilities.TonalPalette.fromHueAndChroma(errorHue, 60);
2445
+ },
2446
+ },
2447
+ customPalettes: ({ colorHct }) => materialColorUtilities.TonalPalette.fromHueAndChroma(colorHct.hue, 16),
2448
+ };
2449
+
2450
+ function defineConfig(configObject) {
2451
+ if (!configObject || typeof configObject !== 'object') {
2452
+ throw new Error('The configuration is missing or not an object');
2453
+ }
2454
+ if (!('sourceColor' in configObject)) {
2455
+ throw new Error('Invalid configuration');
2456
+ }
2457
+ return configObject;
2458
+ }
2459
+ class ConfigService {
2460
+ constructor({ api }) {
2461
+ this.configPath = './theme.config';
2462
+ this.api = api;
2463
+ }
2464
+ loadConfig(config) {
2465
+ const { sourceColor, contrastLevel = 0, isDark = false, variant = tonalSpotVariant, palettes, colors, useDefaultColors = true, plugins, } = config !== null && config !== void 0 ? config : this.getConfig();
2466
+ this.api.themes.create({
2467
+ contrastLevel: contrastLevel,
2468
+ isDark: isDark,
2469
+ sourceColorHex: sourceColor,
2470
+ variant: variant,
2471
+ });
2472
+ if (palettes) {
2473
+ Object.entries(palettes).forEach(([key, value]) => this.api.themes.addCustomPalette(key, value));
2474
+ }
2475
+ if (useDefaultColors) {
2476
+ this.api.colors.addColors(defaultColors);
2477
+ }
2478
+ if (colors) {
2479
+ this.api.colors.addColors(colors);
2480
+ }
2481
+ if (plugins) {
2482
+ plugins.forEach((plugin) => {
2483
+ this.api.plugins.addPlugin(plugin);
2484
+ });
2485
+ this.api.plugins.loadPlugins(this.api);
2486
+ }
2487
+ }
2488
+ getConfig() {
2489
+ if (typeof process !== 'undefined' &&
2490
+ process.release &&
2491
+ process.release.name === 'node') {
2492
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
2493
+ const path = require('path');
2494
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
2495
+ const fs = require('fs');
2496
+ const base = path.resolve(this.configPath);
2497
+ const extensions = ['.js', '.ts', '.jms', '.jcs'];
2498
+ let configImport = null;
2499
+ for (const ext of extensions) {
2500
+ const path = base + ext;
2501
+ if (fs.existsSync(path)) {
2502
+ configImport = require(path);
2503
+ break;
2504
+ }
2505
+ }
2506
+ if (!configImport) {
2507
+ throw new Error(`Configuration file not found, looked for: ${base} with extensions: ${extensions.join(', ')}`);
2508
+ }
2509
+ let config;
2510
+ if ('default' in configImport) {
2511
+ config = configImport.default;
2512
+ }
2513
+ else {
2514
+ config = configImport;
2515
+ }
2516
+ return config;
2517
+ }
2518
+ else {
2519
+ throw new Error('You must provide configuration object when using this library in a browser.');
2520
+ }
2521
+ }
2522
+ }
2523
+
2524
+ const ConfigModule = {
2525
+ configService: awilix.asClass(ConfigService).singleton(),
2526
+ };
2527
+
2528
+ class PluginAbstract {
2529
+ constructor(options) {
2530
+ this.options = options;
2531
+ }
2532
+ init(api) {
2533
+ this.pluginInstance = new this.pluginClass(api, this.options);
2534
+ this.pluginInstance.onInit();
2535
+ return this;
2536
+ }
2537
+ getInstance() {
2538
+ if (!this.pluginInstance) {
2539
+ throw new Error(`Plugin ${this.name} is not initialized`);
2540
+ }
2541
+ return this.pluginInstance;
2542
+ }
2543
+ }
2544
+ class PluginImplAbstract {
2545
+ constructor(api, options) {
2546
+ this.api = api;
2547
+ this.options = options;
2548
+ this.onInit();
2549
+ }
2550
+ }
2551
+
2552
+ class PluginApi {
2553
+ constructor() {
2554
+ this.plugins = new Map();
2555
+ }
2556
+ addPlugin(plugin) {
2557
+ this.plugins.set(plugin.name, plugin);
2558
+ }
2559
+ loadPlugins(api) {
2560
+ const plugins = new Map(this.plugins);
2561
+ let size = 0;
2562
+ do {
2563
+ size = plugins.size;
2564
+ plugins.forEach((plugin, key) => {
2565
+ const deps = plugin.dependencies.filter((dep) => !this.plugins.has(new dep().name));
2566
+ if (deps.length === 0) {
2567
+ this.plugins.set(plugin.name, plugin.init(api));
2568
+ plugins.delete(key);
2569
+ }
2570
+ });
2571
+ } while (plugins.size != 0 && plugins.size < size);
2572
+ if (plugins.size > 0)
2573
+ throw new Error("Some plugins couldn't be loaded due to missing dependencies: " +
2574
+ Array.from(plugins.keys()));
2575
+ }
2576
+ getPlugin(plugin) {
2577
+ const pluginInstance = this.plugins.get(new plugin().name);
2578
+ if (!pluginInstance)
2579
+ throw new Error(`Plugin ${plugin.name} not found`);
2580
+ return pluginInstance;
2581
+ }
2582
+ }
2583
+
2584
+ const PluginModule = {
2585
+ pluginApi: awilix.asClass(PluginApi).singleton(),
2586
+ };
2587
+
2588
+ function importContainer(container, services) {
2589
+ services.forEach((service) => {
2590
+ Object.entries(service).forEach(([name, serviceClass]) => {
2591
+ container.register(name, serviceClass);
2592
+ });
2593
+ });
2594
+ return container;
2595
+ }
2596
+ const AppContainer = awilix.createContainer({
2597
+ injectionMode: awilix.InjectionMode.PROXY,
2598
+ });
2599
+ importContainer(AppContainer, [
2600
+ ConfigModule,
2601
+ AppModule,
2602
+ PluginModule,
2603
+ ColorModule,
2604
+ ThemeModule,
2605
+ ]);
2606
+
2607
+ function bootstrap() {
2608
+ return AppContainer.resolve('api');
2609
+ }
2610
+ function bootstrapFromConfig(args) {
2611
+ const configService = AppContainer.resolve('configService');
2612
+ if (args === null || args === void 0 ? void 0 : args.path)
2613
+ configService.configPath = args.path;
2614
+ configService.loadConfig(args === null || args === void 0 ? void 0 : args.config);
2615
+ return AppContainer.resolve('api');
2616
+ }
2617
+
2618
+ exports.FontFamily = void 0;
2619
+ (function (FontFamily) {
2620
+ FontFamily["Expressive"] = "expressive";
2621
+ FontFamily["Neutral"] = "neutral";
2622
+ })(exports.FontFamily || (exports.FontFamily = {}));
2623
+ class FontPlugin extends PluginAbstract {
2624
+ constructor() {
2625
+ super(...arguments);
2626
+ this.dependencies = [];
2627
+ this.name = 'font';
2628
+ this.pluginClass = FontPluginImpl;
2629
+ }
2630
+ }
2631
+ class FontPluginImpl extends PluginImplAbstract {
2632
+ get fontFamily() {
2633
+ if (!this._fontFamily)
2634
+ throw new Error('Font family not initialized');
2635
+ return this._fontFamily;
2636
+ }
2637
+ set fontFamily(value) {
2638
+ this._fontFamily = value;
2639
+ }
2640
+ get fontStyles() {
2641
+ if (!this._fontStyles)
2642
+ throw new Error('Font styles not initialized');
2643
+ return this._fontStyles;
2644
+ }
2645
+ set fontStyles(value) {
2646
+ this._fontStyles = value;
2647
+ }
2648
+ getFonts() {
2649
+ return {
2650
+ fontStyles: this.fontStyles,
2651
+ fontFamily: this.fontFamily,
2652
+ };
2653
+ }
2654
+ onInit() {
2655
+ var _a, _b, _c, _d, _e, _f;
2656
+ this.fontFamily = {
2657
+ expressive: (_c = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.fontFamily) === null || _b === void 0 ? void 0 : _b.expressive) !== null && _c !== void 0 ? _c : [
2658
+ 'Roboto',
2659
+ 'sans-serif',
2660
+ ],
2661
+ neutral: (_f = (_e = (_d = this.options) === null || _d === void 0 ? void 0 : _d.fontFamily) === null || _e === void 0 ? void 0 : _e.neutral) !== null && _f !== void 0 ? _f : ['Roboto', 'sans-serif'],
2662
+ };
2663
+ this.fontStyles = {
2664
+ display: {
2665
+ large: {
2666
+ fontWeight: 400,
2667
+ fontSize: 3.5625,
2668
+ lineHeight: 4,
2669
+ letterSpacing: -0.015625,
2670
+ fontFamily: exports.FontFamily.Expressive,
2671
+ },
2672
+ medium: {
2673
+ fontWeight: 400,
2674
+ fontSize: 2.8125,
2675
+ lineHeight: 3.25,
2676
+ fontFamily: exports.FontFamily.Expressive,
2677
+ },
2678
+ small: {
2679
+ fontWeight: 400,
2680
+ fontSize: 2.25,
2681
+ lineHeight: 2.75,
2682
+ fontFamily: exports.FontFamily.Expressive,
2683
+ },
2684
+ },
2685
+ headline: {
2686
+ large: {
2687
+ fontWeight: 400,
2688
+ fontSize: 2,
2689
+ lineHeight: 2.5,
2690
+ fontFamily: exports.FontFamily.Expressive,
2691
+ },
2692
+ medium: {
2693
+ fontWeight: 400,
2694
+ fontSize: 1.75,
2695
+ lineHeight: 2.25,
2696
+ fontFamily: exports.FontFamily.Expressive,
2697
+ },
2698
+ small: {
2699
+ fontWeight: 400,
2700
+ fontSize: 1.5,
2701
+ lineHeight: 2,
2702
+ fontFamily: exports.FontFamily.Expressive,
2703
+ },
2704
+ },
2705
+ title: {
2706
+ large: {
2707
+ fontWeight: 400,
2708
+ fontSize: 1.375,
2709
+ lineHeight: 1.75,
2710
+ fontFamily: exports.FontFamily.Neutral,
2711
+ },
2712
+ medium: {
2713
+ fontWeight: 500,
2714
+ fontSize: 1,
2715
+ lineHeight: 1.5,
2716
+ fontFamily: exports.FontFamily.Neutral,
2717
+ letterSpacing: 0.009375,
2718
+ },
2719
+ small: {
2720
+ fontWeight: 500,
2721
+ fontSize: 0.875,
2722
+ lineHeight: 1.25,
2723
+ fontFamily: exports.FontFamily.Neutral,
2724
+ letterSpacing: 0.00625,
2725
+ },
2726
+ },
2727
+ label: {
2728
+ large: {
2729
+ fontWeight: 500,
2730
+ fontSize: 0.875,
2731
+ lineHeight: 1.25,
2732
+ fontFamily: exports.FontFamily.Neutral,
2733
+ letterSpacing: 0.00625,
2734
+ },
2735
+ medium: {
2736
+ fontWeight: 500,
2737
+ fontSize: 0.75,
2738
+ lineHeight: 1,
2739
+ fontFamily: exports.FontFamily.Neutral,
2740
+ letterSpacing: 0.03125,
2741
+ },
2742
+ small: {
2743
+ fontWeight: 500,
2744
+ fontSize: 0.6875,
2745
+ lineHeight: 1,
2746
+ fontFamily: exports.FontFamily.Neutral,
2747
+ letterSpacing: 0.03125,
2748
+ },
2749
+ },
2750
+ body: {
2751
+ large: {
2752
+ fontWeight: 400,
2753
+ fontSize: 1,
2754
+ lineHeight: 1.5625,
2755
+ fontFamily: exports.FontFamily.Neutral,
2756
+ letterSpacing: 0.03125,
2757
+ },
2758
+ medium: {
2759
+ fontWeight: 400,
2760
+ fontSize: 0.875,
2761
+ lineHeight: 1.25,
2762
+ fontFamily: exports.FontFamily.Neutral,
2763
+ letterSpacing: 0.015625,
2764
+ },
2765
+ small: {
2766
+ fontWeight: 400,
2767
+ fontSize: 0.75,
2768
+ lineHeight: 1,
2769
+ fontFamily: exports.FontFamily.Neutral,
2770
+ letterSpacing: 0.025,
2771
+ },
2772
+ },
2773
+ };
2774
+ if (this.options && this.options.fontStyles)
2775
+ Object.entries(this.options.fontStyles).forEach(([key, fontParam]) => {
2776
+ const fontRole = key;
2777
+ Object.entries(fontParam).forEach(([size, fontStyle]) => {
2778
+ const fontSize = size;
2779
+ if (fontStyle) {
2780
+ this.fontStyles[fontRole][fontSize] = Object.assign(Object.assign({}, this.fontStyles[fontRole][fontSize]), fontStyle);
2781
+ }
2782
+ });
2783
+ });
2784
+ }
2785
+ }
2786
+
2787
+ /******************************************************************************
2788
+ Copyright (c) Microsoft Corporation.
2789
+
2790
+ Permission to use, copy, modify, and/or distribute this software for any
2791
+ purpose with or without fee is hereby granted.
2792
+
2793
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
2794
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2795
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
2796
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
2797
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
2798
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2799
+ PERFORMANCE OF THIS SOFTWARE.
2800
+ ***************************************************************************** */
2801
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
2802
+
2803
+
2804
+ function __awaiter(thisArg, _arguments, P, generator) {
2805
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
2806
+ return new (P || (P = Promise))(function (resolve, reject) {
2807
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
2808
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
2809
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
2810
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
2811
+ });
2812
+ }
2813
+
2814
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
2815
+ var e = new Error(message);
2816
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
2817
+ };
2818
+
2819
+ const createOrUpdateFile = (filePath, content) => {
2820
+ try {
2821
+ if (!fs__namespace.existsSync(filePath)) {
2822
+ // Create the folder if necessary.
2823
+ const dirPath = path__namespace.dirname(filePath);
2824
+ if (!fs__namespace.existsSync(dirPath)) {
2825
+ fs__namespace.mkdirSync(dirPath, { recursive: true });
2826
+ }
2827
+ // Create the file with the provided content.
2828
+ fs__namespace.writeFileSync(filePath, content);
2829
+ console.log(`✅ File successfully created: ${filePath}`);
2830
+ }
2831
+ else {
2832
+ console.log(`⚠️ File already exists: ${filePath}`);
2833
+ replaceFileContent(filePath, /[\s\S]*/, content);
2834
+ }
2835
+ }
2836
+ catch (error) {
2837
+ console.error('❌ Error while creating the file:', error);
2838
+ }
2839
+ };
2840
+ const getFileContent = (filePath, searchPattern) => {
2841
+ try {
2842
+ // Vérifier si le fichier existe
2843
+ if (!fs__namespace.existsSync(filePath)) {
2844
+ console.error(`❌ The specified file does not exist: ${filePath}`);
2845
+ return null;
2846
+ }
2847
+ // Lire le contenu du fichier entier
2848
+ const fileContent = fs__namespace.readFileSync(filePath, 'utf8');
2849
+ // Si un motif est fourni, chercher le texte correspondant
2850
+ if (searchPattern) {
2851
+ if (typeof searchPattern === 'string') {
2852
+ const found = fileContent.includes(searchPattern)
2853
+ ? searchPattern
2854
+ : false;
2855
+ console.log(found
2856
+ ? `✅ The file contains the specified string: "${searchPattern}"`
2857
+ : `⚠️ The file does NOT contain the specified string: "${searchPattern}"`);
2858
+ return found;
2859
+ }
2860
+ else {
2861
+ const match = fileContent.match(searchPattern);
2862
+ if (match) {
2863
+ console.log(`✅ Found match: "${match[0]}"`);
2864
+ return match[0]; // Retourner le texte trouvé
2865
+ }
2866
+ else {
2867
+ console.log(`⚠️ No match found for the pattern: "${searchPattern.toString()}"`);
2868
+ return false; // Aucune correspondance trouvée
2869
+ }
2870
+ }
2871
+ }
2872
+ // Si aucun motif n'est fourni, retourner tout le contenu
2873
+ console.log(`✅ File content successfully retrieved.`);
2874
+ return fileContent;
2875
+ }
2876
+ catch (error) {
2877
+ console.error('❌ An error occurred while processing the file:', error);
2878
+ return null;
2879
+ }
2880
+ };
2881
+ const replaceFileContent = (filePath, searchPattern, replacement) => {
2882
+ try {
2883
+ const results = replaceInFile.replaceInFileSync({
2884
+ files: filePath,
2885
+ from: searchPattern,
2886
+ to: replacement,
2887
+ });
2888
+ if (results.length > 0 && results[0].hasChanged) {
2889
+ console.log(`✅ Content successfully replaced in the file: ${filePath}`);
2890
+ }
2891
+ else {
2892
+ console.log(`⚠️ No replacement made. Here are some possible reasons:\n- The pattern ${searchPattern} was not found.\n- The file might already contain the expected content.`);
2893
+ }
2894
+ }
2895
+ catch (error) {
2896
+ console.error('❌ Error while replacing the file content:', error);
2897
+ }
2898
+ };
2899
+ const findTailwindCssFile = (startDir, searchPattern) => {
2900
+ const files = fs__namespace.readdirSync(startDir);
2901
+ for (const file of files) {
2902
+ const filePath = path__namespace.join(startDir, file);
2903
+ const stats = fs__namespace.statSync(filePath);
2904
+ if (stats.isDirectory()) {
2905
+ // Appeler récursivement si c'est un dossier
2906
+ const result = findTailwindCssFile(filePath, searchPattern);
2907
+ if (result)
2908
+ return result;
2909
+ }
2910
+ else if (file.endsWith('.css')) {
2911
+ // Lire chaque fichier .css
2912
+ const content = fs__namespace.readFileSync(filePath, 'utf8');
2913
+ if (content.includes(searchPattern)) {
2914
+ console.log('Fichier trouvé :', filePath);
2915
+ return filePath;
2916
+ }
2917
+ }
2918
+ }
2919
+ return null;
2920
+ };
2921
+
2922
+ const font = (fontStyles, responsiveBreakPoints) => {
2923
+ const createUtilities = ({ theme }) => {
2924
+ const pixelUnit = 'rem';
2925
+ const newUtilities = {};
2926
+ const baseTextStyle = (sizeValue) => ({
2927
+ fontSize: sizeValue.fontSize + pixelUnit,
2928
+ fontWeight: sizeValue.fontWeight,
2929
+ lineHeight: sizeValue.lineHeight + pixelUnit,
2930
+ letterSpacing: sizeValue.letterSpacing
2931
+ ? sizeValue.letterSpacing + pixelUnit
2932
+ : null,
2933
+ fontFamily: theme('fontFamily.' + sizeValue.fontFamily),
2934
+ });
2935
+ const responsiveTextStyle = (sizeValue, breakPointName, breakPointRatio) => ({
2936
+ [`@media (min-width: ${theme('screens.' + breakPointName, {})})`]: {
2937
+ fontSize: sizeValue.fontSize * breakPointRatio + pixelUnit,
2938
+ lineHeight: sizeValue.lineHeight * breakPointRatio + pixelUnit,
2939
+ },
2940
+ });
2941
+ for (const [roleName, roleValue] of Object.entries(fontStyles)) {
2942
+ for (const [sizeName, sizeValue] of Object.entries(roleValue)) {
2943
+ newUtilities['.text-' + roleName + '-' + sizeName] = Object.assign(Object.assign({}, baseTextStyle(sizeValue)), Object.entries(responsiveBreakPoints).reduce((acc, [breakPointName, breakPointRatio]) => {
2944
+ acc = Object.assign(Object.assign({}, acc), responsiveTextStyle(sizeValue, breakPointName, breakPointRatio));
2945
+ return acc;
2946
+ }, {}));
2947
+ }
2948
+ }
2949
+ return newUtilities;
2950
+ };
2951
+ return plugin(({ addUtilities, theme, }) => {
2952
+ const newUtilities = createUtilities({ theme });
2953
+ addUtilities(newUtilities);
2954
+ });
2955
+ };
2956
+
2957
+ // from tailwindcss src/util/flattenColors
2958
+ const state = (colorKeys) => plugin((pluginArgs) => {
2959
+ addAllNewComponents(pluginArgs, {
2960
+ statePrefix: 'state',
2961
+ disabledStyles: {
2962
+ textOpacity: 0.38,
2963
+ backgroundOpacity: 0.12,
2964
+ },
2965
+ transition: {
2966
+ duration: 150,
2967
+ },
2968
+ }, colorKeys);
2969
+ }, {});
2970
+ const addAllNewComponents = ({ addComponents }, { statePrefix, disabledStyles, transition }, colorKeys) => {
2971
+ const newComponents = {};
2972
+ for (const isGroup of [false, true]) {
2973
+ const group = isGroup ? 'group-' : '';
2974
+ for (const colorName of colorKeys) {
2975
+ const className = `.${group}${statePrefix}-${colorName}`;
2976
+ newComponents[className] = {
2977
+ [`@apply ${group}hover:bg-${colorName}/[0.08]`]: {},
2978
+ [`@apply ${group}active:bg-${colorName}/[0.12]`]: {},
2979
+ [`@apply ${group}focus-visible:bg-${colorName}/[0.12]`]: {},
2980
+ };
2981
+ if (transition) {
2982
+ newComponents[className][`@apply transition-colors`] = {};
2983
+ newComponents[className][`@apply duration-${transition.duration}`] = {};
2984
+ }
2985
+ if (disabledStyles) {
2986
+ newComponents[className][`@apply ${group}disabled:text-on-surface/[${disabledStyles.textOpacity}]`] = {};
2987
+ newComponents[className][`@apply ${group}disabled:bg-on-surface/[${disabledStyles.backgroundOpacity}]`] = {};
2988
+ }
2989
+ }
2990
+ }
2991
+ for (const colorName of colorKeys) {
2992
+ for (const stateName of ['hover', 'active', 'focus', 'disabled']) {
2993
+ const className = `.${stateName}-${statePrefix}-${colorName}`;
2994
+ if (stateName === 'active' || stateName === 'focus') {
2995
+ newComponents[className] = {
2996
+ [`@apply bg-${colorName}/[0.12]`]: {},
2997
+ };
2998
+ }
2999
+ else if (stateName === 'hover') {
3000
+ newComponents[className] = {
3001
+ [`@apply bg-${colorName}/[0.08]`]: {},
3002
+ };
3003
+ }
3004
+ else if (stateName === 'disabled') {
3005
+ newComponents[className] = {
3006
+ [`@apply text-on-surface/[${disabledStyles.textOpacity}]`]: {},
3007
+ };
3008
+ newComponents[className] = {
3009
+ [`@apply bg-on-surface/[${disabledStyles.backgroundOpacity}]`]: {},
3010
+ };
3011
+ }
3012
+ }
3013
+ }
3014
+ addComponents(newComponents);
3015
+ };
3016
+
3017
+ function createSubTheme({ name, darkMode, isDarkTheme, colors, }) {
3018
+ const theme = {
3019
+ name: isDarkTheme ? name + 'Dark' : name,
3020
+ selectors: isDarkTheme && darkMode === 'class'
3021
+ ? [
3022
+ '.dark-mode .theme-' + name,
3023
+ '.dark-mode.theme-' + name,
3024
+ '[data-theme="dark"] .theme-' + name,
3025
+ '[data-theme="dark"].theme-' + name,
3026
+ ]
3027
+ : [
3028
+ '.theme-' + name,
3029
+ `.theme-${name} .light-mode`,
3030
+ `.theme-${name} [data-theme="light"]`,
3031
+ `.light-mode .theme-${name}`,
3032
+ `.light-mode.theme-${name}`,
3033
+ `[data-theme="light"] .theme-${name}`,
3034
+ `[data-theme="light"].theme-${name}`,
3035
+ ],
3036
+ mediaQuery: isDarkTheme && darkMode === 'media'
3037
+ ? '@media (prefers-color-scheme: dark)'
3038
+ : undefined,
3039
+ extend: {
3040
+ colors: colors,
3041
+ },
3042
+ };
3043
+ return theme;
3044
+ }
3045
+ const themer = (args) => {
3046
+ const api = args.api;
3047
+ const options = {
3048
+ defaultTheme: {
3049
+ extend: {
3050
+ colors: {},
3051
+ },
3052
+ },
3053
+ themes: [
3054
+ {
3055
+ name: 'darkTheme',
3056
+ extend: {
3057
+ colors: {},
3058
+ },
3059
+ },
3060
+ ],
3061
+ };
3062
+ Object.entries(args.colors).forEach(([key, value]) => {
3063
+ options.defaultTheme.extend.colors[key] = value.light;
3064
+ options.themes[0].extend.colors[key] = value.dark;
3065
+ });
3066
+ options.themes[0].selectors =
3067
+ args.darkMode === 'class'
3068
+ ? ['.dark-mode', '[data-theme="dark"]']
3069
+ : undefined;
3070
+ options.themes[0].mediaQuery =
3071
+ args.darkMode === 'media'
3072
+ ? '@media (prefers-color-scheme: dark)'
3073
+ : undefined;
3074
+ if (args.subThemes) {
3075
+ Object.entries(args.subThemes).forEach(([key, value]) => {
3076
+ api.themes.update({ sourceColorHex: value });
3077
+ for (const isDarkTheme of [true, false]) {
3078
+ const colors = {};
3079
+ api.themes.update({ isDark: isDarkTheme });
3080
+ for (const [key, value] of api.colors.getColors().entries()) {
3081
+ const newKey = key
3082
+ .replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2')
3083
+ .toLowerCase();
3084
+ colors[newKey] = value.getHex();
3085
+ }
3086
+ options.themes.push(createSubTheme({
3087
+ name: key,
3088
+ isDarkTheme: isDarkTheme,
3089
+ darkMode: args.darkMode,
3090
+ colors: colors,
3091
+ }));
3092
+ }
3093
+ });
3094
+ }
3095
+ return require('tailwindcss-themer')(options);
3096
+ };
3097
+
3098
+ class TailwindPlugin extends PluginAbstract {
3099
+ constructor() {
3100
+ super(...arguments);
3101
+ this.dependencies = [FontPlugin];
3102
+ this.name = 'tailwind';
3103
+ this.pluginClass = TailwindImplPlugin;
3104
+ }
3105
+ }
3106
+ class TailwindImplPlugin extends PluginImplAbstract {
3107
+ onInit() {
3108
+ var _a, _b;
3109
+ var _c, _d;
3110
+ (_a = (_c = this.options).darkMode) !== null && _a !== void 0 ? _a : (_c.darkMode = 'class');
3111
+ (_b = (_d = this.options).responsiveBreakPoints) !== null && _b !== void 0 ? _b : (_d.responsiveBreakPoints = {
3112
+ lg: 1.125,
3113
+ });
3114
+ }
3115
+ load() {
3116
+ var _a;
3117
+ const searchKeyword = '@plugin "@udixio/tailwind"';
3118
+ const tailwindCssPath = findTailwindCssFile(process.cwd(), searchKeyword);
3119
+ if (!tailwindCssPath) {
3120
+ throw new Error('Tailwind plugin not found. Please use it first. (@plugin "@udixio/tailwind")');
3121
+ }
3122
+ const searchPattern = /@plugin "@udixio\/tailwind"\s*{\s*}/;
3123
+ const replacement = `@plugin "@udixio/tailwind" {\n}\n@import "./udixio.css";`;
3124
+ if (!getFileContent(tailwindCssPath, /@import\s+"\.\/udixio\.css";/)) {
3125
+ replaceFileContent(tailwindCssPath, searchPattern, replacement);
3126
+ }
3127
+ const cssFilePath = path.dirname(tailwindCssPath);
3128
+ const colors = {};
3129
+ for (const isDark of [false, true]) {
3130
+ this.api.themes.update({ isDark: isDark });
3131
+ for (const [key, value] of this.api.colors.getColors().entries()) {
3132
+ const newKey = key
3133
+ .replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2')
3134
+ .toLowerCase();
3135
+ (_a = colors[newKey]) !== null && _a !== void 0 ? _a : (colors[newKey] = { light: '', dark: '' });
3136
+ colors[newKey][isDark ? 'dark' : 'light'] = value.getHex();
3137
+ }
3138
+ }
3139
+ const { fontStyles, fontFamily } = this.api.plugins
3140
+ .getPlugin(FontPlugin)
3141
+ .getInstance()
3142
+ .getFonts();
3143
+ createOrUpdateFile(path.join(cssFilePath, 'udixio.css'), `
3144
+ @custom-variant dark (&:where(.dark, .dark *));
3145
+ @theme {
3146
+ --color-*: initial;
3147
+ ${Object.entries(colors)
3148
+ .map(([key, value]) => `--color-${key}: ${value.light};`)
3149
+ .join('\n ')}
3150
+ }
3151
+ @layer theme {
3152
+ .dark {
3153
+ ${Object.entries(colors)
3154
+ .map(([key, value]) => `--color-${key}: ${value.dark};`)
3155
+ .join('\n ')}
3156
+ }
3157
+ }
3158
+ `);
3159
+ const plugins = [
3160
+ state(Object.keys(colors)),
3161
+ font(fontStyles, this.options.responsiveBreakPoints),
3162
+ ];
3163
+ return plugin.withOptions(
3164
+ // 1) factory(options) → la fonction “handler” du plugin
3165
+ (options = {}) => {
3166
+ return function (api) {
3167
+ return __awaiter(this, void 0, void 0, function* () {
3168
+ plugins.forEach((plugin) => {
3169
+ plugin.handler(api);
3170
+ });
3171
+ });
3172
+ };
3173
+ },
3174
+ // 2) config(options) → objet à merger dans tailwind.config
3175
+ (options = {}) => {
3176
+ return {
3177
+ theme: {
3178
+ fontFamily,
3179
+ },
3180
+ };
3181
+ });
3182
+ }
3183
+ }
3184
+
3185
+ const createTheme = () => {
3186
+ const app = bootstrapFromConfig();
3187
+ const plugin = app.plugins.getPlugin(TailwindPlugin).getInstance();
3188
+ return plugin.load();
3189
+ };
3190
+
3191
+ exports.API = API;
3192
+ exports.AppContainer = AppContainer;
3193
+ exports.AppModule = AppModule;
3194
+ exports.ColorApi = ColorApi;
3195
+ exports.ColorManager = ColorManager;
3196
+ exports.ColorModule = ColorModule;
3197
+ exports.ConfigModule = ConfigModule;
3198
+ exports.ConfigService = ConfigService;
3199
+ exports.ConfigurableColor = ConfigurableColor;
3200
+ exports.ContrastCurve = ContrastCurve;
3201
+ exports.DynamicColor = DynamicColor;
3202
+ exports.FontPlugin = FontPlugin;
3203
+ exports.PluginAbstract = PluginAbstract;
3204
+ exports.PluginApi = PluginApi;
3205
+ exports.PluginImplAbstract = PluginImplAbstract;
3206
+ exports.PluginModule = PluginModule;
3207
+ exports.Scheme = Scheme;
3208
+ exports.SchemeManager = SchemeManager;
3209
+ exports.TailwindPlugin = TailwindPlugin;
3210
+ exports.ThemeApi = ThemeApi;
3211
+ exports.ThemeModule = ThemeModule;
3212
+ exports.ToneDeltaPair = ToneDeltaPair;
3213
+ exports.Variant = Variant;
3214
+ exports.VariantManager = VariantManager;
3215
+ exports.bootstrap = bootstrap;
3216
+ exports.bootstrapFromConfig = bootstrapFromConfig;
3217
+ exports.createTheme = createTheme;
3218
+ exports.defaultColors = defaultColors;
3219
+ exports.defineConfig = defineConfig;
3220
+ exports.extendSpecVersion = extendSpecVersion;
3221
+ exports.getPiecewiseHue = getPiecewiseHue;
3222
+ exports.getRotatedHue = getRotatedHue;
3223
+ exports.highestSurface = highestSurface;
3224
+ exports.importContainer = importContainer;
3225
+ exports.state = state;
3226
+ exports.themer = themer;