@scality/core-ui 0.202.0 → 0.203.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/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +11 -16
- package/package.json +1 -1
- package/src/lib/utils.test.ts +15 -12
- package/src/lib/utils.ts +15 -17
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAcA;mCACmC;AACnC,eAAO,MAAM,oBAAoB,GAAI,QAAG,MAAM,UAAK,QAGlD,CAAC;AAEF;mCACmC;AACnC,eAAO,MAAM,uBAAuB,SAAU,UAAK,QAIlD,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MACjB,CAAC;AAErC,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAc5D,CAAC;AASF,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,EACf,aAAa,MAAM,EACnB,aAAa,MAAM,KAClB,MAAM,GAAG,IAeX,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,MAahD,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,EACb,UAAS,sBAA2B,KACnC,MAoBF,CAAC"}
|
package/dist/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getLuminance } from 'polished';
|
|
1
2
|
const RGB_HEX = /^#?(?:([\da-f]{3})[\da-f]?|([\da-f]{6})(?:[\da-f]{2})?)$/i;
|
|
2
3
|
/** Ensure the consistency of colors between old and new colors */
|
|
3
4
|
const variantMapping = {
|
|
@@ -37,25 +38,19 @@ export const hex2RGB = (str) => {
|
|
|
37
38
|
}
|
|
38
39
|
throw new Error('Invalid hex string provided');
|
|
39
40
|
};
|
|
40
|
-
// WCAG 2.0 relative luminance
|
|
41
|
-
const relativeLuminance = (r, g, b) => {
|
|
42
|
-
const [rs, gs, bs] = [r, g, b].map((c) => {
|
|
43
|
-
const s = c / 255;
|
|
44
|
-
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
45
|
-
});
|
|
46
|
-
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
|
|
47
|
-
};
|
|
48
41
|
const wcagContrastRatio = (l1, l2) => (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
};
|
|
42
|
+
// Minimum WCAG contrast ratio to consider a text color readable on a background.
|
|
43
|
+
// 3.0 corresponds to WCAG AA for large text — same threshold used by MUI.
|
|
44
|
+
const CONTRAST_THRESHOLD = 3;
|
|
53
45
|
export const getContrastText = (bgColor, textPrimary, textReverse) => {
|
|
54
46
|
try {
|
|
55
|
-
const bgLum =
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
47
|
+
const bgLum = getLuminance(bgColor);
|
|
48
|
+
const primaryLum = getLuminance(textPrimary);
|
|
49
|
+
const reverseLum = getLuminance(textReverse);
|
|
50
|
+
const lighterText = primaryLum >= reverseLum ? textPrimary : textReverse;
|
|
51
|
+
const darkerText = primaryLum >= reverseLum ? textReverse : textPrimary;
|
|
52
|
+
const lighterContrast = wcagContrastRatio(primaryLum >= reverseLum ? primaryLum : reverseLum, bgLum);
|
|
53
|
+
return lighterContrast >= CONTRAST_THRESHOLD ? lighterText : darkerText;
|
|
59
54
|
}
|
|
60
55
|
catch {
|
|
61
56
|
return null;
|
package/package.json
CHANGED
package/src/lib/utils.test.ts
CHANGED
|
@@ -4,22 +4,28 @@ const LIGHT_TEXT = '#EAEAEA';
|
|
|
4
4
|
const DARK_TEXT = '#000000';
|
|
5
5
|
|
|
6
6
|
describe('getContrastText', () => {
|
|
7
|
-
it('returns
|
|
7
|
+
it('returns light text on dark backgrounds', () => {
|
|
8
8
|
expect(getContrastText('#000000', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
9
9
|
expect(getContrastText('#1A1A1A', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
10
10
|
expect(getContrastText('#121219', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
11
11
|
expect(getContrastText('#2F4185', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it('returns
|
|
14
|
+
it('returns dark text on light backgrounds', () => {
|
|
15
15
|
expect(getContrastText('#FFFFFF', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
|
|
16
16
|
expect(getContrastText('#F5F5F5', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
|
|
17
17
|
expect(getContrastText('#FCFCFC', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
it('
|
|
21
|
-
expect(getContrastText('#
|
|
22
|
-
expect(getContrastText('#E9041E',
|
|
20
|
+
it('returns light text on saturated colors where WCAG luminance is ambiguous', () => {
|
|
21
|
+
expect(getContrastText('#E60028', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
22
|
+
expect(getContrastText('#E9041E', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
23
|
+
expect(getContrastText('#E60028', '#0D0D0D', '#EAEAEA')).toBe('#EAEAEA');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('works regardless of which token is lighter', () => {
|
|
27
|
+
expect(getContrastText('#000000', DARK_TEXT, LIGHT_TEXT)).toBe(LIGHT_TEXT);
|
|
28
|
+
expect(getContrastText('#FFFFFF', DARK_TEXT, LIGHT_TEXT)).toBe(DARK_TEXT);
|
|
23
29
|
});
|
|
24
30
|
|
|
25
31
|
it('handles 3-character hex shorthand', () => {
|
|
@@ -27,12 +33,12 @@ describe('getContrastText', () => {
|
|
|
27
33
|
expect(getContrastText('#000', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
28
34
|
});
|
|
29
35
|
|
|
30
|
-
it('handles
|
|
31
|
-
expect(getContrastText('
|
|
32
|
-
expect(getContrastText('
|
|
36
|
+
it('handles rgb color format', () => {
|
|
37
|
+
expect(getContrastText('rgb(0, 0, 0)', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
|
|
38
|
+
expect(getContrastText('rgb(255, 255, 255)', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
|
|
33
39
|
});
|
|
34
40
|
|
|
35
|
-
it('returns null for
|
|
41
|
+
it('returns null for unparseable values', () => {
|
|
36
42
|
expect(
|
|
37
43
|
getContrastText(
|
|
38
44
|
'linear-gradient(130deg, #9355E7 0%, #2E4AA3 60%)',
|
|
@@ -41,8 +47,5 @@ describe('getContrastText', () => {
|
|
|
41
47
|
),
|
|
42
48
|
).toBeNull();
|
|
43
49
|
expect(getContrastText('not-a-color', LIGHT_TEXT, DARK_TEXT)).toBeNull();
|
|
44
|
-
expect(
|
|
45
|
-
getContrastText('rgb(255, 0, 0)', LIGHT_TEXT, DARK_TEXT),
|
|
46
|
-
).toBeNull();
|
|
47
50
|
});
|
|
48
51
|
});
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getLuminance } from 'polished';
|
|
2
|
+
|
|
1
3
|
const RGB_HEX = /^#?(?:([\da-f]{3})[\da-f]?|([\da-f]{6})(?:[\da-f]{2})?)$/i;
|
|
2
4
|
|
|
3
5
|
/** Ensure the consistency of colors between old and new colors */
|
|
@@ -45,22 +47,12 @@ export const hex2RGB = (str: string): [number, number, number] => {
|
|
|
45
47
|
throw new Error('Invalid hex string provided');
|
|
46
48
|
};
|
|
47
49
|
|
|
48
|
-
// WCAG 2.0 relative luminance
|
|
49
|
-
const relativeLuminance = (r: number, g: number, b: number): number => {
|
|
50
|
-
const [rs, gs, bs] = [r, g, b].map((c) => {
|
|
51
|
-
const s = c / 255;
|
|
52
|
-
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
53
|
-
});
|
|
54
|
-
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
50
|
const wcagContrastRatio = (l1: number, l2: number): number =>
|
|
58
51
|
(Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
};
|
|
53
|
+
// Minimum WCAG contrast ratio to consider a text color readable on a background.
|
|
54
|
+
// 3.0 corresponds to WCAG AA for large text — same threshold used by MUI.
|
|
55
|
+
const CONTRAST_THRESHOLD = 3;
|
|
64
56
|
|
|
65
57
|
export const getContrastText = (
|
|
66
58
|
bgColor: string,
|
|
@@ -68,10 +60,16 @@ export const getContrastText = (
|
|
|
68
60
|
textReverse: string,
|
|
69
61
|
): string | null => {
|
|
70
62
|
try {
|
|
71
|
-
const bgLum =
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
63
|
+
const bgLum = getLuminance(bgColor);
|
|
64
|
+
const primaryLum = getLuminance(textPrimary);
|
|
65
|
+
const reverseLum = getLuminance(textReverse);
|
|
66
|
+
|
|
67
|
+
const lighterText = primaryLum >= reverseLum ? textPrimary : textReverse;
|
|
68
|
+
const darkerText = primaryLum >= reverseLum ? textReverse : textPrimary;
|
|
69
|
+
|
|
70
|
+
const lighterContrast = wcagContrastRatio(primaryLum >= reverseLum ? primaryLum : reverseLum, bgLum);
|
|
71
|
+
|
|
72
|
+
return lighterContrast >= CONTRAST_THRESHOLD ? lighterText : darkerText;
|
|
75
73
|
} catch {
|
|
76
74
|
return null;
|
|
77
75
|
}
|