Skip to content

Commit cc5fbda

Browse files
committed
wrapping up rate component for pr
1 parent 75fb282 commit cc5fbda

File tree

6 files changed

+158
-36
lines changed

6 files changed

+158
-36
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
]
8989
},
9090
"dependencies": {
91-
"node-sass": "^4.14.1"
91+
"node-sass": "^4.14.1",
92+
"shortid": "^2.2.15"
9293
}
9394
}

src/components/Rate/index.scss

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
$baseClass: 'vant-rate';
88

99
.#{$baseClass} {
10-
display: flex;
11-
cursor: pointer;
10+
display: flex;
11+
cursor: pointer;
12+
13+
.#{$baseClass}__icon {
14+
&:last-of-type {
15+
margin-right: 0 !important;
16+
}
17+
}
1218
}

src/components/Rate/index.stories.tsx

+65
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,68 @@ export const CustomColor = () => (
2424
<Rate currentRate={4} icon='like' voidIcon='like-o' color='#1989fa' />
2525
</div>
2626
);
27+
28+
export const CustomCount = () => (
29+
<div className='container column grey'>
30+
<Rate
31+
count={10}
32+
currentRate={4}
33+
icon='like'
34+
voidIcon='like-o'
35+
color='#1989fa'
36+
/>
37+
</div>
38+
);
39+
40+
export const Disabled = () => (
41+
<div className='container column grey'>
42+
<Rate
43+
disabled
44+
currentRate={4}
45+
icon='like'
46+
voidIcon='like-o'
47+
color='#1989fa'
48+
/>
49+
</div>
50+
);
51+
52+
export const ReadOnly = () => (
53+
<div className='container column grey'>
54+
<Rate
55+
readonly
56+
currentRate={4}
57+
icon='like'
58+
voidIcon='like-o'
59+
color='#1989fa'
60+
/>
61+
</div>
62+
);
63+
64+
export const CustomGutter = () => (
65+
<div className='container column grey'>
66+
<Rate
67+
gutter='8px'
68+
currentRate={4}
69+
icon='like'
70+
voidIcon='like-o'
71+
color='#1989fa'
72+
/>
73+
</div>
74+
);
75+
76+
export const ListenOnChange = () => {
77+
const [currentRate, setRate] = useState(4);
78+
79+
return (
80+
<div className='container column grey'>
81+
<h1>{currentRate}</h1>
82+
<Rate
83+
change={(rate) => setRate(rate)}
84+
currentRate={currentRate}
85+
icon='like'
86+
voidIcon='like-o'
87+
color='#1989fa'
88+
/>
89+
</div>
90+
);
91+
};

src/components/Rate/index.tsx

+59-33
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,39 @@
11
import React, { useState, useEffect } from 'react';
2+
import shortid from 'shortid';
23

34
import classnames from '../../utils/classNames';
45

56
import './index.scss';
67
import Icon from '../Icons';
78
import { IProps } from './types';
9+
import RateIcon from './subcomponents/rate-icon';
810

911
const baseClass = 'vant-rate';
1012

11-
const renderIcons = (icons, iconCount, iconName, iconColor, iconSize) => {
12-
for (let i = 0; i < iconCount; i++) {
13-
icons.push(<Icon color={iconColor} size={iconSize} name={iconName} />);
13+
const renderIcon = (
14+
color,
15+
size,
16+
icon,
17+
numberOfIcons,
18+
handleClick,
19+
isActive,
20+
activeCount,
21+
gutter
22+
) => {
23+
const icons = new Array(numberOfIcons);
24+
for (let i = 0; i < numberOfIcons; i++) {
25+
icons.push(
26+
<RateIcon
27+
index={i}
28+
gutter={gutter}
29+
handleClick={(index) =>
30+
handleClick(isActive ? index : index + activeCount)
31+
}
32+
key={shortid.generate()}
33+
icon={<Icon color={color} size={size} name={icon} />}
34+
className={`${baseClass}__icon`}
35+
/>
36+
);
1437
}
1538
return icons;
1639
};
@@ -28,32 +51,9 @@ const Rate = ({
2851
allowHalf,
2952
disabled,
3053
readonly,
31-
touchable
54+
change
3255
}: IProps) => {
33-
const [rateIcons, setRateIcons] = useState([]);
34-
35-
useEffect(() => {
36-
let currentIcons = [...rateIcons];
37-
if (disabled) {
38-
currentIcons = renderIcons(
39-
currentIcons,
40-
count,
41-
icon,
42-
disabledColor,
43-
size
44-
);
45-
} else {
46-
currentIcons = renderIcons(currentIcons, currentRate, icon, color, size);
47-
currentIcons = renderIcons(
48-
currentIcons,
49-
count - currentRate,
50-
voidIcon,
51-
voidColor,
52-
size
53-
);
54-
}
55-
setRateIcons(currentIcons);
56-
}, []);
56+
const [activeCount, setActiveCount] = useState(currentRate || count);
5757

5858
const rateProps = {
5959
className: classnames(baseClass, [
@@ -65,13 +65,39 @@ const Rate = ({
6565
])
6666
};
6767

68+
// TODO: Add half star feature
69+
// TODO: Add touchable feature
70+
71+
const handleClick = (index) => {
72+
if (!disabled && !readonly) {
73+
const nextRate = index + 1;
74+
setActiveCount(nextRate);
75+
if (!!change) change(nextRate);
76+
}
77+
};
78+
6879
return (
6980
<div {...rateProps}>
70-
{rateIcons.map((v, i) => (
71-
<div key={i} className={`${baseClass}__icon`}>
72-
{v}
73-
</div>
74-
))}
81+
{renderIcon(
82+
disabled ? disabledColor : color,
83+
size,
84+
icon,
85+
activeCount,
86+
handleClick,
87+
true,
88+
activeCount,
89+
gutter
90+
)}
91+
{renderIcon(
92+
disabled ? disabledColor : voidColor,
93+
size,
94+
voidIcon,
95+
count - activeCount,
96+
handleClick,
97+
false,
98+
activeCount,
99+
gutter
100+
)}
75101
</div>
76102
);
77103
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React, { ReactElement } from 'react';
2+
3+
interface Props {
4+
icon: ReactElement;
5+
className: string;
6+
handleClick: Function;
7+
index: number;
8+
gutter: string;
9+
}
10+
11+
const RateIcon = ({ handleClick, index, gutter, icon, className }: Props) => {
12+
return (
13+
<span
14+
style={{ marginRight: gutter }}
15+
onClick={() => handleClick(index)}
16+
className={className}
17+
>
18+
{icon}
19+
</span>
20+
);
21+
};
22+
23+
export default RateIcon;

src/components/Rate/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export interface IProps {
1212
voidColor?: string;
1313
disabledColor?: string;
1414
touchable?: boolean;
15+
change?: Function;
1516
}

0 commit comments

Comments
 (0)