| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 | 
							- /* eslint-disable max-len */
 
- import React from 'react';
 
- import cls from 'classnames';
 
- import propTypes from 'prop-types';
 
- import { cssClasses, strings } from '@douyinfe/semi-foundation/breadcrumb/constants';
 
- import BreadcrumbFoundation, { BreadcrumbAdapter } from '@douyinfe/semi-foundation/breadcrumb/foundation';
 
- import warning from '@douyinfe/semi-foundation/utils/warning';
 
- import { isFunction } from 'lodash';
 
- import '@douyinfe/semi-foundation/breadcrumb/breadcrumb.scss';
 
- import { noop } from '@douyinfe/semi-foundation/utils/function';
 
- import BaseComponent, { BaseProps } from '../_base/baseComponent';
 
- import Popover from '../popover';
 
- import BreadcrumbItem, { RouteProps, BreadcrumbItemInfo } from './item';
 
- import BreadContext, { BreadContextType } from './bread-context';
 
- import { TooltipProps } from '../tooltip';
 
- import { IconMore } from '@douyinfe/semi-icons';
 
- const clsPrefix = cssClasses.PREFIX;
 
- export type { RouteProps, BreadcrumbItemProps, BreadcrumbItemInfo } from './item';
 
- export interface showToolTipProps {
 
-     width?: string | number;
 
-     ellipsisPos?: 'end' | 'middle';
 
-     opts?: TooltipProps
 
- }
 
- export type MoreType = 'default' | 'popover';
 
- export interface BreadcrumbProps extends BaseProps {
 
-     routes?: Array<RouteProps | string>;
 
-     onClick?: (route: RouteProps, event: React.MouseEvent) => void;
 
-     separator?: React.ReactNode;
 
-     compact?: boolean;
 
-     style?: React.CSSProperties;
 
-     renderItem?: (route: RouteProps) => React.ReactNode;
 
-     className?: string;
 
-     showTooltip?: boolean | showToolTipProps;
 
-     maxItemCount?: number;
 
-     autoCollapse?: boolean;
 
-     /* Customize the contents of the ellipsis area */
 
-     renderMore?: (restItem: Array<React.ReactNode>) => React.ReactNode;
 
-     /* Style type for ellipsis area */
 
-     moreType?: MoreType;
 
-     'aria-label'?: React.AriaAttributes['aria-label']
 
- }
 
- interface BreadcrumbState {
 
-     isCollapsed: boolean
 
- }
 
