UNPKG

7.42 kBJavaScriptView Raw
1/**
2* This source code is quoted from rc-tabs.
3* homepage: https://github.com/react-component/tabs
4*/
5import React from "react";
6import KeyCode from "./KeyCode";
7import TabPane from "./TabPane";
8import classnames from "classnames";
9import TabContent from "./TabContent";
10import ScrollableInkTabBar from "./ScrollableInkTabBar";
11import PropTypes from 'prop-types';
12import createClass from 'create-react-class';
13import Icon from 'bee-icon';
14
15function noop() {}
16
17function getDefaultActiveKey(props) {
18 let activeKey;
19 React.Children.forEach(props.children, child => {
20 if (child && !activeKey && !child.props.disabled) {
21 activeKey = child.key;
22 }
23 });
24 return activeKey;
25}
26
27const Tabs = createClass({
28 propTypes: {
29 destroyInactiveTabPane: PropTypes.bool,
30 renderTabBar: PropTypes.func.isRequired,
31 renderTabContent: PropTypes.func.isRequired,
32 onChange: PropTypes.func,
33 children: PropTypes.any,
34 clsPrefix: PropTypes.string,
35 className: PropTypes.string,
36 tabBarPosition: PropTypes.string,
37 style: PropTypes.object,
38 tabBarStyle: PropTypes.oneOf([
39 "simple",
40 "fill",
41 "primary",
42 "upborder",
43 "fade",
44 "downborder",
45 "trapezoid",
46 "editable-card"
47 ])
48 },
49
50 getDefaultProps() {
51 return {
52 clsPrefix: "u-tabs",
53 destroyInactiveTabPane: false,
54 onChange: noop,
55 tabBarPosition: "top",
56 style: {},
57 renderTabContent: () => <TabContent />,
58 renderTabBar: () => <ScrollableInkTabBar />,
59 tabBarStyle: "simple",
60 animated: true
61 };
62 },
63
64 getInitialState() {
65 const props = this.props;
66 let activeKey;
67 if ("activeKey" in props) {
68 activeKey = props.activeKey;
69 } else if ("defaultActiveKey" in props) {
70 activeKey = props.defaultActiveKey;
71 } else {
72 activeKey = getDefaultActiveKey(props);
73 }
74 return {
75 activeKey
76 };
77 },
78
79 componentWillReceiveProps(nextProps) {
80 if ("activeKey" in nextProps) {
81 this.setState({
82 activeKey: nextProps.activeKey
83 });
84 }
85 },
86
87 onTabClick(activeKey) {
88 this.props.onTabClick && this.props.onTabClick(activeKey);
89 if (this.tabBar.props.onTabClick) {
90 this.tabBar.props.onTabClick(activeKey);
91 }
92 this.setActiveKey(activeKey);
93 },
94
95 onNavKeyDown(e) {
96 const eventKeyCode = e.keyCode;
97 if (eventKeyCode === KeyCode.RIGHT || eventKeyCode === KeyCode.DOWN) {
98 e.preventDefault();
99 const nextKey = this.getNextActiveKey(true);
100 this.onTabClick(nextKey);
101 } else if (eventKeyCode === KeyCode.LEFT || eventKeyCode === KeyCode.UP) {
102 e.preventDefault();
103 const previousKey = this.getNextActiveKey(false);
104 this.onTabClick(previousKey);
105 }
106 },
107
108 setActiveKey(activeKey) {
109 if (this.state.activeKey !== activeKey) {
110 if (!("activeKey" in this.props)) {
111 this.setState({
112 activeKey
113 });
114 }
115 this.props.onChange(activeKey);
116 }
117 },
118
119 getNextActiveKey(next) {
120 const activeKey = this.state.activeKey;
121 const children = [];
122 React.Children.forEach(this.props.children, c => {
123 if (c && !c.props.disabled) {
124 if (next) {
125 children.push(c);
126 } else {
127 children.unshift(c);
128 }
129 }
130 });
131 const length = children.length;
132 let ret = length && children[0].key;
133 children.forEach((child, i) => {
134 if (child.key === activeKey) {
135 if (i === length - 1) {
136 ret = children[0].key;
137 } else {
138 ret = children[i + 1].key;
139 }
140 }
141 });
142 return ret;
143 },
144 onPrevClick(e){
145 this.props.onPrevClick && this.props.onPrevClick(e)
146 },
147 onNextClick(e){
148 this.props.onNextClick && this.props.onNextClick(e)
149 },
150 createNewTab(targetKey){
151 const { onEdit } = this.props;
152 if (onEdit) {
153 onEdit(targetKey, 'add');
154 }
155 },
156 removeTab(targetKey, e){
157 e.stopPropagation();
158 if (!targetKey) {
159 return;
160 }
161
162 const { onEdit } = this.props;
163 if (onEdit) {
164 onEdit(targetKey, 'remove');
165 }
166 },
167
168 render() {
169 const props = this.props;
170 const {
171 activeKey,
172 defaultActiveKey,
173 clsPrefix,
174 tabBarPosition,
175 className,
176 renderTabContent,
177 renderTabBar,
178 tabBarStyle,
179 extraContent,
180 animated,
181 tabIndex,
182 children,
183 hideAdd,
184 scrollAnimated,
185 inkBarAnimated,
186 useTransform3d,
187 destroyInactiveTabPane,
188 onTabClick,
189 onEdit,
190 onNextClick,
191 onPrevClick,
192 onChange,
193 ...others
194 } = props;
195
196 const cls = classnames({
197 [clsPrefix]: true,
198 [`${clsPrefix}-${tabBarPosition}`]: true,
199 [className]: !!className,
200 [`${clsPrefix}-${tabBarStyle}`]: true
201 });
202
203 const renderProps = {
204 ...this.props,
205 children: null,
206 inkBarAnimated,
207 extraContent: extraContent,
208 className: cls,
209 };
210 if (renderTabBar) {
211 this.tabBar = renderTabBar(renderProps, ScrollableInkTabBar);
212 } else {
213 this.tabBar = <ScrollableInkTabBar {...renderProps} />;
214 }
215
216 // only card type tabs can be added and closed
217 let childrenWithClose = [],
218 tabBarExtraContent = extraContent;
219 if (tabBarStyle === 'editable-card') {
220 childrenWithClose = [];
221 React.Children.forEach(children, (child, index) => {
222 if (!React.isValidElement(child)) return child;
223 let { closable } = child.props;
224 closable = typeof closable === 'undefined' ? true : closable;
225 const closeIcon = closable ? (
226 <Icon
227 type="uf-close"
228 className={`${clsPrefix}-close-x`}
229 onClick={e => this.removeTab(child.key, e)}
230 />
231 ) : null;
232 childrenWithClose.push(
233 React.cloneElement(child, {
234 tab: (
235 <div className={closable ? undefined : `${clsPrefix}-tab-unclosable`}>
236 {child.props.tab}
237 {closeIcon}
238 </div>
239 ),
240 key: child.key || index,
241 }),
242 );
243 });
244 // Add new tab handler
245 if (!hideAdd) {
246 tabBarExtraContent = (
247 <span>
248 <Icon type="uf-add-s-o" className={`${clsPrefix}-new-tab`} onClick={this.createNewTab} />
249 {extraContent}
250 </span>
251 );
252 }
253 }
254
255 const contents = [
256 React.cloneElement(this.tabBar, {
257 clsPrefix,
258 key: "tabBar",
259 onKeyDown: this.onNavKeyDown,
260 tabBarPosition,
261 extraContent: tabBarExtraContent,
262 onTabClick: this.onTabClick,
263 panels: childrenWithClose.length > 0 ? childrenWithClose : children,
264 activeKey: this.state.activeKey,
265 tabIndex,
266 onPrevClick: this.onPrevClick,
267 onNextClick: this.onNextClick,
268 }),
269 React.cloneElement(renderTabContent(), {
270 clsPrefix,
271 tabBarPosition,
272 animated,
273 activeKey: this.state.activeKey,
274 destroyInactiveTabPane: props.destroyInactiveTabPane,
275 children: props.children,
276 // style: { height: '100%' },
277 onChange: this.setActiveKey,
278 key: "tabContent"
279 })
280 ];
281 if (tabBarPosition === "bottom") {
282 contents.reverse();
283 }
284 return (
285 <div className={cls} style={props.style} {...others}>
286 {contents}
287 </div>
288 );
289 }
290});
291
292Tabs.TabPane = TabPane;
293
294export {Tabs};