UNPKG

aura-glass

Version:

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

760 lines (757 loc) 27.9 kB
'use client'; import { jsxs, jsx, Fragment } from 'react/jsx-runtime'; import React, { memo, useState, useRef, useCallback, useEffect } from 'react'; import { useMotionAwareAnimation, useAnimationDuration } from '../../hooks/useMotionPreference.js'; import { cn } from '../../lib/utilsComprehensive.js'; import { useMotionValue, useSpring, useTransform, motion } from 'framer-motion'; // Memoized icons for handle indicators to prevent unnecessary re-renders const ChevronLeftIcon = /*#__PURE__*/memo(() => jsx("svg", { className: 'w-3 h-3', fill: "currentColor", viewBox: "0 0 20 20", children: jsx("path", { fillRule: "evenodd", d: "M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z", clipRule: "evenodd" }) })); const ChevronRightIcon = /*#__PURE__*/memo(() => jsx("svg", { className: 'w-3 h-3', fill: "currentColor", viewBox: "0 0 20 20", children: jsx("path", { fillRule: "evenodd", d: "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", clipRule: "evenodd" }) })); const ChevronUpIcon = /*#__PURE__*/memo(() => jsx("svg", { className: 'w-3 h-3', fill: "currentColor", viewBox: "0 0 20 20", children: jsx("path", { fillRule: "evenodd", d: "M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z", clipRule: "evenodd" }) })); const ChevronDownIcon = /*#__PURE__*/memo(() => jsx("svg", { className: 'w-3 h-3', fill: "currentColor", viewBox: "0 0 20 20", children: jsx("path", { fillRule: "evenodd", d: "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z", clipRule: "evenodd" }) })); // Preset positions for common comparisons const SLIDER_PRESETS = { BEFORE_ONLY: 0, QUARTER: 25, HALF: 50, THREE_QUARTER: 75, AFTER_ONLY: 100 }; const GlassWipeSliderComponent = ({ beforeContent, afterContent, className, initialPosition = 50, orientation = "horizontal", enableSnapping = true, snapThreshold = 5, enableMomentum = true, momentumMultiplier = 0.3, debounceMs = 16, handleSize = "md", showLabels = true, showProgress = true, showMetrics = false, labels = { before: "Before", after: "After" }, metrics = [], trackStyle = "default", gradientOverlay = true, height = "24rem", // h-96 minHeight, onPositionChange, onSnapToPreset, onDragStart, onDragEnd }) => { // Motion-aware hooks const { getAnimationProps, getTransition } = useMotionAwareAnimation(); const { duration } = useAnimationDuration(200); // State management const [position, setPosition] = useState(initialPosition); const [isDragging, setIsDragging] = useState(false); const [isHovered, setIsHovered] = useState(false); const [isFocused, setIsFocused] = useState(false); const [velocity, setVelocity] = useState(0); // Refs const containerRef = useRef(null); const handleRef = useRef(null); const lastUpdateTime = useRef(Date.now()); const lastPosition = useRef(initialPosition); const animationFrame = useRef(null); const debounceTimeout = useRef(null); // Memoized motion configuration to prevent unnecessary spring recreations const springConfig = { stiffness: 300, damping: 30 }; // Motion values for smooth animations const motionX = useMotionValue(initialPosition); const motionY = useMotionValue(initialPosition); const springX = useSpring(motionX, springConfig); const springY = useSpring(motionY, springConfig); useTransform(orientation === "horizontal" ? springX : springY, [0, 100], ["translateX(-50%) translateY(-50%)", "translateX(-50%) translateY(-50%)"]); // Memoized preset values to prevent recreation on every render const presetValues = React.useMemo(() => Object.values(SLIDER_PRESETS), []); // Optimized snap to preset positions const snapToNearestPreset = useCallback(currentPos => { if (!enableSnapping) return currentPos; const nearest = presetValues.reduce((prev, curr) => Math.abs(curr - currentPos) < Math.abs(prev - currentPos) ? curr : prev); if (Math.abs(nearest - currentPos) <= snapThreshold) { onSnapToPreset?.(nearest); return nearest; } return currentPos; }, [enableSnapping, snapThreshold, onSnapToPreset, presetValues]); // Apply momentum when drag ends const applyMomentum = useCallback(() => { if (!enableMomentum || Math.abs(velocity) < 0.1) return; const startPos = position; const targetPos = Math.max(0, Math.min(100, position + velocity * momentumMultiplier * 10)); const snappedPos = snapToNearestPreset(targetPos); // Animate to final position const startTime = Date.now(); const duration = Math.min(800, Math.abs(snappedPos - startPos) * 20); const animate = () => { const elapsed = Date.now() - startTime; const progress = Math.min(elapsed / duration, 1); // Easing function (ease-out cubic) const easedProgress = 1 - Math.pow(1 - progress, 3); const currentPos = startPos + (snappedPos - startPos) * easedProgress; setPosition(currentPos); motionX.set(currentPos); motionY.set(currentPos); if (progress < 1) { animationFrame.current = requestAnimationFrame(animate); } else { setVelocity(0); } }; animationFrame.current = requestAnimationFrame(animate); }, [position, velocity, enableMomentum, momentumMultiplier, snapToNearestPreset]); const handleMouseDown = e => { e.preventDefault(); setIsDragging(true); onDragStart?.(); if (animationFrame.current) { cancelAnimationFrame(animationFrame.current); } const clientPos = orientation === "horizontal" ? e.clientX : e.clientY; handleMove(clientPos); // Reset velocity tracking lastUpdateTime.current = Date.now(); lastPosition.current = position; }; // Optimized handle move with better performance const handleMove = useCallback(clientPos => { if (!containerRef.current) return; const rect = containerRef.current.getBoundingClientRect(); const size = orientation === "horizontal" ? rect.width : rect.height; const offset = orientation === "horizontal" ? clientPos - rect.left : clientPos - rect.top; const newPosition = offset / size * 100; const clampedPosition = Math.max(0, Math.min(100, newPosition)); // Calculate velocity for momentum (optimized) const now = Date.now(); const timeDelta = now - lastUpdateTime.current; if (timeDelta > 0) { const positionDelta = clampedPosition - lastPosition.current; setVelocity(positionDelta / timeDelta); lastUpdateTime.current = now; lastPosition.current = clampedPosition; } setPosition(clampedPosition); motionX.set(clampedPosition); motionY.set(clampedPosition); // Debounced callback with cleanup if (debounceTimeout.current) { clearTimeout(debounceTimeout.current); } debounceTimeout.current = setTimeout(() => { onPositionChange?.(clampedPosition); }, debounceMs); }, [orientation, onPositionChange, debounceMs]); useEffect(() => { const handleMouseMove = e => { if (isDragging) { const clientPos = orientation === "horizontal" ? e.clientX : e.clientY; handleMove(clientPos); } }; const handleMouseUp = () => { if (isDragging) { setIsDragging(false); onDragEnd?.(); // Apply momentum and snapping setTimeout(() => { applyMomentum(); }, 0); } }; const handleTouchMove = e => { if (isDragging && e.touches?.[0]) { e.preventDefault(); const touch = e.touches?.[0]; const clientPos = orientation === "horizontal" ? touch.clientX : touch.clientY; handleMove(clientPos); } }; if (isDragging) { document.addEventListener("mousemove", handleMouseMove, { passive: false }); document.addEventListener("mouseup", handleMouseUp); document.addEventListener("touchmove", handleTouchMove, { passive: false }); document.addEventListener("touchend", handleMouseUp); } return () => { document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("mouseup", handleMouseUp); document.removeEventListener("touchmove", handleTouchMove); document.removeEventListener("touchend", handleMouseUp); }; }, [isDragging, handleMove, orientation, applyMomentum, onDragEnd]); const handleTouchStart = e => { e.preventDefault(); setIsDragging(true); onDragStart?.(); if (animationFrame.current) { cancelAnimationFrame(animationFrame.current); } if (e.touches?.[0]) { const touch = e.touches?.[0]; const clientPos = orientation === "horizontal" ? touch.clientX : touch.clientY; handleMove(clientPos); // Reset velocity tracking lastUpdateTime.current = Date.now(); lastPosition.current = position; } }; const handleKeyDown = e => { const step = e.shiftKey ? 10 : e.ctrlKey || e.metaKey ? 25 : 1; let newPosition = position; let shouldSnap = false; switch (e.key) { case "ArrowLeft": case "ArrowUp": e.preventDefault(); newPosition = Math.max(0, position - step); break; case "ArrowRight": case "ArrowDown": e.preventDefault(); newPosition = Math.min(100, position + step); break; case "Home": e.preventDefault(); newPosition = SLIDER_PRESETS.BEFORE_ONLY; shouldSnap = true; break; case "End": e.preventDefault(); newPosition = SLIDER_PRESETS.AFTER_ONLY; shouldSnap = true; break; case "PageUp": e.preventDefault(); newPosition = SLIDER_PRESETS.QUARTER; shouldSnap = true; break; case "PageDown": e.preventDefault(); newPosition = SLIDER_PRESETS.THREE_QUARTER; shouldSnap = true; break; case " ": case "Enter": e.preventDefault(); newPosition = SLIDER_PRESETS.HALF; shouldSnap = true; break; case "0": case "1": case "2": case "3": case "4": case "5": e.preventDefault(); const presetIndex = parseInt(e.key); const presetValues = Object.values(SLIDER_PRESETS); if (presetIndex < (presetValues?.length || 0)) { newPosition = presetValues[presetIndex]; shouldSnap = true; } break; } if (newPosition !== position) { setPosition(newPosition); motionX.set(newPosition); motionY.set(newPosition); onPositionChange?.(newPosition); if (shouldSnap) { onSnapToPreset?.(newPosition); } } }; // Memoized handle size variants to prevent recreation const handleSizes = React.useMemo(() => ({ sm: "w-10 h-10", md: "w-12 h-12", lg: "w-14 h-14" }), []); // Memoized dynamic styles based on props const containerStyles = React.useMemo(() => ({ height: typeof height === "string" ? height : `${height}px`, minHeight: minHeight ? typeof minHeight === "string" ? minHeight : `${minHeight}px` : undefined }), [height, minHeight]); // Clean up on unmount useEffect(() => { return () => { if (animationFrame.current) { cancelAnimationFrame(animationFrame.current); } if (debounceTimeout.current) { clearTimeout(debounceTimeout.current); } }; }, []); // Memoized computed values for better performance const computedValues = React.useMemo(() => { const isVertical = orientation === "vertical"; const cursorClass = isVertical ? "cursor-row-resize" : "cursor-col-resize"; const clipPath = isVertical ? `inset(${100 - position}% 0 0 0)` : `inset(0 ${100 - position}% 0 0)`; return { isVertical, cursorClass, clipPath }; }, [orientation, position]); const { isVertical, cursorClass, clipPath } = computedValues; return jsxs("div", { ref: containerRef, className: cn("relative w-full overflow-hidden glass-radius-lg select-none glass-card-motion-aware", cursorClass, { "h-96": !height || height === "24rem" }, className), style: containerStyles, role: "slider", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(position), "aria-label": `${labels.before} vs ${labels.after} comparison slider. Use arrow keys, Home, End, or number keys 0-5 for presets.`, "aria-describedby": showMetrics && (metrics?.length || 0) > 0 ? "slider-metrics" : undefined, tabIndex: 0, onKeyDown: handleKeyDown, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), onFocus: () => setIsFocused(true), onBlur: () => setIsFocused(false), children: [jsx("div", { className: 'absolute inset-0 glass-w-full glass-h-full', children: beforeContent }), jsx("div", { className: 'absolute inset-0 overflow-hidden transition-all duration-75 ease-out', style: { clipPath, ...(isVertical ? { width: "100%", height: "100%" } : { width: "100%", height: "100%" }) }, children: afterContent }), gradientOverlay && jsx("div", { className: 'absolute pointer-events-none transition-opacity duration-300', style: { ...(isVertical ? { top: `${position}%`, left: 0, right: 0, height: "20px", transform: "translateY(-50%)", background: '/* Use createGlassStyle({ intent: "primary", elevation: "level2" }) */' } : { left: `${position}%`, top: 0, bottom: 0, width: "20px", transform: "translateX(-50%)", background: '/* Use createGlassStyle({ intent: "primary", elevation: "level2" }) */' }), opacity: isHovered || isDragging ? 0.5 : 0.2 } }), jsxs("div", { className: cn("absolute glass-backdrop-blur-md shadow-lg transition-all duration-200 ease-out", { // Horizontal orientation "top-0 bottom-0 bg-gradient-to-b from-white/40 via-white/60 to-white/40": !isVertical, "w-0.5": !isVertical && trackStyle === "minimal", "w-1": !isVertical && trackStyle === "default", "w-2": !isVertical && trackStyle === "bold", // Vertical orientation "left-0 right-0 bg-gradient-to-r from-white/40 via-white/60 to-white/40": isVertical, "h-0.5": isVertical && trackStyle === "minimal", "h-1": isVertical && trackStyle === "default", "h-2": isVertical && trackStyle === "bold" }), style: { ...(isVertical ? { top: `${position}%`, transform: "translateY(-50%)" } : { left: `${position}%`, transform: "translateX(-50%)" }), boxShadow: isDragging || isHovered ? '0 0 20px ${glassStyles.borderColor || "var(--glass-color-primary, 0.6)"}' : '0 0 10px ${glassStyles.borderColor || "var(--glass-bg-hover)"}' }, children: [jsx("div", { className: cn("absolute inset-0", isVertical ? "bg-gradient-to-t from-transparent via-white/20 to-transparent" : "bg-gradient-to-r from-transparent via-white/20 to-transparent") }), jsx("div", { className: cn("absolute inset-0 transition-opacity duration-300", isVertical ? "bg-gradient-to-t from-cyan-500/20 via-blue-500/30 to-cyan-500/20" : "bg-gradient-to-r from-cyan-500/20 via-blue-500/30 to-cyan-500/20"), style: { opacity: isDragging || isHovered ? 0.8 : 0 } })] }), jsx(motion.div, { ref: handleRef, className: cn("absolute cursor-grab active:cursor-grabbing touch-target z-20", handleSizes?.[handleSize], { "top-1/2 -translate-y-1/2": !isVertical, "left-1/2 -translate-x-1/2": isVertical }), style: { ...(isVertical ? { top: `${position}%`, transform: "translateY(-50%) translateX(-50%)" } : { left: `${position}%`, transform: "translateX(-50%) translateY(-50%)" }) }, onMouseDown: handleMouseDown, onTouchStart: handleTouchStart, ...getAnimationProps({ whileHover: { scale: 1.1 }, whileTap: { scale: 0.95 }, animate: { boxShadow: isDragging || isFocused ? '0 0 30px ${glassStyles.borderColor || "var(--glass-color-primary, 0.6)"}' : isHovered ? "0 0 25px var(--glass-border-default)" : '0 0 20px ${glassStyles.borderColor || "var(--glass-bg-hover)"}' } }), transition: getTransition(duration / 1000), children: jsxs("div", { className: 'glass-w-full glass-h-full glass-radius-full glass-foundation-complete bg-glass-gradient-strong glass-glass-backdrop-blur-md-medium glass-border glass-border-white/30 glass-flex glass-items-center glass-justify-center group relative overflow-hidden glass-contrast-guard', children: [jsx("div", { className: cn("flex items-center glass-gap-1 glass-text-primary/70 group-hover:glass-text-primary/90 transition-colors duration-200 relative z-10", isVertical ? "flex-col" : "flex-row"), children: isVertical ? jsxs(Fragment, { children: [jsx(ChevronUpIcon, {}), jsx("div", { className: 'w-1 h-1 glass-radius-full bg-transparent opacity-50' }), jsx(ChevronDownIcon, {})] }) : jsxs(Fragment, { children: [jsx(ChevronLeftIcon, {}), jsx("div", { className: 'w-1 h-1 glass-radius-full bg-transparent opacity-50' }), jsx(ChevronRightIcon, {})] }) }), jsx("div", { className: 'absolute inset-0 glass-radius-full glass-gradient-primary glass-gradient-primary glass-gradient-primary opacity-0 group-hover:opacity-100 transition-opacity duration-300' }), jsx("div", { className: 'absolute inset-0 glass-radius-full glass-gradient-primary glass-gradient-primary glass-gradient-primary transition-opacity duration-200', style: { opacity: isDragging ? 0.7 : 0 } }), isFocused && jsx("div", { className: 'absolute -inset-1 glass-radius-full glass-border-2 glass-border-blue/50 animate-pulse' }), jsx("div", { className: 'absolute inset-0 glass-radius-full glass-surface-subtle/20 scale-0 transition-transform duration-200', style: { transform: isDragging ? "scale(1.5)" : "scale(0)", opacity: isDragging ? 0.3 : 0 } })] }) }), showLabels && jsxs(Fragment, { children: [jsxs(motion.div, { className: cn("absolute chip chip-muted glass-text-sm pointer-events-none z-10", isVertical ? "top-4 left-1/2 transform -translate-x-1/2" : "top-4 left-4"), ...getAnimationProps({ initial: { opacity: 0, scale: 0.9 }, animate: { opacity: 1, scale: 1 } }), transition: getTransition(0.3, "ease-out"), children: [jsx("div", { className: 'font-medium', children: labels.after }), labels.afterDescription && jsx("div", { className: 'glass-text-xs text-primary/60 glass-mt-0-5', children: labels.afterDescription })] }), jsxs(motion.div, { className: cn("absolute chip chip-muted glass-text-sm pointer-events-none z-10", isVertical ? "bottom-4 left-1/2 transform -translate-x-1/2" : "top-4 right-4"), ...getAnimationProps({ initial: { opacity: 0, scale: 0.9 }, animate: { opacity: 1, scale: 1 } }), transition: getTransition(0.3, "ease-out"), children: [jsx("div", { className: 'font-medium', children: labels.before }), labels.beforeDescription && jsx("div", { className: 'glass-text-xs text-primary/60 glass-mt-0-5', children: labels.beforeDescription })] })] }), showProgress && jsx(motion.div, { className: cn("absolute chip chip-muted glass-text-xs pointer-events-none z-10", isVertical ? "bottom-4 right-4" : "bottom-4 left-1/2 transform -translate-x-1/2"), ...getAnimationProps({ initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 } }), transition: getTransition(0.3, "ease-out"), children: jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [jsxs("div", { className: 'font-mono font-medium', children: [Math.round(position), "%"] }), enableSnapping && jsx("div", { className: 'w-1 h-1 glass-radius-full glass-surface-subtle/40' })] }) }), enableSnapping && jsx("div", { className: 'absolute inset-0 pointer-events-none z-5', children: Object.entries(SLIDER_PRESETS).map(([key, value]) => jsx("div", { className: cn("absolute w-2 h-2 glass-radius-full bg-white/30 glass-backdrop-blur-md border border-white/20 transition-all duration-200", Math.abs(position - value) <= snapThreshold ? "glass-surface-primary/60 scale-125" : ""), style: { ...(isVertical ? { top: `${value}%`, left: "50%", transform: "translateX(-50%) translateY(-50%)" } : { left: `${value}%`, top: "50%", transform: "translateX(-50%) translateY(-50%)" }) } }, key)) }), showMetrics && (metrics?.length || 0) > 0 && jsx("div", { id: "slider-metrics", className: cn("absolute glass-foundation-complete bg-glass-gradient-strong glass-backdrop-blur-md-medium border border-white/20 glass-radius-lg glass-p-4 z-10 max-w-sm", isVertical ? "top-1/2 right-4 transform -translate-y-1/2" : "top-4 left-1/2 transform -translate-x-1/2"), style: { opacity: isHovered || isDragging || isFocused ? 0.95 : 0.7 }, children: jsx("div", { className: "glass-auto-gap glass-auto-gap-sm", children: metrics.map((metric, index) => jsxs("div", { className: cn("flex items-center justify-between glass-text-sm", metric?.highlight ? "glass-text-primary font-semibold" : "glass-text-primary/80"), children: [jsx("span", { className: 'font-medium', children: metric?.label }), jsxs("div", { className: 'glass-flex glass-items-center glass-gap-2 font-mono', children: [jsxs("span", { className: "glass-text-danger", children: [metric?.beforeValue, metric?.unit] }), jsx("span", { className: 'text-primary/50', children: "\u2192" }), jsxs("span", { className: "glass-text-success", children: [metric?.afterValue, metric?.unit] })] })] }, index)) }) }), jsx("div", { className: 'sr-only', children: "Use arrow keys to adjust the comparison. Press Home for 0%, End for 100%, Space for 50%. Number keys 0-5 jump to preset positions. Shift+arrows for larger steps." })] }); }; // Export optimized memoized component const GlassWipeSlider = /*#__PURE__*/memo(GlassWipeSliderComponent); // Comparison content components for common use cases function ComparisonImage({ src, alt, className, loading = "lazy" }) { return jsx("img", { src: src, alt: alt, width: 1200, height: 800, className: cn("w-full h-full object-cover transition-all duration-300", className), loading: loading }); } function ComparisonContent({ children, className, background = "gradient" }) { const backgroundClasses = { gradient: "bg-gradient-to-br from-slate-900 via-blue-900 to-slate-900", solid: "glass-surface-primary", glass: "glass-foundation-complete bg-glass-gradient-subtle glass-backdrop-blur-md-medium", transparent: "bg-transparent" }; return jsx("div", { className: cn("w-full h-full flex items-center justify-center p-8 transition-all duration-300", backgroundClasses?.[background], className), children: children }); } // Pre-built comparison layouts function FeatureComparison({ beforeFeatures, afterFeatures, title, className }) { return jsx(ComparisonContent, { className: className, background: "glass", children: jsxs("div", { className: 'glass-w-full max-w-md glass-auto-gap glass-auto-gap-lg', children: [title && jsx("h3", { className: 'glass-text-lg font-semibold text-primary text-center mb-6', children: title }), jsx("div", { className: "glass-auto-gap glass-auto-gap-sm", children: beforeFeatures.map((feature, index) => { const afterFeature = afterFeatures?.[index]; return jsxs("div", { className: 'glass-flex glass-items-center glass-justify-between glass-py-2 glass-px-3 surface-1', children: [jsx("span", { className: cn("glass-text-sm", feature.highlight ? "glass-text-primary font-medium" : "glass-text-primary/90"), children: feature.name }), jsxs("div", { className: "glass-flex glass-items-center glass-gap-3", children: [jsx("div", { className: cn("w-2 h-2 glass-radius-full", feature.available ? "glass-surface-success" : "glass-surface-danger") }), afterFeature && jsxs(Fragment, { children: [jsx("span", { className: 'text-primary/40', children: "\u2192" }), jsx("div", { className: cn("w-2 h-2 glass-radius-full", afterFeature.available ? "glass-surface-success" : "glass-surface-danger") })] })] })] }, feature.name); }) })] }) }); } // Usage examples for AuraOne vs competitors const AURAONE_COMPARISON_EXAMPLES = { SCALE_AI: { labels: { before: "Scale AI", after: "AuraOne", beforeDescription: "Traditional approach", afterDescription: "Next-gen platform" }, metrics: [{ label: "Model Training Speed", beforeValue: "2-4", afterValue: "< 1", unit: " weeks", highlight: true }, { label: "Accuracy Improvement", beforeValue: "85", afterValue: "97", unit: "%", highlight: true }, { label: "Infrastructure Cost", beforeValue: "$10K", afterValue: "$2K", unit: "/month", highlight: true }, { label: "Setup Complexity", beforeValue: "High", afterValue: "Low", unit: "" }] }, OPENAI_GYM: { labels: { before: "OpenAI Gym", after: "AuraOne", beforeDescription: "Research-focused", afterDescription: "Production-ready" }, metrics: [{ label: "Environment Setup", beforeValue: "Hours", afterValue: "Minutes", unit: "", highlight: true }, { label: "Scalability", beforeValue: "Limited", afterValue: "Unlimited", unit: "", highlight: true }, { label: "Production Features", beforeValue: "Basic", afterValue: "Enterprise", unit: "", highlight: true }] } }; export { AURAONE_COMPARISON_EXAMPLES, ComparisonContent, ComparisonImage, FeatureComparison, GlassWipeSlider, SLIDER_PRESETS }; //# sourceMappingURL=GlassWipeSlider.js.map