Skip to content

Commit 640cb47

Browse files
authored
Merge pull request mxdi9i7#32 from mxdi9i7/peterz/rate
Rate Component
2 parents 716c2d6 + 14ce50e commit 640cb47

File tree

6 files changed

+255
-1
lines changed

6 files changed

+255
-1
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

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@import '../../styles/colors.scss';
2+
@import '../../styles/spacing.scss';
3+
@import '../../styles/typography.scss';
4+
@import '../../styles/opacity.scss';
5+
@import '../../styles/variables.scss';
6+
7+
$baseClass: 'vant-rate';
8+
9+
.#{$baseClass} {
10+
display: flex;
11+
cursor: pointer;
12+
13+
.#{$baseClass}__icon {
14+
&:last-of-type {
15+
margin-right: 0 !important;
16+
}
17+
}
18+
}

src/components/Rate/index.stories.tsx

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { useState } from 'react';
2+
import Rate from '../Rate';
3+
import '../../styles/stories.scss';
4+
5+
export default {
6+
title: 'Rate',
7+
component: Rate
8+
};
9+
10+
export const BasicUsage = () => (
11+
<div className='container column grey'>
12+
<Rate currentRate={4} />
13+
</div>
14+
);
15+
16+
export const CustomIcon = () => (
17+
<div className='container column grey'>
18+
<Rate currentRate={4} icon='like' voidIcon='like-o' />
19+
</div>
20+
);
21+
22+
export const CustomColor = () => (
23+
<div className='container column grey'>
24+
<Rate currentRate={4} icon='like' voidIcon='like-o' color='#1989fa' />
25+
</div>
26+
);
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

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import React, { useState } from 'react';
2+
import shortid from 'shortid';
3+
4+
import classnames from '../../utils/classNames';
5+
6+
import './index.scss';
7+
import Icon from '../Icons';
8+
import { IProps } from './types';
9+
import RateIcon from './subcomponents/rate-icon';
10+
11+
const baseClass = 'vant-rate';
12+
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+
);
37+
}
38+
return icons;
39+
};
40+
41+
const Rate = ({
42+
currentRate = 5,
43+
count = 5,
44+
size = '20px',
45+
icon = 'star',
46+
voidIcon = 'star-o',
47+
gutter = '4px',
48+
color = '#ffd21e',
49+
voidColor = '#c8c9cc',
50+
disabledColor = '#c8c9cc',
51+
allowHalf,
52+
disabled,
53+
readonly,
54+
change
55+
}: IProps) => {
56+
const [activeCount, setActiveCount] = useState(currentRate || count);
57+
58+
const rateProps = {
59+
className: classnames(baseClass, [
60+
{
61+
allowHalf,
62+
disabled,
63+
readonly
64+
}
65+
])
66+
};
67+
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+
79+
return (
80+
<div {...rateProps}>
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+
)}
101+
</div>
102+
);
103+
};
104+
105+
export default Rate;
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

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export interface IProps {
2+
currentRate?: number;
3+
count?: number;
4+
size?: string;
5+
icon?: string;
6+
gutter?: string;
7+
voidIcon?: string;
8+
allowHalf?: boolean;
9+
disabled?: boolean;
10+
readonly?: boolean;
11+
color?: string;
12+
voidColor?: string;
13+
disabledColor?: string;
14+
touchable?: boolean;
15+
change?: Function;
16+
}

0 commit comments

Comments
 (0)