first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,191 @@
import React, {ReactNode} from 'react';
import clsx from 'clsx';
import {getInputFieldClassNames} from '../input-field/get-input-field-class-names';
import {UseSliderProps, UseSliderReturn} from './use-slider';
export interface BaseSliderProps extends UseSliderProps {
slider: UseSliderReturn;
children: ReactNode;
}
export function BaseSlider(props: BaseSliderProps) {
const {
size = 'md',
inline,
label,
showValueLabel = !!label,
className,
width = 'w-full',
slider,
children,
trackColor = 'primary',
fillColor = 'primary',
} = props;
const {
domProps,
trackRef,
getThumbPercent,
getThumbValueLabel,
labelId,
groupId,
thumbIds,
isDisabled,
numberFormatter,
minValue,
maxValue,
step,
values,
getValueLabel,
} = slider;
let outputValue = '';
let maxLabelLength = Math.max(
[...numberFormatter.format(minValue)].length,
[...numberFormatter.format(maxValue)].length,
[...numberFormatter.format(step)].length,
);
if (getValueLabel) {
outputValue = getValueLabel(values[0]);
} else if (values.length === 1) {
outputValue = getThumbValueLabel(0);
} else if (values.length === 2) {
// This should really use the NumberFormat#formatRange proposal...
// https://github.com/tc39/ecma402/issues/393
// https://github.com/tc39/proposal-intl-numberformat-v3#formatrange-ecma-402-393
outputValue = `${getThumbValueLabel(0)} ${getThumbValueLabel(1)}`;
maxLabelLength =
3 +
2 *
Math.max(
maxLabelLength,
[...numberFormatter.format(minValue)].length,
[...numberFormatter.format(maxValue)].length,
);
}
const style = getInputFieldClassNames({
size,
disabled: isDisabled,
labelDisplay: 'flex',
});
const wrapperClassname = clsx('touch-none', className, width, {
'flex items-center': inline,
});
return (
<div className={wrapperClassname} role="group" id={groupId}>
{(label || showValueLabel) && (
<div className={clsx(style.label, 'select-none')}>
{label && (
<label
onClick={() => {
// Safari does not focus <input type="range"> elements when clicking on an associated <label>,
// so do it manually. In addition, make sure we show the focus ring.
document.getElementById(thumbIds[0])?.focus();
}}
id={labelId}
htmlFor={groupId}
>
{label}
</label>
)}
{showValueLabel && (
<output
htmlFor={thumbIds[0]}
className="ml-auto text-right"
aria-live="off"
style={
!maxLabelLength
? undefined
: {
width: `${maxLabelLength}ch`,
minWidth: `${maxLabelLength}ch`,
}
}
>
{outputValue}
</output>
)}
</div>
)}
<div
ref={trackRef}
className={clsx('relative', getWrapperHeight(props))}
{...domProps}
role="presentation"
>
<div
className={clsx(
'absolute inset-0 m-auto rounded',
getTrackColor(trackColor, isDisabled),
getTrackHeight(size),
)}
/>
<div
className={clsx(
'absolute inset-0 my-auto rounded',
getFillColor(fillColor, isDisabled),
getTrackHeight(size),
)}
style={{width: `${Math.max(getThumbPercent(0) * 100, 0)}%`}}
/>
{children}
</div>
</div>
);
}
function getWrapperHeight({size, wrapperHeight}: UseSliderProps): string {
if (wrapperHeight) return wrapperHeight;
switch (size) {
case 'xs':
return 'h-14';
case 'sm':
return 'h-20';
default:
return 'h-30';
}
}
function getTrackHeight(size: UseSliderProps['size']): string {
switch (size) {
case 'xs':
return 'h-2';
case 'sm':
return 'h-3';
default:
return 'h-4';
}
}
function getTrackColor(color: string, isDisabled: boolean): string {
if (isDisabled) {
color = 'disabled';
}
switch (color) {
case 'disabled':
return 'bg-slider-disabled/60';
case 'primary':
return 'bg-primary-light';
case 'neutral':
return 'bg-divider';
default:
return color;
}
}
function getFillColor(color: string, isDisabled: boolean): string {
if (isDisabled) {
color = 'disabled';
}
switch (color) {
case 'disabled':
return 'bg-slider-disabled';
case 'primary':
return 'bg-primary';
default:
return color;
}
}