Skip to content
This repository has been archived by the owner on Mar 27, 2019. It is now read-only.

Commit

Permalink
ArrowKeyNavigation prop review & light refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan Scott committed Feb 1, 2017
1 parent 08c7a72 commit 52dbc1e
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 31 deletions.
2 changes: 1 addition & 1 deletion packages/boundless-arrow-key-navigation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ There are no required props.
- | -
`string or function` | `'div'`

- __`defaultActiveChildIndex`__ ・ allows for a particular child to be initially reachable via tabbing
- __`defaultActiveChildIndex`__ ・ allows for a particular child to be initially reachable via tabbing; only applied during first render

Expects | Default Value
- | -
Expand Down
46 changes: 22 additions & 24 deletions packages/boundless-arrow-key-navigation/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React, {PropTypes} from 'react';
import React, {Children, PropTypes} from 'react';
import {findDOMNode} from 'react-dom';

import omit from 'boundless-utils-omit-keys';
import uuid from 'boundless-utils-uuid';

const DATA_ATTRIBUTE_INDEX = 'data-focus-index';
const DATA_ATTRIBUTE_SKIP = 'data-focus-skip';

/**
__A higher-order component for arrow key navigation on a grouping of children.__
Expand All @@ -28,7 +31,7 @@ export default class ArrowKeyNavigation extends React.PureComponent {
]),

/**
Allows for a particular child to be initially reachable via tabbing
Allows for a particular child to be initially reachable via tabbing; only applied during first render
*/
defaultActiveChildIndex: PropTypes.number,

Expand Down Expand Up @@ -71,9 +74,7 @@ export default class ArrowKeyNavigation extends React.PureComponent {

componentWillReceiveProps(nextProps) {
if (this.state.activeChildIndex !== 0) {
const numChildren = nextProps.children
? React.Children.count(nextProps.children)
: 0;
const numChildren = nextProps.children ? Children.count(nextProps.children) : 0;

if (numChildren === 0) {
this.setState({activeChildIndex: 0});
Expand All @@ -84,13 +85,9 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}

setFocus(index) {
const childNode = (
this.refs.wrapper instanceof HTMLElement
? this.refs.wrapper
: findDOMNode(this.refs.wrapper)
).children[index];
const childNode = this.$wrapper.children[index];

if (childNode && childNode.hasAttribute('data-skip')) {
if (childNode && childNode.hasAttribute(DATA_ATTRIBUTE_SKIP)) {
this.moveFocus(
childNode.compareDocumentPosition(document.activeElement) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
);
Expand All @@ -100,10 +97,7 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}

moveFocus(delta) {
const numChildren = this.props.children
? React.Children.count(this.props.children)
: 0;

const numChildren = this.props.children ? Children.count(this.props.children) : 0;
let nextIndex = this.state.activeChildIndex + delta;

if (nextIndex >= numChildren) {
Expand Down Expand Up @@ -160,9 +154,9 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}

handleFocus = (event) => {
if (event.target.hasAttribute('data-focus-index')) {
const index = parseInt(event.target.getAttribute('data-focus-index'), 10);
const child = React.Children.toArray(this.props.children)[index];
if (event.target.hasAttribute(DATA_ATTRIBUTE_INDEX)) {
const index = parseInt(event.target.getAttribute(DATA_ATTRIBUTE_INDEX), 10);
const child = Children.toArray(this.props.children)[index];

this.setState({activeChildIndex: index});

Expand All @@ -172,25 +166,29 @@ export default class ArrowKeyNavigation extends React.PureComponent {
}
}

children() {
return React.Children.map(this.props.children, (child, index) => {
renderChildren() {
return Children.map(this.props.children, (child, index) => {
return React.cloneElement(child, {
'data-focus-index': index,
'data-skip': parseInt(child.props.tabIndex, 10) === -1 || undefined,
[DATA_ATTRIBUTE_INDEX]: index,
[DATA_ATTRIBUTE_SKIP]: parseInt(child.props.tabIndex, 10) === -1 || undefined,
key: child.key || index,
tabIndex: this.state.activeChildIndex === index ? 0 : -1,
});
});
}

persistWrapperElementReference = (unknownType) => {
this.$wrapper = unknownType instanceof HTMLElement ? unknownType : findDOMNode(unknownType);
}

render() {
return (
<this.props.component
{...omit(this.props, ArrowKeyNavigation.internalKeys)}
ref='wrapper'
ref={this.persistWrapperElementReference}
onFocus={this.handleFocus}
onKeyDown={this.handleKeyDown}>
{this.children()}
{this.renderChildren()}
</this.props.component>
);
}
Expand Down
12 changes: 6 additions & 6 deletions packages/boundless-arrow-key-navigation/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('ArrowKeyNavigation higher-order component', () => {

beforeEach(() => {
element = render(base);
node = element.refs.wrapper;
node = ReactDOM.findDOMNode(element);
});

afterEach(() => ReactDOM.unmountComponentAtNode(mountNode));
Expand Down Expand Up @@ -78,7 +78,7 @@ describe('ArrowKeyNavigation higher-order component', () => {
</ArrowKeyNavigation>
);

node = element.refs.wrapper;
node = ReactDOM.findDOMNode(element);

expect(node.querySelector('[data-focus-index="1"][tabindex="0"]')).not.toBeNull();
});
Expand Down Expand Up @@ -242,7 +242,7 @@ describe('ArrowKeyNavigation higher-order component', () => {
</ArrowKeyNavigation>
);

node = element.refs.wrapper;
node = ReactDOM.findDOMNode(element);
});

it('moves focus to the next child that does not have tabindex="-1"', () => {
Expand Down Expand Up @@ -270,7 +270,7 @@ describe('ArrowKeyNavigation higher-order component', () => {

beforeEach(() => {
element = render(verticalBase);
node = element.refs.wrapper;
node = ReactDOM.findDOMNode(element);
});

it('should not move focus on ArrowLeft', () => {
Expand Down Expand Up @@ -298,7 +298,7 @@ describe('ArrowKeyNavigation higher-order component', () => {

beforeEach(() => {
element = render(horizontalBase);
node = element.refs.wrapper;
node = ReactDOM.findDOMNode(element);
});

it('should not move focus on ArrowUp', () => {
Expand Down Expand Up @@ -326,7 +326,7 @@ describe('ArrowKeyNavigation higher-order component', () => {

beforeEach(() => {
element = render(horizontalBase);
node = element.refs.wrapper;
node = ReactDOM.findDOMNode(element);
});

it('should move focus on ArrowUp', () => {
Expand Down

0 comments on commit 52dbc1e

Please sign in to comment.