Minor keyboard navigation around fix
Summary: Fixed minor keyboard navigation annoyance: pressing arrow down on the last entry would remove selection, then jump to first row. Pressing up on first row would deselect then select first again. After this change the first/last item is kept selected in those cases Reviewed By: passy Differential Revision: D28958705 fbshipit-source-id: 01dbce3971ed965eae3b74e6706fef96aa86df66
This commit is contained in:
committed by
Facebook GitHub Bot
parent
6224daf247
commit
23c0781127
@@ -188,9 +188,9 @@ export function DataTable<T extends object>(
|
|||||||
if (e.ctrlKey || e.metaKey) {
|
if (e.ctrlKey || e.metaKey) {
|
||||||
tableManager.addRangeToSelection(index, index, true);
|
tableManager.addRangeToSelection(index, index, true);
|
||||||
} else if (e.shiftKey) {
|
} else if (e.shiftKey) {
|
||||||
tableManager.selectItem(index, true);
|
tableManager.selectItem(index, true, true);
|
||||||
} else {
|
} else {
|
||||||
tableManager.selectItem(index);
|
tableManager.selectItem(index, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
dragging.current = true;
|
dragging.current = true;
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ type DataManagerActions<T> =
|
|||||||
{
|
{
|
||||||
nextIndex: number | ((currentIndex: number) => number);
|
nextIndex: number | ((currentIndex: number) => number);
|
||||||
addToSelection?: boolean;
|
addToSelection?: boolean;
|
||||||
|
allowUnselect?: boolean;
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
| Action<
|
| Action<
|
||||||
@@ -161,9 +162,14 @@ export const dataTableManagerReducer = produce<
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'selectItem': {
|
case 'selectItem': {
|
||||||
const {nextIndex, addToSelection} = action;
|
const {nextIndex, addToSelection, allowUnselect} = action;
|
||||||
draft.selection = castDraft(
|
draft.selection = castDraft(
|
||||||
computeSetSelection(draft.selection, nextIndex, addToSelection),
|
computeSetSelection(
|
||||||
|
draft.selection,
|
||||||
|
nextIndex,
|
||||||
|
addToSelection,
|
||||||
|
allowUnselect,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -252,6 +258,7 @@ export type DataTableManager<T> = {
|
|||||||
selectItem(
|
selectItem(
|
||||||
index: number | ((currentSelection: number) => number),
|
index: number | ((currentSelection: number) => number),
|
||||||
addToSelection?: boolean,
|
addToSelection?: boolean,
|
||||||
|
allowUnselect?: boolean,
|
||||||
): void;
|
): void;
|
||||||
addRangeToSelection(
|
addRangeToSelection(
|
||||||
start: number,
|
start: number,
|
||||||
@@ -276,8 +283,13 @@ export function createDataTableManager<T>(
|
|||||||
reset() {
|
reset() {
|
||||||
dispatch({type: 'reset'});
|
dispatch({type: 'reset'});
|
||||||
},
|
},
|
||||||
selectItem(index: number, addToSelection = false) {
|
selectItem(index: number, addToSelection = false, allowUnselect = false) {
|
||||||
dispatch({type: 'selectItem', nextIndex: index, addToSelection});
|
dispatch({
|
||||||
|
type: 'selectItem',
|
||||||
|
nextIndex: index,
|
||||||
|
addToSelection,
|
||||||
|
allowUnselect,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
selectItemById(id, addToSelection = false) {
|
selectItemById(id, addToSelection = false) {
|
||||||
dispatch({type: 'selectItemById', id, addToSelection});
|
dispatch({type: 'selectItemById', id, addToSelection});
|
||||||
@@ -517,11 +529,17 @@ export function computeSetSelection(
|
|||||||
base: Selection,
|
base: Selection,
|
||||||
nextIndex: number | ((currentIndex: number) => number),
|
nextIndex: number | ((currentIndex: number) => number),
|
||||||
addToSelection?: boolean,
|
addToSelection?: boolean,
|
||||||
|
allowUnselect?: boolean,
|
||||||
): Selection {
|
): Selection {
|
||||||
const newIndex =
|
const newIndex =
|
||||||
typeof nextIndex === 'number' ? nextIndex : nextIndex(base.current);
|
typeof nextIndex === 'number' ? nextIndex : nextIndex(base.current);
|
||||||
// special case: toggle existing selection off
|
// special case: toggle existing selection off
|
||||||
if (!addToSelection && base.items.size === 1 && base.current === newIndex) {
|
if (
|
||||||
|
!addToSelection &&
|
||||||
|
allowUnselect &&
|
||||||
|
base.items.size === 1 &&
|
||||||
|
base.current === newIndex
|
||||||
|
) {
|
||||||
return emptySelection;
|
return emptySelection;
|
||||||
}
|
}
|
||||||
if (newIndex < 0) {
|
if (newIndex < 0) {
|
||||||
|
|||||||
@@ -61,6 +61,20 @@ test('computeSetSelection', () => {
|
|||||||
items: new Set([5]),
|
items: new Set([5]),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// single item existing selection, no selection toggle
|
||||||
|
expect(
|
||||||
|
computeSetSelection(
|
||||||
|
{
|
||||||
|
current: 4,
|
||||||
|
items: new Set([4]),
|
||||||
|
},
|
||||||
|
4,
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
current: 4,
|
||||||
|
items: new Set([4]),
|
||||||
|
});
|
||||||
|
|
||||||
// single item existing selection, toggle item off
|
// single item existing selection, toggle item off
|
||||||
expect(
|
expect(
|
||||||
computeSetSelection(
|
computeSetSelection(
|
||||||
@@ -69,6 +83,8 @@ test('computeSetSelection', () => {
|
|||||||
items: new Set([4]),
|
items: new Set([4]),
|
||||||
},
|
},
|
||||||
4,
|
4,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
).toEqual({
|
).toEqual({
|
||||||
current: -1,
|
current: -1,
|
||||||
|
|||||||
Reference in New Issue
Block a user