-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- color - contrast for ratio - luminance calc
- Loading branch information
Showing
9 changed files
with
244 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { describe, it, expect } from 'vitest' | ||
import { fromHEX, purifyHEX } from './color' | ||
|
||
describe('color', () => { | ||
it('purifyHex to 6-digit string', () => { | ||
expect(purifyHEX('#F367DD18')).toBe('F367DD') | ||
expect(purifyHEX('#CCC')).toBe('CCCCCC') | ||
expect(purifyHEX('#2222')).toBe('222222') | ||
}) | ||
|
||
it('convert HEX color to weight number', () => { | ||
expect(fromHEX('#000')).toEqual([0, 0, 0]) | ||
expect(fromHEX('#66666666')).toEqual([0.4, 0.4, 0.4]) | ||
expect(fromHEX('f06')).toEqual([1, 0, 0.4]) | ||
}) | ||
|
||
it('will throw error', () => { | ||
expect(() => fromHEX('0')).toThrow() | ||
// @ts-expect-error testing | ||
expect(() => fromHEX()).toThrow() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
export const purifyHEX = (hex: string) => { | ||
const str = hex.startsWith('#') ? hex.slice(1) : hex | ||
return str.length <= 4 | ||
? `${str[0].repeat(2)}${str[1].repeat(2)}${str[2].repeat(2)}` | ||
: str.slice(0, 6) | ||
} | ||
|
||
/** | ||
* Get each channel weight value from HEX code | ||
* @param hex HEX color string, can omit '#' and support all 3-digit 4-digit, 6-digit, 8-digit color LV4 version. | ||
* @returns Array of `[R, G, B]` value from 0 to 1 | ||
*/ | ||
export const fromHEX = (hex: string): [number, number, number] => { | ||
const hex6 = purifyHEX(hex) | ||
|
||
return [ | ||
parseInt(hex6.slice(0, 2), 16) / 255, | ||
parseInt(hex6.slice(2, 4), 16) / 255, | ||
parseInt(hex6.slice(4, 6), 16) / 255, | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { describe, it, expect } from 'vitest' | ||
import { getContrastRatio } from './contrast' | ||
|
||
describe('contrast', () => { | ||
it('getContrastRatio with given data', () => { | ||
expect(getContrastRatio('#000', '#FFF')).toBe(21) | ||
expect(getContrastRatio('#222', '#222')).toBe(1) | ||
|
||
// chrome: 3.51, chrome floor to 2 digit | ||
expect(Math.floor(getContrastRatio('#DCB487', '#135F96') * 100) / 100).toBe( | ||
3.51 | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { fromHEX } from './color' | ||
import { toRelativeLuminance } from './luminance' | ||
|
||
const SHIFT = 0.05 | ||
|
||
export const getContrastRatio = (c1: string, c2: string): number => { | ||
const l1 = toRelativeLuminance(...fromHEX(c1)) + SHIFT | ||
const l2 = toRelativeLuminance(...fromHEX(c2)) + SHIFT | ||
return l1 > l2 ? l1 / l2 : l2 / l1 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './color' | ||
export * from './luminance' | ||
export * from './contrast' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { describe, it, expect } from 'vitest' | ||
import { standardizeWeight, toRelativeLuminance } from './luminance' | ||
|
||
describe('luminance', () => { | ||
it('standardizeColor with given weight', () => { | ||
expect(standardizeWeight(0), 'black to black').toBe(0) | ||
expect(standardizeWeight(1), 'white to white').toBe(1) | ||
}) | ||
|
||
it('convert given color to relative luminance', () => { | ||
expect(toRelativeLuminance(0, 0, 0)).toBe(0) | ||
expect(toRelativeLuminance(1, 1, 1)).toBe(1) | ||
|
||
expect( | ||
toRelativeLuminance(65 / 255, 90 / 255, 110 / 255), | ||
'#415A6E = 0.095619' | ||
).toBeCloseTo(0.095619, 5) | ||
|
||
expect( | ||
toRelativeLuminance(220 / 255, 180 / 255, 135 / 255), | ||
'#DCB487 = 0.49607' | ||
).toBeCloseTo(0.49607, 5) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
const R_WEIGHT = 0.2126 | ||
const G_WEIGHT = 0.7152 | ||
const B_WEIGHT = 0.0722 | ||
|
||
const L_THRESHOLD = 0.04045 | ||
const L_LINEAR_SLOPE = 12.92 | ||
const GAMMA = 2.4 | ||
|
||
/** | ||
* channel weight in RGB system, 0~1 value. | ||
*/ | ||
export type ColorWeight = number | ||
|
||
/** | ||
* Standardize color weight into perceptual weight | ||
* @param c | ||
* @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance | ||
*/ | ||
export const standardizeWeight = (c: ColorWeight): ColorWeight => | ||
c <= L_THRESHOLD ? c / L_LINEAR_SLOPE : ((c + 0.055) / 1.055) ** GAMMA | ||
|
||
/** | ||
* Standardize color weight into perceptual weight | ||
* @param r sRGB red value in 0~1 | ||
* @param g sRGB green value in 0~1 | ||
* @param b sRGB blue value in 0~1 | ||
* @see https://www.w3.org/TR/WCAG21/#dfn-relative-luminance | ||
*/ | ||
export const toRelativeLuminance = ( | ||
r: ColorWeight, | ||
g: ColorWeight, | ||
b: ColorWeight | ||
): number => | ||
R_WEIGHT * standardizeWeight(r) + | ||
G_WEIGHT * standardizeWeight(g) + | ||
B_WEIGHT * standardizeWeight(b) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.