- class Breadcrumb extends BaseComponent<BreadcrumbProps, BreadcrumbState> {
 
-     static contextType: React.Context<BreadContextType> = BreadContext;
 
-     static Item: typeof BreadcrumbItem = BreadcrumbItem;
 
-     static propTypes = {
 
-         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,
 
-     };
 
-     static defaultProps = {
 
-         routes: [] as [],
 
-         onClick: noop,
 
-         renderItem: undefined as undefined,
 
-         separator: '/',
 
-         compact: true,
 
-         showTooltip: {
 
-             width: 150,
 
-             ellipsisPos: 'end',
 
-         },
 
-         autoCollapse: true,
 
-         moreType: 'default',
 
-         maxItemCount: 4,
 
-         'aria-label': 'Breadcrumb'
 
-     };
 
-     constructor(props: BreadcrumbProps) {
 
-         super(props);
 
-         this.foundation = new BreadcrumbFoundation(this.adapter);
 
-         this.state = {
 
-             isCollapsed: true,
 
-         };
 
-         this.onClick = this.onClick.bind(this);
 
-     }
 
-     get adapter(): BreadcrumbAdapter<BreadcrumbProps, BreadcrumbState> {
 
-         return {
 
-             ...super.adapter,
 
-             notifyClick: (...args) => {
 
-                 this.props.onClick(...args);
 
-             },
 
-             expandCollapsed: () =>
 
-                 this.setState({
 
-                     isCollapsed: false,
 
-                 }),
 
-         };
 
-     }
 
-     componentDidMount() {
 
-         this.foundation.init();
 
-     }
 
-     componentWillUnmount() {
 
-         this.foundation.destroy();
 
-     }
 
-     renderPopoverMore(restItem: Array<React.ReactNode>) {
 
-         const { separator } = this.props;
 
-         const content = (
 
-             <>
 
-                 {
 
-                     restItem.map((item: React.ReactNode, idx: number) => (
 
-                         <React.Fragment key={`restItem-${idx}`}>
 
-                             {item}
 
-                             {idx !== restItem.length - 1 &&
 
-                                 (
 
-                                     <span className={`${clsPrefix}-restItem`}>
 
-                                         {separator}
 
-                                     </span>
 
-                                 )
 
-                             }
 
-                         </React.Fragment>
 
-                     ))
 
-                 }
 
-             </>
 
-         );
 
-         return (
 
-             <Popover
 
-                 content={content}
 
-                 style={{
 
-                     padding: 12,
 
-                 }}
 
-                 showArrow
 
-             >
 
-                 <IconMore />
 
-             </Popover>
 
-         );
 
-     }
 
-     handleCollapse = (template: Array<React.ReactNode>, itemsLen: number) => {
 
-         const { maxItemCount, renderMore, moreType } = this.props;
 
-         const hasRenderMore = isFunction(renderMore);
 
-         const restItem = template.slice(1, itemsLen - 3);
 
-         const spread = (
 
-             <span className={`${clsPrefix}-collapse`} key={`more-${itemsLen}`}>
 
-                 <span className={`${clsPrefix}-item-wrap`}>
 
-                     <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' && <IconMore />}
 
-                         {!hasRenderMore && moreType === 'popover' && this.renderPopoverMore(restItem)}
 
-                     </span>
 
-                     <span className={`${clsPrefix}-separator`} x-semi-prop="separator">
 
-                         {this.props.separator}
 
-                     </span>
 
-                 </span>
 
-             </span>
 
-         );
 
-         template.splice(1, itemsLen - maxItemCount, spread);
 
-         return template;
 
-     };
 
-     renderRouteItems = (items: Array<RouteProps>, shouldCollapse: boolean, moreTypeIsPopover: boolean) => {
 
-         const { renderItem, renderMore, maxItemCount } = this.props;
 
-         const restItemLength = items.length - maxItemCount;
 
-         const hasRenderMore = isFunction(renderMore);
 
-         const template = (
 
-             items.map((route, idx: number) => {
 
-                 const key = route._origin.key || `item-${route.name || route.path}-${idx}`;
 
-                 const inCollapseArea = idx > 0 && idx <= restItemLength;
 
-                 return (
 
-                     <BreadcrumbItem
 
-                         {...route}
 
-                         key={key}
 
-                         active={idx === items.length - 1}
 
-                         route={route._origin}
 
-                         // eslint-disable-next-line max-len
 
-                         shouldRenderSeparator={!(shouldCollapse && (hasRenderMore || moreTypeIsPopover) && inCollapseArea)}
 
-                     >
 
-                         {renderItem ? renderItem(route._origin) : route.name}
 
-                     </BreadcrumbItem>
 
-                 );
 
-             })
 
-         );
 
-         return template;
 
-     };
 
-     renderList = (): Array<React.ReactNode> => {
 
-         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: any, idx: number) => {
 
-                     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 React.cloneElement(item, {
 
-                         key: `${idx}-item`,
 
-                         active: idx === items.length - 1,
 
-                         shouldRenderSeparator: !(shouldCollapse && (hasRenderMore || moreTypeIsPopover) && inCollapseArea)
 
-                     });
 
-                 })
 
-             );
 
-         }
 
-         if (shouldCollapse) {
 
-             return this.handleCollapse(template, items.length);
 
-         }
 
-         return template;
 
-     };
 
-     onClick = (info: BreadcrumbItemInfo, event: React.MouseEvent) => {
 
-         this.foundation.handleClick(info, event);
 
-     };
 
-     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 (
 
-             <BreadContext.Provider
 
-                 value={{
 
-                     onClick: this.onClick,
 
-                     showTooltip,
 
-                     compact,
 
-                     separator,
 
-                 }}
 
-             >
 
-                 <nav aria-label={this.props['aria-label']} className={sizeCls} style={style}>
 
-                     {breadcrumbs}
 
-                 </nav>
 
-             </BreadContext.Provider>
 
-         );
 
-     }
 
- }
 
- export default Breadcrumb;
 
 
  |