Skip to content

Commit

Permalink
feat(rating): create RatingStar component
Browse files Browse the repository at this point in the history
  • Loading branch information
acd02 committed Nov 3, 2023
1 parent 40a900f commit 890d09d
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
57 changes: 57 additions & 0 deletions packages/components/rating/src/RatingStar.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { cva, cx, type VariantProps } from 'class-variance-authority'

const emptyRemainingStarsOnHoverClass = cx('peer-hover:[&_>_div]:!w-none')

const ratingStarStyles = cva(
['peer', 'after:inset-none', 'group', 'relative', 'after:block after:absolute'],
{
variants: {
disabled: {
true: 'opacity-dim-3',
false: '',
},
readOnly: {
true: '',
false: '',
},
gap: {
sm: ['after:w-[calc(100%_+_theme(spacing.sm))]', 'last-of-type:after:content-none'],
md: ['after:w-[calc(100%_+_theme(spacing.md))]', 'last-of-type:after:content-none'],
},
},
compoundVariants: [
{
readOnly: false,
disabled: false,
className: cx(emptyRemainingStarsOnHoverClass, 'cursor-pointer'),
},
],
defaultVariants: {
disabled: false,
readOnly: false,
gap: 'sm',
},
}
)

const ratingStarIconStyles = cva('', {
variants: {
size: {
sm: 'text-caption-link',
md: 'text-body-1',
lg: 'text-display-1',
},
kind: {
filled: [
'text-main-variant',
'group-[[data-part=star][data-hovered]]:text-main-variant-hovered',
],
outlined: ['text-on-surface/dim-3'],
},
},
})

type RatingStarstylesProps = VariantProps<typeof ratingStarStyles>

export { ratingStarStyles, ratingStarIconStyles }
export type { RatingStarstylesProps }
58 changes: 58 additions & 0 deletions packages/components/rating/src/RatingStar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Icon } from '@spark-ui/icon'
import { StarFill } from '@spark-ui/icons/dist/icons/StarFill'
import { StarOutline } from '@spark-ui/icons/dist/icons/StarOutline'
import { cx } from 'class-variance-authority'
import { forwardRef, type MouseEvent } from 'react'

import {
ratingStarIconStyles,
ratingStarStyles,
type RatingStarstylesProps,
} from './RatingStar.styles'
import type { Size, StarValue } from './types'

export interface RatingStarProps extends RatingStarstylesProps {
size?: Size
value: StarValue
onClick: (event: MouseEvent<HTMLDivElement>) => void
onMouseEnter: (event: MouseEvent<HTMLDivElement>) => void
}

export const RatingStar = forwardRef<HTMLDivElement, RatingStarProps>(
({ value, size, disabled, readOnly, onClick, onMouseEnter }, forwardedRef) => {
return (
<div
ref={forwardedRef}
onMouseEnter={onMouseEnter}
className={ratingStarStyles({
gap: size === 'lg' ? 'md' : 'sm',
disabled,
readOnly,
})}
data-part="star"
onClick={onClick}
>
<div
className={cx(
'absolute z-raised overflow-hidden',
'group-[[data-part=star][data-hovered]]:overflow-visible'
)}
style={{ width: value * 100 + '%' }}
>
<Icon
className={ratingStarIconStyles({
size,
kind: 'filled',
})}
>
<StarFill />
</Icon>
</div>

<Icon className={ratingStarIconStyles({ size, kind: 'outlined' })}>
<StarOutline />
</Icon>
</div>
)
}
)

0 comments on commit 890d09d

Please sign in to comment.