-
Notifications
You must be signed in to change notification settings - Fork 0
[WIP]filter - filter component with checkbox select options #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
c8ae73b
0601694
303b964
36d0d74
5193145
1493fb0
65a71f0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 |
| 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(() => ({ | ||
| 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) => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
| 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} /> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| 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 |
| 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 |
| 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 |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend using
theme.spacingprop for margins/paddings or have values that are a multiplication of 4.