-
Notifications
You must be signed in to change notification settings - Fork 227
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3eb8a4b
commit 731e980
Showing
17 changed files
with
770 additions
and
109 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
index.js |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# React Tab Bar | ||
|
||
A React version of an [MDC Tab Bar](https://github.com/material-components/material-components-web/tree/master/packages/mdc-tab-bar). | ||
|
||
## Installation | ||
|
||
``` | ||
npm install @material/react-tab-bar | ||
``` | ||
|
||
## Usage | ||
|
||
### Styles | ||
|
||
with Sass: | ||
```scss | ||
import '@material/react-tab-bar/index.scss'; | ||
``` | ||
|
||
with CSS: | ||
```css | ||
import '@material/react-tab-bar/dist/tab-bar.css'; | ||
``` | ||
|
||
### Javascript Instantiation | ||
|
||
```js | ||
import React from 'react'; | ||
import Tab from '@material/react-tab'; | ||
import TabBar from '@material/react-tab-bar'; | ||
|
||
class MyApp extends React.Component { | ||
state = {activeIndex: 0}; | ||
|
||
render() { | ||
return ( | ||
<div> | ||
<TabBar | ||
activeIndex={this.state.activeIndex} | ||
handleActiveIndexUpdate={(activeIndex) => this.setState({activeIndex})} | ||
> | ||
<Tab> | ||
<span className='mdc-tab__text-label'>One</span> | ||
</Tab> | ||
... | ||
</TabBar> | ||
</div> | ||
); | ||
} | ||
} | ||
``` | ||
|
||
> _NOTE_: You can also use a custom tab component with the `TabBar`, but it must implement the methods `activate`, `deactivate`, `focus`, `computeIndicatorClientRect`, and `computeDimensions`. See [`MDCTab` documentation](https://github.com/material-components/material-components-web/blob/master/packages/mdc-tab/README.md#mdctab-properties-and-methods) for more details. | ||
## Props | ||
|
||
Prop Name | Type | Description | ||
--- | --- | --- | ||
activeIndex | number | Index of the active tab. | ||
indexInView | number | Index of the tab to be scrolled into view. | ||
handleActiveIndexUpdate | Function(activeIndex: number) => void | Callback after the active index is updated. | ||
className | string | Classes to appear on className attribute of root element. | ||
isRtl | Boolean | Whether the direction of the tab bar is RTL. | ||
|
||
## Sass Mixins | ||
|
||
Sass mixins may be available to customize various aspects of the components. Please refer to the | ||
MDC Web repository for more information on what mixins are available, and how to use them. | ||
|
||
[Advanced Sass Mixins](https://github.com/material-components/material-components-web/blob/master/packages/mdc-tab-bar/README.md#sass-mixins) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
import React, {Component} from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import classnames from 'classnames'; | ||
|
||
import TabScroller from '@material/react-tab-scroller'; | ||
import {MDCTabBarFoundation} from '@material/tab-bar/dist/mdc.tabBar'; | ||
|
||
export default class TabBar extends Component { | ||
tabBarElement_ = React.createRef(); | ||
tabScroller_ = React.createRef(); | ||
tabList_ = []; | ||
|
||
foundation_ = null; | ||
state = { | ||
previousActiveIndex: -1, | ||
} | ||
|
||
componentDidMount() { | ||
this.foundation_ = new MDCTabBarFoundation(this.adapter); | ||
this.foundation_.init(); | ||
|
||
const { | ||
activeIndex, | ||
indexInView, | ||
} = this.props; | ||
if (this.tabList_[activeIndex]) { | ||
this.tabList_[activeIndex].activate({} /* previousIndicatorClientRect */); | ||
} | ||
this.foundation_.scrollIntoView(indexInView); | ||
} | ||
|
||
componentDidUpdate(prevProps) { | ||
if (this.props.activeIndex !== prevProps.activeIndex) { | ||
this.foundation_.activateTab(this.props.activeIndex); | ||
} | ||
if (this.props.indexInView !== prevProps.indexInView) { | ||
this.foundation_.scrollIntoView(this.props.indexInView); | ||
} | ||
} | ||
|
||
componentWillUnmount() { | ||
this.foundation_.destroy(); | ||
} | ||
|
||
get classes() { | ||
return classnames('mdc-tab-bar', this.props.className); | ||
} | ||
|
||
get adapter() { | ||
return { | ||
scrollTo: (scrollX) => this.tabScroller_.current.scrollTo(scrollX), | ||
incrementScroll: (scrollXIncrement) => this.tabScroller_.current.incrementScroll(scrollXIncrement), | ||
getScrollPosition: () => this.tabScroller_.current.getScrollPosition(), | ||
getScrollContentWidth: () => this.tabScroller_.current.getScrollContentWidth(), | ||
getOffsetWidth: () => this.tabBarElement_.current.offsetWidth, | ||
isRTL: () => !!this.props.isRtl, | ||
setActiveTab: (index) => this.props.handleActiveIndexUpdate(index), | ||
activateTabAtIndex: (index, clientRect) => this.tabList_[index].activate(clientRect), | ||
deactivateTabAtIndex: (index) => this.tabList_[index].deactivate(), | ||
focusTabAtIndex: (index) => this.tabList_[index].focus(), | ||
getTabIndicatorClientRectAtIndex: (index) => this.tabList_[index].computeIndicatorClientRect(), | ||
getTabDimensionsAtIndex: (index) => this.tabList_[index].computeDimensions(), | ||
getPreviousActiveTabIndex: () => this.state.previousActiveIndex, | ||
getFocusedTabIndex: () => { | ||
const activeElement = document.activeElement; | ||
this.tabList_.forEach((tabList, index) => { | ||
if (tabList.tabElement_.current === activeElement) { | ||
return index; | ||
} | ||
}); | ||
}, | ||
getIndexOfTab: (tabToFind) => this.tabList_.indexOf(tabToFind), | ||
getTabListLength: () => this.tabList_.length, | ||
}; | ||
} | ||
|
||
pushToTabList = (el) => { | ||
this.tabList_.push(el); | ||
} | ||
|
||
onKeyDown = (e) => { | ||
// Persist the synthetic event to access its `key`. | ||
e.persist(); | ||
this.setState( | ||
{previousActiveIndex: this.props.activeIndex}, | ||
() => this.foundation_.handleKeyDown(e)); | ||
this.props.onKeyDown(e); | ||
} | ||
|
||
render() { | ||
const { | ||
/* eslint-disable no-unused-vars */ | ||
className, | ||
indexInView, | ||
activeIndex, | ||
handleActiveIndexUpdate, | ||
onKeyDown, | ||
/* eslint-enable no-unused-vars */ | ||
isRtl, | ||
children, | ||
...otherProps | ||
} = this.props; | ||
|
||
return ( | ||
<div | ||
dir={isRtl ? 'rtl' : 'ltr'} | ||
className={this.classes} | ||
role='tablist' | ||
onKeyDown={this.onKeyDown} | ||
ref={this.tabBarElement_} | ||
{...otherProps} | ||
> | ||
<TabScroller ref={this.tabScroller_}> | ||
{React.Children.map(children, this.renderTab)} | ||
</TabScroller> | ||
</div> | ||
); | ||
} | ||
|
||
renderTab = (tab, index) => { | ||
const { | ||
children, | ||
onClick, // eslint-disable-line no-unused-vars | ||
...otherProps | ||
} = tab.props; | ||
|
||
const props = { | ||
onClick: (e) => { | ||
this.setState( | ||
{previousActiveIndex: this.props.activeIndex}, | ||
() => this.adapter.setActiveTab(index)); | ||
this.props.onClick(e); | ||
}, | ||
ref: this.pushToTabList, | ||
...otherProps, | ||
}; | ||
|
||
return React.cloneElement(tab, props, children); | ||
} | ||
} | ||
|
||
TabBar.propTypes = { | ||
indexInView: PropTypes.number, | ||
activeIndex: PropTypes.number, | ||
handleActiveIndexUpdate: PropTypes.func, | ||
className: PropTypes.string, | ||
children: PropTypes.oneOfType([ | ||
PropTypes.arrayOf(PropTypes.element), | ||
PropTypes.element, | ||
]), | ||
onClick: PropTypes.func, | ||
onKeyDown: PropTypes.func, | ||
isRtl: PropTypes.bool, | ||
}; | ||
|
||
TabBar.defaultProps = { | ||
indexInView: 0, | ||
activeIndex: 0, | ||
handleActiveIndexUpdate: () => {}, | ||
className: '', | ||
children: [], | ||
onClick: () => {}, | ||
onKeyDown: () => {}, | ||
isRtl: false, | ||
}; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@import "@material/tab-bar/mdc-tab-bar"; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"name": "@material/react-tab-bar", | ||
"version": "0.0.0", | ||
"description": "Material Components React Tab Bar", | ||
"license": "Apache-2.0", | ||
"main": "dist/index.js", | ||
"keywords": [ | ||
"mdc web react", | ||
"material components react", | ||
"material design", | ||
"tab bar", | ||
"tabbar", | ||
"tabs" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/material-components/material-components-web-react.git" | ||
}, | ||
"dependencies": { | ||
"@material/react-tab-scroller": "^0.0.0", | ||
"@material/tab-bar": "^0.39.0", | ||
"classnames": "^2.2.5", | ||
"prop-types": "^15.6.1", | ||
"react": "^16.3.2" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
Oops, something went wrong.