@chipmobilesdk/rn-theme 0.2.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +91 -23
  2. package/NOTICE +9 -0
  3. package/README.md +297 -154
  4. package/package.json +49 -50
  5. package/skills/sdk-rn-theme/SKILL.md +45 -30
  6. package/src/color/categorical.ts +33 -0
  7. package/src/color/contrast.ts +230 -0
  8. package/src/color/parse.ts +120 -0
  9. package/src/color/roles.ts +262 -0
  10. package/src/index.ts +23 -17
  11. package/src/integration/navigationTheme.ts +51 -0
  12. package/src/presets/byTone.ts +28 -0
  13. package/src/presets/layout.ts +38 -0
  14. package/src/presets/themePresets.ts +101 -0
  15. package/src/theme/buildThemes.ts +178 -0
  16. package/src/theme/errors.ts +34 -0
  17. package/src/theme/overrides.ts +142 -0
  18. package/src/theme/validateThemeConfig.ts +171 -0
  19. package/src/tokens/defaults.ts +103 -46
  20. package/src/tokens/typography.ts +144 -64
  21. package/src/types/brand.ts +16 -0
  22. package/src/types/colors.ts +80 -11
  23. package/src/types/index.ts +44 -5
  24. package/src/types/theme.ts +161 -0
  25. package/src/types/tokens.ts +47 -5
  26. package/src/types/typography.ts +46 -10
  27. package/src/unistyles/createUnistylesConfig.ts +165 -177
  28. package/src/unistyles/themeMode.ts +28 -0
  29. package/src/vendor/mcu/LICENSE +191 -0
  30. package/src/vendor/mcu/hct/cam16.ts +419 -0
  31. package/src/vendor/mcu/hct/hct.ts +216 -0
  32. package/src/vendor/mcu/hct/hct_solver.ts +557 -0
  33. package/src/vendor/mcu/hct/viewing_conditions.ts +121 -0
  34. package/src/vendor/mcu/index.ts +5 -0
  35. package/src/vendor/mcu/palettes/tonal_palette.ts +172 -0
  36. package/src/vendor/mcu/utils/color_utils.ts +302 -0
  37. package/src/vendor/mcu/utils/math_utils.ts +148 -0
  38. package/src/types/style.ts +0 -26
  39. package/src/unistyles/types.ts +0 -24
  40. package/src/unistyles/validateThemeConfig.ts +0 -154
  41. package/src/utils/colorGeneration.ts +0 -87
  42. package/src/utils/colorMath.ts +0 -55
