Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScrollableInkTabBar support render props to customize tab node #160

Merged
merged 3 commits into from
Jan 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ scrollable tab bar, in addition to tab bar props, extra props:

scrollable tab bar with ink indicator, same with tab bar and ink bar and scrollable bar props.

| name | type | default | description |
|------|------|---------|-------------|
| children | (node) => node | - | Customize tab bar node |

### lib/SwipeableInkTabBar (Use for Mobile)

swipeable tab bar with ink indicator, same with tab bar/ink bar props, and below is the additional props.
Expand Down
2 changes: 0 additions & 2 deletions examples/activeKey.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint react/no-multi-comp:0, no-console:0, react/prop-types:0 */
import 'rc-tabs/assets/index.less';
import React from 'react';
import Sortable from 'react-sortablejs';
import ReactDOM from 'react-dom';
import Tabs, { TabPane } from 'rc-tabs';
import TabContent from 'rc-tabs/lib/SwipeableTabContent';
Expand Down Expand Up @@ -53,7 +52,6 @@ class Demo extends React.Component {
<Tabs
renderTabBar={() => <ScrollableInkTabBar onTabClick={this.onTabClick}/>}
renderTabContent={() => <TabContent animatedWithMargin />}
navWrapper={(content) => <Sortable>{content}</Sortable>}
activeKey={this.state.activeKey}
onChange={this.onChange}
>
Expand Down
1 change: 1 addition & 0 deletions examples/dnd.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
placeholder
141 changes: 141 additions & 0 deletions examples/dnd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/* eslint react/no-multi-comp:0, no-console:0, react/prop-types:0 */
import 'rc-tabs/assets/index.less';
import React from 'react';
import HTML5Backend from 'react-dnd-html5-backend'
import ReactDOM from 'react-dom';
import Tabs, { TabPane } from 'rc-tabs';
import update from 'immutability-helper';
import TabContent from 'rc-tabs/lib/SwipeableTabContent';
import ScrollableInkTabBar from 'rc-tabs/lib/ScrollableInkTabBar';
import {
DragSource,
DropTarget,
DragDropContextProvider,
} from 'react-dnd';

// Drag & Drop node
class TabNode extends React.Component {
render() {
const {
connectDragSource,
connectDropTarget,
children,
} = this.props

return connectDragSource(
connectDropTarget(children),
);
}
}

const cardTarget = {
drop(props, monitor) {
const dragKey = monitor.getItem().index;
const hoverKey = props.index;

if (dragKey === hoverKey) {
return;
}

props.moveTabNode(dragKey, hoverKey);
monitor.getItem().index = hoverKey;
},
};

const cardSource = {
beginDrag(props) {
return {
id: props.id,
index: props.index,
}
},
};

const WrapTabNode = DropTarget(
'DND_NODE',
cardTarget,
(connect) => ({
connectDropTarget: connect.dropTarget(),
}),
)(
DragSource(
'DND_NODE',
cardSource,
(connect, monitor) => ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
}),
)(TabNode),
);

// Demo
class Demo extends React.Component {
state = {
activeKey: '1',
tabs: ['1', '2', '3'],
};

onChange = (activeKey) => {
console.log(`onChange ${activeKey}`);
this.setState({
activeKey,
});
}

onTabClick = (key) => {
console.log(`onTabClick ${key}`);
if (key === this.state.activeKey) {
this.setState({
activeKey: '',
});
}
}

moveTabNode = (dragKey, hoverKey) => {
const { tabs } = this.state;
const dragIndex = tabs.indexOf(dragKey);
const hoverIndex = tabs.indexOf(hoverKey);
const dragTab = this.state.tabs[dragIndex];
this.setState(
update(this.state, {
tabs: {
$splice: [[dragIndex, 1], [hoverIndex, 0, dragTab]],
},
}),
);
};

renderTabBarNode = (node) => {
return (
<WrapTabNode key={node.key} index={node.key} moveTabNode={this.moveTabNode}>{node}</WrapTabNode>
);
};

render() {
return (
<DragDropContextProvider backend={HTML5Backend}>
<div style={{ margin: 20 }}>
<h1>Simple Tabs</h1>
<Tabs
renderTabBar={() => (
<ScrollableInkTabBar onTabClick={this.onTabClick}>
{this.renderTabBarNode}
</ScrollableInkTabBar>
)}
renderTabContent={() => <TabContent animatedWithMargin />}
activeKey={this.state.activeKey}
onChange={this.onChange}
>
{this.state.tabs.map(id => (
<TabPane tab={`tab ${id}`} key={id}>
{id}
</TabPane>
))}
</Tabs>
</div>
</DragDropContextProvider>
);
}
}

