UNPKG

baseui

Version:

A React Component library implementing the Base design language

268 lines (263 loc) • 9.54 kB
"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;