Last active
August 8, 2016 10:30
-
-
Save ahomu/3c4b0c53250147cc3d8dc766b08d4be3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const KEYCODE_LEFT = 37; | |
const KEYCODE_RIGHT = 39; | |
class TabList extends React.Component { | |
static propTypes = { | |
children : React.PropTypes.node, | |
selectedIndex : React.PropTypes.number, | |
onChangeSelected: React.PropTypes.func | |
}; | |
onClickTab(i) { | |
this.props.onChangeSelected(i); | |
} | |
onMoveFocus(e) { | |
const { selectedIndex } = this.props; | |
let nextIndex; | |
switch(e.keyCode) { | |
case KEYCODE_LEFT: | |
if (selectedIndex !== 0) { | |
nextIndex = selectedIndex - 1; | |
this.props.onChangeSelected(nextIndex); | |
} | |
break; | |
case KEYCODE_RIGHT: | |
if (selectedIndex !== this.props.children.length - 1) { | |
nextIndex = selectedIndex + 1; | |
this.props.onChangeSelected(nextIndex); | |
} | |
break; | |
} | |
if (nextIndex != null) { | |
this.refs[`tab${nextIndex}`].setFocus(); | |
} | |
} | |
render() { | |
const { selectedIndex, onClickTab, onMoveFocus } = this.props; | |
return ( | |
<ul role="tablist"> | |
{this.props.children.map((child, i) => { | |
return React.cloneElement(child, { | |
ref : `tab${i}`, | |
selected : selectedIndex === i, | |
onClickTab : this.onClickTab.bind(this, i), | |
onMoveFocus: this.onMoveFocus.bind(this) | |
}); | |
})} | |
</ul> | |
); | |
} | |
} | |
class Tab extends React.Component { | |
static propTypes = { | |
controlsFor: React.PropTypes.string, | |
children : React.PropTypes.node, | |
selected : React.PropTypes.bool, | |
onMoveFocus: React.PropTypes.func, | |
onClickTab : React.PropTypes.func | |
}; | |
setFocus() { | |
this.refs.tab.focus(); | |
} | |
render() { | |
const { selected, controlsFor } = this.props; | |
return ( | |
<li role="presentation"> | |
<button | |
ref="tab" | |
role="tab" | |
tabIndex={selected ? '0' : '-1'} | |
aria-selected={selected ? 'true' : 'false'} | |
aria-controls={controlsFor} | |
onKeyUp={this.props.onMoveFocus} | |
onClick={this.props.onClickTab}> | |
{this.props.children} | |
</button> | |
</li> | |
); | |
} | |
} | |
class TabPanel extends React.Component { | |
static propTypes = { | |
id : React.PropTypes.string, | |
selected: React.PropTypes.bool | |
}; | |
static defaultProps = { | |
selected: false | |
}; | |
render() { | |
const { id, selected } = this.props; | |
return ( | |
<div role="tabpanel" id={id} aria-hidden={selected ? 'false' : 'true'}> | |
{this.props.children} | |
</div> | |
); | |
} | |
} | |
class Container extends React.Component { | |
state = { | |
selectedIndex: 0 | |
}; | |
onChangeSelected(index) { | |
this.setState({ | |
selectedIndex: index | |
}); | |
} | |
render() { | |
const { selectedIndex } = this.state; | |
return ( | |
<div> | |
<TabList | |
selectedIndex={selectedIndex} | |
onChangeSelected={this.onChangeSelected.bind(this)}> | |
<Tab controlsFor="foo">1st Panel</Tab> | |
<Tab controlsFor="bar">2nd Panel</Tab> | |
<Tab controlsFor="baz">3rd Panale</Tab> | |
</TabList> | |
<TabPanel id="foo" selected={selectedIndex === 0}> | |
<h2>1st Panel</h2> | |
<ul> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
</ul> | |
</TabPanel> | |
<TabPanel id="bar" selected={selectedIndex === 1}> | |
<h2>2nd Panel</h2> | |
<ul> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
</ul> | |
</TabPanel> | |
<TabPanel id="baz" selected={selectedIndex === 2}> | |
<h2>3rd Panel</h2> | |
<ul> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
<li><a href="http://example.com" target="_blank">example.com</a></li> | |
</ul> | |
</TabPanel> | |
</div> | |
); | |
} | |
} | |
ReactDOM.render(<Container />, document.getElementById('example')); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div data-reactroot=""> | |
<ul role="tablist"> | |
<li role="presentation"> | |
<button role="tab" tabindex="0" aria-selected="true" aria-controls="foo">1st Panel</button> | |
</li> | |
<li role="presentation"> | |
<button role="tab" tabindex="-1" aria-selected="false" aria-controls="bar">2nd Panel</button> | |
</li> | |
<li role="presentation"> | |
<button role="tab" tabindex="-1" aria-selected="false" aria-controls="baz">3rd Panale</button> | |
</li> | |
</ul> | |
<div role="tabpanel" id="foo" aria-hidden="false"> | |
<h2>1st Panel</h2> | |
<ul> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
</ul> | |
</div> | |
<div role="tabpanel" id="bar" aria-hidden="true"> | |
<h2>2nd Panel</h2> | |
<ul> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
</ul> | |
</div> | |
<div role="tabpanel" id="baz" aria-hidden="true"> | |
<h2>3rd Panel</h2> | |
<ul> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
<li><a href="http://example.com" target="_blank">example.com</a> | |
</li> | |
</ul> | |
</div> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment