Skip to content

Commit

Permalink
[react-interactions] Add FocusTable colSpan support (#17019)
Browse files Browse the repository at this point in the history
  • Loading branch information
trueadm committed Oct 7, 2019
1 parent 4bc52ef commit fff5b1c
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 91 deletions.
112 changes: 67 additions & 45 deletions packages/react-interactions/accessibility/src/FocusTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import setElementCanTab from './shared/setElementCanTab';
type FocusCellProps = {
children?: React.Node,
onKeyDown?: KeyboardEvent => void,
colSpan?: number,
};

type FocusRowProps = {
Expand All @@ -25,12 +26,12 @@ type FocusRowProps = {

type FocusTableProps = {|
children: React.Node,
id?: string,
onKeyboardOut?: (
direction: 'left' | 'right' | 'up' | 'down',
focusTableByID: (id: string) => void,
event: KeyboardEvent,
) => void,
wrap?: boolean,
wrapX?: boolean,
wrapY?: boolean,
tabScope?: ReactScope,
allowModifiers?: boolean,
|};
Expand Down Expand Up @@ -69,30 +70,59 @@ function focusScope(cell: ReactScopeMethods, event?: KeyboardEvent): void {
}
}

function focusCellByIndex(
// This takes into account colSpan
function focusCellByColumnIndex(
row: ReactScopeMethods,
cellIndex: number,
columnIndex: number,
event?: KeyboardEvent,
): void {
const cells = row.getChildren();
if (cells !== null) {
const cell = cells[cellIndex];
if (cell) {
focusScope(cell, event);
let colSize = 0;
for (let i = 0; i < cells.length; i++) {
const cell = cells[i];
if (cell) {
colSize += cell.getProps().colSpan || 1;
if (colSize > columnIndex) {
focusScope(cell, event);
return;
}
}
}
}
}

function getCellIndexes(
cells: Array<ReactScopeMethods>,
currentCell: ReactScopeMethods,
): [number, number] {
let totalColSpan = 0;
for (let i = 0; i < cells.length; i++) {
const cell = cells[i];
if (cell === currentCell) {
return [i, i + totalColSpan];
}
const colSpan = cell.getProps().colSpan;
if (colSpan) {
totalColSpan += colSpan - 1;
}
}
return [-1, -1];
}

function getRowCells(currentCell: ReactScopeMethods) {
const row = currentCell.getParent();
if (row !== null && row.getProps().type === 'row') {
const cells = row.getChildren();
if (cells !== null) {
const rowIndex = cells.indexOf(currentCell);
return [cells, rowIndex];
const [rowIndex, rowIndexWithColSpan] = getCellIndexes(
cells,
currentCell,
);
return [cells, rowIndex, rowIndexWithColSpan];
}
}
return [null, 0];
return [null, -1, -1];
}

function getRows(currentCell: ReactScopeMethods) {
Expand All @@ -107,7 +137,7 @@ function getRows(currentCell: ReactScopeMethods) {
}
}
}
return [null, 0];
return [null, -1, -1];
}

function triggerNavigateOut(
Expand All @@ -122,19 +152,7 @@ function triggerNavigateOut(
const props = table.getProps();
const onKeyboardOut = props.onKeyboardOut;
if (props.type === 'table' && typeof onKeyboardOut === 'function') {
const focusTableByID = (id: string) => {
const topLevelTables = table.getChildrenFromRoot();
if (topLevelTables !== null) {
for (let i = 0; i < topLevelTables.length; i++) {
const topLevelTable = topLevelTables[i];
if (topLevelTable.getProps().id === id) {
focusFirstCellOnTable(topLevelTable);
return;
}
}
}
};
onKeyboardOut(direction, focusTableByID);
onKeyboardOut(direction, event);
return;
}
}
Expand Down Expand Up @@ -166,8 +184,8 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
function Table({
children,
onKeyboardOut,
id,
wrap,
wrapX,
wrapY,
tabScope: TabScope,
allowModifiers,
}): FocusTableProps {
Expand All @@ -176,8 +194,8 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
<TableScope
type="table"
onKeyboardOut={onKeyboardOut}
id={id}
wrap={wrap}
wrapX={wrapX}
wrapY={wrapY}
tabScopeRef={tabScopeRef}
allowModifiers={allowModifiers}>
{TabScope ? (
Expand All @@ -193,7 +211,7 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
return <TableScope type="row">{children}</TableScope>;
}
function Cell({children, onKeyDown}): FocusCellProps {
function Cell({children, onKeyDown, colSpan}): FocusCellProps {
const scopeRef = useRef(null);
const keyboard = useKeyboard({
onKeyDown(event: KeyboardEvent): void {
Expand Down Expand Up @@ -232,18 +250,18 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
}
switch (key) {
case 'ArrowUp': {
const [cells, cellIndex] = getRowCells(currentCell);
const [cells, , cellIndexWithColSpan] = getRowCells(currentCell);
if (cells !== null) {
const [rows, rowIndex] = getRows(currentCell);
if (rows !== null) {
if (rowIndex > 0) {
const row = rows[rowIndex - 1];
focusCellByIndex(row, cellIndex, event);
focusCellByColumnIndex(row, cellIndexWithColSpan, event);
} else if (rowIndex === 0) {
const wrap = getTableProps(currentCell).wrap;
if (wrap) {
const wrapY = getTableProps(currentCell).wrapY;
if (wrapY) {
const row = rows[rows.length - 1];
focusCellByIndex(row, cellIndex, event);
focusCellByColumnIndex(row, cellIndexWithColSpan, event);
} else {
triggerNavigateOut(currentCell, 'up', event);
}
Expand All @@ -253,22 +271,22 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
return;
}
case 'ArrowDown': {
const [cells, cellIndex] = getRowCells(currentCell);
const [cells, , cellIndexWithColSpan] = getRowCells(currentCell);
if (cells !== null) {
const [rows, rowIndex] = getRows(currentCell);
if (rows !== null) {
if (rowIndex !== -1) {
if (rowIndex === rows.length - 1) {
const wrap = getTableProps(currentCell).wrap;
if (wrap) {
const wrapY = getTableProps(currentCell).wrapY;
if (wrapY) {
const row = rows[0];
focusCellByIndex(row, cellIndex, event);
focusCellByColumnIndex(row, cellIndexWithColSpan, event);
} else {
triggerNavigateOut(currentCell, 'down', event);
}
} else {
const row = rows[rowIndex + 1];
focusCellByIndex(row, cellIndex, event);
focusCellByColumnIndex(row, cellIndexWithColSpan, event);
}
}
}
Expand All @@ -282,8 +300,8 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
focusScope(cells[rowIndex - 1]);
event.preventDefault();
} else if (rowIndex === 0) {
const wrap = getTableProps(currentCell).wrap;
if (wrap) {
const wrapX = getTableProps(currentCell).wrapX;
if (wrapX) {
focusScope(cells[cells.length - 1], event);
} else {
triggerNavigateOut(currentCell, 'left', event);
Expand All @@ -297,8 +315,8 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
if (cells !== null) {
if (rowIndex !== -1) {
if (rowIndex === cells.length - 1) {
const wrap = getTableProps(currentCell).wrap;
if (wrap) {
const wrapX = getTableProps(currentCell).wrapX;
if (wrapX) {
focusScope(cells[0], event);
} else {
triggerNavigateOut(currentCell, 'right', event);
Expand All @@ -317,7 +335,11 @@ export function createFocusTable(scope: ReactScope): Array<React.Component> {
},
});
return (
<TableScope listeners={keyboard} ref={scopeRef} type="cell">
<TableScope
listeners={keyboard}
ref={scopeRef}
type="cell"
colSpan={colSpan}>
{children}
</TableScope>
);
Expand Down
Loading

0 comments on commit fff5b1c

Please sign in to comment.