Зеленый слайдер при введении нового значения в текстовое поле выходит за пределы ползунка rangeSlider
Помогите пожалуйста разобраться с проблемой зеленого ползунка. Когда хочу ввести новое значение в текстовое поле, минимальное или максимальное, я сначала удаляю старое значение, перед тем, как ввести новое, но когда значение при удалении меняется, зеленая часть ползунка вылезает за пределы слайдера. Никак не могу понять, как решить эту проблему.
Пытался ввести фильтр-проверку на меньшее значение чем изначальное, но не сработало-вводится большее, а обратное занчение уже не вернуть.
Помогите решить проблему или подсказать как ее можно решить.
Для удобства публикую код в codesandbox: https://codesandbox.io/p/devbox/price-range-slider-zwfzyz?file=%2Fsrc%2Frange-slider%2FrangeSlider.scss%3A32%2C24
Фото ползунка за пределами слайдера:
React code
function MultiRangeSlider({ minPrice, maxPrice, onChange }) {
const [minPriceVal, setMinPriceVal] = useState(minPrice);
const [maxPriceVal, setMaxPriceVal] = useState(maxPrice);
const minValRef = useRef(null);
const maxValRef = useRef(null);
const range = useRef(null);
const convertToPercent = useCallback(
(value) => Math.round(((value - minPrice) / (maxPrice - minPrice)) * 100),
[minPrice, maxPrice],
);
useEffect(() => {
if (maxValRef.current) {
const minPercent = convertToPercent(minPriceVal);
const maxPercent = convertToPercent(+maxValRef.current.value);
if (range.current) {
range.current.style.left = `${minPercent}%`;
range.current.style.width = `${maxPercent - minPercent}%`;
}
}
}, [minPriceVal, convertToPercent]);
useEffect(() => {
if (minValRef.current) {
const maxPercent = convertToPercent(maxPriceVal);
const minPercent = convertToPercent(+minValRef.current.value);
if (range.current) {
range.current.style.width = `${maxPercent - minPercent}%`;
}
}
}, [maxPriceVal, convertToPercent]);
useEffect(() => {
onChange({ min: minPriceVal, max: maxPriceVal });
}, [minPriceVal, maxPriceVal, onChange]);
const minInputField = (e) => {
setMinPriceVal(e.target.value);
};
const maxInputField = (e) => {
setMaxPriceVal(e.target.value);
};
return (
<div className={"rangeSlider"}>
{/* text input field MIN */}
<input
value={minPriceVal}
type={"number"}
onChange={(e) => {
minInputField(e);
}}
/>
{/* text input field MAX */}
<input
value={maxPriceVal}
type={"number"}
onChange={(e) => {
maxInputField(e);
}}
/>
<div className="container">
<input
type="range"
min={minPrice}
max={maxPrice}
value={minPriceVal}
ref={minValRef}
onChange={(event) => {
const value = Math.min(+event.target.value, maxPriceVal - 1);
setMinPriceVal(value);
event.target.value = value.toString();
}}
className="thumbMin"
/>
<input
type="range"
min={minPrice}
max={maxPrice}
value={maxPriceVal}
ref={maxValRef}
onChange={(event) => {
const value = Math.max(+event.target.value, minPriceVal + 1);
setMaxPriceVal(value);
event.target.value = value.toString();
}}
className="thumbMax"
/>
<div className="slider">
<div className="track" />
<div ref={range} className="range" />
</div>
</div>
</div>
);
}
export default MultiRangeSlider;
style
.slider {
position: relative;
width: 200px;
.track {
border-radius: 3px;
height: 5px;
position: absolute;
background-color: black;
width: 100%;
z-index: 1;
}
.range {
display: block;
border-radius: 3px;
height: 5px;
position: absolute;
background-color: greenyellow;
z-index: 2;
}
}
.container {
margin-top: 40px;
.thumbMin {
pointer-events: none;
position: absolute;
height: 0;
width: 200px;
outline: none;
z-index: 3;
&::-webkit-slider-thumb {
-webkit-appearance: none;
-webkit-tap-highlight-color: transparent;
}
&::-webkit-slider-thumb {
background-color: #f1f5f7;
border: none;
border-radius: 50%;
box-shadow: 0 0 1px 1px #ced4da;
cursor: pointer;
height: 18px;
width: 18px;
margin-top: 4px;
pointer-events: all;
position: relative;
}
&::-moz-range-thumb {
background-color: #f1f5f7;
border: none;
border-radius: 50%;
box-shadow: 0 0 1px 1px #ced4da;
cursor: pointer;
height: 18px;
width: 18px;
margin-top: 4px;
pointer-events: all;
position: relative;
}
}
.thumbMax {
pointer-events: none;
position: absolute;
height: 0;
width: 200px;
outline: none;
z-index: 4;
&::-webkit-slider-thumb {
-webkit-appearance: none;
-webkit-tap-highlight-color: transparent;
}
&::-webkit-slider-thumb {
background-color: #f1f5f7;
border: none;
border-radius: 50%;
box-shadow: 0 0 1px 1px #ced4da;
cursor: pointer;
height: 18px;
width: 18px;
margin-top: 4px;
pointer-events: all;
position: relative;
}
&::-moz-range-thumb {
background-color: #f1f5f7;
border: none;
border-radius: 50%;
box-shadow: 0 0 1px 1px #ced4da;
cursor: pointer;
height: 18px;
width: 18px;
margin-top: 4px;
pointer-events: all;
position: relative;
}
}
}
Ответы (1 шт):
любые изменения с палзунком должны происходить если это верно (изменение стилей и тд)
const isInRange = minPriceVal >= minPrice && maxPriceVal <= maxPrice;
значения ползунков не должны привишать/быт меньше min или мах
//палзунок
value={isInRange ? minPriceVal : minPrice}