UNPKG

nudge-components-library

Version:

A library of nudge UI components

99 lines (96 loc) 6.1 kB
import { jsxs, jsx } from 'react/jsx-runtime'; import React, { useContext, useRef, useState, useLayoutEffect } from 'react'; import { ThemeContext } from '../../theme/ThemeContext.js'; import '../../styles/tokens.css.js'; import '../../styles/globals.css.js'; import styles from './Slider.module.css.js'; function Slider({ sliderLabel, min = 0, max = 100, value, defaultValue, step = 1, showValueTooltip = true, onChange, disabled = false, nudgeText, id, ariaLabel, onFocus, onBlur, onCommit, nudgeVisible = true, nudgePosition = "bottom", renderNudge, renderValueTooltip, tooltipContainerStyle, alwaysShowTooltip, }) { const theme = useContext(ThemeContext); const sliderRef = useRef(null); const containerRef = useRef(null); const [sliderValue, setSliderValue] = useState(defaultValue ?? min); const [thumbCenter, setThumbCenter] = useState(0); const currentValue = value ?? sliderValue; const percentage = ((currentValue - min) / (max - min)) * 100; const filledPercentage = Math.min(percentage, 100); useLayoutEffect(() => { if (sliderRef.current) { const sliderWidth = sliderRef.current.offsetWidth; const thumbWidthStr = theme.slider.thumb.width ? theme.slider.thumb.width.toString() : "20"; const thumbWidth = parseInt(thumbWidthStr, 7); const pos = ((sliderWidth - thumbWidth) * (currentValue - min)) / (max - min) + thumbWidth / 2; setThumbCenter(pos); } }, [currentValue, min, max, theme.slider.thumb.width]); React.useEffect(() => { if (value !== undefined) { setSliderValue(value); } }, [value]); React.useEffect(() => { if (defaultValue !== undefined) { const clampedValue = Math.min(Math.max(defaultValue, min), max); setSliderValue(clampedValue); } }, [defaultValue, min, max]); const handleChange = (event) => { const newValue = Number(event.target.value); if (value === undefined) { setSliderValue(newValue); } onChange?.(newValue); }; const handleBlur = (event) => { onBlur?.(event); onCommit?.(Number(event.target.value)); }; const handleMouseUp = (event) => { onCommit?.(Number(event.currentTarget.value)); }; const handleTouchStart = (e) => { if (onFocus) { onFocus(e); } }; React.useEffect(() => { const handleTouchOutside = (event) => { if (containerRef.current && !containerRef.current.contains(event.target)) { if (onBlur) { const dummyEvent = { target: containerRef.current, }; onBlur(dummyEvent); } onCommit?.(currentValue); } }; document.addEventListener("touchstart", handleTouchOutside); return () => document.removeEventListener("touchstart", handleTouchOutside); }, [onBlur, onCommit, currentValue]); const nudgeId = id ? `${id}-nudge` : undefined; const sliderInputElement = (jsxs("div", { style: theme.slider.container, className: styles.sliderContainer, children: [jsx("input", { ref: sliderRef, id: id, type: "range", min: min, max: max, step: step, value: currentValue, onChange: handleChange, onFocus: onFocus, onBlur: handleBlur, onMouseUp: handleMouseUp, onTouchStart: handleTouchStart, "aria-label": ariaLabel ?? sliderLabel, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": currentValue, "aria-describedby": nudgeVisible ? nudgeId : undefined, style: { ...theme.slider.input, background: `linear-gradient(to right, ${theme.slider.input.filledColor} 0%, ${theme.slider.input.filledColor} ${filledPercentage}%, ${theme.slider.input.emptyColor} ${filledPercentage}%, ${theme.slider.input.emptyColor} 100%)`, }, disabled: disabled, className: styles.inputSlider }), jsx("div", { className: styles.customThumb, style: { ...theme.slider.thumb, left: thumbCenter, } }), showValueTooltip && (jsx("div", { className: `${styles.sliderTooltip} ${alwaysShowTooltip ? styles.alwaysVisible : ""}`, style: { left: thumbCenter, ...theme.slider.tooltip, ...tooltipContainerStyle, "--tooltip-triangle-color": theme.slider.tooltip.triangleColor, "--tooltip-triangle-width": theme.slider.tooltip.triangleWidth, }, children: renderValueTooltip ? renderValueTooltip(currentValue) : currentValue }))] })); const nudgeElement = renderNudge && nudgeVisible ? (jsx("div", { id: nudgeId, style: theme.slider.nudgeText, children: renderNudge(currentValue) })) : nudgeVisible && nudgeText ? (jsx("div", { id: nudgeId, style: theme.slider.nudgeText, children: nudgeText })) : null; return (jsxs("div", { style: { ...theme.slider.wrapper, ...(disabled ? theme.slider.disabled : {}), }, className: styles.wrapper, ref: containerRef, children: [sliderLabel && (jsx("div", { style: theme.slider.sliderLabel, children: jsx("label", { htmlFor: id, children: sliderLabel }) })), nudgeVisible && nudgePosition === "top" && (jsx("div", { style: theme.slider.nudgeTop, children: nudgeElement })), nudgeVisible && (nudgePosition === "left" || nudgePosition === "right") ? (jsxs("div", { style: { display: "flex", alignItems: "center" }, children: [nudgePosition === "left" && (jsx("div", { style: theme.slider.nudgeLeft, children: nudgeElement })), sliderInputElement, nudgePosition === "right" && (jsx("div", { style: theme.slider.nudgeRight, children: nudgeElement }))] })) : (sliderInputElement), nudgeVisible && nudgePosition === "bottom" && (jsx("div", { style: theme.slider.nudgeBottom, children: nudgeElement }))] })); } export { Slider, Slider as default }; //# sourceMappingURL=Slider.js.map