@marianmeres/stuic 2.1.6 → 2.1.8
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/components/Backdrop/Backdrop.svelte +45 -15
- package/dist/components/Button/Button.svelte +2 -1
- package/dist/components/Button/Button.svelte.d.ts +1 -1
- package/dist/components/ModalDialog/ModalDialog.svelte +50 -15
- package/dist/index.css +2 -2
- package/dist/utils/colors.d.ts +56 -0
- package/dist/utils/colors.js +92 -0
- package/dist/utils/index.d.ts +1 -2
- package/dist/utils/index.js +1 -2
- package/package.json +1 -1
- package/dist/utils/hex-to-oklch.d.ts +0 -1
- package/dist/utils/hex-to-oklch.js +0 -53
- package/dist/utils/hex-to-rgb.d.ts +0 -6
- package/dist/utils/hex-to-rgb.js +0 -12
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
|
|
2
|
+
interface BodyStyles {
|
|
3
|
+
position: string | null;
|
|
4
|
+
top: string | null;
|
|
5
|
+
width: string | null;
|
|
6
|
+
overflow: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function get_body_style(): BodyStyles {
|
|
10
|
+
// const style = window.getComputedStyle(document.body);
|
|
11
|
+
const style = document.body.style; // we want only explicitly defined, not computed
|
|
12
|
+
return {
|
|
13
|
+
position: style.position || null,
|
|
14
|
+
top: style.top || null,
|
|
15
|
+
width: style.width || null,
|
|
16
|
+
overflow: style.overflow || null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function restore_body_styles(original: BodyStyles) {
|
|
21
|
+
(["position", "top", "width", "overflow"] as (keyof BodyStyles)[]).forEach((k) => {
|
|
22
|
+
if (original[k] !== null) {
|
|
23
|
+
document.body.style[k] = original[k];
|
|
24
|
+
} else {
|
|
25
|
+
document.body.style.removeProperty(k);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
3
29
|
</script>
|
|
4
30
|
|
|
5
31
|
<script lang="ts">
|
|
@@ -11,7 +37,7 @@
|
|
|
11
37
|
} from "../../index.js";
|
|
12
38
|
import { createClog } from "@marianmeres/clog";
|
|
13
39
|
import { PressedKeys, watch } from "runed";
|
|
14
|
-
import { type Snippet } from "svelte";
|
|
40
|
+
import { onDestroy, tick, type Snippet } from "svelte";
|
|
15
41
|
import { fade } from "svelte/transition";
|
|
16
42
|
|
|
17
43
|
const clog = createClog("Backdrop").debug;
|
|
@@ -95,29 +121,33 @@
|
|
|
95
121
|
);
|
|
96
122
|
|
|
97
123
|
// lock body scroll when open and restore back
|
|
98
|
-
let _original:
|
|
124
|
+
let _original: BodyStyles = {
|
|
125
|
+
position: null,
|
|
126
|
+
top: null,
|
|
127
|
+
width: null,
|
|
128
|
+
overflow: null,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
function _restore() {
|
|
132
|
+
const scrollY = document.body.style.top;
|
|
133
|
+
restore_body_styles(_original);
|
|
134
|
+
// Restore scroll position
|
|
135
|
+
window.scrollTo(0, parseInt(scrollY || "0") * -1);
|
|
136
|
+
}
|
|
137
|
+
|
|
99
138
|
$effect(() => {
|
|
100
139
|
if (noScrollLock) return;
|
|
101
140
|
if (visible) {
|
|
102
|
-
_original =
|
|
141
|
+
_original = get_body_style();
|
|
103
142
|
const scrollY = window.scrollY;
|
|
104
|
-
|
|
105
143
|
document.body.style.position = "fixed";
|
|
106
144
|
document.body.style.top = `-${scrollY}px`;
|
|
107
145
|
document.body.style.width = "100%";
|
|
108
146
|
document.body.style.overflow = "hidden";
|
|
109
147
|
} else {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
document.body.style.position = _original.position;
|
|
113
|
-
document.body.style.position = "";
|
|
114
|
-
document.body.style.top = "";
|
|
115
|
-
document.body.style.width = "";
|
|
116
|
-
document.body.style.overflow = "";
|
|
117
|
-
|
|
118
|
-
// Restore scroll position
|
|
119
|
-
window.scrollTo(0, parseInt(scrollY || "0") * -1);
|
|
148
|
+
_restore();
|
|
120
149
|
}
|
|
150
|
+
return _restore; // onDestroy as well
|
|
121
151
|
});
|
|
122
152
|
|
|
123
153
|
$effect(() => {
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
rounded-md
|
|
10
10
|
inline-flex items-center justify-center gap-x-2
|
|
11
11
|
px-3 py-2
|
|
12
|
+
select-none
|
|
12
13
|
|
|
13
14
|
hover:brightness-105
|
|
14
15
|
active:brightness-95
|
|
15
|
-
disabled:hover:brightness-100
|
|
16
|
+
disabled:hover:brightness-100 disabled:opacity-50
|
|
16
17
|
|
|
17
18
|
focus:brightness-105
|
|
18
19
|
focus:border-button-border-focus focus:dark:border-button-border-focus-dark
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const BUTTON_STUIC_BASE_CLASSES = "\n\t\tbg-button-bg text-button-text \n\t\tdark:bg-button-bg-dark dark:text-button-text-dark\n\t\tfont-mono text-sm text-center \n\t\tleading-none\n\t\tborder-1\n\t\tborder-button-border dark:border-button-border-dark\n\t\trounded-md\n\t\tinline-flex items-center justify-center gap-x-2\n\t\tpx-3 py-2\n\n\t\thover:brightness-105\n\t\tactive:brightness-95\n\t\tdisabled:hover:brightness-100\n\n\t\tfocus:brightness-105\n\t\tfocus:border-button-border-focus focus:dark:border-button-border-focus-dark\n\n\t\t focus:outline-4 focus:outline-black/10 focus:dark:outline-white/20\n\t\tfocus-visible:outline-4 focus-visible:outline-black/10 focus-visible:dark:outline-white/20\n\t";
|
|
1
|
+
export declare const BUTTON_STUIC_BASE_CLASSES = "\n\t\tbg-button-bg text-button-text \n\t\tdark:bg-button-bg-dark dark:text-button-text-dark\n\t\tfont-mono text-sm text-center \n\t\tleading-none\n\t\tborder-1\n\t\tborder-button-border dark:border-button-border-dark\n\t\trounded-md\n\t\tinline-flex items-center justify-center gap-x-2\n\t\tpx-3 py-2\n\t\tselect-none\n\n\t\thover:brightness-105\n\t\tactive:brightness-95\n\t\tdisabled:hover:brightness-100 disabled:opacity-50\n\n\t\tfocus:brightness-105\n\t\tfocus:border-button-border-focus focus:dark:border-button-border-focus-dark\n\n\t\t focus:outline-4 focus:outline-black/10 focus:dark:outline-white/20\n\t\tfocus-visible:outline-4 focus-visible:outline-black/10 focus-visible:dark:outline-white/20\n\t";
|
|
2
2
|
export declare const BUTTON_STUIC_PRESET_CLASSES: any;
|
|
3
3
|
import type { Snippet } from "svelte";
|
|
4
4
|
import type { HTMLButtonAttributes } from "svelte/elements";
|
|
@@ -1,6 +1,36 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
interface BodyStyles {
|
|
3
|
+
position: string | null;
|
|
4
|
+
top: string | null;
|
|
5
|
+
width: string | null;
|
|
6
|
+
overflow: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function get_body_style(): BodyStyles {
|
|
10
|
+
// const style = window.getComputedStyle(document.body);
|
|
11
|
+
const style = document.body.style; // we want only explicitly defined, not computed
|
|
12
|
+
return {
|
|
13
|
+
position: style.position || null,
|
|
14
|
+
top: style.top || null,
|
|
15
|
+
width: style.width || null,
|
|
16
|
+
overflow: style.overflow || null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function restore_body_styles(original: BodyStyles) {
|
|
21
|
+
(["position", "top", "width", "overflow"] as (keyof BodyStyles)[]).forEach((k) => {
|
|
22
|
+
if (original[k] !== null) {
|
|
23
|
+
document.body.style[k] = original[k];
|
|
24
|
+
} else {
|
|
25
|
+
document.body.style.removeProperty(k);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
1
31
|
<script lang="ts">
|
|
2
32
|
import { onClickOutside } from "runed";
|
|
3
|
-
import { onMount, tick, type Snippet } from "svelte";
|
|
33
|
+
import { onDestroy, onMount, tick, type Snippet } from "svelte";
|
|
4
34
|
import { focusTrap } from "../../actions/focus-trap.js";
|
|
5
35
|
import { stopPropagation } from "../../utils/event-modifiers.js";
|
|
6
36
|
import { twMerge } from "../../utils/tw-merge.js";
|
|
@@ -76,29 +106,34 @@
|
|
|
76
106
|
() => !noClickOutsideClose && close()
|
|
77
107
|
);
|
|
78
108
|
|
|
79
|
-
|
|
109
|
+
// lock body scroll when open and restore back
|
|
110
|
+
let _original: BodyStyles = {
|
|
111
|
+
position: null,
|
|
112
|
+
top: null,
|
|
113
|
+
width: null,
|
|
114
|
+
overflow: null,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
function _restore() {
|
|
118
|
+
const scrollY = document.body.style.top;
|
|
119
|
+
restore_body_styles(_original);
|
|
120
|
+
// Restore scroll position
|
|
121
|
+
window.scrollTo(0, parseInt(scrollY || "0") * -1);
|
|
122
|
+
}
|
|
123
|
+
|
|
80
124
|
$effect(() => {
|
|
81
|
-
// if (noScrollLock) return;
|
|
82
125
|
if (visible) {
|
|
83
|
-
_original =
|
|
126
|
+
_original = get_body_style();
|
|
84
127
|
const scrollY = window.scrollY;
|
|
85
|
-
|
|
86
128
|
document.body.style.position = "fixed";
|
|
87
129
|
document.body.style.top = `-${scrollY}px`;
|
|
88
130
|
document.body.style.width = "100%";
|
|
89
131
|
document.body.style.overflow = "hidden";
|
|
90
132
|
} else {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
document.body.style.position = _original.position;
|
|
94
|
-
document.body.style.position = "";
|
|
95
|
-
document.body.style.top = "";
|
|
96
|
-
document.body.style.width = "";
|
|
97
|
-
document.body.style.overflow = "";
|
|
98
|
-
|
|
99
|
-
// Restore scroll position
|
|
100
|
-
window.scrollTo(0, parseInt(scrollY || "0") * -1);
|
|
133
|
+
_restore();
|
|
101
134
|
}
|
|
135
|
+
// also onDestroy (will also reset if nested... which is not desired, but ignoring currently)
|
|
136
|
+
return _restore;
|
|
102
137
|
});
|
|
103
138
|
|
|
104
139
|
// $inspect("Modal dialog mounted, is visible:", visible).with(clog);
|
package/dist/index.css
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
@source "./";
|
|
7
7
|
|
|
8
8
|
/* "components" looks like a better fit here, but forms plugin uses "utilities"
|
|
9
|
-
so, since we need to override, sticking with that*/
|
|
9
|
+
so, since we need to override, sticking with that */
|
|
10
10
|
@layer utilities {
|
|
11
11
|
@import "./actions/tooltip/index.css";
|
|
12
12
|
@import "./components/Button/index.css";
|
|
@@ -29,6 +29,6 @@ so, since we need to override, sticking with that*/
|
|
|
29
29
|
[role="button"]:disabled,
|
|
30
30
|
input:disabled {
|
|
31
31
|
cursor: not-allowed !important;
|
|
32
|
-
opacity: 0.5 !important;
|
|
32
|
+
/* opacity: 0.5 !important; moved to Button itself, so it can be overridden */
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a CSS HEX color string to an Oklch color string.
|
|
3
|
+
*/
|
|
4
|
+
export declare function hexToOklch(hex: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Converts a sRGB (0-255) to an Oklch color string.
|
|
7
|
+
*/
|
|
8
|
+
export declare function rgbToOklch(rgb: {
|
|
9
|
+
r: number;
|
|
10
|
+
g: number;
|
|
11
|
+
b: number;
|
|
12
|
+
}): string;
|
|
13
|
+
/**
|
|
14
|
+
* Converts a HEX string to an RGB object.
|
|
15
|
+
*/
|
|
16
|
+
export declare function hexToRgb(hex: string): {
|
|
17
|
+
r: number;
|
|
18
|
+
g: number;
|
|
19
|
+
b: number;
|
|
20
|
+
} | null;
|
|
21
|
+
/**
|
|
22
|
+
* Converts sRGB (0-255) to linear RGB (0.0-1.0).
|
|
23
|
+
*/
|
|
24
|
+
export declare function srgbToLinearRgb({ r, g, b }: {
|
|
25
|
+
r: number;
|
|
26
|
+
g: number;
|
|
27
|
+
b: number;
|
|
28
|
+
}): {
|
|
29
|
+
r: number;
|
|
30
|
+
g: number;
|
|
31
|
+
b: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Converts linear RGB (0.0-1.0) to Oklab.
|
|
35
|
+
*/
|
|
36
|
+
export declare function linearRgbToOklab({ r, g, b }: {
|
|
37
|
+
r: number;
|
|
38
|
+
g: number;
|
|
39
|
+
b: number;
|
|
40
|
+
}): {
|
|
41
|
+
l: number;
|
|
42
|
+
a: number;
|
|
43
|
+
b: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Converts Oklab to Oklch.
|
|
47
|
+
*/
|
|
48
|
+
export declare function oklabToOklch({ l, a, b }: {
|
|
49
|
+
l: number;
|
|
50
|
+
a: number;
|
|
51
|
+
b: number;
|
|
52
|
+
}): {
|
|
53
|
+
l: number;
|
|
54
|
+
c: number;
|
|
55
|
+
h: number;
|
|
56
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a CSS HEX color string to an Oklch color string.
|
|
3
|
+
*/
|
|
4
|
+
export function hexToOklch(hex) {
|
|
5
|
+
// 1. Parse HEX to RGB
|
|
6
|
+
const rgb = hexToRgb(hex);
|
|
7
|
+
if (!rgb) {
|
|
8
|
+
throw new Error("Invalid HEX color format.");
|
|
9
|
+
}
|
|
10
|
+
// 2. Convert sRGB (0-255) to oklab
|
|
11
|
+
return rgbToOklch(rgb);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Converts a sRGB (0-255) to an Oklch color string.
|
|
15
|
+
*/
|
|
16
|
+
export function rgbToOklch(rgb) {
|
|
17
|
+
// 1. Convert sRGB (0-255) to Linear RGB (0.0-1.0)
|
|
18
|
+
const linearRgb = srgbToLinearRgb(rgb);
|
|
19
|
+
// 2. Convert Linear RGB to Oklab
|
|
20
|
+
const oklab = linearRgbToOklab(linearRgb);
|
|
21
|
+
// 3. Convert Oklab to Oklch
|
|
22
|
+
const oklch = oklabToOklch(oklab);
|
|
23
|
+
// 4. Format as CSS string
|
|
24
|
+
// L is 0-1, formatted as 0-100%
|
|
25
|
+
// C is 0-0.4 (approx), formatted as a number
|
|
26
|
+
// h is 0-360, formatted as a number (degrees)
|
|
27
|
+
const l = (oklch.l * 100).toFixed(1);
|
|
28
|
+
const c = oklch.c.toFixed(3);
|
|
29
|
+
// Handle hue: NaN becomes 0
|
|
30
|
+
const h = isNaN(oklch.h) ? "0" : oklch.h.toFixed(1);
|
|
31
|
+
return `oklch(${l}% ${c} ${h})`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Converts a HEX string to an RGB object.
|
|
35
|
+
*/
|
|
36
|
+
export function hexToRgb(hex) {
|
|
37
|
+
let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
38
|
+
hex = hex.replace(shorthandRegex, (m, r, g, b) => {
|
|
39
|
+
return r + r + g + g + b + b;
|
|
40
|
+
});
|
|
41
|
+
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
42
|
+
return result
|
|
43
|
+
? {
|
|
44
|
+
r: parseInt(result[1], 16),
|
|
45
|
+
g: parseInt(result[2], 16),
|
|
46
|
+
b: parseInt(result[3], 16),
|
|
47
|
+
}
|
|
48
|
+
: null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Converts sRGB (0-255) to linear RGB (0.0-1.0).
|
|
52
|
+
*/
|
|
53
|
+
export function srgbToLinearRgb({ r, g, b }) {
|
|
54
|
+
const convert = (val) => {
|
|
55
|
+
let v = val / 255;
|
|
56
|
+
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
r: convert(r),
|
|
60
|
+
g: convert(g),
|
|
61
|
+
b: convert(b),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Converts linear RGB (0.0-1.0) to Oklab.
|
|
66
|
+
*/
|
|
67
|
+
export function linearRgbToOklab({ r, g, b }) {
|
|
68
|
+
// Based on the conversion matrices from the Oklab color space specification
|
|
69
|
+
const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
|
|
70
|
+
const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
|
|
71
|
+
const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
|
|
72
|
+
const l_ = Math.cbrt(l);
|
|
73
|
+
const m_ = Math.cbrt(m);
|
|
74
|
+
const s_ = Math.cbrt(s);
|
|
75
|
+
return {
|
|
76
|
+
l: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
|
|
77
|
+
a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
|
|
78
|
+
b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Converts Oklab to Oklch.
|
|
83
|
+
*/
|
|
84
|
+
export function oklabToOklch({ l, a, b }) {
|
|
85
|
+
const c = Math.sqrt(a * a + b * b);
|
|
86
|
+
let h = Math.atan2(b, a) * (180 / Math.PI);
|
|
87
|
+
// Normalize hue to be between 0 and 360
|
|
88
|
+
if (h < 0) {
|
|
89
|
+
h += 360;
|
|
90
|
+
}
|
|
91
|
+
return { l, c, h };
|
|
92
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
export * from "./breakpoint.svelte.js";
|
|
2
|
+
export * from "./colors.js";
|
|
2
3
|
export * from "./debounce.js";
|
|
3
4
|
export * from "./device-pointer.svelte.js";
|
|
4
5
|
export * from "./escape-regex.js";
|
|
5
6
|
export * from "./event-emitter.js";
|
|
6
7
|
export * from "./event-modifiers.js";
|
|
7
8
|
export * from "./get-id.js";
|
|
8
|
-
export * from "./hex-to-oklch.js";
|
|
9
|
-
export * from "./hex-to-rgb.js";
|
|
10
9
|
export * from "./is-browser.js";
|
|
11
10
|
export * from "./is-mac.js";
|
|
12
11
|
export * from "./is-nullish.js";
|
package/dist/utils/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
export * from "./breakpoint.svelte.js";
|
|
2
|
+
export * from "./colors.js";
|
|
2
3
|
export * from "./debounce.js";
|
|
3
4
|
export * from "./device-pointer.svelte.js";
|
|
4
5
|
export * from "./escape-regex.js";
|
|
5
6
|
export * from "./event-emitter.js";
|
|
6
7
|
export * from "./event-modifiers.js";
|
|
7
8
|
export * from "./get-id.js";
|
|
8
|
-
export * from "./hex-to-oklch.js";
|
|
9
|
-
export * from "./hex-to-rgb.js";
|
|
10
9
|
export * from "./is-browser.js";
|
|
11
10
|
export * from "./is-mac.js";
|
|
12
11
|
export * from "./is-nullish.js";
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Converts a hex color string to OKLCH
|
|
4
|
-
* @param {string} hex - The hex color string (with or without leading #)
|
|
5
|
-
* @returns {Object} An object with l (lightness), c (chroma), and h (hue) properties
|
|
6
|
-
*/
|
|
7
|
-
function hexToOklch(hex) {
|
|
8
|
-
// Remove the hash if it exists
|
|
9
|
-
hex = hex.replace(/^#/, "");
|
|
10
|
-
// Handle both 3-digit and 6-digit formats
|
|
11
|
-
if (hex.length === 3) {
|
|
12
|
-
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
|
13
|
-
}
|
|
14
|
-
// Parse the hex values to RGB (0-1)
|
|
15
|
-
const r = parseInt(hex.substring(0, 2), 16) / 255;
|
|
16
|
-
const g = parseInt(hex.substring(2, 4), 16) / 255;
|
|
17
|
-
const b = parseInt(hex.substring(4, 6), 16) / 255;
|
|
18
|
-
// Convert RGB to linear RGB (removing gamma correction)
|
|
19
|
-
const linearR = r <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
|
|
20
|
-
const linearG = g <= 0.04045 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
|
|
21
|
-
const linearB = b <= 0.04045 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
|
|
22
|
-
// Convert to XYZ
|
|
23
|
-
const x = 0.4124 * linearR + 0.3576 * linearG + 0.1805 * linearB;
|
|
24
|
-
const y = 0.2126 * linearR + 0.7152 * linearG + 0.0722 * linearB;
|
|
25
|
-
const z = 0.0193 * linearR + 0.1192 * linearG + 0.9505 * linearB;
|
|
26
|
-
// Convert XYZ to LMS (cone response)
|
|
27
|
-
const l = 0.819 * x + 0.3619 * y - 0.1289 * z;
|
|
28
|
-
const m = 0.0329 * x + 0.9293 * y + 0.0361 * z;
|
|
29
|
-
const s = 0.0482 * x + 0.2645 * y + 0.6886 * z;
|
|
30
|
-
// Apply non-linearity to LMS
|
|
31
|
-
const lp = Math.cbrt(l);
|
|
32
|
-
const mp = Math.cbrt(m);
|
|
33
|
-
const sp = Math.cbrt(s);
|
|
34
|
-
// Convert to Oklab
|
|
35
|
-
const L = 0.2104 * lp + 0.7936 * mp - 0.004 * sp;
|
|
36
|
-
const a = 1.9779 * lp - 2.4285 * mp + 0.4505 * sp;
|
|
37
|
-
const bb = 0.0259 * lp + 0.7827 * mp - 0.8086 * sp;
|
|
38
|
-
// Convert Oklab to Oklch
|
|
39
|
-
const C = Math.sqrt(a * a + bb * bb);
|
|
40
|
-
let h = (Math.atan2(bb, a) * 180) / Math.PI;
|
|
41
|
-
// Ensure hue is positive
|
|
42
|
-
if (h < 0) {
|
|
43
|
-
h += 360;
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
l: parseFloat(L.toFixed(4)),
|
|
47
|
-
c: parseFloat(C.toFixed(4)),
|
|
48
|
-
h: parseFloat(h.toFixed(2)),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// Example usage:
|
|
52
|
-
// const oklch = hexToOklch("#ff5733");
|
|
53
|
-
// console.log(oklch); // Example output: { l: 0.6321, c: 0.1549, h: 27.23 }
|
package/dist/utils/hex-to-rgb.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/** Will convert #fff or #ffffff to {r: 255, g: 255, b: 255} */
|
|
2
|
-
export function hexToRgb(hex) {
|
|
3
|
-
hex = hex.replace(/^#/, "");
|
|
4
|
-
// both 3-digit and 6-digit formats
|
|
5
|
-
if (hex.length === 3) {
|
|
6
|
-
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
|
7
|
-
}
|
|
8
|
-
const r = parseInt(hex.substring(0, 2), 16);
|
|
9
|
-
const g = parseInt(hex.substring(2, 4), 16);
|
|
10
|
-
const b = parseInt(hex.substring(4, 6), 16);
|
|
11
|
-
return { r, g, b };
|
|
12
|
-
}
|