@opensumi/ide-theme 2.21.13 → 2.22.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.
- package/lib/browser/icon-theme-data.js.map +1 -1
- package/lib/browser/icon-theme-store.js.map +1 -1
- package/lib/browser/icon.service.d.ts +3 -1
- package/lib/browser/icon.service.d.ts.map +1 -1
- package/lib/browser/icon.service.js +56 -24
- package/lib/browser/icon.service.js.map +1 -1
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/semantic-tokens-registry.js.map +1 -1
- package/lib/browser/style.service.js.map +1 -1
- package/lib/browser/theme-data.js +7 -7
- package/lib/browser/theme-data.js.map +1 -1
- package/lib/browser/theme-store.js.map +1 -1
- package/lib/browser/theme.contribution.js +3 -3
- package/lib/browser/theme.contribution.js.map +1 -1
- package/lib/browser/workbench.theme.service.js +2 -2
- package/lib/browser/workbench.theme.service.js.map +1 -1
- package/lib/common/color-tokens/basic-color.d.ts +1 -1
- package/lib/common/color-tokens/basic-color.d.ts.map +1 -1
- package/lib/common/color-tokens/editor.d.ts +13 -0
- package/lib/common/color-tokens/editor.d.ts.map +1 -1
- package/lib/common/color-tokens/editor.js +35 -1
- package/lib/common/color-tokens/editor.js.map +1 -1
- package/lib/common/color.js +40 -40
- package/lib/common/color.js.map +1 -1
- package/lib/common/mocks/theme.service.js.map +1 -1
- package/lib/common/plistParser.js +40 -40
- package/lib/common/plistParser.js.map +1 -1
- package/lib/common/semantic-tokens-registry.d.ts +7 -7
- package/lib/common/semantic-tokens-registry.d.ts.map +1 -1
- package/lib/common/theme.service.d.ts +26 -6
- package/lib/common/theme.service.d.ts.map +1 -1
- package/lib/common/theme.service.js.map +1 -1
- package/package.json +11 -10
- package/src/browser/default-theme.ts +547 -0
- package/src/browser/icon-theme-data.ts +294 -0
- package/src/browser/icon-theme-store.ts +38 -0
- package/src/browser/icon.less +15 -0
- package/src/browser/icon.service.ts +457 -0
- package/src/browser/index.ts +45 -0
- package/src/browser/semantic-tokens-registry.ts +217 -0
- package/src/browser/style.service.ts +51 -0
- package/src/browser/theme-data.ts +719 -0
- package/src/browser/theme-store.ts +95 -0
- package/src/browser/theme.contribution.ts +343 -0
- package/src/browser/workbench.theme.service.ts +703 -0
- package/src/common/color-registry.ts +52 -0
- package/src/common/color-tokens/activity-bar.ts +122 -0
- package/src/common/color-tokens/badge.ts +31 -0
- package/src/common/color-tokens/base.ts +90 -0
- package/src/common/color-tokens/basic-color.ts +9 -0
- package/src/common/color-tokens/breadcrumb.ts +60 -0
- package/src/common/color-tokens/button.ts +69 -0
- package/src/common/color-tokens/charts.ts +68 -0
- package/src/common/color-tokens/checkbox.ts +23 -0
- package/src/common/color-tokens/custom/actionbar.ts +51 -0
- package/src/common/color-tokens/custom/activity-bar.ts +16 -0
- package/src/common/color-tokens/custom/badge.ts +30 -0
- package/src/common/color-tokens/custom/base.ts +111 -0
- package/src/common/color-tokens/custom/button.ts +359 -0
- package/src/common/color-tokens/custom/checkbox.ts +36 -0
- package/src/common/color-tokens/custom/decoration.ts +71 -0
- package/src/common/color-tokens/custom/editor.ts +27 -0
- package/src/common/color-tokens/custom/extension.ts +9 -0
- package/src/common/color-tokens/custom/icon.ts +30 -0
- package/src/common/color-tokens/custom/index.ts +26 -0
- package/src/common/color-tokens/custom/input.ts +48 -0
- package/src/common/color-tokens/custom/menu.ts +61 -0
- package/src/common/color-tokens/custom/modal.ts +57 -0
- package/src/common/color-tokens/custom/notification.ts +16 -0
- package/src/common/color-tokens/custom/panel.ts +112 -0
- package/src/common/color-tokens/custom/popover.ts +28 -0
- package/src/common/color-tokens/custom/select.ts +155 -0
- package/src/common/color-tokens/custom/settings.ts +32 -0
- package/src/common/color-tokens/custom/statusbar.ts +16 -0
- package/src/common/color-tokens/custom/tab.ts +31 -0
- package/src/common/color-tokens/custom/tooltip.ts +55 -0
- package/src/common/color-tokens/custom/tree.ts +106 -0
- package/src/common/color-tokens/debug.ts +103 -0
- package/src/common/color-tokens/debugToolbar.ts +134 -0
- package/src/common/color-tokens/dropdown.ts +27 -0
- package/src/common/color-tokens/editor.ts +945 -0
- package/src/common/color-tokens/index.ts +35 -0
- package/src/common/color-tokens/input.ts +105 -0
- package/src/common/color-tokens/list-tree.ts +205 -0
- package/src/common/color-tokens/menu-bar.ts +43 -0
- package/src/common/color-tokens/menu.ts +53 -0
- package/src/common/color-tokens/merge-conflict.ts +145 -0
- package/src/common/color-tokens/minimap.ts +99 -0
- package/src/common/color-tokens/notification.ts +169 -0
- package/src/common/color-tokens/panel.ts +177 -0
- package/src/common/color-tokens/pick-view.ts +96 -0
- package/src/common/color-tokens/picker.ts +15 -0
- package/src/common/color-tokens/progress-bar.ts +12 -0
- package/src/common/color-tokens/quick-input.ts +57 -0
- package/src/common/color-tokens/scrollbar.ts +42 -0
- package/src/common/color-tokens/settings.ts +126 -0
- package/src/common/color-tokens/sidebar.ts +121 -0
- package/src/common/color-tokens/snippet.ts +33 -0
- package/src/common/color-tokens/status-bar.ts +350 -0
- package/src/common/color-tokens/tab.ts +346 -0
- package/src/common/color-tokens/testing.ts +105 -0
- package/src/common/color-tokens/text.ts +41 -0
- package/src/common/color-tokens/title-bar.ts +62 -0
- package/src/common/color-tokens/toolbar.ts +28 -0
- package/src/common/color-tokens/welcome-page.ts +27 -0
- package/src/common/color.ts +647 -0
- package/src/common/default-themes.ts +273 -0
- package/src/common/event.ts +9 -0
- package/src/common/index.ts +8 -0
- package/src/common/mocks/theme.service.ts +55 -0
- package/src/common/plistParser.ts +525 -0
- package/src/common/semantic-tokens-registry.ts +439 -0
- package/src/common/style.ts +9 -0
- package/src/common/theme.service.ts +363 -0
- package/src/common/themeCompatibility.ts +95 -0
- package/src/common/utils.ts +195 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
*--------------------------------------------------------------------------------------------*/
|
|
5
|
+
// Some code copied and modified from https://github.com/microsoft/vscode/blob/1.44.0/src/vs/base/common/color.ts
|
|
6
|
+
|
|
7
|
+
import { CharCode } from '@opensumi/ide-core-common';
|
|
8
|
+
|
|
9
|
+
function roundFloat(num: number, decimalPoints: number): number {
|
|
10
|
+
const decimal = Math.pow(10, decimalPoints);
|
|
11
|
+
return Math.round(num * decimal) / decimal;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class RGBA {
|
|
15
|
+
_rgbaBrand: void;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Red: integer in [0-255]
|
|
19
|
+
*/
|
|
20
|
+
readonly r: number;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Green: integer in [0-255]
|
|
24
|
+
*/
|
|
25
|
+
readonly g: number;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Blue: integer in [0-255]
|
|
29
|
+
*/
|
|
30
|
+
readonly b: number;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Alpha: float in [0-1]
|
|
34
|
+
*/
|
|
35
|
+
readonly a: number;
|
|
36
|
+
|
|
37
|
+
constructor(r: number, g: number, b: number, a = 1) {
|
|
38
|
+
this.r = Math.min(255, Math.max(0, r)) | 0;
|
|
39
|
+
this.g = Math.min(255, Math.max(0, g)) | 0;
|
|
40
|
+
this.b = Math.min(255, Math.max(0, b)) | 0;
|
|
41
|
+
this.a = roundFloat(Math.max(Math.min(1, a), 0), 3);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static equals(a: RGBA, b: RGBA): boolean {
|
|
45
|
+
return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class HSLA {
|
|
50
|
+
_hslaBrand: void;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Hue: integer in [0, 360]
|
|
54
|
+
*/
|
|
55
|
+
readonly h: number;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Saturation: float in [0, 1]
|
|
59
|
+
*/
|
|
60
|
+
readonly s: number;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Luminosity: float in [0, 1]
|
|
64
|
+
*/
|
|
65
|
+
readonly l: number;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Alpha: float in [0, 1]
|
|
69
|
+
*/
|
|
70
|
+
readonly a: number;
|
|
71
|
+
|
|
72
|
+
constructor(h: number, s: number, l: number, a: number) {
|
|
73
|
+
this.h = Math.max(Math.min(360, h), 0) | 0;
|
|
74
|
+
this.s = roundFloat(Math.max(Math.min(1, s), 0), 3);
|
|
75
|
+
this.l = roundFloat(Math.max(Math.min(1, l), 0), 3);
|
|
76
|
+
this.a = roundFloat(Math.max(Math.min(1, a), 0), 3);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static equals(a: HSLA, b: HSLA): boolean {
|
|
80
|
+
return a.h === b.h && a.s === b.s && a.l === b.l && a.a === b.a;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Converts an RGB color value to HSL. Conversion formula
|
|
85
|
+
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
|
86
|
+
* Assumes r, g, and b are contained in the set [0, 255] and
|
|
87
|
+
* returns h in the set [0, 360], s, and l in the set [0, 1].
|
|
88
|
+
*/
|
|
89
|
+
static fromRGBA(rgba: RGBA): HSLA {
|
|
90
|
+
const r = rgba.r / 255;
|
|
91
|
+
const g = rgba.g / 255;
|
|
92
|
+
const b = rgba.b / 255;
|
|
93
|
+
const a = rgba.a;
|
|
94
|
+
|
|
95
|
+
const max = Math.max(r, g, b);
|
|
96
|
+
const min = Math.min(r, g, b);
|
|
97
|
+
let h = 0;
|
|
98
|
+
let s = 0;
|
|
99
|
+
const l = (min + max) / 2;
|
|
100
|
+
const chroma = max - min;
|
|
101
|
+
|
|
102
|
+
if (chroma > 0) {
|
|
103
|
+
s = Math.min(l <= 0.5 ? chroma / (2 * l) : chroma / (2 - 2 * l), 1);
|
|
104
|
+
|
|
105
|
+
switch (max) {
|
|
106
|
+
case r:
|
|
107
|
+
h = (g - b) / chroma + (g < b ? 6 : 0);
|
|
108
|
+
break;
|
|
109
|
+
case g:
|
|
110
|
+
h = (b - r) / chroma + 2;
|
|
111
|
+
break;
|
|
112
|
+
case b:
|
|
113
|
+
h = (r - g) / chroma + 4;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
h *= 60;
|
|
118
|
+
h = Math.round(h);
|
|
119
|
+
}
|
|
120
|
+
return new HSLA(h, s, l, a);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private static _hue2rgb(p: number, q: number, t: number): number {
|
|
124
|
+
if (t < 0) {
|
|
125
|
+
t += 1;
|
|
126
|
+
}
|
|
127
|
+
if (t > 1) {
|
|
128
|
+
t -= 1;
|
|
129
|
+
}
|
|
130
|
+
if (t < 1 / 6) {
|
|
131
|
+
return p + (q - p) * 6 * t;
|
|
132
|
+
}
|
|
133
|
+
if (t < 1 / 2) {
|
|
134
|
+
return q;
|
|
135
|
+
}
|
|
136
|
+
if (t < 2 / 3) {
|
|
137
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
138
|
+
}
|
|
139
|
+
return p;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Converts an HSL color value to RGB. Conversion formula
|
|
144
|
+
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
|
145
|
+
* Assumes h in the set [0, 360] s, and l are contained in the set [0, 1] and
|
|
146
|
+
* returns r, g, and b in the set [0, 255].
|
|
147
|
+
*/
|
|
148
|
+
static toRGBA(hsla: HSLA): RGBA {
|
|
149
|
+
const h = hsla.h / 360;
|
|
150
|
+
const { s, l, a } = hsla;
|
|
151
|
+
let r: number;
|
|
152
|
+
let g: number;
|
|
153
|
+
let b: number;
|
|
154
|
+
|
|
155
|
+
if (s === 0) {
|
|
156
|
+
r = g = b = l; // achromatic
|
|
157
|
+
} else {
|
|
158
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
159
|
+
const p = 2 * l - q;
|
|
160
|
+
r = HSLA._hue2rgb(p, q, h + 1 / 3);
|
|
161
|
+
g = HSLA._hue2rgb(p, q, h);
|
|
162
|
+
b = HSLA._hue2rgb(p, q, h - 1 / 3);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return new RGBA(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export class HSVA {
|
|
170
|
+
_hsvaBrand: void;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Hue: integer in [0, 360]
|
|
174
|
+
*/
|
|
175
|
+
readonly h: number;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Saturation: float in [0, 1]
|
|
179
|
+
*/
|
|
180
|
+
readonly s: number;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Value: float in [0, 1]
|
|
184
|
+
*/
|
|
185
|
+
readonly v: number;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Alpha: float in [0, 1]
|
|
189
|
+
*/
|
|
190
|
+
readonly a: number;
|
|
191
|
+
|
|
192
|
+
constructor(h: number, s: number, v: number, a: number) {
|
|
193
|
+
this.h = Math.max(Math.min(360, h), 0) | 0;
|
|
194
|
+
this.s = roundFloat(Math.max(Math.min(1, s), 0), 3);
|
|
195
|
+
this.v = roundFloat(Math.max(Math.min(1, v), 0), 3);
|
|
196
|
+
this.a = roundFloat(Math.max(Math.min(1, a), 0), 3);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
static equals(a: HSVA, b: HSVA): boolean {
|
|
200
|
+
return a.h === b.h && a.s === b.s && a.v === b.v && a.a === b.a;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// from http://www.rapidtables.com/convert/color/rgb-to-hsv.htm
|
|
204
|
+
static fromRGBA(rgba: RGBA): HSVA {
|
|
205
|
+
const r = rgba.r / 255;
|
|
206
|
+
const g = rgba.g / 255;
|
|
207
|
+
const b = rgba.b / 255;
|
|
208
|
+
const cmax = Math.max(r, g, b);
|
|
209
|
+
const cmin = Math.min(r, g, b);
|
|
210
|
+
const delta = cmax - cmin;
|
|
211
|
+
const s = cmax === 0 ? 0 : delta / cmax;
|
|
212
|
+
let m: number;
|
|
213
|
+
|
|
214
|
+
if (delta === 0) {
|
|
215
|
+
m = 0;
|
|
216
|
+
} else if (cmax === r) {
|
|
217
|
+
m = ((((g - b) / delta) % 6) + 6) % 6;
|
|
218
|
+
} else if (cmax === g) {
|
|
219
|
+
m = (b - r) / delta + 2;
|
|
220
|
+
} else {
|
|
221
|
+
m = (r - g) / delta + 4;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return new HSVA(Math.round(m * 60), s, cmax, rgba.a);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// from http://www.rapidtables.com/convert/color/hsv-to-rgb.htm
|
|
228
|
+
static toRGBA(hsva: HSVA): RGBA {
|
|
229
|
+
const { h, s, v, a } = hsva;
|
|
230
|
+
const c = v * s;
|
|
231
|
+
const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
|
|
232
|
+
const m = v - c;
|
|
233
|
+
let [r, g, b] = [0, 0, 0];
|
|
234
|
+
|
|
235
|
+
if (h < 60) {
|
|
236
|
+
r = c;
|
|
237
|
+
g = x;
|
|
238
|
+
} else if (h < 120) {
|
|
239
|
+
r = x;
|
|
240
|
+
g = c;
|
|
241
|
+
} else if (h < 180) {
|
|
242
|
+
g = c;
|
|
243
|
+
b = x;
|
|
244
|
+
} else if (h < 240) {
|
|
245
|
+
g = x;
|
|
246
|
+
b = c;
|
|
247
|
+
} else if (h < 300) {
|
|
248
|
+
r = x;
|
|
249
|
+
b = c;
|
|
250
|
+
} else if (h < 360) {
|
|
251
|
+
r = c;
|
|
252
|
+
b = x;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
r = Math.round((r + m) * 255);
|
|
256
|
+
g = Math.round((g + m) * 255);
|
|
257
|
+
b = Math.round((b + m) * 255);
|
|
258
|
+
|
|
259
|
+
return new RGBA(r, g, b, a);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export class Color {
|
|
264
|
+
static fromHex(hex: string): Color {
|
|
265
|
+
return Color.Format.CSS.parseHex(hex) || Color.red;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
readonly rgba: RGBA;
|
|
269
|
+
private _hsla?: HSLA;
|
|
270
|
+
get hsla(): HSLA {
|
|
271
|
+
if (this._hsla) {
|
|
272
|
+
return this._hsla;
|
|
273
|
+
} else {
|
|
274
|
+
return HSLA.fromRGBA(this.rgba);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private _hsva?: HSVA;
|
|
279
|
+
get hsva(): HSVA {
|
|
280
|
+
if (this._hsva) {
|
|
281
|
+
return this._hsva;
|
|
282
|
+
}
|
|
283
|
+
return HSVA.fromRGBA(this.rgba);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
constructor(arg: RGBA | HSLA | HSVA) {
|
|
287
|
+
if (!arg) {
|
|
288
|
+
throw new Error('Color needs a value');
|
|
289
|
+
} else if (arg instanceof RGBA) {
|
|
290
|
+
this.rgba = arg;
|
|
291
|
+
} else if (arg instanceof HSLA) {
|
|
292
|
+
this._hsla = arg;
|
|
293
|
+
this.rgba = HSLA.toRGBA(arg);
|
|
294
|
+
} else if (arg instanceof HSVA) {
|
|
295
|
+
this._hsva = arg;
|
|
296
|
+
this.rgba = HSVA.toRGBA(arg);
|
|
297
|
+
} else {
|
|
298
|
+
throw new Error('Invalid color ctor argument');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
equals(other: Color): boolean {
|
|
303
|
+
return (
|
|
304
|
+
!!other &&
|
|
305
|
+
RGBA.equals(this.rgba, other.rgba) &&
|
|
306
|
+
HSLA.equals(this.hsla, other.hsla) &&
|
|
307
|
+
HSVA.equals(this.hsva, other.hsva)
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* http://www.w3.org/TR/WCAG20/#relativeluminancedef
|
|
313
|
+
* Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.
|
|
314
|
+
*/
|
|
315
|
+
getRelativeLuminance(): number {
|
|
316
|
+
const R = Color._relativeLuminanceForComponent(this.rgba.r);
|
|
317
|
+
const G = Color._relativeLuminanceForComponent(this.rgba.g);
|
|
318
|
+
const B = Color._relativeLuminanceForComponent(this.rgba.b);
|
|
319
|
+
const luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B;
|
|
320
|
+
|
|
321
|
+
return roundFloat(luminance, 4);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
private static _relativeLuminanceForComponent(color: number): number {
|
|
325
|
+
const c = color / 255;
|
|
326
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* http://www.w3.org/TR/WCAG20/#contrast-ratiodef
|
|
331
|
+
* Returns the contrast ration number in the set [1, 21].
|
|
332
|
+
*/
|
|
333
|
+
getContrastRatio(another: Color): number {
|
|
334
|
+
const lum1 = this.getRelativeLuminance();
|
|
335
|
+
const lum2 = another.getRelativeLuminance();
|
|
336
|
+
return lum1 > lum2 ? (lum1 + 0.05) / (lum2 + 0.05) : (lum2 + 0.05) / (lum1 + 0.05);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* http://24ways.org/2010/calculating-color-contrast
|
|
341
|
+
* Return 'true' if darker color otherwise 'false'
|
|
342
|
+
*/
|
|
343
|
+
isDarker(): boolean {
|
|
344
|
+
const yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
|
|
345
|
+
return yiq < 128;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* http://24ways.org/2010/calculating-color-contrast
|
|
350
|
+
* Return 'true' if lighter color otherwise 'false'
|
|
351
|
+
*/
|
|
352
|
+
isLighter(): boolean {
|
|
353
|
+
const yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;
|
|
354
|
+
return yiq >= 128;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
isLighterThan(another: Color): boolean {
|
|
358
|
+
const lum1 = this.getRelativeLuminance();
|
|
359
|
+
const lum2 = another.getRelativeLuminance();
|
|
360
|
+
return lum1 > lum2;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
isDarkerThan(another: Color): boolean {
|
|
364
|
+
const lum1 = this.getRelativeLuminance();
|
|
365
|
+
const lum2 = another.getRelativeLuminance();
|
|
366
|
+
return lum1 < lum2;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
lighten(factor: number): Color {
|
|
370
|
+
return new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l + this.hsla.l * factor, this.hsla.a));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
darken(factor: number): Color {
|
|
374
|
+
return new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l - this.hsla.l * factor, this.hsla.a));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
transparent(factor: number): Color {
|
|
378
|
+
const { r, g, b, a } = this.rgba;
|
|
379
|
+
return new Color(new RGBA(r, g, b, a * factor));
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
isTransparent(): boolean {
|
|
383
|
+
return this.rgba.a === 0;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
isOpaque(): boolean {
|
|
387
|
+
return this.rgba.a === 1;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
opposite(): Color {
|
|
391
|
+
return new Color(new RGBA(255 - this.rgba.r, 255 - this.rgba.g, 255 - this.rgba.b, this.rgba.a));
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
blend(c: Color): Color {
|
|
395
|
+
const rgba = c.rgba;
|
|
396
|
+
|
|
397
|
+
// Convert to 0..1 opacity
|
|
398
|
+
const thisA = this.rgba.a;
|
|
399
|
+
const colorA = rgba.a;
|
|
400
|
+
|
|
401
|
+
const a = thisA + colorA * (1 - thisA);
|
|
402
|
+
if (a < 1e-6) {
|
|
403
|
+
return Color.transparent;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const r = (this.rgba.r * thisA) / a + (rgba.r * colorA * (1 - thisA)) / a;
|
|
407
|
+
const g = (this.rgba.g * thisA) / a + (rgba.g * colorA * (1 - thisA)) / a;
|
|
408
|
+
const b = (this.rgba.b * thisA) / a + (rgba.b * colorA * (1 - thisA)) / a;
|
|
409
|
+
|
|
410
|
+
return new Color(new RGBA(r, g, b, a));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
flatten(...backgrounds: Color[]): Color {
|
|
414
|
+
const background = backgrounds.reduceRight((accumulator, color) => Color._flatten(color, accumulator));
|
|
415
|
+
return Color._flatten(this, background);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
private static _flatten(foreground: Color, background: Color) {
|
|
419
|
+
const backgroundAlpha = 1 - foreground.rgba.a;
|
|
420
|
+
return new Color(
|
|
421
|
+
new RGBA(
|
|
422
|
+
backgroundAlpha * background.rgba.r + foreground.rgba.a * foreground.rgba.r,
|
|
423
|
+
backgroundAlpha * background.rgba.g + foreground.rgba.a * foreground.rgba.g,
|
|
424
|
+
backgroundAlpha * background.rgba.b + foreground.rgba.a * foreground.rgba.b,
|
|
425
|
+
),
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
toString(): string {
|
|
430
|
+
return '' + Color.Format.CSS.format(this);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
static getLighterColor(of: Color, relative: Color, factor?: number): Color {
|
|
434
|
+
if (of.isLighterThan(relative)) {
|
|
435
|
+
return of;
|
|
436
|
+
}
|
|
437
|
+
factor = factor ? factor : 0.5;
|
|
438
|
+
const lum1 = of.getRelativeLuminance();
|
|
439
|
+
const lum2 = relative.getRelativeLuminance();
|
|
440
|
+
factor = (factor * (lum2 - lum1)) / lum2;
|
|
441
|
+
return of.lighten(factor);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
static getDarkerColor(of: Color, relative: Color, factor?: number): Color {
|
|
445
|
+
if (of.isDarkerThan(relative)) {
|
|
446
|
+
return of;
|
|
447
|
+
}
|
|
448
|
+
factor = factor ? factor : 0.5;
|
|
449
|
+
const lum1 = of.getRelativeLuminance();
|
|
450
|
+
const lum2 = relative.getRelativeLuminance();
|
|
451
|
+
factor = (factor * (lum1 - lum2)) / lum1;
|
|
452
|
+
return of.darken(factor);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
static readonly white = new Color(new RGBA(255, 255, 255, 1));
|
|
456
|
+
static readonly black = new Color(new RGBA(0, 0, 0, 1));
|
|
457
|
+
static readonly red = new Color(new RGBA(255, 0, 0, 1));
|
|
458
|
+
static readonly blue = new Color(new RGBA(0, 0, 255, 1));
|
|
459
|
+
static readonly green = new Color(new RGBA(0, 255, 0, 1));
|
|
460
|
+
static readonly cyan = new Color(new RGBA(0, 255, 255, 1));
|
|
461
|
+
static readonly lightgrey = new Color(new RGBA(211, 211, 211, 1));
|
|
462
|
+
static readonly transparent = new Color(new RGBA(0, 0, 0, 0));
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export namespace Color {
|
|
466
|
+
export namespace Format {
|
|
467
|
+
export namespace CSS {
|
|
468
|
+
export function formatRGB(color: Color): string {
|
|
469
|
+
if (color.rgba.a === 1) {
|
|
470
|
+
return `rgb(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b})`;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return Color.Format.CSS.formatRGBA(color);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
export function formatRGBA(color: Color): string {
|
|
477
|
+
return `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${+color.rgba.a.toFixed(2)})`;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
export function formatHSL(color: Color): string {
|
|
481
|
+
if (color.hsla.a === 1) {
|
|
482
|
+
return `hsl(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(2)}%)`;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return Color.Format.CSS.formatHSLA(color);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
export function formatHSLA(color: Color): string {
|
|
489
|
+
return `hsla(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(
|
|
490
|
+
2,
|
|
491
|
+
)}%, ${color.hsla.a.toFixed(2)})`;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function _toTwoDigitHex(n: number): string {
|
|
495
|
+
const r = n.toString(16);
|
|
496
|
+
return r.length !== 2 ? '0' + r : r;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Formats the color as #RRGGBB
|
|
501
|
+
*/
|
|
502
|
+
export function formatHex(color: Color): string {
|
|
503
|
+
return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}`;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Formats the color as #RRGGBBAA
|
|
508
|
+
* If 'compact' is set, colors without transparancy will be printed as #RRGGBB
|
|
509
|
+
*/
|
|
510
|
+
export function formatHexA(color: Color, compact = false): string {
|
|
511
|
+
if (compact && color.rgba.a === 1) {
|
|
512
|
+
return Color.Format.CSS.formatHex(color);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(
|
|
516
|
+
color.rgba.b,
|
|
517
|
+
)}${_toTwoDigitHex(Math.round(color.rgba.a * 255))}`;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* The default format will use HEX if opaque and RGBA otherwise.
|
|
522
|
+
*/
|
|
523
|
+
export function format(color: Color): string | null {
|
|
524
|
+
if (!color) {
|
|
525
|
+
return null;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (color.isOpaque()) {
|
|
529
|
+
return Color.Format.CSS.formatHex(color);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return Color.Format.CSS.formatRGBA(color);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Converts an Hex color value to a Color.
|
|
537
|
+
* returns r, g, and b are contained in the set [0, 255]
|
|
538
|
+
* @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA).
|
|
539
|
+
*/
|
|
540
|
+
export function parseHex(hex: string): Color | null {
|
|
541
|
+
if (!hex) {
|
|
542
|
+
// Invalid color
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const length = hex.length;
|
|
547
|
+
|
|
548
|
+
if (length === 0) {
|
|
549
|
+
// Invalid color
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (hex.charCodeAt(0) !== CharCode.Hash) {
|
|
554
|
+
// Does not begin with a #
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (length === 7) {
|
|
559
|
+
// #RRGGBB format
|
|
560
|
+
const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
|
|
561
|
+
const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
|
|
562
|
+
const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
|
|
563
|
+
return new Color(new RGBA(r, g, b, 1));
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (length === 9) {
|
|
567
|
+
// #RRGGBBAA format
|
|
568
|
+
const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));
|
|
569
|
+
const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));
|
|
570
|
+
const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));
|
|
571
|
+
const a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8));
|
|
572
|
+
return new Color(new RGBA(r, g, b, a / 255));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (length === 4) {
|
|
576
|
+
// #RGB format
|
|
577
|
+
const r = _parseHexDigit(hex.charCodeAt(1));
|
|
578
|
+
const g = _parseHexDigit(hex.charCodeAt(2));
|
|
579
|
+
const b = _parseHexDigit(hex.charCodeAt(3));
|
|
580
|
+
return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (length === 5) {
|
|
584
|
+
// #RGBA format
|
|
585
|
+
const r = _parseHexDigit(hex.charCodeAt(1));
|
|
586
|
+
const g = _parseHexDigit(hex.charCodeAt(2));
|
|
587
|
+
const b = _parseHexDigit(hex.charCodeAt(3));
|
|
588
|
+
const a = _parseHexDigit(hex.charCodeAt(4));
|
|
589
|
+
return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b, (16 * a + a) / 255));
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Invalid color
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function _parseHexDigit(charCode: CharCode): number {
|
|
597
|
+
switch (charCode) {
|
|
598
|
+
case CharCode.Digit0:
|
|
599
|
+
return 0;
|
|
600
|
+
case CharCode.Digit1:
|
|
601
|
+
return 1;
|
|
602
|
+
case CharCode.Digit2:
|
|
603
|
+
return 2;
|
|
604
|
+
case CharCode.Digit3:
|
|
605
|
+
return 3;
|
|
606
|
+
case CharCode.Digit4:
|
|
607
|
+
return 4;
|
|
608
|
+
case CharCode.Digit5:
|
|
609
|
+
return 5;
|
|
610
|
+
case CharCode.Digit6:
|
|
611
|
+
return 6;
|
|
612
|
+
case CharCode.Digit7:
|
|
613
|
+
return 7;
|
|
614
|
+
case CharCode.Digit8:
|
|
615
|
+
return 8;
|
|
616
|
+
case CharCode.Digit9:
|
|
617
|
+
return 9;
|
|
618
|
+
case CharCode.a:
|
|
619
|
+
return 10;
|
|
620
|
+
case CharCode.A:
|
|
621
|
+
return 10;
|
|
622
|
+
case CharCode.b:
|
|
623
|
+
return 11;
|
|
624
|
+
case CharCode.B:
|
|
625
|
+
return 11;
|
|
626
|
+
case CharCode.c:
|
|
627
|
+
return 12;
|
|
628
|
+
case CharCode.C:
|
|
629
|
+
return 12;
|
|
630
|
+
case CharCode.d:
|
|
631
|
+
return 13;
|
|
632
|
+
case CharCode.D:
|
|
633
|
+
return 13;
|
|
634
|
+
case CharCode.e:
|
|
635
|
+
return 14;
|
|
636
|
+
case CharCode.E:
|
|
637
|
+
return 14;
|
|
638
|
+
case CharCode.f:
|
|
639
|
+
return 15;
|
|
640
|
+
case CharCode.F:
|
|
641
|
+
return 15;
|
|
642
|
+
}
|
|
643
|
+
return 0;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|