UNPKG

@douyinfe/semi-ui

Version:

A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.

218 lines 8.13 kB
import _isFunction from "lodash/isFunction"; import React from 'react'; import cls from 'classnames'; import propTypes from 'prop-types'; import { cssClasses, strings } from '@douyinfe/semi-foundation/lib/es/breadcrumb/constants'; import BreadcrumbFoundation from '@douyinfe/semi-foundation/lib/es/breadcrumb/foundation'; import warning from '@douyinfe/semi-foundation/lib/es/utils/warning'; import '@douyinfe/semi-foundation/lib/es/breadcrumb/breadcrumb.css'; import { noop } from '@douyinfe/semi-foundation/lib/es/utils/function'; import BaseComponent from '../_base/baseComponent'; import Popover from '../popover'; import BreadcrumbItem from './item'; import BreadContext from './bread-context'; import { IconMore } from '@douyinfe/semi-icons'; const clsPrefix = cssClasses.PREFIX; class Breadcrumb extends BaseComponent { constructor(props) { super(props); this.handleCollapse = (template, itemsLen) => { const { maxItemCount, renderMore, moreType } = this.props; const hasRenderMore = _isFunction(renderMore); const restItem = template.slice(1, itemsLen - maxItemCount + 1); const spread = /*#__PURE__*/React.createElement("span", { className: `${clsPrefix}-collapse`, key: `more-${itemsLen}` }, /*#__PURE__*/React.createElement("span", { className: `${clsPrefix}-item-wrap` }, /*#__PURE__*/React.createElement("span", { role: "button", tabIndex: 0, "aria-label": "Expand breadcrumb items", className: `${clsPrefix}-item ${clsPrefix}-item-more`, onClick: item => this.foundation.handleExpand(item), onKeyPress: e => this.foundation.handleExpandEnterPress(e) }, hasRenderMore && renderMore(restItem), !hasRenderMore && moreType === 'default' && /*#__PURE__*/React.createElement(IconMore, null), !hasRenderMore && moreType === 'popover' && this.renderPopoverMore(restItem)), /*#__PURE__*/React.createElement("span", { className: `${clsPrefix}-separator`, "x-semi-prop": "separator" }, this.props.separator))); template.splice(1, itemsLen - maxItemCount, spread); return template; }; this.renderRouteItems = (items, shouldCollapse, moreTypeIsPopover) => { const { renderItem, renderMore, maxItemCount } = this.props; const restItemLength = items.length - maxItemCount; const hasRenderMore = _isFunction(renderMore); const template = items.map((route, idx) => { const key = route._origin.key || `item-${route.name || route.path}-${idx}`; const inCollapseArea = idx > 0 && idx <= restItemLength; return /*#__PURE__*/React.createElement(BreadcrumbItem, Object.assign({}, route, { key: key, active: this.props.activeIndex !== undefined ? this.props.activeIndex === idx : idx === items.length - 1, route: route._origin, shouldRenderSeparator: idx !== items.length - 1 && !(shouldCollapse && (hasRenderMore || moreTypeIsPopover) && inCollapseArea) }), renderItem ? renderItem(route._origin) : route.name); }); return template; }; this.renderList = () => { const { routes, children, autoCollapse, maxItemCount, renderMore, moreType } = this.props; const { isCollapsed } = this.state; const hasRoutes = routes && routes.length > 0; const items = hasRoutes ? this.foundation.genRoutes(routes) : React.Children.toArray(children); let template; const itemLength = items.length; // children length const restItemLength = itemLength - maxItemCount; // Omitted children items const shouldCollapse = items && autoCollapse && itemLength > maxItemCount && isCollapsed; // Whether the number of children exceeds, need to collapse const hasRenderMore = _isFunction(renderMore); // Whether the user passes in the renderMore method const moreTypeIsPopover = moreType === 'popover'; if (hasRoutes) { template = this.renderRouteItems(items, shouldCollapse, moreTypeIsPopover); } else { template = items.map((item, idx) => { const inCollapseArea = idx > 0 && idx <= restItemLength; if (!item) { return item; } warning(item.type && !item.type.isBreadcrumbItem, '[Semi Breadcrumb]: Only accepts Breadcrumb.Item as its children'); return /*#__PURE__*/React.cloneElement(item, { key: `${idx}-item`, active: this.props.activeIndex !== undefined ? this.props.activeIndex === idx : idx === items.length - 1, shouldRenderSeparator: idx !== items.length - 1 && !(shouldCollapse && (hasRenderMore || moreTypeIsPopover) && inCollapseArea) }); }); } if (shouldCollapse) { return this.handleCollapse(template, items.length); } return template; }; this.onClick = (info, event) => { this.foundation.handleClick(info, event); }; this.foundation = new BreadcrumbFoundation(this.adapter); this.state = { isCollapsed: true }; this.onClick = this.onClick.bind(this); } get adapter() { var _this = this; return Object.assign(Object.assign({}, super.adapter), { notifyClick: function () { _this.props.onClick(...arguments); }, expandCollapsed: () => this.setState({ isCollapsed: false }) }); } componentDidMount() { this.foundation.init(); } componentWillUnmount() { this.foundation.destroy(); } renderPopoverMore(restItem) { const { separator } = this.props; const content = /*#__PURE__*/React.createElement(React.Fragment, null, restItem.map((item, idx) => (/*#__PURE__*/React.createElement(React.Fragment, { key: `restItem-${idx}` }, item, idx !== restItem.length - 1 && (/*#__PURE__*/React.createElement("span", { className: `${clsPrefix}-restItem` }, separator)))))); return /*#__PURE__*/React.createElement(Popover, { content: content, style: { padding: 12 }, showArrow: true }, /*#__PURE__*/React.createElement(IconMore, null)); } render() { const breadcrumbs = this.renderList(); const { compact, className, style, separator, showTooltip } = this.props; const sizeCls = cls(className, { [`${clsPrefix}-wrapper`]: true, [`${clsPrefix}-wrapper-compact`]: compact, [`${clsPrefix}-wrapper-loose`]: !compact }); return /*#__PURE__*/React.createElement(BreadContext.Provider, { value: { onClick: this.onClick, showTooltip, compact, separator } }, /*#__PURE__*/React.createElement("nav", Object.assign({ "aria-label": this.props['aria-label'], className: sizeCls, style: style }, this.getDataAttr(this.props)), breadcrumbs)); } } Breadcrumb.contextType = BreadContext; Breadcrumb.Item = BreadcrumbItem; Breadcrumb.propTypes = { activeIndex: propTypes.number, routes: propTypes.array, onClick: propTypes.func, separator: propTypes.node, compact: propTypes.bool, children: propTypes.node, style: propTypes.object, renderItem: propTypes.func, showTooltip: propTypes.oneOfType([propTypes.shape({ width: propTypes.oneOfType([propTypes.string, propTypes.number]), ellipsisPos: propTypes.oneOf(['end', 'middle']), opts: propTypes.object }), propTypes.bool]), className: propTypes.string, autoCollapse: propTypes.bool, maxItemCount: propTypes.number, /* Customize the contents of the ellipsis area */ renderMore: propTypes.func, /* Type of ellipsis area */ moreType: propTypes.oneOf(strings.MORE_TYPE), 'aria-label': propTypes.string }; Breadcrumb.defaultProps = { routes: [], onClick: noop, renderItem: undefined, separator: '/', compact: true, showTooltip: { width: 150, ellipsisPos: 'end' }, autoCollapse: true, moreType: 'default', maxItemCount: 4, 'aria-label': 'Breadcrumb' }; export default Breadcrumb;