Skip to content

Commit dd266f6

Browse files
authored
fix: gridManager cleanup, fixes (#1241)
* fix: fix selectors in calendar, space handling in ie * fix: refactor to store cell properties * fix: fix calendar classname, header row handling * fix: skipped rows handling * fix: row navigation tabindex
1 parent c01c1de commit dd266f6

File tree

2 files changed

+62
-99
lines changed

2 files changed

+62
-99
lines changed

src/Calendar/Calendar.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ class Calendar extends Component {
7676
const { gridBoundaryContext, refocusGrid } = this.state;
7777
const tableElement = this.tableRef.current;
7878
const focusedDateElement = tableElement.querySelector('[data-is-focused=true]');
79-
const selectedDateElement = tableElement.querySelector(classnames('.is-selected'));
80-
const todayDateElement = tableElement.querySelector(classnames(`.${cssNamespace}-calendar__item--current`));
81-
const disabledDateElements = tableElement.querySelectorAll(classnames(`.${cssNamespace}-calendar__item--other-month`));
79+
const selectedDateElement = tableElement.querySelector(`.${classnames('is-selected')}`);
80+
const todayDateElement = tableElement.querySelector(`.${classnames(`${cssNamespace}-calendar__item--current`)}`);
81+
const disabledDateElements = tableElement.querySelectorAll(`.${classnames(`${cssNamespace}-calendar__item--other-month`)}`);
8282
const focusOnInit = newView || gridBoundaryContext || refocusGrid;
8383

8484
let firstFocusedElement;

src/utils/gridManager/gridManager.js

Lines changed: 59 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default class GridManager {
5858
row: firstFocusedCoordinates.row,
5959
col: firstFocusedCoordinates.col,
6060
element: this.grid[firstFocusedCoordinates.row] ?
61-
this.grid[firstFocusedCoordinates.row][firstFocusedCoordinates.col] : null
61+
this.grid[firstFocusedCoordinates.row][firstFocusedCoordinates.col]?.element : null
6262
};
6363

6464
if (!this.isValidCell(firstFocusedCell) || this.isDisabledCell(firstFocusedCell.element)) {
@@ -84,26 +84,37 @@ export default class GridManager {
8484

8585
setupFocusGrid = () => {
8686
this.grid = [];
87+
let skippedRows = 0;
8788

8889
this.gridNode && Array.prototype.forEach.call(
89-
this.gridNode.querySelectorAll(GridSelector.ROW), (row) => {
90+
this.gridNode.querySelectorAll(GridSelector.ROW), (row, rowIndex) => {
9091
const rowCells = [];
9192
if (this.rowNavigation) {
9293
row.setAttribute('tabindex', -1);
9394
}
9495

9596
Array.prototype.forEach.call(
96-
row.querySelectorAll(this.cellSelector), (cell) => {
97+
row.querySelectorAll(this.cellSelector), (cell, cellIndex) => {
9798
let colSpan = cell.colSpan;
9899
cell.setAttribute('tabindex', -1);
99100
cell.addEventListener('focus', this.handleFocusCell);
100-
101-
colSpan > 0 ? rowCells.push(...this.createFilledArray(colSpan, cell)) : rowCells.push(cell);
101+
const cellObj = {
102+
row: rowIndex - skippedRows,
103+
col: cellIndex,
104+
element: cell,
105+
rowElement: row,
106+
focusableElements: cell.querySelectorAll(GridSelector.FOCUSABLE),
107+
editableElement: cell.querySelector(GridSelector.EDITABLE)
108+
};
109+
110+
colSpan > 0 ? rowCells.push(...this.createFilledArray(colSpan, cellObj)) : rowCells.push(cellObj);
102111
}
103112
);
104113

105114
if (rowCells.length) {
106115
this.grid.push(rowCells);
116+
} else {
117+
skippedRows++;
107118
}
108119
}
109120
);
@@ -133,15 +144,7 @@ export default class GridManager {
133144
const cellCoordinates = knownCoordinates ? knownCoordinates : this.getCellCoordinates(element);
134145
let cell;
135146
if (cellCoordinates) {
136-
cell = {
137-
row: cellCoordinates.row,
138-
col: cellCoordinates.col,
139-
element: element
140-
};
141-
if (element) {
142-
cell.focusableElements = cell.element.querySelectorAll(GridSelector.FOCUSABLE);
143-
cell.editableElement = cell.element.querySelector(GridSelector.EDITABLE);
144-
}
147+
cell = this.grid[cellCoordinates.row][cellCoordinates.col];
145148
}
146149

147150
return cell;
@@ -151,9 +154,9 @@ export default class GridManager {
151154
for (let row = 0; row < this.grid.length; row++) {
152155
for (let col = 0; col < this.grid[row].length; col++) {
153156
if (element && (
154-
this.grid[row][col] === element ||
155-
this.grid[row][col].contains(element) ||
156-
element.contains(this.grid[row][col])
157+
this.grid[row][col].element === element ||
158+
this.grid[row][col].element.contains(element) ||
159+
element.contains(this.grid[row][col].element)
157160
)) {
158161
return { row, col };
159162
}
@@ -163,20 +166,18 @@ export default class GridManager {
163166
}
164167

165168
getCurrentCellProperties = () => {
166-
return this.getCellProperties(
167-
this.grid[this.focusedRow][this.focusedCol],
168-
{ row: this.focusedRow, col: this.focusedCol }
169-
);
169+
return this.grid[this.focusedRow][this.focusedCol];
170170
}
171171

172172
setFocusPointer = (row, col) => {
173173
if (this.isValidCell({ row, col })) {
174-
const currentElement = this.grid[this.focusedRow][this.focusedCol];
175-
const nextElement = this.grid[row][col];
174+
const currentCell = this.grid[this.focusedRow][this.focusedCol];
175+
const nextCell = this.grid[row][col];
176+
const elementProp = !this.rowNavigation ? 'element' : 'rowElement';
176177

177178
if (!this.editMode) {
178-
currentElement.setAttribute('tabindex', -1);
179-
nextElement.setAttribute('tabindex', 0);
179+
currentCell[elementProp].setAttribute('tabindex', -1);
180+
nextCell[elementProp].setAttribute('tabindex', 0);
180181
}
181182

182183
this.focusedRow = row;
@@ -239,15 +240,16 @@ export default class GridManager {
239240
) {
240241
cell.focusableElements[0].focus();
241242
} else if (this.rowNavigation) {
242-
event.target.parentNode.focus();
243+
cell.rowElement?.focus();
243244
}
244245
this.onFocusCell(cell, event);
245246
}
246247
}
247248

248249
toggleEditMode = (currentCell, enable) => {
249250
this.editMode = !!enable;
250-
currentCell.element.setAttribute('tabindex', enable ? -1 : 0);
251+
const elementProp = !this.rowNavigation ? 'element' : 'rowElement';
252+
currentCell[elementProp].setAttribute('tabindex', enable ? -1 : 0);
251253
const focusableElements = this.getAllFocusableElements(this.skipFirstColumnTabbing);
252254
this.toggleTabbableElements(enable, focusableElements);
253255
if (focusableElements.length > 0) {
@@ -257,12 +259,13 @@ export default class GridManager {
257259

258260
getAllFocusableElements = (skipFirstColumn) => {
259261
let focusableElements = [];
260-
const cells = this.gridNode.querySelectorAll(this.cellSelector);
261-
cells.forEach(cell => {
262-
const { col } = this.getCellCoordinates(cell);
263-
if (!(this.rowNavigation && skipFirstColumn && col === 0)) {
264-
focusableElements = [...focusableElements, ...cell.querySelectorAll(GridSelector.FOCUSABLE)];
265-
}
262+
263+
this.grid.forEach((row) => {
264+
row.forEach((cell) => {
265+
if (!(this.rowNavigation && skipFirstColumn && cell?.col === 0)) {
266+
focusableElements = [...focusableElements, ...cell?.focusableElements];
267+
}
268+
});
266269
});
267270

268271
return focusableElements;
@@ -277,53 +280,43 @@ export default class GridManager {
277280
}
278281

279282
handleKeyDown = (event) => {
280-
this.syncFocusPointerToActiveElement(event.target);
281-
282283
const key = event.which || event.keyCode;
283-
const currentCell = this.getCurrentCellProperties();
284+
const currentCell = this.grid[this.focusedRow][this.focusedCol];
284285

285286
let nextCell = currentCell;
286-
let pressedArrowKey = false;
287+
let pressedNavigationalKey = false;
287288

288289
switch (key) {
289290
case keycode.codes.up:
290291
nextCell = this.getNextCell(currentCell, 0, -1);
291-
pressedArrowKey = true;
292+
pressedNavigationalKey = true;
292293
break;
293294
case keycode.codes.down:
294295
nextCell = this.getNextCell(currentCell, 0, 1);
295-
pressedArrowKey = true;
296+
pressedNavigationalKey = true;
296297
break;
297298
case keycode.codes.left:
298299
if (!this.rowNavigation) {
299300
nextCell = this.getNextCell(currentCell, -1, 0);
300-
pressedArrowKey = true;
301+
pressedNavigationalKey = true;
301302
}
302303
break;
303304
case keycode.codes.right:
304305
if (!this.rowNavigation) {
305306
nextCell = this.getNextCell(currentCell, 1, 0);
306-
pressedArrowKey = true;
307+
pressedNavigationalKey = true;
307308
}
308309
break;
309310
case keycode.codes.home:
310311
if (!this.rowNavigation) {
311-
nextCell = this.getNextCell(
312-
this.getCellProperties(
313-
this.grid[this.focusedRow][this.grid[this.focusedRow].length],
314-
{ row: this.focusedRow, col: -1 }
315-
), 1, 0
316-
);
312+
nextCell = this.getNextCell({ row: this.focusedRow, col: -1 }, 1, 0);
313+
pressedNavigationalKey = true;
317314
}
318315
break;
319316
case keycode.codes.end:
320317
if (!this.rowNavigation) {
321-
nextCell = this.getNextCell(
322-
this.getCellProperties(
323-
this.grid[this.focusedRow][this.grid[this.focusedRow].length],
324-
{ row: this.focusedRow, col: this.grid[this.focusedRow].length }
325-
), -1, 0
326-
);
318+
nextCell = this.getNextCell({ row: this.focusedRow, col: this.grid[this.focusedRow].length }, -1, 0);
319+
pressedNavigationalKey = true;
327320
}
328321
break;
329322
case keycode.codes.enter:
@@ -359,35 +352,23 @@ export default class GridManager {
359352
}
360353
return;
361354
default:
362-
break;
355+
this.onKeyDownCell(nextCell, event);
356+
return;
363357
}
364358

365359
if (nextCell) {
366360
this.focusCell(nextCell, event);
367361
this.onKeyDownCell(nextCell, event);
368362
}
369363

370-
if (!this.editMode && pressedArrowKey) {
364+
if (!this.editMode && pressedNavigationalKey) {
371365
event.preventDefault();
372366
}
373367
};
374368

375-
syncFocusPointerToActiveElement = (focusedTarget) => {
376-
const focusedCell = this.getCellProperties(
377-
this.grid[this.focusedRow][this.focusedCol],
378-
{ row: this.focusedRow, col: this.focusedCol }
379-
).element;
380-
381-
if (focusedCell === focusedTarget || focusedCell.contains(focusedTarget)) {
382-
return;
383-
}
384-
385-
this.setFocusPointer(focusedCell.row, focusedCell.col);
386-
};
387-
388369
handleClickCell = (event) => {
389370
// reset current edit state
390-
const currentCell = this.getCurrentCellProperties();
371+
const currentCell = this.grid[this.focusedRow][this.focusedCol];
391372

392373
if (this.isEditableCell(currentCell) && this.editMode) {
393374
this.toggleEditMode(currentCell, false);
@@ -400,13 +381,7 @@ export default class GridManager {
400381
}
401382

402383
if (clickedGridCell) {
403-
this.focusCell({
404-
row: clickedGridCell.row,
405-
col: clickedGridCell.col,
406-
element: clickedGridCell.element,
407-
focusableElements: clickedGridCell.focusableElements,
408-
editableElement: clickedGridCell.editableElement
409-
}, event);
384+
this.focusCell(clickedGridCell, event);
410385
}
411386
};
412387

@@ -443,7 +418,7 @@ export default class GridManager {
443418
return null;
444419
}
445420

446-
let nextCellElement = currentCell;
421+
let nextCell = currentCell;
447422

448423
if (directionX !== 0) { // horizontal
449424
let candidateRow = currentCell.row;
@@ -474,14 +449,11 @@ export default class GridManager {
474449
}
475450
} while (
476451
!this.isValidCell({ row: candidateRow, col: candidateCol }) ||
477-
this.isDisabledCell(this.grid[candidateRow][candidateCol]) ||
478-
this.grid[candidateRow][candidateCol] === currentCell.element
452+
this.isDisabledCell(this.grid[candidateRow][candidateCol].element) ||
453+
this.grid[candidateRow][candidateCol].element === currentCell.element
479454
);
480455

481-
nextCellElement = this.getCellProperties(
482-
this.grid[candidateRow][candidateCol],
483-
{ row: candidateRow, col: candidateCol }
484-
);
456+
nextCell = this.grid[candidateRow][candidateCol];
485457
} else if (directionY !== 0) { // vertical
486458
let candidateRow = currentCell.row;
487459
let candidateCol = currentCell.col;
@@ -507,23 +479,14 @@ export default class GridManager {
507479
}
508480
} while (
509481
!this.isValidCell({ row: candidateRow, col: candidateCol }) ||
510-
this.isDisabledCell(this.grid[candidateRow][candidateCol]) ||
511-
this.grid[candidateRow][candidateCol] === currentCell.element
482+
this.isDisabledCell(this.grid[candidateRow][candidateCol].element) ||
483+
this.grid[candidateRow][candidateCol].element === currentCell.element
512484
);
513485

514-
nextCellElement = this.getCellProperties(
515-
this.grid[candidateRow][candidateCol],
516-
{ row: candidateRow, col: candidateCol }
517-
);
486+
nextCell = this.grid[candidateRow][candidateCol];
518487
}
519488

520-
return {
521-
row: nextCellElement.row,
522-
col: nextCellElement.col,
523-
element: nextCellElement.element,
524-
focusableElements: nextCellElement.focusableElements,
525-
editableElement: nextCellElement.editableElement
526-
};
489+
return nextCell;
527490
};
528491

529492
getNextOutsideTabbableElement = (shiftKey) => {

0 commit comments

Comments
 (0)