@sinchsmb/ui-kit
Version:
UI kit for SinchSMB frontend
99 lines (86 loc) • 3.42 kB
text/typescript
import { useCallback, useMemo } from 'react';
import { useTranslation } from '../../../core/hooks/useTranslation';
import { useToast } from '../../../core/managers/ToastManager/hooks/useToast';
import { assertUnreachable } from '../../../utils/assertUnreachable';
import { ToastAppearance } from '../../Toast/constants';
import { TableSelectionType } from '../constants';
import { useTableCellContext } from '../contexts/TableCellContext';
import { useTablePropsContext } from '../contexts/TablePropsContext';
import { useTableSelectionContext } from '../contexts/TableSelectionContext';
/** Result of {@link useSingleRowSelection} hook. */
export interface UseSingleRowSelectionResult {
/** Flag indicating current row is selected. */
isSingleRowSelected: boolean;
/** Function that will toggle current row selection. */
onSingleRowSelectionChange: (selected: boolean) => void;
}
/** Hook that returns information about current row selection. */
export function useSingleRowSelection(): UseSingleRowSelectionResult {
const { t } = useTranslation();
const showToast = useToast();
const { rowNumber } = useTableCellContext();
const { selection, onSelectionChanged } = useTableSelectionContext();
const { rows, rowIdProvider, rowSelectionIncludeLimit, rowSelectionName } = useTablePropsContext();
const headerRowsCount = 1;
const rowId = useMemo(() => {
const dataRowNumber = rowNumber - headerRowsCount;
return rowIdProvider(rows[dataRowNumber]);
}, [rowIdProvider, rowNumber, rows]);
const onSingleRowSelectionChange = useCallback(
(selected: boolean) => {
if (!onSelectionChanged) {
return;
}
if (selection?.type === TableSelectionType.Exclude) {
const unselectedIds = new Set(selection.unselectedIds);
if (selected) {
unselectedIds.delete(rowId);
} else {
unselectedIds.add(rowId);
}
onSelectionChanged({
type: TableSelectionType.Exclude,
unselectedIds: Array.from(unselectedIds),
});
} else {
const selectedIds = new Set(selection?.selectedIds ?? []);
if (selected) {
selectedIds.add(rowId);
} else {
selectedIds.delete(rowId);
}
if (rowSelectionIncludeLimit && selectedIds.size > rowSelectionIncludeLimit) {
const message = t('ui.table.selectionIncludeLimit', {
count: rowSelectionIncludeLimit,
actionText: t('ui.table.selectAll'),
name: rowSelectionName,
});
showToast(message, { appearance: ToastAppearance.Warning });
}
onSelectionChanged({
type: TableSelectionType.Include,
selectedIds: Array.from(selectedIds).slice(0, rowSelectionIncludeLimit),
});
}
},
[onSelectionChanged, selection, rowId, rowSelectionIncludeLimit, t, rowSelectionName, showToast],
);
const isSingleRowSelected = useMemo(() => {
if (!selection) {
return false;
}
switch (selection.type) {
case TableSelectionType.Exclude:
return !selection.unselectedIds.has(rowId);
case TableSelectionType.Include:
return selection.selectedIds.has(rowId);
/* istanbul ignore next */
default:
assertUnreachable(selection);
}
}, [rowId, selection]);
return {
onSingleRowSelectionChange,
isSingleRowSelected,
};
}