UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

139 lines (136 loc) 4.8 kB
'use client'; import { jsxs, jsx } from 'react/jsx-runtime'; import React, { forwardRef } from 'react'; import { cn } from '../../lib/utilsComprehensive.js'; import { useA11yId } from '../../utils/a11y.js'; import { useMotionPreferenceContext } from '../../contexts/MotionPreferenceContext.js'; /** * GlassSplitPane component * Resizable split pane with glassmorphism styling */ const GlassSplitPane = /*#__PURE__*/forwardRef(({ // TODO: Integrate ContrastGuard for any section titles, labels, and helper text for WCAG AA compliance direction = "horizontal", initial = 50, min = 20, max = 80, left, right, respectMotionPreference = true, "aria-label": ariaLabel = "Split pane", onSplitChange, className, ...props }, ref) => { const [pct, setPct] = React.useState(initial); const dragging = React.useRef(false); const splitPaneId = useA11yId(); const separatorId = useA11yId(); const splitPaneLabelId = useA11yId("split-pane-label"); const leftPaneLabelId = useA11yId("split-pane-left"); const rightPaneLabelId = useA11yId("split-pane-right"); const { prefersReducedMotion } = useMotionPreferenceContext(); const shouldRespectMotion = respectMotionPreference && !prefersReducedMotion; const onDown = () => dragging.current = true; const onUp = () => dragging.current = false; const onMove = React.useCallback(e => { if (!dragging.current) return; let newPct; if (direction === "horizontal") { newPct = e.clientX / window.innerWidth * 100; } else { newPct = e.clientY / window.innerHeight * 100; } const clampedPct = Math.max(min, Math.min(max, newPct)); setPct(clampedPct); onSplitChange?.(clampedPct); }, [direction, min, max, onSplitChange]); React.useEffect(() => { window.addEventListener("mousemove", onMove); window.addEventListener("mouseup", onUp); return () => { window.removeEventListener("mousemove", onMove); window.removeEventListener("mouseup", onUp); }; }, [onMove]); // Keyboard support for separator const handleKeyDown = e => { const step = 5; // 5% steps let newPct = pct; switch (e.key) { case "ArrowLeft": case "ArrowUp": newPct = Math.max(min, pct - step); break; case "ArrowRight": case "ArrowDown": newPct = Math.min(max, pct + step); break; case "Home": newPct = min; break; case "End": newPct = max; break; default: return; } e.preventDefault(); setPct(newPct); onSplitChange?.(newPct); }; return jsxs("div", { ref: ref, id: splitPaneId, className: cn("relative w-full h-full", direction === "horizontal" ? "grid grid-cols-[var(--a)_12px_1fr]" : "grid grid-rows-[var(--a)_12px_1fr]", // Motion preferences shouldRespectMotion && "motion-safe:transition-all motion-reduce:transition-none", className), style: { // @ts-ignore custom var ["--a"]: `${pct}%` }, role: "group", "aria-labelledby": splitPaneLabelId, ...props, children: [jsx("span", { id: splitPaneLabelId, className: "sr-only", children: ariaLabel }), jsxs("div", { className: 'glass-min-w-0 glass-min-h-0 overflow-auto', role: "region", "aria-labelledby": leftPaneLabelId, children: [jsx("span", { id: leftPaneLabelId, className: "sr-only", children: direction === "horizontal" ? "Left pane" : "Top pane" }), left] }), jsx("div", { id: separatorId, role: "separator", tabIndex: 0, "aria-orientation": direction === "horizontal" ? "vertical" : "horizontal", "aria-valuenow": pct, "aria-valuemin": min, "aria-valuemax": max, "aria-label": `Resize ${direction === "horizontal" ? "vertical" : "horizontal"} split. Currently at ${Math.round(pct)}%`, onMouseDown: onDown, onKeyDown: handleKeyDown, className: cn("select-none glass-radius-full focus:outline-none focus:ring-2 focus:ring-primary/50", direction === "horizontal" ? "w-3 h-full cursor-col-resize" : "h-3 w-full cursor-row-resize", "bg-white/10", shouldRespectMotion ? "hover:bg-white/20 transition-colors duration-200" : "hover:bg-white/20", dragging.current && "bg-white/30") }), jsxs("div", { className: 'glass-min-w-0 glass-min-h-0 overflow-auto', role: "region", "aria-labelledby": rightPaneLabelId, children: [jsx("span", { id: rightPaneLabelId, className: "sr-only", children: direction === "horizontal" ? "Right pane" : "Bottom pane" }), right] })] }); }); GlassSplitPane.displayName = "GlassSplitPane"; export { GlassSplitPane, GlassSplitPane as default }; //# sourceMappingURL=GlassSplitPane.js.map