ReactDOM.render(<Demo />, document.getElementById('__react-content'));
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,18 @@
"enzyme-to-json": "^3.3.4",
"fastclick": "~1.0.6",
"history": "^1.17.0",
"immutability-helper": "^2.9.0",
"jest": "^23.6.0",
"pre-commit": "1.x",
"preact": "^8.2.1",
"preact-compat": "^3.16.0",
"rc-test": "^6.0.1",
"rc-tools": "8.x",
"react": "^16.0.0",
"react-dnd": "^7.0.2",
"react-dnd-html5-backend": "^7.0.2",
"react-dom": "^16.0.0",
"react-router": "^3.0.0",
"react-sortablejs": "^1.3.6",
"react-test-renderer": "^16.0.0",
"sortablejs": "^1.7.0"
},
Expand Down
15 changes: 11 additions & 4 deletions src/ScrollableInkTabBar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable react/prefer-stateless-function */
import React from 'react';
import PropTypes from 'prop-types';
import InkTabBarNode from './InkTabBarNode';
import TabBarTabsNode from './TabBarTabsNode';
import TabBarRootNode from './TabBarRootNode';
Expand All @@ -8,17 +9,23 @@ import SaveRef from './SaveRef';

export default class ScrollableInkTabBar extends React.Component {
render() {
const { children: renderTabBarNode, ...restProps } = this.props;

return (
<SaveRef>
{(saveRef, getRef) => (
<TabBarRootNode saveRef={saveRef} {...this.props}>
<ScrollableTabBarNode saveRef={saveRef} getRef={getRef} {...this.props}>
<TabBarTabsNode saveRef={saveRef} {...this.props} />
<InkTabBarNode saveRef={saveRef} getRef={getRef} {...this.props} />
<TabBarRootNode saveRef={saveRef} {...restProps}>
<ScrollableTabBarNode saveRef={saveRef} getRef={getRef} {...restProps}>
<TabBarTabsNode saveRef={saveRef} renderTabBarNode={renderTabBarNode} {...restProps} />
<InkTabBarNode saveRef={saveRef} getRef={getRef} {...restProps} />
</ScrollableTabBarNode>
</TabBarRootNode>
)}
</SaveRef>
);
}
}

ScrollableInkTabBar.propTypes = {
children: PropTypes.func,
};
1 change: 1 addition & 0 deletions src/ScrollableTabBarNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ export default class ScrollableTabBarNode extends React.Component {
}

ScrollableTabBarNode.propTypes = {
activeKey: PropTypes.string,
getRef: PropTypes.func.isRequired,
saveRef: PropTypes.func.isRequired,
tabBarPosition: PropTypes.oneOf(['left', 'right', 'top', 'bottom']),
Expand Down
11 changes: 10 additions & 1 deletion src/TabBarTabsNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default class TabBarTabsNode extends React.Component {
tabBarGutter,
saveRef,
tabBarPosition,
renderTabBarNode,
} = this.props;
const rst = [];

Expand Down Expand Up @@ -40,7 +41,8 @@ export default class TabBarTabsNode extends React.Component {
[isVertical(tabBarPosition) ? 'marginBottom' : 'marginRight']: gutter,
};
warning('tab' in child.props, 'There must be `tab` property on children of Tabs.');
rst.push(

let node = (
<div
role="tab"
aria-disabled={child.props.disabled ? 'true' : 'false'}
Expand All @@ -54,6 +56,12 @@ export default class TabBarTabsNode extends React.Component {
{child.props.tab}
</div>
);

if (renderTabBarNode) {
node = renderTabBarNode(node);
}

rst.push(node);
});

return (
Expand All @@ -71,6 +79,7 @@ TabBarTabsNode.propTypes = {
tabBarGutter: PropTypes.number,
onTabClick: PropTypes.func,
saveRef: PropTypes.func,
renderTabBarNode: PropTypes.func,
tabBarPosition: PropTypes.string,
};

Expand Down
8 changes: 4 additions & 4 deletions tests/__snapshots__/index.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ exports[`rc-tabs should render Tabs with correct DOM structure 1`] = `
</div>
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
<div
Expand All @@ -92,13 +92,13 @@ exports[`rc-tabs should render Tabs with correct DOM structure 1`] = `
>
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
second
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
</div>
Expand All @@ -110,7 +110,7 @@ exports[`rc-tabs should render Tabs with correct DOM structure 1`] = `
</div>
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
</div>
Expand Down
8 changes: 4 additions & 4 deletions tests/__snapshots__/swipe.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ exports[`rc-swipeable-tabs should render Slider with correct DOM structure 1`] =
</div>
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
<div
Expand Down Expand Up @@ -187,7 +187,7 @@ exports[`rc-swipeable-tabs should render Slider with correct DOM structure 1`] =
>
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
<div
Expand All @@ -197,7 +197,7 @@ exports[`rc-swipeable-tabs should render Slider with correct DOM structure 1`] =
</div>
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
</div>
Expand All @@ -214,7 +214,7 @@ exports[`rc-swipeable-tabs should render Slider with correct DOM structure 1`] =
</div>
<div
role="presentation"
style="width:0;height:0;overflow:hidden"
style="width:0;height:0;overflow:hidden;position:absolute"
tabindex="0"
/>
</div>
Expand Down