react-mapfilter
Version:
These components are designed for viewing data in Mapeo. They share a common interface:
185 lines (166 loc) • 6.2 kB
JavaScript
import "core-js/modules/es.array.iterator";
import "core-js/modules/web.dom-collections.iterator";
import _indexOfInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/index-of";
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
import _JSON$stringify from "@babel/runtime-corejs3/core-js-stable/json/stringify";
import _findInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/find";
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
import _sortInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/sort";
import _Set from "@babel/runtime-corejs3/core-js-stable/set";
import _reduceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/reduce";
// @flow
import * as React from 'react';
import Checkbox from './StyledCheckbox';
import ListIcon from '@material-ui/icons/List';
import { makeStyles } from '@material-ui/core/styles';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
import ListItemText from '@material-ui/core/ListItemText';
import FilterSection from './FilterSection';
import OnlyButton from './OnlyButton';
import { getField } from '../lib/data_analysis';
import FormattedValue from '../internal/FormattedValue';
/*:: import type { Key, Filter, SelectOptions, SelectableFieldValue } from '../types'*/
// import {FIELD_TYPE_BOOLEAN, FIELD_TYPE_NUMBER} from '../../constants'
const FilterItem = ({
onClick,
checked,
label,
id,
onOnlyClick
}) => {
const cx = useStyles();
return /*#__PURE__*/React.createElement(ListItem, {
role: undefined,
dense: true,
button: true,
onClick: onClick,
className: cx.filterItem
}, /*#__PURE__*/React.createElement(ListItemIcon, {
className: cx.checkboxIcon
}, /*#__PURE__*/React.createElement(Checkbox, {
edge: "start",
checked: checked,
tabIndex: -1,
disableRipple: true,
inputProps: {
'aria-labelledby': id
},
className: cx.checkbox
})), /*#__PURE__*/React.createElement(ListItemText, {
id: id,
primary: label
}), /*#__PURE__*/React.createElement(ListItemSecondaryAction, null, /*#__PURE__*/React.createElement(OnlyButton, {
className: cx.onlyButton,
onClick: onOnlyClick
})));
};
/*:: type Props = {
label: React.Node,
fieldKey: Key,
filter?: Filter | null,
options: SelectOptions,
onChangeFilter: (filter: Array<any> | null) => void
}*/
const DiscreteFilter = ({
label,
fieldKey,
filter,
options,
onChangeFilter
}
/*: Props*/
) => {
var _context;
const values
/*: Array<number | string | boolean>*/
= _reduceInstanceProperty(options).call(options, (acc, cur) => {
// Filter null values
if (cur == null) return acc;
if (typeof cur === 'object' && cur.value != null) acc.push(cur.value);else if (typeof cur !== 'object') acc.push(cur);
return acc;
}, []);
const shownValues = valuesFromFilter(filter, values);
const allValues = [...new _Set(_sortInstanceProperty(_context = [...shownValues, ...values]).call(_context))];
const handleClick = value => e => {
if (shownValues.has(value)) shownValues.delete(value);else shownValues.add(value);
const newFilter = // If all items are selected we're implicitly including undefined and null
// values, so we clear the filter altogether if everything is selected
shownValues.size === allValues.length ? null : shownValues.size > 0 ? ['in', fieldKey, ...shownValues] : ['!in', fieldKey, ...allValues];
onChangeFilter(newFilter);
};
const handleOnlyClick = value => () => {
onChangeFilter(['in', fieldKey, value]);
}; // Don't render the filter if there is nothing to choose from
if (!allValues || allValues.length === 0) return null;
return /*#__PURE__*/React.createElement(FilterSection, {
title: label,
icon: /*#__PURE__*/React.createElement(ListIcon, null),
isFiltered: !!filter,
onShowAllClick: () => onChangeFilter(null)
}, _mapInstanceProperty(allValues).call(allValues, (v, i) => {
// TODO use FormattedValue here
const option = _findInstanceProperty(options).call(options, o => typeof o === 'object' && o !== null && o.value === v);
const label = option ? // $FlowFixMe - pretty sure the find above means this must have a label prop
option.label : v == null ? '[No Value]' :
/*#__PURE__*/
// This is kind of a hack just to re-use code that detects and formats dates if they are options
React.createElement(FormattedValue, {
value: v,
field: getField([], v)
});
const key = _JSON$stringify(v);
return /*#__PURE__*/React.createElement(FilterItem, {
key: key,
id: key,
label: label,
checked: shownValues.has(v),
onClick: handleClick(v),
onOnlyClick: handleOnlyClick(v)
});
}));
};
function valuesFromFilter(filter, values = [])
/*: Set<SelectableFieldValue>*/
{
if (!filter || filter.length < 3) return new _Set(values); // $FlowFixMe - need to better define type for filter
if (filter[0] === 'in') return new _Set(_sliceInstanceProperty(filter).call(filter, 2));
if (filter[0] === '!in') {
const notShown = _sliceInstanceProperty(filter).call(filter, 2);
const shown = _filterInstanceProperty(values).call(values, v => _indexOfInstanceProperty(notShown).call(notShown, v) < 0);
return new _Set(shown);
}
return new _Set(values);
}
export default DiscreteFilter;
const useStyles = makeStyles(theme => ({
filterItem: {
paddingTop: 0,
paddingBottom: 0,
'& $onlyButton': {
display: 'none'
},
'&:hover $onlyButton': {
display: 'block'
}
},
onlyButton: {
fontSize: 12,
lineHeight: '16px',
minWidth: 'auto'
},
checkboxIcon: {
minWidth: 36,
paddingLeft: 4
},
checkbox: {
padding: 0,
paddingLeft: 12,
'&:hover': {
backgroundColor: 'inherit !important'
}
}
}));
//# sourceMappingURL=DiscreteFilter.js.map