aporia 0.2.7 → 0.2.9
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 +13 -0
- 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 +25 -3
- package/dist/components/Panel.d.ts.map +1 -1
- package/dist/index.css +201 -25
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +418 -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,398 @@
|
|
|
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 normalizePanelAnchor(anchor) {
|
|
23
|
+
if (anchor === "left") return "top-left";
|
|
24
|
+
if (anchor === "right") return "top-right";
|
|
25
|
+
return anchor;
|
|
26
|
+
}
|
|
27
|
+
function readRootPxVar(name, fallback) {
|
|
28
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
29
|
+
return fallback;
|
|
30
|
+
}
|
|
31
|
+
const raw = window.getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
32
|
+
const parsed = Number.parseFloat(raw);
|
|
33
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
34
|
+
}
|
|
35
|
+
function anchorFromPoint(centerX, centerY, viewportWidth, viewportHeight) {
|
|
36
|
+
const vertical = centerY > viewportHeight / 2 ? "bottom" : "top";
|
|
37
|
+
const horizontal = centerX > viewportWidth / 2 ? "right" : "left";
|
|
38
|
+
return `${vertical}-${horizontal}`;
|
|
39
|
+
}
|
|
40
|
+
function anchorPosition(anchor, offsets, viewportWidth, viewportHeight) {
|
|
41
|
+
const left = anchor.endsWith("left") ? offsets.left : viewportWidth - offsets.right - COLLAPSED_SIZE_PX;
|
|
42
|
+
const top = anchor.startsWith("top") ? offsets.top : viewportHeight - offsets.bottom - COLLAPSED_SIZE_PX;
|
|
43
|
+
return { left, top };
|
|
44
|
+
}
|
|
45
|
+
function Panel({
|
|
46
|
+
children,
|
|
47
|
+
className,
|
|
48
|
+
floating = true,
|
|
49
|
+
defaultAnchor = "top-left",
|
|
50
|
+
collapsed: collapsedProp,
|
|
51
|
+
defaultCollapsed = false,
|
|
52
|
+
onCollapsedChange,
|
|
53
|
+
collapseAriaLabel = "Toggle panel",
|
|
54
|
+
style: externalStyle,
|
|
55
|
+
...domRest
|
|
56
|
+
}) {
|
|
57
|
+
const [uncontrolledCollapsed, setUncontrolledCollapsed] = useState(defaultCollapsed);
|
|
58
|
+
const shouldReduceMotion = useReducedMotion();
|
|
59
|
+
const collapsed = collapsedProp !== void 0 ? collapsedProp : uncontrolledCollapsed;
|
|
60
|
+
const setCollapsed = useCallback(
|
|
61
|
+
(next) => {
|
|
62
|
+
onCollapsedChange == null ? void 0 : onCollapsedChange(next);
|
|
63
|
+
if (collapsedProp === void 0) {
|
|
64
|
+
setUncontrolledCollapsed(next);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
[collapsedProp, onCollapsedChange]
|
|
68
|
+
);
|
|
69
|
+
const prevCollapsedRef = useRef(collapsed);
|
|
70
|
+
const collapsedChanged = prevCollapsedRef.current !== collapsed;
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
prevCollapsedRef.current = collapsed;
|
|
73
|
+
}, [collapsed]);
|
|
74
|
+
const shellHeightTransition = shouldReduceMotion ? { duration: 0 } : collapsedChanged ? { duration: MORPH_DURATION, ease: EASE_IN_OUT_STRONG } : { duration: 0 };
|
|
75
|
+
const shellShapeTransition = shouldReduceMotion ? { duration: 0 } : collapsedChanged ? { duration: MORPH_DURATION, ease: EASE_IN_OUT_STRONG } : { duration: 0 };
|
|
76
|
+
const bodyTransition = shouldReduceMotion ? { duration: 0 } : { duration: collapsed ? 0.12 : 0.18, ease: FAST_EASE_OUT };
|
|
77
|
+
const initialAnchor = normalizePanelAnchor(defaultAnchor);
|
|
78
|
+
const [floatingAnchor, setFloatingAnchor] = useState(initialAnchor);
|
|
79
|
+
const bodyRef = useRef(null);
|
|
80
|
+
const bodyContentRef = useRef(null);
|
|
81
|
+
const [measuredBodyHeight, setMeasuredBodyHeight] = useState(0);
|
|
82
|
+
const [viewportHeight, setViewportHeight] = useState(
|
|
83
|
+
() => typeof window !== "undefined" ? window.innerHeight : 0
|
|
84
|
+
);
|
|
85
|
+
const [dragRect, setDragRect] = useState(null);
|
|
86
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
87
|
+
const justDraggedRef = useRef(false);
|
|
88
|
+
const dragSessionRef = useRef(null);
|
|
89
|
+
useLayoutEffect(() => {
|
|
90
|
+
const bodyContent = bodyContentRef.current;
|
|
91
|
+
if (!bodyContent) return;
|
|
92
|
+
const measure = () => {
|
|
93
|
+
setMeasuredBodyHeight(bodyContent.scrollHeight);
|
|
94
|
+
};
|
|
95
|
+
measure();
|
|
96
|
+
const ro = new ResizeObserver(measure);
|
|
97
|
+
ro.observe(bodyContent);
|
|
98
|
+
return () => ro.disconnect();
|
|
99
|
+
}, []);
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (typeof window === "undefined") return;
|
|
102
|
+
const onResize = () => setViewportHeight(window.innerHeight);
|
|
103
|
+
window.addEventListener("resize", onResize);
|
|
104
|
+
return () => window.removeEventListener("resize", onResize);
|
|
105
|
+
}, []);
|
|
106
|
+
const handleShellClick = () => {
|
|
107
|
+
if (!collapsed) return;
|
|
108
|
+
if (justDraggedRef.current) {
|
|
109
|
+
justDraggedRef.current = false;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
setCollapsed(false);
|
|
113
|
+
};
|
|
114
|
+
const handleShellKeyDown = (e) => {
|
|
115
|
+
if (!collapsed) return;
|
|
116
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
setCollapsed(false);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const handlePointerDown = (e) => {
|
|
122
|
+
if (!collapsed || !floating) return;
|
|
123
|
+
if (e.button !== 0) return;
|
|
124
|
+
justDraggedRef.current = false;
|
|
125
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
126
|
+
dragSessionRef.current = {
|
|
127
|
+
pointerId: e.pointerId,
|
|
128
|
+
startClientX: e.clientX,
|
|
129
|
+
startClientY: e.clientY,
|
|
130
|
+
startTop: rect.top,
|
|
131
|
+
startLeft: rect.left,
|
|
132
|
+
moved: false
|
|
133
|
+
};
|
|
134
|
+
setDragRect({ top: rect.top, left: rect.left });
|
|
135
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
136
|
+
};
|
|
137
|
+
const handlePointerMove = (e) => {
|
|
138
|
+
const session = dragSessionRef.current;
|
|
139
|
+
if (!session || session.pointerId !== e.pointerId) return;
|
|
140
|
+
const deltaY = e.clientY - session.startClientY;
|
|
141
|
+
const deltaX = e.clientX - session.startClientX;
|
|
142
|
+
if (!session.moved && (Math.abs(deltaY) >= DRAG_THRESHOLD_PX || Math.abs(deltaX) >= DRAG_THRESHOLD_PX)) {
|
|
143
|
+
session.moved = true;
|
|
144
|
+
setIsDragging(true);
|
|
145
|
+
}
|
|
146
|
+
if (!session.moved) return;
|
|
147
|
+
const viewportHeight2 = typeof window !== "undefined" ? window.innerHeight : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
148
|
+
const viewportWidth = typeof window !== "undefined" ? window.innerWidth : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
149
|
+
const maxTop = Math.max(
|
|
150
|
+
EDGE_PADDING_PX,
|
|
151
|
+
viewportHeight2 - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
152
|
+
);
|
|
153
|
+
const maxLeft = Math.max(
|
|
154
|
+
EDGE_PADDING_PX,
|
|
155
|
+
viewportWidth - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
156
|
+
);
|
|
157
|
+
setDragRect({
|
|
158
|
+
top: clamp(session.startTop + deltaY, EDGE_PADDING_PX, maxTop),
|
|
159
|
+
left: clamp(session.startLeft + deltaX, EDGE_PADDING_PX, maxLeft)
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
const handlePointerUp = (e) => {
|
|
163
|
+
const session = dragSessionRef.current;
|
|
164
|
+
if (!session || session.pointerId !== e.pointerId) return;
|
|
165
|
+
if (e.currentTarget.hasPointerCapture(e.pointerId)) {
|
|
166
|
+
e.currentTarget.releasePointerCapture(e.pointerId);
|
|
167
|
+
}
|
|
168
|
+
dragSessionRef.current = null;
|
|
169
|
+
setIsDragging(false);
|
|
170
|
+
if (!session.moved) {
|
|
171
|
+
setDragRect(null);
|
|
172
|
+
return;
|
|
15
173
|
}
|
|
174
|
+
justDraggedRef.current = true;
|
|
175
|
+
const viewportHeight2 = typeof window !== "undefined" ? window.innerHeight : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
176
|
+
const viewportWidth = typeof window !== "undefined" ? window.innerWidth : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2;
|
|
177
|
+
const maxTop = Math.max(
|
|
178
|
+
EDGE_PADDING_PX,
|
|
179
|
+
viewportHeight2 - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
180
|
+
);
|
|
181
|
+
const maxLeft = Math.max(
|
|
182
|
+
EDGE_PADDING_PX,
|
|
183
|
+
viewportWidth - COLLAPSED_SIZE_PX - EDGE_PADDING_PX
|
|
184
|
+
);
|
|
185
|
+
const finalTop = clamp(
|
|
186
|
+
(dragRect == null ? void 0 : dragRect.top) ?? session.startTop,
|
|
187
|
+
EDGE_PADDING_PX,
|
|
188
|
+
maxTop
|
|
189
|
+
);
|
|
190
|
+
const finalLeft = clamp(
|
|
191
|
+
(dragRect == null ? void 0 : dragRect.left) ?? session.startLeft,
|
|
192
|
+
EDGE_PADDING_PX,
|
|
193
|
+
maxLeft
|
|
194
|
+
);
|
|
195
|
+
const centerY = finalTop + COLLAPSED_SIZE_PX / 2;
|
|
196
|
+
const centerX = finalLeft + COLLAPSED_SIZE_PX / 2;
|
|
197
|
+
setFloatingAnchor(anchorFromPoint(centerX, centerY, viewportWidth, viewportHeight2));
|
|
198
|
+
setDragRect(null);
|
|
199
|
+
};
|
|
200
|
+
const offsets = {
|
|
201
|
+
top: readRootPxVar("--aporia-panel-offset-top", 40),
|
|
202
|
+
left: readRootPxVar("--aporia-panel-offset-left", 40),
|
|
203
|
+
right: readRootPxVar("--aporia-panel-offset-right", 40),
|
|
204
|
+
bottom: readRootPxVar("--aporia-panel-offset-bottom", 40),
|
|
205
|
+
zIndex: readRootPxVar("--aporia-panel-z-index", 1e3)
|
|
206
|
+
};
|
|
207
|
+
const expandedChromeHeight = PANEL_EXPANDED_PADDING_PX * 2 + PANEL_HEADER_HEIGHT_PX + PANEL_BODY_MARGIN_TOP_PX;
|
|
208
|
+
const expandedContentHeight = expandedChromeHeight + measuredBodyHeight;
|
|
209
|
+
const maxExpandedHeight = floating ? Math.max(
|
|
210
|
+
COLLAPSED_SIZE_PX,
|
|
211
|
+
viewportHeight - offsets.top - offsets.bottom
|
|
212
|
+
) : Number.POSITIVE_INFINITY;
|
|
213
|
+
const targetExpandedHeight = Math.max(
|
|
214
|
+
COLLAPSED_SIZE_PX,
|
|
215
|
+
Math.min(expandedContentHeight, maxExpandedHeight)
|
|
16
216
|
);
|
|
217
|
+
const viewport = {
|
|
218
|
+
width: typeof window !== "undefined" ? window.innerWidth : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2,
|
|
219
|
+
height: typeof window !== "undefined" ? window.innerHeight : COLLAPSED_SIZE_PX + EDGE_PADDING_PX * 2
|
|
220
|
+
};
|
|
221
|
+
const floatingStyle = (() => {
|
|
222
|
+
if (!floating) return void 0;
|
|
223
|
+
if (dragRect !== null) {
|
|
224
|
+
return {
|
|
225
|
+
left: `${dragRect.left}px`,
|
|
226
|
+
top: `${dragRect.top}px`,
|
|
227
|
+
bottom: "auto",
|
|
228
|
+
right: "auto"
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (floatingAnchor === "bottom-left") {
|
|
232
|
+
return {
|
|
233
|
+
left: `${offsets.left}px`,
|
|
234
|
+
bottom: `${offsets.bottom}px`,
|
|
235
|
+
top: "auto",
|
|
236
|
+
right: "auto"
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
if (floatingAnchor === "top-right") {
|
|
240
|
+
return {
|
|
241
|
+
right: `${offsets.right}px`,
|
|
242
|
+
top: `${offsets.top}px`,
|
|
243
|
+
left: "auto",
|
|
244
|
+
bottom: "auto"
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (floatingAnchor === "bottom-right") {
|
|
248
|
+
return {
|
|
249
|
+
right: `${offsets.right}px`,
|
|
250
|
+
bottom: `${offsets.bottom}px`,
|
|
251
|
+
left: "auto",
|
|
252
|
+
top: "auto"
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
left: `${offsets.left}px`,
|
|
257
|
+
top: `${offsets.top}px`,
|
|
258
|
+
bottom: "auto",
|
|
259
|
+
right: "auto"
|
|
260
|
+
};
|
|
261
|
+
})();
|
|
262
|
+
const snapHints = (() => {
|
|
263
|
+
if (!floating || !collapsed || !isDragging || dragRect === null) return [];
|
|
264
|
+
const corners = [
|
|
265
|
+
"top-left",
|
|
266
|
+
"top-right",
|
|
267
|
+
"bottom-left",
|
|
268
|
+
"bottom-right"
|
|
269
|
+
];
|
|
270
|
+
const dragCenter = {
|
|
271
|
+
x: dragRect.left + COLLAPSED_SIZE_PX / 2,
|
|
272
|
+
y: dragRect.top + COLLAPSED_SIZE_PX / 2
|
|
273
|
+
};
|
|
274
|
+
const activeAnchor = anchorFromPoint(
|
|
275
|
+
dragCenter.x,
|
|
276
|
+
dragCenter.y,
|
|
277
|
+
viewport.width,
|
|
278
|
+
viewport.height
|
|
279
|
+
);
|
|
280
|
+
return corners.map((anchor) => {
|
|
281
|
+
const pos = anchorPosition(anchor, offsets, viewport.width, viewport.height);
|
|
282
|
+
const isActive = anchor === activeAnchor;
|
|
283
|
+
return {
|
|
284
|
+
anchor,
|
|
285
|
+
left: pos.left,
|
|
286
|
+
top: pos.top,
|
|
287
|
+
opacity: isActive ? SNAP_HINT_ACTIVE_OPACITY : SNAP_HINT_IDLE_OPACITY
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
})();
|
|
291
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
292
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: snapHints.map((hint) => /* @__PURE__ */ jsx(
|
|
293
|
+
motion.div,
|
|
294
|
+
{
|
|
295
|
+
className: "aporiaPanelSnapHint",
|
|
296
|
+
initial: { opacity: 0 },
|
|
297
|
+
animate: { opacity: hint.opacity },
|
|
298
|
+
exit: { opacity: 0 },
|
|
299
|
+
transition: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT },
|
|
300
|
+
style: {
|
|
301
|
+
top: hint.top,
|
|
302
|
+
left: hint.left,
|
|
303
|
+
zIndex: Math.max(0, Math.round(offsets.zIndex - 1))
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
hint.anchor
|
|
307
|
+
)) }),
|
|
308
|
+
/* @__PURE__ */ jsxs(
|
|
309
|
+
motion.section,
|
|
310
|
+
{
|
|
311
|
+
...domRest,
|
|
312
|
+
initial: false,
|
|
313
|
+
onClick: handleShellClick,
|
|
314
|
+
onKeyDown: handleShellKeyDown,
|
|
315
|
+
onPointerDown: handlePointerDown,
|
|
316
|
+
onPointerMove: handlePointerMove,
|
|
317
|
+
onPointerUp: handlePointerUp,
|
|
318
|
+
onPointerCancel: handlePointerUp,
|
|
319
|
+
role: collapsed ? "button" : void 0,
|
|
320
|
+
tabIndex: collapsed ? 0 : void 0,
|
|
321
|
+
"aria-label": collapsed ? "Expand panel" : void 0,
|
|
322
|
+
animate: {
|
|
323
|
+
height: collapsed ? COLLAPSED_SIZE_PX : targetExpandedHeight,
|
|
324
|
+
borderRadius: collapsed ? 12 : 24,
|
|
325
|
+
padding: collapsed ? 5 : 16,
|
|
326
|
+
scale: collapsed && isDragging ? 1.06 : 1,
|
|
327
|
+
rotate: collapsed && isDragging ? -2.5 : 0,
|
|
328
|
+
y: collapsed && isDragging ? -4 : 0
|
|
329
|
+
},
|
|
330
|
+
transition: {
|
|
331
|
+
height: shellHeightTransition,
|
|
332
|
+
borderRadius: shellShapeTransition,
|
|
333
|
+
padding: shellShapeTransition,
|
|
334
|
+
scale: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT },
|
|
335
|
+
rotate: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT },
|
|
336
|
+
y: shouldReduceMotion ? { duration: 0 } : { duration: 0.18, ease: FAST_EASE_OUT }
|
|
337
|
+
},
|
|
338
|
+
style: {
|
|
339
|
+
...externalStyle,
|
|
340
|
+
...floatingStyle
|
|
341
|
+
},
|
|
342
|
+
className: ["aporiaPanel", className].filter(Boolean).join(" "),
|
|
343
|
+
"data-collapsed": collapsed ? "true" : "false",
|
|
344
|
+
"data-floating": floating ? "true" : "false",
|
|
345
|
+
"data-anchor": floatingAnchor,
|
|
346
|
+
"data-dragging": isDragging ? "true" : "false",
|
|
347
|
+
children: [
|
|
348
|
+
/* @__PURE__ */ jsx("div", { className: "aporiaPanelHeader", children: /* @__PURE__ */ jsx(
|
|
349
|
+
"button",
|
|
350
|
+
{
|
|
351
|
+
type: "button",
|
|
352
|
+
className: "aporiaPanelToggle",
|
|
353
|
+
"aria-label": collapseAriaLabel,
|
|
354
|
+
"aria-pressed": collapsed,
|
|
355
|
+
onClick: () => setCollapsed(!collapsed),
|
|
356
|
+
children: /* @__PURE__ */ jsx(
|
|
357
|
+
"svg",
|
|
358
|
+
{
|
|
359
|
+
className: "aporiaPanelLogoGlyph",
|
|
360
|
+
viewBox: "0 0 22 22",
|
|
361
|
+
"aria-hidden": "true",
|
|
362
|
+
focusable: "false",
|
|
363
|
+
children: /* @__PURE__ */ jsx(
|
|
364
|
+
"path",
|
|
365
|
+
{
|
|
366
|
+
fillRule: "evenodd",
|
|
367
|
+
clipRule: "evenodd",
|
|
368
|
+
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",
|
|
369
|
+
fill: "currentColor"
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
) }),
|
|
376
|
+
/* @__PURE__ */ jsx(
|
|
377
|
+
motion.div,
|
|
378
|
+
{
|
|
379
|
+
ref: bodyRef,
|
|
380
|
+
className: "aporiaPanelBody",
|
|
381
|
+
"aria-hidden": collapsed,
|
|
382
|
+
inert: collapsed,
|
|
383
|
+
initial: false,
|
|
384
|
+
animate: {
|
|
385
|
+
opacity: collapsed ? 0 : 1,
|
|
386
|
+
marginTop: collapsed ? 0 : 16
|
|
387
|
+
},
|
|
388
|
+
transition: bodyTransition,
|
|
389
|
+
children: /* @__PURE__ */ jsx("div", { ref: bodyContentRef, className: "aporiaPanelBodyContent", children })
|
|
390
|
+
}
|
|
391
|
+
)
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
)
|
|
395
|
+
] });
|
|
17
396
|
}
|
|
18
397
|
const CategoryDisabledContext = createContext(false);
|
|
19
398
|
function CategoryDisabledProvider({
|
|
@@ -90,8 +469,8 @@ function Category({
|
|
|
90
469
|
{
|
|
91
470
|
className: "categoryChevronIcon",
|
|
92
471
|
"data-collapsed": collapsed ? "true" : "false",
|
|
93
|
-
width: "
|
|
94
|
-
height: "
|
|
472
|
+
width: "14",
|
|
473
|
+
height: "14",
|
|
95
474
|
viewBox: "0 0 12 12",
|
|
96
475
|
"aria-hidden": true,
|
|
97
476
|
children: /* @__PURE__ */ jsx(
|
|
@@ -153,8 +532,9 @@ function Category({
|
|
|
153
532
|
opacity: collapsed ? { duration: 0.09, ease: "easeIn" } : { duration: 0.15, ease: "easeOut" }
|
|
154
533
|
},
|
|
155
534
|
style: {
|
|
156
|
-
|
|
157
|
-
|
|
535
|
+
// Keep overdrag visible while open, but fully clip collapsed content so
|
|
536
|
+
// the last category cannot leak height into panel measurements.
|
|
537
|
+
overflow: collapsed ? "hidden" : "visible",
|
|
158
538
|
minHeight: 0,
|
|
159
539
|
boxSizing: "border-box"
|
|
160
540
|
},
|
|
@@ -1210,6 +1590,14 @@ function normalizeHex(raw) {
|
|
|
1210
1590
|
}
|
|
1211
1591
|
return `#${h2.toUpperCase()}`;
|
|
1212
1592
|
}
|
|
1593
|
+
function sanitizeHexDigits(raw) {
|
|
1594
|
+
return raw.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
1595
|
+
}
|
|
1596
|
+
function expandHexDigitsToSix(raw) {
|
|
1597
|
+
const digits = sanitizeHexDigits(raw);
|
|
1598
|
+
if (!digits) return null;
|
|
1599
|
+
return digits.repeat(Math.ceil(6 / digits.length)).slice(0, 6).toUpperCase();
|
|
1600
|
+
}
|
|
1213
1601
|
function hslToHex(h2, s, l2) {
|
|
1214
1602
|
const [r, g, b2] = hslToRgbBytes(h2, s, l2);
|
|
1215
1603
|
const toHex = (v2) => v2.toString(16).padStart(2, "0");
|
|
@@ -1447,12 +1835,6 @@ function clampHueDeg(h2) {
|
|
|
1447
1835
|
function clampInt(n2, min, max) {
|
|
1448
1836
|
return Math.max(min, Math.min(max, Math.round(n2)));
|
|
1449
1837
|
}
|
|
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
1838
|
function clampHsv01(base) {
|
|
1457
1839
|
return { h: clampHueDeg(base.h), s: clamp01(base.s), v: clamp01(base.v) };
|
|
1458
1840
|
}
|
|
@@ -1796,11 +2178,11 @@ function ColorPicker({ value, onChange }) {
|
|
|
1796
2178
|
value: hex.slice(1),
|
|
1797
2179
|
prefix: "#",
|
|
1798
2180
|
onCommit: (val) => {
|
|
1799
|
-
const
|
|
1800
|
-
if (
|
|
2181
|
+
const expanded = expandHexDigitsToSix(val);
|
|
2182
|
+
if (expanded) onChange(`#${expanded}`);
|
|
1801
2183
|
},
|
|
1802
|
-
sanitize:
|
|
1803
|
-
validate:
|
|
2184
|
+
sanitize: sanitizeHexDigits,
|
|
2185
|
+
validate: (v2) => sanitizeHexDigits(v2).length > 0,
|
|
1804
2186
|
maxLength: 6,
|
|
1805
2187
|
inputMode: "text",
|
|
1806
2188
|
ariaLabel: `Edit hex color, ${hex}`,
|
|
@@ -1811,7 +2193,7 @@ function ColorPicker({ value, onChange }) {
|
|
|
1811
2193
|
onChange(parsed);
|
|
1812
2194
|
return "";
|
|
1813
2195
|
}
|
|
1814
|
-
return
|
|
2196
|
+
return sanitizeHexDigits(pasted);
|
|
1815
2197
|
}
|
|
1816
2198
|
}
|
|
1817
2199
|
) : mode === "hsl" ? /* @__PURE__ */ jsxs("div", { className: "colorPickerTriplet", "aria-label": "HSL values", children: [
|
|
@@ -2048,20 +2430,15 @@ function hexDigits$1(hex) {
|
|
|
2048
2430
|
const n2 = normalizeHex(hex);
|
|
2049
2431
|
return n2.slice(1);
|
|
2050
2432
|
}
|
|
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
2433
|
function ColorRow({ label = "Color", value, onChange, disabled: disabledProp }) {
|
|
2058
2434
|
const categoryDisabled = useCategoryDisabled();
|
|
2059
2435
|
const disabled = Boolean(disabledProp || categoryDisabled);
|
|
2060
2436
|
const [hovered, setHovered] = useState(false);
|
|
2061
2437
|
const hex = normalizeHex(value);
|
|
2062
2438
|
const handleCommit = (sanitized) => {
|
|
2063
|
-
|
|
2064
|
-
|
|
2439
|
+
const expanded = expandHexDigitsToSix(sanitized);
|
|
2440
|
+
if (expanded) {
|
|
2441
|
+
onChange(`#${expanded}`);
|
|
2065
2442
|
}
|
|
2066
2443
|
};
|
|
2067
2444
|
const handlePaste = (pasted) => {
|
|
@@ -2083,8 +2460,8 @@ function ColorRow({ label = "Color", value, onChange, disabled: disabledProp })
|
|
|
2083
2460
|
value: hexDigits$1(hex),
|
|
2084
2461
|
prefix: "#",
|
|
2085
2462
|
onCommit: handleCommit,
|
|
2086
|
-
sanitize:
|
|
2087
|
-
validate:
|
|
2463
|
+
sanitize: sanitizeHexDigits,
|
|
2464
|
+
validate: (v2) => sanitizeHexDigits(v2).length > 0,
|
|
2088
2465
|
maxLength: 6,
|
|
2089
2466
|
inputMode: "text",
|
|
2090
2467
|
ariaLabel: `Edit hex color, ${hex}`,
|
|
@@ -2256,9 +2633,6 @@ function generateAestheticGradient(stopCount) {
|
|
|
2256
2633
|
function hexDigits(hex) {
|
|
2257
2634
|
return normalizeHex(hex).slice(1);
|
|
2258
2635
|
}
|
|
2259
|
-
function isValidSixHex(d2) {
|
|
2260
|
-
return /^[0-9a-fA-F]{6}$/.test(d2);
|
|
2261
|
-
}
|
|
2262
2636
|
function stopsToGradient(stops, angle = 90) {
|
|
2263
2637
|
if (stops.length === 0) return "linear-gradient(90deg, #808080, #808080)";
|
|
2264
2638
|
if (stops.length === 1) {
|
|
@@ -2293,19 +2667,16 @@ const DEFAULT_GRADIENT_STOPS = [
|
|
|
2293
2667
|
{ color: "#42C0B0" },
|
|
2294
2668
|
{ color: "#BAC9C7" }
|
|
2295
2669
|
];
|
|
2296
|
-
function sanitizeHex(input) {
|
|
2297
|
-
return input.replace(/[^0-9a-fA-F]/g, "").slice(0, 6);
|
|
2298
|
-
}
|
|
2299
2670
|
function StopRow({ index, stop, canDelete, onColorChange, onDelete }) {
|
|
2300
2671
|
const hex = normalizeHex(stop.color);
|
|
2301
2672
|
const handleCommit = (val) => {
|
|
2302
|
-
const
|
|
2303
|
-
if (
|
|
2304
|
-
onColorChange(`#${
|
|
2673
|
+
const expanded = expandHexDigitsToSix(val);
|
|
2674
|
+
if (expanded) {
|
|
2675
|
+
onColorChange(`#${expanded}`);
|
|
2305
2676
|
}
|
|
2306
2677
|
};
|
|
2307
2678
|
const handlePaste = (pasted) => {
|
|
2308
|
-
return
|
|
2679
|
+
return sanitizeHexDigits(pasted);
|
|
2309
2680
|
};
|
|
2310
2681
|
return /* @__PURE__ */ jsxs("div", { className: "gradientPickerStop", children: [
|
|
2311
2682
|
/* @__PURE__ */ jsxs("div", { className: "gradientPickerStopColorHex", children: [
|
|
@@ -2336,8 +2707,8 @@ function StopRow({ index, stop, canDelete, onColorChange, onDelete }) {
|
|
|
2336
2707
|
value: hexDigits(hex),
|
|
2337
2708
|
prefix: "#",
|
|
2338
2709
|
onCommit: handleCommit,
|
|
2339
|
-
sanitize:
|
|
2340
|
-
validate:
|
|
2710
|
+
sanitize: sanitizeHexDigits,
|
|
2711
|
+
validate: (v2) => sanitizeHexDigits(v2).length > 0,
|
|
2341
2712
|
maxLength: 6,
|
|
2342
2713
|
inputMode: "text",
|
|
2343
2714
|
ariaLabel: "Hex color without hash",
|