| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- import React, { Fragment } from 'react';
- import cls from 'classnames';
- import propTypes from 'prop-types';
- import { cssClasses } from '@douyinfe/semi-foundation/breadcrumb/constants';
- import BreadcrumbItemFoundation, { BreadcrumbItemAdapter, BreadcrumbItemInfo, Route } from '@douyinfe/semi-foundation/breadcrumb/itemFoundation';
- import BaseComponent, { BaseProps } from '../_base/baseComponent';
- import { noop } from '@douyinfe/semi-foundation/utils/function';
- import BreadContext, { BreadContextType } from './bread-context';
- import Typography, { EllipsisPos, ShowTooltip as ShowTooltipType } from '../typography';
- import { merge, isUndefined, isNull } from 'lodash';
- const clsPrefix = cssClasses.PREFIX;
- export type { BreadcrumbItemInfo };
- export interface RouteProps extends Route {
- icon?: React.ReactNode
- }
- export interface BreadcrumbItemProps extends BaseProps {
- onClick?: (item: RouteProps, e: React.MouseEvent) => void;
- icon?: React.ReactNode;
- href?: string;
- separator?: React.ReactNode;
- noLink?: boolean;
- active?: boolean;
- shouldRenderSeparator?: boolean;
- route?: RouteProps
- }
- type BreadcrumbItemState = Record<string, never>;
- interface GetTooltipOptType {
- width: number;
- ellipsisPos: EllipsisPos;
- opts?: ShowTooltipType['opts']
- }
- export default class BreadcrumbItem extends BaseComponent<BreadcrumbItemProps, BreadcrumbItemState> {
- static isBreadcrumbItem = true;
- static contextType = BreadContext;
- static propTypes = {
- onClick: propTypes.func,
- route: propTypes.oneOfType([propTypes.object, propTypes.string]),
- name: propTypes.string,
- children: propTypes.node,
- active: propTypes.bool,
- shouldRenderSeparator: propTypes.bool,
- icon: propTypes.oneOfType([propTypes.string, propTypes.node]),
- separator: propTypes.node,
- noLink: propTypes.bool,
- };
- static defaultProps = {
- onClick: noop,
- shouldRenderSeparator: true
- };
- context: BreadContextType;
- get adapter(): BreadcrumbItemAdapter<BreadcrumbItemProps, BreadcrumbItemState> {
- return {
- ...super.adapter,
- notifyClick: (...args) => {
- this.props.onClick(...args);
- },
- notifyParent: (...args) => {
- this.context.onClick(...args);
- },
- };
- }
- constructor(props: BreadcrumbItemProps) {
- super(props);
- this.foundation = new BreadcrumbItemFoundation(this.adapter);
- }
- componentDidMount() {
- this.foundation.init();
- }
- componentWillUnmount() {
- this.foundation.destroy();
- }
- renderIcon = () => {
- const iconType = this.props.icon;
- const { compact } = this.context;
- const iconSize = compact ? 'small' : 'default';
- const className = `${clsPrefix}-item-icon`;
- if (React.isValidElement(iconType)) {
- //@ts-ignore
- return React.cloneElement(iconType, { className, size: iconSize });
- }
- return iconType;
- };
- getTooltipOpt = () => {
- const { showTooltip } = this.context;
- if (!showTooltip) {
- return {
- width: 150,
- ellipsisPos: 'end',
- };
- }
- const defaultOpts = {
- width: 150,
- ellipsisPos: 'end',
- opts: {
- autoAdjustOverflow: true,
- position: 'top',
- },
- };
- if (typeof showTooltip === 'object') {
- return merge(defaultOpts, showTooltip);
- }
- return defaultOpts;
- };
- getItemInfo = (): BreadcrumbItemInfo => {
- let itemInfo: BreadcrumbItemInfo = {};
- const { route, children, href } = this.props;
- const hasHref = !isUndefined(href) && !isNull(href);
- if (route) {
- itemInfo = route;
- } else {
- itemInfo.name = children;
- if (hasHref) {
- itemInfo.href = href;
- }
- }
- return itemInfo;
- };
- renderBreadItem = () => {
- const { children } = this.props;
- const { compact } = this.context;
- const showTooltip = this.getTooltipOpt();
- const icon = this.renderIcon();
- if (Boolean(children) && typeof children === 'string') {
- const { opts, ellipsisPos, width } = showTooltip as GetTooltipOptType;
- return (
- <Fragment>
- {icon}
- <span className={`${clsPrefix}-item-title`}>
- <Typography.Text
- ellipsis={{
- showTooltip: opts ? { opts } : false,
- pos: ellipsisPos,
- }}
- // icon={this.renderIcon(icon)}
- style={{ width }}
- size={compact ? 'small' : 'normal'}
- >
- {children}
- </Typography.Text>
- </span>
- </Fragment>
- );
- }
- return (
- <Fragment>
- {icon}
- {children ? (
- <span className={`${clsPrefix}-item-title ${clsPrefix}-item-title-inline`}>{children}</span>
- ) : null}
- </Fragment>
- );
- };
- renderItem = () => {
- const { href, active, noLink } = this.props;
- const hasHref = href !== null && typeof href !== 'undefined';
- const itemCls = cls({
- [`${clsPrefix}-item`]: true,
- [`${clsPrefix}-item-active`]: active,
- [`${clsPrefix}-item-link`]: !noLink,
- });
- const itemInner = this.renderBreadItem();
- const tag = active || !hasHref ? 'span' : 'a';
- const itemInfo = this.getItemInfo();
- return React.createElement(
- tag,
- {
- className: itemCls,
- onClick: e => this.foundation.handleClick(itemInfo, e),
- href,
- },
- itemInner
- );
- };
- render() {
- const {
- active,
- shouldRenderSeparator
- // children,
- } = this.props;
- const pageLabel = active ? { 'aria-current': 'page' as const } : {} ;
- const item = this.renderItem();
- const separator = !active ?
- this.props.separator || <span className={`${clsPrefix}-separator`}>{this.context.separator}</span> :
- null;
- const wrapperCLs = cls({
- [`${clsPrefix}-item-wrap`]: true,
- // [`${clsPrefix}-item-wrap-iconOnly`]: !!children && this.props.icon,
- });
- return (
- <span className={wrapperCLs} {...pageLabel}>
- {item}
- {shouldRenderSeparator && separator}
- </span>
- );
- }
- }
|