import React , { forwardRef , ReactNode , ChangeEvent , useCallback } from 'react' ; import { BaseProps , SizeType } from '@toptal/picasso-shared' ; import { makeStyles } from '@material-ui/core/styles' ; import cx from 'classnames' ; import Container from '../Container' ; import RatingIcon from '../RatingIcon' ; import styles from './styles' ; export type RatingSize = SizeType < 'small' | 'large' > ; export interface Props extends BaseProps { /** Value of the name attribute of the rating input */ name : string ; /** Current rating */ value ? : number ; /** Callback invoked when a rating icon is clicked */ onChange ? : ( event : ChangeEvent < HTMLInputElement > ) => void ; /** Function to customize icon rendering */ renderItem ? : ( value : number , defaultIcon : ReactNode ) => ReactNode ; /** Number of rating icons */ max ? : number ; /** Flag to allow or disable interactions with the component */ interactive ? : boolean ; /** Size variant */ size ? : RatingSize ; } const useStyles = makeStyles ( styles , { name : 'PicassoRating' } ) ; const Rating = forwardRef < HTMLDivElement , Props > ( function Rating ( props , ref ) { const { name , value , onChange , renderItem = ( _ , icon ) => icon , max , interactive = true , size = 'small' , ... rest } = props ; const classes = useStyles ( ) ; const handleChange = useCallback ( ( event ) => { if ( onChange && interactive ) { onChange ( event ) ; } } , [ onChange , interactive ] ) ; const resetInputId = `${ name }-reset` ; return ( < Container { ... rest } ref = { ref } > { [ ... Array ( max ) ] . map ( ( _ , index ) => { const itemValue = index + 1 ; const itemId = `${ name }-${ itemValue }` ; const defaultIcon = ( < RatingIcon active = { ! ! value && itemValue <= value } interactive = { interactive } size = { size } / > ) ; const shouldReset = itemValue === Number ( value ) ; return ( < label key = { itemId } htmlFor = { shouldReset ? resetInputId : itemId } className = { cx ( classes . label , { [ classes . clickableLabel ] : interactive } ) } > { renderItem ( itemValue , defaultIcon ) } < input type = 'radio' name = { name } id = { itemId } value = { itemValue } onChange = { handleChange } readOnly = { ! interactive } checked = { itemValue === value } className = { classes . radio } data - testid = { itemId } /> < /label>); } ) } { } < input type = 'radio' name = { name } id = { resetInputId } value = '' onChange = { handleChange } className = { classes . radio } / > < /Container>); } ) ; Rating . defaultProps = { interactive : true , max : 5 , size : 'small' } ; Rating . displayName = 'Rating' ; export default Rating ;