@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
JavaScript
;
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