aporia 0.1.0 → 0.2.1
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 +31 -23
- package/dist/ThemeProvider.d.ts +1 -3
- package/dist/ThemeProvider.d.ts.map +1 -1
- package/dist/components/Category.d.ts +21 -0
- package/dist/components/Category.d.ts.map +1 -0
- package/dist/components/ColorPicker.d.ts +6 -0
- package/dist/components/ColorPicker.d.ts.map +1 -0
- package/dist/components/ColorRow.d.ts +2 -1
- package/dist/components/ColorRow.d.ts.map +1 -1
- package/dist/components/GradientPicker.d.ts +1 -1
- package/dist/components/GradientPicker.d.ts.map +1 -1
- package/dist/components/GradientRow.d.ts +2 -1
- package/dist/components/GradientRow.d.ts.map +1 -1
- package/dist/components/Panel.d.ts +10 -0
- package/dist/components/Panel.d.ts.map +1 -0
- package/dist/components/SliderRow.d.ts +3 -1
- package/dist/components/SliderRow.d.ts.map +1 -1
- package/dist/components/SwatchPopover.d.ts +7 -1
- package/dist/components/SwatchPopover.d.ts.map +1 -1
- package/dist/components/ToggleRow.d.ts +2 -1
- package/dist/components/ToggleRow.d.ts.map +1 -1
- package/dist/components/ValueInput.d.ts +66 -0
- package/dist/components/ValueInput.d.ts.map +1 -0
- package/dist/components/categoryDisabledContext.d.ts +8 -0
- package/dist/components/categoryDisabledContext.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1682 -433
- package/dist/index.js.map +1 -1
- package/dist/style.css +624 -245
- package/dist/utils/colorSpace.d.ts +41 -0
- package/dist/utils/colorSpace.d.ts.map +1 -0
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,425 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import t, { useContext, createContext, useId, useState, useCallback, useEffect, useRef, useLayoutEffect, useMemo } from "react";
|
|
3
6
|
import { useMotionValue, useSpring, useTransform, motion } from "motion/react";
|
|
4
7
|
import { Popover } from "@base-ui/react";
|
|
8
|
+
function Panel({ children, className, ...rest }) {
|
|
9
|
+
return /* @__PURE__ */ jsx(
|
|
10
|
+
"div",
|
|
11
|
+
{
|
|
12
|
+
className: ["aporiaPanel", className].filter(Boolean).join(" "),
|
|
13
|
+
...rest,
|
|
14
|
+
children
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
const CategoryDisabledContext = createContext(false);
|
|
19
|
+
function CategoryDisabledProvider({
|
|
20
|
+
value,
|
|
21
|
+
children
|
|
22
|
+
}) {
|
|
23
|
+
return /* @__PURE__ */ jsx(CategoryDisabledContext.Provider, { value, children });
|
|
24
|
+
}
|
|
25
|
+
function useCategoryDisabled() {
|
|
26
|
+
return useContext(CategoryDisabledContext);
|
|
27
|
+
}
|
|
28
|
+
function Category({
|
|
29
|
+
title,
|
|
30
|
+
children,
|
|
31
|
+
disabled = false,
|
|
32
|
+
onDisabledChange,
|
|
33
|
+
collapsed: collapsedProp,
|
|
34
|
+
onCollapsedChange,
|
|
35
|
+
defaultCollapsed = false,
|
|
36
|
+
className
|
|
37
|
+
}) {
|
|
38
|
+
const bodyId = useId();
|
|
39
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(defaultCollapsed);
|
|
40
|
+
const collapsed = collapsedProp !== void 0 ? collapsedProp : uncontrolledCollapsed;
|
|
41
|
+
const setCollapsed = useCallback(
|
|
42
|
+
(next) => {
|
|
43
|
+
onCollapsedChange == null ? void 0 : onCollapsedChange(next);
|
|
44
|
+
if (collapsedProp === void 0) {
|
|
45
|
+
setUncontrolledCollapsed(next);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
[collapsedProp, onCollapsedChange]
|
|
49
|
+
);
|
|
50
|
+
return /* @__PURE__ */ jsxs(
|
|
51
|
+
"section",
|
|
52
|
+
{
|
|
53
|
+
className: ["category", className].filter(Boolean).join(" "),
|
|
54
|
+
"data-disabled": disabled ? "true" : "false",
|
|
55
|
+
children: [
|
|
56
|
+
/* @__PURE__ */ jsxs("div", { className: "categoryHeader", children: [
|
|
57
|
+
/* @__PURE__ */ jsxs("div", { className: "categoryHeaderStart", children: [
|
|
58
|
+
/* @__PURE__ */ jsx("div", { className: "categoryChevronReveal", children: /* @__PURE__ */ jsx(
|
|
59
|
+
"button",
|
|
60
|
+
{
|
|
61
|
+
type: "button",
|
|
62
|
+
className: "categoryChevronBtn",
|
|
63
|
+
"aria-expanded": !collapsed,
|
|
64
|
+
"aria-controls": bodyId,
|
|
65
|
+
"aria-label": collapsed ? "Expand category" : "Collapse category",
|
|
66
|
+
onClick: () => setCollapsed(!collapsed),
|
|
67
|
+
children: /* @__PURE__ */ jsx(
|
|
68
|
+
"svg",
|
|
69
|
+
{
|
|
70
|
+
className: "categoryChevronIcon",
|
|
71
|
+
"data-collapsed": collapsed ? "true" : "false",
|
|
72
|
+
width: "12",
|
|
73
|
+
height: "12",
|
|
74
|
+
viewBox: "0 0 12 12",
|
|
75
|
+
"aria-hidden": true,
|
|
76
|
+
children: /* @__PURE__ */ jsx(
|
|
77
|
+
"path",
|
|
78
|
+
{
|
|
79
|
+
d: "M3 4.5L6 7.5L9 4.5",
|
|
80
|
+
fill: "none",
|
|
81
|
+
stroke: "currentColor",
|
|
82
|
+
strokeWidth: "1.5",
|
|
83
|
+
strokeLinecap: "round",
|
|
84
|
+
strokeLinejoin: "round"
|
|
85
|
+
}
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
) }),
|
|
91
|
+
/* @__PURE__ */ jsx("h2", { className: "categoryTitle", id: `${bodyId}-label`, children: title })
|
|
92
|
+
] }),
|
|
93
|
+
onDisabledChange ? /* @__PURE__ */ jsx(
|
|
94
|
+
"button",
|
|
95
|
+
{
|
|
96
|
+
type: "button",
|
|
97
|
+
className: "categoryDisabledDot",
|
|
98
|
+
"aria-label": disabled ? "Enable category" : "Disable category",
|
|
99
|
+
"aria-pressed": disabled,
|
|
100
|
+
onClick: (e) => {
|
|
101
|
+
e.stopPropagation();
|
|
102
|
+
onDisabledChange(!disabled);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
) : null
|
|
106
|
+
] }),
|
|
107
|
+
/* @__PURE__ */ jsx(CategoryDisabledProvider, { value: disabled, children: /* @__PURE__ */ jsx(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
id: bodyId,
|
|
111
|
+
className: "categoryBody sliderGroup",
|
|
112
|
+
role: "region",
|
|
113
|
+
"aria-labelledby": `${bodyId}-label`,
|
|
114
|
+
hidden: collapsed,
|
|
115
|
+
"aria-hidden": collapsed,
|
|
116
|
+
children
|
|
117
|
+
}
|
|
118
|
+
) })
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
function $(n2, e, t2) {
|
|
124
|
+
if (t2 < 1) {
|
|
125
|
+
let u = e * Math.sqrt(1 - t2 * t2);
|
|
126
|
+
return 1 - Math.exp(-t2 * e * n2) * (Math.cos(u * n2) + t2 * e / u * Math.sin(u * n2));
|
|
127
|
+
}
|
|
128
|
+
let i = Math.sqrt(t2 * t2 - 1), s = -e * (t2 + i), r = -e * (t2 - i), o = -s / (r - s);
|
|
129
|
+
return 1 - (1 - o) * Math.exp(s * n2) - o * Math.exp(r * n2);
|
|
130
|
+
}
|
|
131
|
+
function j(n2, e, t2) {
|
|
132
|
+
let r = 0;
|
|
133
|
+
for (let o = 0; o < 10; o += 1e-3) if (Math.abs($(o, n2, e) - 1) > t2) r = 0;
|
|
134
|
+
else if (r += 1e-3, r > 0.1) return Math.ceil((o - r + 1e-3) * 1e3);
|
|
135
|
+
return Math.ceil(10 * 1e3);
|
|
136
|
+
}
|
|
137
|
+
var O = /* @__PURE__ */ new Map();
|
|
138
|
+
function D(n2) {
|
|
139
|
+
let { stiffness: e = 100, damping: t2 = 10, mass: i = 1, precision: s = 1e-3 } = n2 ?? {}, r = `${e}:${t2}:${i}:${s}`, o = O.get(r);
|
|
140
|
+
if (o) return o;
|
|
141
|
+
let a = Math.sqrt(e / i), u = t2 / (2 * Math.sqrt(e * i)), l2 = j(a, u, s), c = Math.min(100, Math.max(32, Math.round(l2 / 15))), m = [];
|
|
142
|
+
for (let g = 0; g < c; g++) {
|
|
143
|
+
let A = g / (c - 1) * (l2 / 1e3), S = g === c - 1 ? 1 : $(A, a, u);
|
|
144
|
+
m.push(Math.round(S * 1e4) / 1e4 + "");
|
|
145
|
+
}
|
|
146
|
+
for (; m.length > 2 && m[m.length - 2] === "1"; ) m.splice(m.length - 2, 1);
|
|
147
|
+
let p = { easing: `linear(${m.join(", ")})`, duration: l2 };
|
|
148
|
+
return O.set(r, p), p;
|
|
149
|
+
}
|
|
150
|
+
function H(n2, e) {
|
|
151
|
+
let t2 = n2.includes(" ");
|
|
152
|
+
if (typeof Intl.Segmenter < "u") {
|
|
153
|
+
let s = new Intl.Segmenter(e, { granularity: t2 ? "word" : "grapheme" }).segment(n2)[Symbol.iterator]();
|
|
154
|
+
return q(s);
|
|
155
|
+
}
|
|
156
|
+
return Y(n2, t2);
|
|
157
|
+
}
|
|
158
|
+
function q(n2) {
|
|
159
|
+
return Array.from(n2).reduce((e, t2) => t2.segment === " " ? [...e, { id: `space-${t2.index}`, string: " " }] : e.find((s) => s.string === t2.segment) ? [...e, { id: `${t2.segment}-${t2.index}`, string: t2.segment }] : [...e, { id: t2.segment, string: t2.segment }], []);
|
|
160
|
+
}
|
|
161
|
+
function K(n2, e, t2) {
|
|
162
|
+
let i = n2.find((s) => s.string === e);
|
|
163
|
+
n2.push(i ? { id: `${e}-${t2}`, string: e } : { id: e, string: e });
|
|
164
|
+
}
|
|
165
|
+
function Y(n2, e) {
|
|
166
|
+
let t2 = e ? n2.split(" ") : n2.split(""), i = [];
|
|
167
|
+
return t2.forEach((s, r) => {
|
|
168
|
+
e && r > 0 && i.push({ id: `space-${r}`, string: " " }), K(i, s, r);
|
|
169
|
+
}), i;
|
|
170
|
+
}
|
|
171
|
+
var y = "torph-root", T = "torph-item", d = "torph-id", f$1 = "torph-exiting", M = "torph-debug";
|
|
172
|
+
function w(n2) {
|
|
173
|
+
let e = Array.from(n2.children), t2 = {};
|
|
174
|
+
return e.forEach((i, s) => {
|
|
175
|
+
if (i.hasAttribute(f$1)) return;
|
|
176
|
+
let r = i.getAttribute(d) || `child-${s}`;
|
|
177
|
+
t2[r] = { x: i.offsetLeft, y: i.offsetTop };
|
|
178
|
+
}), t2;
|
|
179
|
+
}
|
|
180
|
+
function R(n2, e, t2) {
|
|
181
|
+
let i = n2[t2], s = e[t2];
|
|
182
|
+
return !i || !s ? { dx: 0, dy: 0 } : { dx: i.x - s.x, dy: i.y - s.y };
|
|
183
|
+
}
|
|
184
|
+
function v(n2, e, t2, i = "backward-first") {
|
|
185
|
+
let [s, r] = i === "backward-first" ? ["backward", "forward"] : ["forward", "backward"], o = (a) => {
|
|
186
|
+
if (a === "backward") {
|
|
187
|
+
for (let u = n2 - 1; u >= 0; u--) if (t2.has(e[u])) return e[u];
|
|
188
|
+
} else for (let u = n2 + 1; u < e.length; u++) if (t2.has(e[u])) return e[u];
|
|
189
|
+
return null;
|
|
190
|
+
};
|
|
191
|
+
return o(s) ?? o(r);
|
|
192
|
+
}
|
|
193
|
+
function _(n2, e, t2, i) {
|
|
194
|
+
let s = new Set(t2.filter((o, a) => i.has(o) && !e.has(n2[a]))), r = /* @__PURE__ */ new Map();
|
|
195
|
+
for (let o = 0; o < n2.length; o++) {
|
|
196
|
+
let a = n2[o];
|
|
197
|
+
e.has(a) && r.set(a, v(o, t2, s, "forward-first"));
|
|
198
|
+
}
|
|
199
|
+
return r;
|
|
200
|
+
}
|
|
201
|
+
function C(n2, e) {
|
|
202
|
+
return Math.min(n2 * e, 150);
|
|
203
|
+
}
|
|
204
|
+
function L(n2) {
|
|
205
|
+
let e = getComputedStyle(n2).transform;
|
|
206
|
+
if (!e || e === "none") return { tx: 0, ty: 0 };
|
|
207
|
+
let t2 = e.match(/matrix\(([^)]+)\)/);
|
|
208
|
+
if (!t2) return { tx: 0, ty: 0 };
|
|
209
|
+
let i = t2[1].split(",").map(Number);
|
|
210
|
+
return { tx: i[4] || 0, ty: i[5] || 0 };
|
|
211
|
+
}
|
|
212
|
+
function Q(n2) {
|
|
213
|
+
let { tx: e, ty: t2 } = L(n2), i = Number(getComputedStyle(n2).opacity) || 1;
|
|
214
|
+
return n2.getAnimations().forEach((s) => s.cancel()), { tx: e, ty: t2, opacity: i };
|
|
215
|
+
}
|
|
216
|
+
function N(n2, e) {
|
|
217
|
+
let { dx: t2, dy: i, duration: s, ease: r, scale: o } = e;
|
|
218
|
+
n2.animate({ transform: o ? `translate(${t2}px, ${i}px) scale(0.95)` : `translate(${t2}px, ${i}px)`, offset: 1 }, { duration: s, easing: r, fill: "both" });
|
|
219
|
+
let a = n2.animate({ opacity: 0, offset: 1 }, { duration: C(s, 0.25), easing: "linear", fill: "both" });
|
|
220
|
+
a.onfinish = () => n2.remove();
|
|
221
|
+
}
|
|
222
|
+
function k(n2, e) {
|
|
223
|
+
let { deltaX: t2, deltaY: i, isNew: s, duration: r, ease: o } = e, a = Q(n2), u = t2 + a.tx, l2 = i + a.ty;
|
|
224
|
+
n2.animate({ transform: `translate(${u}px, ${l2}px) scale(${s ? 0.95 : 1})`, offset: 0 }, { duration: r, easing: o, fill: "both" });
|
|
225
|
+
let c = s && a.opacity >= 1 ? 0 : a.opacity;
|
|
226
|
+
c < 1 && n2.animate([{ opacity: c }, { opacity: 1 }], { duration: C(r, s ? 0.5 : 0.25), easing: "linear", fill: "both" });
|
|
227
|
+
}
|
|
228
|
+
var x = null;
|
|
229
|
+
function F(n2, e, t2, i, s) {
|
|
230
|
+
if (x && (x(), x = null), e === 0 || t2 === 0) return;
|
|
231
|
+
n2.style.width = "auto", n2.style.height = "auto", n2.offsetWidth;
|
|
232
|
+
let r = n2.offsetWidth, o = n2.offsetHeight;
|
|
233
|
+
n2.style.width = `${e}px`, n2.style.height = `${t2}px`, n2.offsetWidth, n2.style.width = `${r}px`, n2.style.height = `${o}px`;
|
|
234
|
+
function a() {
|
|
235
|
+
n2.removeEventListener("transitionend", u), clearTimeout(l2), x = null, n2.style.width = "auto", n2.style.height = "auto", s == null ? void 0 : s();
|
|
236
|
+
}
|
|
237
|
+
function u(c) {
|
|
238
|
+
c.target === n2 && (c.propertyName !== "width" && c.propertyName !== "height" || a());
|
|
239
|
+
}
|
|
240
|
+
n2.addEventListener("transitionend", u);
|
|
241
|
+
let l2 = setTimeout(a, i + 50);
|
|
242
|
+
x = () => {
|
|
243
|
+
n2.removeEventListener("transitionend", u), clearTimeout(l2), x = null;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function P(n2) {
|
|
247
|
+
let e = n2.map((t2) => {
|
|
248
|
+
let { tx: i, ty: s } = L(t2), r = Number(getComputedStyle(t2).opacity) || 1;
|
|
249
|
+
return t2.getAnimations().forEach((o) => o.cancel()), { left: t2.offsetLeft + i, top: t2.offsetTop + s, width: t2.offsetWidth, height: t2.offsetHeight, opacity: r };
|
|
250
|
+
});
|
|
251
|
+
n2.forEach((t2, i) => {
|
|
252
|
+
let s = e[i];
|
|
253
|
+
t2.setAttribute(f$1, ""), t2.style.position = "absolute", t2.style.pointerEvents = "none", t2.style.left = `${s.left}px`, t2.style.top = `${s.top}px`, t2.style.width = `${s.width}px`, t2.style.height = `${s.height}px`, t2.style.opacity = String(s.opacity);
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function X(n2, e, t2, i) {
|
|
257
|
+
let s = /* @__PURE__ */ new Map();
|
|
258
|
+
e.forEach((r) => {
|
|
259
|
+
let o = r.getAttribute(d);
|
|
260
|
+
t2.has(o) && !r.hasAttribute(f$1) && (s.set(o, r), r.remove());
|
|
261
|
+
}), Array.from(n2.childNodes).forEach((r) => {
|
|
262
|
+
r.nodeType === Node.TEXT_NODE && r.remove();
|
|
263
|
+
}), i.forEach((r) => {
|
|
264
|
+
let o = s.get(r.id);
|
|
265
|
+
if (o) o.textContent = r.string, n2.appendChild(o);
|
|
266
|
+
else {
|
|
267
|
+
let a = document.createElement("span");
|
|
268
|
+
a.setAttribute(T, ""), a.setAttribute(d, r.id), a.textContent = r.string, n2.appendChild(a);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
var J = `
|
|
273
|
+
[${y}] {
|
|
274
|
+
display: inline-block;
|
|
275
|
+
position: relative;
|
|
276
|
+
will-change: width, height;
|
|
277
|
+
transition-property: width, height;
|
|
278
|
+
white-space: nowrap;
|
|
279
|
+
text-align: left;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
[${T}] {
|
|
283
|
+
display: inline-block;
|
|
284
|
+
will-change: opacity, transform;
|
|
285
|
+
transform: none;
|
|
286
|
+
opacity: 1;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
[${y}][${M}] {
|
|
290
|
+
outline: 2px solid magenta;
|
|
291
|
+
[${T}] {
|
|
292
|
+
outline: 2px solid cyan;
|
|
293
|
+
outline-offset: -4px;
|
|
294
|
+
}
|
|
295
|
+
}`, h$1 = null, I = 0;
|
|
296
|
+
function G() {
|
|
297
|
+
I++, !h$1 && (h$1 = document.createElement("style"), h$1.dataset.torph = "true", h$1.textContent = J, document.head.appendChild(h$1));
|
|
298
|
+
}
|
|
299
|
+
function U() {
|
|
300
|
+
I--, !(I > 0 || !h$1) && (h$1.remove(), h$1 = null);
|
|
301
|
+
}
|
|
302
|
+
function W() {
|
|
303
|
+
if (typeof window > "u") return { prefersReducedMotion: false, destroy: () => {
|
|
304
|
+
} };
|
|
305
|
+
let n2 = window.matchMedia("(prefers-reduced-motion: reduce)"), e = { prefersReducedMotion: n2.matches, destroy: i };
|
|
306
|
+
function t2(s) {
|
|
307
|
+
e.prefersReducedMotion = s.matches;
|
|
308
|
+
}
|
|
309
|
+
function i() {
|
|
310
|
+
n2.removeEventListener("change", t2);
|
|
311
|
+
}
|
|
312
|
+
return n2.addEventListener("change", t2), e;
|
|
313
|
+
}
|
|
314
|
+
var E = class n {
|
|
315
|
+
constructor() {
|
|
316
|
+
__publicField(this, "instance", null);
|
|
317
|
+
__publicField(this, "lastText", "");
|
|
318
|
+
__publicField(this, "configKey", "");
|
|
319
|
+
}
|
|
320
|
+
attach(e, t2) {
|
|
321
|
+
var _a;
|
|
322
|
+
(_a = this.instance) == null ? void 0 : _a.destroy(), this.instance = new b({ element: e, ...t2 }), this.configKey = n.serializeConfig(t2), this.lastText && this.instance.update(this.lastText);
|
|
323
|
+
}
|
|
324
|
+
update(e) {
|
|
325
|
+
var _a;
|
|
326
|
+
this.lastText = e, (_a = this.instance) == null ? void 0 : _a.update(e);
|
|
327
|
+
}
|
|
328
|
+
needsRecreate(e) {
|
|
329
|
+
return n.serializeConfig(e) !== this.configKey;
|
|
330
|
+
}
|
|
331
|
+
destroy() {
|
|
332
|
+
var _a;
|
|
333
|
+
(_a = this.instance) == null ? void 0 : _a.destroy(), this.instance = null;
|
|
334
|
+
}
|
|
335
|
+
static serializeConfig(e) {
|
|
336
|
+
return JSON.stringify({ ease: e.ease, duration: e.duration, locale: e.locale, scale: e.scale, debug: e.debug, disabled: e.disabled, respectReducedMotion: e.respectReducedMotion });
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
var V = "span", B = { debug: false, locale: "en", duration: 400, scale: true, ease: "cubic-bezier(0.19, 1, 0.22, 1)", disabled: false, respectReducedMotion: true }, b = class {
|
|
340
|
+
constructor(e) {
|
|
341
|
+
__publicField(this, "element");
|
|
342
|
+
__publicField(this, "options", {});
|
|
343
|
+
__publicField(this, "data");
|
|
344
|
+
__publicField(this, "currentMeasures", {});
|
|
345
|
+
__publicField(this, "prevMeasures", {});
|
|
346
|
+
__publicField(this, "isInitialRender", true);
|
|
347
|
+
__publicField(this, "reducedMotion", null);
|
|
348
|
+
let { ease: t2, ...i } = { ...B, ...e }, s, r;
|
|
349
|
+
if (typeof t2 == "object") {
|
|
350
|
+
let o = D(t2);
|
|
351
|
+
s = o.easing, r = o.duration;
|
|
352
|
+
} else s = t2, r = i.duration;
|
|
353
|
+
this.options = { ...i, ease: s, duration: r }, this.element = e.element, this.options.respectReducedMotion && (this.reducedMotion = W()), this.isDisabled() || (this.element.setAttribute(y, ""), this.element.style.transitionDuration = `${this.options.duration}ms`, this.element.style.transitionTimingFunction = this.options.ease, e.debug && this.element.setAttribute(M, "")), this.data = "", this.isDisabled() || G();
|
|
354
|
+
}
|
|
355
|
+
destroy() {
|
|
356
|
+
var _a;
|
|
357
|
+
(_a = this.reducedMotion) == null ? void 0 : _a.destroy(), this.element.getAnimations().forEach((e) => e.cancel()), this.element.removeAttribute(y), this.element.removeAttribute(M), U();
|
|
358
|
+
}
|
|
359
|
+
isDisabled() {
|
|
360
|
+
var _a;
|
|
361
|
+
return !!(this.options.disabled || ((_a = this.reducedMotion) == null ? void 0 : _a.prefersReducedMotion));
|
|
362
|
+
}
|
|
363
|
+
update(e) {
|
|
364
|
+
if (e !== this.data) {
|
|
365
|
+
if (this.data = e, this.isDisabled()) {
|
|
366
|
+
typeof e == "string" && (this.element.textContent = e);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (this.data instanceof HTMLElement) throw new Error("HTMLElement not yet supported");
|
|
370
|
+
this.options.onAnimationStart && !this.isInitialRender && this.options.onAnimationStart(), this.createTextGroup(this.data, this.element);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
createTextGroup(e, t2) {
|
|
374
|
+
let i = t2.offsetWidth, s = t2.offsetHeight, r = H(e, this.options.locale);
|
|
375
|
+
this.prevMeasures = w(this.element);
|
|
376
|
+
let o = Array.from(t2.children), a = new Set(r.map((p) => p.id)), u = o.filter((p) => !a.has(p.getAttribute(d)) && !p.hasAttribute(f$1)), l2 = new Set(u), c = o.map((p) => p.getAttribute(d)), m = _(o, l2, c, a);
|
|
377
|
+
if (P(u), X(t2, o, a, r), this.currentMeasures = w(this.element), this.updateStyles(r), u.forEach((p) => {
|
|
378
|
+
if (this.isInitialRender) {
|
|
379
|
+
p.remove();
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
let g = m.get(p), { dx: A, dy: S } = g ? R(this.currentMeasures, this.prevMeasures, g) : { dx: 0, dy: 0 };
|
|
383
|
+
N(p, { dx: A, dy: S, duration: this.options.duration, ease: this.options.ease, scale: this.options.scale });
|
|
384
|
+
}), this.isInitialRender) {
|
|
385
|
+
this.isInitialRender = false, t2.style.width = "auto", t2.style.height = "auto";
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
F(t2, i, s, this.options.duration, this.options.onAnimationComplete);
|
|
389
|
+
}
|
|
390
|
+
updateStyles(e) {
|
|
391
|
+
if (this.isInitialRender) return;
|
|
392
|
+
let t2 = Array.from(this.element.children), i = e.map((r) => r.id), s = new Set(i.filter((r) => this.prevMeasures[r]));
|
|
393
|
+
t2.forEach((r, o) => {
|
|
394
|
+
if (r.hasAttribute(f$1)) return;
|
|
395
|
+
let a = r.getAttribute(d) || `child-${o}`, u = !this.prevMeasures[a], l2 = u ? v(e.findIndex((p) => p.id === a), i, s) : a, { dx: c, dy: m } = l2 ? R(this.prevMeasures, this.currentMeasures, l2) : { dx: 0, dy: 0 };
|
|
396
|
+
k(r, { deltaX: c, deltaY: m, isNew: u, duration: this.options.duration, ease: this.options.ease });
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
function f(e) {
|
|
401
|
+
if (typeof e == "string") return e;
|
|
402
|
+
if (typeof e == "number") return String(e);
|
|
403
|
+
if (!e || typeof e == "boolean") return "";
|
|
404
|
+
if (Array.isArray(e)) return e.map(f).join("");
|
|
405
|
+
throw t.isValidElement(e) ? new Error("TextMorph only accepts text content. Found a React element — use strings, numbers, or expressions instead.") : new Error(`TextMorph received an unsupported child of type "${typeof e}".`);
|
|
406
|
+
}
|
|
407
|
+
var h = ({ children: e, className: r, style: o, as: n2 = V, ...s }) => {
|
|
408
|
+
let { ref: p, update: c } = l(s), i = f(e), a = t.useRef({ __html: i });
|
|
409
|
+
return t.useEffect(() => {
|
|
410
|
+
c(i);
|
|
411
|
+
}, [i, c]), t.createElement(n2, { ref: p, className: r, style: o, dangerouslySetInnerHTML: a.current });
|
|
412
|
+
};
|
|
413
|
+
function l(e) {
|
|
414
|
+
let r = t.useRef(null), o = t.useRef(new E()), n2 = E.serializeConfig(e);
|
|
415
|
+
t.useEffect(() => (r.current && o.current.attach(r.current, e), () => {
|
|
416
|
+
o.current.destroy();
|
|
417
|
+
}), [n2]);
|
|
418
|
+
let s = t.useCallback((p) => {
|
|
419
|
+
o.current.update(p);
|
|
420
|
+
}, []);
|
|
421
|
+
return { ref: r, update: s };
|
|
422
|
+
}
|
|
5
423
|
function isTextInputTarget(target) {
|
|
6
424
|
if (!(target instanceof HTMLElement)) return false;
|
|
7
425
|
if (target.isContentEditable) return true;
|
|
@@ -20,7 +438,7 @@ function SliderOverlapDebugProvider({ children }) {
|
|
|
20
438
|
if (e.code !== "KeyD") return;
|
|
21
439
|
if (isTextInputTarget(e.target)) return;
|
|
22
440
|
e.preventDefault();
|
|
23
|
-
setEnabled((
|
|
441
|
+
setEnabled((v2) => !v2);
|
|
24
442
|
};
|
|
25
443
|
window.addEventListener("keydown", onKeyDown);
|
|
26
444
|
return () => window.removeEventListener("keydown", onKeyDown);
|
|
@@ -30,41 +448,13 @@ function SliderOverlapDebugProvider({ children }) {
|
|
|
30
448
|
function useSliderOverlapDebugEnabled() {
|
|
31
449
|
return useContext(SliderOverlapDebugContext);
|
|
32
450
|
}
|
|
33
|
-
const STORAGE_KEY = "aporia-theme";
|
|
34
451
|
const ThemeContext = createContext(null);
|
|
35
|
-
function readStoredTheme() {
|
|
36
|
-
try {
|
|
37
|
-
const s = localStorage.getItem(STORAGE_KEY);
|
|
38
|
-
if (s === "light" || s === "dark") return s;
|
|
39
|
-
} catch {
|
|
40
|
-
}
|
|
41
|
-
return "dark";
|
|
42
|
-
}
|
|
43
452
|
function ThemeProvider({ children }) {
|
|
44
|
-
const
|
|
453
|
+
const theme = "dark";
|
|
45
454
|
useEffect(() => {
|
|
46
455
|
document.documentElement.dataset.theme = theme;
|
|
47
|
-
try {
|
|
48
|
-
localStorage.setItem(STORAGE_KEY, theme);
|
|
49
|
-
} catch {
|
|
50
|
-
}
|
|
51
456
|
}, [theme]);
|
|
52
|
-
|
|
53
|
-
const toggleTheme = useCallback(() => {
|
|
54
|
-
setThemeState((t) => t === "dark" ? "light" : "dark");
|
|
55
|
-
}, []);
|
|
56
|
-
useEffect(() => {
|
|
57
|
-
const onKeyDown = (e) => {
|
|
58
|
-
if (!e.shiftKey || e.repeat) return;
|
|
59
|
-
if (e.code !== "KeyT") return;
|
|
60
|
-
if (isTextInputTarget(e.target)) return;
|
|
61
|
-
e.preventDefault();
|
|
62
|
-
toggleTheme();
|
|
63
|
-
};
|
|
64
|
-
window.addEventListener("keydown", onKeyDown);
|
|
65
|
-
return () => window.removeEventListener("keydown", onKeyDown);
|
|
66
|
-
}, [toggleTheme]);
|
|
67
|
-
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme, setTheme, toggleTheme }, children });
|
|
457
|
+
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme }, children });
|
|
68
458
|
}
|
|
69
459
|
function useTheme() {
|
|
70
460
|
const ctx = useContext(ThemeContext);
|
|
@@ -73,6 +463,210 @@ function useTheme() {
|
|
|
73
463
|
}
|
|
74
464
|
return ctx;
|
|
75
465
|
}
|
|
466
|
+
function ValueInput({
|
|
467
|
+
value,
|
|
468
|
+
prefix,
|
|
469
|
+
suffix,
|
|
470
|
+
onCommit,
|
|
471
|
+
sanitize = (v2) => v2,
|
|
472
|
+
validate = () => true,
|
|
473
|
+
maxLength,
|
|
474
|
+
inputMode = "text",
|
|
475
|
+
align = "left",
|
|
476
|
+
ariaLabel,
|
|
477
|
+
isActive = false,
|
|
478
|
+
className,
|
|
479
|
+
autoWidth = false,
|
|
480
|
+
valueTextRef,
|
|
481
|
+
onPaste,
|
|
482
|
+
renderValue,
|
|
483
|
+
inputRef: externalInputRef,
|
|
484
|
+
onEditingChange,
|
|
485
|
+
editing: externalEditing,
|
|
486
|
+
draft: externalDraft,
|
|
487
|
+
onDraftChange,
|
|
488
|
+
arrowStep,
|
|
489
|
+
arrowMin,
|
|
490
|
+
arrowMax,
|
|
491
|
+
disabled = false
|
|
492
|
+
}) {
|
|
493
|
+
const [internalEditing, setInternalEditing] = useState(false);
|
|
494
|
+
const [internalDraft, setInternalDraft] = useState("");
|
|
495
|
+
const internalInputRef = useRef(null);
|
|
496
|
+
const measureRef = useRef(null);
|
|
497
|
+
const internalValueTextRef = useRef(null);
|
|
498
|
+
const [inputWidth, setInputWidth] = useState(null);
|
|
499
|
+
const editing = externalEditing !== void 0 ? externalEditing : internalEditing;
|
|
500
|
+
const draft = externalDraft !== void 0 ? externalDraft : internalDraft;
|
|
501
|
+
const inputRef = externalInputRef ?? internalInputRef;
|
|
502
|
+
const setEditing = (value2) => {
|
|
503
|
+
if (externalEditing === void 0) {
|
|
504
|
+
setInternalEditing(value2);
|
|
505
|
+
}
|
|
506
|
+
onEditingChange == null ? void 0 : onEditingChange(value2);
|
|
507
|
+
};
|
|
508
|
+
const setDraft = (value2) => {
|
|
509
|
+
if (externalDraft === void 0) {
|
|
510
|
+
setInternalDraft(value2);
|
|
511
|
+
}
|
|
512
|
+
onDraftChange == null ? void 0 : onDraftChange(value2);
|
|
513
|
+
};
|
|
514
|
+
const actualValueTextRef = valueTextRef ?? internalValueTextRef;
|
|
515
|
+
useLayoutEffect(() => {
|
|
516
|
+
var _a, _b;
|
|
517
|
+
if (!editing) return;
|
|
518
|
+
(_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
519
|
+
(_b = inputRef.current) == null ? void 0 : _b.select();
|
|
520
|
+
}, [editing, inputRef]);
|
|
521
|
+
useLayoutEffect(() => {
|
|
522
|
+
if (!editing || !autoWidth) {
|
|
523
|
+
setInputWidth(null);
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const measure = () => {
|
|
527
|
+
const m = measureRef.current;
|
|
528
|
+
if (!m) return;
|
|
529
|
+
const w2 = m.getBoundingClientRect().width;
|
|
530
|
+
const next = Math.max(Math.ceil(w2 + 6), 22);
|
|
531
|
+
setInputWidth((prev) => prev === next ? prev : next);
|
|
532
|
+
};
|
|
533
|
+
measure();
|
|
534
|
+
}, [editing, draft, autoWidth]);
|
|
535
|
+
const startEdit = (e) => {
|
|
536
|
+
e.stopPropagation();
|
|
537
|
+
setDraft(value);
|
|
538
|
+
setEditing(true);
|
|
539
|
+
};
|
|
540
|
+
const commit = () => {
|
|
541
|
+
const sanitized = sanitize(draft);
|
|
542
|
+
if (validate(sanitized)) {
|
|
543
|
+
onCommit(sanitized);
|
|
544
|
+
}
|
|
545
|
+
setEditing(false);
|
|
546
|
+
};
|
|
547
|
+
const stepDecimals = (s) => {
|
|
548
|
+
const txt = String(s);
|
|
549
|
+
const i = txt.indexOf(".");
|
|
550
|
+
return i === -1 ? 0 : Math.max(0, txt.length - i - 1);
|
|
551
|
+
};
|
|
552
|
+
const handleKeyDown = (e) => {
|
|
553
|
+
if ((e.key === "ArrowUp" || e.key === "ArrowDown") && arrowStep != null) {
|
|
554
|
+
const dir = e.key === "ArrowUp" ? 1 : -1;
|
|
555
|
+
const mult = e.shiftKey ? 10 : 1;
|
|
556
|
+
const current = Number(sanitize(draft));
|
|
557
|
+
if (Number.isFinite(current) && Number.isFinite(arrowStep) && arrowStep !== 0) {
|
|
558
|
+
e.preventDefault();
|
|
559
|
+
let nextNum = current + dir * arrowStep * mult;
|
|
560
|
+
if (Number.isFinite(arrowMin)) nextNum = Math.max(arrowMin, nextNum);
|
|
561
|
+
if (Number.isFinite(arrowMax)) nextNum = Math.min(arrowMax, nextNum);
|
|
562
|
+
const decimals = stepDecimals(arrowStep);
|
|
563
|
+
const nextTxt = decimals > 0 ? nextNum.toFixed(decimals) : String(Math.round(nextNum));
|
|
564
|
+
setDraft(sanitize(nextTxt));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (e.key === "Enter") {
|
|
569
|
+
e.preventDefault();
|
|
570
|
+
commit();
|
|
571
|
+
}
|
|
572
|
+
if (e.key === "Escape") {
|
|
573
|
+
setEditing(false);
|
|
574
|
+
}
|
|
575
|
+
e.stopPropagation();
|
|
576
|
+
};
|
|
577
|
+
const handleChange = (e) => {
|
|
578
|
+
const next = sanitize(e.target.value);
|
|
579
|
+
setDraft(next);
|
|
580
|
+
};
|
|
581
|
+
const handlePaste = (e) => {
|
|
582
|
+
const pasted = e.clipboardData.getData("text");
|
|
583
|
+
if (onPaste) {
|
|
584
|
+
const result = onPaste(pasted);
|
|
585
|
+
if (result !== null) {
|
|
586
|
+
e.preventDefault();
|
|
587
|
+
setDraft(result);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
const containerClass = [
|
|
593
|
+
"valueInput",
|
|
594
|
+
className,
|
|
595
|
+
align === "right" && "valueInput--right"
|
|
596
|
+
].filter(Boolean).join(" ");
|
|
597
|
+
if (disabled) {
|
|
598
|
+
return /* @__PURE__ */ jsxs(
|
|
599
|
+
"span",
|
|
600
|
+
{
|
|
601
|
+
className: containerClass,
|
|
602
|
+
"data-disabled": "true",
|
|
603
|
+
"aria-label": ariaLabel ?? `Value, ${value}`,
|
|
604
|
+
children: [
|
|
605
|
+
prefix && /* @__PURE__ */ jsx("span", { className: "valueInputPrefix", children: prefix }),
|
|
606
|
+
/* @__PURE__ */ jsx("span", { className: "valueInputText", children: renderValue ? renderValue(value) : value }),
|
|
607
|
+
suffix && /* @__PURE__ */ jsx("span", { className: "valueInputSuffix", children: suffix })
|
|
608
|
+
]
|
|
609
|
+
}
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
if (editing) {
|
|
613
|
+
return /* @__PURE__ */ jsxs("span", { className: containerClass, "data-editing": "true", children: [
|
|
614
|
+
prefix && /* @__PURE__ */ jsx("span", { className: "valueInputPrefix", children: prefix }),
|
|
615
|
+
autoWidth && /* @__PURE__ */ jsx(
|
|
616
|
+
"span",
|
|
617
|
+
{
|
|
618
|
+
ref: measureRef,
|
|
619
|
+
className: "valueInputMeasure",
|
|
620
|
+
"aria-hidden": true,
|
|
621
|
+
children: draft.length > 0 ? draft : "0"
|
|
622
|
+
}
|
|
623
|
+
),
|
|
624
|
+
/* @__PURE__ */ jsx(
|
|
625
|
+
"input",
|
|
626
|
+
{
|
|
627
|
+
ref: inputRef,
|
|
628
|
+
className: "valueInputField",
|
|
629
|
+
value: draft,
|
|
630
|
+
onChange: handleChange,
|
|
631
|
+
onPaste: handlePaste,
|
|
632
|
+
onBlur: commit,
|
|
633
|
+
onKeyDown: handleKeyDown,
|
|
634
|
+
onClick: (e) => e.stopPropagation(),
|
|
635
|
+
maxLength,
|
|
636
|
+
inputMode,
|
|
637
|
+
autoComplete: "off",
|
|
638
|
+
spellCheck: false,
|
|
639
|
+
"aria-label": ariaLabel,
|
|
640
|
+
style: inputWidth != null ? { width: inputWidth } : void 0
|
|
641
|
+
}
|
|
642
|
+
),
|
|
643
|
+
suffix && /* @__PURE__ */ jsx("span", { className: "valueInputSuffix", children: suffix })
|
|
644
|
+
] });
|
|
645
|
+
}
|
|
646
|
+
return /* @__PURE__ */ jsxs(
|
|
647
|
+
"span",
|
|
648
|
+
{
|
|
649
|
+
className: containerClass,
|
|
650
|
+
"data-active": isActive ? "true" : "false",
|
|
651
|
+
role: "button",
|
|
652
|
+
tabIndex: 0,
|
|
653
|
+
"aria-label": ariaLabel ?? `Edit value, ${value}`,
|
|
654
|
+
onClick: startEdit,
|
|
655
|
+
onKeyDown: (e) => {
|
|
656
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
657
|
+
e.preventDefault();
|
|
658
|
+
setDraft(value);
|
|
659
|
+
setEditing(true);
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
children: [
|
|
663
|
+
prefix && /* @__PURE__ */ jsx("span", { className: "valueInputPrefix", children: prefix }),
|
|
664
|
+
/* @__PURE__ */ jsx("span", { ref: actualValueTextRef, className: "valueInputText", children: renderValue ? renderValue(value) : value }),
|
|
665
|
+
suffix && /* @__PURE__ */ jsx("span", { className: "valueInputSuffix", children: suffix })
|
|
666
|
+
]
|
|
667
|
+
}
|
|
668
|
+
);
|
|
669
|
+
}
|
|
76
670
|
function clearDocumentSelection() {
|
|
77
671
|
var _a;
|
|
78
672
|
const sel = (_a = window.getSelection) == null ? void 0 : _a.call(window);
|
|
@@ -139,7 +733,6 @@ const THUMB_HEIGHT_PX = 16;
|
|
|
139
733
|
const THUMB_HEIGHT_BEHIND_LABEL_PX = 10;
|
|
140
734
|
const THUMB_INSET_FROM_FILL_END_PX = 10;
|
|
141
735
|
const THUMB_OVERLAP_PAD_PX = 10;
|
|
142
|
-
const VALUE_EDIT_WIDTH_CARET_PAD_PX = 6;
|
|
143
736
|
function SliderRow({
|
|
144
737
|
label,
|
|
145
738
|
value,
|
|
@@ -147,23 +740,23 @@ function SliderRow({
|
|
|
147
740
|
max,
|
|
148
741
|
step,
|
|
149
742
|
onChange,
|
|
150
|
-
fmt
|
|
743
|
+
fmt,
|
|
744
|
+
disabled: disabledProp
|
|
151
745
|
}) {
|
|
152
|
-
|
|
746
|
+
useTheme();
|
|
747
|
+
const categoryDisabled = useCategoryDisabled();
|
|
748
|
+
const disabled = Boolean(disabledProp || categoryDisabled);
|
|
153
749
|
const debugOverlap = useSliderOverlapDebugEnabled();
|
|
154
|
-
const [
|
|
750
|
+
const [valueEditing, setValueEditing] = useState(false);
|
|
155
751
|
const [hovered, setHovered] = useState(false);
|
|
156
752
|
const [dragging, setDragging] = useState(false);
|
|
157
|
-
const [draft, setDraft] = useState("");
|
|
158
753
|
const [mounted, setMounted] = useState(false);
|
|
159
754
|
const inputRef = useRef(null);
|
|
160
755
|
const cardRef = useRef(null);
|
|
161
756
|
const wrapRef = useRef(null);
|
|
162
757
|
const labelTextRef = useRef(null);
|
|
163
758
|
const valueTextRef = useRef(null);
|
|
164
|
-
const valueEditMeasureRef = useRef(null);
|
|
165
759
|
const valueRef = useRef(null);
|
|
166
|
-
const [valueEditWidthPx, setValueEditWidthPx] = useState(null);
|
|
167
760
|
const [overlapLayout, setOverlapLayout] = useState(null);
|
|
168
761
|
const [idleThumbOpacity, setIdleThumbOpacity] = useState(0);
|
|
169
762
|
const lastPointerXRef = useRef(0);
|
|
@@ -180,15 +773,15 @@ function SliderRow({
|
|
|
180
773
|
const baseW = useMotionValue(0);
|
|
181
774
|
const cardWidth = useTransform(
|
|
182
775
|
[stretchL, stretchR, pullLSpring, pullRSpring, baseW],
|
|
183
|
-
([
|
|
184
|
-
const base = Number(
|
|
185
|
-
let extra = Number(
|
|
776
|
+
([l2, r, pl, pr, b2]) => {
|
|
777
|
+
const base = Number(b2);
|
|
778
|
+
let extra = Number(l2) + Number(r) + Number(pl) + Number(pr);
|
|
186
779
|
if (Math.abs(extra) < STRETCH_SNAP_EPS_PX) extra = 0;
|
|
187
780
|
return Math.max(1, Math.round(base + extra));
|
|
188
781
|
}
|
|
189
782
|
);
|
|
190
|
-
const cardMarginLeft = useTransform([stretchL, pullLSpring], ([
|
|
191
|
-
let leftExtra = Number(
|
|
783
|
+
const cardMarginLeft = useTransform([stretchL, pullLSpring], ([l2, pl]) => {
|
|
784
|
+
let leftExtra = Number(l2) + Number(pl);
|
|
192
785
|
if (Math.abs(leftExtra) < STRETCH_SNAP_EPS_PX) leftExtra = 0;
|
|
193
786
|
return Math.round(-leftExtra);
|
|
194
787
|
});
|
|
@@ -213,19 +806,13 @@ function SliderRow({
|
|
|
213
806
|
setMounted(true);
|
|
214
807
|
}, []);
|
|
215
808
|
useLayoutEffect(() => {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
const raw = getComputedStyle(document.documentElement).getPropertyValue("--slider-thumb-idle-opacity").trim();
|
|
221
|
-
const n = parseFloat(raw);
|
|
222
|
-
setIdleThumbOpacity(Number.isFinite(n) ? n : 0.4);
|
|
223
|
-
}, [theme]);
|
|
809
|
+
setIdleThumbOpacity(0);
|
|
810
|
+
}, []);
|
|
224
811
|
const display = fmt ? fmt(value) : value;
|
|
225
812
|
useLayoutEffect(() => {
|
|
226
813
|
const card = cardRef.current;
|
|
227
814
|
const labelEl = labelTextRef.current;
|
|
228
|
-
const valueEl =
|
|
815
|
+
const valueEl = valueEditing ? inputRef.current : valueTextRef.current;
|
|
229
816
|
if (!mounted || !card || !labelEl || !valueEl) {
|
|
230
817
|
setOverlapLayout(null);
|
|
231
818
|
return;
|
|
@@ -233,7 +820,7 @@ function SliderRow({
|
|
|
233
820
|
const measure = () => {
|
|
234
821
|
const c = cardRef.current;
|
|
235
822
|
const le = labelTextRef.current;
|
|
236
|
-
const ve =
|
|
823
|
+
const ve = valueEditing ? inputRef.current : valueTextRef.current;
|
|
237
824
|
if (!c || !le || !ve) {
|
|
238
825
|
setOverlapLayout(null);
|
|
239
826
|
return;
|
|
@@ -241,11 +828,11 @@ function SliderRow({
|
|
|
241
828
|
const cardRect = c.getBoundingClientRect();
|
|
242
829
|
const lr = le.getBoundingClientRect();
|
|
243
830
|
const vr = ve.getBoundingClientRect();
|
|
244
|
-
const
|
|
831
|
+
const w2 = cardRect.width;
|
|
245
832
|
let labelEnd = lr.right - cardRect.left + THUMB_OVERLAP_PAD_PX;
|
|
246
833
|
let valueStart = vr.left - cardRect.left - THUMB_OVERLAP_PAD_PX;
|
|
247
|
-
labelEnd = Math.min(Math.max(0, labelEnd),
|
|
248
|
-
valueStart = Math.min(Math.max(0, valueStart),
|
|
834
|
+
labelEnd = Math.min(Math.max(0, labelEnd), w2);
|
|
835
|
+
valueStart = Math.min(Math.max(0, valueStart), w2);
|
|
249
836
|
if (valueStart < labelEnd) valueStart = labelEnd;
|
|
250
837
|
setOverlapLayout((prev) => {
|
|
251
838
|
if (prev && prev.labelEnd === labelEnd && prev.valueStart === valueStart) {
|
|
@@ -258,33 +845,7 @@ function SliderRow({
|
|
|
258
845
|
const ro = new ResizeObserver(measure);
|
|
259
846
|
ro.observe(card);
|
|
260
847
|
return () => ro.disconnect();
|
|
261
|
-
}, [mounted, label, display,
|
|
262
|
-
useLayoutEffect(() => {
|
|
263
|
-
if (!editing) {
|
|
264
|
-
setValueEditWidthPx(null);
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
const measure = () => {
|
|
268
|
-
const m = valueEditMeasureRef.current;
|
|
269
|
-
const zone = valueRef.current;
|
|
270
|
-
if (!m || !zone) return;
|
|
271
|
-
const w = m.getBoundingClientRect().width;
|
|
272
|
-
const cs = getComputedStyle(zone);
|
|
273
|
-
const padL = parseFloat(cs.paddingLeft) || 0;
|
|
274
|
-
const padR = parseFloat(cs.paddingRight) || 0;
|
|
275
|
-
const maxInner = Math.max(0, zone.clientWidth - padL - padR);
|
|
276
|
-
const next = Math.min(
|
|
277
|
-
Math.max(Math.ceil(w + VALUE_EDIT_WIDTH_CARET_PAD_PX), 22),
|
|
278
|
-
Math.max(maxInner, 22)
|
|
279
|
-
);
|
|
280
|
-
setValueEditWidthPx((prev) => prev === next ? prev : next);
|
|
281
|
-
};
|
|
282
|
-
measure();
|
|
283
|
-
const ro = new ResizeObserver(measure);
|
|
284
|
-
const z = valueRef.current;
|
|
285
|
-
if (z) ro.observe(z);
|
|
286
|
-
return () => ro.disconnect();
|
|
287
|
-
}, [editing, draft]);
|
|
848
|
+
}, [mounted, label, display, valueEditing, value]);
|
|
288
849
|
const span = max - min;
|
|
289
850
|
const u = span > 0 ? (value - min) / span : 0;
|
|
290
851
|
useEffect(() => {
|
|
@@ -306,10 +867,10 @@ function SliderRow({
|
|
|
306
867
|
useEffect(() => {
|
|
307
868
|
if (!dragging) return;
|
|
308
869
|
const onMove = (e) => {
|
|
309
|
-
const { value:
|
|
870
|
+
const { value: v2, min: lo, max: hi } = dragStateRef.current;
|
|
310
871
|
const sp = hi - lo;
|
|
311
872
|
if (sp <= 0) return;
|
|
312
|
-
const uNow = (
|
|
873
|
+
const uNow = (v2 - lo) / sp;
|
|
313
874
|
const dx = e.clientX - lastPointerXRef.current;
|
|
314
875
|
lastPointerXRef.current = e.clientX;
|
|
315
876
|
if (uNow >= 1 - 1e-6 && dx > 0) {
|
|
@@ -357,10 +918,10 @@ function SliderRow({
|
|
|
357
918
|
}
|
|
358
919
|
const height = behindLabel ? THUMB_HEIGHT_BEHIND_LABEL_PX : THUMB_HEIGHT_PX;
|
|
359
920
|
let debugZones2 = null;
|
|
360
|
-
if (debugOverlap && labelTextRef.current && (
|
|
921
|
+
if (debugOverlap && labelTextRef.current && (valueEditing ? inputRef.current : valueTextRef.current)) {
|
|
361
922
|
const cr = cardRef.current.getBoundingClientRect();
|
|
362
923
|
const lr = labelTextRef.current.getBoundingClientRect();
|
|
363
|
-
const ve =
|
|
924
|
+
const ve = valueEditing ? inputRef.current : valueTextRef.current;
|
|
364
925
|
const vr = ve.getBoundingClientRect();
|
|
365
926
|
debugZones2 = {
|
|
366
927
|
overlapLabelEnd: labelEnd,
|
|
@@ -382,35 +943,10 @@ function SliderRow({
|
|
|
382
943
|
return { opacity, height, debugZones: debugZones2 };
|
|
383
944
|
};
|
|
384
945
|
const { opacity: thumbOpacity, height: thumbHeight, debugZones } = getThumbLayout();
|
|
385
|
-
const startEdit = (e) => {
|
|
386
|
-
e.stopPropagation();
|
|
387
|
-
setDraft(String(value));
|
|
388
|
-
setEditing(true);
|
|
389
|
-
setTimeout(() => {
|
|
390
|
-
var _a;
|
|
391
|
-
return (_a = inputRef.current) == null ? void 0 : _a.select();
|
|
392
|
-
}, 0);
|
|
393
|
-
};
|
|
394
|
-
const commitEdit = () => {
|
|
395
|
-
const parsed = parseFloat(draft);
|
|
396
|
-
if (!Number.isNaN(parsed)) {
|
|
397
|
-
onChange(Math.max(min, Math.min(max, parsed)));
|
|
398
|
-
}
|
|
399
|
-
setEditing(false);
|
|
400
|
-
};
|
|
401
|
-
const handleKeyDown = (e) => {
|
|
402
|
-
if (e.key === "Enter") {
|
|
403
|
-
e.preventDefault();
|
|
404
|
-
commitEdit();
|
|
405
|
-
}
|
|
406
|
-
if (e.key === "Escape") {
|
|
407
|
-
setEditing(false);
|
|
408
|
-
}
|
|
409
|
-
e.stopPropagation();
|
|
410
|
-
};
|
|
411
946
|
const isActive = hovered || dragging;
|
|
412
|
-
const idleThumbWidth =
|
|
947
|
+
const idleThumbWidth = 0;
|
|
413
948
|
const handleRangePointerDown = (e) => {
|
|
949
|
+
if (disabled) return;
|
|
414
950
|
clearDocumentSelection();
|
|
415
951
|
lastPointerXRef.current = e.clientX;
|
|
416
952
|
syncBaseWidthFromParent();
|
|
@@ -441,7 +977,8 @@ function SliderRow({
|
|
|
441
977
|
{
|
|
442
978
|
className: "sliderCardWrap",
|
|
443
979
|
ref: wrapRef,
|
|
444
|
-
|
|
980
|
+
"data-disabled": disabled ? "true" : "false",
|
|
981
|
+
onPointerEnter: () => !disabled && setHovered(true),
|
|
445
982
|
onPointerLeave: () => setHovered(false),
|
|
446
983
|
children: /* @__PURE__ */ jsxs(
|
|
447
984
|
motion.div,
|
|
@@ -527,7 +1064,7 @@ function SliderRow({
|
|
|
527
1064
|
className: "sliderTicks",
|
|
528
1065
|
animate: { opacity: isActive ? 1 : 0 },
|
|
529
1066
|
transition: { duration: 0.15, ease: "easeOut" },
|
|
530
|
-
children: [...Array(10)].map((
|
|
1067
|
+
children: [...Array(10)].map((_2, i) => /* @__PURE__ */ jsx("div", { className: "sliderTick" }, i))
|
|
531
1068
|
}
|
|
532
1069
|
),
|
|
533
1070
|
/* @__PURE__ */ jsx(
|
|
@@ -539,6 +1076,7 @@ function SliderRow({
|
|
|
539
1076
|
max,
|
|
540
1077
|
step,
|
|
541
1078
|
value,
|
|
1079
|
+
disabled,
|
|
542
1080
|
draggable: false,
|
|
543
1081
|
onChange: (e) => onChange(parseFloat(e.target.value)),
|
|
544
1082
|
onPointerDown: handleRangePointerDown,
|
|
@@ -570,43 +1108,40 @@ function SliderRow({
|
|
|
570
1108
|
ref: valueRef,
|
|
571
1109
|
className: "sliderValueZone",
|
|
572
1110
|
onClick: (e) => e.stopPropagation(),
|
|
573
|
-
children:
|
|
574
|
-
|
|
575
|
-
"span",
|
|
576
|
-
{
|
|
577
|
-
ref: valueEditMeasureRef,
|
|
578
|
-
className: "sliderValue sliderValueText sliderValueMeasure",
|
|
579
|
-
"aria-hidden": true,
|
|
580
|
-
children: draft.length > 0 ? draft : "0"
|
|
581
|
-
}
|
|
582
|
-
),
|
|
583
|
-
/* @__PURE__ */ jsx(
|
|
584
|
-
"input",
|
|
585
|
-
{
|
|
586
|
-
ref: inputRef,
|
|
587
|
-
className: "sliderValueInput",
|
|
588
|
-
type: "text",
|
|
589
|
-
inputMode: min < 0 || stepAllowsDecimal(step) ? "decimal" : "numeric",
|
|
590
|
-
value: draft,
|
|
591
|
-
autoComplete: "off",
|
|
592
|
-
spellCheck: false,
|
|
593
|
-
"aria-valuemin": min,
|
|
594
|
-
"aria-valuemax": max,
|
|
595
|
-
style: valueEditWidthPx != null ? { width: valueEditWidthPx } : { minWidth: 22 },
|
|
596
|
-
onChange: (e) => setDraft(sanitizeValueDraft(e.target.value, min, step)),
|
|
597
|
-
onBlur: commitEdit,
|
|
598
|
-
onKeyDown: handleKeyDown,
|
|
599
|
-
onClick: (e) => e.stopPropagation()
|
|
600
|
-
}
|
|
601
|
-
)
|
|
602
|
-
] }) : /* @__PURE__ */ jsx(
|
|
603
|
-
"span",
|
|
1111
|
+
children: /* @__PURE__ */ jsx(
|
|
1112
|
+
ValueInput,
|
|
604
1113
|
{
|
|
1114
|
+
value: String(display),
|
|
1115
|
+
disabled,
|
|
1116
|
+
onCommit: (val) => {
|
|
1117
|
+
const parsed = parseFloat(val);
|
|
1118
|
+
if (!Number.isNaN(parsed)) {
|
|
1119
|
+
onChange(Math.max(min, Math.min(max, parsed)));
|
|
1120
|
+
}
|
|
1121
|
+
},
|
|
1122
|
+
sanitize: (val) => sanitizeValueDraft(val, min, step),
|
|
1123
|
+
validate: (val) => !Number.isNaN(parseFloat(val)),
|
|
1124
|
+
inputMode: min < 0 || stepAllowsDecimal(step) ? "decimal" : "numeric",
|
|
1125
|
+
align: "right",
|
|
1126
|
+
isActive,
|
|
605
1127
|
className: "sliderValue",
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
1128
|
+
autoWidth: true,
|
|
1129
|
+
arrowStep: step,
|
|
1130
|
+
arrowMin: min,
|
|
1131
|
+
arrowMax: max,
|
|
1132
|
+
valueTextRef,
|
|
1133
|
+
inputRef,
|
|
1134
|
+
onEditingChange: setValueEditing,
|
|
1135
|
+
renderValue: (val) => dragging ? val : /* @__PURE__ */ jsx(
|
|
1136
|
+
h,
|
|
1137
|
+
{
|
|
1138
|
+
className: "sliderValueMorph",
|
|
1139
|
+
as: "span",
|
|
1140
|
+
duration: 260,
|
|
1141
|
+
ease: { stiffness: 380, damping: 34, mass: 0.42 },
|
|
1142
|
+
children: val
|
|
1143
|
+
}
|
|
1144
|
+
)
|
|
610
1145
|
}
|
|
611
1146
|
)
|
|
612
1147
|
}
|
|
@@ -617,177 +1152,915 @@ function SliderRow({
|
|
|
617
1152
|
}
|
|
618
1153
|
);
|
|
619
1154
|
}
|
|
620
|
-
function
|
|
621
|
-
return /* @__PURE__ */ jsxs(Popover.Root, { modal: true, children: [
|
|
622
|
-
/* @__PURE__ */ jsx(Popover.Trigger, { render: renderTrigger }),
|
|
623
|
-
/* @__PURE__ */ jsx(Popover.Portal, { className: "swatchPopoverPortal", children: /* @__PURE__ */ jsx(
|
|
624
|
-
Popover.Positioner,
|
|
625
|
-
{
|
|
626
|
-
className: "swatchPopoverPositioner",
|
|
627
|
-
positionMethod: "fixed",
|
|
628
|
-
side: "bottom",
|
|
629
|
-
align: "end",
|
|
630
|
-
sideOffset: 6,
|
|
631
|
-
collisionAvoidance: { side: "flip", align: "shift", fallbackAxisSide: "none" },
|
|
632
|
-
children: /* @__PURE__ */ jsxs(
|
|
633
|
-
Popover.Popup,
|
|
634
|
-
{
|
|
635
|
-
className: "swatchPopoverPopup",
|
|
636
|
-
initialFocus: (openType) => openType === "keyboard",
|
|
637
|
-
children: [
|
|
638
|
-
title && /* @__PURE__ */ jsx(Popover.Title, { className: "swatchPopoverTitle", children: title }),
|
|
639
|
-
/* @__PURE__ */ jsx(Popover.Close, { type: "button", className: "swatchPopoverCloseSrOnly", children: "Close" }),
|
|
640
|
-
/* @__PURE__ */ jsx("div", { className: "swatchPopoverBody", children })
|
|
641
|
-
]
|
|
642
|
-
}
|
|
643
|
-
)
|
|
644
|
-
}
|
|
645
|
-
) })
|
|
646
|
-
] });
|
|
647
|
-
}
|
|
648
|
-
function normalizeHex$1(raw) {
|
|
1155
|
+
function normalizeHex(raw) {
|
|
649
1156
|
const s = raw.trim();
|
|
650
1157
|
const m = s.match(/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/);
|
|
651
1158
|
if (!m) return "#808080";
|
|
652
|
-
let
|
|
653
|
-
if (
|
|
654
|
-
|
|
1159
|
+
let h2 = m[1];
|
|
1160
|
+
if (h2.length === 3) {
|
|
1161
|
+
h2 = h2[0] + h2[0] + h2[1] + h2[1] + h2[2] + h2[2];
|
|
655
1162
|
}
|
|
656
|
-
return `#${
|
|
1163
|
+
return `#${h2.toUpperCase()}`;
|
|
657
1164
|
}
|
|
658
|
-
function
|
|
659
|
-
const
|
|
660
|
-
|
|
1165
|
+
function hslToHex(h2, s, l2) {
|
|
1166
|
+
const [r, g, b2] = hslToRgbBytes(h2, s, l2);
|
|
1167
|
+
const toHex = (v2) => v2.toString(16).padStart(2, "0");
|
|
1168
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b2)}`.toUpperCase();
|
|
661
1169
|
}
|
|
662
|
-
function
|
|
663
|
-
|
|
1170
|
+
function hslToRgbBytes(h2, s, l2) {
|
|
1171
|
+
const hue = (h2 % 360 + 360) % 360;
|
|
1172
|
+
const sat = Math.max(0, Math.min(1, s));
|
|
1173
|
+
const lit = Math.max(0, Math.min(1, l2));
|
|
1174
|
+
const c = (1 - Math.abs(2 * lit - 1)) * sat;
|
|
1175
|
+
const x2 = c * (1 - Math.abs(hue / 60 % 2 - 1));
|
|
1176
|
+
const m = lit - c / 2;
|
|
1177
|
+
let rp = 0;
|
|
1178
|
+
let gp = 0;
|
|
1179
|
+
let bp = 0;
|
|
1180
|
+
if (hue < 60) {
|
|
1181
|
+
rp = c;
|
|
1182
|
+
gp = x2;
|
|
1183
|
+
} else if (hue < 120) {
|
|
1184
|
+
rp = x2;
|
|
1185
|
+
gp = c;
|
|
1186
|
+
} else if (hue < 180) {
|
|
1187
|
+
gp = c;
|
|
1188
|
+
bp = x2;
|
|
1189
|
+
} else if (hue < 240) {
|
|
1190
|
+
gp = x2;
|
|
1191
|
+
bp = c;
|
|
1192
|
+
} else if (hue < 300) {
|
|
1193
|
+
rp = x2;
|
|
1194
|
+
bp = c;
|
|
1195
|
+
} else {
|
|
1196
|
+
rp = c;
|
|
1197
|
+
bp = x2;
|
|
1198
|
+
}
|
|
1199
|
+
return [Math.round((rp + m) * 255), Math.round((gp + m) * 255), Math.round((bp + m) * 255)];
|
|
664
1200
|
}
|
|
665
|
-
function
|
|
666
|
-
const
|
|
667
|
-
const
|
|
668
|
-
const
|
|
669
|
-
const
|
|
670
|
-
const
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
1201
|
+
function hexToHsl(hex) {
|
|
1202
|
+
const n2 = normalizeHex(hex);
|
|
1203
|
+
const r = parseInt(n2.slice(1, 3), 16) / 255;
|
|
1204
|
+
const g = parseInt(n2.slice(3, 5), 16) / 255;
|
|
1205
|
+
const b2 = parseInt(n2.slice(5, 7), 16) / 255;
|
|
1206
|
+
const max = Math.max(r, g, b2);
|
|
1207
|
+
const min = Math.min(r, g, b2);
|
|
1208
|
+
const l2 = (max + min) / 2;
|
|
1209
|
+
let h2 = 0;
|
|
1210
|
+
let s = 0;
|
|
1211
|
+
const d2 = max - min;
|
|
1212
|
+
if (d2 !== 0) {
|
|
1213
|
+
s = l2 > 0.5 ? d2 / (2 - max - min) : d2 / (max + min);
|
|
1214
|
+
switch (max) {
|
|
1215
|
+
case r:
|
|
1216
|
+
h2 = ((g - b2) / d2 + (g < b2 ? 6 : 0)) * 60;
|
|
1217
|
+
break;
|
|
1218
|
+
case g:
|
|
1219
|
+
h2 = ((b2 - r) / d2 + 2) * 60;
|
|
1220
|
+
break;
|
|
1221
|
+
default:
|
|
1222
|
+
h2 = ((r - g) / d2 + 4) * 60;
|
|
1223
|
+
break;
|
|
687
1224
|
}
|
|
688
|
-
|
|
689
|
-
};
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
1225
|
+
}
|
|
1226
|
+
return { h: h2, s, l: l2 };
|
|
1227
|
+
}
|
|
1228
|
+
function hsvToRgbBytes(h2, s, v2) {
|
|
1229
|
+
const hue = (h2 % 360 + 360) % 360;
|
|
1230
|
+
const sat = Math.max(0, Math.min(1, s));
|
|
1231
|
+
const val = Math.max(0, Math.min(1, v2));
|
|
1232
|
+
const c = val * sat;
|
|
1233
|
+
const x2 = c * (1 - Math.abs(hue / 60 % 2 - 1));
|
|
1234
|
+
const m = val - c;
|
|
1235
|
+
let rp = 0;
|
|
1236
|
+
let gp = 0;
|
|
1237
|
+
let bp = 0;
|
|
1238
|
+
if (hue < 60) {
|
|
1239
|
+
rp = c;
|
|
1240
|
+
gp = x2;
|
|
1241
|
+
} else if (hue < 120) {
|
|
1242
|
+
rp = x2;
|
|
1243
|
+
gp = c;
|
|
1244
|
+
} else if (hue < 180) {
|
|
1245
|
+
gp = c;
|
|
1246
|
+
bp = x2;
|
|
1247
|
+
} else if (hue < 240) {
|
|
1248
|
+
gp = x2;
|
|
1249
|
+
bp = c;
|
|
1250
|
+
} else if (hue < 300) {
|
|
1251
|
+
rp = x2;
|
|
1252
|
+
bp = c;
|
|
1253
|
+
} else {
|
|
1254
|
+
rp = c;
|
|
1255
|
+
bp = x2;
|
|
1256
|
+
}
|
|
1257
|
+
return [Math.round((rp + m) * 255), Math.round((gp + m) * 255), Math.round((bp + m) * 255)];
|
|
1258
|
+
}
|
|
1259
|
+
function hsvToHex(h2, s, v2) {
|
|
1260
|
+
const [r, g, b2] = hsvToRgbBytes(h2, s, v2);
|
|
1261
|
+
const toHex = (n2) => n2.toString(16).padStart(2, "0");
|
|
1262
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b2)}`.toUpperCase();
|
|
1263
|
+
}
|
|
1264
|
+
function hexToHsv(hex) {
|
|
1265
|
+
const n2 = normalizeHex(hex);
|
|
1266
|
+
const r = parseInt(n2.slice(1, 3), 16) / 255;
|
|
1267
|
+
const g = parseInt(n2.slice(3, 5), 16) / 255;
|
|
1268
|
+
const b2 = parseInt(n2.slice(5, 7), 16) / 255;
|
|
1269
|
+
const max = Math.max(r, g, b2);
|
|
1270
|
+
const min = Math.min(r, g, b2);
|
|
1271
|
+
const d2 = max - min;
|
|
1272
|
+
let h2 = 0;
|
|
1273
|
+
if (d2 !== 0) {
|
|
1274
|
+
switch (max) {
|
|
1275
|
+
case r:
|
|
1276
|
+
h2 = ((g - b2) / d2 + (g < b2 ? 6 : 0)) * 60;
|
|
1277
|
+
break;
|
|
1278
|
+
case g:
|
|
1279
|
+
h2 = ((b2 - r) / d2 + 2) * 60;
|
|
1280
|
+
break;
|
|
1281
|
+
default:
|
|
1282
|
+
h2 = ((r - g) / d2 + 4) * 60;
|
|
1283
|
+
break;
|
|
694
1284
|
}
|
|
695
|
-
|
|
696
|
-
|
|
1285
|
+
}
|
|
1286
|
+
const v2 = max;
|
|
1287
|
+
const s = max === 0 ? 0 : d2 / max;
|
|
1288
|
+
return { h: h2, s, v: v2 };
|
|
1289
|
+
}
|
|
1290
|
+
function hexToRgb(hex) {
|
|
1291
|
+
const n2 = normalizeHex(hex);
|
|
1292
|
+
return {
|
|
1293
|
+
r: parseInt(n2.slice(1, 3), 16),
|
|
1294
|
+
g: parseInt(n2.slice(3, 5), 16),
|
|
1295
|
+
b: parseInt(n2.slice(5, 7), 16)
|
|
1296
|
+
};
|
|
1297
|
+
}
|
|
1298
|
+
function rgbToHex(r, g, b2) {
|
|
1299
|
+
const clampByte = (v2) => Math.max(0, Math.min(255, Math.round(v2)));
|
|
1300
|
+
const toHex = (v2) => clampByte(v2).toString(16).padStart(2, "0");
|
|
1301
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b2)}`.toUpperCase();
|
|
1302
|
+
}
|
|
1303
|
+
function clampHueDeg$1(h2) {
|
|
1304
|
+
return (h2 % 360 + 360) % 360;
|
|
1305
|
+
}
|
|
1306
|
+
function clamp01$1(v2) {
|
|
1307
|
+
return Math.max(0, Math.min(1, v2));
|
|
1308
|
+
}
|
|
1309
|
+
function parseNumberish(s) {
|
|
1310
|
+
const n2 = Number.parseFloat(s.trim());
|
|
1311
|
+
return Number.isFinite(n2) ? n2 : null;
|
|
1312
|
+
}
|
|
1313
|
+
function splitCssArgs(raw) {
|
|
1314
|
+
const noAlpha = raw.split("/")[0] ?? raw;
|
|
1315
|
+
return noAlpha.trim().replace(/,/g, " ").split(/\s+/).filter(Boolean);
|
|
1316
|
+
}
|
|
1317
|
+
function parseRgbArgsToBytes(args) {
|
|
1318
|
+
if (args.length < 3) return null;
|
|
1319
|
+
const nums = args.slice(0, 3);
|
|
1320
|
+
const bytes = [];
|
|
1321
|
+
for (const token of nums) {
|
|
1322
|
+
if (token.endsWith("%")) {
|
|
1323
|
+
const n2 = parseNumberish(token.slice(0, -1));
|
|
1324
|
+
if (n2 === null) return null;
|
|
1325
|
+
bytes.push(Math.round(Math.max(0, Math.min(100, n2)) / 100 * 255));
|
|
1326
|
+
} else {
|
|
1327
|
+
const n2 = parseNumberish(token);
|
|
1328
|
+
if (n2 === null) return null;
|
|
1329
|
+
bytes.push(Math.round(Math.max(0, Math.min(255, n2))));
|
|
697
1330
|
}
|
|
698
|
-
|
|
1331
|
+
}
|
|
1332
|
+
return { r: bytes[0], g: bytes[1], b: bytes[2] };
|
|
1333
|
+
}
|
|
1334
|
+
function parseHslArgs(args) {
|
|
1335
|
+
if (args.length < 3) return null;
|
|
1336
|
+
const hRaw = parseNumberish(args[0]);
|
|
1337
|
+
if (hRaw === null) return null;
|
|
1338
|
+
const h2 = clampHueDeg$1(String(args[0]).endsWith("deg") ? parseNumberish(String(args[0]).replace(/deg$/i, "")) ?? hRaw : hRaw);
|
|
1339
|
+
const sTok = args[1];
|
|
1340
|
+
const lTok = args[2];
|
|
1341
|
+
if (!sTok.endsWith("%") || !lTok.endsWith("%")) return null;
|
|
1342
|
+
const sN = parseNumberish(sTok.slice(0, -1));
|
|
1343
|
+
const lN = parseNumberish(lTok.slice(0, -1));
|
|
1344
|
+
if (sN === null || lN === null) return null;
|
|
1345
|
+
return { h: h2, s: clamp01$1(sN / 100), l: clamp01$1(lN / 100) };
|
|
1346
|
+
}
|
|
1347
|
+
function parseHsvArgs(args) {
|
|
1348
|
+
if (args.length < 3) return null;
|
|
1349
|
+
const hRaw = parseNumberish(args[0]);
|
|
1350
|
+
if (hRaw === null) return null;
|
|
1351
|
+
const h2 = clampHueDeg$1(hRaw);
|
|
1352
|
+
const sTok = args[1];
|
|
1353
|
+
const vTok = args[2];
|
|
1354
|
+
if (!sTok.endsWith("%") || !vTok.endsWith("%")) return null;
|
|
1355
|
+
const sN = parseNumberish(sTok.slice(0, -1));
|
|
1356
|
+
const vN = parseNumberish(vTok.slice(0, -1));
|
|
1357
|
+
if (sN === null || vN === null) return null;
|
|
1358
|
+
return { h: h2, s: clamp01$1(sN / 100), v: clamp01$1(vN / 100) };
|
|
1359
|
+
}
|
|
1360
|
+
function parseCssColorToHex(raw) {
|
|
1361
|
+
const s = raw.trim();
|
|
1362
|
+
if (!s) return null;
|
|
1363
|
+
if (/^#?[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/.test(s)) {
|
|
1364
|
+
return normalizeHex(s);
|
|
1365
|
+
}
|
|
1366
|
+
const fn = s.match(/^([a-zA-Z]+)\((.*)\)$/);
|
|
1367
|
+
if (!fn) return null;
|
|
1368
|
+
const name = fn[1].toLowerCase();
|
|
1369
|
+
const args = splitCssArgs(fn[2] ?? "");
|
|
1370
|
+
if (name === "rgb" || name === "rgba") {
|
|
1371
|
+
const rgb = parseRgbArgsToBytes(args);
|
|
1372
|
+
return rgb ? rgbToHex(rgb.r, rgb.g, rgb.b) : null;
|
|
1373
|
+
}
|
|
1374
|
+
if (name === "hsl" || name === "hsla") {
|
|
1375
|
+
const hsl = parseHslArgs(args);
|
|
1376
|
+
return hsl ? hslToHex(hsl.h, hsl.s, hsl.l) : null;
|
|
1377
|
+
}
|
|
1378
|
+
if (name === "hsv" || name === "hsb") {
|
|
1379
|
+
const hsv = parseHsvArgs(args);
|
|
1380
|
+
return hsv ? hsvToHex(hsv.h, hsv.s, hsv.v) : null;
|
|
1381
|
+
}
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
const HUE_STOPS = [
|
|
1385
|
+
"#FF0000",
|
|
1386
|
+
"#FFFF00",
|
|
1387
|
+
"#00FF00",
|
|
1388
|
+
"#00FFFF",
|
|
1389
|
+
"#0000FF",
|
|
1390
|
+
"#FF00FF",
|
|
1391
|
+
"#FF0000"
|
|
1392
|
+
];
|
|
1393
|
+
function clamp01(v2) {
|
|
1394
|
+
return Math.max(0, Math.min(1, v2));
|
|
1395
|
+
}
|
|
1396
|
+
function clampHueDeg(h2) {
|
|
1397
|
+
return (h2 % 360 + 360) % 360;
|
|
1398
|
+
}
|
|
1399
|
+
function clampInt(n2, min, max) {
|
|
1400
|
+
return Math.max(min, Math.min(max, Math.round(n2)));
|
|
1401
|
+
}
|
|
1402
|
+
function normalizeHexDigits(raw) {
|
|
1403
|
+
return raw.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
1404
|
+
}
|
|
1405
|
+
function isValidSixHex$2(d2) {
|
|
1406
|
+
return /^[0-9a-fA-F]{6}$/.test(d2);
|
|
1407
|
+
}
|
|
1408
|
+
function clampHsv01(base) {
|
|
1409
|
+
return { h: clampHueDeg(base.h), s: clamp01(base.s), v: clamp01(base.v) };
|
|
1410
|
+
}
|
|
1411
|
+
function clampHsl01(base) {
|
|
1412
|
+
return { h: clampHueDeg(base.h), s: clamp01(base.s), l: clamp01(base.l) };
|
|
1413
|
+
}
|
|
1414
|
+
function cycleMode(m) {
|
|
1415
|
+
if (m === "hex") return "hsl";
|
|
1416
|
+
if (m === "hsl") return "hsb";
|
|
1417
|
+
if (m === "hsb") return "rgb";
|
|
1418
|
+
return "hex";
|
|
1419
|
+
}
|
|
1420
|
+
function drawSvPlane(ctx, w2, h2, hue) {
|
|
1421
|
+
const img = ctx.createImageData(w2, h2);
|
|
1422
|
+
const d2 = img.data;
|
|
1423
|
+
let p = 0;
|
|
1424
|
+
for (let y2 = 0; y2 < h2; y2++) {
|
|
1425
|
+
const v2 = 1 - y2 / Math.max(1, h2 - 1);
|
|
1426
|
+
for (let x2 = 0; x2 < w2; x2++) {
|
|
1427
|
+
const s = x2 / Math.max(1, w2 - 1);
|
|
1428
|
+
const [r, g, b2] = hsvToRgbBytes(hue, s, v2);
|
|
1429
|
+
d2[p] = r;
|
|
1430
|
+
d2[p + 1] = g;
|
|
1431
|
+
d2[p + 2] = b2;
|
|
1432
|
+
d2[p + 3] = 255;
|
|
1433
|
+
p += 4;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
ctx.putImageData(img, 0, 0);
|
|
1437
|
+
}
|
|
1438
|
+
function readSvFromClient(clientX, clientY, base, svEl) {
|
|
1439
|
+
if (!svEl) return null;
|
|
1440
|
+
const r = svEl.getBoundingClientRect();
|
|
1441
|
+
if (r.width <= 0 || r.height <= 0) return null;
|
|
1442
|
+
const s = clamp01((clientX - r.left) / r.width);
|
|
1443
|
+
const v2 = clamp01(1 - (clientY - r.top) / r.height);
|
|
1444
|
+
return { ...base, s, v: v2 };
|
|
1445
|
+
}
|
|
1446
|
+
function readHueFromClient(clientY, base, hueEl) {
|
|
1447
|
+
if (!hueEl) return null;
|
|
1448
|
+
const r = hueEl.getBoundingClientRect();
|
|
1449
|
+
if (r.height <= 0) return null;
|
|
1450
|
+
const t2 = clamp01((clientY - r.top) / r.height);
|
|
1451
|
+
return { ...base, h: t2 * 360 };
|
|
1452
|
+
}
|
|
1453
|
+
function EyeDropperIcon() {
|
|
1454
|
+
return /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 18 18", "aria-hidden": "true", focusable: "false", children: [
|
|
1455
|
+
/* @__PURE__ */ jsx(
|
|
1456
|
+
"path",
|
|
1457
|
+
{
|
|
1458
|
+
d: "M15.651,2.348c-.998-.998-2.739-.998-3.737,0l-2.503,2.503-1.131-1.131c-.293-.293-.768-.293-1.061,0s-.293,.768,0,1.061l6,6c.146,.146,.338,.22,.53,.22s.384-.073,.53-.22c.293-.293,.293-.768,0-1.061l-1.131-1.131,2.502-2.502c1.03-1.03,1.03-2.708,0-3.738Z",
|
|
1459
|
+
fill: "currentColor"
|
|
1460
|
+
}
|
|
1461
|
+
),
|
|
1462
|
+
/* @__PURE__ */ jsx(
|
|
1463
|
+
"path",
|
|
1464
|
+
{
|
|
1465
|
+
d: "M2.596,11.667c-.845,.845-.985,2.12-.444,3.121l-.932,.931c-.293,.292-.293,.768,0,1.061,.146,.146,.338,.22,.53,.22,.191,0,.384-.073,.53-.22l.931-.931c.382,.208,.807,.329,1.254,.329,.706,0,1.369-.275,1.868-.774l4.695-4.695-3.738-3.737L2.596,11.667Z",
|
|
1466
|
+
fill: "currentColor"
|
|
1467
|
+
}
|
|
1468
|
+
)
|
|
1469
|
+
] });
|
|
1470
|
+
}
|
|
1471
|
+
function ColorPicker({ value, onChange }) {
|
|
1472
|
+
const canvasRef = useRef(null);
|
|
1473
|
+
const svWrapRef = useRef(null);
|
|
1474
|
+
const hueRef = useRef(null);
|
|
1475
|
+
const [dragging, setDragging] = useState(null);
|
|
1476
|
+
const [pointerDraft, setPointerDraft] = useState(null);
|
|
1477
|
+
const [memory, setMemory] = useState(() => {
|
|
1478
|
+
const base = hexToHsv(normalizeHex(value));
|
|
1479
|
+
return { h: base.h, s: base.s || 1 };
|
|
1480
|
+
});
|
|
1481
|
+
const [mode, setMode] = useState("hex");
|
|
1482
|
+
const hsvFromValueRaw = useMemo(() => hexToHsv(normalizeHex(value)), [value]);
|
|
1483
|
+
const hsvFromValue = useMemo(() => {
|
|
1484
|
+
const base = hsvFromValueRaw;
|
|
1485
|
+
if (base.v === 0) {
|
|
1486
|
+
return { ...base, h: memory.h, s: memory.s };
|
|
1487
|
+
}
|
|
1488
|
+
if (base.s === 0) {
|
|
1489
|
+
return { ...base, h: memory.h };
|
|
1490
|
+
}
|
|
1491
|
+
return base;
|
|
1492
|
+
}, [hsvFromValueRaw, memory.h, memory.s]);
|
|
1493
|
+
const draft = pointerDraft ?? hsvFromValue;
|
|
1494
|
+
const hex = useMemo(() => normalizeHex(value), [value]);
|
|
1495
|
+
const hslFromHex = useMemo(() => hexToHsl(hex), [hex]);
|
|
1496
|
+
const rgbFromHex = useMemo(() => hexToRgb(hex), [hex]);
|
|
1497
|
+
const redrawCanvas = useCallback(() => {
|
|
1498
|
+
const canvas = canvasRef.current;
|
|
1499
|
+
if (!canvas) return;
|
|
1500
|
+
const rect = canvas.getBoundingClientRect();
|
|
1501
|
+
const w2 = Math.max(1, Math.round(rect.width * (window.devicePixelRatio || 1)));
|
|
1502
|
+
const h2 = Math.max(1, Math.round(rect.height * (window.devicePixelRatio || 1)));
|
|
1503
|
+
if (canvas.width !== w2 || canvas.height !== h2) {
|
|
1504
|
+
canvas.width = w2;
|
|
1505
|
+
canvas.height = h2;
|
|
1506
|
+
}
|
|
1507
|
+
const ctx = canvas.getContext("2d");
|
|
1508
|
+
if (!ctx) return;
|
|
1509
|
+
drawSvPlane(ctx, w2, h2, draft.h);
|
|
1510
|
+
}, [draft.h]);
|
|
1511
|
+
useLayoutEffect(() => {
|
|
1512
|
+
redrawCanvas();
|
|
1513
|
+
}, [redrawCanvas]);
|
|
1514
|
+
useEffect(() => {
|
|
1515
|
+
const el = canvasRef.current;
|
|
1516
|
+
if (!el || typeof ResizeObserver === "undefined") return;
|
|
1517
|
+
const ro = new ResizeObserver(() => redrawCanvas());
|
|
1518
|
+
ro.observe(el);
|
|
1519
|
+
return () => ro.disconnect();
|
|
1520
|
+
}, [redrawCanvas]);
|
|
1521
|
+
const commit = useCallback(
|
|
1522
|
+
(next) => {
|
|
1523
|
+
setMemory({ h: next.h, s: next.s || memory.s });
|
|
1524
|
+
onChange(hsvToHex(next.h, next.s, next.v));
|
|
1525
|
+
},
|
|
1526
|
+
[onChange, memory.s]
|
|
1527
|
+
);
|
|
1528
|
+
const onToggleMode = () => {
|
|
1529
|
+
setMode((m) => cycleMode(m));
|
|
699
1530
|
};
|
|
700
|
-
const
|
|
701
|
-
const
|
|
702
|
-
|
|
1531
|
+
const handleColorPaste = (pasted) => {
|
|
1532
|
+
const parsed = parseCssColorToHex(pasted);
|
|
1533
|
+
if (parsed) {
|
|
1534
|
+
onChange(parsed);
|
|
1535
|
+
return "";
|
|
1536
|
+
}
|
|
1537
|
+
return null;
|
|
1538
|
+
};
|
|
1539
|
+
const onEyeDropper = async () => {
|
|
1540
|
+
const AnyWindow = window;
|
|
1541
|
+
if (!AnyWindow.EyeDropper) return;
|
|
1542
|
+
try {
|
|
1543
|
+
const dropper = new AnyWindow.EyeDropper();
|
|
1544
|
+
const result = await dropper.open();
|
|
1545
|
+
onChange(normalizeHex(result.sRGBHex));
|
|
1546
|
+
} catch {
|
|
1547
|
+
}
|
|
703
1548
|
};
|
|
704
|
-
const
|
|
1549
|
+
const onSlPointerDown = (e) => {
|
|
1550
|
+
if (e.button !== 0) return;
|
|
705
1551
|
e.preventDefault();
|
|
706
|
-
const
|
|
707
|
-
const
|
|
708
|
-
|
|
1552
|
+
const base = pointerDraft ?? hsvFromValue;
|
|
1553
|
+
const next = readSvFromClient(e.clientX, e.clientY, base, svWrapRef.current);
|
|
1554
|
+
if (!next) return;
|
|
1555
|
+
setMemory({ h: next.h, s: next.s || memory.s });
|
|
1556
|
+
setPointerDraft(next);
|
|
1557
|
+
setDragging("sl");
|
|
1558
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1559
|
+
};
|
|
1560
|
+
const onSlPointerMove = (e) => {
|
|
1561
|
+
if (dragging !== "sl" || !e.currentTarget.hasPointerCapture(e.pointerId)) return;
|
|
1562
|
+
setPointerDraft((prev) => {
|
|
1563
|
+
const base = prev ?? hsvFromValue;
|
|
1564
|
+
const next = readSvFromClient(e.clientX, e.clientY, base, svWrapRef.current);
|
|
1565
|
+
if (next) setMemory({ h: next.h, s: next.s || memory.s });
|
|
1566
|
+
return next ?? prev;
|
|
1567
|
+
});
|
|
1568
|
+
};
|
|
1569
|
+
const onSlPointerUp = (e) => {
|
|
1570
|
+
if (dragging !== "sl" || !e.currentTarget.hasPointerCapture(e.pointerId)) return;
|
|
1571
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
1572
|
+
const base = pointerDraft ?? hsvFromValue;
|
|
1573
|
+
const next = readSvFromClient(e.clientX, e.clientY, base, svWrapRef.current);
|
|
1574
|
+
if (next) commit(next);
|
|
1575
|
+
setPointerDraft(null);
|
|
1576
|
+
setDragging(null);
|
|
1577
|
+
};
|
|
1578
|
+
const onHuePointerDown = (e) => {
|
|
1579
|
+
if (e.button !== 0) return;
|
|
1580
|
+
e.preventDefault();
|
|
1581
|
+
const base = pointerDraft ?? hsvFromValue;
|
|
1582
|
+
const next = readHueFromClient(e.clientY, base, hueRef.current);
|
|
1583
|
+
if (!next) return;
|
|
1584
|
+
setMemory({ h: next.h, s: next.s || memory.s });
|
|
1585
|
+
setPointerDraft(next);
|
|
1586
|
+
setDragging("hue");
|
|
1587
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1588
|
+
};
|
|
1589
|
+
const onHuePointerMove = (e) => {
|
|
1590
|
+
if (dragging !== "hue" || !e.currentTarget.hasPointerCapture(e.pointerId)) return;
|
|
1591
|
+
setPointerDraft((prev) => {
|
|
1592
|
+
const base = prev ?? hsvFromValue;
|
|
1593
|
+
const next = readHueFromClient(e.clientY, base, hueRef.current);
|
|
1594
|
+
if (next) setMemory({ h: next.h, s: next.s || memory.s });
|
|
1595
|
+
return next ?? prev;
|
|
1596
|
+
});
|
|
709
1597
|
};
|
|
710
|
-
const
|
|
711
|
-
|
|
1598
|
+
const onHuePointerUp = (e) => {
|
|
1599
|
+
if (dragging !== "hue" || !e.currentTarget.hasPointerCapture(e.pointerId)) return;
|
|
1600
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
1601
|
+
const base = pointerDraft ?? hsvFromValue;
|
|
1602
|
+
const next = readHueFromClient(e.clientY, base, hueRef.current);
|
|
1603
|
+
if (next) commit(next);
|
|
1604
|
+
setPointerDraft(null);
|
|
1605
|
+
setDragging(null);
|
|
1606
|
+
};
|
|
1607
|
+
const previewHex = hsvToHex(draft.h, draft.s, draft.v);
|
|
1608
|
+
const onSlKeyDown = (e) => {
|
|
1609
|
+
const step = e.shiftKey ? 0.05 : 0.01;
|
|
1610
|
+
let { s, v: v2 } = draft;
|
|
1611
|
+
let handled = true;
|
|
1612
|
+
switch (e.key) {
|
|
1613
|
+
case "ArrowRight":
|
|
1614
|
+
s = clamp01(s + step);
|
|
1615
|
+
break;
|
|
1616
|
+
case "ArrowLeft":
|
|
1617
|
+
s = clamp01(s - step);
|
|
1618
|
+
break;
|
|
1619
|
+
case "ArrowUp":
|
|
1620
|
+
v2 = clamp01(v2 + step);
|
|
1621
|
+
break;
|
|
1622
|
+
case "ArrowDown":
|
|
1623
|
+
v2 = clamp01(v2 - step);
|
|
1624
|
+
break;
|
|
1625
|
+
case "Home":
|
|
1626
|
+
s = 0;
|
|
1627
|
+
break;
|
|
1628
|
+
case "End":
|
|
1629
|
+
s = 1;
|
|
1630
|
+
break;
|
|
1631
|
+
case "PageUp":
|
|
1632
|
+
v2 = clamp01(v2 + 0.1);
|
|
1633
|
+
break;
|
|
1634
|
+
case "PageDown":
|
|
1635
|
+
v2 = clamp01(v2 - 0.1);
|
|
1636
|
+
break;
|
|
1637
|
+
default:
|
|
1638
|
+
handled = false;
|
|
1639
|
+
}
|
|
1640
|
+
if (!handled) return;
|
|
1641
|
+
e.preventDefault();
|
|
1642
|
+
e.stopPropagation();
|
|
1643
|
+
const next = { ...draft, s, v: v2 };
|
|
1644
|
+
commit(next);
|
|
1645
|
+
};
|
|
1646
|
+
const onHueKeyDown = (e) => {
|
|
1647
|
+
const stepSmall = e.shiftKey ? 10 : 1;
|
|
1648
|
+
let h2 = draft.h;
|
|
1649
|
+
let handled = true;
|
|
1650
|
+
switch (e.key) {
|
|
1651
|
+
case "ArrowRight":
|
|
1652
|
+
h2 = (h2 + stepSmall) % 360 + 360;
|
|
1653
|
+
h2 %= 360;
|
|
1654
|
+
break;
|
|
1655
|
+
case "ArrowLeft":
|
|
1656
|
+
h2 = (h2 - stepSmall) % 360 + 360;
|
|
1657
|
+
h2 %= 360;
|
|
1658
|
+
break;
|
|
1659
|
+
case "Home":
|
|
1660
|
+
h2 = 0;
|
|
1661
|
+
break;
|
|
1662
|
+
case "End":
|
|
1663
|
+
h2 = 359;
|
|
1664
|
+
break;
|
|
1665
|
+
case "PageUp":
|
|
1666
|
+
h2 = ((Math.round(h2) + 10) % 360 + 360) % 360;
|
|
1667
|
+
break;
|
|
1668
|
+
case "PageDown":
|
|
1669
|
+
h2 = ((Math.round(h2) - 10) % 360 + 360) % 360;
|
|
1670
|
+
break;
|
|
1671
|
+
default:
|
|
1672
|
+
handled = false;
|
|
1673
|
+
}
|
|
1674
|
+
if (!handled) return;
|
|
1675
|
+
e.preventDefault();
|
|
1676
|
+
e.stopPropagation();
|
|
1677
|
+
const next = { ...draft, h: h2 };
|
|
1678
|
+
commit(next);
|
|
1679
|
+
};
|
|
1680
|
+
const crossLeft = `${draft.s * 100}%`;
|
|
1681
|
+
const crossTop = `${(1 - draft.v) * 100}%`;
|
|
1682
|
+
const hueThumbTop = `${draft.h / 360 * 100}%`;
|
|
1683
|
+
const hueThumbTopClamped = `clamp(8px, ${hueThumbTop}, calc(100% - 8px))`;
|
|
1684
|
+
const hslUiH = clampInt(hslFromHex.h, 0, 360);
|
|
1685
|
+
const hslUiS = clampInt(hslFromHex.s * 100, 0, 100);
|
|
1686
|
+
const hslUiL = clampInt(hslFromHex.l * 100, 0, 100);
|
|
1687
|
+
const hsbUiH = clampInt(draft.h, 0, 360);
|
|
1688
|
+
const hsbUiS = clampInt(draft.s * 100, 0, 100);
|
|
1689
|
+
const hsbUiB = clampInt(draft.v * 100, 0, 100);
|
|
1690
|
+
return /* @__PURE__ */ jsxs("div", { className: "colorPicker", children: [
|
|
1691
|
+
/* @__PURE__ */ jsxs(
|
|
1692
|
+
"div",
|
|
1693
|
+
{
|
|
1694
|
+
className: "colorPickerSpace",
|
|
1695
|
+
"data-node-id": "565:1006",
|
|
1696
|
+
children: [
|
|
1697
|
+
/* @__PURE__ */ jsxs(
|
|
1698
|
+
"div",
|
|
1699
|
+
{
|
|
1700
|
+
ref: svWrapRef,
|
|
1701
|
+
className: "colorPickerSv",
|
|
1702
|
+
onPointerDown: onSlPointerDown,
|
|
1703
|
+
onPointerMove: onSlPointerMove,
|
|
1704
|
+
onPointerUp: onSlPointerUp,
|
|
1705
|
+
onPointerCancel: onSlPointerUp,
|
|
1706
|
+
role: "group",
|
|
1707
|
+
"aria-label": "Saturation and brightness",
|
|
1708
|
+
tabIndex: 0,
|
|
1709
|
+
onKeyDown: onSlKeyDown,
|
|
1710
|
+
"data-node-id": "565:1007",
|
|
1711
|
+
children: [
|
|
1712
|
+
/* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "colorPickerSvCanvas", "aria-hidden": true }),
|
|
1713
|
+
/* @__PURE__ */ jsx("span", { className: "colorPickerIndicator", style: { left: crossLeft, top: crossTop }, "aria-hidden": true })
|
|
1714
|
+
]
|
|
1715
|
+
}
|
|
1716
|
+
),
|
|
1717
|
+
/* @__PURE__ */ jsx("div", { className: "colorPickerHueWrap", children: /* @__PURE__ */ jsx(
|
|
1718
|
+
"div",
|
|
1719
|
+
{
|
|
1720
|
+
ref: hueRef,
|
|
1721
|
+
className: "colorPickerHue",
|
|
1722
|
+
onPointerDown: onHuePointerDown,
|
|
1723
|
+
onPointerMove: onHuePointerMove,
|
|
1724
|
+
onPointerUp: onHuePointerUp,
|
|
1725
|
+
onPointerCancel: onHuePointerUp,
|
|
1726
|
+
role: "slider",
|
|
1727
|
+
"aria-label": "Hue",
|
|
1728
|
+
"aria-valuemin": 0,
|
|
1729
|
+
"aria-valuemax": 360,
|
|
1730
|
+
"aria-valuenow": Math.round(draft.h),
|
|
1731
|
+
"aria-orientation": "vertical",
|
|
1732
|
+
tabIndex: 0,
|
|
1733
|
+
onKeyDown: onHueKeyDown,
|
|
1734
|
+
style: {
|
|
1735
|
+
background: `linear-gradient(to bottom, ${HUE_STOPS.join(", ")})`
|
|
1736
|
+
},
|
|
1737
|
+
"data-node-id": "565:1008",
|
|
1738
|
+
children: /* @__PURE__ */ jsx("span", { className: "colorPickerIndicator", style: { left: "50%", top: hueThumbTopClamped }, "aria-hidden": true })
|
|
1739
|
+
}
|
|
1740
|
+
) })
|
|
1741
|
+
]
|
|
1742
|
+
}
|
|
1743
|
+
),
|
|
1744
|
+
/* @__PURE__ */ jsxs("div", { className: "colorPickerFooter", "data-node-id": "565:1011", children: [
|
|
1745
|
+
/* @__PURE__ */ jsx("div", { className: "colorPickerValueZone", "data-node-id": "565:1012", children: mode === "hex" ? /* @__PURE__ */ jsx(
|
|
1746
|
+
ValueInput,
|
|
1747
|
+
{
|
|
1748
|
+
value: hex.slice(1),
|
|
1749
|
+
prefix: "#",
|
|
1750
|
+
onCommit: (val) => {
|
|
1751
|
+
const d2 = normalizeHexDigits(val);
|
|
1752
|
+
if (isValidSixHex$2(d2)) onChange(`#${d2.toUpperCase()}`);
|
|
1753
|
+
},
|
|
1754
|
+
sanitize: normalizeHexDigits,
|
|
1755
|
+
validate: isValidSixHex$2,
|
|
1756
|
+
maxLength: 6,
|
|
1757
|
+
inputMode: "text",
|
|
1758
|
+
ariaLabel: `Edit hex color, ${hex}`,
|
|
1759
|
+
className: "colorPickerHex",
|
|
1760
|
+
onPaste: (pasted) => {
|
|
1761
|
+
const parsed = parseCssColorToHex(pasted);
|
|
1762
|
+
if (parsed) {
|
|
1763
|
+
onChange(parsed);
|
|
1764
|
+
return "";
|
|
1765
|
+
}
|
|
1766
|
+
return normalizeHexDigits(pasted);
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
) : mode === "hsl" ? /* @__PURE__ */ jsxs("div", { className: "colorPickerTriplet", "aria-label": "HSL values", children: [
|
|
1770
|
+
/* @__PURE__ */ jsx(
|
|
1771
|
+
ValueInput,
|
|
1772
|
+
{
|
|
1773
|
+
value: String(hslUiH),
|
|
1774
|
+
onCommit: (val) => {
|
|
1775
|
+
const n2 = Number.parseInt(val, 10);
|
|
1776
|
+
if (!Number.isFinite(n2)) return;
|
|
1777
|
+
const next = clampHsl01({ ...hslFromHex, h: clampHueDeg(n2) });
|
|
1778
|
+
onChange(hslToHex(next.h, next.s, next.l));
|
|
1779
|
+
},
|
|
1780
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1781
|
+
maxLength: 3,
|
|
1782
|
+
inputMode: "numeric",
|
|
1783
|
+
ariaLabel: "Hue",
|
|
1784
|
+
className: "colorPickerTripletBtn",
|
|
1785
|
+
onPaste: handleColorPaste
|
|
1786
|
+
}
|
|
1787
|
+
),
|
|
1788
|
+
/* @__PURE__ */ jsx(
|
|
1789
|
+
ValueInput,
|
|
1790
|
+
{
|
|
1791
|
+
value: String(hslUiS),
|
|
1792
|
+
onCommit: (val) => {
|
|
1793
|
+
const n2 = Number.parseInt(val, 10);
|
|
1794
|
+
if (!Number.isFinite(n2)) return;
|
|
1795
|
+
const next = clampHsl01({ ...hslFromHex, s: clamp01(n2 / 100) });
|
|
1796
|
+
onChange(hslToHex(next.h, next.s, next.l));
|
|
1797
|
+
},
|
|
1798
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1799
|
+
maxLength: 3,
|
|
1800
|
+
inputMode: "numeric",
|
|
1801
|
+
ariaLabel: "Saturation",
|
|
1802
|
+
className: "colorPickerTripletBtn",
|
|
1803
|
+
onPaste: handleColorPaste
|
|
1804
|
+
}
|
|
1805
|
+
),
|
|
1806
|
+
/* @__PURE__ */ jsx(
|
|
1807
|
+
ValueInput,
|
|
1808
|
+
{
|
|
1809
|
+
value: String(hslUiL),
|
|
1810
|
+
onCommit: (val) => {
|
|
1811
|
+
const n2 = Number.parseInt(val, 10);
|
|
1812
|
+
if (!Number.isFinite(n2)) return;
|
|
1813
|
+
const next = clampHsl01({ ...hslFromHex, l: clamp01(n2 / 100) });
|
|
1814
|
+
onChange(hslToHex(next.h, next.s, next.l));
|
|
1815
|
+
},
|
|
1816
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1817
|
+
maxLength: 3,
|
|
1818
|
+
inputMode: "numeric",
|
|
1819
|
+
ariaLabel: "Lightness",
|
|
1820
|
+
className: "colorPickerTripletBtn",
|
|
1821
|
+
onPaste: handleColorPaste
|
|
1822
|
+
}
|
|
1823
|
+
)
|
|
1824
|
+
] }) : mode === "hsb" ? /* @__PURE__ */ jsxs("div", { className: "colorPickerTriplet", "aria-label": "HSB values", children: [
|
|
1825
|
+
/* @__PURE__ */ jsx(
|
|
1826
|
+
ValueInput,
|
|
1827
|
+
{
|
|
1828
|
+
value: String(hsbUiH),
|
|
1829
|
+
onCommit: (val) => {
|
|
1830
|
+
const n2 = Number.parseInt(val, 10);
|
|
1831
|
+
if (!Number.isFinite(n2)) return;
|
|
1832
|
+
const next = clampHsv01({ ...draft, h: clampHueDeg(n2) });
|
|
1833
|
+
onChange(hsvToHex(next.h, next.s, next.v));
|
|
1834
|
+
},
|
|
1835
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1836
|
+
maxLength: 3,
|
|
1837
|
+
inputMode: "numeric",
|
|
1838
|
+
ariaLabel: "Hue",
|
|
1839
|
+
className: "colorPickerTripletBtn",
|
|
1840
|
+
onPaste: handleColorPaste
|
|
1841
|
+
}
|
|
1842
|
+
),
|
|
1843
|
+
/* @__PURE__ */ jsx(
|
|
1844
|
+
ValueInput,
|
|
1845
|
+
{
|
|
1846
|
+
value: String(hsbUiS),
|
|
1847
|
+
onCommit: (val) => {
|
|
1848
|
+
const n2 = Number.parseInt(val, 10);
|
|
1849
|
+
if (!Number.isFinite(n2)) return;
|
|
1850
|
+
const next = clampHsv01({ ...draft, s: clamp01(n2 / 100) });
|
|
1851
|
+
onChange(hsvToHex(next.h, next.s, next.v));
|
|
1852
|
+
},
|
|
1853
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1854
|
+
maxLength: 3,
|
|
1855
|
+
inputMode: "numeric",
|
|
1856
|
+
ariaLabel: "Saturation",
|
|
1857
|
+
className: "colorPickerTripletBtn",
|
|
1858
|
+
onPaste: handleColorPaste
|
|
1859
|
+
}
|
|
1860
|
+
),
|
|
1861
|
+
/* @__PURE__ */ jsx(
|
|
1862
|
+
ValueInput,
|
|
1863
|
+
{
|
|
1864
|
+
value: String(hsbUiB),
|
|
1865
|
+
onCommit: (val) => {
|
|
1866
|
+
const n2 = Number.parseInt(val, 10);
|
|
1867
|
+
if (!Number.isFinite(n2)) return;
|
|
1868
|
+
const next = clampHsv01({ ...draft, v: clamp01(n2 / 100) });
|
|
1869
|
+
onChange(hsvToHex(next.h, next.s, next.v));
|
|
1870
|
+
},
|
|
1871
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1872
|
+
maxLength: 3,
|
|
1873
|
+
inputMode: "numeric",
|
|
1874
|
+
ariaLabel: "Brightness",
|
|
1875
|
+
className: "colorPickerTripletBtn",
|
|
1876
|
+
onPaste: handleColorPaste
|
|
1877
|
+
}
|
|
1878
|
+
)
|
|
1879
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "colorPickerTriplet", "aria-label": "RGB values", children: [
|
|
1880
|
+
/* @__PURE__ */ jsx(
|
|
1881
|
+
ValueInput,
|
|
1882
|
+
{
|
|
1883
|
+
value: String(clampInt(rgbFromHex.r, 0, 255)),
|
|
1884
|
+
onCommit: (val) => {
|
|
1885
|
+
const n2 = Number.parseInt(val, 10);
|
|
1886
|
+
if (!Number.isFinite(n2)) return;
|
|
1887
|
+
onChange(rgbToHex(clampInt(n2, 0, 255), rgbFromHex.g, rgbFromHex.b));
|
|
1888
|
+
},
|
|
1889
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1890
|
+
maxLength: 3,
|
|
1891
|
+
inputMode: "numeric",
|
|
1892
|
+
ariaLabel: "Red",
|
|
1893
|
+
className: "colorPickerTripletBtn",
|
|
1894
|
+
onPaste: handleColorPaste
|
|
1895
|
+
}
|
|
1896
|
+
),
|
|
1897
|
+
/* @__PURE__ */ jsx(
|
|
1898
|
+
ValueInput,
|
|
1899
|
+
{
|
|
1900
|
+
value: String(clampInt(rgbFromHex.g, 0, 255)),
|
|
1901
|
+
onCommit: (val) => {
|
|
1902
|
+
const n2 = Number.parseInt(val, 10);
|
|
1903
|
+
if (!Number.isFinite(n2)) return;
|
|
1904
|
+
onChange(rgbToHex(rgbFromHex.r, clampInt(n2, 0, 255), rgbFromHex.b));
|
|
1905
|
+
},
|
|
1906
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1907
|
+
maxLength: 3,
|
|
1908
|
+
inputMode: "numeric",
|
|
1909
|
+
ariaLabel: "Green",
|
|
1910
|
+
className: "colorPickerTripletBtn",
|
|
1911
|
+
onPaste: handleColorPaste
|
|
1912
|
+
}
|
|
1913
|
+
),
|
|
1914
|
+
/* @__PURE__ */ jsx(
|
|
1915
|
+
ValueInput,
|
|
1916
|
+
{
|
|
1917
|
+
value: String(clampInt(rgbFromHex.b, 0, 255)),
|
|
1918
|
+
onCommit: (val) => {
|
|
1919
|
+
const n2 = Number.parseInt(val, 10);
|
|
1920
|
+
if (!Number.isFinite(n2)) return;
|
|
1921
|
+
onChange(rgbToHex(rgbFromHex.r, rgbFromHex.g, clampInt(n2, 0, 255)));
|
|
1922
|
+
},
|
|
1923
|
+
sanitize: (v2) => v2.replace(/[^\d]/g, "").slice(0, 3),
|
|
1924
|
+
maxLength: 3,
|
|
1925
|
+
inputMode: "numeric",
|
|
1926
|
+
ariaLabel: "Blue",
|
|
1927
|
+
className: "colorPickerTripletBtn",
|
|
1928
|
+
onPaste: handleColorPaste
|
|
1929
|
+
}
|
|
1930
|
+
)
|
|
1931
|
+
] }) }),
|
|
1932
|
+
/* @__PURE__ */ jsxs("div", { className: "colorPickerActions", "data-node-id": "565:1014", children: [
|
|
1933
|
+
/* @__PURE__ */ jsx(
|
|
1934
|
+
"button",
|
|
1935
|
+
{
|
|
1936
|
+
type: "button",
|
|
1937
|
+
className: "colorPickerModeBtn",
|
|
1938
|
+
onClick: onToggleMode,
|
|
1939
|
+
"aria-label": "Switch color value mode",
|
|
1940
|
+
title: "Switch value mode",
|
|
1941
|
+
"data-node-id": "565:1015",
|
|
1942
|
+
children: mode.toUpperCase()
|
|
1943
|
+
}
|
|
1944
|
+
),
|
|
1945
|
+
/* @__PURE__ */ jsx(
|
|
1946
|
+
"button",
|
|
1947
|
+
{
|
|
1948
|
+
type: "button",
|
|
1949
|
+
className: "colorPickerIconBtn",
|
|
1950
|
+
onClick: onEyeDropper,
|
|
1951
|
+
"aria-label": "Pick color from screen",
|
|
1952
|
+
title: "Eyedropper",
|
|
1953
|
+
"data-node-id": "565:1020",
|
|
1954
|
+
children: /* @__PURE__ */ jsx(EyeDropperIcon, {})
|
|
1955
|
+
}
|
|
1956
|
+
)
|
|
1957
|
+
] })
|
|
1958
|
+
] }),
|
|
1959
|
+
/* @__PURE__ */ jsx("div", { className: "colorPickerLiveSr", "aria-live": "polite", "aria-atomic": "true", children: dragging === null ? `Color ${previewHex}` : "" })
|
|
1960
|
+
] });
|
|
1961
|
+
}
|
|
1962
|
+
function SwatchPopover({
|
|
1963
|
+
title,
|
|
1964
|
+
renderTrigger,
|
|
1965
|
+
children,
|
|
1966
|
+
modal = true,
|
|
1967
|
+
side = "bottom",
|
|
1968
|
+
align = "end",
|
|
1969
|
+
sideOffset = 6,
|
|
1970
|
+
zIndex
|
|
1971
|
+
}) {
|
|
1972
|
+
return /* @__PURE__ */ jsxs(Popover.Root, { modal, children: [
|
|
1973
|
+
/* @__PURE__ */ jsx(Popover.Trigger, { render: renderTrigger }),
|
|
1974
|
+
/* @__PURE__ */ jsx(Popover.Portal, { className: "swatchPopoverPortal", style: zIndex != null ? { zIndex } : void 0, children: /* @__PURE__ */ jsx(
|
|
1975
|
+
Popover.Positioner,
|
|
1976
|
+
{
|
|
1977
|
+
className: "swatchPopoverPositioner",
|
|
1978
|
+
positionMethod: "fixed",
|
|
1979
|
+
side,
|
|
1980
|
+
align,
|
|
1981
|
+
sideOffset,
|
|
1982
|
+
collisionAvoidance: { side: "flip", align: "shift", fallbackAxisSide: "none" },
|
|
1983
|
+
children: /* @__PURE__ */ jsxs(
|
|
1984
|
+
Popover.Popup,
|
|
1985
|
+
{
|
|
1986
|
+
className: "swatchPopoverPopup",
|
|
1987
|
+
initialFocus: (openType) => openType === "keyboard",
|
|
1988
|
+
children: [
|
|
1989
|
+
title && /* @__PURE__ */ jsx(Popover.Title, { className: "swatchPopoverTitle", children: title }),
|
|
1990
|
+
/* @__PURE__ */ jsx(Popover.Close, { type: "button", className: "swatchPopoverCloseSrOnly", children: "Close" }),
|
|
1991
|
+
/* @__PURE__ */ jsx("div", { className: "swatchPopoverBody", children })
|
|
1992
|
+
]
|
|
1993
|
+
}
|
|
1994
|
+
)
|
|
1995
|
+
}
|
|
1996
|
+
) })
|
|
1997
|
+
] });
|
|
1998
|
+
}
|
|
1999
|
+
function hexDigits$1(hex) {
|
|
2000
|
+
const n2 = normalizeHex(hex);
|
|
2001
|
+
return n2.slice(1);
|
|
2002
|
+
}
|
|
2003
|
+
function isValidSixHex$1(d2) {
|
|
2004
|
+
return /^[0-9a-fA-F]{6}$/.test(d2);
|
|
2005
|
+
}
|
|
2006
|
+
function sanitizeHex$1(input) {
|
|
2007
|
+
return input.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
2008
|
+
}
|
|
2009
|
+
function ColorRow({ label = "Color", value, onChange, disabled: disabledProp }) {
|
|
2010
|
+
const categoryDisabled = useCategoryDisabled();
|
|
2011
|
+
const disabled = Boolean(disabledProp || categoryDisabled);
|
|
2012
|
+
const [hovered, setHovered] = useState(false);
|
|
2013
|
+
const hex = normalizeHex(value);
|
|
2014
|
+
const handleCommit = (sanitized) => {
|
|
2015
|
+
if (isValidSixHex$1(sanitized)) {
|
|
2016
|
+
onChange(`#${sanitized.toUpperCase()}`);
|
|
2017
|
+
}
|
|
2018
|
+
};
|
|
2019
|
+
const handlePaste = (pasted) => {
|
|
2020
|
+
return pasted.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
712
2021
|
};
|
|
713
2022
|
return /* @__PURE__ */ jsx(
|
|
714
2023
|
"div",
|
|
715
2024
|
{
|
|
716
2025
|
className: "colorRowWrap",
|
|
717
|
-
|
|
2026
|
+
"data-disabled": disabled ? "true" : "false",
|
|
2027
|
+
onPointerEnter: () => !disabled && setHovered(true),
|
|
718
2028
|
onPointerLeave: () => setHovered(false),
|
|
719
|
-
children: /* @__PURE__ */ jsxs("div", { className: "colorCard", "data-active":
|
|
2029
|
+
children: /* @__PURE__ */ jsxs("div", { className: "colorCard", "data-active": !disabled && hovered ? "true" : "false", children: [
|
|
720
2030
|
/* @__PURE__ */ jsx("span", { className: "colorLabel", children: label }),
|
|
721
2031
|
/* @__PURE__ */ jsxs("div", { className: "colorValueZone", children: [
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
/* @__PURE__ */ jsx(
|
|
725
|
-
"input",
|
|
726
|
-
{
|
|
727
|
-
ref: inputRef,
|
|
728
|
-
className: "colorHexInput",
|
|
729
|
-
value: draft,
|
|
730
|
-
onChange: onHexChange,
|
|
731
|
-
onPaste: onHexPaste,
|
|
732
|
-
onBlur: commit,
|
|
733
|
-
onKeyDown: onHexKeyDown,
|
|
734
|
-
onClick: (e) => e.stopPropagation(),
|
|
735
|
-
maxLength: 6,
|
|
736
|
-
inputMode: "text",
|
|
737
|
-
autoComplete: "off",
|
|
738
|
-
spellCheck: false,
|
|
739
|
-
"aria-label": "Hex color without hash"
|
|
740
|
-
}
|
|
741
|
-
)
|
|
742
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
743
|
-
"span",
|
|
2032
|
+
/* @__PURE__ */ jsx(
|
|
2033
|
+
ValueInput,
|
|
744
2034
|
{
|
|
2035
|
+
value: hexDigits$1(hex),
|
|
2036
|
+
prefix: "#",
|
|
2037
|
+
onCommit: handleCommit,
|
|
2038
|
+
sanitize: sanitizeHex$1,
|
|
2039
|
+
validate: isValidSixHex$1,
|
|
2040
|
+
maxLength: 6,
|
|
2041
|
+
inputMode: "text",
|
|
2042
|
+
ariaLabel: `Edit hex color, ${hex}`,
|
|
2043
|
+
disabled,
|
|
2044
|
+
isActive: !disabled && hovered,
|
|
745
2045
|
className: "colorRowValue",
|
|
746
|
-
|
|
747
|
-
role: "button",
|
|
748
|
-
tabIndex: 0,
|
|
749
|
-
"aria-label": `Edit hex color, ${hex}`,
|
|
750
|
-
onClick: startEdit,
|
|
751
|
-
onKeyDown: (e) => {
|
|
752
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
753
|
-
e.preventDefault();
|
|
754
|
-
setDraft(hexDigits$1(value));
|
|
755
|
-
setEditing(true);
|
|
756
|
-
}
|
|
757
|
-
},
|
|
758
|
-
children: [
|
|
759
|
-
/* @__PURE__ */ jsx("span", { className: "colorHexHash", children: "#" }),
|
|
760
|
-
/* @__PURE__ */ jsx("span", { className: "colorHexDigits", children: hexDigits$1(hex) })
|
|
761
|
-
]
|
|
2046
|
+
onPaste: handlePaste
|
|
762
2047
|
}
|
|
763
2048
|
),
|
|
764
|
-
/* @__PURE__ */
|
|
2049
|
+
/* @__PURE__ */ jsx(
|
|
765
2050
|
SwatchPopover,
|
|
766
2051
|
{
|
|
767
|
-
title: label,
|
|
768
2052
|
renderTrigger: (props) => /* @__PURE__ */ jsx(
|
|
769
2053
|
"button",
|
|
770
2054
|
{
|
|
771
2055
|
type: "button",
|
|
772
2056
|
...props,
|
|
2057
|
+
disabled,
|
|
773
2058
|
className: ["colorSwatchBtn", props.className].filter(Boolean).join(" "),
|
|
774
|
-
style: { ...props.style,
|
|
2059
|
+
style: { ...props.style, ["--swatch-color"]: hex },
|
|
775
2060
|
"aria-label": `Open ${label} picker`
|
|
776
2061
|
}
|
|
777
2062
|
),
|
|
778
|
-
children:
|
|
779
|
-
/* @__PURE__ */ jsx("p", { children: "Custom color controls will live here. For now, use the system picker below." }),
|
|
780
|
-
/* @__PURE__ */ jsx(
|
|
781
|
-
"input",
|
|
782
|
-
{
|
|
783
|
-
type: "color",
|
|
784
|
-
className: "swatchPopoverNativeColor",
|
|
785
|
-
value: hex,
|
|
786
|
-
onChange: onPickerChange,
|
|
787
|
-
"aria-label": "Native color picker"
|
|
788
|
-
}
|
|
789
|
-
)
|
|
790
|
-
]
|
|
2063
|
+
children: /* @__PURE__ */ jsx(ColorPicker, { value: hex, onChange })
|
|
791
2064
|
}
|
|
792
2065
|
)
|
|
793
2066
|
] })
|
|
@@ -795,21 +2068,28 @@ function ColorRow({ label = "Color", value, onChange }) {
|
|
|
795
2068
|
}
|
|
796
2069
|
);
|
|
797
2070
|
}
|
|
798
|
-
function ToggleRow({ label, checked, onChange }) {
|
|
799
|
-
const
|
|
2071
|
+
function ToggleRow({ label, checked, onChange, disabled: disabledProp }) {
|
|
2072
|
+
const categoryDisabled = useCategoryDisabled();
|
|
2073
|
+
const disabled = Boolean(disabledProp || categoryDisabled);
|
|
2074
|
+
const toggle = () => {
|
|
2075
|
+
if (disabled) return;
|
|
2076
|
+
onChange(!checked);
|
|
2077
|
+
};
|
|
800
2078
|
const onKeyDown = (e) => {
|
|
2079
|
+
if (disabled) return;
|
|
801
2080
|
if (e.key === " " || e.key === "Enter") {
|
|
802
2081
|
e.preventDefault();
|
|
803
2082
|
toggle();
|
|
804
2083
|
}
|
|
805
2084
|
};
|
|
806
|
-
return /* @__PURE__ */ jsx("div", { className: "toggleRowWrap", children: /* @__PURE__ */ jsxs(
|
|
2085
|
+
return /* @__PURE__ */ jsx("div", { className: "toggleRowWrap", "data-disabled": disabled ? "true" : "false", children: /* @__PURE__ */ jsxs(
|
|
807
2086
|
"div",
|
|
808
2087
|
{
|
|
809
2088
|
role: "switch",
|
|
810
|
-
tabIndex: 0,
|
|
2089
|
+
tabIndex: disabled ? -1 : 0,
|
|
811
2090
|
"aria-checked": checked,
|
|
812
2091
|
"aria-label": label,
|
|
2092
|
+
"aria-disabled": disabled,
|
|
813
2093
|
className: "toggleCard",
|
|
814
2094
|
"data-on": checked ? "true" : "false",
|
|
815
2095
|
onClick: toggle,
|
|
@@ -821,66 +2101,20 @@ function ToggleRow({ label, checked, onChange }) {
|
|
|
821
2101
|
}
|
|
822
2102
|
) });
|
|
823
2103
|
}
|
|
824
|
-
function normalizeHex(raw) {
|
|
825
|
-
const s = raw.trim();
|
|
826
|
-
const m = s.match(/^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/);
|
|
827
|
-
if (!m) return "#808080";
|
|
828
|
-
let h = m[1];
|
|
829
|
-
if (h.length === 3) {
|
|
830
|
-
h = h[0] + h[0] + h[1] + h[1] + h[2] + h[2];
|
|
831
|
-
}
|
|
832
|
-
return `#${h.toUpperCase()}`;
|
|
833
|
-
}
|
|
834
|
-
function hslToHex(h, s, l) {
|
|
835
|
-
const hue = (h % 360 + 360) % 360;
|
|
836
|
-
const sat = Math.max(0, Math.min(1, s));
|
|
837
|
-
const lit = Math.max(0, Math.min(1, l));
|
|
838
|
-
const c = (1 - Math.abs(2 * lit - 1)) * sat;
|
|
839
|
-
const x = c * (1 - Math.abs(hue / 60 % 2 - 1));
|
|
840
|
-
const m = lit - c / 2;
|
|
841
|
-
let r = 0, g = 0, b = 0;
|
|
842
|
-
if (hue < 60) {
|
|
843
|
-
r = c;
|
|
844
|
-
g = x;
|
|
845
|
-
b = 0;
|
|
846
|
-
} else if (hue < 120) {
|
|
847
|
-
r = x;
|
|
848
|
-
g = c;
|
|
849
|
-
b = 0;
|
|
850
|
-
} else if (hue < 180) {
|
|
851
|
-
r = 0;
|
|
852
|
-
g = c;
|
|
853
|
-
b = x;
|
|
854
|
-
} else if (hue < 240) {
|
|
855
|
-
r = 0;
|
|
856
|
-
g = x;
|
|
857
|
-
b = c;
|
|
858
|
-
} else if (hue < 300) {
|
|
859
|
-
r = x;
|
|
860
|
-
g = 0;
|
|
861
|
-
b = c;
|
|
862
|
-
} else {
|
|
863
|
-
r = c;
|
|
864
|
-
g = 0;
|
|
865
|
-
b = x;
|
|
866
|
-
}
|
|
867
|
-
const toHex = (v) => Math.round((v + m) * 255).toString(16).padStart(2, "0");
|
|
868
|
-
return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
|
|
869
|
-
}
|
|
870
2104
|
function generateAestheticGradient(stopCount) {
|
|
871
2105
|
const baseHue = Math.random() * 360;
|
|
872
2106
|
const hueShift = 25 + Math.random() * 35;
|
|
873
2107
|
const hueDirection = Math.random() > 0.5 ? 1 : -1;
|
|
874
2108
|
const stops = [];
|
|
875
2109
|
for (let i = 0; i < stopCount; i++) {
|
|
876
|
-
const
|
|
877
|
-
const hue = baseHue + hueDirection * hueShift *
|
|
2110
|
+
const t2 = i / (stopCount - 1);
|
|
2111
|
+
const hue = baseHue + hueDirection * hueShift * t2;
|
|
878
2112
|
const satBase = 0.35 + Math.random() * 0.15;
|
|
879
2113
|
const satPeak = 0.65 + Math.random() * 0.25;
|
|
880
|
-
const saturation = satBase + (satPeak - satBase) * Math.sin(
|
|
2114
|
+
const saturation = satBase + (satPeak - satBase) * Math.sin(t2 * Math.PI * 0.8);
|
|
881
2115
|
const lightStart = 0.75 + Math.random() * 0.1;
|
|
882
2116
|
const lightEnd = 0.08 + Math.random() * 0.07;
|
|
883
|
-
const eased =
|
|
2117
|
+
const eased = t2 * t2 * (3 - 2 * t2);
|
|
884
2118
|
const lightness = lightStart + (lightEnd - lightStart) * eased;
|
|
885
2119
|
stops.push({ color: hslToHex(hue, saturation, lightness) });
|
|
886
2120
|
}
|
|
@@ -889,8 +2123,8 @@ function generateAestheticGradient(stopCount) {
|
|
|
889
2123
|
function hexDigits(hex) {
|
|
890
2124
|
return normalizeHex(hex).slice(1);
|
|
891
2125
|
}
|
|
892
|
-
function isValidSixHex(
|
|
893
|
-
return /^[0-9a-fA-F]{6}$/.test(
|
|
2126
|
+
function isValidSixHex(d2) {
|
|
2127
|
+
return /^[0-9a-fA-F]{6}$/.test(d2);
|
|
894
2128
|
}
|
|
895
2129
|
function stopsToGradient(stops, angle = 90) {
|
|
896
2130
|
if (stops.length === 0) return "linear-gradient(90deg, #808080, #808080)";
|
|
@@ -926,99 +2160,56 @@ const DEFAULT_GRADIENT_STOPS = [
|
|
|
926
2160
|
{ color: "#42C0B0" },
|
|
927
2161
|
{ color: "#BAC9C7" }
|
|
928
2162
|
];
|
|
2163
|
+
function sanitizeHex(input) {
|
|
2164
|
+
return input.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
2165
|
+
}
|
|
929
2166
|
function StopRow({ index, stop, canDelete, onColorChange, onDelete }) {
|
|
930
|
-
const [editing, setEditing] = useState(false);
|
|
931
|
-
const [draft, setDraft] = useState("");
|
|
932
|
-
const inputRef = useRef(null);
|
|
933
2167
|
const hex = normalizeHex(stop.color);
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
if (
|
|
937
|
-
|
|
938
|
-
(_b = inputRef.current) == null ? void 0 : _b.select();
|
|
939
|
-
}, [editing]);
|
|
940
|
-
const startEdit = (e) => {
|
|
941
|
-
e.stopPropagation();
|
|
942
|
-
setDraft(hexDigits(stop.color));
|
|
943
|
-
setEditing(true);
|
|
944
|
-
};
|
|
945
|
-
const commit = () => {
|
|
946
|
-
const d = draft.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
947
|
-
if (isValidSixHex(d)) {
|
|
948
|
-
onColorChange(`#${d.toUpperCase()}`);
|
|
949
|
-
}
|
|
950
|
-
setEditing(false);
|
|
951
|
-
};
|
|
952
|
-
const onHexKeyDown = (e) => {
|
|
953
|
-
if (e.key === "Enter") {
|
|
954
|
-
e.preventDefault();
|
|
955
|
-
commit();
|
|
2168
|
+
const handleCommit = (val) => {
|
|
2169
|
+
const d2 = sanitizeHex(val);
|
|
2170
|
+
if (isValidSixHex(d2)) {
|
|
2171
|
+
onColorChange(`#${d2.toUpperCase()}`);
|
|
956
2172
|
}
|
|
957
|
-
if (e.key === "Escape") {
|
|
958
|
-
setEditing(false);
|
|
959
|
-
}
|
|
960
|
-
e.stopPropagation();
|
|
961
2173
|
};
|
|
962
|
-
const
|
|
963
|
-
|
|
964
|
-
setDraft(next);
|
|
965
|
-
};
|
|
966
|
-
const onHexPaste = (e) => {
|
|
967
|
-
e.preventDefault();
|
|
968
|
-
const pasted = e.clipboardData.getData("text");
|
|
969
|
-
const cleaned = pasted.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
970
|
-
setDraft(cleaned);
|
|
2174
|
+
const handlePaste = (pasted) => {
|
|
2175
|
+
return sanitizeHex(pasted);
|
|
971
2176
|
};
|
|
972
2177
|
return /* @__PURE__ */ jsxs("div", { className: "gradientPickerStop", children: [
|
|
973
2178
|
/* @__PURE__ */ jsxs("div", { className: "gradientPickerStopColorHex", children: [
|
|
974
2179
|
/* @__PURE__ */ jsx(
|
|
975
|
-
|
|
2180
|
+
SwatchPopover,
|
|
976
2181
|
{
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
2182
|
+
modal: false,
|
|
2183
|
+
side: "right",
|
|
2184
|
+
align: "start",
|
|
2185
|
+
sideOffset: 8,
|
|
2186
|
+
zIndex: 200001,
|
|
2187
|
+
renderTrigger: (props) => /* @__PURE__ */ jsx(
|
|
2188
|
+
"button",
|
|
2189
|
+
{
|
|
2190
|
+
type: "button",
|
|
2191
|
+
...props,
|
|
2192
|
+
className: ["gradientPickerStopSwatch", props.className].filter(Boolean).join(" "),
|
|
2193
|
+
style: { ...props.style, backgroundColor: hex },
|
|
2194
|
+
"aria-label": `Edit color for stop ${index + 1}`
|
|
2195
|
+
}
|
|
2196
|
+
),
|
|
2197
|
+
children: /* @__PURE__ */ jsx(ColorPicker, { value: hex, onChange: onColorChange })
|
|
982
2198
|
}
|
|
983
2199
|
),
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
/* @__PURE__ */ jsx(
|
|
987
|
-
"input",
|
|
988
|
-
{
|
|
989
|
-
ref: inputRef,
|
|
990
|
-
className: "gradientPickerStopHexInput",
|
|
991
|
-
value: draft,
|
|
992
|
-
onChange: onHexChange,
|
|
993
|
-
onPaste: onHexPaste,
|
|
994
|
-
onBlur: commit,
|
|
995
|
-
onKeyDown: onHexKeyDown,
|
|
996
|
-
onClick: (e) => e.stopPropagation(),
|
|
997
|
-
maxLength: 6,
|
|
998
|
-
inputMode: "text",
|
|
999
|
-
autoComplete: "off",
|
|
1000
|
-
spellCheck: false,
|
|
1001
|
-
"aria-label": "Hex color without hash"
|
|
1002
|
-
}
|
|
1003
|
-
)
|
|
1004
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
1005
|
-
"span",
|
|
2200
|
+
/* @__PURE__ */ jsx(
|
|
2201
|
+
ValueInput,
|
|
1006
2202
|
{
|
|
2203
|
+
value: hexDigits(hex),
|
|
2204
|
+
prefix: "#",
|
|
2205
|
+
onCommit: handleCommit,
|
|
2206
|
+
sanitize: sanitizeHex,
|
|
2207
|
+
validate: isValidSixHex,
|
|
2208
|
+
maxLength: 6,
|
|
2209
|
+
inputMode: "text",
|
|
2210
|
+
ariaLabel: "Hex color without hash",
|
|
1007
2211
|
className: "gradientPickerStopHex",
|
|
1008
|
-
|
|
1009
|
-
tabIndex: 0,
|
|
1010
|
-
onClick: startEdit,
|
|
1011
|
-
onKeyDown: (e) => {
|
|
1012
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
1013
|
-
e.preventDefault();
|
|
1014
|
-
setDraft(hexDigits(stop.color));
|
|
1015
|
-
setEditing(true);
|
|
1016
|
-
}
|
|
1017
|
-
},
|
|
1018
|
-
children: [
|
|
1019
|
-
/* @__PURE__ */ jsx("span", { className: "gradientPickerStopHexHash", children: "#" }),
|
|
1020
|
-
/* @__PURE__ */ jsx("span", { className: "gradientPickerStopHexDigits", children: hexDigits(hex) })
|
|
1021
|
-
]
|
|
2212
|
+
onPaste: handlePaste
|
|
1022
2213
|
}
|
|
1023
2214
|
)
|
|
1024
2215
|
] }),
|
|
@@ -1026,16 +2217,16 @@ function StopRow({ index, stop, canDelete, onColorChange, onDelete }) {
|
|
|
1026
2217
|
"button",
|
|
1027
2218
|
{
|
|
1028
2219
|
type: "button",
|
|
1029
|
-
className: "gradientPickerStopDelete",
|
|
2220
|
+
className: "gradientPickerIconBtn gradientPickerStopDelete",
|
|
1030
2221
|
onClick: onDelete,
|
|
1031
2222
|
disabled: !canDelete,
|
|
1032
2223
|
"aria-label": `Remove stop ${index + 1}`,
|
|
1033
|
-
children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", "aria-hidden": "true", children: /* @__PURE__ */ jsx("
|
|
2224
|
+
children: /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 18 18", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M14.75,9.75H3.25c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75H14.75c.414,0,.75,.336,.75,.75s-.336,.75-.75,.75Z", fill: "currentColor" }) })
|
|
1034
2225
|
}
|
|
1035
2226
|
)
|
|
1036
2227
|
] });
|
|
1037
2228
|
}
|
|
1038
|
-
function GradientPicker({ stops, onChange }) {
|
|
2229
|
+
function GradientPicker({ stops, onChange, angle = 90 }) {
|
|
1039
2230
|
const handleInvert = () => {
|
|
1040
2231
|
onChange([...stops].reverse());
|
|
1041
2232
|
};
|
|
@@ -1054,13 +2245,21 @@ function GradientPicker({ stops, onChange }) {
|
|
|
1054
2245
|
};
|
|
1055
2246
|
const handleDeleteStop = (index) => {
|
|
1056
2247
|
if (stops.length <= 2) return;
|
|
1057
|
-
onChange(stops.filter((
|
|
2248
|
+
onChange(stops.filter((_2, i) => i !== index));
|
|
1058
2249
|
};
|
|
1059
2250
|
const handleColorChange = (index, color) => {
|
|
1060
2251
|
const newStops = stops.map((s, i) => i === index ? { ...s, color } : s);
|
|
1061
2252
|
onChange(newStops);
|
|
1062
2253
|
};
|
|
1063
2254
|
return /* @__PURE__ */ jsxs("div", { className: "gradientPicker", children: [
|
|
2255
|
+
/* @__PURE__ */ jsx("div", { className: "gradientPickerPreviewWrap", children: /* @__PURE__ */ jsx(
|
|
2256
|
+
"div",
|
|
2257
|
+
{
|
|
2258
|
+
className: "gradientPickerPreview",
|
|
2259
|
+
"aria-hidden": true,
|
|
2260
|
+
style: { background: stopsToGradient(stops, angle) }
|
|
2261
|
+
}
|
|
2262
|
+
) }),
|
|
1064
2263
|
/* @__PURE__ */ jsxs("div", { className: "gradientPickerHeader", children: [
|
|
1065
2264
|
/* @__PURE__ */ jsxs("div", { className: "gradientPickerHeaderIconsLeft", children: [
|
|
1066
2265
|
/* @__PURE__ */ jsx(
|
|
@@ -1071,7 +2270,24 @@ function GradientPicker({ stops, onChange }) {
|
|
|
1071
2270
|
onClick: handleShuffle,
|
|
1072
2271
|
"aria-label": "Randomize gradient",
|
|
1073
2272
|
title: "Randomize gradient",
|
|
1074
|
-
children: /* @__PURE__ */
|
|
2273
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 18 18", "aria-hidden": "true", focusable: "false", children: [
|
|
2274
|
+
/* @__PURE__ */ jsx(
|
|
2275
|
+
"path",
|
|
2276
|
+
{
|
|
2277
|
+
d: "M16.525 6.05302L13.245 4.75602L11.947 1.47502C11.72 0.903021 10.779 0.903021 10.552 1.47502L9.25399 4.75602L5.97399 6.05302C5.68799 6.16602 5.49899 6.44302 5.49899 6.75002C5.49899 7.05702 5.68699 7.33402 5.97399 7.44702L9.25399 8.74402L10.552 12.025C10.665 12.311 10.942 12.499 11.249 12.499C11.556 12.499 11.833 12.311 11.946 12.025L13.244 8.74402L16.524 7.44702C16.81 7.33402 16.999 7.05702 16.999 6.75002C16.999 6.44302 16.812 6.16602 16.525 6.05302Z",
|
|
2278
|
+
fill: "currentColor"
|
|
2279
|
+
}
|
|
2280
|
+
),
|
|
2281
|
+
/* @__PURE__ */ jsx(
|
|
2282
|
+
"path",
|
|
2283
|
+
{
|
|
2284
|
+
fillRule: "evenodd",
|
|
2285
|
+
clipRule: "evenodd",
|
|
2286
|
+
d: "M4.75 9.5C5.09415 9.5 5.39414 9.73422 5.47761 10.0681L5.96847 12.0315L7.9319 12.5224C8.26578 12.6059 8.5 12.9058 8.5 13.25C8.5 13.5942 8.26578 13.8941 7.9319 13.9776L5.96847 14.4685L5.47761 16.4319C5.39414 16.7658 5.09415 17 4.75 17C4.40585 17 4.10586 16.7658 4.02239 16.4319L3.53153 14.4685L1.5681 13.9776C1.23422 13.8941 1 13.5942 1 13.25C1 12.9058 1.23422 12.6059 1.5681 12.5224L3.53153 12.0315L4.02239 10.0681C4.10586 9.73422 4.40585 9.5 4.75 9.5Z",
|
|
2287
|
+
fill: "currentColor"
|
|
2288
|
+
}
|
|
2289
|
+
)
|
|
2290
|
+
] })
|
|
1075
2291
|
}
|
|
1076
2292
|
),
|
|
1077
2293
|
/* @__PURE__ */ jsx(
|
|
@@ -1082,7 +2298,22 @@ function GradientPicker({ stops, onChange }) {
|
|
|
1082
2298
|
onClick: handleInvert,
|
|
1083
2299
|
"aria-label": "Invert gradient",
|
|
1084
2300
|
title: "Invert gradient",
|
|
1085
|
-
children: /* @__PURE__ */
|
|
2301
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 18 18", "aria-hidden": "true", focusable: "false", children: [
|
|
2302
|
+
/* @__PURE__ */ jsx(
|
|
2303
|
+
"path",
|
|
2304
|
+
{
|
|
2305
|
+
d: "M4.061,7h6.189c.414,0,.75-.336,.75-.75s-.336-.75-.75-.75H4.061l1.97-1.97c.293-.293,.293-.768,0-1.061s-.768-.293-1.061,0L1.72,5.72c-.293,.293-.293,.768,0,1.061l3.25,3.25c.146,.146,.338,.22,.53,.22s.384-.073,.53-.22c.293-.293,.293-.768,0-1.061l-1.97-1.97Z",
|
|
2306
|
+
fill: "currentColor"
|
|
2307
|
+
}
|
|
2308
|
+
),
|
|
2309
|
+
/* @__PURE__ */ jsx(
|
|
2310
|
+
"path",
|
|
2311
|
+
{
|
|
2312
|
+
d: "M13.03,7.97c-.293-.293-.768-.293-1.061,0s-.293,.768,0,1.061l1.97,1.97H7.75c-.414,0-.75,.336-.75,.75s.336,.75,.75,.75h6.189l-1.97,1.97c-.293,.293-.293,.768,0,1.061,.146,.146,.338,.22,.53,.22s.384-.073,.53-.22l3.25-3.25c.293-.293,.293-.768,0-1.061l-3.25-3.25Z",
|
|
2313
|
+
fill: "currentColor"
|
|
2314
|
+
}
|
|
2315
|
+
)
|
|
2316
|
+
] })
|
|
1086
2317
|
}
|
|
1087
2318
|
)
|
|
1088
2319
|
] }),
|
|
@@ -1094,7 +2325,10 @@ function GradientPicker({ stops, onChange }) {
|
|
|
1094
2325
|
onClick: handleAddStop,
|
|
1095
2326
|
"aria-label": "Add color stop",
|
|
1096
2327
|
title: "Add color stop",
|
|
1097
|
-
children: /* @__PURE__ */
|
|
2328
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 18 18", "aria-hidden": "true", children: [
|
|
2329
|
+
/* @__PURE__ */ jsx("path", { d: "M14.75,9.75H3.25c-.414,0-.75-.336-.75-.75s.336-.75,.75-.75H14.75c.414,0,.75,.336,.75,.75s-.336,.75-.75,.75Z", fill: "currentColor" }),
|
|
2330
|
+
/* @__PURE__ */ jsx("path", { d: "M9,15.5c-.414,0-.75-.336-.75-.75V3.25c0-.414,.336-.75,.75-.75s.75,.336,.75,.75V14.75c0,.414-.336,.75-.75,.75Z", fill: "currentColor" })
|
|
2331
|
+
] })
|
|
1098
2332
|
}
|
|
1099
2333
|
)
|
|
1100
2334
|
] }),
|
|
@@ -1111,9 +2345,17 @@ function GradientPicker({ stops, onChange }) {
|
|
|
1111
2345
|
)) })
|
|
1112
2346
|
] });
|
|
1113
2347
|
}
|
|
1114
|
-
function GradientRow({
|
|
2348
|
+
function GradientRow({
|
|
2349
|
+
label = "Gradient",
|
|
2350
|
+
initialStops,
|
|
2351
|
+
onChange,
|
|
2352
|
+
angle = 90,
|
|
2353
|
+
disabled: disabledProp
|
|
2354
|
+
}) {
|
|
2355
|
+
const categoryDisabled = useCategoryDisabled();
|
|
2356
|
+
const disabled = Boolean(disabledProp || categoryDisabled);
|
|
1115
2357
|
const [hovered, setHovered] = useState(false);
|
|
1116
|
-
const isActive = hovered;
|
|
2358
|
+
const isActive = !disabled && hovered;
|
|
1117
2359
|
const [stops, setStops] = useState(() => initialStops ?? DEFAULT_GRADIENT_STOPS);
|
|
1118
2360
|
const handleStopsChange = (newStops) => {
|
|
1119
2361
|
setStops(newStops);
|
|
@@ -1126,7 +2368,8 @@ function GradientRow({ label = "Gradient", initialStops, onChange, angle = 90 })
|
|
|
1126
2368
|
"div",
|
|
1127
2369
|
{
|
|
1128
2370
|
className: "gradientRowWrap",
|
|
1129
|
-
|
|
2371
|
+
"data-disabled": disabled ? "true" : "false",
|
|
2372
|
+
onPointerEnter: () => !disabled && setHovered(true),
|
|
1130
2373
|
onPointerLeave: () => setHovered(false),
|
|
1131
2374
|
children: /* @__PURE__ */ jsxs("div", { className: "gradientCard", "data-active": isActive ? "true" : "false", children: [
|
|
1132
2375
|
/* @__PURE__ */ jsx("span", { className: "gradientLabel", children: label }),
|
|
@@ -1138,6 +2381,7 @@ function GradientRow({ label = "Gradient", initialStops, onChange, angle = 90 })
|
|
|
1138
2381
|
{
|
|
1139
2382
|
type: "button",
|
|
1140
2383
|
...props,
|
|
2384
|
+
disabled,
|
|
1141
2385
|
className: ["gradientSwatchBtn", props.className].filter(Boolean).join(" "),
|
|
1142
2386
|
style: { ...props.style, background: currentGradient },
|
|
1143
2387
|
"aria-label": `Open ${label} editor`
|
|
@@ -1151,18 +2395,23 @@ function GradientRow({ label = "Gradient", initialStops, onChange, angle = 90 })
|
|
|
1151
2395
|
);
|
|
1152
2396
|
}
|
|
1153
2397
|
export {
|
|
2398
|
+
Category,
|
|
2399
|
+
ColorPicker,
|
|
1154
2400
|
ColorRow,
|
|
1155
2401
|
DEFAULT_GRADIENT_STOPS,
|
|
1156
2402
|
GradientPicker,
|
|
1157
2403
|
GradientRow,
|
|
2404
|
+
Panel,
|
|
1158
2405
|
SliderOverlapDebugProvider,
|
|
1159
2406
|
SliderRow,
|
|
1160
2407
|
SwatchPopover,
|
|
1161
2408
|
ThemeProvider,
|
|
1162
2409
|
ToggleRow,
|
|
2410
|
+
Panel as default,
|
|
1163
2411
|
isTextInputTarget,
|
|
1164
2412
|
parseGradient,
|
|
1165
2413
|
stopsToGradient,
|
|
2414
|
+
useCategoryDisabled,
|
|
1166
2415
|
useSliderOverlapDebugEnabled,
|
|
1167
2416
|
useTheme
|
|
1168
2417
|
};
|