mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-12 02:38:15 +00:00
chore: initial Untitled UI Vite scaffold with FontAwesome Pro
This commit is contained in:
73
src/components/base/slider/slider.tsx
Normal file
73
src/components/base/slider/slider.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import type { SliderProps as AriaSliderProps } from "react-aria-components";
|
||||
import {
|
||||
Label as AriaLabel,
|
||||
Slider as AriaSlider,
|
||||
SliderOutput as AriaSliderOutput,
|
||||
SliderThumb as AriaSliderThumb,
|
||||
SliderTrack as AriaSliderTrack,
|
||||
} from "react-aria-components";
|
||||
import { cx, sortCx } from "@/utils/cx";
|
||||
|
||||
const styles = sortCx({
|
||||
default: "hidden",
|
||||
bottom: "absolute top-2 left-1/2 -translate-x-1/2 translate-y-full text-md font-medium text-primary",
|
||||
"top-floating":
|
||||
"absolute -top-2 left-1/2 -translate-x-1/2 -translate-y-full rounded-lg bg-primary px-3 py-2 text-xs font-semibold text-secondary shadow-lg ring-1 ring-secondary_alt",
|
||||
});
|
||||
|
||||
interface SliderProps extends AriaSliderProps {
|
||||
labelPosition?: keyof typeof styles;
|
||||
labelFormatter?: (value: number) => string;
|
||||
}
|
||||
|
||||
export const Slider = ({ labelPosition = "default", minValue = 0, maxValue = 100, labelFormatter, formatOptions, ...rest }: SliderProps) => {
|
||||
// Format thumb value as percentage by default.
|
||||
const defaultFormatOptions: Intl.NumberFormatOptions = {
|
||||
style: "percent",
|
||||
maximumFractionDigits: 0,
|
||||
};
|
||||
|
||||
return (
|
||||
<AriaSlider {...rest} {...{ minValue, maxValue }} formatOptions={formatOptions ?? defaultFormatOptions}>
|
||||
<AriaLabel />
|
||||
<AriaSliderTrack className="relative h-6 w-full">
|
||||
{({ state: { values, getThumbValue, getThumbPercent, getFormattedValue } }) => {
|
||||
const left = values.length === 1 ? 0 : getThumbPercent(0);
|
||||
const width = values.length === 1 ? getThumbPercent(0) : getThumbPercent(1) - left;
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className="absolute top-1/2 h-2 w-full -translate-y-1/2 rounded-full bg-quaternary" />
|
||||
<span
|
||||
className="absolute top-1/2 h-2 w-full -translate-y-1/2 rounded-full bg-brand-solid"
|
||||
style={{
|
||||
left: `${left * 100}%`,
|
||||
width: `${width * 100}%`,
|
||||
}}
|
||||
/>
|
||||
{values.map((_, index) => {
|
||||
return (
|
||||
<AriaSliderThumb
|
||||
key={index}
|
||||
index={index}
|
||||
className={({ isFocusVisible, isDragging }) =>
|
||||
cx(
|
||||
"top-1/2 box-border size-6 cursor-grab rounded-full bg-slider-handle-bg shadow-md ring-2 ring-slider-handle-border ring-inset",
|
||||
isFocusVisible && "outline-2 outline-offset-2 outline-focus-ring",
|
||||
isDragging && "cursor-grabbing",
|
||||
)
|
||||
}
|
||||
>
|
||||
<AriaSliderOutput className={cx("whitespace-nowrap", styles[labelPosition])}>
|
||||
{labelFormatter ? labelFormatter(getThumbValue(index)) : getFormattedValue(getThumbValue(index) / 100)}
|
||||
</AriaSliderOutput>
|
||||
</AriaSliderThumb>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</AriaSliderTrack>
|
||||
</AriaSlider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user