UNPKG

@drivy/cobalt

Version:

Opinionated design system for Drivy's projects.

106 lines (105 loc) 4.23 kB
import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import classnames from "classnames"; import { nanoid } from "nanoid"; import react, { useCallback, useRef, useState } from "react"; import { getA11yOnClick } from "../../helpers/index.js"; import { StarFilledIcon } from "../Icon/index.js"; const defaultRatingIcon = /*#__PURE__*/ jsx(StarFilledIcon, { color: "primary" }); const itemEmptyColor = "surfaceContainerVariant"; function roundHalf(num) { return Math.floor(2 * num) / 2; } function computeItemStatus(ratingValue, itemValue, icon) { let itemStatus = "empty"; if (Array.isArray(icon)) { if (itemValue === ratingValue) itemStatus = "full"; } else { const isHalfItem = itemValue > ratingValue && ratingValue > itemValue - 1; if (isHalfItem) itemStatus = "half"; else if (itemValue <= ratingValue) itemStatus = "full"; } return itemStatus; } const RatingIcon = ({ icon, status = "full", size = 24 })=>{ if ("half" === status) return /*#__PURE__*/ jsxs(Fragment, { children: [ /*#__PURE__*/ react.cloneElement(icon, { color: itemEmptyColor, size }), /*#__PURE__*/ jsx("div", { className: "cobalt-rating-icons__icon-half-container", children: /*#__PURE__*/ react.cloneElement(icon, { size }) }) ] }); { const iconColor = "empty" === status ? itemEmptyColor : icon.props.color; return /*#__PURE__*/ react.cloneElement(icon, { color: iconColor, size }); } }; const RatingIcons = ({ className, max = 5, value, size = 24, editable = false, onChange, icon = defaultRatingIcon })=>{ const name = useRef(nanoid()); const items = useRef(Array.from(new Array(Array.isArray(icon) ? icon.length : max))); const [ratingValue, setRatingValue] = useState(()=>editable ? Math.floor(value) : roundHalf(value)); const [selectedIndex, setSelectedIndex] = useState(-1); const resetSelection = useCallback(()=>{ setSelectedIndex(-1); }, []); const itemSize = 48 === size ? 16 : size; return /*#__PURE__*/ jsx("div", { className: classnames("cobalt-rating-icons", className, { "cobalt-rating-icons--icon-size-48": 48 === size }), onPointerLeave: ()=>{ if (editable) document.activeElement.blur(); }, children: items.current.map((_value, idx)=>{ const itemValue = idx + 1; const itemStatus = computeItemStatus(ratingValue, itemValue, icon); return /*#__PURE__*/ jsxs("label", { className: classnames("cobalt-rating-icons__icon-wrapper", { "cobalt-rating-icons__icon-wrapper--selected": selectedIndex === idx }), ...getA11yOnClick(()=>{ if (editable) { setRatingValue(itemValue); setSelectedIndex(idx); } }), onMouseEnter: (e)=>{ if (editable) { e.target.focus(); resetSelection(); } }, children: [ /*#__PURE__*/ jsx("input", { tabIndex: editable && (ratingValue === itemValue || 0 === ratingValue && 1 === itemValue) ? 0 : -1, name: name.current, type: "radio", value: itemValue, onChange: ()=>{ onChange?.(itemValue); }, disabled: !editable }), /*#__PURE__*/ jsx(RatingIcon, { icon: Array.isArray(icon) ? icon[idx] : icon, status: itemStatus, size: itemSize }) ] }, itemValue); }) }); }; export { RatingIcon, RatingIcons, computeItemStatus, defaultRatingIcon, roundHalf }; //# sourceMappingURL=RatingIcons.js.map