@mui/x-data-grid-pro
Version:
The Pro plan edition of the MUI X Data Grid components.
373 lines (371 loc) • 16.4 kB
JavaScript
"use strict";
'use client';
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 _styles = require("@mui/material/styles");
var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef"));
var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses"));
var _capitalize = _interopRequireDefault(require("@mui/utils/capitalize"));
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 _InputBase = require("@mui/material/InputBase");
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 StyledInputComponent = (0, _styles.styled)(_xDataGrid.GridFilterInputValue, {
name: 'MuiDataGrid',
slot: 'ColumnHeaderFilterInput'
})({
flex: 1,
marginRight: _internals.vars.spacing(0.5),
marginBottom: _internals.vars.spacing(-0.25),
'& input[type="number"], & input[type="date"], & input[type="datetime-local"]': {
'&[value=""]:not(:focus)': {
color: 'transparent'
}
},
[`& .${_InputBase.inputBaseClasses.input}`]: {
fontSize: '14px'
},
[`.${_xDataGrid.gridClasses['root--densityCompact']} & .${_InputBase.inputBaseClasses.input}`]: {
paddingTop: _internals.vars.spacing(0.5),
paddingBottom: _internals.vars.spacing(0.5),
height: 23
}
});
const OperatorLabel = (0, _styles.styled)('span', {
name: 'MuiDataGrid',
slot: 'ColumnHeaderFilterOperatorLabel'
})({
flex: 1,
marginRight: _internals.vars.spacing(0.5),
color: _internals.vars.colors.foreground.muted,
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden'
});
const useUtilityClasses = ownerState => {
const {
colDef,
classes,
showRightBorder,
showLeftBorder,
pinnedPosition
} = ownerState;
const slots = {
root: ['columnHeader', 'columnHeader--filter', 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'],
input: ['columnHeaderFilterInput'],
operatorLabel: ['columnHeaderFilterOperatorLabel']
};
return (0, _composeClasses.default)(slots, _xDataGrid.getDataGridUtilityClass, classes);
};
const DEFAULT_INPUT_COMPONENTS = {
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 = false,
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, _useForkRef.default)(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 ?? DEFAULT_INPUT_COMPONENTS[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 label = currentOperator.headerLabel ?? apiRef.current.getLocaleText(`headerFilterOperator${(0, _capitalize.default)(item.operator)}`);
const isNoInputOperator = currentOperator.requiresFilterValue === false;
const isApplied = item?.value !== undefined || isNoInputOperator;
const isFilterActive = isApplied || hasFocus;
const headerFilterMenu = /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridHeaderFilterMenuContainer.GridHeaderFilterMenuContainer, {
operators: filterOperators,
item: item,
field: colDef.field,
disabled: isFilterReadOnly,
applyFilterChanges: apiRef.current.upsertFilterItem,
headerFilterMenuRef: headerFilterMenuRef,
buttonRef: buttonRef,
showClearItem: !showClearIcon && isApplied,
clearFilterItem: clearFilterItem
});
const clearButton = showClearIcon && isApplied ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_GridHeaderFilterClearButton.GridHeaderFilterClearButton, {
onClick: clearFilterItem,
disabled: isFilterReadOnly
}) : null;
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, headerFilterComponent === undefined ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(React.Fragment, {
children: [isNoInputOperator ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(React.Fragment, {
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(OperatorLabel, {
className: classes.operatorLabel,
children: label
}), clearButton, headerFilterMenu]
}) : null, InputComponent && !isNoInputOperator ? /*#__PURE__*/(0, _jsxRuntime.jsx)(StyledInputComponent, (0, _extends2.default)({
as: InputComponent,
className: classes.input,
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
}
}));
}
},
isFilterActive: isFilterActive,
headerFilterMenu: headerFilterMenu,
clearButton: clearButton,
disabled: isFilterReadOnly || isNoInputOperator,
tabIndex: -1,
slotProps: {
root: {
size: 'small',
label: (0, _capitalize.default)(label),
placeholder: ''
}
}
}, isNoInputOperator ? {
value: ''
} : {}, currentOperator?.InputComponentProps, InputComponentProps)) : null]
}) : null]
}));
});
if (process.env.NODE_ENV !== "production") GridHeaderFilterCell.displayName = "GridHeaderFilterCell";
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.shape({
apiRef: _propTypes.default.shape({
current: _propTypes.default.object.isRequired
}),
applyValue: _propTypes.default.func,
className: _propTypes.default.string,
clearButton: _propTypes.default.node,
disabled: _propTypes.default.bool,
focusElementRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.shape({
current: _propTypes.default.any.isRequired
})]),
headerFilterMenu: _propTypes.default.node,
inputRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.shape({
current: (props, propName) => {
if (props[propName] == null) {
return null;
}
if (typeof props[propName] !== 'object' || props[propName].nodeType !== 1) {
return new Error(`Expected prop '${propName}' to be of type Element`);
}
return null;
}
})]),
isFilterActive: _propTypes.default.bool,
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
}),
onBlur: _propTypes.default.func,
onFocus: _propTypes.default.func,
slotProps: _propTypes.default.object,
tabIndex: _propTypes.default.number
}),
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);