From 974c0348f0adc66ce1f03cd2459aed3d5671b545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C9=A7=CF=83=E2=84=93=CF=83?= Date: Fri, 13 Feb 2026 18:23:18 +0100 Subject: [PATCH] feat: add half-star rating support with click position detection and visual rendering --- src/components/StarRating.jsx | 65 ++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/src/components/StarRating.jsx b/src/components/StarRating.jsx index 55f7420..0260c34 100644 --- a/src/components/StarRating.jsx +++ b/src/components/StarRating.jsx @@ -1,28 +1,51 @@ import { Star } from "lucide-react"; -export default function StarRating({ value, onChange, disabled = false }) { +export default function StarRating({ value = 0, onChange, disabled = false }) { + const handleSelect = (event, star) => { + if (disabled) return; + + const rect = event.currentTarget.getBoundingClientRect(); + let clientX = event.clientX ?? event.nativeEvent?.clientX ?? 0; + + if (event.nativeEvent?.touches?.length) { + clientX = event.nativeEvent.touches[0].clientX; + } else if (event.nativeEvent?.changedTouches?.length) { + clientX = event.nativeEvent.changedTouches[0].clientX; + } + + const clickX = clientX - rect.left; + const isHalf = clickX <= rect.width / 2; + const nextValue = isHalf ? star - 0.5 : star; + + onChange?.(value === nextValue ? 0 : nextValue); + }; + return (
- {[1, 2, 3, 4, 5].map((star) => ( - - ))} + {[1, 2, 3, 4, 5].map((star) => { + const filled = Math.min(Math.max(value - (star - 1), 0), 1); + + return ( + + ); + })}
); }