Skip to content

Commit ef52749

Browse files
authored
fix: stuck to bottom on filter clear (#1579)
Closes #1477 Previous comments are in #1571 PR. Note: Once this PR is merged #1571 can go in as well
1 parent b065f1c commit ef52749

2 files changed

Lines changed: 84 additions & 21 deletions

File tree

packages/grid/src/Grid.tsx

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ type LegacyCanvasRenderingContext2D = CanvasRenderingContext2D & {
6868
backingStorePixelRatio?: number;
6969
};
7070

71+
export type StickyOptions = {
72+
shouldStickBottom?: boolean;
73+
shouldStickRight?: boolean;
74+
};
75+
7176
export type GridProps = typeof Grid.defaultProps & {
7277
// Options to set on the canvas
7378
canvasOptions?: CanvasRenderingContext2DSettings;
@@ -1181,26 +1186,42 @@ class Grid extends PureComponent<GridProps, GridState> {
11811186
* @param deltaColumn Number of columns to move the cursor
11821187
* @param deltaRow Number of rows to move the cursor
11831188
* @param extendSelection True if the current selection should be extended, false to start a new selection
1189+
* @param stickyOptions Options for sticky behavior
11841190
*/
11851191
moveCursor(
11861192
deltaColumn: number,
11871193
deltaRow: number,
1188-
extendSelection: boolean
1194+
extendSelection: boolean,
1195+
stickyOptions?: StickyOptions
11891196
): void {
11901197
const { cursorRow, cursorColumn, selectionEndColumn, selectionEndRow } =
11911198
this.state;
11921199
const column = extendSelection ? selectionEndColumn : cursorColumn;
11931200
const row = extendSelection ? selectionEndRow : cursorRow;
11941201
if (row === null || column === null) {
11951202
const { left, top } = this.state;
1196-
this.moveCursorToPosition(left, top, extendSelection);
1203+
this.moveCursorToPosition(
1204+
left,
1205+
top,
1206+
extendSelection,
1207+
true,
1208+
false,
1209+
stickyOptions
1210+
);
11971211
} else {
11981212
const { model } = this.props;
11991213
const { columnCount, rowCount } = model;
12001214

12011215
const left = clamp(column + deltaColumn, 0, columnCount - 1);
12021216
const top = clamp(row + deltaRow, 0, rowCount - 1);
1203-
this.moveCursorToPosition(left, top, extendSelection);
1217+
this.moveCursorToPosition(
1218+
left,
1219+
top,
1220+
extendSelection,
1221+
true,
1222+
false,
1223+
stickyOptions
1224+
);
12041225
}
12051226
}
12061227

@@ -1260,13 +1281,15 @@ class Grid extends PureComponent<GridProps, GridState> {
12601281
* @param extendSelection Whether to extend the current selection (eg. holding Shift)
12611282
* @param keepCursorInView Whether to move the viewport so that the cursor is in view
12621283
* @param maximizePreviousRange With this and `extendSelection` true, it will maximize/add to the previous range only, ignoring where the selection was started
1284+
* @param stickyOptions Options for sticky behavior
12631285
*/
12641286
moveCursorToPosition(
12651287
column: GridRangeIndex,
12661288
row: GridRangeIndex,
12671289
extendSelection = false,
12681290
keepCursorInView = true,
1269-
maximizePreviousRange = false
1291+
maximizePreviousRange = false,
1292+
stickyOptions?: StickyOptions
12701293
): void {
12711294
if (!extendSelection) {
12721295
this.beginSelection(column, row);
@@ -1275,7 +1298,7 @@ class Grid extends PureComponent<GridProps, GridState> {
12751298
this.moveSelection(column, row, extendSelection, maximizePreviousRange);
12761299

12771300
if (keepCursorInView) {
1278-
this.moveViewToCell(column, row);
1301+
this.moveViewToCell(column, row, stickyOptions);
12791302
}
12801303
}
12811304

@@ -1284,8 +1307,13 @@ class Grid extends PureComponent<GridProps, GridState> {
12841307
*
12851308
* @param column The column index to bring into view
12861309
* @param row The row index to bring into view
1310+
* @param stickyOptions Options for sticky behavior
12871311
*/
1288-
moveViewToCell(column: GridRangeIndex, row: GridRangeIndex): void {
1312+
moveViewToCell(
1313+
column: GridRangeIndex,
1314+
row: GridRangeIndex,
1315+
stickyOptions?: StickyOptions
1316+
): void {
12891317
if (!this.metrics) throw new Error('metrics not set');
12901318

12911319
const { metricCalculator } = this;
@@ -1314,26 +1342,41 @@ class Grid extends PureComponent<GridProps, GridState> {
13141342
}
13151343
}
13161344

1317-
this.setViewState({ top, left, topOffset, leftOffset });
1345+
this.setViewState(
1346+
{ top, left, topOffset, leftOffset },
1347+
false,
1348+
stickyOptions
1349+
);
13181350
}
13191351

13201352
/**
13211353
* Checks the `top` and `left` properties that are set and updates the isStuckToBottom/Right properties
13221354
* Should be called when user interaction occurs
13231355
* @param viewState New state properties to set.
13241356
* @param forceUpdate Whether to force an update.
1357+
* @param stickyOptions Options for sticky behavior
13251358
*/
1326-
setViewState(viewState: Partial<GridState>, forceUpdate = false): void {
1359+
1360+
setViewState(
1361+
viewState: Partial<GridState>,
1362+
forceUpdate = false,
1363+
stickyOptions?: StickyOptions
1364+
): void {
13271365
if (!this.metrics) throw new Error('metrics not set');
13281366

13291367
const { isStickyBottom, isStickyRight } = this.props;
13301368
const { top, left } = viewState;
13311369
const { lastTop, lastLeft } = this.metrics;
1332-
if (top != null) {
1333-
this.setState({ isStuckToBottom: isStickyBottom && top >= lastTop });
1370+
1371+
if (top != null && (stickyOptions?.shouldStickBottom ?? false)) {
1372+
this.setState({
1373+
isStuckToBottom: isStickyBottom && top >= lastTop,
1374+
});
13341375
}
1335-
if (left != null) {
1336-
this.setState({ isStuckToRight: isStickyRight && left >= lastLeft });
1376+
if (left != null && (stickyOptions?.shouldStickRight ?? false)) {
1377+
this.setState({
1378+
isStuckToRight: isStickyRight && left >= lastLeft,
1379+
});
13371380
}
13381381

13391382
this.setState(viewState as GridState);
@@ -1978,7 +2021,15 @@ class Grid extends PureComponent<GridProps, GridState> {
19782021
}
19792022
}
19802023

1981-
this.setViewState({ top, left, leftOffset, topOffset });
2024+
const stickyOptions: StickyOptions = {
2025+
shouldStickBottom: event.deltaY > 0,
2026+
shouldStickRight: event.deltaX > 0,
2027+
};
2028+
this.setViewState(
2029+
{ top, left, leftOffset, topOffset },
2030+
false,
2031+
stickyOptions
2032+
);
19822033

19832034
event.stopPropagation();
19842035
event.preventDefault();

packages/grid/src/key-handlers/SelectionKeyHandler.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint class-methods-use-this: "off" */
22
import clamp from 'lodash.clamp';
33
import { EventHandlerResult } from '../EventHandlerResult';
4-
import Grid from '../Grid';
4+
import Grid, { StickyOptions } from '../Grid';
55
import GridRange from '../GridRange';
66
import GridUtils from '../GridUtils';
77
import KeyHandler, { GridKeyboardEvent } from '../KeyHandler';
@@ -144,6 +144,11 @@ class SelectionKeyHandler extends KeyHandler {
144144
grid.state;
145145
const column = isShiftKey ? selectionEndColumn : cursorColumn;
146146
const row = isShiftKey ? selectionEndRow : cursorRow;
147+
const stickyOptions: StickyOptions = {
148+
shouldStickBottom: deltaRow > 0,
149+
shouldStickRight: deltaColumn > 0,
150+
};
151+
147152
if (isModifierKey) {
148153
const { model } = grid.props;
149154
const { columnCount, rowCount } = model;
@@ -169,14 +174,16 @@ class SelectionKeyHandler extends KeyHandler {
169174
moveToRow,
170175
isShiftKey,
171176
true,
172-
maximizePreviousRange
177+
maximizePreviousRange,
178+
stickyOptions
173179
);
174180
}
175181
} else {
176182
if (!grid.metrics) throw new Error('grid.metrics are not set');
177183

178184
const { theme } = grid.props;
179185
const { autoSelectRow = false, autoSelectColumn = false } = theme;
186+
180187
if (autoSelectRow && deltaColumn !== 0) {
181188
const { lastLeft } = grid.metrics;
182189
let { left } = grid.state;
@@ -185,7 +192,7 @@ class SelectionKeyHandler extends KeyHandler {
185192

186193
grid.moveCursorToPosition(left, cursorRow, isShiftKey, false);
187194

188-
grid.setViewState({ left });
195+
grid.setViewState({ left }, false, stickyOptions);
189196
} else if (autoSelectColumn && deltaRow !== 0) {
190197
const { lastTop } = grid.metrics;
191198
let { top } = grid.state;
@@ -194,9 +201,9 @@ class SelectionKeyHandler extends KeyHandler {
194201

195202
grid.moveCursorToPosition(top, cursorColumn, isShiftKey, false);
196203

197-
grid.setViewState({ top });
204+
grid.setViewState({ top }, false, stickyOptions);
198205
} else {
199-
grid.moveCursor(deltaColumn, deltaRow, isShiftKey);
206+
grid.moveCursor(deltaColumn, deltaRow, isShiftKey, stickyOptions);
200207
}
201208
}
202209
return true;
@@ -242,8 +249,8 @@ class SelectionKeyHandler extends KeyHandler {
242249
return true;
243250
}
244251

245-
handlePageDown(e: GridKeyboardEvent, grid: Grid): boolean {
246-
const isShiftKey = e.shiftKey;
252+
handlePageDown(event: GridKeyboardEvent, grid: Grid): boolean {
253+
const isShiftKey = event.shiftKey;
247254

248255
if (isShiftKey) {
249256
grid.trimSelectedRanges();
@@ -279,7 +286,12 @@ class SelectionKeyHandler extends KeyHandler {
279286
isShiftKey,
280287
false
281288
);
282-
grid.setViewState({ top: viewportPosition });
289+
290+
const stickyOptions: StickyOptions = {
291+
shouldStickBottom: true,
292+
shouldStickRight: false,
293+
};
294+
grid.setViewState({ top: viewportPosition }, false, stickyOptions);
283295

284296
return true;
285297
}

0 commit comments

Comments
 (0)