Skip to content

Commit

Permalink
Add indeterminate state of header checkbox
Browse files Browse the repository at this point in the history
Added someRowsSelected property to DataGrid to determine if indeterminate

Provide someRowsSelected as a new property to HeaderRendererProps

Automatically set indeterminate property on built-in or overridden checkboxFormatter
as long as the ref exists and the ref component has a property named `indeterminate`
(e.x. input component)

Fixed typo in comment

resolves adazzle#3058
  • Loading branch information
paustint committed Dec 25, 2022
1 parent 66bc050 commit 378ac22
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/Columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const SelectColumn: Column<any, any> = {
aria-label="Select All"
isCellSelected={props.isCellSelected}
value={props.allRowsSelected}
isIndeterminate={props.someRowsSelected}
onChange={props.onAllRowsSelectionChange}
/>
);
Expand Down
14 changes: 13 additions & 1 deletion src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ function DataGrid<R, SR, K extends Key>(
);

const allRowsSelected = useMemo((): boolean => {
// no rows to select = explicitely unchecked
// no rows to select = explicitly unchecked
const { length } = rawRows;
return (
length !== 0 &&
Expand All @@ -315,6 +315,17 @@ function DataGrid<R, SR, K extends Key>(
);
}, [rawRows, selectedRows, rowKeyGetter]);

const someRowsSelected = useMemo((): boolean => {
const { length } = rawRows;
return (
length !== 0 &&
selectedRows != null &&
rowKeyGetter != null &&
selectedRows.size > 0 &&
selectedRows.size < length
);
}, [rawRows, selectedRows, rowKeyGetter]);

const {
columns,
colSpanColumns,
Expand Down Expand Up @@ -1221,6 +1232,7 @@ function DataGrid<R, SR, K extends Key>(
onColumnResize={handleColumnResizeLatest}
allRowsSelected={allRowsSelected}
onAllRowsSelectionChange={selectAllRowsLatest}
someRowsSelected={someRowsSelected}
sortColumns={sortColumns}
onSortColumnsChange={onSortColumnsChangeLatest}
lastFrozenColumnIndex={lastFrozenColumnIndex}
Expand Down
3 changes: 3 additions & 0 deletions src/HeaderCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type SharedHeaderRowProps<R, SR> = Pick<
| 'sortColumns'
| 'onSortColumnsChange'
| 'allRowsSelected'
| 'someRowsSelected'
| 'onAllRowsSelectionChange'
| 'selectCell'
| 'onColumnResize'
Expand All @@ -48,6 +49,7 @@ export default function HeaderCell<R, SR>({
isCellSelected,
onColumnResize,
allRowsSelected,
someRowsSelected,
onAllRowsSelectionChange,
sortColumns,
onSortColumnsChange,
Expand Down Expand Up @@ -189,6 +191,7 @@ export default function HeaderCell<R, SR>({
priority,
onSort,
allRowsSelected,
someRowsSelected,
onAllRowsSelectionChange,
isCellSelected
})}
Expand Down
3 changes: 3 additions & 0 deletions src/HeaderRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type SharedDataGridProps<R, SR, K extends React.Key> = Pick<
export interface HeaderRowProps<R, SR, K extends React.Key> extends SharedDataGridProps<R, SR, K> {
columns: readonly CalculatedColumn<R, SR>[];
allRowsSelected: boolean;
someRowsSelected: boolean;
onAllRowsSelectionChange: (checked: boolean) => void;
onColumnResize: (column: CalculatedColumn<R, SR>, width: number | 'max-content') => void;
selectCell: (columnIdx: number) => void;
Expand Down Expand Up @@ -50,6 +51,7 @@ const headerRowClassname = `rdg-header-row ${headerRow}`;
function HeaderRow<R, SR, K extends React.Key>({
columns,
allRowsSelected,
someRowsSelected,
onAllRowsSelectionChange,
onColumnResize,
sortColumns,
Expand All @@ -76,6 +78,7 @@ function HeaderRow<R, SR, K extends React.Key>({
isCellSelected={selectedCellIdx === column.idx}
onColumnResize={onColumnResize}
allRowsSelected={allRowsSelected}
someRowsSelected={someRowsSelected}
onAllRowsSelectionChange={onAllRowsSelectionChange}
onSortColumnsChange={onSortColumnsChange}
sortColumns={sortColumns}
Expand Down
10 changes: 10 additions & 0 deletions src/formatters/SelectCellFormatter.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useEffect } from 'react';
import { useFocusRef } from '../hooks/useFocusRef';
import { useDefaultComponents } from '../DataGridDefaultComponentsProvider';
import type { CheckboxFormatterProps } from '../types';
Expand All @@ -6,13 +7,15 @@ type SharedInputProps = Pick<CheckboxFormatterProps, 'disabled' | 'aria-label' |

interface SelectCellFormatterProps extends SharedInputProps {
isCellSelected: boolean;
isIndeterminate?: boolean;
value: boolean;
onChange: (value: boolean, isShiftClick: boolean) => void;
}

export function SelectCellFormatter({
value,
isCellSelected,
isIndeterminate = false,
disabled,
onChange,
'aria-label': ariaLabel,
Expand All @@ -21,6 +24,13 @@ export function SelectCellFormatter({
const { ref, tabIndex } = useFocusRef<HTMLInputElement>(isCellSelected);
const checkboxFormatter = useDefaultComponents()!.checkboxFormatter!;

useEffect(() => {
if (typeof ref.current?.indeterminate === 'boolean') {
ref.current.indeterminate = isIndeterminate;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isIndeterminate]);

return (
<>
{checkboxFormatter(
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export interface HeaderRendererProps<TRow, TSummaryRow = unknown> {
priority: number | undefined;
onSort: (ctrlClick: boolean) => void;
allRowsSelected: boolean;
someRowsSelected: boolean;
onAllRowsSelectionChange: (checked: boolean) => void;
isCellSelected: boolean;
}
Expand Down

0 comments on commit 378ac22

Please sign in to comment.