@yamada-ui/rating
Version:
Yamada UI rating component
209 lines (207 loc) • 5.53 kB
JavaScript
"use client"
import {
RatingGroup
} from "./chunk-LHWQAME3.mjs";
import {
getRoundedValue
} from "./chunk-5OU2JQG4.mjs";
// src/use-rating.tsx
import {
formControlProperties,
useFormControlProps
} from "@yamada-ui/form-control";
import { useControllableState } from "@yamada-ui/use-controllable-state";
import {
clampNumber,
dataAttr,
handlerAll,
mergeRefs,
runIfFunc,
splitObject
} from "@yamada-ui/utils";
import { useCallback, useId, useRef, useState } from "react";
import { jsx } from "react/jsx-runtime";
var useRating = ({
name,
color,
defaultValue = 0,
emptyIcon,
filledIcon,
fractions = 1,
highlightSelectedOnly = false,
items = 5,
value: valueProp,
groupProps,
inputProps,
itemProps,
onChange: onChangeProp,
onHover,
onMouseEnter: onMouseEnterProp,
onMouseLeave: onMouseLeaveProp,
onMouseMove: onMouseMoveProp,
onTouchEnd: onTouchEndProp,
onTouchStart: onTouchStartProp,
...props
}) => {
const uuid = useId();
const { id = uuid, ...rest } = useFormControlProps(props);
const containerRef = useRef(null);
const [value, setValue] = useControllableState({
defaultValue,
value: valueProp,
onChange: onChangeProp
});
const [hoveredValue, setHoveredValue] = useState(-1);
const [outside, setOutside] = useState(true);
const [formControlProps, containerProps] = splitObject(
rest,
formControlProperties
);
const { disabled, readOnly, ...omittedFormControlProps } = formControlProps;
const resolvedFractions = Math.floor(fractions);
const resolvedItems = Math.floor(items);
const decimal = 1 / resolvedFractions;
const roundedValue = getRoundedValue(value, decimal);
const resolvedValue = hoveredValue !== -1 ? hoveredValue : roundedValue;
name != null ? name : name = `rating-${id}`;
const getHoveredValue = useCallback(
(x) => {
const { left, width } = containerRef.current.getBoundingClientRect();
const itemWidth = width / resolvedItems;
const hoveredValue2 = (x - left) / itemWidth;
const value2 = clampNumber(
getRoundedValue(hoveredValue2 + decimal / 2, decimal),
decimal,
resolvedItems
);
return value2;
},
[decimal, resolvedItems]
);
const onMouseEnter = useCallback(() => {
if (!disabled && !readOnly) setOutside(false);
}, [disabled, readOnly]);
const onMouseLeave = useCallback(() => {
if (disabled || readOnly) return;
setHoveredValue(-1);
setOutside(true);
if (hoveredValue !== -1) onHover == null ? void 0 : onHover(-1);
}, [disabled, hoveredValue, onHover, readOnly, setHoveredValue]);
const onTouchStart = useCallback(
(ev) => {
ev.preventDefault();
const el = ev.touches[0];
if (!el) return;
const value2 = getHoveredValue(el.clientX);
setValue(value2);
},
[getHoveredValue, setValue]
);
const onTouchEnd = useCallback((ev) => {
ev.preventDefault();
}, []);
const onMouseMove = useCallback(
(ev) => {
if (disabled || readOnly) return;
const roundedValue2 = getHoveredValue(ev.clientX);
setHoveredValue(roundedValue2);
if (roundedValue2 !== hoveredValue) onHover == null ? void 0 : onHover(roundedValue2);
},
[disabled, getHoveredValue, hoveredValue, readOnly, onHover]
);
const getContainerProps = useCallback(
(props2 = {}, ref = null) => ({
ref: mergeRefs(ref, containerRef),
"aria-label": `${value} Stars`,
role: "radiogroup",
...omittedFormControlProps,
...containerProps,
...props2,
id,
onMouseEnter: handlerAll(
onMouseEnter,
props2.onMouseEnter,
onMouseEnterProp
),
onMouseLeave: handlerAll(
onMouseLeave,
props2.onMouseLeave,
onMouseLeaveProp
),
onMouseMove: handlerAll(onMouseMove, props2.onMouseMove, onMouseMoveProp),
onTouchEnd: handlerAll(onTouchEnd, props2.onTouchEnd, onTouchEndProp),
onTouchStart: handlerAll(
onTouchStart,
props2.onTouchStart,
onTouchStartProp
)
}),
[
omittedFormControlProps,
containerProps,
id,
value,
onMouseEnter,
onMouseEnterProp,
onMouseLeave,
onMouseLeaveProp,
onMouseMove,
onMouseMoveProp,
onTouchEnd,
onTouchEndProp,
onTouchStart,
onTouchStartProp
]
);
const getGroupProps = useCallback(
({ value: value2, ...props2 }, ref = null) => {
const isActive = !readOnly && Math.ceil(hoveredValue) === value2;
return {
ref,
whileTap: !disabled && !readOnly ? { y: -4 } : void 0,
...props2,
"data-active": dataAttr(isActive),
tabIndex: -1
};
},
[disabled, hoveredValue, readOnly]
);
const children = Array(resolvedItems).fill(0).map((_, index) => {
const value2 = index + 1;
return /* @__PURE__ */ jsx(
RatingGroup,
{
color: runIfFunc(color, value2),
items: index === 0 ? resolvedFractions + 1 : resolvedFractions,
value: value2
},
value2
);
});
return {
id,
name,
children,
decimal,
emptyIcon,
filledIcon,
highlightSelectedOnly,
hoveredValue,
outside,
resolvedValue,
roundedValue,
setHoveredValue,
setValue,
value,
formControlProps,
getContainerProps,
getGroupProps,
groupProps,
inputProps,
itemProps
};
};
export {
useRating
};
//# sourceMappingURL=chunk-PRD35X5H.mjs.map