@muvehealth/fixins
Version:
Component library for Muvehealth
164 lines (153 loc) • 4.52 kB
Flow
// @flow
import React, { PureComponent } from 'react'
import { any, append, equals, map, pathOr, prop, propOr, reject } from 'ramda'
import Box from '../../elements/Box'
import Checkbox from '../../elements/Checkbox'
import ErrorMessage from '../../elements/ErrorMessage'
import Grid from '../../elements/Grid'
import Label from '../../elements/Label'
import { isNotEmptyOrNotNil } from '../../utils'
import { type EventType, type InputType, type MetaType } from '../../types'
const checkboxGridModifierProps = (modifier, columns) => {
switch (modifier) {
case 'vertical':
return null
default:
return {
gridTemplateColumns: [
'1fr',
`repeat(${columns != null ? columns : 4}, 1fr)`,
`repeat(${columns != null ? columns : 4}, 1fr)`,
],
gridTemplateRows: [
`repeat(${columns != null ? columns : 4}, 1fr)`,
'1fr',
'1fr',
],
}
}
}
type Props = {
change?: (string | () => string, Array<string> | () => Array<string>) => void,
columns?: number,
input?: InputType,
gridStyles?: {},
label: string,
labelColor?: ?string,
labelModifier?: ?string,
labelTextStyle?: string,
meta?: MetaType,
modifier?: string,
noLabel?: boolean,
onChange?: ?(boolean, Array<string>) => void,
onChangeDouble?: ?(boolean, Array<string>) => void,
readOnly?: boolean,
values: Array<{
label: string,
value: string,
id?: ?string,
}>,
}
type State = {
values: Array<string>,
}
class CheckboxGroup extends PureComponent<Props, State> {
static defaultProps = {
change: undefined,
columns: 4,
gridStyles: undefined,
input: undefined,
labelColor: undefined,
labelModifier: undefined,
labelTextStyle: '',
meta: undefined,
modifier: 'horizontal',
noLabel: false,
onChange: undefined,
onChangeDouble: undefined,
readOnly: false,
}
// eslint-disable-next-line react/no-unused-state
state = { values: [] }
componentWillMount() {
this.setState((state, props) => ({
values: pathOr([], ['input', 'value'], props),
}))
}
handleOnChange = (e: EventType) => {
const { target } = e
this.setState((state, props) => {
let newValues = state.values
const { change, input, onChange, onChangeDouble } = props
if (target && target.checked) {
newValues = append(target.value, state.values)
} else if (target && !target.checked) {
newValues = reject(equals(target.value), state.values)
}
if (change && input) {
change(input.name, newValues)
}
if (onChangeDouble != null) {
onChangeDouble(target.checked, newValues)
} else if (onChange) {
onChange(target.checked, newValues)
}
return {
values: newValues,
}
})
}
render() {
const { columns, input, label, labelColor, labelModifier, labelTextStyle,
meta, modifier, noLabel, onChange, onChangeDouble,
readOnly, values, gridStyles, ...styles
} = this.props
return (
<Box {...styles}>
<Label
color={labelColor}
fontSize={2}
hidden={noLabel}
htmlFor={prop('name', input)}
mb={4}
textStyle={labelModifier === 'decal' ? 'uppercase' : labelTextStyle}
modifier={labelModifier}
>
{label}
</Label>
<Grid
gridColumnGap={3}
gridRowGap={4}
{...checkboxGridModifierProps(modifier, columns)}
// $FlowFixMe: Dont want to limit styled-system props
{...gridStyles}
>
{ map(({ label: optionLabel, value: optionValue }) => (
<Checkbox
defaultChecked={any(equals(optionValue), propOr([], 'value', input))}
id={`${prop('name', input)}-${optionLabel}`}
key={optionLabel}
label={optionLabel}
name={prop('name', input)}
onFocus={prop('onFocus', input)}
onChange={this.handleOnChange}
onBlur={this.handleOnChange}
readOnly={readOnly === true}
value={optionValue}
/>
), values)
}
</Grid>
{ prop('touched', meta) === true && isNotEmptyOrNotNil(prop('error', meta))
&& (
<ErrorMessage
message={prop('error', meta)}
maxWidth={116}
/>
)
}
</Box>
)
}
}
export default CheckboxGroup