"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TailwindSlider = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const cn_js_1 = require("../utils/cn.js");
/**
 * Slider component built with Tailwind CSS
 *
 * A customizable slider with various options like markers, tooltips, and different sizes.
 *
 * @example
 * // Basic usage
 * <TailwindSlider defaultValue={50} />
 *
 * @example
 * // With markers and tooltip
 * <TailwindSlider
 *   min={0}
 *   max={100}
 *   step={10}
 *   markers={[0, 25, 50, 75, 100]}
 *   showTooltip
 * />
 *
 * @example
 * // With custom color and size
 * <TailwindSlider
 *   defaultValue={75}
 *   colorScheme="success"
 *   size="lg"
 * />
 */
exports.TailwindSlider = (0, react_1.forwardRef)(({ value: propValue, defaultValue = 0, onChange, onChangeStart, onChangeEnd, min = 0, max = 100, step = 1, size = 'md', isDisabled = false, showThumb = true, showTooltip = false, formatTooltip, markers = [], isInverted = false, showLabel = false, label, colorScheme = 'primary', trackClassName, filledTrackClassName, thumbClassName, markerClassName, className, ...props }, ref) => {
    // State for controlled and uncontrolled usage
    const [localValue, setLocalValue] = (0, react_1.useState)(defaultValue);
    const value = propValue !== undefined ? propValue : localValue;
    // State for dragging
    const [isDragging, setIsDragging] = (0, react_1.useState)(false);
    const [showTooltipValue, setShowTooltipValue] = (0, react_1.useState)(showTooltip);
    // Refs
    const trackRef = (0, react_1.useRef)(null);
    const thumbRef = (0, react_1.useRef)(null);
    // Calculate the percentage for styling and positioning
    const getPercentage = (0, react_1.useCallback)((value) => {
        return ((value - min) / (max - min)) * 100;
    }, [min, max]);
    const percentage = getPercentage(value);
    // Format tooltip value
    const formattedValue = formatTooltip ? formatTooltip(value) : value.toString();
    // Size classes
    const sizeClasses = {
        track: {
            sm: 'h-1',
            md: 'h-2',
            lg: 'h-3',
        },
        thumb: {
            sm: 'h-3 w-3',
            md: 'h-4 w-4',
            lg: 'h-5 w-5',
        },
        tooltip: {
            sm: 'text-xs py-0.5 px-1',
            md: 'text-sm py-1 px-2',
            lg: 'text-base py-1 px-2',
        },
        marker: {
            sm: 'h-2 w-2',
            md: 'h-2.5 w-2.5',
            lg: 'h-3 w-3',
        },
    };
    // Color classes
    const colorClasses = {
        primary: {
            filled: 'bg-primary-500 dark:bg-primary-400',
            thumb: 'bg-primary-500 dark:bg-primary-400 border-primary-500 dark:border-primary-400',
            focus: 'focus:ring-primary-500 dark:focus:ring-primary-400',
        },
        secondary: {
            filled: 'bg-gray-500 dark:bg-gray-400',
            thumb: 'bg-gray-500 dark:bg-gray-400 border-gray-500 dark:border-gray-400',
            focus: 'focus:ring-gray-500 dark:focus:ring-gray-400',
        },
        success: {
            filled: 'bg-green-500 dark:bg-green-400',
            thumb: 'bg-green-500 dark:bg-green-400 border-green-500 dark:border-green-400',
            focus: 'focus:ring-green-500 dark:focus:ring-green-400',
        },
        danger: {
            filled: 'bg-red-500 dark:bg-red-400',
            thumb: 'bg-red-500 dark:bg-red-400 border-red-500 dark:border-red-400',
            focus: 'focus:ring-red-500 dark:focus:ring-red-400',
        },
        warning: {
            filled: 'bg-yellow-500 dark:bg-yellow-400',
            thumb: 'bg-yellow-500 dark:bg-yellow-400 border-yellow-500 dark:border-yellow-400',
            focus: 'focus:ring-yellow-500 dark:focus:ring-yellow-400',
        },
        info: {
            filled: 'bg-blue-500 dark:bg-blue-400',
            thumb: 'bg-blue-500 dark:bg-blue-400 border-blue-500 dark:border-blue-400',
            focus: 'focus:ring-blue-500 dark:focus:ring-blue-400',
        },
    };
    // Handle mouse and touch events
    const handleChange = (0, react_1.useCallback)((newValue) => {
        // Ensure the value is within bounds and aligned to step
        const clampedValue = Math.max(min, Math.min(max, newValue));
        const steppedValue = Math.round((clampedValue - min) / step) * step + min;
        // Update local value if uncontrolled
        if (propValue === undefined) {
            setLocalValue(steppedValue);
        }
        // Invoke callback
        onChange?.(steppedValue);
    }, [propValue, min, max, step, onChange]);
    const updateValue = (0, react_1.useCallback)((event) => {
        if (!trackRef.current || isDisabled)
            return;
        const track = trackRef.current;
        const trackRect = track.getBoundingClientRect();
        // Get the client X from either mouse or touch event
        const clientX = 'touches' in event
            ? event.touches[0].clientX
            : event.clientX;
        // Calculate percentage
        const offset = clientX - trackRect.left;
        const percentage = offset / trackRect.width;
        // Calculate new value
        const newValue = isInverted
            ? max - percentage * (max - min)
            : percentage * (max - min) + min;
        handleChange(newValue);
    }, [handleChange, min, max, isDisabled, isInverted]);
    // Handle start dragging
    const handleDragStart = (0, react_1.useCallback)((event) => {
        if (isDisabled)
            return;
        // Set dragging state
        setIsDragging(true);
        setShowTooltipValue(true);
        // Invoke callback
        onChangeStart?.(value);
        // Update value on start
        updateValue(event.nativeEvent);
        // Prevent text selection while dragging
        event.preventDefault();
    }, [isDisabled, updateValue, value, onChangeStart]);
    // Handle end dragging
    const handleDragEnd = (0, react_1.useCallback)(() => {
        if (!isDragging)
            return;
        // Reset dragging state
        setIsDragging(false);
        // Reset tooltip visibility if it was not initially shown
        if (!showTooltip) {
            setShowTooltipValue(false);
        }
        // Invoke callback
        onChangeEnd?.(value);
    }, [isDragging, showTooltip, value, onChangeEnd]);
    // Add event listeners for dragging
    (0, react_1.useEffect)(() => {
        if (isDragging) {
            const handleMouseMove = (e) => {
                updateValue(e);
            };
            const handleTouchMove = (e) => {
                updateValue(e);
            };
            // Add document-level event listeners
            document.addEventListener('mousemove', handleMouseMove);
            document.addEventListener('mouseup', handleDragEnd);
            document.addEventListener('touchmove', handleTouchMove);
            document.addEventListener('touchend', handleDragEnd);
            document.addEventListener('touchcancel', handleDragEnd);
            // Cleanup
            return () => {
                document.removeEventListener('mousemove', handleMouseMove);
                document.removeEventListener('mouseup', handleDragEnd);
                document.removeEventListener('touchmove', handleTouchMove);
                document.removeEventListener('touchend', handleDragEnd);
                document.removeEventListener('touchcancel', handleDragEnd);
            };
        }
    }, [isDragging, updateValue, handleDragEnd]);
    // Keyboard interaction
    const handleKeyDown = (0, react_1.useCallback)((e) => {
        if (isDisabled)
            return;
        let newValue = value;
        switch (e.key) {
            case 'ArrowRight':
            case 'ArrowUp':
                newValue = Math.min(max, value + step);
                e.preventDefault();
                break;
            case 'ArrowLeft':
            case 'ArrowDown':
                newValue = Math.max(min, value - step);
                e.preventDefault();
                break;
            case 'Home':
                newValue = min;
                e.preventDefault();
                break;
            case 'End':
                newValue = max;
                e.preventDefault();
                break;
            case 'PageUp':
                newValue = Math.min(max, value + step * 10);
                e.preventDefault();
                break;
            case 'PageDown':
                newValue = Math.max(min, value - step * 10);
                e.preventDefault();
                break;
            default:
                return;
        }
        handleChange(newValue);
    }, [isDisabled, value, min, max, step, handleChange]);
    // Container classes
    const containerClasses = (0, cn_js_1.cn)('relative flex flex-col w-full', isDisabled && 'opacity-50 cursor-not-allowed', className);
    // Track classes
    const trackClasses = (0, cn_js_1.cn)('relative w-full rounded-full cursor-pointer', 'bg-gray-200 dark:bg-gray-700', sizeClasses.track[size], isDisabled && 'cursor-not-allowed', trackClassName);
    // Filled track classes
    const filledTrackClasses = (0, cn_js_1.cn)('absolute h-full rounded-full', colorClasses[colorScheme].filled, filledTrackClassName);
    // Thumb classes
    const thumbClasses = (0, cn_js_1.cn)('absolute rounded-full border-2 border-white shadow-md', 'focus:outline-none focus:ring-2 focus:ring-offset-2', 'transform -translate-x-1/2 -translate-y-1/2', 'top-1/2', sizeClasses.thumb[size], colorClasses[colorScheme].thumb, colorClasses[colorScheme].focus, isDisabled && 'cursor-not-allowed', thumbClassName);
    // Marker classes
    const baseMarkerClasses = (0, cn_js_1.cn)('absolute rounded-full bg-gray-400 dark:bg-gray-500', 'transform -translate-x-1/2 top-1/2 -translate-y-1/2', sizeClasses.marker[size], markerClassName);
    // Tooltip classes
    const tooltipClasses = (0, cn_js_1.cn)('absolute bottom-full mb-2 transform -translate-x-1/2 whitespace-nowrap', 'bg-gray-800 text-white rounded shadow-md', 'transition-opacity duration-200', sizeClasses.tooltip[size], showTooltipValue ? 'opacity-100' : 'opacity-0');
    // Label classes
    const labelClasses = (0, cn_js_1.cn)('mb-2 text-sm font-medium text-gray-700 dark:text-gray-300');
    return ((0, jsx_runtime_1.jsxs)("div", { ref: ref, className: containerClasses, ...props, children: [(label || showLabel) && ((0, jsx_runtime_1.jsx)("div", { className: labelClasses, children: label || (showLabel && `Value: ${value}`) })), (0, jsx_runtime_1.jsx)("div", { className: "relative pt-1 pb-1", children: (0, jsx_runtime_1.jsxs)("div", { ref: trackRef, className: trackClasses, onMouseDown: handleDragStart, onTouchStart: handleDragStart, role: "slider", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": value, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, onKeyDown: handleKeyDown, children: [(0, jsx_runtime_1.jsx)("div", { className: filledTrackClasses, style: {
                                [isInverted ? 'right' : 'left']: 0,
                                width: `${percentage}%`,
                            } }), markers.map((markerValue) => {
                            const markerPercentage = getPercentage(markerValue);
                            const active = isInverted
                                ? value <= markerValue
                                : value >= markerValue;
                            return ((0, jsx_runtime_1.jsx)("div", { className: (0, cn_js_1.cn)(baseMarkerClasses, active && colorClasses[colorScheme].thumb), style: { left: `${markerPercentage}%` }, "aria-hidden": "true" }, markerValue));
                        }), showThumb && ((0, jsx_runtime_1.jsx)("div", { ref: thumbRef, className: thumbClasses, style: { left: `${percentage}%` }, "aria-hidden": "true", children: showTooltipValue && ((0, jsx_runtime_1.jsx)("div", { className: tooltipClasses, children: formattedValue })) }))] }) })] }));
});
exports.TailwindSlider.displayName = 'TailwindSlider';
exports.default = exports.TailwindSlider;
//# sourceMappingURL=TailwindSlider.js.map