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 GitHub
parent 81d444d167
commit 26490d43d4
14 changed files with 35072 additions and 101 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',