Skip to content

Commit 6696594

Browse files
committed
added start rating with partial selection and accessibility
1 parent 4cd71c1 commit 6696594

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

src/App.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Metronome from './pages/MetroNome/Metronome'
88
import OtpInput from './pages/OTPInput/OtpInput'
99
import Pagination from './pages/Pagination'
1010
import ProgressBar from './pages/ProgressBar/ProgressBar'
11+
import StarRating from './pages/StarRating'
1112
const options=[
1213
{
1314
id:1,name:'Amit'
@@ -41,6 +42,7 @@ function App() {
4142
<>
4243
<div>
4344
<CustomCheckbox options={options}/>
45+
<StarRating/>
4446
</div>
4547
</>
4648
)

src/pages/StarRating/index.tsx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import React, { useState } from 'react';
2+
3+
const styles = {
4+
container: {
5+
display: 'inline-flex',
6+
fontSize: '32px',
7+
cursor: 'pointer',
8+
outline: 'none',
9+
},
10+
starWrapper: {
11+
position: 'relative',
12+
color: '#ddd',
13+
},
14+
starOverlay: {
15+
position: 'absolute',
16+
top: 0,
17+
left: 0,
18+
overflow: 'hidden',
19+
color: '#ffc107',
20+
pointerEvents: 'none',
21+
width: '0%',
22+
transition: 'width 0.2s'
23+
}
24+
};
25+
26+
const StarRating = ({ max = 5, initialValue = 0, onChange }) => {
27+
const [rating, setRating] = useState(initialValue);
28+
const [hover, setHover] = useState(null);
29+
console.log(rating,hover)
30+
const displayValue = hover !== null ? hover : rating;
31+
32+
const handleMouseMove = (e, index) => {
33+
const { left, width } = e.currentTarget.getBoundingClientRect();
34+
const percent = (e.clientX - left) / width;
35+
36+
const newValue = index + (percent < 0.5 ? 0.5 : 1);
37+
setHover(newValue);
38+
};
39+
40+
const handleClick = () => {
41+
const newValue = hover === rating ? 0 : hover;
42+
43+
setRating(newValue);
44+
if (onChange) onChange(newValue);
45+
};
46+
47+
const handleKeyDown = (e) => {
48+
let newValue = rating;
49+
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
50+
newValue = Math.min(max, rating + 0.5);
51+
e.preventDefault();
52+
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
53+
newValue = Math.max(0, rating - 0.5);
54+
e.preventDefault();
55+
}
56+
57+
if (newValue !== rating) {
58+
setRating(newValue);
59+
if (onChange) onChange(newValue);
60+
}
61+
};
62+
63+
return (
64+
<div
65+
style={styles.container}
66+
role="slider"
67+
tabIndex={0}
68+
aria-valuemin={0}
69+
aria-valuemax={max}
70+
aria-valuenow={rating}
71+
aria-label="Star Rating"
72+
onKeyDown={handleKeyDown}
73+
onMouseLeave={() => setHover(null)}
74+
>
75+
{[...Array(max)].map((_, i) => {
76+
let width = '0%';
77+
if (displayValue > i) {
78+
const val = displayValue - i;
79+
width = val >= 1 ? '100%' : `${val * 100}%`;
80+
}
81+
82+
return (
83+
<span
84+
key={i}
85+
style={styles.starWrapper}
86+
onMouseMove={(e) => handleMouseMove(e, i)}
87+
onClick={handleClick}
88+
>
89+
90+
<span style={{ ...styles.starOverlay, width }}>
91+
92+
</span>
93+
</span>
94+
);
95+
})}
96+
</div>
97+
);
98+
};
99+
100+
export default StarRating;

0 commit comments

Comments
 (0)