@rific/auto-paper 0.7.0 → 0.9.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/README.md +121 -28
- package/dist/index.d.mts +75 -12
- package/dist/index.d.ts +75 -12
- package/dist/index.js +260 -116
- package/dist/index.mjs +241 -111
- package/package.json +5 -4
- package/src/ThemeProvider.tsx +22 -6
- package/src/ThemeSettingsContext.ts +2 -2
- package/src/components/AppearancePicker.tsx +25 -5
- package/src/components/BlurView.tsx +14 -17
- package/src/components/BottomNavigation.tsx +5 -5
- package/src/components/ColorPicker.tsx +7 -6
- package/src/components/PalettePicker.tsx +11 -11
- package/src/index.ts +11 -4
- package/src/navigation-bar.ts +3 -11
- package/src/redux/themeSlice.ts +4 -4
- package/src/useComputedTheme.ts +104 -24
- package/src/useSwatchGrid.ts +1 -1
- package/src/useTheme.ts +11 -0
- package/src/utils/getColorRoles.ts +29 -0
- package/src/utils/getSwatchContrast.ts +26 -0
- package/src/utils/getThirdColor.ts +103 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { getHex } from './getHex'
|
|
2
|
+
import { getRgb } from './getRgb'
|
|
3
|
+
|
|
4
|
+
type HSL = { h: number; s: number; l: number }
|
|
5
|
+
|
|
6
|
+
function rgbToHsl(r: number, g: number, b: number): HSL {
|
|
7
|
+
r /= 255
|
|
8
|
+
g /= 255
|
|
9
|
+
b /= 255
|
|
10
|
+
|
|
11
|
+
const max = Math.max(r, g, b)
|
|
12
|
+
const min = Math.min(r, g, b)
|
|
13
|
+
const delta = max - min
|
|
14
|
+
|
|
15
|
+
let h = 0
|
|
16
|
+
if (delta !== 0) {
|
|
17
|
+
if (max === r) h = ((g - b) / delta) % 6
|
|
18
|
+
else if (max === g) h = (b - r) / delta + 2
|
|
19
|
+
else h = (r - g) / delta + 4
|
|
20
|
+
h = (h * 60 + 360) % 360
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const l = (max + min) / 2
|
|
24
|
+
const s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1))
|
|
25
|
+
|
|
26
|
+
return { h, s, l }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hslToHex(h: number, s: number, l: number): string {
|
|
30
|
+
const c = (1 - Math.abs(2 * l - 1)) * s
|
|
31
|
+
const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
|
|
32
|
+
const m = l - c / 2
|
|
33
|
+
|
|
34
|
+
let r = 0
|
|
35
|
+
let g = 0
|
|
36
|
+
let b = 0
|
|
37
|
+
|
|
38
|
+
if (h < 60) {
|
|
39
|
+
r = c
|
|
40
|
+
g = x
|
|
41
|
+
b = 0
|
|
42
|
+
} else if (h < 120) {
|
|
43
|
+
r = x
|
|
44
|
+
g = c
|
|
45
|
+
b = 0
|
|
46
|
+
} else if (h < 180) {
|
|
47
|
+
r = 0
|
|
48
|
+
g = c
|
|
49
|
+
b = x
|
|
50
|
+
} else if (h < 240) {
|
|
51
|
+
r = 0
|
|
52
|
+
g = x
|
|
53
|
+
b = c
|
|
54
|
+
} else if (h < 300) {
|
|
55
|
+
r = x
|
|
56
|
+
g = 0
|
|
57
|
+
b = c
|
|
58
|
+
} else {
|
|
59
|
+
r = c
|
|
60
|
+
g = 0
|
|
61
|
+
b = x
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const toInt = (value: number) => Math.round((value + m) * 255)
|
|
65
|
+
return getHex(`rgb(${toInt(r)}, ${toInt(g)}, ${toInt(b)})`) ?? '#000000'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const toRad = (deg: number) => (deg * Math.PI) / 180
|
|
69
|
+
const toDeg = (rad: number) => (rad * 180) / Math.PI
|
|
70
|
+
|
|
71
|
+
// The hue maximally distant from both inputs: the midpoint of the longer arc between them.
|
|
72
|
+
// Falls back to a perpendicular hue when the inputs are exact complements, since both arcs are
|
|
73
|
+
// equal length there, so every point on the perpendicular bisector is equally valid.
|
|
74
|
+
function thirdHue(hA: number, hB: number): number {
|
|
75
|
+
const x = Math.cos(toRad(hA)) + Math.cos(toRad(hB))
|
|
76
|
+
const y = Math.sin(toRad(hA)) + Math.sin(toRad(hB))
|
|
77
|
+
|
|
78
|
+
if (Math.abs(x) < 1e-9 && Math.abs(y) < 1e-9) return (hA + 90) % 360
|
|
79
|
+
|
|
80
|
+
const meanHue = (toDeg(Math.atan2(y, x)) + 360) % 360
|
|
81
|
+
return (meanHue + 180) % 360
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Given two arbitrary colors, derives a third that's maximally distinct in hue from both, useful
|
|
85
|
+
// for a neutral element that shouldn't visually clash with either. Saturation and lightness are
|
|
86
|
+
// averaged from the two inputs.
|
|
87
|
+
export function getThirdColor(colorA: string, colorB: string): string {
|
|
88
|
+
const rgbA = getRgb(colorA)
|
|
89
|
+
const rgbB = getRgb(colorB)
|
|
90
|
+
if (!rgbA) throw new Error(`Invalid color format: ${colorA}`)
|
|
91
|
+
if (!rgbB) throw new Error(`Invalid color format: ${colorB}`)
|
|
92
|
+
|
|
93
|
+
const hslA = rgbToHsl(rgbA.r, rgbA.g, rgbA.b)
|
|
94
|
+
const hslB = rgbToHsl(rgbB.r, rgbB.g, rgbB.b)
|
|
95
|
+
|
|
96
|
+
const h = thirdHue(hslA.h, hslB.h)
|
|
97
|
+
const s = (hslA.s + hslB.s) / 2
|
|
98
|
+
const l = (hslA.l + hslB.l) / 2
|
|
99
|
+
|
|
100
|
+
return hslToHex(h, s, l)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default getThirdColor
|