UNPKG

11.1 kBJavaScriptView Raw
1import _typeof from 'babel-runtime/helpers/typeof';
2import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
3import _extends from 'babel-runtime/helpers/extends';
4import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
5import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
6import _inherits from 'babel-runtime/helpers/inherits';
7
8var _class, _temp, _initialiseProps;
9
10import React, { Component, Children, isValidElement } from 'react';
11import PropTypes from 'prop-types';
12import { polyfill } from 'react-lifecycles-compat';
13import Icon from '../icon';
14import ConfigProvider from '../config-provider';
15import Dropdown from '../dropdown';
16import Menu from '../menu';
17import Item from './item';
18import { events } from '../util';
19
20/**
21 * Breadcrumb
22 */
23var Breadcrumb = (_temp = _class = function (_Component) {
24 _inherits(Breadcrumb, _Component);
25
26 function Breadcrumb(props) {
27 _classCallCheck(this, Breadcrumb);
28
29 var _this = _possibleConstructorReturn(this, _Component.call(this, props));
30
31 _initialiseProps.call(_this);
32
33 _this.state = {
34 maxNode: props.maxNode === 'auto' ? 100 : props.maxNode
35 };
36 return _this;
37 }
38
39 Breadcrumb.getDerivedStateFromProps = function getDerivedStateFromProps(props, state) {
40 if (state.prevMaxNode === props.maxNode) {
41 return {};
42 }
43
44 return {
45 prevMaxNode: props.maxNode,
46 maxNode: props.maxNode === 'auto' ? 100 : props.maxNode
47 };
48 };
49
50 Breadcrumb.prototype.componentDidMount = function componentDidMount() {
51 this.computeMaxNode();
52 events.on(window, 'resize', this.computeMaxNode);
53 };
54
55 Breadcrumb.prototype.componentDidUpdate = function componentDidUpdate() {
56 this.computeMaxNode();
57 };
58
59 Breadcrumb.prototype.componentWillUnmount = function componentWillUnmount() {
60 events.off(window, 'resize', this.computeMaxNode);
61 };
62
63 Breadcrumb.prototype.renderEllipsisNodeWithMenu = function renderEllipsisNodeWithMenu(children, breakpointer) {
64 // 拿到被隐藏的项
65 var hiddenItems = [];
66 Children.forEach(children, function (item, i) {
67 var _item$props = item.props,
68 link = _item$props.link,
69 itemChildren = _item$props.children;
70
71 if (i > 0 && i <= breakpointer) {
72 hiddenItems.push(React.createElement(
73 Menu.Item,
74 { key: i },
75 link ? React.createElement(
76 'a',
77 { href: link },
78 itemChildren
79 ) : itemChildren
80 ));
81 }
82 });
83
84 var _props = this.props,
85 prefix = _props.prefix,
86 followTrigger = _props.followTrigger,
87 popupContainer = _props.popupContainer,
88 popupProps = _props.popupProps;
89
90
91 return React.createElement(
92 Dropdown,
93 _extends({
94 trigger: React.createElement(
95 'span',
96 null,
97 '...'
98 )
99 }, popupProps, {
100 container: popupContainer,
101 followTrigger: followTrigger
102 }),
103 React.createElement(
104 'div',
105 { className: prefix + 'breadcrumb-dropdown-wrapper' },
106 React.createElement(
107 Menu,
108 null,
109 hiddenItems
110 )
111 )
112 );
113 };
114
115 Breadcrumb.prototype.render = function render() {
116 var _this2 = this;
117
118 var _props2 = this.props,
119 prefix = _props2.prefix,
120 rtl = _props2.rtl,
121 className = _props2.className,
122 children = _props2.children,
123 component = _props2.component,
124 showHiddenItems = _props2.showHiddenItems,
125 maxNodeProp = _props2.maxNode,
126 others = _objectWithoutProperties(_props2, ['prefix', 'rtl', 'className', 'children', 'component', 'showHiddenItems', 'maxNode']);
127
128 var separator = this.props.separator || React.createElement(Icon, { type: 'arrow-right', className: prefix + 'breadcrumb-icon-sep' });
129
130 var maxNode = this.state.maxNode;
131
132
133 var items = void 0;
134 var length = Children.count(children);
135
136 if (maxNode > 1 && length > maxNode) {
137 var breakpointer = length - maxNode + 1;
138 items = [];
139
140 Children.forEach(children, function (item, i) {
141 var ariaProps = {};
142
143 // 增加空值判断
144 if (!item) {
145 return;
146 }
147 if (i === length - 1) {
148 ariaProps['aria-current'] = 'page';
149 }
150
151 if (i && i === breakpointer) {
152 items.push(React.cloneElement(item, _extends({
153 separator: separator,
154 prefix: prefix,
155 key: i,
156 activated: i === length - 1
157 }, ariaProps, {
158 className: showHiddenItems ? prefix + 'breadcrumb-text-ellipsis-clickable' : prefix + 'breadcrumb-text-ellipsis'
159 }), showHiddenItems ? _this2.renderEllipsisNodeWithMenu(children, breakpointer) : '...'));
160 } else if (!i || i > breakpointer) {
161 items.push(React.cloneElement(item, _extends({
162 separator: separator,
163 prefix: prefix,
164 key: i
165 }, ariaProps, {
166 activated: i === length - 1
167 })));
168 }
169 });
170 } else {
171 items = Children.map(children, function (item, i) {
172 var ariaProps = {};
173 // 增加空值判断
174 if (!item) {
175 return;
176 }
177 if (i === length - 1) {
178 ariaProps['aria-current'] = 'page';
179 }
180
181 return React.cloneElement(item, _extends({
182 separator: separator,
183 prefix: prefix,
184 activated: i === length - 1
185 }, ariaProps, {
186 key: i
187 }));
188 });
189 }
190
191 if (rtl) {
192 others.dir = 'rtl';
193 }
194
195 var BreadcrumbComponent = component;
196
197 delete others.maxNode;
198
199 return React.createElement(
200 BreadcrumbComponent,
201 _extends({
202 'aria-label': 'Breadcrumb',
203 className: className
204 }, others, {
205 style: _extends({ position: 'relative' }, others.style || {})
206 }),
207 React.createElement(
208 'ul',
209 { className: prefix + 'breadcrumb' },
210 items
211 ),
212 maxNodeProp === 'auto' ? React.createElement(
213 'ul',
214 {
215 style: {
216 position: 'absolute',
217 left: 0,
218 right: 0,
219 top: 0,
220 visibility: 'hidden'
221 },
222 ref: this.saveBreadcrumbRef,
223 className: prefix + 'breadcrumb'
224 },
225 Children.map(children, function (item, i) {
226 return React.cloneElement(item, {
227 separator: separator,
228 prefix: prefix,
229 activated: i === length - 1,
230 key: i
231 });
232 })
233 ) : null
234 );
235 };
236
237 return Breadcrumb;
238}(Component), _class.Item = Item, _class.propTypes = {
239 /**
240 * 样式类名的品牌前缀
241 */
242 prefix: PropTypes.string,
243 rtl: PropTypes.bool,
244 /*eslint-disable*/
245 /**
246 * 面包屑子节点,需传入 Breadcrumb.Item
247 */
248 children: function children(props, propName) {
249 Children.forEach(props[propName], function (child) {
250 if (!(child && ['function', 'object'].indexOf(_typeof(child.type)) > -1 && child.type._typeMark === 'breadcrumb_item')) {
251 throw new Error("Breadcrumb's children must be Breadcrumb.Item!");
252 }
253 });
254 },
255 /*eslint-enable*/
256 /**
257 * 面包屑最多显示个数,超出部分会被隐藏, 设置为 auto 会自动根据父元素的宽度适配。
258 */
259 maxNode: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf(['auto'])]),
260 /**
261 * 当超过的项被隐藏时,是否可通过点击省略号展示菜单(包含被隐藏的项)
262 * @version 1.23
263 */
264 showHiddenItems: PropTypes.bool,
265 /**
266 * 弹层挂载的容器节点(在showHiddenItems为true时才有意义)
267 * @version 1.23
268 */
269 popupContainer: PropTypes.any,
270 /**
271 * 是否跟随trigger滚动(在showHiddenItems为true时才有意义)
272 * @version 1.23
273 */
274 followTrigger: PropTypes.bool,
275 /**
276 * 添加到弹层上的属性(在showHiddenItems为true时才有意义)
277 * @version 1.23
278 */
279 popupProps: PropTypes.object,
280 /**
281 * 分隔符,可以是文本或 Icon
282 */
283 separator: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
284 /**
285 * 设置标签类型
286 */
287 component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
288 className: PropTypes.any
289}, _class.defaultProps = {
290 prefix: 'next-',
291 maxNode: 100,
292 showHiddenItems: false,
293 component: 'nav'
294}, _initialiseProps = function _initialiseProps() {
295 var _this3 = this;
296
297 this.computeMaxNode = function () {
298 // 计算最大node节点,无法获取到 ... 节点的宽度,目前会有 nodeWidth - ellipsisNodeWidth 的误差
299 if (_this3.props.maxNode !== 'auto' || !_this3.breadcrumbEl) return;
300 var scrollWidth = _this3.breadcrumbEl.scrollWidth;
301 var rect = _this3.breadcrumbEl.getBoundingClientRect();
302
303 if (scrollWidth <= rect.width) return;
304 var maxNode = _this3.breadcrumbEl.children.length;
305 var index = 1;
306 var fullWidth = scrollWidth;
307
308 while (index < _this3.breadcrumbEl.children.length - 1) {
309 var el = _this3.breadcrumbEl.children[index];
310 maxNode--;
311 fullWidth -= el.getBoundingClientRect().width;
312 if (fullWidth <= rect.width) {
313 break;
314 }
315 index++;
316 }
317
318 maxNode = Math.max(3, maxNode);
319
320 if (maxNode !== _this3.state.maxNode) {
321 _this3.setState({
322 maxNode: maxNode
323 });
324 }
325 };
326
327 this.saveBreadcrumbRef = function (ref) {
328 _this3.breadcrumbEl = ref;
329 };
330}, _temp);
331Breadcrumb.displayName = 'Breadcrumb';
332
333
334export default ConfigProvider.config(polyfill(Breadcrumb));
\No newline at end of file