Skip to content

Commit

Permalink
Allow developer to configure auto focus on the grid (addresses #813) (#…
Browse files Browse the repository at this point in the history
…845)

* Allow autofocus to be configured so that the developer can choose whether the grid can steal focus from the body (#813)

* set enableAutoFocus to true by default, and add tests for the enableAutoFocus configuration (#813)

* Update Cell's enableCellAutoFocus tests to reflect change to using ref instead of ReactDOM to find node to focus on

* Change render function name for Cell's enableCellAutoFocus tests so it is unique
  • Loading branch information
supamanda authored and malonecj committed Nov 6, 2017
1 parent 57df3c3 commit 3dbc315
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 5 deletions.
6 changes: 6 additions & 0 deletions docs/markdowns/ReactDataGrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ type: `element`
type: `func`


### `enableCellAutoFocus`

type: `bool`
defaultValue: `true`


### `enableCellSelect`

type: `bool`
Expand Down
6 changes: 4 additions & 2 deletions packages/react-data-grid/src/Cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,12 @@ class Cell extends React.Component {
if (this.props.isScrolling && !this.props.cellMetaData.isScrollingVerticallyWithKeyboard && !this.props.cellMetaData.isScrollingHorizontallyWithKeyboard) {
return;
}
// Only focus to the current cell if the currently active node in the document is within the data grid.
// If the enableCellAutoFocus is set in the ReactDataGrid props, it will allow the cell to take focus when the browser is focused on the body.
// Otherwise, only focus to the current cell if the currently active node in the document is within the data grid.
// Meaning focus should not be stolen from elements that the grid doesnt control.
const cellAutoFocusEnabled = this.props.cellMetaData && this.props.cellMetaData.enableCellAutoFocus;
let dataGridDOMNode = this.props.cellMetaData && this.props.cellMetaData.getDataGridDOMNode ? this.props.cellMetaData.getDataGridDOMNode() : null;
if (this.isFocusedOnCell() || this.isFocusedOnBody() || (dataGridDOMNode && dataGridDOMNode.contains(document.activeElement))) {
if (this.isFocusedOnCell() || (cellAutoFocusEnabled && this.isFocusedOnBody()) || (dataGridDOMNode && dataGridDOMNode.contains(document.activeElement))) {
let cellDOMNode = this.node;
if (cellDOMNode) {
cellDOMNode.focus();
Expand Down
9 changes: 6 additions & 3 deletions packages/react-data-grid/src/ReactDataGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ const ReactDataGrid = createReactClass({
/* called before cell is set active, returns a boolean to determine whether cell is editable */
overScan: PropTypes.object,
onDeleteSubRow: PropTypes.func,
onAddSubRow: PropTypes.func
onAddSubRow: PropTypes.func,
enableCellAutoFocus: PropTypes.bool
},

getDefaultProps(): {enableCellSelect: boolean} {
Expand All @@ -135,7 +136,8 @@ const ReactDataGrid = createReactClass({
colsEnd: 5,
rowsStart: 5,
rowsEnd: 5
}
},
enableCellAutoFocus: true
};
},

Expand Down Expand Up @@ -931,7 +933,8 @@ const ReactDataGrid = createReactClass({
onDeleteSubRow: this.props.onDeleteSubRow,
onAddSubRow: this.props.onAddSubRow,
isScrollingVerticallyWithKeyboard: this.isKeyDown(KeyCodes.DownArrow) || this.isKeyDown(KeyCodes.UpArrow),
isScrollingHorizontallyWithKeyboard: this.isKeyDown(KeyCodes.LeftArrow) || this.isKeyDown(KeyCodes.RightArrow) || this.isKeyDown(KeyCodes.Tab)
isScrollingHorizontallyWithKeyboard: this.isKeyDown(KeyCodes.LeftArrow) || this.isKeyDown(KeyCodes.RightArrow) || this.isKeyDown(KeyCodes.Tab),
enableCellAutoFocus: this.props.enableCellAutoFocus
};

let toolbar = this.renderToolbar();
Expand Down
63 changes: 63 additions & 0 deletions packages/react-data-grid/src/__tests__/Cell.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,69 @@ describe('Cell Tests', () => {
});
});

describe('Cell checkFocus', () => {
const renderCellComponent = (props) => {
const wrapper = mount(<Cell {...props} />);
return wrapper;
};
describe('when the cell is selected but not active and the grid is not scrolling', () => {
const getProps = ({
enableCellAutoFocus = true,
getDataGridDOMNode = () => ({})
}) => ({
column: helpers.columns[0],
isScrolling: false,
cellMetaData: {
selected: { rowIdx: 1, idx: 1 },
active: false,
enableCellAutoFocus
},
getDataGridDOMNode,
rowIdx: 1,
idx: 1,
value: 'value'
});
describe('when enableCellAutoFocus is set to true', () => {
const enableCellAutoFocus = true;
it('focuses on the cell when document has no active element', () => {
const enzymeWrapper = renderCellComponent(getProps({ enableCellAutoFocus }));
spyOn(document, 'activeElement').and.returnValue(null);
const cellDiv = enzymeWrapper.find('div').at(0).node;
spyOn(cellDiv, 'focus');
enzymeWrapper.instance().checkFocus();
expect(cellDiv.focus).toHaveBeenCalled();
});
it('focuses on the cell when document is focused on body and cell autofocus is enabled', () => {
const enzymeWrapper = renderCellComponent(getProps({ enableCellAutoFocus }));
spyOn(document, 'activeElement').and.returnValue({ nodeName: 'body' });
const cellDiv = enzymeWrapper.find('div').at(0).node;
spyOn(cellDiv, 'focus');
enzymeWrapper.instance().checkFocus();
expect(cellDiv.focus).toHaveBeenCalled();
});
});
describe('when enableCellAutoFocus is set to false', () => {
const enableCellAutoFocus = false;
it('does not focus on the cell when document has no active element', () => {
const enzymeWrapper = renderCellComponent(getProps({ enableCellAutoFocus }));
spyOn(document, 'activeElement').and.returnValue(null);
const cellDiv = enzymeWrapper.find('div').at(0).node;
spyOn(cellDiv, 'focus');
enzymeWrapper.instance().checkFocus();
expect(cellDiv.focus).not.toHaveBeenCalled();
});
it('does not focus on the cell when document is focused on body and cell autofocus is enabled', () => {
const enzymeWrapper = renderCellComponent(getProps({ enableCellAutoFocus }));
spyOn(document, 'activeElement').and.returnValue({ nodeName: 'body' });
const cellDiv = enzymeWrapper.find('div').at(0).node;
spyOn(cellDiv, 'focus');
enzymeWrapper.instance().checkFocus();
expect(cellDiv.focus).not.toHaveBeenCalled();
});
});
});
});

describe('Rendering Cell component', () => {
const shallowRenderComponent = (props) => {
const wrapper = shallow(<Cell {...props} />);
Expand Down
35 changes: 35 additions & 0 deletions packages/react-data-grid/src/__tests__/ReactDataGrid.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
import React from 'react';
import ReactDataGrid from '../ReactDataGrid';
import { shallow } from 'enzyme';
import * as helpers from '../helpers/test/GridPropHelpers';

function shallowRenderGrid({
enableCellAutoFocus = undefined
}) {
const enzymeWrapper = shallow(<ReactDataGrid
columns={helpers.columns}
rowGetter={helpers.rowGetter}
rowsCount={helpers.rowsCount()}
enableCellSelect
enableCellAutoFocus={enableCellAutoFocus}
/>);
return {
enzymeWrapper
};
}

describe('configure enableCellAutoFocus property', () => {
it('passes enableCellAutoFocus property in the Grid cellMetaData', () => {
const enableCellAutoFocus = true;
const { enzymeWrapper } = shallowRenderGrid({ enableCellAutoFocus });
expect(enzymeWrapper.find('Grid').props().cellMetaData.enableCellAutoFocus).toEqual(enableCellAutoFocus);
});
it('sets enableCellAutoFocus to true by default', () => {
const { enzymeWrapper } = shallowRenderGrid({});
expect(enzymeWrapper.find('Grid').props().cellMetaData.enableCellAutoFocus).toBe(true);
});
it('sets enableCellAutoFocus to false if it is configured', () => {
const { enzymeWrapper } = shallowRenderGrid({ enableCellAutoFocus: false });
expect(enzymeWrapper.find('Grid').props().cellMetaData.enableCellAutoFocus).toBe(false);
});
});

//
// var testProps = {
Expand Down

0 comments on commit 3dbc315

Please sign in to comment.