import React, { CSSProperties, ReactNode, useState, useRef, useEffect, useMemo, } from 'react' import classNames from 'classnames' import _ from 'lodash' import { Flex, FlexProps } from '../flex' import SVGCloseSquare from '../../svg/close-square.svg' import PopupContentConfirm from '../popup/popup_content_confirm' import Popover from '../popover/popover' import { anyCallback } from '../../types' import { judgeFunction } from '../../common/utils/utils' interface TabsItem { text: string value: V children: ReactNode disabled?: boolean /* 是否可关闭 */ closable?: boolean ref?: HTMLDivElement | null /** 是否隐藏 */ hide?: boolean } interface TabsProps extends Omit { tabs: TabsItem[] defaultActive?: V active?: V onChange?(value: V): void onClose?(value: V): void onChangeValidate?(): boolean keep?: boolean light?: boolean /* didMount之后不再重新渲染 */ activeOnce?: boolean /* 是否全屏 */ full?: boolean className?: string column?: boolean /* 卡片类型 editable-card 可以编辑的卡片 */ type?: 'editable-card' style?: CSSProperties /* 而外操作,比如新增tab的操作 */ extraAction?: ReactNode popup?(value: V, closePopup: anyCallback): ReactNode isPopover?: boolean popoverContent?: ReactNode popverTitle?: string } function Tabs({ tabs, light, active, defaultActive, keep, onChange, onClose, onChangeValidate, className, column = true, activeOnce, full, type, extraAction, isPopover, popup, popoverContent, popverTitle, ...rest }: TabsProps) { tabs = useMemo(() => tabs.filter((tab) => !tab.hide), [tabs]) const editableCard: boolean = type === 'editable-card' const baseTabClassName = `gm-${full ? 'framework-full-' : ''}tabs` if (active !== undefined && defaultActive !== undefined) { console.warn('prop `active` and prop `defaultActive` can not exist at the same time!') } if (active !== undefined && !onChange) { console.warn('prop `active` `onChange` must exist at the same time!') } const [selected, setSelected] = useState(defaultActive || active) const hasSelectedsRef = useRef>(new Set()) // tab滚动使用 const tabRef = useRef(null) useEffect(() => { defaultActive === undefined && active !== undefined && setSelected(active) }, [active, defaultActive]) // 增加切换tab的校验 const handleClick = (value: V) => { if (typeof onChangeValidate === 'function' && !onChangeValidate()) return setSelected(value) judgeFunction(onChange, value) } const tabsChildrenKeep = (tabs: TabsItem[]) => ( <> {_.map(tabs, (tab: TabsItem) => (
{tab.children}
))} ) const tabsChildren = () => { if (activeOnce && selected) { hasSelectedsRef.current.add(selected) } let items: typeof tabs = [] if (activeOnce) { items = _.filter(tabs, (tab) => hasSelectedsRef.current.has(tab.value)) } else { const item = _.find(tabs, (tab) => tab.value === selected) if (item) { items = [item] } } return tabsChildrenKeep(items) } const handleClose = (value: V) => { judgeFunction(onClose, value) } const handleDelete = (value: V) => { handleClose(value) } const innerPopup: TabsProps['popup'] = (value, closePopover) => { if (popup) { return popup(value, closePopover) } return ( handleDelete(value)} > {popoverContent} ) } return (
{_.map(tabs, (tab) => { const isClose = tab.closable === false ? false : editableCard return ( (tab.ref = ref)} key={tab.value} className={classNames(`${baseTabClassName}-head-item`, { active: !tab.disabled && selected === tab.value, 'gm-tabs-head-disabled': tab.disabled, 'gm-tabs-closable': isClose, })} > handleClick(tab.value)} > {tab.text} {isClose && isPopover && ( innerPopup(tab.value, closePopover)} >
)}
) })}
{extraAction && ( {extraAction} )}
{keep ? tabsChildrenKeep(tabs) : tabsChildren()}
) } export default Tabs export type { TabsProps, TabsItem }