baseui
Version:
A React Component library implementing the Base design language
268 lines (263 loc) • 9.54 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
var _button = require("../button");
var _icon = require("../icon");
var _input = require("../input");
var _popover = require("../popover");
var _styles = require("../styles");
var _reactUid = require("react-uid");
var _constants = require("./constants");
var _textSearch = require("./text-search");
var _locale = require("../locale");
var _focusVisible = require("../utils/focusVisible");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/*
Copyright (c) Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
const ColumnIcon = props => {
if (props.column.kind === _constants.COLUMNS.BOOLEAN) {
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "01");
}
if (props.column.kind === _constants.COLUMNS.CATEGORICAL) {
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "abc");
}
if (props.column.kind === _constants.COLUMNS.DATETIME) {
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "dt");
}
if (props.column.kind === _constants.COLUMNS.NUMERICAL) {
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, "#");
}
return /*#__PURE__*/_react.default.createElement(_icon.Filter, null);
};
function Options(props) {
const [css, theme] = (0, _styles.useStyletron)();
const locale = _react.default.useContext(_locale.LocaleContext);
const inputRef = _react.default.useRef(null);
_react.default.useEffect(() => {
if (inputRef.current) {
// @ts-ignore
inputRef.current.focus();
}
}, [inputRef.current]);
const [focusVisible, setFocusVisible] = _react.default.useState(false);
const seed = (0, _reactUid.useUIDSeed)();
const buiRef = _react.default.useRef(props.columns.map(col => seed(col)));
const activeDescendant = buiRef.current[props.highlightIndex] ? `bui-${buiRef.current[props.highlightIndex]}` : undefined;
const optionsLabelId = seed('options-label');
const handleFocus = event => {
if ((0, _focusVisible.isFocusVisible)(event)) {
setFocusVisible(true);
}
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const handleBlur = event => {
if (focusVisible !== false) {
setFocusVisible(false);
}
};
return /*#__PURE__*/_react.default.createElement("div", {
className: css({
backgroundColor: theme.colors.menuFill,
minWidth: '320px',
outline: focusVisible ? `3px solid ${theme.colors.borderAccent}` : 'none',
paddingTop: theme.sizing.scale600,
paddingBottom: theme.sizing.scale600
})
}, /*#__PURE__*/_react.default.createElement("p", {
id: optionsLabelId,
className: css({
...theme.typography.font100,
marginTop: 'unset',
paddingRight: theme.sizing.scale600,
paddingLeft: theme.sizing.scale600
})
}, locale.datatable.optionsLabel), props.searchable && /*#__PURE__*/_react.default.createElement("div", {
className: css({
marginBottom: theme.sizing.scale500,
marginRight: theme.sizing.scale600,
marginLeft: theme.sizing.scale600
})
}, /*#__PURE__*/_react.default.createElement(_input.Input, {
inputRef: inputRef,
value: props.query,
onChange: event => props.onQueryChange(event.target.value),
placeholder: locale.datatable.optionsSearch,
size: _input.SIZE.compact,
clearable: true
})), !props.columns.length && /*#__PURE__*/_react.default.createElement("div", {
className: css({
...theme.typography.font100,
paddingRight: theme.sizing.scale600,
paddingLeft: theme.sizing.scale600
})
}, locale.datatable.optionsEmpty), /*#__PURE__*/_react.default.createElement("ul", {
onKeyDown: props.onKeyDown,
onFocus: handleFocus,
onBlur: handleBlur,
tabIndex: 0,
role: "listbox",
"aria-activedescendant": activeDescendant,
"aria-labelledby": optionsLabelId,
className: css({
listStyleType: 'none',
marginBlockStart: 'unset',
marginBlockEnd: 'unset',
maxHeight: '256px',
paddingInlineStart: 'unset',
outline: 'none',
overflowY: 'auto'
})
}, props.columns.map((column, index) => {
const isHighlighted = index === props.highlightIndex;
return (
/*#__PURE__*/
// handled on the wrapper element
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
_react.default.createElement("li", {
id: `bui-${buiRef.current[index]}`,
role: "option",
"aria-selected": isHighlighted,
onMouseEnter: () => props.onMouseEnter(index),
onClick: () => props.onClick(column),
key: column.title,
className: css({
...theme.typography.font100,
alignItems: 'center',
// @ts-ignore
backgroundColor: isHighlighted ? theme.colors.menuFillHover : null,
cursor: 'pointer',
display: 'flex',
paddingTop: theme.sizing.scale100,
paddingRight: theme.sizing.scale600,
paddingBottom: theme.sizing.scale100,
paddingLeft: theme.sizing.scale600
})
}, /*#__PURE__*/_react.default.createElement("div", {
className: css({
...theme.typography.font150,
fontSize: '8px',
alignItems: 'center',
backgroundColor: theme.colors.backgroundTertiary,
borderRadius: theme.borders.radius200,
display: 'flex',
height: theme.sizing.scale800,
justifyContent: 'center',
marginRight: theme.sizing.scale300,
width: theme.sizing.scale800
})
}, /*#__PURE__*/_react.default.createElement(ColumnIcon, {
column: column
})), column.title)
);
})));
}
function FilterMenu(props) {
const [, theme] = (0, _styles.useStyletron)();
const locale = _react.default.useContext(_locale.LocaleContext);
const [isOpen, setIsOpen] = _react.default.useState(false);
const [highlightIndex, setHighlightIndex] = _react.default.useState(-1);
const [query, setQuery] = _react.default.useState('');
const [activeColumn, setActiveColumn] = _react.default.useState(null);
const handleOptionClick = _react.default.useCallback(setActiveColumn, []);
const handleClose = _react.default.useCallback(() => {
setIsOpen(false);
setActiveColumn(null);
setHighlightIndex(-1);
setQuery('');
}, []);
const filterableColumns = _react.default.useMemo(() => {
return props.columns.filter(column => {
return column.filterable && !props.filters.has(column.title);
});
}, [props.columns, props.filters]);
const columns = _react.default.useMemo(() => {
return filterableColumns.filter(column => (0, _textSearch.matchesQuery)(column.title, query));
}, [filterableColumns, query]);
const Filter = _react.default.useMemo(() => {
if (!activeColumn) return null;
// @ts-ignore
return activeColumn.renderFilter;
}, [activeColumn]);
const activeColumnData = _react.default.useMemo(() => {
const columnIndex = props.columns.findIndex(c => c === activeColumn);
if (columnIndex < 0) return [];
return props.rows.map(row => props.columns[columnIndex].mapDataToValue(row.data));
}, [props.columns, props.rows, activeColumn]);
// @ts-ignore
function handleKeyDown(event) {
if (event.keyCode === 13) {
event.preventDefault();
// @ts-ignore
setActiveColumn(columns[highlightIndex]);
}
if (event.keyCode === 38) {
event.preventDefault();
setHighlightIndex(Math.max(0, highlightIndex - 1));
}
if (event.keyCode === 40) {
event.preventDefault();
if (!isOpen) {
setIsOpen(true);
} else {
setHighlightIndex(Math.min(columns.length - 1, highlightIndex + 1));
}
}
}
return /*#__PURE__*/_react.default.createElement(_popover.Popover, {
focusLock: true,
returnFocus: true,
placement: _popover.PLACEMENT.bottomLeft,
content: () => {
if (Filter && activeColumn) {
return /*#__PURE__*/_react.default.createElement(Filter, {
data: activeColumnData,
close: handleClose
// @ts-ignore
,
setFilter: filterParams => props.onSetFilter(activeColumn.title, filterParams)
});
}
return /*#__PURE__*/_react.default.createElement(Options, {
columns: columns,
highlightIndex: highlightIndex
// @ts-ignore
,
onClick: handleOptionClick,
onKeyDown: handleKeyDown,
onMouseEnter: setHighlightIndex,
onQueryChange: setQuery,
query: query,
searchable: filterableColumns.length >= 10
});
},
onClick: () => {
if (isOpen) {
handleClose();
} else {
setIsOpen(true);
}
},
onClickOutside: handleClose,
onEsc: handleClose,
isOpen: isOpen,
ignoreBoundary: true
}, /*#__PURE__*/_react.default.createElement(_button.Button, {
shape: _button.SHAPE.pill,
size: _button.SIZE.compact,
overrides: {
BaseButton: {
style: {
marginLeft: theme.sizing.scale500,
marginBottom: theme.sizing.scale500
}
}
}
}, locale.datatable.filterAdd));
}
var _default = exports.default = FilterMenu;