slider refactored with liverefs

This commit is contained in:
nklhrstv 2020-03-06 14:43:00 +02:00
parent d0e8f8c0ab
commit 8412c22e64
2 changed files with 30 additions and 24 deletions

View file

@ -7,9 +7,9 @@ const useLiveRef = require('stremio/common/useLiveRef');
const styles = require('./styles'); const styles = require('./styles');
const Slider = ({ className, value, minimumValue, maximumValue, onSlide, onComplete }) => { const Slider = ({ className, value, minimumValue, maximumValue, onSlide, onComplete }) => {
minimumValue = minimumValue !== null && !isNaN(minimumValue) && isFinite(minimumValue) ? minimumValue : 0; const minimumValueRef = useLiveRef(minimumValue !== null && !isNaN(minimumValue) ? minimumValue : 0, [minimumValue]);
maximumValue = maximumValue !== null && !isNaN(maximumValue) && isFinite(maximumValue) ? maximumValue : 100; const maximumValueRef = useLiveRef(maximumValue !== null && !isNaN(maximumValue) ? maximumValue : 100, [maximumValue]);
value = value !== null && !isNaN(value) && value >= minimumValue && value <= maximumValue ? value : 0; const valueRef = useLiveRef(value !== null && !isNaN(value) ? Math.min(maximumValueRef.current, Math.max(minimumValueRef.current, value)) : 0, [minimumValue, maximumValue, value]);
const onSlideRef = useLiveRef(onSlide, [onSlide]); const onSlideRef = useLiveRef(onSlide, [onSlide]);
const onCompleteRef = useLiveRef(onComplete, [onComplete]); const onCompleteRef = useLiveRef(onComplete, [onComplete]);
const sliderContainerRef = React.useRef(null); const sliderContainerRef = React.useRef(null);
@ -20,11 +20,9 @@ const Slider = ({ className, value, minimumValue, maximumValue, onSlide, onCompl
return 0; return 0;
} }
const minimumValue = parseInt(sliderContainerRef.current.getAttribute('aria-valuemin'));
const maximumValue = parseInt(sliderContainerRef.current.getAttribute('aria-valuemax'));
const { x: sliderX, width: sliderWidth } = sliderContainerRef.current.getBoundingClientRect(); const { x: sliderX, width: sliderWidth } = sliderContainerRef.current.getBoundingClientRect();
const thumbStart = Math.min(Math.max(mouseX - sliderX, 0), sliderWidth); const thumbStart = Math.min(Math.max(mouseX - sliderX, 0), sliderWidth);
const value = (thumbStart / sliderWidth) * (maximumValue - minimumValue) + minimumValue; const value = (thumbStart / sliderWidth) * (maximumValueRef.current - minimumValueRef.current) + minimumValueRef.current;
return value; return value;
}, []); }, []);
const retainThumb = React.useCallback(() => { const retainThumb = React.useCallback(() => {
@ -42,17 +40,16 @@ const Slider = ({ className, value, minimumValue, maximumValue, onSlide, onCompl
const classIndex = classList.indexOf(styles['active-slider-within']); const classIndex = classList.indexOf(styles['active-slider-within']);
if (classIndex !== -1) { if (classIndex !== -1) {
classList.splice(classIndex, 1); classList.splice(classIndex, 1);
document.documentElement.className = classnames(classList);
} }
document.documentElement.className = classnames(classList);
}, []); }, []);
const onBlur = React.useCallback(() => { const onBlur = React.useCallback(() => {
const value = parseInt(sliderContainerRef.current.getAttribute('aria-valuenow'));
if (typeof onSlideRef.current === 'function') { if (typeof onSlideRef.current === 'function') {
onSlideRef.current(value); onSlideRef.current(valueRef.current);
} }
if (typeof onCompleteRef.current === 'function') { if (typeof onCompleteRef.current === 'function') {
onCompleteRef.current(value); onCompleteRef.current(valueRef.current);
} }
releaseThumb(); releaseThumb();
@ -85,22 +82,19 @@ const Slider = ({ className, value, minimumValue, maximumValue, onSlide, onCompl
retainThumb(); retainThumb();
}, []); }, []);
React.useLayoutEffect(() => {
React.useEffect(() => {
if (!routeFocused) { if (!routeFocused) {
releaseThumb(); releaseThumb();
} }
}, [routeFocused]); }, [routeFocused]);
React.useEffect(() => { React.useLayoutEffect(() => {
return () => { return () => {
releaseThumb(); releaseThumb();
}; };
}, []); }, []);
const thumbPosition = React.useMemo(() => { const thumbPosition = Math.max(0, Math.min(1, (valueRef.current - minimumValueRef.current) / (maximumValueRef.current - minimumValueRef.current)));
return Math.max(0, Math.min(1, (value - minimumValue) / (maximumValue - minimumValue)));
}, [value, minimumValue, maximumValue]);
return ( return (
<div ref={sliderContainerRef} className={classnames(className, styles['slider-container'])} aria-valuenow={value} aria-valuemin={minimumValue} aria-valuemax={maximumValue} onMouseDown={onMouseDown}> <div ref={sliderContainerRef} className={classnames(className, styles['slider-container'])} onMouseDown={onMouseDown}>
<div className={styles['layer']}> <div className={styles['layer']}>
<div className={styles['track']} /> <div className={styles['track']} />
</div> </div>

View file

@ -1,3 +1,5 @@
@import (reference) '~stremio-colors/dist/less/stremio-colors.less';
html.active-slider-within { html.active-slider-within {
cursor: grabbing; cursor: grabbing;
@ -12,15 +14,25 @@ html.active-slider-within {
overflow: visible; overflow: visible;
cursor: pointer; cursor: pointer;
&:hover, &:global(.active) {
.track-before {
background-color: @color-primary-light5;
}
}
&:global(.disabled) { &:global(.disabled) {
pointer-events: none; pointer-events: none;
.track, .track-before { .track {
background-color: var(--color-surfacedark); background-color: @color-surface-dark5;
}
.track-before {
background-color: @color-surface;
} }
.thumb { .thumb {
fill: var(--color-surfacedark); fill: @color-surface;
} }
} }
@ -40,13 +52,13 @@ html.active-slider-within {
.track { .track {
flex: 1; flex: 1;
height: var(--track-size, 0.5rem); height: var(--track-size, 0.5rem);
background-color: var(--color-backgroundlighter); background-color: @color-primary-dark3;
} }
.track-before { .track-before {
flex: none; flex: none;
height: var(--track-size, 0.5rem); height: var(--track-size, 0.5rem);
background-color: var(--color-primary); background-color: @color-primary-light3;
} }
.thumb { .thumb {
@ -54,6 +66,6 @@ html.active-slider-within {
width: var(--thumb-size, 1.5rem); width: var(--thumb-size, 1.5rem);
height: var(--thumb-size, 1.5rem); height: var(--thumb-size, 1.5rem);
transform: translateX(-50%); transform: translateX(-50%);
fill: var(--color-surfacelighter); fill: @color-surface-light5;
} }
} }