@@ -0,0 +1,557 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2021 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ // Vendored from material-foundation/material-color-utilities v0.4.0
19
+ // (commit dd62982dfdefdfc9232ce8d76e122fb1c6d188ae, typescript/). Modified:
20
+ // relative import specifiers drop the `.js` suffix so Metro and Jest resolve them.
21
+ // This file is automatically generated. Do not modify it.
22
+
23
+ import * as colorUtils from '../utils/color_utils';
24
+ import * as mathUtils from '../utils/math_utils';
25
+
26
+ import {Cam16} from './cam16';
27
+ import {ViewingConditions} from './viewing_conditions';
28
+
29
+
30
+ // material_color_utilities is designed to have a consistent API across
31
+ // platforms and modular components that can be moved around easily. Using a
32
+ // class as a namespace facilitates this.
33
+ //
34
+ // tslint:disable:class-as-namespace
35
+ /**
36
+ * A class that solves the HCT equation.
37
+ */
38
+ export class HctSolver {
39
+ static SCALED_DISCOUNT_FROM_LINRGB = [
40
+ [
41
+ 0.001200833568784504,
42
+ 0.002389694492170889,
43
+ 0.0002795742885861124,
44
+ ],
45
+ [
46
+ 0.0005891086651375999,
47
+ 0.0029785502573438758,
48
+ 0.0003270666104008398,
49
+ ],
50
+ [
51
+ 0.00010146692491640572,
52
+ 0.0005364214359186694,
53
+ 0.0032979401770712076,
54
+ ],
55
+ ];
56
+
57
+ static LINRGB_FROM_SCALED_DISCOUNT = [
58
+ [
59
+ 1373.2198709594231,
60
+ -1100.4251190754821,
61
+ -7.278681089101213,
62
+ ],
63
+ [
64
+ -271.815969077903,
65
+ 559.6580465940733,
66
+ -32.46047482791194,
67
+ ],
68
+ [
69
+ 1.9622899599665666,
70
+ -57.173814538844006,
71
+ 308.7233197812385,
72
+ ],
73
+ ];
74
+
75
+ static Y_FROM_LINRGB = [0.2126, 0.7152, 0.0722];
76
+
77
+ static CRITICAL_PLANES = [
78
+ 0.015176349177441876, 0.045529047532325624, 0.07588174588720938,
79
+ 0.10623444424209313, 0.13658714259697685, 0.16693984095186062,
80
+ 0.19729253930674434, 0.2276452376616281, 0.2579979360165119,
81
+ 0.28835063437139563, 0.3188300904430532, 0.350925934958123,
82
+ 0.3848314933096426, 0.42057480301049466, 0.458183274052838,
83
+ 0.4976837250274023, 0.5391024159806381, 0.5824650784040898,
84
+ 0.6277969426914107, 0.6751227633498623, 0.7244668422128921,
85
+ 0.775853049866786, 0.829304845476233, 0.8848452951698498,
86
+ 0.942497089126609, 1.0022825574869039, 1.0642236851973577,
87
+ 1.1283421258858297, 1.1946592148522128, 1.2631959812511864,
88
+ 1.3339731595349034, 1.407011200216447, 1.4823302800086415,
89
+ 1.5599503113873272, 1.6398909516233677, 1.7221716113234105,
90
+ 1.8068114625156377, 1.8938294463134073, 1.9832442801866852,
91
+ 2.075074464868551, 2.1693382909216234, 2.2660538449872063,
92
+ 2.36523901573795, 2.4669114995532007, 2.5710888059345764,
93
+ 2.6777882626779785, 2.7870270208169257, 2.898822059350997,
94
+ 3.0131901897720907, 3.1301480604002863, 3.2497121605402226,
95
+ 3.3718988244681087, 3.4967242352587946, 3.624204428461639,
96
+ 3.754355295633311, 3.887192587735158, 4.022731918402185,
97
+ 4.160988767090289, 4.301978482107941, 4.445716283538092,
98
+ 4.592217266055746, 4.741496401646282, 4.893568542229298,
99
+ 5.048448422192488, 5.20615066083972, 5.3666897647573375,
100
+ 5.5300801301023865, 5.696336044816294, 5.865471690767354,
101
+ 6.037501145825082, 6.212438385869475, 6.390297286737924,
102
+ 6.571091626112461, 6.7548350853498045, 6.941541251256611,
103
+ 7.131223617812143, 7.323895587840543, 7.5195704746346665,
104
+ 7.7182615035334345, 7.919981813454504, 8.124744458384042,
105
+ 8.332562408825165, 8.543448553206703, 8.757415699253682,
106
+ 8.974476575321063, 9.194643831691977, 9.417930041841839,
107
+ 9.644347703669503, 9.873909240696694, 10.106627003236781,
108
+ 10.342513269534024, 10.58158024687427, 10.8238400726681,
109
+ 11.069304815507364, 11.317986476196008, 11.569896988756009,
110
+ 11.825048221409341, 12.083451977536606, 12.345119996613247,
111
+ 12.610063955123938, 12.878295467455942, 13.149826086772048,
112
+ 13.42466730586372, 13.702830557985108, 13.984327217668513,
113
+ 14.269168601521828, 14.55736596900856, 14.848930523210871,
114
+ 15.143873411576273, 15.44220572664832, 15.743938506781891,
115
+ 16.04908273684337, 16.35764934889634, 16.66964922287304,
116
+ 16.985093187232053, 17.30399201960269, 17.62635644741625,
117
+ 17.95219714852476, 18.281524751807332, 18.614349837764564,
118
+ 18.95068293910138, 19.290534541298456, 19.633915083172692,
119
+ 19.98083495742689, 20.331304511189067, 20.685334046541502,
120
+ 21.042933821039977, 21.404114048223256, 21.76888489811322,
121
+ 22.137256497705877, 22.50923893145328, 22.884842241736916,
122
+ 23.264076429332462, 23.6469514538663, 24.033477234264016,
123
+ 24.42366364919083, 24.817520537484558, 25.21505769858089,
124
+ 25.61628489293138, 26.021211842414342, 26.429848230738664,
125
+ 26.842203703840827, 27.258287870275353, 27.678110301598522,
126
+ 28.10168053274597, 28.529008062403893, 28.96010235337422,
127
+ 29.39497283293396, 29.83362889318845, 30.276079891419332,
128
+ 30.722335150426627, 31.172403958865512, 31.62629557157785,
129
+ 32.08401920991837, 32.54558406207592, 33.010999283389665,
130
+ 33.4802739966603, 33.953417292456834, 34.430438229418264,
131
+ 34.911345834551085, 35.39614910352207, 35.88485700094671,
132
+ 36.37747846067349, 36.87402238606382, 37.37449765026789,
133
+ 37.87891309649659, 38.38727753828926, 38.89959975977785,
134
+ 39.41588851594697, 39.93615253289054, 40.460400508064545,
135
+ 40.98864111053629, 41.520882981230194, 42.05713473317016,
136
+ 42.597404951718396, 43.141702194811224, 43.6900349931913,
137
+ 44.24241185063697, 44.798841244188324, 45.35933162437017,
138
+ 45.92389141541209, 46.49252901546552, 47.065252796817916,
139
+ 47.64207110610409, 48.22299226451468, 48.808024568002054,
140
+ 49.3971762874833, 49.9904556690408, 50.587870934119984,
141
+ 51.189430279724725, 51.79514187861014, 52.40501387947288,
142
+ 53.0190544071392, 53.637271562750364, 54.259673423945976,
143
+ 54.88626804504493, 55.517063457223934, 56.15206766869424,
144
+ 56.79128866487574, 57.43473440856916, 58.08241284012621,
145
+ 58.734331877617365, 59.39049941699807, 60.05092333227251,
146
+ 60.715611475655585, 61.38457167773311, 62.057811747619894,
147
+ 62.7353394731159, 63.417162620860914, 64.10328893648692,
148
+ 64.79372614476921, 65.48848194977529, 66.18756403501224,
149
+ 66.89098006357258, 67.59873767827808, 68.31084450182222,
150
+ 69.02730813691093, 69.74813616640164, 70.47333615344107,
151
+ 71.20291564160104, 71.93688215501312, 72.67524319850172,
152
+ 73.41800625771542, 74.16517879925733, 74.9167682708136,
153
+ 75.67278210128072, 76.43322770089146, 77.1981124613393,
154
+ 77.96744375590167, 78.74122893956174, 79.51947534912904,
155
+ 80.30219030335869, 81.08938110306934, 81.88105503125999,
156
+ 82.67721935322541, 83.4778813166706, 84.28304815182372,
157
+ 85.09272707154808, 85.90692527145302, 86.72564993000343,
158
+ 87.54890820862819, 88.3767072518277, 89.2090541872801,
159
+ 90.04595612594655, 90.88742016217518, 91.73345337380438,
160
+ 92.58406282226491, 93.43925555268066, 94.29903859396902,
161
+ 95.16341895893969, 96.03240364439274, 96.9059996312159,
162
+ 97.78421388448044, 98.6670533535366, 99.55452497210776,
163
+ ];
164
+
165
+ /**
166
+ * Sanitizes a small enough angle in radians.
167
+ *
168
+ * @param angle An angle in radians; must not deviate too much
169
+ * from 0.
170
+ * @return A coterminal angle between 0 and 2pi.
171
+ */
172
+ private static sanitizeRadians(angle: number): number {
173
+ return (angle + Math.PI * 8) % (Math.PI * 2);
174
+ }
175
+
176
+ /**
177
+ * Delinearizes an RGB component, returning a floating-point
178
+ * number.
179
+ *
180
+ * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents
181
+ * linear R/G/B channel
182
+ * @return 0.0 <= output <= 255.0, color channel converted to
183
+ * regular RGB space
184
+ */
185
+ private static trueDelinearized(rgbComponent: number): number {
186
+ const normalized = rgbComponent / 100.0;
187
+ let delinearized = 0.0;
188
+ if (normalized <= 0.0031308) {
189
+ delinearized = normalized * 12.92;
190
+ } else {
191
+ delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055;
192
+ }
193
+ return delinearized * 255.0;
194
+ }
195
+
196
+ private static chromaticAdaptation(component: number): number {
197
+ const af = Math.pow(Math.abs(component), 0.42);
198
+ return mathUtils.signum(component) * 400.0 * af / (af + 27.13);
199
+ }
200
+
201
+ /**
202
+ * Returns the hue of a linear RGB color in CAM16.
203
+ *
204
+ * @param linrgb The linear RGB coordinates of a color.
205
+ * @return The hue of the color in CAM16, in radians.
206
+ */
207
+ private static hueOf(linrgb: number[]): number {
208
+ const scaledDiscount =
209
+ mathUtils.matrixMultiply(linrgb, HctSolver.SCALED_DISCOUNT_FROM_LINRGB);
210
+ const rA = HctSolver.chromaticAdaptation(scaledDiscount[0]);
211
+ const gA = HctSolver.chromaticAdaptation(scaledDiscount[1]);
212
+ const bA = HctSolver.chromaticAdaptation(scaledDiscount[2]);
213
+ // redness-greenness
214
+ const a = (11.0 * rA + -12.0 * gA + bA) / 11.0;
215
+ // yellowness-blueness
216
+ const b = (rA + gA - 2.0 * bA) / 9.0;
217
+ return Math.atan2(b, a);
218
+ }
219
+
220
+ private static areInCyclicOrder(a: number, b: number, c: number): boolean {
221
+ const deltaAB = HctSolver.sanitizeRadians(b - a);
222
+ const deltaAC = HctSolver.sanitizeRadians(c - a);
223
+ return deltaAB < deltaAC;
224
+ }
225
+
226
+ /**
227
+ * Solves the lerp equation.
228
+ *
229
+ * @param source The starting number.
230
+ * @param mid The number in the middle.
231
+ * @param target The ending number.
232
+ * @return A number t such that lerp(source, target, t) = mid.
233
+ */
234
+ private static intercept(source: number, mid: number, target: number):
235
+ number {
236
+ return (mid - source) / (target - source);
237
+ }
238
+
239
+ private static lerpPoint(source: number[], t: number, target: number[]):
240
+ number[] {
241
+ return [
242
+ source[0] + (target[0] - source[0]) * t,
243
+ source[1] + (target[1] - source[1]) * t,
244
+ source[2] + (target[2] - source[2]) * t,
245
+ ];
246
+ }
247
+
248
+ /**
249
+ * Intersects a segment with a plane.
250
+ *
251
+ * @param source The coordinates of point A.
252
+ * @param coordinate The R-, G-, or B-coordinate of the plane.
253
+ * @param target The coordinates of point B.
254
+ * @param axis The axis the plane is perpendicular with. (0: R, 1:
255
+ * G, 2: B)
256
+ * @return The intersection point of the segment AB with the plane
257
+ * R=coordinate, G=coordinate, or B=coordinate
258
+ */
259
+ private static setCoordinate(
260
+ source: number[],
261
+ coordinate: number,
262
+ target: number[],
263
+ axis: number,
264
+ ): number[] {
265
+ const t = HctSolver.intercept(source[axis], coordinate, target[axis]);
266
+ return HctSolver.lerpPoint(source, t, target);
267
+ }
268
+
269
+ private static isBounded(x: number): boolean {
270
+ return 0.0 <= x && x <= 100.0;
271
+ }
272
+
273
+ /**
274
+ * Returns the nth possible vertex of the polygonal intersection.
275
+ *
276
+ * @param y The Y value of the plane.
277
+ * @param n The zero-based index of the point. 0 <= n <= 11.
278
+ * @return The nth possible vertex of the polygonal intersection
279
+ * of the y plane and the RGB cube, in linear RGB coordinates, if
280
+ * it exists. If this possible vertex lies outside of the cube,
281
+ * [-1.0, -1.0, -1.0] is returned.
282
+ */
283
+ private static nthVertex(y: number, n: number): number[] {
284
+ const kR = HctSolver.Y_FROM_LINRGB[0];
285
+ const kG = HctSolver.Y_FROM_LINRGB[1];
286
+ const kB = HctSolver.Y_FROM_LINRGB[2];
287
+ const coordA = n % 4 <= 1 ? 0.0 : 100.0;
288
+ const coordB = n % 2 === 0 ? 0.0 : 100.0;
289
+ if (n < 4) {
290
+ const g = coordA;
291
+ const b = coordB;
292
+ const r = (y - g * kG - b * kB) / kR;
293
+ if (HctSolver.isBounded(r)) {
294
+ return [r, g, b];
295
+ } else {
296
+ return [-1.0, -1.0, -1.0];
297
+ }
298
+ } else if (n < 8) {
299
+ const b = coordA;
300
+ const r = coordB;
301
+ const g = (y - r * kR - b * kB) / kG;
302
+ if (HctSolver.isBounded(g)) {
303
+ return [r, g, b];
304
+ } else {
305
+ return [-1.0, -1.0, -1.0];
306
+ }
307
+ } else {
308
+ const r = coordA;
309
+ const g = coordB;
310
+ const b = (y - r * kR - g * kG) / kB;
311
+ if (HctSolver.isBounded(b)) {
312
+ return [r, g, b];
313
+ } else {
314
+ return [-1.0, -1.0, -1.0];
315
+ }
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Finds the segment containing the desired color.
321
+ *
322
+ * @param y The Y value of the color.
323
+ * @param targetHue The hue of the color.
324
+ * @return A list of two sets of linear RGB coordinates, each
325
+ * corresponding to an endpoint of the segment containing the
326
+ * desired color.
327
+ */
328
+ private static bisectToSegment(y: number, targetHue: number): number[][] {
329
+ let left = [-1.0, -1.0, -1.0];
330
+ let right = left;
331
+ let leftHue = 0.0;
332
+ let rightHue = 0.0;
333
+ let initialized = false;
334
+ let uncut = true;
335
+ for (let n = 0; n < 12; n++) {
336
+ const mid = HctSolver.nthVertex(y, n);
337
+ if (mid[0] < 0) {
338
+ continue;
339
+ }
340
+ const midHue = HctSolver.hueOf(mid);
341
+ if (!initialized) {
342
+ left = mid;
343
+ right = mid;
344
+ leftHue = midHue;
345
+ rightHue = midHue;
346
+ initialized = true;
347
+ continue;
348
+ }
349
+ if (uncut || HctSolver.areInCyclicOrder(leftHue, midHue, rightHue)) {
350
+ uncut = false;
351
+ if (HctSolver.areInCyclicOrder(leftHue, targetHue, midHue)) {
352
+ right = mid;
353
+ rightHue = midHue;
354
+ } else {
355
+ left = mid;
356
+ leftHue = midHue;
357
+ }
358
+ }
359
+ }
360
+ return [left, right];
361
+ }
362
+
363
+ private static midpoint(a: number[], b: number[]): number[] {
364
+ return [
365
+ (a[0] + b[0]) / 2,
366
+ (a[1] + b[1]) / 2,
367
+ (a[2] + b[2]) / 2,
368
+ ];
369
+ }
370
+
371
+ private static criticalPlaneBelow(x: number): number {
372
+ return Math.floor(x - 0.5);
373
+ }
374
+
375
+ private static criticalPlaneAbove(x: number): number {
376
+ return Math.ceil(x - 0.5);
377
+ }
378
+
379
+ /**
380
+ * Finds a color with the given Y and hue on the boundary of the
381
+ * cube.
382
+ *
383
+ * @param y The Y value of the color.
384
+ * @param targetHue The hue of the color.
385
+ * @return The desired color, in linear RGB coordinates.
386
+ */
387
+ private static bisectToLimit(y: number, targetHue: number): number[] {
388
+ const segment = HctSolver.bisectToSegment(y, targetHue);
389
+ let left = segment[0];
390
+ let leftHue = HctSolver.hueOf(left);
391
+ let right = segment[1];
392
+ for (let axis = 0; axis < 3; axis++) {
393
+ if (left[axis] !== right[axis]) {
394
+ let lPlane = -1;
395
+ let rPlane = 255;
396
+ if (left[axis] < right[axis]) {
397
+ lPlane = HctSolver.criticalPlaneBelow(
398
+ HctSolver.trueDelinearized(left[axis]));
399
+ rPlane = HctSolver.criticalPlaneAbove(
400
+ HctSolver.trueDelinearized(right[axis]));
401
+ } else {
402
+ lPlane = HctSolver.criticalPlaneAbove(
403
+ HctSolver.trueDelinearized(left[axis]));
404
+ rPlane = HctSolver.criticalPlaneBelow(
405
+ HctSolver.trueDelinearized(right[axis]));
406
+ }
407
+ for (let i = 0; i < 8; i++) {
408
+ if (Math.abs(rPlane - lPlane) <= 1) {
409
+ break;
410
+ } else {
411
+ const mPlane = Math.floor((lPlane + rPlane) / 2.0);
412
+ const midPlaneCoordinate = HctSolver.CRITICAL_PLANES[mPlane];
413
+ const mid =
414
+ HctSolver.setCoordinate(left, midPlaneCoordinate, right, axis);
415
+ const midHue = HctSolver.hueOf(mid);
416
+ if (HctSolver.areInCyclicOrder(leftHue, targetHue, midHue)) {
417
+ right = mid;
418
+ rPlane = mPlane;
419
+ } else {
420
+ left = mid;
421
+ leftHue = midHue;
422
+ lPlane = mPlane;
423
+ }
424
+ }
425
+ }
426
+ }
427
+ }
428
+ return HctSolver.midpoint(left, right);
429
+ }
430
+
431
+ private static inverseChromaticAdaptation(adapted: number): number {
432
+ const adaptedAbs = Math.abs(adapted);
433
+ const base = Math.max(0, 27.13 * adaptedAbs / (400.0 - adaptedAbs));
434
+ return mathUtils.signum(adapted) * Math.pow(base, 1.0 / 0.42);
435
+ }
436
+
437
+ /**
438
+ * Finds a color with the given hue, chroma, and Y.
439
+ *
440
+ * @param hueRadians The desired hue in radians.
441
+ * @param chroma The desired chroma.
442
+ * @param y The desired Y.
443
+ * @return The desired color as a hexadecimal integer, if found; 0
444
+ * otherwise.
445
+ */
446
+ private static findResultByJ(hueRadians: number, chroma: number, y: number):
447
+ number {
448
+ // Initial estimate of j.
449
+ let j = Math.sqrt(y) * 11.0;
450
+ // ===========================================================
451
+ // Operations inlined from Cam16 to avoid repeated calculation
452
+ // ===========================================================
453
+ const viewingConditions = ViewingConditions.DEFAULT;
454
+ const tInnerCoeff =
455
+ 1 / Math.pow(1.64 - Math.pow(0.29, viewingConditions.n), 0.73);
456
+ const eHue = 0.25 * (Math.cos(hueRadians + 2.0) + 3.8);
457
+ const p1 =
458
+ eHue * (50000.0 / 13.0) * viewingConditions.nc * viewingConditions.ncb;
459
+ const hSin = Math.sin(hueRadians);
460
+ const hCos = Math.cos(hueRadians);
461
+ for (let iterationRound = 0; iterationRound < 5; iterationRound++) {
462
+ // ===========================================================
463
+ // Operations inlined from Cam16 to avoid repeated calculation
464
+ // ===========================================================
465
+ const jNormalized = j / 100.0;
466
+ const alpha =
467
+ chroma === 0.0 || j === 0.0 ? 0.0 : chroma / Math.sqrt(jNormalized);
468
+ const t = Math.pow(alpha * tInnerCoeff, 1.0 / 0.9);
469
+ const ac = viewingConditions.aw *
470
+ Math.pow(
471
+ jNormalized,
472
+ 1.0 / viewingConditions.c / viewingConditions.z,
473
+ );
474
+ const p2 = ac / viewingConditions.nbb;
475
+ const gamma = 23.0 * (p2 + 0.305) * t /
476
+ (23.0 * p1 + 11 * t * hCos + 108.0 * t * hSin);
477
+ const a = gamma * hCos;
478
+ const b = gamma * hSin;
479
+ const rA = (460.0 * p2 + 451.0 * a + 288.0 * b) / 1403.0;
480
+ const gA = (460.0 * p2 - 891.0 * a - 261.0 * b) / 1403.0;
481
+ const bA = (460.0 * p2 - 220.0 * a - 6300.0 * b) / 1403.0;
482
+ const rCScaled = HctSolver.inverseChromaticAdaptation(rA);
483
+ const gCScaled = HctSolver.inverseChromaticAdaptation(gA);
484
+ const bCScaled = HctSolver.inverseChromaticAdaptation(bA);
485
+ const linrgb = mathUtils.matrixMultiply(
486
+ [rCScaled, gCScaled, bCScaled],
487
+ HctSolver.LINRGB_FROM_SCALED_DISCOUNT,
488
+ );
489
+ // ===========================================================
490
+ // Operations inlined from Cam16 to avoid repeated calculation
491
+ // ===========================================================
492
+ if (linrgb[0] < 0 || linrgb[1] < 0 || linrgb[2] < 0) {
493
+ return 0;
494
+ }
495
+ const kR = HctSolver.Y_FROM_LINRGB[0];
496
+ const kG = HctSolver.Y_FROM_LINRGB[1];
497
+ const kB = HctSolver.Y_FROM_LINRGB[2];
498
+ const fnj = kR * linrgb[0] + kG * linrgb[1] + kB * linrgb[2];
499
+ if (fnj <= 0) {
500
+ return 0;
501
+ }
502
+ if (iterationRound === 4 || Math.abs(fnj - y) < 0.002) {
503
+ if (linrgb[0] > 100.01 || linrgb[1] > 100.01 || linrgb[2] > 100.01) {
504
+ return 0;
505
+ }
506
+ return colorUtils.argbFromLinrgb(linrgb);
507
+ }
508
+ // Iterates with Newton method,
509
+ // Using 2 * fn(j) / j as the approximation of fn'(j)
510
+ j = j - (fnj - y) * j / (2 * fnj);
511
+ }
512
+ return 0;
513
+ }
514
+
515
+ /**
516
+ * Finds an sRGB color with the given hue, chroma, and L*, if
517
+ * possible.
518
+ *
519
+ * @param hueDegrees The desired hue, in degrees.
520
+ * @param chroma The desired chroma.
521
+ * @param lstar The desired L*.
522
+ * @return A hexadecimal representing the sRGB color. The color
523
+ * has sufficiently close hue, chroma, and L* to the desired
524
+ * values, if possible; otherwise, the hue and L* will be
525
+ * sufficiently close, and chroma will be maximized.
526
+ */
527
+ static solveToInt(hueDegrees: number, chroma: number, lstar: number): number {
528
+ if (chroma < 0.0001 || lstar < 0.0001 || lstar > 99.9999) {
529
+ return colorUtils.argbFromLstar(lstar);
530
+ }
531
+ hueDegrees = mathUtils.sanitizeDegreesDouble(hueDegrees);
532
+ const hueRadians = hueDegrees / 180 * Math.PI;
533
+ const y = colorUtils.yFromLstar(lstar);
534
+ const exactAnswer = HctSolver.findResultByJ(hueRadians, chroma, y);
535
+ if (exactAnswer !== 0) {
536
+ return exactAnswer;
537
+ }
538
+ const linrgb = HctSolver.bisectToLimit(y, hueRadians);
539
+ return colorUtils.argbFromLinrgb(linrgb);
540
+ }
541
+
542
+ /**
543
+ * Finds an sRGB color with the given hue, chroma, and L*, if
544
+ * possible.
545
+ *
546
+ * @param hueDegrees The desired hue, in degrees.
547
+ * @param chroma The desired chroma.
548
+ * @param lstar The desired L*.
549
+ * @return An CAM16 object representing the sRGB color. The color
550
+ * has sufficiently close hue, chroma, and L* to the desired
551
+ * values, if possible; otherwise, the hue and L* will be
552
+ * sufficiently close, and chroma will be maximized.
553
+ */
554
+ static solveToCam(hueDegrees: number, chroma: number, lstar: number): Cam16 {
555
+ return Cam16.fromInt(HctSolver.solveToInt(hueDegrees, chroma, lstar));
556
+ }
557
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2021 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ // Vendored from material-foundation/material-color-utilities v0.4.0
19
+ // (commit dd62982dfdefdfc9232ce8d76e122fb1c6d188ae, typescript/). Modified:
20
+ // relative import specifiers drop the `.js` suffix so Metro and Jest resolve them.
21
+ import * as utils from '../utils/color_utils';
22
+ import * as math from '../utils/math_utils';
23
+
24
+ /**
25
+ * In traditional color spaces, a color can be identified solely by the
26
+ * observer's measurement of the color. Color appearance models such as CAM16
27
+ * also use information about the environment where the color was
28
+ * observed, known as the viewing conditions.
29
+ *
30
+ * For example, white under the traditional assumption of a midday sun white
31
+ * point is accurately measured as a slightly chromatic blue by CAM16. (roughly,
32
+ * hue 203, chroma 3, lightness 100)
33
+ *
34
+ * This class caches intermediate values of the CAM16 conversion process that
35
+ * depend only on viewing conditions, enabling speed ups.
36
+ */
37
+ export class ViewingConditions {
38
+ /** sRGB-like viewing conditions. */
39
+ static DEFAULT = ViewingConditions.make();
40
+
41
+ /**
42
+ * Create ViewingConditions from a simple, physically relevant, set of
43
+ * parameters.
44
+ *
45
+ * @param whitePoint White point, measured in the XYZ color space.
46
+ * default = D65, or sunny day afternoon
47
+ * @param adaptingLuminance The luminance of the adapting field. Informally,
48
+ * how bright it is in the room where the color is viewed. Can be
49
+ * calculated from lux by multiplying lux by 0.0586. default = 11.72,
50
+ * or 200 lux.
51
+ * @param backgroundLstar The lightness of the area surrounding the color.
52
+ * measured by L* in L*a*b*. default = 50.0
53
+ * @param surround A general description of the lighting surrounding the
54
+ * color. 0 is pitch dark, like watching a movie in a theater. 1.0 is a
55
+ * dimly light room, like watching TV at home at night. 2.0 means there
56
+ * is no difference between the lighting on the color and around it.
57
+ * default = 2.0
58
+ * @param discountingIlluminant Whether the eye accounts for the tint of the
59
+ * ambient lighting, such as knowing an apple is still red in green light.
60
+ * default = false, the eye does not perform this process on
61
+ * self-luminous objects like displays.
62
+ */
63
+ static make(
64
+ whitePoint = utils.whitePointD65(),
65
+ adaptingLuminance = (200.0 / Math.PI) * utils.yFromLstar(50.0) / 100.0,
66
+ backgroundLstar = 50.0, surround = 2.0,
67
+ discountingIlluminant = false): ViewingConditions {
68
+ const xyz = whitePoint;
69
+ const rW = xyz[0] * 0.401288 + xyz[1] * 0.650173 + xyz[2] * -0.051461;
70
+ const gW = xyz[0] * -0.250268 + xyz[1] * 1.204414 + xyz[2] * 0.045854;
71
+ const bW = xyz[0] * -0.002079 + xyz[1] * 0.048952 + xyz[2] * 0.953127;
72
+ const f = 0.8 + surround / 10.0;
73
+ const c = f >= 0.9 ? math.lerp(0.59, 0.69, (f - 0.9) * 10.0) :
74
+ math.lerp(0.525, 0.59, (f - 0.8) * 10.0);
75
+ let d = discountingIlluminant ?
76
+ 1.0 :
77
+ f * (1.0 - (1.0 / 3.6) * Math.exp((-adaptingLuminance - 42.0) / 92.0));
78
+ d = d > 1.0 ? 1.0 : d < 0.0 ? 0.0 : d;
79
+ const nc = f;
80
+ const rgbD = [
81
+ d * (100.0 / rW) + 1.0 - d,
82
+ d * (100.0 / gW) + 1.0 - d,
83
+ d * (100.0 / bW) + 1.0 - d,
84
+ ];
85
+ const k = 1.0 / (5.0 * adaptingLuminance + 1.0);
86
+ const k4 = k * k * k * k;
87
+ const k4F = 1.0 - k4;
88
+ const fl = k4 * adaptingLuminance +
89
+ 0.1 * k4F * k4F * Math.cbrt(5.0 * adaptingLuminance);
90
+ const n = utils.yFromLstar(backgroundLstar) / whitePoint[1];
91
+ const z = 1.48 + Math.sqrt(n);
92
+ const nbb = 0.725 / Math.pow(n, 0.2);
93
+ const ncb = nbb;
94
+ const rgbAFactors = [
95
+ Math.pow((fl * rgbD[0] * rW) / 100.0, 0.42),
96
+ Math.pow((fl * rgbD[1] * gW) / 100.0, 0.42),
97
+ Math.pow((fl * rgbD[2] * bW) / 100.0, 0.42),
98
+ ];
99
+ const rgbA = [
100
+ (400.0 * rgbAFactors[0]) / (rgbAFactors[0] + 27.13),
101
+ (400.0 * rgbAFactors[1]) / (rgbAFactors[1] + 27.13),
102
+ (400.0 * rgbAFactors[2]) / (rgbAFactors[2] + 27.13),
103
+ ];
104
+ const aw = (2.0 * rgbA[0] + rgbA[1] + 0.05 * rgbA[2]) * nbb;
105
+ return new ViewingConditions(
106
+ n, aw, nbb, ncb, c, nc, rgbD, fl, Math.pow(fl, 0.25), z);
107
+ }
108
+
109
+ /**
110
+ * Parameters are intermediate values of the CAM16 conversion process. Their
111
+ * names are shorthand for technical color science terminology, this class
112
+ * would not benefit from documenting them individually. A brief overview
113
+ * is available in the CAM16 specification, and a complete overview requires
114
+ * a color science textbook, such as Fairchild's Color Appearance Models.
115
+ */
116
+ private constructor(
117
+ public n: number, public aw: number, public nbb: number,
118
+ public ncb: number, public c: number, public nc: number,
119
+ public rgbD: number[], public fl: number, public fLRoot: number,
120
+ public z: number) {}
121
+ }
@@ -0,0 +1,5 @@
1
+ // Entry point for the vendored material-color-utilities subset. Package code
2
+ // imports from here only, so the vendored surface stays explicit.
3
+ export { Hct } from './hct/hct';
4
+ export { TonalPalette } from './palettes/tonal_palette';
5
+ export { argbFromRgb, lstarFromArgb } from './utils/color_utils';