feat(rating): a new component rating indicator (#543)

* chore(deps): bump lodash from 4.17.20 to 4.17.21 (#537)

Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* (feature) rating state working and islocked working

* (feature) custom emojis for the ratings added

* refactor(rating): migrate component to scaleable

* feat(rating): use inline icon component

test(rating): update testcase

* docs(rating): add document for zh-cn

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: unix <unix.bio@gmail.com>
This commit is contained in:
Nils J
2021-06-25 16:53:22 +02:00
committed by unix
parent 41213076a1
commit 144eaf332f
13 changed files with 34968 additions and 2 deletions

View File

@@ -118,6 +118,9 @@ export type { ProgressProps } from './progress'
export { default as Radio } from './radio'
export type { RadioProps, RadioGroupProps, RadioDescriptionProps } from './radio'
export { default as Rating } from './rating'
export type { RatingProps } from './rating'
export { default as Select } from './select'
export type { SelectProps, SelectOptionProps } from './select'

View File

@@ -0,0 +1,362 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Rating should render correctly 1`] = `
"<div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #000;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #000;
transform: scale(0.9);
}
</style></div>"
`;
exports[`Rating should show different initialization values 1`] = `
"<div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #000;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #000;
transform: scale(0.9);
}
</style></div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #000;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #000;
transform: scale(0.9);
}
</style></div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #000;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #000;
transform: scale(0.9);
}
</style></div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #000;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #000;
transform: scale(0.9);
}
</style></div></div>"
`;
exports[`Rating should update snapshot on mouse enter 1`] = `
"<div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #0070f3;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #0070f3;
transform: scale(0.9);
}
</style></div><div id=\\"valueDiv\\">5</div><div id=\\"lockDiv\\">false</div></div>"
`;
exports[`Rating should update snapshot on mouse enter 2`] = `
"<div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #0070f3;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: default;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #0070f3;
transform: scale(0.9);
}
</style></div><div id=\\"valueDiv\\">5</div><div id=\\"lockDiv\\">true</div></div>"
`;
exports[`Rating should work with different types 1`] = `
"<div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #000;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #000;
transform: scale(0.9);
}
</style></div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #0070f3;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #0070f3;
transform: scale(0.9);
}
</style></div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #f5a623;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #f5a623;
transform: scale(0.9);
}
</style></div><div class=\\"rating \\"><div class=\\"icon-box hovered\\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><div class=\\"icon-box \\"><svg viewBox=\\"0 0 24 24\\" width=\\"24\\" height=\\"24\\" stroke=\\"currentColor\\" stroke-width=\\"1.5\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\\"></path></svg></div><style>
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: calc(1 * 16px);
font-size: var(--rating-font-size);
width: auto;
height: auto;
padding: 0 0 0 0;
margin: 0 0 0 0;
}
.icon-box {
box-sizing: border-box;
color: #e00;
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: pointer;
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: #e00;
transform: scale(0.9);
}
</style></div></div>"
`;

View File

@@ -0,0 +1,108 @@
import React, { useState } from 'react'
import { Rating } from 'components'
import { mount } from 'enzyme'
import { nativeEvent } from 'tests/utils'
describe('Rating', () => {
it('should render correctly', () => {
const wrapper = mount(<Rating />)
expect(wrapper.html()).toMatchSnapshot()
expect(() => wrapper.unmount()).not.toThrow()
})
it('should work with different types', () => {
const wrapper = mount(
<div>
<Rating type="secondary" />
<Rating type="success" />
<Rating type="warning" />
<Rating type="error" />
</div>,
)
expect(wrapper.html()).toMatchSnapshot()
expect(() => wrapper.unmount()).not.toThrow()
})
it('should show different initialization values', () => {
const wrapper = mount(
<div>
<Rating count={10} value={5} />
<Rating count={2} value={1} />
<Rating count={10} value={10} />
<Rating count={2} value={2} />
</div>,
)
expect(wrapper.html()).toMatchSnapshot()
expect(() => wrapper.unmount()).not.toThrow()
})
it('should initialize state and lock value', () => {
const WrapperRating = () => {
const [value, setValue] = useState<number>(1)
const [lock, setLock] = useState<boolean>(false)
return (
<div>
<Rating
type="success"
value={value}
onLockedChange={setLock}
onValueChange={setValue}
/>
<div id="valueDiv">{value}</div>
<div id="lockDiv">{lock ? 'true' : 'false'}</div>
</div>
)
}
const wrapper = mount(<WrapperRating />)
expect(wrapper.find('svg').children())
expect(wrapper.find('#valueDiv').text()).toContain('1')
expect(wrapper.find('#lockDiv').text()).toContain('false')
})
it('should update state and lock value on click', () => {
const WrapperRating = () => {
const [value, setValue] = useState<number>(1)
const [lock, setLock] = useState<boolean>(false)
return (
<div>
<Rating type="success" onLockedChange={setLock} onValueChange={setValue} />
<div id="valueDiv">{value}</div>
<div id="lockDiv">{lock ? 'true' : 'false'}</div>
</div>
)
}
const wrapper = mount(<WrapperRating />)
expect(wrapper.find('.icon-box').last().simulate('click', nativeEvent))
expect(wrapper.find('#valueDiv').text()).toContain('5')
expect(wrapper.find('#lockDiv').text()).toContain('true')
// unlock again
expect(wrapper.find('.icon-box').last().simulate('click', nativeEvent))
expect(wrapper.find('#valueDiv').text()).toContain('5')
expect(wrapper.find('#lockDiv').text()).toContain('false')
})
it('should update snapshot on mouse enter', () => {
const WrapperRating = () => {
const [value, setValue] = useState<number>(0)
const [lock, setLock] = useState<boolean>(false)
return (
<div>
<Rating type="success" onLockedChange={setLock} onValueChange={setValue} />
<div id="valueDiv">{value}</div>
<div id="lockDiv">{lock ? 'true' : 'false'}</div>
</div>
)
}
const wrapper = mount(<WrapperRating />)
const lastStar = wrapper.find('.icon-box').last()
const firstStar = wrapper.find('.icon-box').first()
expect(lastStar.simulate('mouseenter'))
expect(wrapper.html()).toMatchSnapshot()
expect(lastStar.simulate('click', nativeEvent))
expect(firstStar.simulate('mouseenter'))
expect(wrapper.html()).toMatchSnapshot()
})
})

View File

@@ -0,0 +1,4 @@
import Rating from './rating'
export type { RatingProps, RatingTypes, RatingCount, RatingValue } from './rating'
export default Rating

View File

@@ -0,0 +1,21 @@
import React from 'react'
const RatingIcon: React.FC<unknown> = () => {
return (
<svg
viewBox="0 0 24 24"
width="24"
height="24"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
fill="none"
shapeRendering="geometricPrecision">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" />
</svg>
)
}
RatingIcon.displayName = 'GeistRatingIcon'
export default RatingIcon

View File

@@ -0,0 +1,141 @@
import React, { useEffect, useMemo, useState } from 'react'
import { GeistUIThemesPalette } from '../themes'
import { NormalTypes, tupleNumber } from '../utils/prop-types'
import RatingIcon from './rating-icon'
import useTheme from '../use-theme'
import useScaleable, { withScaleable } from '../use-scaleable'
export type RatingTypes = NormalTypes
const ratingCountTuple = tupleNumber(2, 3, 4, 5, 6, 7, 8, 9, 10)
const ratingValueTuple = tupleNumber(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
export type RatingValue = typeof ratingValueTuple[number]
export type RatingCount = typeof ratingCountTuple[number]
interface Props {
type?: RatingTypes
className?: string
icon?: JSX.Element
count?: RatingCount | number
value?: RatingValue | number
initialValue?: RatingValue
onValueChange?: (value: number) => void
locked?: boolean
onLockedChange?: (locked: boolean) => void
}
const defaultProps = {
type: 'default' as RatingTypes,
className: '',
icon: (<RatingIcon />) as JSX.Element,
count: 5 as RatingCount,
initialValue: 1 as RatingValue,
locked: false,
}
type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
export type RatingProps = Props & NativeAttrs
const getColor = (type: RatingTypes, palette: GeistUIThemesPalette): string => {
const colors: { [key in RatingTypes]?: string } = {
default: palette.foreground,
success: palette.success,
warning: palette.warning,
error: palette.error,
}
return colors[type] || (colors.default as string)
}
const RatingComponent: React.FC<RatingProps> = ({
type,
children,
className,
icon,
count,
value: customValue,
initialValue,
onValueChange,
locked,
onLockedChange,
...props
}: React.PropsWithChildren<RatingProps> & typeof defaultProps) => {
const theme = useTheme()
const { SCALES } = useScaleable()
const color = useMemo(() => getColor(type, theme.palette), [type, theme.palette])
const [value, setValue] = useState<number>(initialValue)
const [isLocked, setIsLocked] = useState<boolean>(locked)
const lockedChangeHandler = (next: boolean) => {
setIsLocked(next)
onLockedChange && onLockedChange(next)
}
const valueChangeHandler = (next: number) => {
setValue(next)
const emitValue = next > count ? count : next
onValueChange && onValueChange(emitValue)
}
const clickHandler = (index: number) => {
if (isLocked) return lockedChangeHandler(false)
valueChangeHandler(index)
lockedChangeHandler(true)
}
const mouseEnterHandler = (index: number) => {
if (isLocked) return
valueChangeHandler(index)
}
useEffect(() => {
if (typeof customValue === 'undefined') return
setValue(customValue < 0 ? 0 : customValue)
}, [customValue])
return (
<div className={`rating ${className}`} {...props}>
{[...Array(count)].map((_, index) => (
<div
className={`icon-box ${index + 1 <= value ? 'hovered' : ''}`}
key={index}
onMouseEnter={() => mouseEnterHandler(index + 1)}
onClick={() => clickHandler(index + 1)}>
{icon}
</div>
))}
<style jsx>{`
.rating {
box-sizing: border-box;
display: inline-flex;
align-items: center;
--rating-font-size: ${SCALES.font(1)};
font-size: var(--rating-font-size);
width: ${SCALES.width(1, 'auto')};
height: ${SCALES.height(1, 'auto')};
padding: ${SCALES.pt(0)} ${SCALES.pr(0)} ${SCALES.pb(0)} ${SCALES.pl(0)};
margin: ${SCALES.mt(0)} ${SCALES.mr(0)} ${SCALES.mb(0)} ${SCALES.ml(0)};
}
.icon-box {
box-sizing: border-box;
color: ${color};
width: calc(var(--rating-font-size) * 1.5);
height: calc(var(--rating-font-size) * 1.5);
margin-right: calc(var(--rating-font-size) * 1 / 5);
cursor: ${isLocked ? 'default' : 'pointer'};
}
.icon-box :global(svg) {
width: 100%;
height: 100%;
fill: transparent;
transform: scale(1);
transition: transform, color, fill 30ms linear;
}
.hovered :global(svg) {
fill: ${color};
transform: scale(0.9);
}
`}</style>
</div>
)
}
RatingComponent.defaultProps = defaultProps
RatingComponent.displayName = 'GeistRating'
const Rating = withScaleable(RatingComponent)
export default Rating

View File

@@ -1,5 +1,7 @@
export const tuple = <T extends string[]>(...args: T) => args
export const tupleNumber = <T extends number[]>(...args: T) => args
const buttonTypes = tuple(
'default',
'secondary',

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
next-env.d.ts vendored
View File

@@ -1,2 +1,3 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

34093
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
import { Layout, Playground, Attributes } from 'lib/components'
import { Rating, Grid, Spacer } from 'components'
import { useState } from 'react'
import { Award, Github } from '@geist-ui/react-icons'
export const meta = {
title: 'Rating',
group: 'Feedback',
}
## Rating
Display an indicator of rankings with stars.
<Playground
title="Default"
desc="A default rating component with initializers and callbacks."
scope={{ Rating, Grid, useState }}
code={`
() => {
const [value, setValue] = useState(1)
const [locked, setLocked] = useState(false)
return(
<Grid.Container gap={2}>
<Grid xs={24} md={8} justify="center">
<Rating onLockedChange={setLocked} value={value} onValueChange={setValue}/>
</Grid>
<Grid xs={12} md={8} justify="center">Selection: {value}</Grid>
<Grid xs={12} md={8} justify="center">Locked: {locked ? "true" : "false"}</Grid>
</Grid.Container>
)
}
`}
/>
<Playground
title="Types"
desc="Pass the property `type` to the Rating component."
scope={{ Rating, Grid }}
code={`
<Grid.Container gap={2} justify="center">
<Grid xs={24} sm={24} md={8} justify="center"><Rating type="success"/></Grid>
<Grid xs={24} sm={12} md={8} justify="center"><Rating type="error"/></Grid>
<Grid xs={24} sm={12} md={8} justify="center"><Rating type="warning"/></Grid>
</Grid.Container>
`}
/>
<Playground
title="Custom Amount"
desc="Customize the amount of stars."
scope={{ Rating, Spacer }}
code={`
<>
<Rating count={2} />
<Spacer h={0.5} />
<Rating value={3} count={6} />
<Spacer h={0.5} />
<Rating value={4} count={8}/>
</>
`}
/>
<Playground
title="Icon"
desc="Customize the icons of a rating."
scope={{ Rating, Award, Github, Spacer }}
code={`
<>
<Rating
value={4}
count={6}
type="success"
icon={<Github />} />
<Spacer h={0.5} />
<Rating count={7} type="error" icon={<Award />} />
</>
`}
/>
<Attributes edit="/pages/en-us/components/rating.mdx">
<Attributes.Title>Rating.Props</Attributes.Title>
| Attribute | Description | Type | Accepted values | Default |
| ------------------ | ------------------- | ----------------------- | --------------------------- | --------- |
| **type** | rating type | `RatingTypes` | [RatingTypes](#ratingtypes) | `default` |
| **icon** | custom icon | `JSX.Element` | - | - |
| **count** | rating star count | `number` | [RatingCount](#ratingcount) | `5` |
| **value** | star values | `number` | [RatingValue](#ratingvalue) | - |
| **initialValue** | initial star values | `number` | [RatingValue](#ratingvalue) | `1` |
| **onValueChange** | value change event | `(value?: any) => void` | - | - |
| **locked** | lock state | `boolean` | - | `false` |
| **onLockedChange** | locked change event | `(value?: any) => void` | - | - |
| ... | native props | `HTMLAttributes` | - | - |
<Attributes.Title>RatingTypes</Attributes.Title>
```ts
type RatingTypes = 'default' | 'secondary' | 'success' | 'warning' | 'error'
```
<Attributes.Title>RatingCount</Attributes.Title>
```ts
type RatingCount = 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
```
<Attributes.Title>RatingValue</Attributes.Title>
```ts
type RatingValue = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
```
</Attributes>
export default ({ children }) => <Layout meta={meta}>{children}</Layout>

View File

@@ -0,0 +1,115 @@
import { Layout, Playground, Attributes } from 'lib/components'
import { Rating, Grid, Spacer } from 'components'
import { useState } from 'react'
import { Award, Github } from '@geist-ui/react-icons'
export const meta = {
title: '评分 Rating',
group: '反馈',
}
## Rating / 评分
以多个图标展示可互动的评分。
<Playground
desc="设置初始值与回调事件。"
scope={{ Rating, Grid, useState }}
code={`
() => {
const [value, setValue] = useState(1)
const [locked, setLocked] = useState(false)
return(
<Grid.Container gap={2}>
<Grid xs={24} md={8} justify="center">
<Rating onLockedChange={setLocked} value={value} onValueChange={setValue}/>
</Grid>
<Grid xs={12} md={8} justify="center">已选择: {value}</Grid>
<Grid xs={12} md={8} justify="center">锁定: {locked ? "是" : "否"}</Grid>
</Grid.Container>
)
}
`}
/>
<Playground
title="类型"
desc="通过 `type` 属性展示不同的评分组件。"
scope={{ Rating, Grid }}
code={`
<Grid.Container gap={2} justify="center">
<Grid xs={24} sm={24} md={8} justify="center"><Rating type="success"/></Grid>
<Grid xs={24} sm={12} md={8} justify="center"><Rating type="error"/></Grid>
<Grid xs={24} sm={12} md={8} justify="center"><Rating type="warning"/></Grid>
</Grid.Container>
`}
/>
<Playground
title="最大数量"
desc="定制图标的最大数量。"
scope={{ Rating, Spacer }}
code={`
<>
<Rating count={2} />
<Spacer h={0.5} />
<Rating value={3} count={6} />
<Spacer h={0.5} />
<Rating value={4} count={8}/>
</>
`}
/>
<Playground
title="图标"
desc="以自定义 SVG 图标代替默认的星星图案。"
scope={{ Rating, Award, Github, Spacer }}
code={`
<>
<Rating
value={4}
count={6}
type="success"
icon={<Github />} />
<Spacer h={0.5} />
<Rating count={7} type="error" icon={<Award />} />
</>
`}
/>
<Attributes edit="/pages/zh-cn/components/rating.mdx">
<Attributes.Title>Rating.Props</Attributes.Title>
| 属性 | 描述 | 类型 | 推荐值 | 默认 |
| ------------------ | ---------------- | ----------------------- | --------------------------- | --------- |
| **type** | 评分组件类型 | `RatingTypes` | [RatingTypes](#ratingtypes) | `default` |
| **icon** | 自定义图标 | `JSX.Element` | - | - |
| **count** | 展示图标最大数量 | `number` | [RatingCount](#ratingcount) | `5` |
| **value** | 选中值 | `number` | [RatingValue](#ratingvalue) | - |
| **initialValue** | 初始值 | `number` | [RatingValue](#ratingvalue) | `1` |
| **onValueChange** | 值变化的事件 | `(value?: any) => void` | - | - |
| **locked** | 是否锁定 | `boolean` | - | `false` |
| **onLockedChange** | 锁定变化事件 | `(value?: any) => void` | - | - |
| ... | 原生属性 | `HTMLAttributes` | - | - |
<Attributes.Title>RatingTypes</Attributes.Title>
```ts
type RatingTypes = 'default' | 'secondary' | 'success' | 'warning' | 'error'
```
<Attributes.Title>RatingCount</Attributes.Title>
```ts
type RatingCount = 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
```
<Attributes.Title>RatingValue</Attributes.Title>
```ts
type RatingValue = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
```
</Attributes>
export default ({ children }) => <Layout meta={meta}>{children}</Layout>