UNPKG

@mui/x-data-grid

Version:

The Community plan edition of the Data Grid components (MUI X).

131 lines (128 loc) 6.1 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; const _excluded = ["field", "colDef"]; import * as React from 'react'; import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; import { forwardRef } from '@mui/x-internals/forwardRef'; import { isMultipleRowSelectionEnabled } from "../../hooks/features/rowSelection/utils.js"; import { useGridSelector } from "../../hooks/utils/useGridSelector.js"; import { gridTabIndexColumnHeaderSelector } from "../../hooks/features/focus/gridFocusStateSelector.js"; import { gridRowSelectionStateSelector } from "../../hooks/features/rowSelection/gridRowSelectionSelector.js"; import { useGridApiContext } from "../../hooks/utils/useGridApiContext.js"; import { getDataGridUtilityClass } from "../../constants/gridClasses.js"; import { useGridRootProps } from "../../hooks/utils/useGridRootProps.js"; import { gridExpandedSortedRowIdsSelector } from "../../hooks/features/filter/gridFilterSelector.js"; import { gridPaginatedVisibleSortedGridRowIdsSelector } from "../../hooks/features/pagination/gridPaginationSelector.js"; import { jsx as _jsx } from "react/jsx-runtime"; const useUtilityClasses = ownerState => { const { classes } = ownerState; const slots = { root: ['checkboxInput'] }; return composeClasses(slots, getDataGridUtilityClass, classes); }; const GridHeaderCheckbox = forwardRef(function GridHeaderCheckbox(props, ref) { const other = _objectWithoutPropertiesLoose(props, _excluded); const [, forceUpdate] = React.useState(false); const apiRef = useGridApiContext(); const rootProps = useGridRootProps(); const ownerState = { classes: rootProps.classes }; const classes = useUtilityClasses(ownerState); const tabIndexState = useGridSelector(apiRef, gridTabIndexColumnHeaderSelector); const selection = useGridSelector(apiRef, gridRowSelectionStateSelector); const visibleRowIds = useGridSelector(apiRef, gridExpandedSortedRowIdsSelector); const paginatedVisibleRowIds = useGridSelector(apiRef, gridPaginatedVisibleSortedGridRowIdsSelector); const filteredSelection = React.useMemo(() => { if (typeof rootProps.isRowSelectable !== 'function') { return selection; } return selection.filter(id => { if (rootProps.keepNonExistentRowsSelected) { return true; } // The row might have been deleted if (!apiRef.current.getRow(id)) { return false; } return rootProps.isRowSelectable(apiRef.current.getRowParams(id)); }); }, [apiRef, rootProps.isRowSelectable, selection, rootProps.keepNonExistentRowsSelected]); // All the rows that could be selected / unselected by toggling this checkbox const selectionCandidates = React.useMemo(() => { const rowIds = !rootProps.pagination || !rootProps.checkboxSelectionVisibleOnly ? visibleRowIds : paginatedVisibleRowIds; // Convert to an object to make O(1) checking if a row exists or not // TODO create selector that returns visibleRowIds/paginatedVisibleRowIds as an object return rowIds.reduce((acc, id) => { acc[id] = true; return acc; }, {}); }, [rootProps.pagination, rootProps.checkboxSelectionVisibleOnly, paginatedVisibleRowIds, visibleRowIds]); // Amount of rows selected and that are visible in the current page const currentSelectionSize = React.useMemo(() => filteredSelection.filter(id => selectionCandidates[id]).length, [filteredSelection, selectionCandidates]); const isIndeterminate = currentSelectionSize > 0 && currentSelectionSize < Object.keys(selectionCandidates).length; const isChecked = currentSelectionSize > 0; const handleChange = event => { const params = { value: event.target.checked }; apiRef.current.publishEvent('headerSelectionCheckboxChange', params); }; const tabIndex = tabIndexState !== null && tabIndexState.field === props.field ? 0 : -1; React.useLayoutEffect(() => { const element = apiRef.current.getColumnHeaderElement(props.field); if (tabIndex === 0 && element) { element.tabIndex = -1; } }, [tabIndex, apiRef, props.field]); const handleKeyDown = React.useCallback(event => { if (event.key === ' ') { // imperative toggle the checkbox because Space is disable by some preventDefault apiRef.current.publishEvent('headerSelectionCheckboxChange', { value: !isChecked }); } }, [apiRef, isChecked]); const handleSelectionChange = React.useCallback(() => { forceUpdate(p => !p); }, []); React.useEffect(() => { return apiRef.current.subscribeEvent('rowSelectionChange', handleSelectionChange); }, [apiRef, handleSelectionChange]); const checked = rootProps.indeterminateCheckboxAction === 'select' ? isChecked && !isIndeterminate : isChecked; const label = apiRef.current.getLocaleText(checked ? 'checkboxSelectionUnselectAllRows' : 'checkboxSelectionSelectAllRows'); return /*#__PURE__*/_jsx(rootProps.slots.baseCheckbox, _extends({ indeterminate: isIndeterminate, checked: checked, onChange: handleChange, className: classes.root, inputProps: { 'aria-label': label, name: 'select_all_rows' }, tabIndex: tabIndex, onKeyDown: handleKeyDown, disabled: !isMultipleRowSelectionEnabled(rootProps) }, rootProps.slotProps?.baseCheckbox, other, { ref: ref })); }); process.env.NODE_ENV !== "production" ? GridHeaderCheckbox.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- /** * The column of the current header component. */ colDef: PropTypes.object.isRequired, /** * The column field of the column that triggered the event */ field: PropTypes.string.isRequired } : void 0; export { GridHeaderCheckbox };