🆙 Updates thanks to Life

react-slider → @radix-ui/react-slider
react-tiny-popover → @radix-ui/react-popover
react-youtube → react-player (more formats, better maintained)
This commit is contained in:
DuckieTM
2026-05-03 17:54:10 +02:00
parent 99aceefb9e
commit 92e9bb19cd
7 changed files with 229 additions and 162 deletions
+127 -14
View File
@@ -1,35 +1,148 @@
import { FC } from 'react';
import ReactSlider, { ReactSliderProps } from 'react-slider';
import * as RadixSlider from '@radix-ui/react-slider';
import { CSSProperties, FC, HTMLProps, ReactElement } from 'react';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
import { Button } from './Button';
import { Flex } from './Flex';
import { FaAngleLeft, FaAngleRight } from 'react-icons/fa';
export interface SliderProps extends ReactSliderProps
export interface SliderThumbState
{
disabledButton?: boolean;
index: number;
value: number | number[];
valueNow: number;
}
export interface SliderProps
{
min?: number;
max?: number;
step?: number;
value?: number | number[];
defaultValue?: number | number[];
onChange?: (value: any, thumbIndex: number) => void;
disabled?: boolean;
disabledButton?: boolean;
invert?: boolean;
className?: string;
style?: CSSProperties;
trackClassName?: string;
thumbClassName?: string;
renderThumb?: (props: HTMLProps<HTMLDivElement>, state: SliderThumbState) => ReactElement;
}
const toArray = (value: number | number[] | undefined): number[] =>
{
if(Array.isArray(value)) return value;
if(typeof value === 'number') return [ value ];
return [ 0 ];
};
const cn = (...parts: (string | undefined | false)[]) => parts.filter(Boolean).join(' ');
export const Slider: FC<SliderProps> = props =>
{
const { disabledButton, max, min, step, value, onChange, ...rest } = props;
const currentValue = Array.isArray(value) ? value[0] : ((typeof value === 'number') ? value : 0);
const {
disabledButton,
disabled,
max = 100,
min = 0,
step = 1,
value,
defaultValue,
onChange,
invert,
className,
style,
trackClassName,
thumbClassName,
renderThumb
} = props;
const valueArr = toArray(value);
const currentValue = valueArr[0] ?? 0;
const minimum = (typeof min === 'number') ? min : 0;
const maximum = (typeof max === 'number') ? max : 0;
const buttonStep = ((typeof step === 'number') && (step > 0)) ? step : 1;
const isRange = valueArr.length > 1;
const roundToStep = (nextValue: number) =>
{
if(typeof buttonStep !== 'number') return nextValue;
const decimalStep = buttonStep.toString();
const precision = decimalStep.includes('.') ? (decimalStep.length - decimalStep.indexOf('.') - 1) : 0;
return parseFloat(nextValue.toFixed(precision));
};
return <Flex fullWidth gap={ 1 } classNames={ [ 'nitro-slider-wrapper' ] }>
{ !disabledButton && <Button classNames={ [ 'nitro-slider-button', 'nitro-slider-button-left' ] } disabled={ minimum >= currentValue } onClick={ () => onChange(roundToStep(minimum < currentValue ? currentValue - buttonStep : minimum), 0) }><FaAngleLeft /></Button> }
<ReactSlider className={ 'nitro-slider' } max={ max } min={ min } step={ step } value={ value } onChange={ onChange } { ...rest } />
{ !disabledButton && <Button classNames={ [ 'nitro-slider-button', 'nitro-slider-button-right' ] } disabled={ maximum <= currentValue } onClick={ () => onChange(roundToStep(maximum > currentValue ? currentValue + buttonStep : maximum), 0) }><FaAngleRight /></Button> }
</Flex>;
const emit = (next: number[]) =>
{
if(!onChange) return;
if(isRange) onChange(next, 0);
else onChange(next[0], 0);
};
const stepDown = () =>
{
const next = roundToStep(minimum < currentValue ? currentValue - buttonStep : minimum);
emit([ next, ...valueArr.slice(1) ]);
};
const stepUp = () =>
{
const next = roundToStep(maximum > currentValue ? currentValue + buttonStep : maximum);
emit([ next, ...valueArr.slice(1) ]);
};
const renderThumbElement = (i: number) =>
{
const baseProps: HTMLProps<HTMLDivElement> = {
key: i,
className: cn('thumb', `thumb-${ i }`, thumbClassName)
};
const state: SliderThumbState = {
index: i,
value: isRange ? valueArr : currentValue,
valueNow: valueArr[i] ?? 0
};
return (
<RadixSlider.Thumb key={ i } asChild>
{ renderThumb ? renderThumb(baseProps, state) : <div { ...baseProps } /> }
</RadixSlider.Thumb>
);
};
return (
<Flex fullWidth gap={ 1 } classNames={ [ 'nitro-slider-wrapper' ] }>
{ !disabledButton && (
<Button classNames={ [ 'nitro-slider-button', 'nitro-slider-button-left' ] } disabled={ disabled || (minimum >= currentValue) } onClick={ stepDown }>
<FaAngleLeft />
</Button>
) }
<RadixSlider.Root
inverted={ invert }
disabled={ disabled }
className={ cn('nitro-slider', 'relative', 'min-w-0', 'grow', className) }
style={ style }
max={ max }
min={ min }
step={ step }
value={ value !== undefined ? valueArr : undefined }
defaultValue={ defaultValue !== undefined ? toArray(defaultValue) : undefined }
onValueChange={ emit }>
<RadixSlider.Track className={ cn('track', 'track-1', 'grow', trackClassName) }>
<RadixSlider.Range className={ cn('track', 'track-0', trackClassName) } />
</RadixSlider.Track>
{ valueArr.map((_, i) => renderThumbElement(i)) }
</RadixSlider.Root>
{ !disabledButton && (
<Button classNames={ [ 'nitro-slider-button', 'nitro-slider-button-right' ] } disabled={ disabled || (maximum <= currentValue) } onClick={ stepUp }>
<FaAngleRight />
</Button>
) }
</Flex>
);
}