@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
JavaScript
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