1 | import _extends from 'babel-runtime/helpers/extends';
|
2 | import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
|
3 | import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
|
4 | import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
|
5 | import _inherits from 'babel-runtime/helpers/inherits';
|
6 | import classNames from 'classnames';
|
7 | import keycode from 'keycode';
|
8 | import React, { cloneElement } from 'react';
|
9 | import PropTypes from 'prop-types';
|
10 | import ReactDOM from 'react-dom';
|
11 | import all from 'prop-types-extra/lib/all';
|
12 | import warning from 'warning';
|
13 |
|
14 | import { bsClass, bsStyles, getClassSet, prefix, splitBsProps } from './utils/bootstrapUtils';
|
15 | import createChainedFunction from './utils/createChainedFunction';
|
16 | import ValidComponentChildren from './utils/ValidComponentChildren';
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | var propTypes = {
|
26 | |
27 |
|
28 |
|
29 |
|
30 | activeKey: PropTypes.any,
|
31 |
|
32 | |
33 |
|
34 |
|
35 | activeHref: PropTypes.string,
|
36 |
|
37 | |
38 |
|
39 |
|
40 | stacked: PropTypes.bool,
|
41 |
|
42 | justified: all(PropTypes.bool, function (_ref) {
|
43 | var justified = _ref.justified,
|
44 | navbar = _ref.navbar;
|
45 | return justified && navbar ? Error('justified navbar `Nav`s are not supported') : null;
|
46 | }),
|
47 |
|
48 | |
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | onSelect: PropTypes.func,
|
59 |
|
60 | |
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 | role: PropTypes.string,
|
69 |
|
70 | |
71 |
|
72 |
|
73 |
|
74 | navbar: PropTypes.bool,
|
75 |
|
76 | |
77 |
|
78 |
|
79 |
|
80 | pullRight: PropTypes.bool,
|
81 |
|
82 | |
83 |
|
84 |
|
85 |
|
86 | pullLeft: PropTypes.bool
|
87 | };
|
88 |
|
89 | var defaultProps = {
|
90 | justified: false,
|
91 | pullRight: false,
|
92 | pullLeft: false,
|
93 | stacked: false
|
94 | };
|
95 |
|
96 | var contextTypes = {
|
97 | $bs_navbar: PropTypes.shape({
|
98 | bsClass: PropTypes.string,
|
99 | onSelect: PropTypes.func
|
100 | }),
|
101 |
|
102 | $bs_tabContainer: PropTypes.shape({
|
103 | activeKey: PropTypes.any,
|
104 | onSelect: PropTypes.func.isRequired,
|
105 | getTabId: PropTypes.func.isRequired,
|
106 | getPaneId: PropTypes.func.isRequired
|
107 | })
|
108 | };
|
109 |
|
110 | var Nav = function (_React$Component) {
|
111 | _inherits(Nav, _React$Component);
|
112 |
|
113 | function Nav() {
|
114 | _classCallCheck(this, Nav);
|
115 |
|
116 | return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
|
117 | }
|
118 |
|
119 | Nav.prototype.componentDidUpdate = function componentDidUpdate() {
|
120 | var _this2 = this;
|
121 |
|
122 | if (!this._needsRefocus) {
|
123 | return;
|
124 | }
|
125 |
|
126 | this._needsRefocus = false;
|
127 |
|
128 | var children = this.props.children;
|
129 |
|
130 | var _getActiveProps = this.getActiveProps(),
|
131 | activeKey = _getActiveProps.activeKey,
|
132 | activeHref = _getActiveProps.activeHref;
|
133 |
|
134 | var activeChild = ValidComponentChildren.find(children, function (child) {
|
135 | return _this2.isActive(child, activeKey, activeHref);
|
136 | });
|
137 |
|
138 | var childrenArray = ValidComponentChildren.toArray(children);
|
139 | var activeChildIndex = childrenArray.indexOf(activeChild);
|
140 |
|
141 | var childNodes = ReactDOM.findDOMNode(this).children;
|
142 | var activeNode = childNodes && childNodes[activeChildIndex];
|
143 |
|
144 | if (!activeNode || !activeNode.firstChild) {
|
145 | return;
|
146 | }
|
147 |
|
148 | activeNode.firstChild.focus();
|
149 | };
|
150 |
|
151 | Nav.prototype.getActiveProps = function getActiveProps() {
|
152 | var tabContainer = this.context.$bs_tabContainer;
|
153 |
|
154 | if (tabContainer) {
|
155 | process.env.NODE_ENV !== 'production' ? warning(this.props.activeKey == null && !this.props.activeHref, 'Specifying a `<Nav>` `activeKey` or `activeHref` in the context of ' + 'a `<TabContainer>` is not supported. Instead use `<TabContainer ' + ('activeKey={' + this.props.activeKey + '} />`.')) : void 0;
|
156 |
|
157 | return tabContainer;
|
158 | }
|
159 |
|
160 | return this.props;
|
161 | };
|
162 |
|
163 | Nav.prototype.getNextActiveChild = function getNextActiveChild(offset) {
|
164 | var _this3 = this;
|
165 |
|
166 | var children = this.props.children;
|
167 |
|
168 | var validChildren = children.filter(function (child) {
|
169 | return child.props.eventKey != null && !child.props.disabled;
|
170 | });
|
171 |
|
172 | var _getActiveProps2 = this.getActiveProps(),
|
173 | activeKey = _getActiveProps2.activeKey,
|
174 | activeHref = _getActiveProps2.activeHref;
|
175 |
|
176 | var activeChild = ValidComponentChildren.find(children, function (child) {
|
177 | return _this3.isActive(child, activeKey, activeHref);
|
178 | });
|
179 |
|
180 |
|
181 | var activeChildIndex = validChildren.indexOf(activeChild);
|
182 | if (activeChildIndex === -1) {
|
183 |
|
184 | return validChildren[0];
|
185 | }
|
186 |
|
187 | var nextIndex = activeChildIndex + offset;
|
188 | var numValidChildren = validChildren.length;
|
189 |
|
190 | if (nextIndex >= numValidChildren) {
|
191 | nextIndex = 0;
|
192 | } else if (nextIndex < 0) {
|
193 | nextIndex = numValidChildren - 1;
|
194 | }
|
195 |
|
196 | return validChildren[nextIndex];
|
197 | };
|
198 |
|
199 | Nav.prototype.getTabProps = function getTabProps(child, tabContainer, navRole, active, onSelect) {
|
200 | var _this4 = this;
|
201 |
|
202 | if (!tabContainer && navRole !== 'tablist') {
|
203 |
|
204 | return null;
|
205 | }
|
206 |
|
207 | var _child$props = child.props,
|
208 | id = _child$props.id,
|
209 | controls = _child$props['aria-controls'],
|
210 | eventKey = _child$props.eventKey,
|
211 | role = _child$props.role,
|
212 | onKeyDown = _child$props.onKeyDown,
|
213 | tabIndex = _child$props.tabIndex;
|
214 |
|
215 |
|
216 | if (tabContainer) {
|
217 | process.env.NODE_ENV !== 'production' ? warning(!id && !controls, 'In the context of a `<TabContainer>`, `<NavItem>`s are given ' + 'generated `id` and `aria-controls` attributes for the sake of ' + 'proper component accessibility. Any provided ones will be ignored. ' + 'To control these attributes directly, provide a `generateChildId` ' + 'prop to the parent `<TabContainer>`.') : void 0;
|
218 |
|
219 | id = tabContainer.getTabId(eventKey);
|
220 | controls = tabContainer.getPaneId(eventKey);
|
221 | }
|
222 |
|
223 | if (navRole === 'tablist') {
|
224 | role = role || 'tab';
|
225 | onKeyDown = createChainedFunction(function (event) {
|
226 | return _this4.handleTabKeyDown(onSelect, event);
|
227 | }, onKeyDown);
|
228 | tabIndex = active ? tabIndex : -1;
|
229 | }
|
230 |
|
231 | return {
|
232 | id: id,
|
233 | role: role,
|
234 | onKeyDown: onKeyDown,
|
235 | 'aria-controls': controls,
|
236 | tabIndex: tabIndex
|
237 | };
|
238 | };
|
239 |
|
240 | Nav.prototype.handleTabKeyDown = function handleTabKeyDown(onSelect, event) {
|
241 | var nextActiveChild = void 0;
|
242 |
|
243 | switch (event.keyCode) {
|
244 | case keycode.codes.left:
|
245 | case keycode.codes.up:
|
246 | nextActiveChild = this.getNextActiveChild(-1);
|
247 | break;
|
248 | case keycode.codes.right:
|
249 | case keycode.codes.down:
|
250 | nextActiveChild = this.getNextActiveChild(1);
|
251 | break;
|
252 | default:
|
253 |
|
254 | return;
|
255 | }
|
256 |
|
257 | event.preventDefault();
|
258 |
|
259 | if (onSelect && nextActiveChild && nextActiveChild.props.eventKey != null) {
|
260 | onSelect(nextActiveChild.props.eventKey);
|
261 | }
|
262 |
|
263 | this._needsRefocus = true;
|
264 | };
|
265 |
|
266 | Nav.prototype.isActive = function isActive(_ref2, activeKey, activeHref) {
|
267 | var props = _ref2.props;
|
268 |
|
269 | if (props.active || activeKey != null && props.eventKey === activeKey || activeHref && props.href === activeHref) {
|
270 | return true;
|
271 | }
|
272 |
|
273 | return props.active;
|
274 | };
|
275 |
|
276 | Nav.prototype.render = function render() {
|
277 | var _extends2,
|
278 | _this5 = this;
|
279 |
|
280 | var _props = this.props,
|
281 | stacked = _props.stacked,
|
282 | justified = _props.justified,
|
283 | onSelect = _props.onSelect,
|
284 | propsRole = _props.role,
|
285 | propsNavbar = _props.navbar,
|
286 | pullRight = _props.pullRight,
|
287 | pullLeft = _props.pullLeft,
|
288 | className = _props.className,
|
289 | children = _props.children,
|
290 | props = _objectWithoutProperties(_props, ['stacked', 'justified', 'onSelect', 'role', 'navbar', 'pullRight', 'pullLeft', 'className', 'children']);
|
291 |
|
292 | var tabContainer = this.context.$bs_tabContainer;
|
293 | var role = propsRole || (tabContainer ? 'tablist' : null);
|
294 |
|
295 | var _getActiveProps3 = this.getActiveProps(),
|
296 | activeKey = _getActiveProps3.activeKey,
|
297 | activeHref = _getActiveProps3.activeHref;
|
298 |
|
299 | delete props.activeKey;
|
300 | delete props.activeHref;
|
301 |
|
302 | var _splitBsProps = splitBsProps(props),
|
303 | bsProps = _splitBsProps[0],
|
304 | elementProps = _splitBsProps[1];
|
305 |
|
306 | var classes = _extends({}, getClassSet(bsProps), (_extends2 = {}, _extends2[prefix(bsProps, 'stacked')] = stacked, _extends2[prefix(bsProps, 'justified')] = justified, _extends2));
|
307 |
|
308 | var navbar = propsNavbar != null ? propsNavbar : this.context.$bs_navbar;
|
309 | var pullLeftClassName = void 0;
|
310 | var pullRightClassName = void 0;
|
311 |
|
312 | if (navbar) {
|
313 | var navbarProps = this.context.$bs_navbar || { bsClass: 'navbar' };
|
314 |
|
315 | classes[prefix(navbarProps, 'nav')] = true;
|
316 |
|
317 | pullRightClassName = prefix(navbarProps, 'right');
|
318 | pullLeftClassName = prefix(navbarProps, 'left');
|
319 | } else {
|
320 | pullRightClassName = 'pull-right';
|
321 | pullLeftClassName = 'pull-left';
|
322 | }
|
323 |
|
324 | classes[pullRightClassName] = pullRight;
|
325 | classes[pullLeftClassName] = pullLeft;
|
326 |
|
327 | return React.createElement(
|
328 | 'ul',
|
329 | _extends({}, elementProps, {
|
330 | role: role,
|
331 | className: classNames(className, classes)
|
332 | }),
|
333 | ValidComponentChildren.map(children, function (child) {
|
334 | var active = _this5.isActive(child, activeKey, activeHref);
|
335 | var childOnSelect = createChainedFunction(child.props.onSelect, onSelect, navbar && navbar.onSelect, tabContainer && tabContainer.onSelect);
|
336 |
|
337 | return cloneElement(child, _extends({}, _this5.getTabProps(child, tabContainer, role, active, childOnSelect), {
|
338 | active: active,
|
339 | activeKey: activeKey,
|
340 | activeHref: activeHref,
|
341 | onSelect: childOnSelect
|
342 | }));
|
343 | })
|
344 | );
|
345 | };
|
346 |
|
347 | return Nav;
|
348 | }(React.Component);
|
349 |
|
350 | Nav.propTypes = propTypes;
|
351 | Nav.defaultProps = defaultProps;
|
352 | Nav.contextTypes = contextTypes;
|
353 |
|
354 | export default bsClass('nav', bsStyles(['tabs', 'pills'], Nav)); |
\ | No newline at end of file |