aporia 0.2.7 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Category.d.ts.map +1 -1
- package/dist/components/ColorPicker.d.ts.map +1 -1
- package/dist/components/ColorRow.d.ts.map +1 -1
- package/dist/components/GradientPicker.d.ts.map +1 -1
- package/dist/components/Panel.d.ts +16 -3
- package/dist/components/Panel.d.ts.map +1 -1
- package/dist/index.css +201 -25
- package/dist/index.js +411 -47
- package/dist/index.js.map +1 -1
- package/dist/utils/colorSpace.d.ts +12 -0
- package/dist/utils/colorSpace.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,19 +1,391 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import {
|
|
5
|
-
import t, {
|
|
6
|
-
import { motion, useMotionValue, useSpring, useTransform } from "motion/react";
|
|
4
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
5
|
+
import t, { useState, useCallback, useRef, useEffect, useLayoutEffect, Fragment, useContext, createContext, useId, useMemo } from "react";
|
|
6
|
+
import { useReducedMotion, AnimatePresence, motion, useMotionValue, useSpring, useTransform } from "motion/react";
|
|
7
7
|
import { Popover, Select } from "@base-ui/react";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
const EASE_IN_OUT_STRONG = [0.77, 0, 0.175, 1];
|
|
9
|
+
const MORPH_DURATION = 0.28;
|
|
10
|
+
const FAST_EASE_OUT = [0.23, 1, 0.32, 1];
|
|
11
|
+
const COLLAPSED_SIZE_PX = 32;
|
|
12
|
+
const DRAG_THRESHOLD_PX = 4;
|
|
13
|
+
const EDGE_PADDING_PX = 8;
|
|
14
|
+
const PANEL_EXPANDED_PADDING_PX = 16;
|
|
15
|
+
const PANEL_HEADER_HEIGHT_PX = 22;
|
|
16
|
+
const PANEL_BODY_MARGIN_TOP_PX = 16;
|
|
17
|
+
const SNAP_HINT_IDLE_OPACITY = 0.5;
|
|
18
|
+
const SNAP_HINT_ACTIVE_OPACITY = 0.8;
|
|
19
|
+
function clamp(n2, min, max) {
|
|
20
|
+
return Math.min(Math.max(n2, min), max);
|
|
21
|
+
}
|
|
22
|
+
function readRootPxVar(name, fallback) {
|
|
23
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
26
|
+
const raw = window.getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
27
|
+
const parsed = Number.parseFloat(raw);
|
|
28
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
29
|
+
}
|
|
30
|
+
function anchorFromPoint(centerX, centerY, viewportWidth, viewportHeight) {
|
|
31
|
+
const vertical = centerY > viewportHeight / 2 ? "bottom" : "top";
|
|
32
|
+
const horizontal = centerX > viewportWidth / 2 ? "right" : "left";
|
|
33
|
+
return `${vertical}-${horizontal}`;
|
|
34
|
+
}
|
|
35
|
+
function anchorPosition(anchor, offsets, viewportWidth, viewportHeight) {
|
|
36
|
+
const left = anchor.endsWith("left") ? offsets.left : viewportWidth - offsets.right - COLLAPSED_SIZE_PX;
|
|
37
|
+
const top = anchor.startsWith("top") ? offsets.top : viewportHeight - offsets.bottom - COLLAPSED_SIZE_PX;
|
|
38
|
+
return { left, top };
|
|
39
|
+
}
|
|
40
|
+
function Panel({
|
|
41
|
+
children,
|
|
42
|
+
className,
|
|
43
|
+
floating = true,
|
|
44
|
+
collapsed: collapsedProp,
|
|
45
|
+
defaultCollapsed = false,
|
|
46
|
+
onCollapsedChange,
|
|
47
|
+
collapseAriaLabel = "Toggle panel",
|
|
48
|
+
style: externalStyle,
|
|
49
|
+
...domRest
|
|
50
|
+
}) {
|
|
51
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(defaultCollapsed);
|
|
52
|
+
const shouldReduceMotion = useReducedMotion();
|
|
53
|
+
const collapsed = collapsedProp !== void 0 ? collapsedProp : uncontrolledCollapsed;
|
|
54
|
+
const setCollapsed = useCallback(
|
|
55
|
+
(next) => {
|
|
56
|
+
onCollapsedChange == null ? void 0 : onCollapsedChange(next);
|
|
57
|
+
if (collapsedProp === void 0) {
|
|
58
|
+
setUncontrolledCollapsed(next);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
[collapsedProp, onCollapsedChange]
|
|
62
|
+
);
|
|
63
|
+
const prevCollapsedRef = useRef(collapsed);
|
|
64
|
+
const collapsedChanged = prevCollapsedRef.current !== collapsed;
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
prevCollapsedRef.current = collapsed;
|
|
67
|
+
}, [collapsed]);
|
|
68
|
+
const shellHeightTransition = shouldReduceMotion ? { duration: 0 } : collapsedChanged ? { duration: MORPH_DURATION, ease: EASE_IN_OUT_STRONG } : { duration: 0 };
|
|
69
|
+
const shellShapeTransition = shouldReduceMotion ? { duration: 0 } : collapsedChanged ? { duration: MORPH_DURATION, ease: EASE_IN_OUT_STRONG } : { duration: 0 };
|
|
70
|
+
const bodyTransition = shouldReduceMotion ? { duration: 0 } : { duration: collapsed ? 0.12 : 0.18, ease: FAST_EASE_OUT };
|
|
71
|
+
const [floatingAnchor, setFloatingAnchor] = useState("top-left");
|
|
72
|
+
const bodyRef = useRef(null);
|
|
73
|
+
const bodyContentRef = useRef(null);
|
|
74
|
+
const [measuredBodyHeight, setMeasuredBodyHeight] = useState(0);
|
|
75
|
+
const [viewportHeight, setViewportHeight] = useState(
|
|
76
|
+
() => typeof window !== "undefined" ? window.innerHeight : 0
|
|
77
|
+
);
|
|
78
|
+
const [dragRect, setDragRect] = useState(null);
|
|
79
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
80
|
+
const justDraggedRef = useRef(false);
|
|
81
|
+
const dragSessionRef = useRef(null);
|
|
82
|
+
useLayoutEffect(() => {
|
|
83
|
+
const bodyContent = bodyContentRef.current;
|
|
84
|
+
if (!bodyContent) return;
|
|
85
|
+
const measure = () => {
|
|
86
|
+
setMeasuredBodyHeight(bodyContent.scrollHeight);
|
|
87
|
+
};
|
|
88
|
+
measure();
|
|
89
|
+
const ro = new ResizeObserver(measure);
|
|
90
|
+
ro.observe(bodyContent);
|
|
91
|
+
return () => ro.disconnect();
|
|
92
|
+
}, []);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (typeof window === "undefined") return;
|
|
95
|
+
const onResize = () => setViewportHeight(window.innerHeight);
|
|
96
|
+
window.addEventListener("resize", onResize);
|
|
97
|
+
return () => window.removeEventListener("resize", onResize);
|
|
98
|
+
}, []);
|
|
99
|
+
const handleShellClick = () => {
|
|
100
|
+
if (!collapsed) return;
|
|
101
|
+
if (justDraggedRef.current) {
|
|
102
|
+
justDraggedRef.current = false;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
setCollapsed(false);
|
|
106
|
+
};
|
|
107
|
+
const handleShellKeyDown = (e) => {
|
|
108
|
+
if (!collapsed) return;
|
|
109
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
setCollapsed(false);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const handlePointerDown = (e) => {
|
|
115
|
+
if (!collapsed || !floating) return;
|
|
116
|
+
if (e.button !== 0) return;
|
|
117
|
+
justDraggedRef.current = false;
|
|
118
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
119
|
+
dragSessionRef.current = {
|
|
120
|
+
pointerId: e.pointerId,
|
|
121
|
+
startClientX: e.clientX,
|
|
122
|
+
startClientY: e.clientY,
|
|
123
|
+
startTop: rect.top,
|
|
124
|
+
startLeft: rect.left,
|
|
125
|
+
moved: false
|
|
126
|
+
};
|
|
127
|
+
setDragRect({ top: rect.top, left: rect.left });
|
|
128
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
129
|
+
};
|
|
130
|
+
const handlePointerMove = (e) => {
|
|
131
|
+
const session = dragSessionRef.current;
|
|
132
|
+
if (!session || session.pointerId !== e.pointerId) return;
|
|
133
|
+
const deltaY = e.clientY - session.startClientY;
|
|
134
|
+
const deltaX = e.clientX - session.startClientX;
|
|
135
|
+
if (!session.moved && (Math.abs(deltaY) >= DRAG_THRESHOLD_PX || Math.abs(deltaX) >= DRAG_THRESHOLD_PX)) {
|
|
136
|
+
session.moved = true;
|
|
137
|
+
setIsDragging(true);
|
|
138
|
+
}
|
|
139
|
+
if (!session.moved) return;
|
|
140
|
+
const viewportHeight2 = typeof window !== "undefined" ? window.innerHeight : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
141
|
+
const viewportWidth = typeof window !== "undefined" ? window.innerWidth : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
142
|
+
const maxTop = Math.max(
|
|
143
|
+
EDGE_PADDING_PX,
|
|
144
|
+
viewportHeight2 - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
145
|
+
);
|
|
146
|
+
const maxLeft = Math.max(
|
|
147
|
+
EDGE_PADDING_PX,
|
|
148
|
+
viewportWidth - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
149
|
+
);
|
|
150
|
+
setDragRect({
|
|
151
|
+
top: clamp(session.startTop + deltaY, EDGE_PADDING_PX, maxTop),
|
|
152
|
+
left: clamp(session.startLeft + deltaX, EDGE_PADDING_PX, maxLeft)
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
const handlePointerUp = (e) => {
|
|
156
|
+
const session = dragSessionRef.current;
|
|
157
|
+
if (!session || session.pointerId !== e.pointerId) return;
|
|
158
|
+
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
159
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
160
|
+
}
|
|
161
|
+
dragSessionRef.current = null;
|
|
162
|
+
setIsDragging(false);
|
|
163
|
+
if (!session.moved) {
|
|
164
|
+
setDragRect(null);
|
|
165
|
+
return;
|
|
15
166
|
}
|
|
167
|
+
justDraggedRef.current = true;
|
|
168
|
+
const viewportHeight2 = typeof window !== "undefined" ? window.innerHeight : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
169
|
+
const viewportWidth = typeof window !== "undefined" ? window.innerWidth : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
170
|
+
const maxTop = Math.max(
|
|
171
|
+
EDGE_PADDING_PX,
|
|
172
|
+
viewportHeight2 - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
173
|
+
);
|
|
174
|
+
const maxLeft = Math.max(
|
|
175
|
+
EDGE_PADDING_PX,
|
|
176
|
+
viewportWidth - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
177
|
+
);
|
|
178
|
+
const finalTop = clamp(
|
|
179
|
+
(dragRect == null ? void 0 : dragRect.top) ?? session.startTop,
|
|
180
|
+
EDGE_PADDING_PX,
|
|
181
|
+
maxTop
|
|
182
|
+
);
|
|
183
|
+
const finalLeft = clamp(
|
|
184
|
+
(dragRect == null ? void 0 : dragRect.left) ?? session.startLeft,
|
|
185
|
+
EDGE_PADDING_PX,
|
|
186
|
+
maxLeft
|
|
187
|
+
);
|
|
188
|
+
const centerY = finalTop + COLLAPSED_SIZE_PX / 2;
|
|
189
|
+
const centerX = finalLeft + COLLAPSED_SIZE_PX / 2;
|
|
190
|
+
setFloatingAnchor(anchorFromPoint(centerX, centerY, viewportWidth, viewportHeight2));
|
|
191
|
+
setDragRect(null);
|
|
192
|
+
};
|
|
193
|
+
const offsets = {
|
|
194
|
+
top: readRootPxVar("--aporia-panel-offset-top", 40),
|
|
195
|
+
left: readRootPxVar("--aporia-panel-offset-left", 40),
|
|
196
|
+
right: readRootPxVar("--aporia-panel-offset-right", 40),
|
|
197
|
+
bottom: readRootPxVar("--aporia-panel-offset-bottom", 40),
|
|
198
|
+
zIndex: readRootPxVar("--aporia-panel-z-index", 1e3)
|
|
199
|
+
};
|
|
200
|
+
const expandedChromeHeight = PANEL_EXPANDED_PADDING_PX * 2 + PANEL_HEADER_HEIGHT_PX + PANEL_BODY_MARGIN_TOP_PX;
|
|
201
|
+
const expandedContentHeight = expandedChromeHeight + measuredBodyHeight;
|
|
202
|
+
const maxExpandedHeight = floating ? Math.max(
|
|
203
|
+
COLLAPSED_SIZE_PX,
|
|
204
|
+
viewportHeight - offsets.top - offsets.bottom
|
|
205
|
+
) : Number.POSITIVE_INFINITY;
|
|
206
|
+
const targetExpandedHeight = Math.max(
|
|
207
|
+
COLLAPSED_SIZE_PX,
|
|
208
|
+
Math.min(expandedContentHeight, maxExpandedHeight)
|
|
16
209
|
);
|
|
210
|
+
const viewport = {
|
|
211
|
+
width: typeof window !== "undefined" ? window.innerWidth : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2,
|
|
212
|
+
height: typeof window !== "undefined" ? window.innerHeight : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2
|
|
213
|
+
};
|
|
214
|
+
const floatingStyle = (() => {
|
|
215
|
+
if (!floating) return void 0;
|
|
216
|
+
if (dragRect !== null) {
|
|
217
|
+
return {
|
|
218
|
+
left: `${dragRect.left}px`,
|
|
219
|
+
top: `${dragRect.top}px`,
|
|
220
|
+
bottom: "auto",
|
|
221
|
+
right: "auto"
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (floatingAnchor === "bottom-left") {
|
|
225
|
+
return {
|
|
226
|
+
left: `${offsets.left}px`,
|
|
227
|
+
bottom: `${offsets.bottom}px`,
|
|
228
|
+
top: "auto",
|
|
229
|
+
right: "auto"
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (floatingAnchor === "top-right") {
|
|
233
|
+
return {
|
|
234
|
+
right: `${offsets.right}px`,
|
|
235
|
+
top: `${offsets.top}px`,
|
|
236
|
+
left: "auto",
|
|
237
|
+
bottom: "auto"
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
if (floatingAnchor === "bottom-right") {
|
|
241
|
+
return {
|
|
242
|
+
right: `${offsets.right}px`,
|
|
243
|
+
bottom: `${offsets.bottom}px`,
|
|
244
|
+
left: "auto",
|
|
245
|
+
top: "auto"
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
left: `${offsets.left}px`,
|
|
250
|
+
top: `${offsets.top}px`,
|
|
251
|
+
bottom: "auto",
|
|
252
|
+
right: "auto"
|
|
253
|
+
};
|
|
254
|
+
})();
|
|
255
|
+
const snapHints = (() => {
|
|
256
|
+
if (!floating || !collapsed || !isDragging || dragRect === null) return [];
|
|
257
|
+
const corners = [
|
|
258
|
+
"top-left",
|
|
259
|
+
"top-right",
|
|
260
|
+
"bottom-left",
|
|
261
|
+
"bottom-right"
|
|
262
|
+
];
|
|
263
|
+
const dragCenter = {
|
|
264
|
+
x: dragRect.left + COLLAPSED_SIZE_PX / 2,
|
|
265
|
+
y: dragRect.top + COLLAPSED_SIZE_PX / 2
|
|
266
|
+
};
|
|
267
|
+
const activeAnchor = anchorFromPoint(
|
|
268
|
+
dragCenter.x,
|
|
269
|
+
dragCenter.y,
|
|
270
|
+
viewport.width,
|
|
271
|
+
viewport.height
|
|
272
|
+
);
|
|
273
|
+
return corners.map((anchor) => {
|
|
274
|
+
const pos = anchorPosition(anchor, offsets, viewport.width, viewport.height);
|
|
275
|
+
const isActive = anchor === activeAnchor;
|
|
276
|
+
return {
|
|
277
|
+
anchor,
|
|
278
|
+
left: pos.left,
|
|
279
|
+
top: pos.top,
|
|
280
|
+
opacity: isActive ? SNAP_HINT_ACTIVE_OPACITY : SNAP_HINT_IDLE_OPACITY
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
})();
|
|
284
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
285
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: snapHints.map((hint) => /* @__PURE__ */ jsx(
|
|
286
|
+
motion.div,
|
|
287
|
+
{
|
|
288
|
+
className: "aporiaPanelSnapHint",
|
|
289
|
+
initial: { opacity: 0 },
|
|
290
|
+
animate: { opacity: hint.opacity },
|
|
291
|
+
exit: { opacity: 0 },
|
|
292
|
+
transition: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT },
|
|
293
|
+
style: {
|
|
294
|
+
top: hint.top,
|
|
295
|
+
left: hint.left,
|
|
296
|
+
zIndex: Math.max(0, Math.round(offsets.zIndex - 1))
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
hint.anchor
|
|
300
|
+
)) }),
|
|
301
|
+
/* @__PURE__ */ jsxs(
|
|
302
|
+
motion.section,
|
|
303
|
+
{
|
|
304
|
+
...domRest,
|
|
305
|
+
initial: false,
|
|
306
|
+
onClick: handleShellClick,
|
|
307
|
+
onKeyDown: handleShellKeyDown,
|
|
308
|
+
onPointerDown: handlePointerDown,
|
|
309
|
+
onPointerMove: handlePointerMove,
|
|
310
|
+
onPointerUp: handlePointerUp,
|
|
311
|
+
onPointerCancel: handlePointerUp,
|
|
312
|
+
role: collapsed ? "button" : void 0,
|
|
313
|
+
tabIndex: collapsed ? 0 : void 0,
|
|
314
|
+
"aria-label": collapsed ? "Expand panel" : void 0,
|
|
315
|
+
animate: {
|
|
316
|
+
height: collapsed ? COLLAPSED_SIZE_PX : targetExpandedHeight,
|
|
317
|
+
borderRadius: collapsed ? 12 : 24,
|
|
318
|
+
padding: collapsed ? 5 : 16,
|
|
319
|
+
scale: collapsed && isDragging ? 1.06 : 1,
|
|
320
|
+
rotate: collapsed && isDragging ? -2.5 : 0,
|
|
321
|
+
y: collapsed && isDragging ? -4 : 0
|
|
322
|
+
},
|
|
323
|
+
transition: {
|
|
324
|
+
height: shellHeightTransition,
|
|
325
|
+
borderRadius: shellShapeTransition,
|
|
326
|
+
padding: shellShapeTransition,
|
|
327
|
+
scale: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT },
|
|
328
|
+
rotate: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT },
|
|
329
|
+
y: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT }
|
|
330
|
+
},
|
|
331
|
+
style: {
|
|
332
|
+
...externalStyle,
|
|
333
|
+
...floatingStyle
|
|
334
|
+
},
|
|
335
|
+
className: ["aporiaPanel", className].filter(Boolean).join(" "),
|
|
336
|
+
"data-collapsed": collapsed ? "true" : "false",
|
|
337
|
+
"data-floating": floating ? "true" : "false",
|
|
338
|
+
"data-anchor": floatingAnchor,
|
|
339
|
+
"data-dragging": isDragging ? "true" : "false",
|
|
340
|
+
children: [
|
|
341
|
+
/* @__PURE__ */ jsx("div", { className: "aporiaPanelHeader", children: /* @__PURE__ */ jsx(
|
|
342
|
+
"button",
|
|
343
|
+
{
|
|
344
|
+
type: "button",
|
|
345
|
+
className: "aporiaPanelToggle",
|
|
346
|
+
"aria-label": collapseAriaLabel,
|
|
347
|
+
"aria-pressed": collapsed,
|
|
348
|
+
onClick: () => setCollapsed(!collapsed),
|
|
349
|
+
children: /* @__PURE__ */ jsx(
|
|
350
|
+
"svg",
|
|
351
|
+
{
|
|
352
|
+
className: "aporiaPanelLogoGlyph",
|
|
353
|
+
viewBox: "0 0 22 22",
|
|
354
|
+
"aria-hidden": "true",
|
|
355
|
+
focusable: "false",
|
|
356
|
+
children: /* @__PURE__ */ jsx(
|
|
357
|
+
"path",
|
|
358
|
+
{
|
|
359
|
+
fillRule: "evenodd",
|
|
360
|
+
clipRule: "evenodd",
|
|
361
|
+
d: "M17.6185 16.089C18 15.3403 18 14.3602 18 12.4V9.6C18 7.63982 18 6.65972 17.6185 5.91103C17.283 5.25247 16.7475 4.71703 16.089 4.38148C15.3403 4 14.3602 4 12.4 4H9.6C7.63982 4 6.65972 4 5.91103 4.38148C5.25247 4.71703 4.71703 5.25247 4.38148 5.91103C4 6.65972 4 7.63982 4 9.6V12.4C4 14.3602 4 15.3403 4.38148 16.089C4.71703 16.7475 5.25247 17.283 5.91103 17.6185C6.65972 18 7.63982 18 9.6 18H12.4C14.3602 18 15.3403 18 16.089 17.6185C16.7475 17.283 17.283 16.7475 17.6185 16.089ZM10.125 13.4062V8.59375C10.125 7.5745 10.125 7.06488 10.2915 6.66288C10.5135 6.12688 10.9394 5.70103 11.4754 5.47901C11.8774 5.3125 12.387 5.3125 13.4062 5.3125C14.4255 5.3125 14.9351 5.3125 15.3371 5.47901C15.8731 5.70103 16.299 6.12688 16.521 6.66288C16.6875 7.06488 16.6875 7.5745 16.6875 8.59375V13.4062C16.6875 14.4255 16.6875 14.9351 16.521 15.3371C16.299 15.8731 15.8731 16.299 15.3371 16.521C14.9351 16.6875 14.4255 16.6875 13.4062 16.6875C12.387 16.6875 11.8774 16.6875 11.4754 16.521C10.9394 16.299 10.5135 15.8731 10.2915 15.3371C10.125 14.9351 10.125 14.4255 10.125 13.4062Z",
|
|
362
|
+
fill: "currentColor"
|
|
363
|
+
}
|
|
364
|
+
)
|
|
365
|
+
}
|
|
366
|
+
)
|
|
367
|
+
}
|
|
368
|
+
) }),
|
|
369
|
+
/* @__PURE__ */ jsx(
|
|
370
|
+
motion.div,
|
|
371
|
+
{
|
|
372
|
+
ref: bodyRef,
|
|
373
|
+
className: "aporiaPanelBody",
|
|
374
|
+
"aria-hidden": collapsed,
|
|
375
|
+
inert: collapsed,
|
|
376
|
+
initial: false,
|
|
377
|
+
animate: {
|
|
378
|
+
opacity: collapsed ? 0 : 1,
|
|
379
|
+
marginTop: collapsed ? 0 : 16
|
|
380
|
+
},
|
|
381
|
+
transition: bodyTransition,
|
|
382
|
+
children: /* @__PURE__ */ jsx("div", { ref: bodyContentRef, className: "aporiaPanelBodyContent", children })
|
|
383
|
+
}
|
|
384
|
+
)
|
|
385
|
+
]
|
|
386
|
+
}
|
|
387
|
+
)
|
|
388
|
+
] });
|
|
17
389
|
}
|
|
18
390
|
const CategoryDisabledContext = createContext(false);
|
|
19
391
|
function CategoryDisabledProvider({
|
|
@@ -90,8 +462,8 @@ function Category({
|
|
|
90
462
|
{
|
|
91
463
|
className: "categoryChevronIcon",
|
|
92
464
|
"data-collapsed": collapsed ? "true" : "false",
|
|
93
|
-
width: "
|
|
94
|
-
height: "
|
|
465
|
+
width: "14",
|
|
466
|
+
height: "14",
|
|
95
467
|
viewBox: "0 0 12 12",
|
|
96
468
|
"aria-hidden": true,
|
|
97
469
|
children: /* @__PURE__ */ jsx(
|
|
@@ -153,8 +525,9 @@ function Category({
|
|
|
153
525
|
opacity: collapsed ? { duration: 0.09, ease: "easeIn" } : { duration: 0.15, ease: "easeOut" }
|
|
154
526
|
},
|
|
155
527
|
style: {
|
|
156
|
-
|
|
157
|
-
|
|
528
|
+
// Keep overdrag visible while open, but fully clip collapsed content so
|
|
529
|
+
// the last category cannot leak height into panel measurements.
|
|
530
|
+
overflow: collapsed ? "hidden" : "visible",
|
|
158
531
|
minHeight: 0,
|
|
159
532
|
boxSizing: "border-box"
|
|
160
533
|
},
|
|
@@ -1210,6 +1583,14 @@ function normalizeHex(raw) {
|
|
|
1210
1583
|
}
|
|
1211
1584
|
return `#${h2.toUpperCase()}`;
|
|
1212
1585
|
}
|
|
1586
|
+
function sanitizeHexDigits(raw) {
|
|
1587
|
+
return raw.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
1588
|
+
}
|
|
1589
|
+
function expandHexDigitsToSix(raw) {
|
|
1590
|
+
const digits = sanitizeHexDigits(raw);
|
|
1591
|
+
if (!digits) return null;
|
|
1592
|
+
return digits.repeat(Math.ceil(6 / digits.length)).slice(0, 6).toUpperCase();
|
|
1593
|
+
}
|
|
1213
1594
|
function hslToHex(h2, s, l2) {
|
|
1214
1595
|
const [r, g, b2] = hslToRgbBytes(h2, s, l2);
|
|
1215
1596
|
const toHex = (v2) => v2.toString(16).padStart(2, "0");
|
|
@@ -1447,12 +1828,6 @@ function clampHueDeg(h2) {
|
|
|
1447
1828
|
function clampInt(n2, min, max) {
|
|
1448
1829
|
return Math.max(min, Math.min(max, Math.round(n2)));
|
|
1449
1830
|
}
|
|
1450
|
-
function normalizeHexDigits(raw) {
|
|
1451
|
-
return raw.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
1452
|
-
}
|
|
1453
|
-
function isValidSixHex$2(d2) {
|
|
1454
|
-
return /^[0-9a-fA-F]{6}$/.test(d2);
|
|
1455
|
-
}
|
|
1456
1831
|
function clampHsv01(base) {
|
|
1457
1832
|
return { h: clampHueDeg(base.h), s: clamp01(base.s), v: clamp01(base.v) };
|
|
1458
1833
|
}
|
|
@@ -1796,11 +2171,11 @@ function ColorPicker({ value, onChange }) {
|
|
|
1796
2171
|
value: hex.slice(1),
|
|
1797
2172
|
prefix: "#",
|
|
1798
2173
|
onCommit: (val) => {
|
|
1799
|
-
const
|
|
1800
|
-
if (
|
|
2174
|
+
const expanded = expandHexDigitsToSix(val);
|
|
2175
|
+
if (expanded) onChange(`#${expanded}`);
|
|
1801
2176
|
},
|
|
1802
|
-
sanitize:
|
|
1803
|
-
validate:
|
|
2177
|
+
sanitize: sanitizeHexDigits,
|
|
2178
|
+
validate: (v2) => sanitizeHexDigits(v2).length > 0,
|
|
1804
2179
|
maxLength: 6,
|
|
1805
2180
|
inputMode: "text",
|
|
1806
2181
|
ariaLabel: `Edit hex color, ${hex}`,
|
|
@@ -1811,7 +2186,7 @@ function ColorPicker({ value, onChange }) {
|
|
|
1811
2186
|
onChange(parsed);
|
|
1812
2187
|
return "";
|
|
1813
2188
|
}
|
|
1814
|
-
return
|
|
2189
|
+
return sanitizeHexDigits(pasted);
|
|
1815
2190
|
}
|
|
1816
2191
|
}
|
|
1817
2192
|
) : mode === "hsl" ? /* @__PURE__ */ jsxs("div", { className: "colorPickerTriplet", "aria-label": "HSL values", children: [
|
|
@@ -2048,20 +2423,15 @@ function hexDigits$1(hex) {
|
|
|
2048
2423
|
const n2 = normalizeHex(hex);
|
|
2049
2424
|
return n2.slice(1);
|
|
2050
2425
|
}
|
|
2051
|
-
function isValidSixHex$1(d2) {
|
|
2052
|
-
return /^[0-9a-fA-F]{6}$/.test(d2);
|
|
2053
|
-
}
|
|
2054
|
-
function sanitizeHex$1(input) {
|
|
2055
|
-
return input.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
2056
|
-
}
|
|
2057
2426
|
function ColorRow({ label = "Color", value, onChange, disabled: disabledProp }) {
|
|
2058
2427
|
const categoryDisabled = useCategoryDisabled();
|
|
2059
2428
|
const disabled = Boolean(disabledProp || categoryDisabled);
|
|
2060
2429
|
const [hovered, setHovered] = useState(false);
|
|
2061
2430
|
const hex = normalizeHex(value);
|
|
2062
2431
|
const handleCommit = (sanitized) => {
|
|
2063
|
-
|
|
2064
|
-
|
|
2432
|
+
const expanded = expandHexDigitsToSix(sanitized);
|
|
2433
|
+
if (expanded) {
|
|
2434
|
+
onChange(`#${expanded}`);
|
|
2065
2435
|
}
|
|
2066
2436
|
};
|
|
2067
2437
|
const handlePaste = (pasted) => {
|
|
@@ -2083,8 +2453,8 @@ function ColorRow({ label = "Color", value, onChange, disabled: disabledProp })
|
|
|
2083
2453
|
value: hexDigits$1(hex),
|
|
2084
2454
|
prefix: "#",
|
|
2085
2455
|
onCommit: handleCommit,
|
|
2086
|
-
sanitize:
|
|
2087
|
-
validate:
|
|
2456
|
+
sanitize: sanitizeHexDigits,
|
|
2457
|
+
validate: (v2) => sanitizeHexDigits(v2).length > 0,
|
|
2088
2458
|
maxLength: 6,
|
|
2089
2459
|
inputMode: "text",
|
|
2090
2460
|
ariaLabel: `Edit hex color, ${hex}`,
|
|
@@ -2256,9 +2626,6 @@ function generateAestheticGradient(stopCount) {
|
|
|
2256
2626
|
function hexDigits(hex) {
|
|
2257
2627
|
return normalizeHex(hex).slice(1);
|
|
2258
2628
|
}
|
|
2259
|
-
function isValidSixHex(d2) {
|
|
2260
|
-
return /^[0-9a-fA-F]{6}$/.test(d2);
|
|
2261
|
-
}
|
|
2262
2629
|
function stopsToGradient(stops, angle = 90) {
|
|
2263
2630
|
if (stops.length === 0) return "linear-gradient(90deg, #808080, #808080)";
|
|
2264
2631
|
if (stops.length === 1) {
|
|
@@ -2293,19 +2660,16 @@ const DEFAULT_GRADIENT_STOPS = [
|
|
|
2293
2660
|
{ color: "#42C0B0" },
|
|
2294
2661
|
{ color: "#BAC9C7" }
|
|
2295
2662
|
];
|
|
2296
|
-
function sanitizeHex(input) {
|
|
2297
|
-
return input.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
2298
|
-
}
|
|
2299
2663
|
function StopRow({ index, stop, canDelete, onColorChange, onDelete }) {
|
|
2300
2664
|
const hex = normalizeHex(stop.color);
|
|
2301
2665
|
const handleCommit = (val) => {
|
|
2302
|
-
const
|
|
2303
|
-
if (
|
|
2304
|
-
onColorChange(`#${
|
|
2666
|
+
const expanded = expandHexDigitsToSix(val);
|
|
2667
|
+
if (expanded) {
|
|
2668
|
+
onColorChange(`#${expanded}`);
|
|
2305
2669
|
}
|
|
2306
2670
|
};
|
|
2307
2671
|
const handlePaste = (pasted) => {
|
|
2308
|
-
return
|
|
2672
|
+
return sanitizeHexDigits(pasted);
|
|
2309
2673
|
};
|
|
2310
2674
|
return /* @__PURE__ */ jsxs("div", { className: "gradientPickerStop", children: [
|
|
2311
2675
|
/* @__PURE__ */ jsxs("div", { className: "gradientPickerStopColorHex", children: [
|
|
@@ -2336,8 +2700,8 @@ function StopRow({ index, stop, canDelete, onColorChange, onDelete }) {
|
|
|
2336
2700
|
value: hexDigits(hex),
|
|
2337
2701
|
prefix: "#",
|
|
2338
2702
|
onCommit: handleCommit,
|
|
2339
|
-
sanitize:
|
|
2340
|
-
validate:
|
|
2703
|
+
sanitize: sanitizeHexDigits,
|
|
2704
|
+
validate: (v2) => sanitizeHexDigits(v2).length > 0,
|
|
2341
2705
|
maxLength: 6,
|
|
2342
2706
|
inputMode: "text",
|
|
2343
2707
|
ariaLabel: "Hex color without hash",
|