Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import TextFieldComponent from './text-field'
import WidgetStatsComponent from './widget-stats'
// export { default as WidgetNumber } from './widget-number' // deprecated by WidgetStats
// export { default as WidgetTrend } from './widget-trend' // deprecated by WidgetStats
import SelectionGroupComponent from './selection-group'

const wrapTheme = (WrappedComponent, theme = defaultTheme) => {
class Wrapper extends React.PureComponent {
Expand Down Expand Up @@ -57,6 +58,7 @@ const StyledSwitch = wrapTheme(StyledSwitchComponent)
const TabPanels = wrapTheme(TabPanelsComponent)
const TextField = wrapTheme(TextFieldComponent)
const WidgetStats = wrapTheme(WidgetStatsComponent)
const SelectionGroup = wrapTheme(SelectionGroupComponent)

export {
Alert,
Expand All @@ -77,4 +79,5 @@ export {
TabPanels,
TextField,
WidgetStats,
SelectionGroup,
}
41 changes: 41 additions & 0 deletions src/selection-group/checkbox-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react'
import PropTypes from 'prop-types'

import FormGroup from '@material-ui/core/FormGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import Grid from '@material-ui/core/Grid'

import StyledCheckbox from '../styled-checkbox'


const CheckboxGroup = ({ filterVals, checkboxOnChange, direction }) => (
<FormGroup>
<Grid container direction={direction}>
{filterVals.map((val) => {
const [optionName, optionState] = Object.entries(val)[0]
return (
<div key={optionName}>
<FormControlLabel
control={(
<StyledCheckbox
checked={optionState}
onChange={checkboxOnChange}
name={optionName}
/>
)}
label={optionName}
/>
</div>
)
})}
</Grid>
</FormGroup>
)

CheckboxGroup.propTypes = {
filterVals: PropTypes.array.isRequired,
checkboxOnChange: PropTypes.func.isRequired,
direction: PropTypes.string.isRequired,
}

export default CheckboxGroup
128 changes: 128 additions & 0 deletions src/selection-group/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import React, { useState } from 'react'
import PropTypes from 'prop-types'

import { makeStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import FormControl from '@material-ui/core/FormControl'
import Paper from '@material-ui/core/Paper'
import Typography from '@material-ui/core/Typography'

import DynamicButton from '../dynamic-button'
import CheckboxGroup from './checkbox-group'
import RadioGroup from './radio-group'
import SwitchGroup from './switch-group'
import SliderGroup from './slider-group'


const useStyles = makeStyles(() => ({
Copy link
Contributor

@parkdoeui parkdoeui Aug 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend using theme.spacing prop for margins/paddings or have values that are a multiplication of 4.

paper: { paddingBottom: '10px' },
formControl: { margin: '15px 15px 5px 15px' },
select: { paddingLeft: '15px' },
}))

const SelectionGroup = ({
type,
options,
optionsLabel,
onChange,
direction,
hasSelectAll,
sliderStep,
}) => {
const classes = useStyles()
const [filterVals, setFilterVals] = useState(options)
const [selectAll, setSelectAll] = useState(true)

const checkboxOnChange = (e) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name of this should be changed as it is used for both CheckboxGroup and SwitchGroup

const newFilterVals = filterVals.map((v) => {
const [ filterName ] = Object.keys(v)
if (filterName === e.target.name) {
return { [e.target.name]: e.target.checked }
}
return v
})
const optionsState = newFilterVals.filter((v) => !Object.values(v)[0])
if (optionsState.length === 0) setSelectAll(!selectAll)
if (optionsState.length > 0 && !selectAll) setSelectAll(!selectAll)
setFilterVals(newFilterVals)

const selectedVals = newFilterVals.reduce((arr, val) => {
const [ name, selected ] = Object.entries(val)[0]
if (selected) arr.push(name)
return arr
}, [])
onChange(newFilterVals, selectedVals)
}

const selectAllOnClick = () => {
const newFilterVals = filterVals.reduce((arr, opt) => {
const [ name ] = Object.keys(opt)
arr.push({ [name]: selectAll })
return arr
}, [])
setFilterVals(newFilterVals)
setSelectAll(!selectAll)

const selectedVals = newFilterVals.reduce((arr, val) => {
const [ name, selected ] = Object.entries(val)[0]
if (selected) arr.push(name)
return arr
}, [])
onChange(newFilterVals, selectedVals)
}

return (
<Paper className={hasSelectAll ? null : classes.paper}>
<Grid container justify='flex-start' alignItems='flex-start' direction='column'>
<FormControl component='fieldset' className={classes.formControl}>
<Typography variant='subtitle1' gutterBottom>{optionsLabel}</Typography>
{type === 'checkbox' && (
<CheckboxGroup filterVals={filterVals} checkboxOnChange={checkboxOnChange} direction={direction} />
)}
{type === 'radio' && (<RadioGroup options={options} onChange={onChange} direction={direction} />)}
{type === 'switch' && (
<SwitchGroup filterVals={filterVals} switchOnChange={checkboxOnChange} direction={direction} />
)}
{type === 'slider' && (
<SliderGroup direction={direction} sliderStep={sliderStep} options={options} onChange={onChange} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, we don't have any plans to incorporate vertical sliders. It should be always horizontal regardless of direction.

)}
</FormControl>
{hasSelectAll &&
type !== 'radio' &&
type !== 'slider' &&
<div className={classes.select}>
<DynamicButton
type='tertiary'
style={{ padding: '0px', margin: '0px 0px 15px 0px' }}
onClick={selectAllOnClick}
>
{selectAll ? 'Select All' : 'Reset'}
</DynamicButton>
</div>}
</Grid>
</Paper>
)
}

SelectionGroup.propTypes = {
options: PropTypes.array.isRequired,
type: PropTypes.string.isRequired,
optionsLabel: PropTypes.string,
hasSelectAll: PropTypes.bool,
onChange: PropTypes.func,
direction: PropTypes.string,
sliderStep: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
]),
}

SelectionGroup.defaultProps = {
hasSelectAll: false,
onChange: () => {},
direction: 'column',
optionsLabel: '',
sliderStep: 1,
}

export default SelectionGroup
42 changes: 42 additions & 0 deletions src/selection-group/radio-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { useState } from 'react'
import PropTypes from 'prop-types'

import MUIRadioGroup from '@material-ui/core/RadioGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import Grid from '@material-ui/core/Grid'

import StyledRadio from '../styled-radio'


const RadioGroup = ({ options, onChange, direction }) => {
const [val, setVal] = useState(options[0])

const radioOnChange = (e) => {
setVal(e.target.value)
onChange(e.target.value)
}

return (
<MUIRadioGroup value={val} onChange={radioOnChange}>
<Grid container direction={direction}>
{options.map((o, i) => (
<div key={i}>
<FormControlLabel
value={o}
control={(<StyledRadio />)}
label={o}
/>
</div>
))}
</Grid>
</MUIRadioGroup>
)
}

RadioGroup.propTypes = {
options: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired,
direction: PropTypes.string.isRequired,
}

export default RadioGroup
106 changes: 106 additions & 0 deletions src/selection-group/slider-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, { useState } from 'react'
import PropTypes from 'prop-types'

import { makeStyles } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import Slider from '@material-ui/core/Slider'
import FormControl from '@material-ui/core/FormControl'
import Input from '@material-ui/core/Input'


const useStyles = makeStyles(() => ({
sliderInput: {
boxSizing: 'border-box',
marginRight: '4px',
padding: '4px',
border: '1px solid',
borderRadius: '4px',
},
verHeight: { height: '300px' },
}))
const SliderGroup = ({ sliderStep, options, direction, onChange }) => {
const classes = useStyles()
const orientation = direction === 'column' ? 'vertical' : 'horizontal'
const gridContainerProps = direction === 'column'
? { container: true, direction: 'row-reverse', justify: 'center', alignItems:'center' }
: {}
const gridSliderProps = direction === 'column' ? { item: true, xs: 6 } : {}
const gridInputProps = direction === 'column'
? {
item: true,
container: true,
direction: 'column-reverse',
alignItems: 'center',
justify: 'space-between',
}
: {}

let [min, max, initialMin = '', initialMax = ''] = options
if (!initialMin && initialMin !== 0) initialMin = min
if (!initialMax) initialMax = max

const [val, setVal] = useState([initialMin, initialMax])
const [currentMin, currentMax] = val

const sliderOnChange = (_, val) => {
setVal(val)
onChange(val)
}

const minOnChange = (e) => setVal([e.target.value, currentMax])
const maxOnChange = (e) => setVal([currentMin, e.target.value])

return (
<Grid {...gridContainerProps}>
<Grid {...gridSliderProps} className={direction === 'column' ? classes.verHeight : null}>
<Slider
marks={sliderStep !== 1}
value={[currentMin, currentMax]}
step={sliderStep}
min={min}
max={max}
orientation={orientation}
onChange={sliderOnChange}
/>
</Grid>
<Grid {...gridSliderProps} className={direction === 'column' ? classes.verHeight : null}>
<Grid {...gridInputProps} className={direction === 'column' ? classes.verHeight : null}>
<FormControl>
<Input
className={classes.sliderInput}
disableUnderline
value={currentMin}
readOnly={sliderStep !== 1}
onChange={minOnChange}
/>
</FormControl>
<FormControl>
<Input
className={classes.sliderInput}
disableUnderline
value={currentMax}
readOnly={sliderStep !==1}
onChange={maxOnChange}
/>
</FormControl>
</Grid>
</Grid>
</Grid>
)
}

SliderGroup.propTypes = {
onChange: PropTypes.func.isRequired,
options: PropTypes.array.isRequired,
sliderStep: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
]),
direction: PropTypes.string,
}

SliderGroup.defaultProps = {
direction: 'row',
}

export default SliderGroup
41 changes: 41 additions & 0 deletions src/selection-group/switch-group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react'
import PropTypes from 'prop-types'

import FormGroup from '@material-ui/core/FormGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import Grid from '@material-ui/core/Grid'
import Switch from '@material-ui/core/Switch'


const SwitchGroup = ({ filterVals, switchOnChange, direction }) => (
<FormGroup>
<Grid container direction={direction}>
{filterVals.map((val) => {
const [optionName, optionState] = Object.entries(val)[0]
return (
<div key={optionName}>
<FormControlLabel
control={(
<Switch
color='primary'
checked={optionState}
onChange={switchOnChange}
name={optionName}
/>
)}
label={optionName}
/>
</div>
)
})}
</Grid>
</FormGroup>
)

SwitchGroup.propTypes = {
filterVals: PropTypes.array.isRequired,
switchOnChange: PropTypes.func.isRequired,
direction: PropTypes.string.isRequired,
}

export default SwitchGroup
Loading