From 537acca14224a2b77821c9c8b011b817bdea2e7b Mon Sep 17 00:00:00 2001 From: Chris Lewis Date: Wed, 30 Aug 2017 09:20:48 -0700 Subject: [PATCH] [Table] Show focus cell appropriately when enableFocus becomes true (#1447) * Show focus cell appropriately when enableFocus becomes true * Add focusUtils.ts * Rename file, incorporate, add first test * Write more tests * Oops, delete .only * Add missing file header --- .../src/common/internal/focusedCellUtils.ts | 38 ++++++++ packages/table/src/table.tsx | 28 +++--- .../common/internal/focusCellUtilsTests.ts | 87 +++++++++++++++++++ packages/table/test/common/internal/index.ts | 9 ++ packages/table/test/index.ts | 2 +- 5 files changed, 150 insertions(+), 14 deletions(-) create mode 100644 packages/table/src/common/internal/focusedCellUtils.ts create mode 100644 packages/table/test/common/internal/focusCellUtilsTests.ts create mode 100644 packages/table/test/common/internal/index.ts diff --git a/packages/table/src/common/internal/focusedCellUtils.ts b/packages/table/src/common/internal/focusedCellUtils.ts new file mode 100644 index 0000000000..c685eb8207 --- /dev/null +++ b/packages/table/src/common/internal/focusedCellUtils.ts @@ -0,0 +1,38 @@ +/** + * Copyright 2017 Palantir Technologies, Inc. All rights reserved. + * Licensed under the BSD-3 License as modified (the “License”); you may obtain a copy + * of the license at https://github.com/palantir/blueprint/blob/master/LICENSE + * and https://github.com/palantir/blueprint/blob/master/PATENTS + */ + +import { IRegion, Regions } from "../../regions"; +import { IFocusedCellCoordinates } from "../cell"; + +/** + * Returns the proper focused cell for the given set of initial conditions. + */ +export function getInitialFocusedCell( + enableFocus: boolean, + focusedCellFromProps: IFocusedCellCoordinates, + focusedCellFromState: IFocusedCellCoordinates, + selectedRegions: IRegion[], +): IFocusedCellCoordinates { + if (!enableFocus) { + return undefined; + } else if (focusedCellFromProps != null) { + // controlled mode + return focusedCellFromProps; + } else if (focusedCellFromState != null) { + // use the current focused cell from state + return focusedCellFromState; + } else if (selectedRegions.length > 0) { + // focus the top-left cell of the first selection + return { + ...Regions.getFocusCellCoordinatesFromRegion(selectedRegions[0]), + focusSelectionIndex: 0, + }; + } else { + // focus the top-left cell of the table + return { col: 0, row: 0, focusSelectionIndex: 0 }; + } +} diff --git a/packages/table/src/table.tsx b/packages/table/src/table.tsx index 7b2d78213c..7992fbe70e 100644 --- a/packages/table/src/table.tsx +++ b/packages/table/src/table.tsx @@ -17,6 +17,7 @@ import * as Classes from "./common/classes"; import { Clipboard } from "./common/clipboard"; import * as Errors from "./common/errors"; import { Grid, IColumnIndices, IRowIndices } from "./common/grid"; +import * as FocusedCellUtils from "./common/internal/focusedCellUtils"; import * as ScrollUtils from "./common/internal/scrollUtils"; import { Rect } from "./common/rect"; import { RenderMode } from "./common/renderMode"; @@ -433,15 +434,12 @@ export class Table extends AbstractComponent { newRowHeights = Utils.assignSparseValues(newRowHeights, rowHeights); const selectedRegions = (props.selectedRegions == null) ? [] as IRegion[] : props.selectedRegions; - - let focusedCell: IFocusedCellCoordinates; - if (props.enableFocus) { - if (props.focusedCell != null) { - focusedCell = props.focusedCell; - } else { - focusedCell = { col: 0, row: 0, focusSelectionIndex: 0 }; - } - } + const focusedCell = FocusedCellUtils.getInitialFocusedCell( + props.enableFocus, + props.focusedCell, + undefined, + selectedRegions, + ); this.state = { columnWidths: newColumnWidths, @@ -578,16 +576,20 @@ export class Table extends AbstractComponent { return isSelectionModeEnabled && Regions.isRegionValidForTable(region, numRows, numCols); }); } - const newFocusedCellCoordinates = (focusedCell == null) - ? this.state.focusedCell - : focusedCell; + + const newFocusedCell = FocusedCellUtils.getInitialFocusedCell( + enableFocus, + focusedCell, + this.state.focusedCell, + newSelectedRegions, + ); this.childrenArray = newChildArray; this.columnIdToIndex = Table.createColumnIdIndex(this.childrenArray); this.invalidateGrid(); this.setState({ columnWidths: newColumnWidths, - focusedCell: enableFocus ? newFocusedCellCoordinates : undefined, + focusedCell: newFocusedCell, rowHeights: newRowHeights, selectedRegions: newSelectedRegions, }); diff --git a/packages/table/test/common/internal/focusCellUtilsTests.ts b/packages/table/test/common/internal/focusCellUtilsTests.ts new file mode 100644 index 0000000000..e68f21013a --- /dev/null +++ b/packages/table/test/common/internal/focusCellUtilsTests.ts @@ -0,0 +1,87 @@ +/** + * Copyright 2017 Palantir Technologies, Inc. All rights reserved. + * Licensed under the BSD-3 License as modified (the “License”); you may obtain a copy + * of the license at https://github.com/palantir/blueprint/blob/master/LICENSE + * and https://github.com/palantir/blueprint/blob/master/PATENTS + */ + +import { expect } from "chai"; + +import { IFocusedCellCoordinates } from "../../../src/common/cell"; +import * as FocusedCellUtils from "../../../src/common/internal/focusedCellUtils"; +import { Regions } from "../../../src/regions"; + +describe("focusCellUtils", () => { + describe("getInitialFocusedCell", () => { + const FOCUSED_CELL_FROM_PROPS = getFocusedCell(1, 2); + const FOCUSED_CELL_FROM_STATE = getFocusedCell(3, 4); + const SELECTED_REGIONS = [ + Regions.cell(1, 1, 4, 5), + Regions.cell(5, 1, 6, 2), + ]; + + it("returns undefined if enableFocus=false", () => { + const focusedCell = FocusedCellUtils.getInitialFocusedCell( + false, + FOCUSED_CELL_FROM_PROPS, + FOCUSED_CELL_FROM_STATE, + SELECTED_REGIONS, + ); + expect(focusedCell).to.be.undefined; + }); + + it("returns the focusedCellFromProps if defined", () => { + const focusedCell = FocusedCellUtils.getInitialFocusedCell( + true, + FOCUSED_CELL_FROM_PROPS, + FOCUSED_CELL_FROM_STATE, + SELECTED_REGIONS, + ); + expect(focusedCell).to.deep.equal(FOCUSED_CELL_FROM_PROPS); + }); + + it("returns the focusedCellFromState if focusedCellFromProps not defined", () => { + const focusedCell = FocusedCellUtils.getInitialFocusedCell( + true, + null, + FOCUSED_CELL_FROM_STATE, + SELECTED_REGIONS, + ); + expect(focusedCell).to.deep.equal(FOCUSED_CELL_FROM_STATE); + }); + + it("returns the focused cell for the first selected region if " + + "focusedCellFromState and focusedCellFromProps not defined", () => { + const focusedCell = FocusedCellUtils.getInitialFocusedCell( + true, + null, + null, + SELECTED_REGIONS, + ); + const expectedFocusedCell = { + ...Regions.getFocusCellCoordinatesFromRegion(SELECTED_REGIONS[0]), + focusSelectionIndex: 0, + }; + expect(focusedCell).to.deep.equal(expectedFocusedCell); + }); + + it("returns cell (0, 0) if nothing else is defined", () => { + const focusedCell = FocusedCellUtils.getInitialFocusedCell( + true, + null, + null, + [], + ); + const expectedFocusedCell = { + col: 0, + focusSelectionIndex: 0, + row: 0, + }; + expect(focusedCell).to.deep.equal(expectedFocusedCell); + }); + + function getFocusedCell(row: number, col: number, focusSelectionIndex: number = 0): IFocusedCellCoordinates { + return { row, col, focusSelectionIndex }; + } + }); +}); diff --git a/packages/table/test/common/internal/index.ts b/packages/table/test/common/internal/index.ts new file mode 100644 index 0000000000..ac99018805 --- /dev/null +++ b/packages/table/test/common/internal/index.ts @@ -0,0 +1,9 @@ +/** + * Copyright 2017 Palantir Technologies, Inc. All rights reserved. + * Licensed under the BSD-3 License as modified (the “License”); you may obtain a copy + * of the license at https://github.com/palantir/blueprint/blob/master/LICENSE + * and https://github.com/palantir/blueprint/blob/master/PATENTS + */ + +import "./focusCellUtilsTests"; +import "./scrollUtilsTests"; diff --git a/packages/table/test/index.ts b/packages/table/test/index.ts index 392a700391..882fe3c7ea 100644 --- a/packages/table/test/index.ts +++ b/packages/table/test/index.ts @@ -12,7 +12,7 @@ import "./cellTests.tsx"; import "./clipboardTests.ts"; import "./columnHeaderCellTests.tsx"; import "./columnTests.tsx"; -import "./common/internal/scrollUtilsTests.ts"; +import "./common/internal/"; import "./editableCellTests.tsx"; import "./editableNameTests.tsx"; import "./formatsTests.tsx";