Files
Checkmate/client/src/Components/inputs/Slider.tsx
T

108 lines
2.6 KiB
TypeScript
Raw Normal View History

2026-01-30 18:28:30 +00:00
import Typography from "@mui/material/Typography";
2026-01-29 23:52:21 +00:00
import { forwardRef } from "react";
import Slider from "@mui/material/Slider";
import type { SliderProps } from "@mui/material/Slider";
import { useTheme } from "@mui/material/styles";
2026-01-30 00:00:12 +00:00
import Stack from "@mui/material/Stack";
import { FieldLabel } from "./FieldLabel";
2026-01-30 18:28:30 +00:00
import Box from "@mui/material/Box";
import type { ResponsiveStyleValue } from "@mui/system";
2026-01-29 23:52:21 +00:00
2026-01-30 18:28:30 +00:00
interface SliderInputProps extends SliderProps {
sx?: SliderProps["sx"];
showValue?: boolean;
2026-03-09 11:32:01 -07:00
formatDisplayValue?: (value: number) => string;
2026-01-30 18:28:30 +00:00
}
2026-01-29 23:52:21 +00:00
2026-01-30 18:28:30 +00:00
export const SliderInput = forwardRef<HTMLSpanElement, SliderInputProps>(
2026-03-09 11:32:01 -07:00
({ sx, showValue = false, formatDisplayValue, ...props }, ref) => {
2026-01-30 18:28:30 +00:00
const theme = useTheme();
const additionalSx = Array.isArray(sx) ? sx : sx ? [sx] : [];
2026-03-09 11:32:01 -07:00
const displayValue =
showValue && formatDisplayValue && typeof props.value === "number"
? formatDisplayValue(props.value)
: props.value;
2026-01-30 18:28:30 +00:00
return (
<Stack
gap={theme.spacing(8)}
direction={"row"}
alignItems={"center"}
>
2026-03-09 11:32:01 -07:00
{showValue && <Typography>{displayValue}</Typography>}
2026-01-30 18:28:30 +00:00
<Slider
{...props}
ref={ref}
sx={[
{
"& .MuiSlider-track": {
backgroundColor: theme.palette.primary.main,
border: "none",
},
"& .MuiSlider-rail": {
backgroundColor: theme.palette.grey[300],
opacity: 1,
},
"& .MuiSlider-thumb": {
backgroundColor: "#fff",
"&:hover, &.Mui-focusVisible": {
2026-02-14 01:15:12 +00:00
boxShadow: "none",
},
"&:active": {
boxShadow: "none",
2026-01-30 18:28:30 +00:00
},
},
"& .MuiSlider-valueLabel": {
backgroundColor: theme.palette.primary.main,
},
2026-01-29 23:52:21 +00:00
},
2026-01-30 18:28:30 +00:00
...additionalSx,
]}
/>
</Stack>
);
}
);
2026-01-30 00:00:12 +00:00
interface SliderWithLabelProps extends SliderProps {
fieldLabel?: string;
required?: boolean;
showValue?: boolean;
2026-03-09 11:32:01 -07:00
formatDisplayValue?: (value: number) => string;
2026-01-30 18:28:30 +00:00
sliderMaxWidth?: ResponsiveStyleValue<number | string>;
2026-01-30 00:00:12 +00:00
}
export const SliderWithLabel = forwardRef<HTMLSpanElement, SliderWithLabelProps>(
2026-01-30 18:28:30 +00:00
(
2026-03-09 11:32:01 -07:00
{
fieldLabel,
required,
showValue = true,
formatDisplayValue,
value,
sliderMaxWidth = "100%",
...props
},
2026-01-30 00:00:12 +00:00
ref
2026-01-30 18:28:30 +00:00
) => {
2026-01-30 00:00:12 +00:00
const theme = useTheme();
2026-01-30 18:28:30 +00:00
const labelText = fieldLabel;
2026-01-30 00:00:12 +00:00
return (
<Stack spacing={theme.spacing(2)}>
{fieldLabel && <FieldLabel required={required}>{labelText}</FieldLabel>}
2026-01-30 18:28:30 +00:00
<Box maxWidth={sliderMaxWidth}>
<SliderInput
{...props}
showValue={showValue}
2026-03-09 11:32:01 -07:00
formatDisplayValue={formatDisplayValue}
2026-01-30 18:28:30 +00:00
value={value}
ref={ref}
/>
</Box>
2026-01-30 00:00:12 +00:00
</Stack>
2026-01-29 23:52:21 +00:00
);
}
);