Skip to content

Instantly share code, notes, and snippets.

@fabiospampinato
Created April 19, 2023 13:55
Show Gist options
  • Save fabiospampinato/36bdf44dca584df2b155ce5603489a53 to your computer and use it in GitHub Desktop.
Save fabiospampinato/36bdf44dca584df2b155ce5603489a53 to your computer and use it in GitHub Desktop.
Some code that will probably look pretty weird to you
/* IMPORT */
import './styles.scss';
import _ from '_';
import {$, $$} from 'voby';
import {If} from '~/components';
import {useActiving, useDragger} from '~/hooks';
import type {Props} from './types';
/* MAIN */
const RangeSlider = ( { disabled, grow, min, max, start = min, end = max, name, step, tooltip = true, value, onChange }: Props ): JSX.Element => {
const ref = $<HTMLDivElement>();
const handleMinRef = $<HTMLDivElement>();
const handleMaxRef = $<HTMLDivElement>();
const handleMinActiving = useActiving ( handleMinRef );
const handleMaxActiving = useActiving ( handleMaxRef );
const clampMin = ( valueMin: number ) => _.clamp ( _.round ( valueMin, $$(step) ), $$(min), valueMax () );
const clampMax = ( valueMax: number ) => _.clamp ( _.round ( valueMax, $$(step) ), valueMin (), $$(max) );
const valueMin = () => $$(value)[0];
const valueMax = () => $$(value)[1];
const valueMinClamped = () => clampMin ( valueMin () );
const valueMaxClamped = () => clampMax ( valueMax () );
const onChangeMin = ( valueMin: number ) => onChange?.([ clampMin ( valueMin ), valueMax () ]);
const onChangeMax = ( valueMax: number ) => onChange?.([ valueMin (), clampMax ( valueMax ) ]);
const decrementMin = () => onChangeMin ( valueMin () - $$(step) );
const incrementMin = () => onChangeMin ( valueMin () + $$(step) );
const decrementMinFast = () => onChangeMin ( valueMin () - ( $$(step) * 5 ) );
const incrementMinFast = () => onChangeMin ( valueMin () + ( $$(step) * 5 ) );
const decrementMax = () => onChangeMax ( valueMax () - $$(step) );
const incrementMax = () => onChangeMax ( valueMax () + $$(step) );
const decrementMaxFast = () => onChangeMax ( valueMax () - ( $$(step) * 5 ) );
const incrementMaxFast = () => onChangeMax ( valueMax () + ( $$(step) * 5 ) );
const input = () => `${valueMinClamped ()},${valueMaxClamped ()}`;
const onInput = ( input: string ) => onChange?.([ clampMin ( Number ( input.split ( ',' )[0] ) ), clampMax ( Number ( input.split ( ',' )[1] ) ) ]);
const highlightLeft = () => `${( valueMin () - $$(start) ) * 100 / ( $$(end) - $$(start) )}%`;
const highlightRight = () => `${( $$(end) - valueMax () ) * 100 / ( $$(end) - $$(start) )}%`;
const handleMinLeft = highlightLeft;
const handleMaxLeft = () => `${( valueMax () - $$(start) ) * 100 / ( $$(end) - $$(start) )}%`;
useDragger ( ref, {
onUpdate: ({ constrainedPercentageX }) => {
const value = ( constrainedPercentageX * ( $$(end) - $$(start) ) ) + $$(start);
if ( handleMinActiving () ) {
onChangeMin ( value );
}
if ( handleMaxActiving () ) {
onChangeMax ( value );
}
}
});
return (
<div use:ui="range-slider" ref={ref} class={{ disabled, grow }} disabled={disabled}>
<input use:ui="range-slider-input" use:controlled={[input, onInput]} type="text" name={name} value={input} />
<div use:ui="range-slider-track" />
<div use:ui="range-slider-highlight" style={{ left: highlightLeft, right: highlightRight }} />
<div use:ui="range-slider-side-min" use:shortcuts={{ 'Left': decrementMin, 'Down': decrementMin, 'Right': incrementMin, 'Up': incrementMin, 'Shift+Left': decrementMinFast, 'Shift+Down': decrementMinFast, 'Shift+Right': incrementMinFast, 'Shift+Up': incrementMinFast }} tabIndex>
<div use:ui="range-slider-handle" ref={handleMinRef} style={{ left: handleMinLeft }} />
<div use:ui="range-slider-handle-halo" style={{ left: handleMinLeft }} />
<If when={tooltip}>
<div use:ui="range-slider-tooltip" style={{ left: handleMinLeft }}>
{valueMinClamped}
</div>
</If>
</div>
<div use:ui="range-slider-side-max" use:shortcuts={{ 'Left': decrementMax, 'Down': decrementMax, 'Right': incrementMax, 'Up': incrementMax, 'Shift+Left': decrementMaxFast, 'Shift+Down': decrementMaxFast, 'Shift+Right': incrementMaxFast, 'Shift+Up': incrementMaxFast }} tabIndex>
<div use:ui="range-slider-handle" ref={handleMaxRef} style={{ left: handleMaxLeft }} />
<div use:ui="range-slider-handle-halo" style={{ left: handleMaxLeft }} />
<If when={tooltip}>
<div use:ui="range-slider-tooltip" style={{ left: handleMaxLeft }}>
{valueMaxClamped}
</div>
</If>
</div>
</div>
);
};
/* EXPORT */
export default RangeSlider;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment