UNPKG

@re-flex/ui

Version:
161 lines (160 loc) 5.84 kB
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;