UNPKG

@mui/x-data-grid-pro

Version:

The Pro plan edition of the MUI X Data Grid components.

373 lines (371 loc) 16.4 kB
"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);