@prototyperco/ui 0.5.0-alpha.0 → 0.5.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/components/accordion.cjs +154 -0
- package/dist/components/accordion.cjs.map +1 -0
- package/dist/components/accordion.d.cts +14 -0
- package/dist/components/accordion.d.ts +14 -0
- package/dist/components/accordion.js +127 -0
- package/dist/components/accordion.js.map +1 -0
- package/dist/components/alert-dialog.cjs +324 -0
- package/dist/components/alert-dialog.cjs.map +1 -0
- package/dist/components/alert-dialog.d.cts +30 -0
- package/dist/components/alert-dialog.d.ts +30 -0
- package/dist/components/alert-dialog.js +289 -0
- package/dist/components/alert-dialog.js.map +1 -0
- package/dist/components/alert.cjs +105 -0
- package/dist/components/alert.cjs.map +1 -0
- package/dist/components/alert.d.cts +17 -0
- package/dist/components/alert.d.ts +17 -0
- package/dist/components/alert.js +78 -0
- package/dist/components/alert.js.map +1 -0
- package/dist/components/autocomplete.cjs +512 -0
- package/dist/components/autocomplete.cjs.map +1 -0
- package/dist/components/autocomplete.d.cts +31 -0
- package/dist/components/autocomplete.d.ts +31 -0
- package/dist/components/autocomplete.js +472 -0
- package/dist/components/autocomplete.js.map +1 -0
- package/dist/components/avatar.cjs +144 -0
- package/dist/components/avatar.cjs.map +1 -0
- package/dist/components/avatar.d.cts +18 -0
- package/dist/components/avatar.d.ts +18 -0
- package/dist/components/avatar.js +115 -0
- package/dist/components/avatar.js.map +1 -0
- package/dist/components/badge.cjs +81 -0
- package/dist/components/badge.cjs.map +1 -0
- package/dist/components/badge.d.cts +13 -0
- package/dist/components/badge.d.ts +13 -0
- package/dist/components/badge.js +56 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/breadcrumb.cjs +142 -0
- package/dist/components/breadcrumb.cjs.map +1 -0
- package/dist/components/breadcrumb.d.cts +20 -0
- package/dist/components/breadcrumb.d.ts +20 -0
- package/dist/components/breadcrumb.js +112 -0
- package/dist/components/breadcrumb.js.map +1 -0
- package/dist/components/button.cjs +145 -0
- package/dist/components/button.cjs.map +1 -0
- package/dist/components/button.d.cts +16 -0
- package/dist/components/button.d.ts +16 -0
- package/dist/components/button.js +120 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/card.cjs +141 -0
- package/dist/components/card.cjs.map +1 -0
- package/dist/components/card.d.cts +23 -0
- package/dist/components/card.d.ts +23 -0
- package/dist/components/card.js +111 -0
- package/dist/components/card.js.map +1 -0
- package/dist/components/checkbox-group.cjs +56 -0
- package/dist/components/checkbox-group.cjs.map +1 -0
- package/dist/components/checkbox-group.d.cts +8 -0
- package/dist/components/checkbox-group.d.ts +8 -0
- package/dist/components/checkbox-group.js +32 -0
- package/dist/components/checkbox-group.js.map +1 -0
- package/dist/components/checkbox.cjs +152 -0
- package/dist/components/checkbox.cjs.map +1 -0
- package/dist/components/checkbox.d.cts +12 -0
- package/dist/components/checkbox.d.ts +12 -0
- package/dist/components/checkbox.js +126 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/collapsible.cjs +89 -0
- package/dist/components/collapsible.cjs.map +1 -0
- package/dist/components/collapsible.d.cts +12 -0
- package/dist/components/collapsible.d.ts +12 -0
- package/dist/components/collapsible.js +63 -0
- package/dist/components/collapsible.js.map +1 -0
- package/dist/components/color-picker.cjs +983 -0
- package/dist/components/color-picker.cjs.map +1 -0
- package/dist/components/color-picker.d.cts +41 -0
- package/dist/components/color-picker.d.ts +41 -0
- package/dist/components/color-picker.js +939 -0
- package/dist/components/color-picker.js.map +1 -0
- package/dist/components/columns.cjs +163 -0
- package/dist/components/columns.cjs.map +1 -0
- package/dist/components/columns.d.cts +16 -0
- package/dist/components/columns.d.ts +16 -0
- package/dist/components/columns.js +136 -0
- package/dist/components/columns.js.map +1 -0
- package/dist/components/combobox.cjs +633 -0
- package/dist/components/combobox.cjs.map +1 -0
- package/dist/components/combobox.d.cts +40 -0
- package/dist/components/combobox.d.ts +40 -0
- package/dist/components/combobox.js +576 -0
- package/dist/components/combobox.js.map +1 -0
- package/dist/components/command-palette.cjs +370 -0
- package/dist/components/command-palette.cjs.map +1 -0
- package/dist/components/command-palette.d.cts +42 -0
- package/dist/components/command-palette.d.ts +42 -0
- package/dist/components/command-palette.js +329 -0
- package/dist/components/command-palette.js.map +1 -0
- package/dist/components/container.cjs +80 -0
- package/dist/components/container.cjs.map +1 -0
- package/dist/components/container.d.cts +27 -0
- package/dist/components/container.d.ts +27 -0
- package/dist/components/container.js +54 -0
- package/dist/components/container.js.map +1 -0
- package/dist/components/context-menu.cjs +309 -0
- package/dist/components/context-menu.cjs.map +1 -0
- package/dist/components/context-menu.d.cts +37 -0
- package/dist/components/context-menu.d.ts +37 -0
- package/dist/components/context-menu.js +271 -0
- package/dist/components/context-menu.js.map +1 -0
- package/dist/components/dialog.cjs +319 -0
- package/dist/components/dialog.cjs.map +1 -0
- package/dist/components/dialog.d.cts +32 -0
- package/dist/components/dialog.d.ts +32 -0
- package/dist/components/dialog.js +285 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/drawer.cjs +185 -0
- package/dist/components/drawer.cjs.map +1 -0
- package/dist/components/drawer.d.cts +32 -0
- package/dist/components/drawer.d.ts +32 -0
- package/dist/components/drawer.js +151 -0
- package/dist/components/drawer.js.map +1 -0
- package/dist/components/field.cjs +334 -0
- package/dist/components/field.cjs.map +1 -0
- package/dist/components/field.d.cts +39 -0
- package/dist/components/field.d.ts +39 -0
- package/dist/components/field.js +299 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/fieldset.cjs +75 -0
- package/dist/components/fieldset.cjs.map +1 -0
- package/dist/components/fieldset.d.cts +12 -0
- package/dist/components/fieldset.d.ts +12 -0
- package/dist/components/fieldset.js +50 -0
- package/dist/components/fieldset.js.map +1 -0
- package/dist/components/form.cjs +52 -0
- package/dist/components/form.cjs.map +1 -0
- package/dist/components/form.d.cts +8 -0
- package/dist/components/form.d.ts +8 -0
- package/dist/components/form.js +28 -0
- package/dist/components/form.js.map +1 -0
- package/dist/components/input-group.cjs +338 -0
- package/dist/components/input-group.cjs.map +1 -0
- package/dist/components/input-group.d.cts +27 -0
- package/dist/components/input-group.d.ts +27 -0
- package/dist/components/input-group.js +307 -0
- package/dist/components/input-group.js.map +1 -0
- package/dist/components/input.cjs +63 -0
- package/dist/components/input.cjs.map +1 -0
- package/dist/components/input.d.cts +8 -0
- package/dist/components/input.d.ts +8 -0
- package/dist/components/input.js +39 -0
- package/dist/components/input.js.map +1 -0
- package/dist/components/label.cjs +54 -0
- package/dist/components/label.cjs.map +1 -0
- package/dist/components/label.d.cts +8 -0
- package/dist/components/label.d.ts +8 -0
- package/dist/components/label.js +28 -0
- package/dist/components/label.js.map +1 -0
- package/dist/components/menu.cjs +305 -0
- package/dist/components/menu.cjs.map +1 -0
- package/dist/components/menu.d.cts +37 -0
- package/dist/components/menu.d.ts +37 -0
- package/dist/components/menu.js +267 -0
- package/dist/components/menu.js.map +1 -0
- package/dist/components/menubar.cjs +503 -0
- package/dist/components/menubar.cjs.map +1 -0
- package/dist/components/menubar.d.cts +37 -0
- package/dist/components/menubar.d.ts +37 -0
- package/dist/components/menubar.js +464 -0
- package/dist/components/menubar.js.map +1 -0
- package/dist/components/meter.cjs +152 -0
- package/dist/components/meter.cjs.map +1 -0
- package/dist/components/meter.d.cts +23 -0
- package/dist/components/meter.d.ts +23 -0
- package/dist/components/meter.js +122 -0
- package/dist/components/meter.js.map +1 -0
- package/dist/components/navigation-menu.cjs +315 -0
- package/dist/components/navigation-menu.cjs.map +1 -0
- package/dist/components/navigation-menu.d.cts +22 -0
- package/dist/components/navigation-menu.d.ts +22 -0
- package/dist/components/navigation-menu.js +283 -0
- package/dist/components/navigation-menu.js.map +1 -0
- package/dist/components/number-field.cjs +217 -0
- package/dist/components/number-field.cjs.map +1 -0
- package/dist/components/number-field.d.cts +23 -0
- package/dist/components/number-field.d.ts +23 -0
- package/dist/components/number-field.js +185 -0
- package/dist/components/number-field.js.map +1 -0
- package/dist/components/popover.cjs +125 -0
- package/dist/components/popover.cjs.map +1 -0
- package/dist/components/popover.d.cts +16 -0
- package/dist/components/popover.d.ts +16 -0
- package/dist/components/popover.js +96 -0
- package/dist/components/popover.js.map +1 -0
- package/dist/components/preview-card.cjs +86 -0
- package/dist/components/preview-card.cjs.map +1 -0
- package/dist/components/preview-card.d.cts +12 -0
- package/dist/components/preview-card.d.ts +12 -0
- package/dist/components/preview-card.js +60 -0
- package/dist/components/preview-card.js.map +1 -0
- package/dist/components/progress.cjs +167 -0
- package/dist/components/progress.cjs.map +1 -0
- package/dist/components/progress.d.cts +23 -0
- package/dist/components/progress.d.ts +23 -0
- package/dist/components/progress.js +137 -0
- package/dist/components/progress.js.map +1 -0
- package/dist/components/radio-group.cjs +98 -0
- package/dist/components/radio-group.cjs.map +1 -0
- package/dist/components/radio-group.d.cts +11 -0
- package/dist/components/radio-group.d.ts +11 -0
- package/dist/components/radio-group.js +73 -0
- package/dist/components/radio-group.js.map +1 -0
- package/dist/components/resizable-panel.cjs +91 -0
- package/dist/components/resizable-panel.cjs.map +1 -0
- package/dist/components/resizable-panel.d.cts +14 -0
- package/dist/components/resizable-panel.d.ts +14 -0
- package/dist/components/resizable-panel.js +69 -0
- package/dist/components/resizable-panel.js.map +1 -0
- package/dist/components/row.cjs +94 -0
- package/dist/components/row.cjs.map +1 -0
- package/dist/components/row.d.cts +27 -0
- package/dist/components/row.d.ts +27 -0
- package/dist/components/row.js +68 -0
- package/dist/components/row.js.map +1 -0
- package/dist/components/scroll-area.cjs +96 -0
- package/dist/components/scroll-area.cjs.map +1 -0
- package/dist/components/scroll-area.d.cts +10 -0
- package/dist/components/scroll-area.d.ts +10 -0
- package/dist/components/scroll-area.js +71 -0
- package/dist/components/scroll-area.js.map +1 -0
- package/dist/components/section.cjs +104 -0
- package/dist/components/section.cjs.map +1 -0
- package/dist/components/section.d.cts +26 -0
- package/dist/components/section.d.ts +26 -0
- package/dist/components/section.js +79 -0
- package/dist/components/section.js.map +1 -0
- package/dist/components/segmented-control.cjs +117 -0
- package/dist/components/segmented-control.cjs.map +1 -0
- package/dist/components/segmented-control.d.cts +16 -0
- package/dist/components/segmented-control.d.ts +16 -0
- package/dist/components/segmented-control.js +91 -0
- package/dist/components/segmented-control.js.map +1 -0
- package/dist/components/select.cjs +273 -0
- package/dist/components/select.cjs.map +1 -0
- package/dist/components/select.d.cts +26 -0
- package/dist/components/select.d.ts +26 -0
- package/dist/components/select.js +239 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/separator.cjs +60 -0
- package/dist/components/separator.cjs.map +1 -0
- package/dist/components/separator.d.cts +8 -0
- package/dist/components/separator.d.ts +8 -0
- package/dist/components/separator.js +36 -0
- package/dist/components/separator.js.map +1 -0
- package/dist/components/skeleton.cjs +54 -0
- package/dist/components/skeleton.cjs.map +1 -0
- package/dist/components/skeleton.d.cts +8 -0
- package/dist/components/skeleton.d.ts +8 -0
- package/dist/components/skeleton.js +28 -0
- package/dist/components/skeleton.js.map +1 -0
- package/dist/components/slider.cjs +221 -0
- package/dist/components/slider.cjs.map +1 -0
- package/dist/components/slider.d.cts +16 -0
- package/dist/components/slider.d.ts +16 -0
- package/dist/components/slider.js +182 -0
- package/dist/components/slider.js.map +1 -0
- package/dist/components/spinner.cjs +97 -0
- package/dist/components/spinner.cjs.map +1 -0
- package/dist/components/spinner.d.cts +13 -0
- package/dist/components/spinner.d.ts +13 -0
- package/dist/components/spinner.js +72 -0
- package/dist/components/spinner.js.map +1 -0
- package/dist/components/switch.cjs +177 -0
- package/dist/components/switch.cjs.map +1 -0
- package/dist/components/switch.d.cts +22 -0
- package/dist/components/switch.d.ts +22 -0
- package/dist/components/switch.js +139 -0
- package/dist/components/switch.js.map +1 -0
- package/dist/components/tabs.cjs +123 -0
- package/dist/components/tabs.cjs.map +1 -0
- package/dist/components/tabs.d.cts +19 -0
- package/dist/components/tabs.d.ts +19 -0
- package/dist/components/tabs.js +95 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/text-field.cjs +290 -0
- package/dist/components/text-field.cjs.map +1 -0
- package/dist/components/text-field.d.cts +27 -0
- package/dist/components/text-field.d.ts +27 -0
- package/dist/components/text-field.js +262 -0
- package/dist/components/text-field.js.map +1 -0
- package/dist/components/textarea.cjs +60 -0
- package/dist/components/textarea.cjs.map +1 -0
- package/dist/components/textarea.d.cts +8 -0
- package/dist/components/textarea.d.ts +8 -0
- package/dist/components/textarea.js +34 -0
- package/dist/components/textarea.js.map +1 -0
- package/dist/components/toast.cjs +167 -0
- package/dist/components/toast.cjs.map +1 -0
- package/dist/components/toast.d.cts +28 -0
- package/dist/components/toast.d.ts +28 -0
- package/dist/components/toast.js +147 -0
- package/dist/components/toast.js.map +1 -0
- package/dist/components/toggle-group.cjs +171 -0
- package/dist/components/toggle-group.cjs.map +1 -0
- package/dist/components/toggle-group.d.cts +18 -0
- package/dist/components/toggle-group.d.ts +18 -0
- package/dist/components/toggle-group.js +136 -0
- package/dist/components/toggle-group.js.map +1 -0
- package/dist/components/toggle.cjs +92 -0
- package/dist/components/toggle.cjs.map +1 -0
- package/dist/components/toggle.d.cts +14 -0
- package/dist/components/toggle.d.ts +14 -0
- package/dist/components/toggle.js +67 -0
- package/dist/components/toggle.js.map +1 -0
- package/dist/components/toolbar.cjs +160 -0
- package/dist/components/toolbar.cjs.map +1 -0
- package/dist/components/toolbar.d.cts +14 -0
- package/dist/components/toolbar.d.ts +14 -0
- package/dist/components/toolbar.js +131 -0
- package/dist/components/toolbar.js.map +1 -0
- package/dist/components/tooltip.cjs +116 -0
- package/dist/components/tooltip.cjs.map +1 -0
- package/dist/components/tooltip.d.cts +13 -0
- package/dist/components/tooltip.d.ts +13 -0
- package/dist/components/tooltip.js +89 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/components/tree-view.cjs +472 -0
- package/dist/components/tree-view.cjs.map +1 -0
- package/dist/components/tree-view.d.cts +33 -0
- package/dist/components/tree-view.d.ts +33 -0
- package/dist/components/tree-view.js +435 -0
- package/dist/components/tree-view.js.map +1 -0
- package/dist/index.cjs +11 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +101 -903
- package/dist/index.d.ts +101 -903
- package/dist/index.js +4 -6
- package/dist/index.js.map +1 -1
- package/dist/lib/color-utils.cjs +315 -0
- package/dist/lib/color-utils.cjs.map +1 -0
- package/dist/lib/color-utils.d.cts +24 -0
- package/dist/lib/color-utils.d.ts +24 -0
- package/dist/lib/color-utils.js +280 -0
- package/dist/lib/color-utils.js.map +1 -0
- package/dist/lib/utils.cjs +35 -0
- package/dist/lib/utils.cjs.map +1 -0
- package/dist/lib/utils.d.cts +5 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +10 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +24 -5
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/lib/color-utils.ts
|
|
21
|
+
var color_utils_exports = {};
|
|
22
|
+
__export(color_utils_exports, {
|
|
23
|
+
clamp: () => clamp,
|
|
24
|
+
formatColor: () => formatColor,
|
|
25
|
+
gamutMapChroma: () => gamutMapChroma,
|
|
26
|
+
hexToRgb: () => hexToRgb,
|
|
27
|
+
isInGamut: () => isInGamut,
|
|
28
|
+
maxChromaForLH: () => maxChromaForLH,
|
|
29
|
+
oklchToRgb: () => oklchToRgb,
|
|
30
|
+
parseColor: () => parseColor,
|
|
31
|
+
renderAreaGradient: () => renderAreaGradient,
|
|
32
|
+
rgbToHex: () => rgbToHex,
|
|
33
|
+
rgbToOklch: () => rgbToOklch
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(color_utils_exports);
|
|
36
|
+
var DEG = Math.PI / 180;
|
|
37
|
+
var MAX_CHROMA = 0.4;
|
|
38
|
+
function clamp(v, min, max) {
|
|
39
|
+
return Math.min(max, Math.max(min, v));
|
|
40
|
+
}
|
|
41
|
+
function round(v, d) {
|
|
42
|
+
const f = 10 ** d;
|
|
43
|
+
return Math.round(v * f) / f;
|
|
44
|
+
}
|
|
45
|
+
function oklchToOklab(l, c, h) {
|
|
46
|
+
const hRad = h * DEG;
|
|
47
|
+
return { L: l, a: c * Math.cos(hRad), b: c * Math.sin(hRad) };
|
|
48
|
+
}
|
|
49
|
+
function oklabToOklch(L, a, b) {
|
|
50
|
+
const c = Math.sqrt(a * a + b * b);
|
|
51
|
+
let h = Math.atan2(b, a) / DEG;
|
|
52
|
+
if (h < 0) h += 360;
|
|
53
|
+
return { l: L, c, h };
|
|
54
|
+
}
|
|
55
|
+
function oklabToLinearRgb(L, a, b) {
|
|
56
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
57
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
58
|
+
const s_ = L - 0.0894841775 * a - 1.291485548 * b;
|
|
59
|
+
const l = l_ * l_ * l_;
|
|
60
|
+
const m = m_ * m_ * m_;
|
|
61
|
+
const s = s_ * s_ * s_;
|
|
62
|
+
return {
|
|
63
|
+
r: 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
64
|
+
g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
65
|
+
b: -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function linearRgbToOklab(r, g, b) {
|
|
69
|
+
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
70
|
+
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
71
|
+
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
72
|
+
return {
|
|
73
|
+
L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
74
|
+
a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
75
|
+
b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function linearToSrgb(c) {
|
|
79
|
+
return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
80
|
+
}
|
|
81
|
+
function srgbToLinear(c) {
|
|
82
|
+
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
83
|
+
}
|
|
84
|
+
function oklchToRgb(l, c, h) {
|
|
85
|
+
const lab = oklchToOklab(l, c, h);
|
|
86
|
+
const lin = oklabToLinearRgb(lab.L, lab.a, lab.b);
|
|
87
|
+
return [
|
|
88
|
+
clamp(Math.round(linearToSrgb(lin.r) * 255), 0, 255),
|
|
89
|
+
clamp(Math.round(linearToSrgb(lin.g) * 255), 0, 255),
|
|
90
|
+
clamp(Math.round(linearToSrgb(lin.b) * 255), 0, 255)
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
function rgbToOklch(r, g, b) {
|
|
94
|
+
const lr = srgbToLinear(r / 255);
|
|
95
|
+
const lg = srgbToLinear(g / 255);
|
|
96
|
+
const lb = srgbToLinear(b / 255);
|
|
97
|
+
const lab = linearRgbToOklab(lr, lg, lb);
|
|
98
|
+
return oklabToOklch(lab.L, lab.a, lab.b);
|
|
99
|
+
}
|
|
100
|
+
function isInGamut(l, c, h) {
|
|
101
|
+
const lab = oklchToOklab(l, c, h);
|
|
102
|
+
const lin = oklabToLinearRgb(lab.L, lab.a, lab.b);
|
|
103
|
+
const eps = 1e-3;
|
|
104
|
+
return lin.r >= -eps && lin.r <= 1 + eps && lin.g >= -eps && lin.g <= 1 + eps && lin.b >= -eps && lin.b <= 1 + eps;
|
|
105
|
+
}
|
|
106
|
+
function gamutMapChroma(l, c, h) {
|
|
107
|
+
if (isInGamut(l, c, h)) return c;
|
|
108
|
+
let lo = 0;
|
|
109
|
+
let hi = c;
|
|
110
|
+
while (hi - lo > 1e-3) {
|
|
111
|
+
const mid = (lo + hi) / 2;
|
|
112
|
+
if (isInGamut(l, mid, h)) lo = mid;
|
|
113
|
+
else hi = mid;
|
|
114
|
+
}
|
|
115
|
+
return lo;
|
|
116
|
+
}
|
|
117
|
+
function maxChromaForLH(l, h) {
|
|
118
|
+
let lo = 0;
|
|
119
|
+
let hi = MAX_CHROMA;
|
|
120
|
+
while (hi - lo > 1e-3) {
|
|
121
|
+
const mid = (lo + hi) / 2;
|
|
122
|
+
if (isInGamut(l, mid, h)) lo = mid;
|
|
123
|
+
else hi = mid;
|
|
124
|
+
}
|
|
125
|
+
return lo;
|
|
126
|
+
}
|
|
127
|
+
function hexToRgb(hex) {
|
|
128
|
+
hex = hex.replace(/^#/, "");
|
|
129
|
+
if (hex.length === 3 || hex.length === 4) {
|
|
130
|
+
hex = hex.split("").map((c) => c + c).join("");
|
|
131
|
+
}
|
|
132
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
133
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
134
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
135
|
+
const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1;
|
|
136
|
+
return [r, g, b, a];
|
|
137
|
+
}
|
|
138
|
+
function rgbToHex(r, g, b, a) {
|
|
139
|
+
const hex = [r, g, b].map((v) => clamp(Math.round(v), 0, 255).toString(16).padStart(2, "0")).join("");
|
|
140
|
+
if (a !== void 0 && a < 1) {
|
|
141
|
+
return `#${hex}${clamp(Math.round(a * 255), 0, 255).toString(16).padStart(2, "0")}`;
|
|
142
|
+
}
|
|
143
|
+
return `#${hex}`;
|
|
144
|
+
}
|
|
145
|
+
function parseColor(input) {
|
|
146
|
+
const s = input.trim().toLowerCase();
|
|
147
|
+
if (s.startsWith("#")) {
|
|
148
|
+
const [r, g, b, a] = hexToRgb(s);
|
|
149
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) return null;
|
|
150
|
+
const oklch = rgbToOklch(r, g, b);
|
|
151
|
+
return { l: oklch.l, c: oklch.c, h: oklch.h, a };
|
|
152
|
+
}
|
|
153
|
+
const oklchMatch = s.match(
|
|
154
|
+
/oklch\(\s*([\d.]+)%?\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+%?))?\s*\)/
|
|
155
|
+
);
|
|
156
|
+
if (oklchMatch) {
|
|
157
|
+
let l = parseFloat(oklchMatch[1]);
|
|
158
|
+
if (l > 1) l /= 100;
|
|
159
|
+
const c = parseFloat(oklchMatch[2]);
|
|
160
|
+
const h = parseFloat(oklchMatch[3]);
|
|
161
|
+
let a = 1;
|
|
162
|
+
if (oklchMatch[4]) {
|
|
163
|
+
a = oklchMatch[4].endsWith("%") ? parseFloat(oklchMatch[4]) / 100 : parseFloat(oklchMatch[4]);
|
|
164
|
+
}
|
|
165
|
+
return { l, c, h, a };
|
|
166
|
+
}
|
|
167
|
+
const rgbMatch = s.match(
|
|
168
|
+
/rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:[,\s/]+([\d.]+%?))?\s*\)/
|
|
169
|
+
);
|
|
170
|
+
if (rgbMatch) {
|
|
171
|
+
const r = parseFloat(rgbMatch[1]);
|
|
172
|
+
const g = parseFloat(rgbMatch[2]);
|
|
173
|
+
const b = parseFloat(rgbMatch[3]);
|
|
174
|
+
let a = 1;
|
|
175
|
+
if (rgbMatch[4]) {
|
|
176
|
+
a = rgbMatch[4].endsWith("%") ? parseFloat(rgbMatch[4]) / 100 : parseFloat(rgbMatch[4]);
|
|
177
|
+
}
|
|
178
|
+
const oklch = rgbToOklch(r, g, b);
|
|
179
|
+
return { l: oklch.l, c: oklch.c, h: oklch.h, a };
|
|
180
|
+
}
|
|
181
|
+
const hslMatch = s.match(
|
|
182
|
+
/hsla?\(\s*([\d.]+)[,\s]+([\d.]+)%[,\s]+([\d.]+)%(?:[,\s/]+([\d.]+%?))?\s*\)/
|
|
183
|
+
);
|
|
184
|
+
if (hslMatch) {
|
|
185
|
+
const [r, g, b] = hslToRgb(
|
|
186
|
+
parseFloat(hslMatch[1]),
|
|
187
|
+
parseFloat(hslMatch[2]),
|
|
188
|
+
parseFloat(hslMatch[3])
|
|
189
|
+
);
|
|
190
|
+
let a = 1;
|
|
191
|
+
if (hslMatch[4]) {
|
|
192
|
+
a = hslMatch[4].endsWith("%") ? parseFloat(hslMatch[4]) / 100 : parseFloat(hslMatch[4]);
|
|
193
|
+
}
|
|
194
|
+
const oklch = rgbToOklch(r, g, b);
|
|
195
|
+
return { l: oklch.l, c: oklch.c, h: oklch.h, a };
|
|
196
|
+
}
|
|
197
|
+
const named = {
|
|
198
|
+
white: "#ffffff",
|
|
199
|
+
black: "#000000",
|
|
200
|
+
red: "#ff0000",
|
|
201
|
+
green: "#008000",
|
|
202
|
+
blue: "#0000ff",
|
|
203
|
+
yellow: "#ffff00",
|
|
204
|
+
cyan: "#00ffff",
|
|
205
|
+
magenta: "#ff00ff",
|
|
206
|
+
orange: "#ffa500",
|
|
207
|
+
transparent: "#00000000"
|
|
208
|
+
};
|
|
209
|
+
if (named[s]) return parseColor(named[s]);
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
function hslToRgb(h, s, l) {
|
|
213
|
+
s /= 100;
|
|
214
|
+
l /= 100;
|
|
215
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
216
|
+
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
217
|
+
const m = l - c / 2;
|
|
218
|
+
let r = 0, g = 0, b = 0;
|
|
219
|
+
if (h < 60) {
|
|
220
|
+
r = c;
|
|
221
|
+
g = x;
|
|
222
|
+
} else if (h < 120) {
|
|
223
|
+
r = x;
|
|
224
|
+
g = c;
|
|
225
|
+
} else if (h < 180) {
|
|
226
|
+
g = c;
|
|
227
|
+
b = x;
|
|
228
|
+
} else if (h < 240) {
|
|
229
|
+
g = x;
|
|
230
|
+
b = c;
|
|
231
|
+
} else if (h < 300) {
|
|
232
|
+
r = x;
|
|
233
|
+
b = c;
|
|
234
|
+
} else {
|
|
235
|
+
r = c;
|
|
236
|
+
b = x;
|
|
237
|
+
}
|
|
238
|
+
return [
|
|
239
|
+
Math.round((r + m) * 255),
|
|
240
|
+
Math.round((g + m) * 255),
|
|
241
|
+
Math.round((b + m) * 255)
|
|
242
|
+
];
|
|
243
|
+
}
|
|
244
|
+
function rgbToHsl(r, g, b) {
|
|
245
|
+
r /= 255;
|
|
246
|
+
g /= 255;
|
|
247
|
+
b /= 255;
|
|
248
|
+
const max = Math.max(r, g, b);
|
|
249
|
+
const min = Math.min(r, g, b);
|
|
250
|
+
const l = (max + min) / 2;
|
|
251
|
+
if (max === min) return [0, 0, l * 100];
|
|
252
|
+
const d = max - min;
|
|
253
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
254
|
+
let h = 0;
|
|
255
|
+
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
256
|
+
else if (max === g) h = ((b - r) / d + 2) / 6;
|
|
257
|
+
else h = ((r - g) / d + 4) / 6;
|
|
258
|
+
return [h * 360, s * 100, l * 100];
|
|
259
|
+
}
|
|
260
|
+
function formatColor(color, format) {
|
|
261
|
+
const hasAlpha = color.a < 1;
|
|
262
|
+
switch (format) {
|
|
263
|
+
case "hex": {
|
|
264
|
+
const [r, g, b] = oklchToRgb(color.l, color.c, color.h);
|
|
265
|
+
return rgbToHex(r, g, b, hasAlpha ? color.a : void 0);
|
|
266
|
+
}
|
|
267
|
+
case "oklch": {
|
|
268
|
+
const l = round(color.l * 100, 1);
|
|
269
|
+
const c = round(color.c, 3);
|
|
270
|
+
const h = round(color.h, 1);
|
|
271
|
+
return hasAlpha ? `oklch(${l}% ${c} ${h} / ${round(color.a, 2)})` : `oklch(${l}% ${c} ${h})`;
|
|
272
|
+
}
|
|
273
|
+
case "rgb": {
|
|
274
|
+
const [r, g, b] = oklchToRgb(color.l, color.c, color.h);
|
|
275
|
+
return hasAlpha ? `rgba(${r}, ${g}, ${b}, ${round(color.a, 2)})` : `rgb(${r}, ${g}, ${b})`;
|
|
276
|
+
}
|
|
277
|
+
case "hsl": {
|
|
278
|
+
const [r, g, b] = oklchToRgb(color.l, color.c, color.h);
|
|
279
|
+
const [h, s, l] = rgbToHsl(r, g, b);
|
|
280
|
+
return hasAlpha ? `hsla(${round(h, 0)}, ${round(s, 1)}%, ${round(l, 1)}%, ${round(color.a, 2)})` : `hsl(${round(h, 0)}, ${round(s, 1)}%, ${round(l, 1)}%)`;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function renderAreaGradient(width, height, hue) {
|
|
285
|
+
const data = new ImageData(width, height);
|
|
286
|
+
const buf = data.data;
|
|
287
|
+
for (let y = 0; y < height; y++) {
|
|
288
|
+
const l = 1 - y / (height - 1);
|
|
289
|
+
for (let x = 0; x < width; x++) {
|
|
290
|
+
const c = x / (width - 1) * MAX_CHROMA;
|
|
291
|
+
const [r, g, b] = oklchToRgb(l, c, hue);
|
|
292
|
+
const idx = (y * width + x) * 4;
|
|
293
|
+
buf[idx] = r;
|
|
294
|
+
buf[idx + 1] = g;
|
|
295
|
+
buf[idx + 2] = b;
|
|
296
|
+
buf[idx + 3] = 255;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return data;
|
|
300
|
+
}
|
|
301
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
302
|
+
0 && (module.exports = {
|
|
303
|
+
clamp,
|
|
304
|
+
formatColor,
|
|
305
|
+
gamutMapChroma,
|
|
306
|
+
hexToRgb,
|
|
307
|
+
isInGamut,
|
|
308
|
+
maxChromaForLH,
|
|
309
|
+
oklchToRgb,
|
|
310
|
+
parseColor,
|
|
311
|
+
renderAreaGradient,
|
|
312
|
+
rgbToHex,
|
|
313
|
+
rgbToOklch
|
|
314
|
+
});
|
|
315
|
+
//# sourceMappingURL=color-utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/color-utils.ts"],"sourcesContent":["/* ============================================================\n * color-utils — OKLCH-native color conversion & gamut mapping\n * ============================================================\n * Pure math, no React.\n * All internal state uses OKLCH { l, c, h, a }.\n * Provides parsing from CSS strings and formatting to hex/oklch/rgb/hsl.\n * ============================================================ */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface OklchColor {\n l: number; // 0 – 1 (lightness)\n c: number; // 0 – 0.4 (chroma)\n h: number; // 0 – 360 (hue, degrees)\n a: number; // 0 – 1 (alpha)\n}\n\nexport type ColorFormat = \"hex\" | \"oklch\" | \"rgb\" | \"hsl\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEG = Math.PI / 180;\nconst MAX_CHROMA = 0.4;\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function clamp(v: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, v));\n}\n\nfunction round(v: number, d: number): number {\n const f = 10 ** d;\n return Math.round(v * f) / f;\n}\n\n// ---------------------------------------------------------------------------\n// OKLCH ↔ OKLab\n// ---------------------------------------------------------------------------\n\nfunction oklchToOklab(l: number, c: number, h: number) {\n const hRad = h * DEG;\n return { L: l, a: c * Math.cos(hRad), b: c * Math.sin(hRad) };\n}\n\nfunction oklabToOklch(L: number, a: number, b: number) {\n const c = Math.sqrt(a * a + b * b);\n let h = Math.atan2(b, a) / DEG;\n if (h < 0) h += 360;\n return { l: L, c, h };\n}\n\n// ---------------------------------------------------------------------------\n// OKLab ↔ Linear sRGB\n// ---------------------------------------------------------------------------\n\nfunction oklabToLinearRgb(L: number, a: number, b: number) {\n const l_ = L + 0.3963377774 * a + 0.2158037573 * b;\n const m_ = L - 0.1055613458 * a - 0.0638541728 * b;\n const s_ = L - 0.0894841775 * a - 1.291485548 * b;\n\n const l = l_ * l_ * l_;\n const m = m_ * m_ * m_;\n const s = s_ * s_ * s_;\n\n return {\n r: +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n b: -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n };\n}\n\nfunction linearRgbToOklab(r: number, g: number, b: number) {\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n\n return {\n L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Linear sRGB ↔ sRGB (gamma)\n// ---------------------------------------------------------------------------\n\nfunction linearToSrgb(c: number): number {\n return c <= 0.0031308 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;\n}\n\nfunction srgbToLinear(c: number): number {\n return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n}\n\n// ---------------------------------------------------------------------------\n// OKLCH → sRGB (clamped 0-255)\n// ---------------------------------------------------------------------------\n\nexport function oklchToRgb(\n l: number,\n c: number,\n h: number,\n): [number, number, number] {\n const lab = oklchToOklab(l, c, h);\n const lin = oklabToLinearRgb(lab.L, lab.a, lab.b);\n return [\n clamp(Math.round(linearToSrgb(lin.r) * 255), 0, 255),\n clamp(Math.round(linearToSrgb(lin.g) * 255), 0, 255),\n clamp(Math.round(linearToSrgb(lin.b) * 255), 0, 255),\n ];\n}\n\n// ---------------------------------------------------------------------------\n// sRGB → OKLCH\n// ---------------------------------------------------------------------------\n\nexport function rgbToOklch(\n r: number,\n g: number,\n b: number,\n): { l: number; c: number; h: number } {\n const lr = srgbToLinear(r / 255);\n const lg = srgbToLinear(g / 255);\n const lb = srgbToLinear(b / 255);\n const lab = linearRgbToOklab(lr, lg, lb);\n return oklabToOklch(lab.L, lab.a, lab.b);\n}\n\n// ---------------------------------------------------------------------------\n// Gamut check — is (l, c, h) within sRGB?\n// ---------------------------------------------------------------------------\n\nexport function isInGamut(l: number, c: number, h: number): boolean {\n const lab = oklchToOklab(l, c, h);\n const lin = oklabToLinearRgb(lab.L, lab.a, lab.b);\n const eps = 0.001;\n return (\n lin.r >= -eps &&\n lin.r <= 1 + eps &&\n lin.g >= -eps &&\n lin.g <= 1 + eps &&\n lin.b >= -eps &&\n lin.b <= 1 + eps\n );\n}\n\n// ---------------------------------------------------------------------------\n// Gamut mapping — reduce chroma until in gamut (binary search)\n// ---------------------------------------------------------------------------\n\nexport function gamutMapChroma(l: number, c: number, h: number): number {\n if (isInGamut(l, c, h)) return c;\n let lo = 0;\n let hi = c;\n while (hi - lo > 0.001) {\n const mid = (lo + hi) / 2;\n if (isInGamut(l, mid, h)) lo = mid;\n else hi = mid;\n }\n return lo;\n}\n\n// ---------------------------------------------------------------------------\n// Max chroma for a given (l, h) — for area rendering\n// ---------------------------------------------------------------------------\n\nexport function maxChromaForLH(l: number, h: number): number {\n let lo = 0;\n let hi = MAX_CHROMA;\n while (hi - lo > 0.001) {\n const mid = (lo + hi) / 2;\n if (isInGamut(l, mid, h)) lo = mid;\n else hi = mid;\n }\n return lo;\n}\n\n// ---------------------------------------------------------------------------\n// Hex parsing & formatting\n// ---------------------------------------------------------------------------\n\nexport function hexToRgb(hex: string): [number, number, number, number] {\n hex = hex.replace(/^#/, \"\");\n if (hex.length === 3 || hex.length === 4) {\n hex = hex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n const r = parseInt(hex.slice(0, 2), 16);\n const g = parseInt(hex.slice(2, 4), 16);\n const b = parseInt(hex.slice(4, 6), 16);\n const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1;\n return [r, g, b, a];\n}\n\nexport function rgbToHex(r: number, g: number, b: number, a?: number): string {\n const hex = [r, g, b]\n .map((v) => clamp(Math.round(v), 0, 255).toString(16).padStart(2, \"0\"))\n .join(\"\");\n if (a !== undefined && a < 1) {\n return `#${hex}${clamp(Math.round(a * 255), 0, 255)\n .toString(16)\n .padStart(2, \"0\")}`;\n }\n return `#${hex}`;\n}\n\n// ---------------------------------------------------------------------------\n// Parse any CSS color string → OklchColor\n// ---------------------------------------------------------------------------\n\nexport function parseColor(input: string): OklchColor | null {\n const s = input.trim().toLowerCase();\n\n // hex: #rgb, #rgba, #rrggbb, #rrggbbaa\n if (s.startsWith(\"#\")) {\n const [r, g, b, a] = hexToRgb(s);\n if (isNaN(r) || isNaN(g) || isNaN(b)) return null;\n const oklch = rgbToOklch(r, g, b);\n return { l: oklch.l, c: oklch.c, h: oklch.h, a };\n }\n\n // oklch(l% c h) or oklch(l% c h / a)\n const oklchMatch = s.match(\n /oklch\\(\\s*([\\d.]+)%?\\s+([\\d.]+)\\s+([\\d.]+)(?:\\s*\\/\\s*([\\d.]+%?))?\\s*\\)/,\n );\n if (oklchMatch) {\n let l = parseFloat(oklchMatch[1]);\n if (l > 1) l /= 100; // handle percentage\n const c = parseFloat(oklchMatch[2]);\n const h = parseFloat(oklchMatch[3]);\n let a = 1;\n if (oklchMatch[4]) {\n a = oklchMatch[4].endsWith(\"%\")\n ? parseFloat(oklchMatch[4]) / 100\n : parseFloat(oklchMatch[4]);\n }\n return { l, c, h, a };\n }\n\n // rgb(r, g, b) or rgb(r g b) or rgba(r, g, b, a)\n const rgbMatch = s.match(\n /rgba?\\(\\s*([\\d.]+)[,\\s]+([\\d.]+)[,\\s]+([\\d.]+)(?:[,\\s/]+([\\d.]+%?))?\\s*\\)/,\n );\n if (rgbMatch) {\n const r = parseFloat(rgbMatch[1]);\n const g = parseFloat(rgbMatch[2]);\n const b = parseFloat(rgbMatch[3]);\n let a = 1;\n if (rgbMatch[4]) {\n a = rgbMatch[4].endsWith(\"%\")\n ? parseFloat(rgbMatch[4]) / 100\n : parseFloat(rgbMatch[4]);\n }\n const oklch = rgbToOklch(r, g, b);\n return { l: oklch.l, c: oklch.c, h: oklch.h, a };\n }\n\n // hsl(h, s%, l%) or hsla(h, s%, l%, a)\n const hslMatch = s.match(\n /hsla?\\(\\s*([\\d.]+)[,\\s]+([\\d.]+)%[,\\s]+([\\d.]+)%(?:[,\\s/]+([\\d.]+%?))?\\s*\\)/,\n );\n if (hslMatch) {\n const [r, g, b] = hslToRgb(\n parseFloat(hslMatch[1]),\n parseFloat(hslMatch[2]),\n parseFloat(hslMatch[3]),\n );\n let a = 1;\n if (hslMatch[4]) {\n a = hslMatch[4].endsWith(\"%\")\n ? parseFloat(hslMatch[4]) / 100\n : parseFloat(hslMatch[4]);\n }\n const oklch = rgbToOklch(r, g, b);\n return { l: oklch.l, c: oklch.c, h: oklch.h, a };\n }\n\n // Named colors — small subset for common use\n const named: Record<string, string> = {\n white: \"#ffffff\",\n black: \"#000000\",\n red: \"#ff0000\",\n green: \"#008000\",\n blue: \"#0000ff\",\n yellow: \"#ffff00\",\n cyan: \"#00ffff\",\n magenta: \"#ff00ff\",\n orange: \"#ffa500\",\n transparent: \"#00000000\",\n };\n if (named[s]) return parseColor(named[s]);\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// HSL ↔ RGB helpers\n// ---------------------------------------------------------------------------\n\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n s /= 100;\n l /= 100;\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = l - c / 2;\n let r = 0,\n g = 0,\n b = 0;\n if (h < 60) {\n r = c;\n g = x;\n } else if (h < 120) {\n r = x;\n g = c;\n } else if (h < 180) {\n g = c;\n b = x;\n } else if (h < 240) {\n g = x;\n b = c;\n } else if (h < 300) {\n r = x;\n b = c;\n } else {\n r = c;\n b = x;\n }\n return [\n Math.round((r + m) * 255),\n Math.round((g + m) * 255),\n Math.round((b + m) * 255),\n ];\n}\n\nfunction rgbToHsl(r: number, g: number, b: number): [number, number, number] {\n r /= 255;\n g /= 255;\n b /= 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const l = (max + min) / 2;\n if (max === min) return [0, 0, l * 100];\n const d = max - min;\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n let h = 0;\n if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;\n else if (max === g) h = ((b - r) / d + 2) / 6;\n else h = ((r - g) / d + 4) / 6;\n return [h * 360, s * 100, l * 100];\n}\n\n// ---------------------------------------------------------------------------\n// Format OklchColor → CSS string\n// ---------------------------------------------------------------------------\n\nexport function formatColor(color: OklchColor, format: ColorFormat): string {\n const hasAlpha = color.a < 1;\n\n switch (format) {\n case \"hex\": {\n const [r, g, b] = oklchToRgb(color.l, color.c, color.h);\n return rgbToHex(r, g, b, hasAlpha ? color.a : undefined);\n }\n case \"oklch\": {\n const l = round(color.l * 100, 1);\n const c = round(color.c, 3);\n const h = round(color.h, 1);\n return hasAlpha\n ? `oklch(${l}% ${c} ${h} / ${round(color.a, 2)})`\n : `oklch(${l}% ${c} ${h})`;\n }\n case \"rgb\": {\n const [r, g, b] = oklchToRgb(color.l, color.c, color.h);\n return hasAlpha\n ? `rgba(${r}, ${g}, ${b}, ${round(color.a, 2)})`\n : `rgb(${r}, ${g}, ${b})`;\n }\n case \"hsl\": {\n const [r, g, b] = oklchToRgb(color.l, color.c, color.h);\n const [h, s, l] = rgbToHsl(r, g, b);\n return hasAlpha\n ? `hsla(${round(h, 0)}, ${round(s, 1)}%, ${round(l, 1)}%, ${round(color.a, 2)})`\n : `hsl(${round(h, 0)}, ${round(s, 1)}%, ${round(l, 1)}%)`;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Render a 2D area gradient (lightness × chroma) for a given hue\n// Returns ImageData to draw onto a canvas\n// ---------------------------------------------------------------------------\n\nexport function renderAreaGradient(\n width: number,\n height: number,\n hue: number,\n): ImageData {\n const data = new ImageData(width, height);\n const buf = data.data;\n\n for (let y = 0; y < height; y++) {\n const l = 1 - y / (height - 1); // top = 1 (light), bottom = 0 (dark)\n for (let x = 0; x < width; x++) {\n const c = (x / (width - 1)) * MAX_CHROMA;\n const [r, g, b] = oklchToRgb(l, c, hue);\n const idx = (y * width + x) * 4;\n buf[idx] = r;\n buf[idx + 1] = g;\n buf[idx + 2] = b;\n buf[idx + 3] = 255;\n }\n }\n\n return data;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface OklchColor {
|
|
2
|
+
l: number;
|
|
3
|
+
c: number;
|
|
4
|
+
h: number;
|
|
5
|
+
a: number;
|
|
6
|
+
}
|
|
7
|
+
type ColorFormat = "hex" | "oklch" | "rgb" | "hsl";
|
|
8
|
+
declare function clamp(v: number, min: number, max: number): number;
|
|
9
|
+
declare function oklchToRgb(l: number, c: number, h: number): [number, number, number];
|
|
10
|
+
declare function rgbToOklch(r: number, g: number, b: number): {
|
|
11
|
+
l: number;
|
|
12
|
+
c: number;
|
|
13
|
+
h: number;
|
|
14
|
+
};
|
|
15
|
+
declare function isInGamut(l: number, c: number, h: number): boolean;
|
|
16
|
+
declare function gamutMapChroma(l: number, c: number, h: number): number;
|
|
17
|
+
declare function maxChromaForLH(l: number, h: number): number;
|
|
18
|
+
declare function hexToRgb(hex: string): [number, number, number, number];
|
|
19
|
+
declare function rgbToHex(r: number, g: number, b: number, a?: number): string;
|
|
20
|
+
declare function parseColor(input: string): OklchColor | null;
|
|
21
|
+
declare function formatColor(color: OklchColor, format: ColorFormat): string;
|
|
22
|
+
declare function renderAreaGradient(width: number, height: number, hue: number): ImageData;
|
|
23
|
+
|
|
24
|
+
export { type ColorFormat, type OklchColor, clamp, formatColor, gamutMapChroma, hexToRgb, isInGamut, maxChromaForLH, oklchToRgb, parseColor, renderAreaGradient, rgbToHex, rgbToOklch };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface OklchColor {
|
|
2
|
+
l: number;
|
|
3
|
+
c: number;
|
|
4
|
+
h: number;
|
|
5
|
+
a: number;
|
|
6
|
+
}
|
|
7
|
+
type ColorFormat = "hex" | "oklch" | "rgb" | "hsl";
|
|
8
|
+
declare function clamp(v: number, min: number, max: number): number;
|
|
9
|
+
declare function oklchToRgb(l: number, c: number, h: number): [number, number, number];
|
|
10
|
+
declare function rgbToOklch(r: number, g: number, b: number): {
|
|
11
|
+
l: number;
|
|
12
|
+
c: number;
|
|
13
|
+
h: number;
|
|
14
|
+
};
|
|
15
|
+
declare function isInGamut(l: number, c: number, h: number): boolean;
|
|
16
|
+
declare function gamutMapChroma(l: number, c: number, h: number): number;
|
|
17
|
+
declare function maxChromaForLH(l: number, h: number): number;
|
|
18
|
+
declare function hexToRgb(hex: string): [number, number, number, number];
|
|
19
|
+
declare function rgbToHex(r: number, g: number, b: number, a?: number): string;
|
|
20
|
+
declare function parseColor(input: string): OklchColor | null;
|
|
21
|
+
declare function formatColor(color: OklchColor, format: ColorFormat): string;
|
|
22
|
+
declare function renderAreaGradient(width: number, height: number, hue: number): ImageData;
|
|
23
|
+
|
|
24
|
+
export { type ColorFormat, type OklchColor, clamp, formatColor, gamutMapChroma, hexToRgb, isInGamut, maxChromaForLH, oklchToRgb, parseColor, renderAreaGradient, rgbToHex, rgbToOklch };
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// src/lib/color-utils.ts
|
|
2
|
+
var DEG = Math.PI / 180;
|
|
3
|
+
var MAX_CHROMA = 0.4;
|
|
4
|
+
function clamp(v, min, max) {
|
|
5
|
+
return Math.min(max, Math.max(min, v));
|
|
6
|
+
}
|
|
7
|
+
function round(v, d) {
|
|
8
|
+
const f = 10 ** d;
|
|
9
|
+
return Math.round(v * f) / f;
|
|
10
|
+
}
|
|
11
|
+
function oklchToOklab(l, c, h) {
|
|
12
|
+
const hRad = h * DEG;
|
|
13
|
+
return { L: l, a: c * Math.cos(hRad), b: c * Math.sin(hRad) };
|
|
14
|
+
}
|
|
15
|
+
function oklabToOklch(L, a, b) {
|
|
16
|
+
const c = Math.sqrt(a * a + b * b);
|
|
17
|
+
let h = Math.atan2(b, a) / DEG;
|
|
18
|
+
if (h < 0) h += 360;
|
|
19
|
+
return { l: L, c, h };
|
|
20
|
+
}
|
|
21
|
+
function oklabToLinearRgb(L, a, b) {
|
|
22
|
+
const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
|
|
23
|
+
const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
|
|
24
|
+
const s_ = L - 0.0894841775 * a - 1.291485548 * b;
|
|
25
|
+
const l = l_ * l_ * l_;
|
|
26
|
+
const m = m_ * m_ * m_;
|
|
27
|
+
const s = s_ * s_ * s_;
|
|
28
|
+
return {
|
|
29
|
+
r: 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
30
|
+
g: -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
31
|
+
b: -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function linearRgbToOklab(r, g, b) {
|
|
35
|
+
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
36
|
+
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
37
|
+
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
38
|
+
return {
|
|
39
|
+
L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
40
|
+
a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
41
|
+
b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function linearToSrgb(c) {
|
|
45
|
+
return c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
|
|
46
|
+
}
|
|
47
|
+
function srgbToLinear(c) {
|
|
48
|
+
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
49
|
+
}
|
|
50
|
+
function oklchToRgb(l, c, h) {
|
|
51
|
+
const lab = oklchToOklab(l, c, h);
|
|
52
|
+
const lin = oklabToLinearRgb(lab.L, lab.a, lab.b);
|
|
53
|
+
return [
|
|
54
|
+
clamp(Math.round(linearToSrgb(lin.r) * 255), 0, 255),
|
|
55
|
+
clamp(Math.round(linearToSrgb(lin.g) * 255), 0, 255),
|
|
56
|
+
clamp(Math.round(linearToSrgb(lin.b) * 255), 0, 255)
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
function rgbToOklch(r, g, b) {
|
|
60
|
+
const lr = srgbToLinear(r / 255);
|
|
61
|
+
const lg = srgbToLinear(g / 255);
|
|
62
|
+
const lb = srgbToLinear(b / 255);
|
|
63
|
+
const lab = linearRgbToOklab(lr, lg, lb);
|
|
64
|
+
return oklabToOklch(lab.L, lab.a, lab.b);
|
|
65
|
+
}
|
|
66
|
+
function isInGamut(l, c, h) {
|
|
67
|
+
const lab = oklchToOklab(l, c, h);
|
|
68
|
+
const lin = oklabToLinearRgb(lab.L, lab.a, lab.b);
|
|
69
|
+
const eps = 1e-3;
|
|
70
|
+
return lin.r >= -eps && lin.r <= 1 + eps && lin.g >= -eps && lin.g <= 1 + eps && lin.b >= -eps && lin.b <= 1 + eps;
|
|
71
|
+
}
|
|
72
|
+
function gamutMapChroma(l, c, h) {
|
|
73
|
+
if (isInGamut(l, c, h)) return c;
|
|
74
|
+
let lo = 0;
|
|
75
|
+
let hi = c;
|
|
76
|
+
while (hi - lo > 1e-3) {
|
|
77
|
+
const mid = (lo + hi) / 2;
|
|
78
|
+
if (isInGamut(l, mid, h)) lo = mid;
|
|
79
|
+
else hi = mid;
|
|
80
|
+
}
|
|
81
|
+
return lo;
|
|
82
|
+
}
|
|
83
|
+
function maxChromaForLH(l, h) {
|
|
84
|
+
let lo = 0;
|
|
85
|
+
let hi = MAX_CHROMA;
|
|
86
|
+
while (hi - lo > 1e-3) {
|
|
87
|
+
const mid = (lo + hi) / 2;
|
|
88
|
+
if (isInGamut(l, mid, h)) lo = mid;
|
|
89
|
+
else hi = mid;
|
|
90
|
+
}
|
|
91
|
+
return lo;
|
|
92
|
+
}
|
|
93
|
+
function hexToRgb(hex) {
|
|
94
|
+
hex = hex.replace(/^#/, "");
|
|
95
|
+
if (hex.length === 3 || hex.length === 4) {
|
|
96
|
+
hex = hex.split("").map((c) => c + c).join("");
|
|
97
|
+
}
|
|
98
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
99
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
100
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
101
|
+
const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1;
|
|
102
|
+
return [r, g, b, a];
|
|
103
|
+
}
|
|
104
|
+
function rgbToHex(r, g, b, a) {
|
|
105
|
+
const hex = [r, g, b].map((v) => clamp(Math.round(v), 0, 255).toString(16).padStart(2, "0")).join("");
|
|
106
|
+
if (a !== void 0 && a < 1) {
|
|
107
|
+
return `#${hex}${clamp(Math.round(a * 255), 0, 255).toString(16).padStart(2, "0")}`;
|
|
108
|
+
}
|
|
109
|
+
return `#${hex}`;
|
|
110
|
+
}
|
|
111
|
+
function parseColor(input) {
|
|
112
|
+
const s = input.trim().toLowerCase();
|
|
113
|
+
if (s.startsWith("#")) {
|
|
114
|
+
const [r, g, b, a] = hexToRgb(s);
|
|
115
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) return null;
|
|
116
|
+
const oklch = rgbToOklch(r, g, b);
|
|
117
|
+
return { l: oklch.l, c: oklch.c, h: oklch.h, a };
|
|
118
|
+
}
|
|
119
|
+
const oklchMatch = s.match(
|
|
120
|
+
/oklch\(\s*([\d.]+)%?\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+%?))?\s*\)/
|
|
121
|
+
);
|
|
122
|
+
if (oklchMatch) {
|
|
123
|
+
let l = parseFloat(oklchMatch[1]);
|
|
124
|
+
if (l > 1) l /= 100;
|
|
125
|
+
const c = parseFloat(oklchMatch[2]);
|
|
126
|
+
const h = parseFloat(oklchMatch[3]);
|
|
127
|
+
let a = 1;
|
|
128
|
+
if (oklchMatch[4]) {
|
|
129
|
+
a = oklchMatch[4].endsWith("%") ? parseFloat(oklchMatch[4]) / 100 : parseFloat(oklchMatch[4]);
|
|
130
|
+
}
|
|
131
|
+
return { l, c, h, a };
|
|
132
|
+
}
|
|
133
|
+
const rgbMatch = s.match(
|
|
134
|
+
/rgba?\(\s*([\d.]+)[,\s]+([\d.]+)[,\s]+([\d.]+)(?:[,\s/]+([\d.]+%?))?\s*\)/
|
|
135
|
+
);
|
|
136
|
+
if (rgbMatch) {
|
|
137
|
+
const r = parseFloat(rgbMatch[1]);
|
|
138
|
+
const g = parseFloat(rgbMatch[2]);
|
|
139
|
+
const b = parseFloat(rgbMatch[3]);
|
|
140
|
+
let a = 1;
|
|
141
|
+
if (rgbMatch[4]) {
|
|
142
|
+
a = rgbMatch[4].endsWith("%") ? parseFloat(rgbMatch[4]) / 100 : parseFloat(rgbMatch[4]);
|
|
143
|
+
}
|
|
144
|
+
const oklch = rgbToOklch(r, g, b);
|
|
145
|
+
return { l: oklch.l, c: oklch.c, h: oklch.h, a };
|
|
146
|
+
}
|
|
147
|
+
const hslMatch = s.match(
|
|
148
|
+
/hsla?\(\s*([\d.]+)[,\s]+([\d.]+)%[,\s]+([\d.]+)%(?:[,\s/]+([\d.]+%?))?\s*\)/
|
|
149
|
+
);
|
|
150
|
+
if (hslMatch) {
|
|
151
|
+
const [r, g, b] = hslToRgb(
|
|
152
|
+
parseFloat(hslMatch[1]),
|
|
153
|
+
parseFloat(hslMatch[2]),
|
|
154
|
+
parseFloat(hslMatch[3])
|
|
155
|
+
);
|
|
156
|
+
let a = 1;
|
|
157
|
+
if (hslMatch[4]) {
|
|
158
|
+
a = hslMatch[4].endsWith("%") ? parseFloat(hslMatch[4]) / 100 : parseFloat(hslMatch[4]);
|
|
159
|
+
}
|
|
160
|
+
const oklch = rgbToOklch(r, g, b);
|
|
161
|
+
return { l: oklch.l, c: oklch.c, h: oklch.h, a };
|
|
162
|
+
}
|
|
163
|
+
const named = {
|
|
164
|
+
white: "#ffffff",
|
|
165
|
+
black: "#000000",
|
|
166
|
+
red: "#ff0000",
|
|
167
|
+
green: "#008000",
|
|
168
|
+
blue: "#0000ff",
|
|
169
|
+
yellow: "#ffff00",
|
|
170
|
+
cyan: "#00ffff",
|
|
171
|
+
magenta: "#ff00ff",
|
|
172
|
+
orange: "#ffa500",
|
|
173
|
+
transparent: "#00000000"
|
|
174
|
+
};
|
|
175
|
+
if (named[s]) return parseColor(named[s]);
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
function hslToRgb(h, s, l) {
|
|
179
|
+
s /= 100;
|
|
180
|
+
l /= 100;
|
|
181
|
+
const c = (1 - Math.abs(2 * l - 1)) * s;
|
|
182
|
+
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
183
|
+
const m = l - c / 2;
|
|
184
|
+
let r = 0, g = 0, b = 0;
|
|
185
|
+
if (h < 60) {
|
|
186
|
+
r = c;
|
|
187
|
+
g = x;
|
|
188
|
+
} else if (h < 120) {
|
|
189
|
+
r = x;
|
|
190
|
+
g = c;
|
|
191
|
+
} else if (h < 180) {
|
|
192
|
+
g = c;
|
|
193
|
+
b = x;
|
|
194
|
+
} else if (h < 240) {
|
|
195
|
+
g = x;
|
|
196
|
+
b = c;
|
|
197
|
+
} else if (h < 300) {
|
|
198
|
+
r = x;
|
|
199
|
+
b = c;
|
|
200
|
+
} else {
|
|
201
|
+
r = c;
|
|
202
|
+
b = x;
|
|
203
|
+
}
|
|
204
|
+
return [
|
|
205
|
+
Math.round((r + m) * 255),
|
|
206
|
+
Math.round((g + m) * 255),
|
|
207
|
+
Math.round((b + m) * 255)
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
function rgbToHsl(r, g, b) {
|
|
211
|
+
r /= 255;
|
|
212
|
+
g /= 255;
|
|
213
|
+
b /= 255;
|
|
214
|
+
const max = Math.max(r, g, b);
|
|
215
|
+
const min = Math.min(r, g, b);
|
|
216
|
+
const l = (max + min) / 2;
|
|
217
|
+
if (max === min) return [0, 0, l * 100];
|
|
218
|
+
const d = max - min;
|
|
219
|
+
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
220
|
+
let h = 0;
|
|
221
|
+
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
222
|
+
else if (max === g) h = ((b - r) / d + 2) / 6;
|
|
223
|
+
else h = ((r - g) / d + 4) / 6;
|
|
224
|
+
return [h * 360, s * 100, l * 100];
|
|
225
|
+
}
|
|
226
|
+
function formatColor(color, format) {
|
|
227
|
+
const hasAlpha = color.a < 1;
|
|
228
|
+
switch (format) {
|
|
229
|
+
case "hex": {
|
|
230
|
+
const [r, g, b] = oklchToRgb(color.l, color.c, color.h);
|
|
231
|
+
return rgbToHex(r, g, b, hasAlpha ? color.a : void 0);
|
|
232
|
+
}
|
|
233
|
+
case "oklch": {
|
|
234
|
+
const l = round(color.l * 100, 1);
|
|
235
|
+
const c = round(color.c, 3);
|
|
236
|
+
const h = round(color.h, 1);
|
|
237
|
+
return hasAlpha ? `oklch(${l}% ${c} ${h} / ${round(color.a, 2)})` : `oklch(${l}% ${c} ${h})`;
|
|
238
|
+
}
|
|
239
|
+
case "rgb": {
|
|
240
|
+
const [r, g, b] = oklchToRgb(color.l, color.c, color.h);
|
|
241
|
+
return hasAlpha ? `rgba(${r}, ${g}, ${b}, ${round(color.a, 2)})` : `rgb(${r}, ${g}, ${b})`;
|
|
242
|
+
}
|
|
243
|
+
case "hsl": {
|
|
244
|
+
const [r, g, b] = oklchToRgb(color.l, color.c, color.h);
|
|
245
|
+
const [h, s, l] = rgbToHsl(r, g, b);
|
|
246
|
+
return hasAlpha ? `hsla(${round(h, 0)}, ${round(s, 1)}%, ${round(l, 1)}%, ${round(color.a, 2)})` : `hsl(${round(h, 0)}, ${round(s, 1)}%, ${round(l, 1)}%)`;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function renderAreaGradient(width, height, hue) {
|
|
251
|
+
const data = new ImageData(width, height);
|
|
252
|
+
const buf = data.data;
|
|
253
|
+
for (let y = 0; y < height; y++) {
|
|
254
|
+
const l = 1 - y / (height - 1);
|
|
255
|
+
for (let x = 0; x < width; x++) {
|
|
256
|
+
const c = x / (width - 1) * MAX_CHROMA;
|
|
257
|
+
const [r, g, b] = oklchToRgb(l, c, hue);
|
|
258
|
+
const idx = (y * width + x) * 4;
|
|
259
|
+
buf[idx] = r;
|
|
260
|
+
buf[idx + 1] = g;
|
|
261
|
+
buf[idx + 2] = b;
|
|
262
|
+
buf[idx + 3] = 255;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return data;
|
|
266
|
+
}
|
|
267
|
+
export {
|
|
268
|
+
clamp,
|
|
269
|
+
formatColor,
|
|
270
|
+
gamutMapChroma,
|
|
271
|
+
hexToRgb,
|
|
272
|
+
isInGamut,
|
|
273
|
+
maxChromaForLH,
|
|
274
|
+
oklchToRgb,
|
|
275
|
+
parseColor,
|
|
276
|
+
renderAreaGradient,
|
|
277
|
+
rgbToHex,
|
|
278
|
+
rgbToOklch
|
|
279
|
+
};
|
|
280
|
+
//# sourceMappingURL=color-utils.js.map
|