@re-flex/ui
Version:
Re-Flex ui library
161 lines (160 loc) • 5.84 kB
JavaScript
import { css, styled, useTheme, } from "@re-flex/styles";
import { convertUnit2Rem } from "@re-flex/utils";
import clsx from "clsx";
import React, { useRef } from "react";
import useRanger from "../hooks/useRanger";
import Text from "../Typography";
export const Track = styled("div", true)(({ height, width, borderRadius: radius, mode }) => [
{ borderRadius: typeof radius === "number" ? `${radius}px` : radius },
{
height: height
? convertUnit2Rem(height)
: mode === "vertical"
? "100%"
: "8px",
},
{
width: width
? convertUnit2Rem(width)
: mode === "horizontal"
? "100%"
: "8px",
},
{
display: "flex",
position: "relative",
overflow: "visible",
userSelect: "none",
},
]);
export const Tick = styled("div", true)(({ mode, color = "text.primary" }) => ({
display: "block",
position: "absolute",
width: 0,
height: "100%",
"&:before": {
content: '""',
position: "absolute",
left: "0",
backgroundColor: color,
height: mode === "horizontal" ? "100%" : "2px",
width: mode === "vertical" ? "100%" : "2px",
},
}));
export const TickLabel = styled(Text, true)(({ color = "text.primary", mode }) => [
{ color },
{
transform: mode === "vertical"
? "translate(1.2rem,-50%)"
: "translate(-50%, 1.2rem)",
},
{
position: "absolute",
top: "100%",
whiteSpace: "nowrap",
},
]);
export const Segment = styled("div")(({ backgroundColor, mode }) => [
{
backgroundColor,
},
{
[mode === "vertical" ? "width" : "height"]: "100%",
},
{
position: "absolute",
"&:not(:hover)": {
transition: "all 0.05s linear",
},
},
]);
export const Handle = styled("div", true)(({ color = "primary.main", activeSize, size, active, mode, theme: { sizes, space }, }) => {
size = typeof size === "string" ? (sizes?.[size] || 2) * 8 : size || 2;
activeSize =
typeof activeSize === "string"
? (sizes?.[activeSize] || 2) * 8
: activeSize || 2;
return [
{
backgroundColor: color,
},
{
width: active ? activeSize : size,
height: active ? activeSize : size,
fontSize: active ? (activeSize / 5) * 3 : (size / 5) * 3,
fontWeight: active ? "bold" : "normal",
},
{
"&:hover": {
"&::before": {
content: "' '",
position: "absolute",
top: 0,
left: 0,
width: (active ? activeSize : size) * 1.75,
height: (active ? activeSize : size) * 1.75,
backgroundColor: color,
opacity: 0.3,
borderRadius: "50%",
},
},
},
{
"&:focus": {
"&::before": {
content: "' '",
position: "absolute",
top: 0,
left: 0,
width: (active ? activeSize : size) * 2.25,
height: (active ? activeSize : size) * 2.25,
backgroundColor: color,
opacity: 0.3,
borderRadius: "50%",
},
},
},
{
color: "#ffffff",
boxShadow: 1,
borderRadius: "50%",
whiteSpace: "nowrap",
display: "flex",
alignItems: "center",
justifyContent: "center",
},
];
});
const Slider = ({ width, height, size = "md", activeSize = "md", step = 0.1, min = 0, max = 10, values = [], borderRadius = "16%", onChange, color, mode = "horizontal", }) => {
const theme = useTheme();
const sliderRef = useRef(null);
const { activeHandleIndex, onClickTrack, ticks, segments, handles } = useRanger({
trackElRef: sliderRef,
min,
stepSize: step,
max,
values,
mode,
onChange: (changedValues) => {
if (typeof onChange === "function")
onChange(...changedValues);
},
});
return (React.createElement(Track, { role: "slider", width: width, height: height, borderRadius: borderRadius, color: color, ref: sliderRef, mode: mode, onClick: onClickTrack },
ticks.map(({ value, getTickProps }, k) => (React.createElement(Tick, { key: k, mode: mode, color: color, ...getTickProps() },
React.createElement(TickLabel, { variant: "caption", mode: mode, color: color }, value)))),
segments.map(({ getSegmentProps }, i) => (React.createElement(Segment, { key: i, mode: mode, ...getSegmentProps(), color: color, backgroundColor: values.length === 1 && i === 0
? "primary.main"
: values.length > 1 && i > 0 && i < 2
? "primary.main"
: `${theme.palette.primary.main}60` }))),
handles.map(({ value, active, getHandleProps }, k) => (React.createElement("div", { role: "button", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": value, key: k, className: clsx(css({
position: "absolute",
transform: "translate(-50%, 50%)",
"&:not(:hover)": {
transition: "all 0.2s linear",
},
}), "reflex-slider-thumb"), ...getHandleProps() },
React.createElement(Handle, { role: "button", mode: mode, size: size, activeSize: activeSize, active: active, className: "reflex-slider-thumb" }))))));
};
export default Slider;