@mui/x-data-grid-pro
Version:
The Pro plan edition of the Data Grid components (MUI X).
289 lines (287 loc) • 13.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.GridHeaderFilterCell = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var React = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _clsx = _interopRequireDefault(require("clsx"));
var _utils = require("@mui/utils");
var _fastMemo = require("@mui/x-internals/fastMemo");
var _xDataGrid = require("@mui/x-data-grid");
var _internals = require("@mui/x-data-grid/internals");
var _RtlProvider = require("@mui/system/RtlProvider");
var _forwardRef = require("@mui/x-internals/forwardRef");
var _useGridRootProps = require("../../hooks/utils/useGridRootProps");
var _GridHeaderFilterMenuContainer = require("./GridHeaderFilterMenuContainer");
var _GridHeaderFilterClearButton = require("./GridHeaderFilterClearButton");
var _jsxRuntime = require("react/jsx-runtime");
const _excluded = ["colIndex", "height", "hasFocus", "width", "headerClassName", "colDef", "item", "headerFilterMenuRef", "InputComponentProps", "showClearIcon", "pinnedPosition", "pinnedOffset", "style", "showLeftBorder", "showRightBorder"];
const useUtilityClasses = ownerState => {
const {
colDef,
classes,
showRightBorder,
showLeftBorder,
pinnedPosition
} = ownerState;
const slots = {
root: ['columnHeader', colDef.headerAlign === 'left' && 'columnHeader--alignLeft', colDef.headerAlign === 'center' && 'columnHeader--alignCenter', colDef.headerAlign === 'right' && 'columnHeader--alignRight', 'withBorderColor', showRightBorder && 'columnHeader--withRightBorder', showLeftBorder && 'columnHeader--withLeftBorder', pinnedPosition === _internals.PinnedColumnPosition.LEFT && 'columnHeader--pinnedLeft', pinnedPosition === _internals.PinnedColumnPosition.RIGHT && 'columnHeader--pinnedRight']
};
return (0, _utils.unstable_composeClasses)(slots, _xDataGrid.getDataGridUtilityClass, classes);
};
const emptyFieldSx = {
[`& input[value=""]:not(:focus)`]: {
color: 'transparent'
}
};
const defaultInputComponents = {
string: _xDataGrid.GridFilterInputValue,
number: _xDataGrid.GridFilterInputValue,
date: _xDataGrid.GridFilterInputDate,
dateTime: _xDataGrid.GridFilterInputDate,
boolean: _xDataGrid.GridFilterInputBoolean,
singleSelect: _xDataGrid.GridFilterInputSingleSelect,
actions: null,
custom: null
};
const GridHeaderFilterCell = (0, _forwardRef.forwardRef)((props, ref) => {
const {
colIndex,
height,
hasFocus,
width,
headerClassName,
colDef,
item,
headerFilterMenuRef,
InputComponentProps,
showClearIcon = true,
pinnedPosition,
pinnedOffset,
style: styleProp,
showLeftBorder,
showRightBorder
} = props,
other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
const apiRef = (0, _internals.useGridPrivateApiContext)();
const isRtl = (0, _RtlProvider.useRtl)();
const columnFields = (0, _xDataGrid.useGridSelector)(apiRef, _xDataGrid.gridVisibleColumnFieldsSelector);
const rootProps = (0, _useGridRootProps.useGridRootProps)();
const cellRef = React.useRef(null);
const handleRef = (0, _utils.unstable_useForkRef)(ref, cellRef);
const inputRef = React.useRef(null);
const buttonRef = React.useRef(null);
const editingField = (0, _xDataGrid.useGridSelector)(apiRef, _internals.gridHeaderFilteringEditFieldSelector);
const isEditing = editingField === colDef.field;
const menuOpenField = (0, _xDataGrid.useGridSelector)(apiRef, _internals.gridHeaderFilteringMenuSelector);
const isMenuOpen = menuOpenField === colDef.field;
// TODO: Support for `isAnyOf` operator
const filterOperators = React.useMemo(() => {
if (!colDef.filterOperators) {
return [];
}
return colDef.filterOperators.filter(operator => operator.value !== 'isAnyOf');
}, [colDef.filterOperators]);
const filterModel = (0, _xDataGrid.useGridSelector)(apiRef, _xDataGrid.gridFilterModelSelector);
const filterableColumnsLookup = (0, _xDataGrid.useGridSelector)(apiRef, _xDataGrid.gridFilterableColumnLookupSelector);
const isFilterReadOnly = React.useMemo(() => {
if (!filterModel?.items.length) {
return false;
}
const filterModelItem = filterModel.items.find(it => it.field === colDef.field);
return filterModelItem ? !filterableColumnsLookup[filterModelItem.field] : false;
}, [colDef.field, filterModel, filterableColumnsLookup]);
const currentOperator = React.useMemo(() => filterOperators.find(operator => operator.value === item.operator) ?? filterOperators[0], [item.operator, filterOperators]);
const InputComponent = colDef.filterable || isFilterReadOnly ? currentOperator.InputComponent ?? defaultInputComponents[colDef.type] : null;
const clearFilterItem = React.useCallback(() => {
apiRef.current.deleteFilterItem(item);
}, [apiRef, item]);
let headerFilterComponent;
if (colDef.renderHeaderFilter) {
headerFilterComponent = colDef.renderHeaderFilter((0, _extends2.default)({}, props, {
inputRef
}));
}
React.useLayoutEffect(() => {
if (hasFocus && !isMenuOpen) {
let focusableElement = cellRef.current.querySelector('[tabindex="0"]');
if (isEditing && InputComponent) {
focusableElement = inputRef.current;
}
const elementToFocus = focusableElement || cellRef.current;
elementToFocus?.focus();
if (apiRef.current.columnHeadersContainerRef.current) {
apiRef.current.columnHeadersContainerRef.current.scrollLeft = 0;
}
}
}, [InputComponent, apiRef, hasFocus, isEditing, isMenuOpen]);
const onKeyDown = React.useCallback(event => {
if (isMenuOpen || (0, _internals.isNavigationKey)(event.key) || isFilterReadOnly) {
return;
}
switch (event.key) {
case 'Escape':
if (isEditing) {
apiRef.current.stopHeaderFilterEditMode();
}
break;
case 'Enter':
if (isEditing) {
if (!event.defaultPrevented) {
apiRef.current.stopHeaderFilterEditMode();
break;
}
}
if (event.metaKey || event.ctrlKey) {
headerFilterMenuRef.current = buttonRef.current;
apiRef.current.showHeaderFilterMenu(colDef.field);
break;
}
apiRef.current.startHeaderFilterEditMode(colDef.field);
break;
case 'Tab':
{
if (isEditing) {
const fieldToFocus = columnFields[colIndex + (event.shiftKey ? -1 : 1)] ?? null;
if (fieldToFocus) {
apiRef.current.startHeaderFilterEditMode(fieldToFocus);
apiRef.current.setColumnHeaderFilterFocus(fieldToFocus, event);
}
}
break;
}
default:
if (isEditing || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) {
break;
}
apiRef.current.startHeaderFilterEditMode(colDef.field);
break;
}
}, [apiRef, colDef.field, colIndex, columnFields, headerFilterMenuRef, isEditing, isFilterReadOnly, isMenuOpen]);
const publish = React.useCallback((eventName, propHandler) => event => {
apiRef.current.publishEvent(eventName, apiRef.current.getColumnHeaderParams(colDef.field), event);
if (propHandler) {
propHandler(event);
}
}, [apiRef, colDef.field]);
const onMouseDown = React.useCallback(event => {
if (!hasFocus) {
if (inputRef.current?.contains?.(event.target)) {
inputRef.current.focus();
}
apiRef.current.setColumnHeaderFilterFocus(colDef.field, event);
}
}, [apiRef, colDef.field, hasFocus]);
const mouseEventsHandlers = React.useMemo(() => ({
onKeyDown: publish('headerFilterKeyDown', onKeyDown),
onClick: publish('headerFilterClick'),
onMouseDown: publish('headerFilterMouseDown', onMouseDown),
onBlur: publish('headerFilterBlur')
}), [onMouseDown, onKeyDown, publish]);
const ownerState = (0, _extends2.default)({}, rootProps, {
pinnedPosition,
colDef,
showLeftBorder,
showRightBorder
});
const classes = useUtilityClasses(ownerState);
const isNoInputOperator = currentOperator.requiresFilterValue === false;
const isApplied = item?.value !== undefined || isNoInputOperator;
const label = currentOperator.headerLabel ?? apiRef.current.getLocaleText(`headerFilterOperator${(0, _utils.unstable_capitalize)(item.operator)}`);
const isFilterActive = isApplied || hasFocus;
return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", (0, _extends2.default)({
className: (0, _clsx.default)(classes.root, headerClassName),
style: (0, _internals.attachPinnedStyle)((0, _extends2.default)({
height,
width
}, styleProp), isRtl, pinnedPosition, pinnedOffset),
role: "columnheader",
"aria-colindex": colIndex + 1,
"aria-label": headerFilterComponent == null ? colDef.headerName ?? colDef.field : undefined
}, other, mouseEventsHandlers, {
ref: handleRef,
children: [headerFilterComponent, InputComponent && headerFilterComponent === undefined ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(React.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(InputComponent, (0, _extends2.default)({
apiRef: apiRef,
item: item,
inputRef: inputRef,
applyValue: apiRef.current.upsertFilterItem,
onFocus: () => apiRef.current.startHeaderFilterEditMode(colDef.field),
onBlur: event => {
apiRef.current.stopHeaderFilterEditMode();
// Blurring an input element should reset focus state only if `relatedTarget` is not the header filter cell
if (!event.relatedTarget?.className.includes('columnHeader')) {
apiRef.current.setState(state => (0, _extends2.default)({}, state, {
focus: {
cell: null,
columnHeader: null,
columnHeaderFilter: null,
columnGroupHeader: null
}
}));
}
},
label: (0, _utils.unstable_capitalize)(label),
placeholder: "",
isFilterActive: isFilterActive,
clearButton: showClearIcon && isApplied ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridHeaderFilterClearButton.GridHeaderFilterClearButton, {
onClick: clearFilterItem,
disabled: isFilterReadOnly
}) : null,
disabled: isFilterReadOnly || isNoInputOperator,
tabIndex: -1,
InputLabelProps: null,
sx: colDef.type === 'date' || colDef.type === 'dateTime' || colDef.type === 'number' ? emptyFieldSx : undefined
}, isNoInputOperator ? {
value: ''
} : {}, currentOperator?.InputComponentProps, InputComponentProps)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridHeaderFilterMenuContainer.GridHeaderFilterMenuContainer, {
operators: filterOperators,
item: item,
field: colDef.field,
disabled: isFilterReadOnly,
applyFilterChanges: apiRef.current.upsertFilterItem,
headerFilterMenuRef: headerFilterMenuRef,
buttonRef: buttonRef
})]
}) : null]
}));
});
process.env.NODE_ENV !== "production" ? GridHeaderFilterCell.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit the TypeScript types and run "pnpm proptypes" |
// ----------------------------------------------------------------------
colDef: _propTypes.default.object.isRequired,
colIndex: _propTypes.default.number.isRequired,
hasFocus: _propTypes.default.bool,
/**
* Class name added to the column header cell.
*/
headerClassName: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.string]),
headerFilterMenuRef: _propTypes.default.shape({
current: _propTypes.default.object
}).isRequired,
height: _propTypes.default.number.isRequired,
InputComponentProps: _propTypes.default.object,
item: _propTypes.default.shape({
field: _propTypes.default.string.isRequired,
id: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
operator: _propTypes.default.string.isRequired,
value: _propTypes.default.any
}).isRequired,
pinnedOffset: _propTypes.default.number,
pinnedPosition: _propTypes.default.oneOf([0, 1, 2, 3]),
showClearIcon: _propTypes.default.bool,
showLeftBorder: _propTypes.default.bool.isRequired,
showRightBorder: _propTypes.default.bool.isRequired,
sortIndex: _propTypes.default.number,
style: _propTypes.default.object,
tabIndex: _propTypes.default.oneOf([-1, 0]).isRequired,
width: _propTypes.default.number.isRequired
} : void 0;
const Memoized = exports.GridHeaderFilterCell = (0, _fastMemo.fastMemo)(GridHeaderFilterCell);