UNPKG

@veracity/vui

Version:

Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.

127 lines (125 loc) 4.14 kB
import { mergeRefs } from "../utils/react.js"; import theme_default from "./theme.js"; import vui from "../core/vui.js"; import { Box } from "../box/box.js"; import { Icon } from "../icon/icon.js"; import { useRef, useState } from "react"; import { jsx } from "react/jsx-runtime"; //#region src/rating/rating.tsx const Rating = vui((props, ref) => { const { value: propValue = 0, isDisabled = false, max: propMax, onChange, showAll: showAllProp = true, variant = "yellow", size, ...rest } = props; const [hoverValue, setHoverValue] = useState(null); const [internalValue, setInternalValue] = useState(propValue || 0); const [focusedStar, setFocusedStar] = useState(null); const containerRef = useRef(null); const isInteractive = !isDisabled && onChange !== void 0; const showAll = showAllProp || isInteractive; const { variants } = theme_default ?? {}; const color = isDisabled ? "sandstone.79" : variants[variant].color; if (propValue < 0) console.error(`Rating: value (${propValue}) cannot be negative`); const value = Math.max(0, propValue); const max = propMax ? propMax : Math.max(value, 5); if (value > max) console.error(`Rating: value (${value}) cannot be greater than max (${max})`); const handleValueChange = (newValue) => { if (!isInteractive) return; const clampedValue = Math.max(0, Math.min(newValue, max)); setInternalValue(clampedValue); onChange?.(clampedValue); }; const handleStarClick = (clickedValue) => { if (!isInteractive) return; handleValueChange(clickedValue === internalValue ? 0 : clickedValue); }; const handleStarHover = (hoveredValue) => { if (!isInteractive) return; setHoverValue(hoveredValue); }; const handleMouseLeave = () => { if (!isInteractive) return; setHoverValue(null); }; const handleKeyDown = (event) => { if (!isInteractive) return; const currentValue = propValue !== void 0 ? propValue : internalValue; switch (event.key) { case "ArrowRight": case "ArrowUp": event.preventDefault(); handleValueChange(Math.min(currentValue + 1, max)); break; case "ArrowLeft": case "ArrowDown": event.preventDefault(); handleValueChange(Math.max(currentValue - 1, 0)); break; case "Home": event.preventDefault(); handleValueChange(0); break; case "End": event.preventDefault(); handleValueChange(max); } }; const handleFocus = () => { if (!isInteractive) return; if (focusedStar === null) setFocusedStar(propValue !== void 0 ? propValue : internalValue); }; const handleBlur = () => { if (!isInteractive) return; setFocusedStar(null); }; const displayValue = hoverValue !== null ? hoverValue : value !== void 0 ? value : internalValue; return /* @__PURE__ */ jsx(Box, { "aria-label": "Rating", "aria-valuemax": max, "aria-valuemin": 0, "aria-valuenow": displayValue, className: "vui-rating", focusRing: 3, focusRingColor: "focusColor", onBlur: handleBlur, onFocus: handleFocus, onKeyDown: handleKeyDown, onMouseLeave: handleMouseLeave, outline: "none", ref: mergeRefs(ref, containerRef), role: "slider", tabIndex: isInteractive ? 0 : -1, ...rest, children: Array.from({ length: max }).map((_, index) => { const starValue = index + 1; return /* @__PURE__ */ jsx(Box, { className: "vui-rating-star", cursor: isInteractive ? "pointer" : void 0, gap: "1px", onClick: () => handleStarClick(starValue), onFocus: () => setFocusedStar(starValue), onMouseEnter: () => handleStarHover(starValue), tabIndex: -1, children: index < displayValue ? /* @__PURE__ */ jsx(FullStar, { color, size }) : showAll ? /* @__PURE__ */ jsx(EmptyStar, { color: "sandstone.79", size }) : null }, index); }) }); }); const FullStar = (props) => /* @__PURE__ */ jsx(Icon, { color: props.color, name: "uiStar", size: props.size }); const EmptyStar = (props) => /* @__PURE__ */ jsx(Icon, { color: props.color, name: "uiStar", size: props.size }); Rating.displayName = "Rating"; //#endregion export { Rating, Rating as default }; globalThis.__vuiVersion__ = "5.3.1" //# sourceMappingURL=rating.js.map