UNPKG

@kubit-ui-web/react-components

Version:

Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience

234 lines 10.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Slider = exports.SliderComponent = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = __importDefault(require("react")); const useStyles_1 = require("../../hooks/useStyles/useStyles"); const errorBoundary_1 = require("../../provider/errorBoundary/errorBoundary"); const fallbackComponent_1 = require("../../provider/errorBoundary/fallbackComponent"); const role_1 = require("../../types/role/role"); const sliderStandAlone_1 = require("./sliderStandAlone"); const type_1 = require("./types/type"); const accessibility_utils_1 = require("./utils/accessibility.utils"); const slider_utils_1 = require("./utils/slider.utils"); const ON_CHANGE_DEBOUNCE_TIMEOUT = 50; const SLIDER_STYLES = 'SLIDER_STYLES'; exports.SliderComponent = react_1.default.forwardRef(({ variant, type = type_1.SliderType.DISCRETE, range = false, min = 0, max = 100, step = 1, initialStepOffset, disabled = false, defaultValue, value: propValue, onChange, onDragStart, onDragEnd, tooltip, rightTooltip, leftHelperText, rightHelperText, // label label, // Increment and decrement buttons incrementButton, decrementButton, // Thumb icons thumbIcon, rightThumbIcon, // Aria helpers ariaLabel, rightAriaLabel, ariaLabelBy, rightAriaLabelBy, ctv, }, ref) => { const _calcDefaultValue = _value => (0, slider_utils_1.calcDefaultValue)({ range, max, min, step, initialStepOffset, value: _value }); const containerRef = react_1.default.useRef(null); const [value, setValue] = react_1.default.useState(_calcDefaultValue(propValue ?? defaultValue)); const [hover, setHover] = react_1.default.useState(false); const [pressed, setPressed] = react_1.default.useState(false); const activePointer = react_1.default.useRef('left'); const [offsetBoundaries, setOffsetBoundaries] = react_1.default.useState({ min: 0, max: 100, }); const styles = (0, useStyles_1.useStyles)(SLIDER_STYLES, variant, ctv); // thumbExceedsTrack by default is true const thumbExceedsTrack = react_1.default.useMemo(() => styles?.thumbExceedsTrack ?? true, [styles?.thumbExceedsTrack]); // When !thumbExceedsTrack, the ratio of the thumb to the track could change // So the offset boundaries should be recalculated // When thumbExceedsTrack is true, the offset boundaries are always 0 and 100 const initialiceBoundaries = react_1.default.useCallback(() => { if (thumbExceedsTrack) { setOffsetBoundaries({ min: 0, max: 100 }); return; } if (!containerRef.current) { return; } // Select by ROLES.Slider const thumb = containerRef.current.querySelector(`[role="${role_1.ROLES.SLIDER}"]`); if (!thumb) { return; } // Get container width const containerWidth = containerRef.current.getBoundingClientRect().width; // Get thumb width const thumbWidth = thumb.getBoundingClientRect().width; // Calc thumbWidth as percentage of the containerWidth const thumbWidthPercentage = (thumbWidth / containerWidth) * 100.0; // Calc min and max offset boundaries const minOffset = thumbWidthPercentage / 2; const maxOffset = 100 - minOffset; setOffsetBoundaries({ min: minOffset, max: maxOffset }); }, [thumbExceedsTrack]); react_1.default.useEffect(() => { initialiceBoundaries(); // Only add resize event listener if thumbExceedsTrack is false // When false, the ratio of the thumb to the track could change if (!thumbExceedsTrack) { window.addEventListener('resize', initialiceBoundaries); } return () => { if (!thumbExceedsTrack) { window.removeEventListener('resize', initialiceBoundaries); } }; }, [thumbExceedsTrack]); // Update inner value when new propValue is received react_1.default.useEffect(() => { if (propValue !== undefined) { if ((range && !(0, slider_utils_1.equalsRangeValues)({ values1: propValue, values2: value })) || (!range && propValue !== value)) { setValue(_calcDefaultValue(propValue)); } } }, [propValue]); // Debounce callback to avoid calling onChange too many times const timeoutOnChange = react_1.default.useRef(); const onChangeDebounce = react_1.default.useCallback((val) => { if (!onChange) { return; } clearTimeout(timeoutOnChange.current); timeoutOnChange.current = setTimeout(() => { onChange(val); }, ON_CHANGE_DEBOUNCE_TIMEOUT); }, [onchange]); // On unmount call unbindEventListeners react_1.default.useEffect(() => { return unbindEventListeners; }, []); const onMouseDown = event => { onDragStart?.(); setPressed(true); handleChange(event); window.addEventListener('mousemove', handleChange); window.addEventListener('mouseup', onMouseUp); }; const onMouseUp = () => { onDragEnd?.(); setPressed(false); unbindEventListeners(); }; const onTouchStart = event => { onDragStart?.(); setPressed(true); handleChange(event); window.addEventListener('touchend', onMouseUp); }; const handleChange = (event) => { if (!containerRef.current || disabled) { return; } // Offset percentaje const _offset = (0, slider_utils_1.calculateChange)({ event, container: containerRef.current, offsetBoundaries }); const _value = (0, slider_utils_1.calcValueByOffset)({ max, min, step, offset: _offset, offsetBoundaries: offsetBoundaries, }); const newValue = (0, slider_utils_1.calcScaleValue)({ max, min, step, initialStepOffset, value: _value }); setValue(prevValue => { let _newValue = newValue; if (range) { _newValue = (0, slider_utils_1.calcNewRangeValue)({ prevValue: prevValue, newValue, activePointer, }); } onChangeDebounce(_newValue); return _newValue; }); }; const unbindEventListeners = () => { window.removeEventListener('mousemove', handleChange); window.removeEventListener('mouseup', onMouseUp); window.removeEventListener('touchend', onMouseUp); }; const handleKeyPress = event => { if (disabled) { return; } const newValue = (0, accessibility_utils_1.calcNewValueAfterKeyPress)({ event, range, activePointer: activePointer.current, max, min, step, value, }); if (newValue !== undefined) { setValue(newValue); onChangeDebounce(newValue); } }; const handleIncrementClick = event => { const newValue = (0, accessibility_utils_1.incrementValue)({ activePointer: activePointer.current, range, max, step, value, }); if (newValue !== undefined) { setValue(newValue); onChangeDebounce(newValue); } incrementButton?.onClick?.(event); }; const handleDecrementClick = event => { const newValue = (0, accessibility_utils_1.decrementValue)({ activePointer: activePointer.current, range, min, step, value, }); if (newValue !== undefined) { setValue(newValue); onChangeDebounce(newValue); } decrementButton?.onClick?.(event); }; const { showScale, scaleOffsets } = (0, slider_utils_1.getScale)({ type, max, min, step, initialStepOffset, }); const { offset, offsetLeft, offsetRight } = (0, slider_utils_1.getOffset)({ range, max, min, value, offsetBoundaries, }); return ((0, jsx_runtime_1.jsx)(sliderStandAlone_1.SliderStandAlone, { ref: ref, activePointer: activePointer, ariaLabel: ariaLabel, ariaLabelBy: ariaLabelBy, containerRef: containerRef, decrementButton: { ...decrementButton, onClick: handleDecrementClick, disabled: disabled || decrementButton?.disabled, }, disabled: disabled, hover: hover, incrementButton: { ...incrementButton, onClick: handleIncrementClick, disabled: disabled || incrementButton?.disabled, }, label: label, leftHelperText: leftHelperText, max: max, min: min, offset: offset, offsetLeft: offsetLeft, offsetRight: offsetRight, pressed: pressed, range: range, rightAriaLabel: rightAriaLabel, rightAriaLabelBy: rightAriaLabelBy, rightHelperText: rightHelperText, rightThumbIcon: rightThumbIcon, rightTooltip: rightTooltip, scaleOffsets: scaleOffsets, setHover: setHover, showScale: showScale, step: step, styles: styles, thumbIcon: thumbIcon, tooltip: tooltip, value: value, onChange: handleChange, onKeyPress: handleKeyPress, onMouseDown: onMouseDown, onTouchStart: onTouchStart })); }); exports.SliderComponent.displayName = 'SliderComponent'; const SliderBoundary = (props, ref) => ((0, jsx_runtime_1.jsx)(errorBoundary_1.ErrorBoundary, { fallBackComponent: (0, jsx_runtime_1.jsx)(fallbackComponent_1.FallbackComponent, { children: (0, jsx_runtime_1.jsx)(sliderStandAlone_1.SliderStandAlone, { ...props, ref: ref }) }), children: (0, jsx_runtime_1.jsx)(exports.SliderComponent, { ...props, ref: ref }) })); /** * @description * Slider component is used to select a value from a range of values. */ const Slider = react_1.default.forwardRef(SliderBoundary); exports.Slider = Slider; //# sourceMappingURL=slider.js.map