-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
GridHeaderCheckbox.tsx
90 lines (79 loc) · 3.55 KB
/
GridHeaderCheckbox.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import * as React from 'react';
import {
GRID_COLUMN_HEADER_NAVIGATION_KEYDOWN,
GRID_SELECTION_CHANGED,
} from '../../constants/eventsConstants';
import { useGridSelector } from '../../hooks/features/core/useGridSelector';
import { visibleSortedGridRowIdsSelector } from '../../hooks/features/filter/gridFilterSelector';
import { gridTabIndexColumnHeaderSelector } from '../../hooks/features/focus/gridFocusStateSelector';
import { gridRowCountSelector } from '../../hooks/features/rows/gridRowsSelector';
import { selectedGridRowsCountSelector } from '../../hooks/features/selection/gridSelectionSelector';
import { GridColumnHeaderParams } from '../../models/params/gridColumnHeaderParams';
import { isNavigationKey, isSpaceKey } from '../../utils/keyboardUtils';
import { GridApiContext } from '../GridApiContext';
export const GridHeaderCheckbox = React.forwardRef<HTMLInputElement, GridColumnHeaderParams>(
function GridHeaderCheckbox(props, ref) {
const [, forceUpdate] = React.useState(false);
const apiRef = React.useContext(GridApiContext);
const visibleRowIds = useGridSelector(apiRef, visibleSortedGridRowIdsSelector);
const tabIndexState = useGridSelector(apiRef, gridTabIndexColumnHeaderSelector);
const element = apiRef!.current.getColumnHeaderElement(props.field);
const totalSelectedRows = useGridSelector(apiRef, selectedGridRowsCountSelector);
const totalRows = useGridSelector(apiRef, gridRowCountSelector);
const [isIndeterminate, setIsIndeterminate] = React.useState(
totalSelectedRows > 0 && totalSelectedRows !== totalRows,
);
const [isChecked, setChecked] = React.useState(
totalSelectedRows === totalRows || isIndeterminate,
);
React.useEffect(() => {
const isNewIndeterminate = totalSelectedRows > 0 && totalSelectedRows !== totalRows;
const isNewChecked = (totalRows > 0 && totalSelectedRows === totalRows) || isIndeterminate;
setChecked(isNewChecked);
setIsIndeterminate(isNewIndeterminate);
}, [isIndeterminate, totalRows, totalSelectedRows]);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const checked = event.target.checked;
setChecked(checked);
apiRef!.current.selectRows(visibleRowIds, checked);
};
const tabIndex = tabIndexState !== null && tabIndexState.field === props.field ? 0 : -1;
React.useLayoutEffect(() => {
if (tabIndex === 0 && element) {
element!.tabIndex = -1;
}
}, [element, tabIndex]);
const handleKeyDown = React.useCallback(
(event) => {
if (isSpaceKey(event.key)) {
event.stopPropagation();
}
if (isNavigationKey(event.key) && !event.shiftKey) {
apiRef!.current.publishEvent(GRID_COLUMN_HEADER_NAVIGATION_KEYDOWN, props, event);
}
},
[apiRef, props],
);
const handleSelectionChange = React.useCallback(() => {
forceUpdate((p) => !p);
}, []);
React.useEffect(() => {
return apiRef?.current.subscribeEvent(GRID_SELECTION_CHANGED, handleSelectionChange);
}, [apiRef, handleSelectionChange]);
const CheckboxComponent = apiRef?.current.components.Checkbox!;
return (
<CheckboxComponent
ref={ref}
indeterminate={isIndeterminate}
checked={isChecked}
onChange={handleChange}
className="MuiDataGrid-checkboxInput"
color="primary"
inputProps={{ 'aria-label': 'Select All Rows checkbox' }}
tabIndex={tabIndex}
onKeyDown={handleKeyDown}
{...apiRef?.current.componentsProps?.checkbox}
/>
);
},
);