import React, { useState, useRef } from "react";
import classNames from "classnames";
import { isChildOfType } from "../_util/is-child-of-type";
import { TabBar } from "./TabBar";
import { TabPanel } from "./TabPanel";
import { TabsProps, Tab } from "./TabProps";
import { useConfig } from "../_util/config-context";
const getHiddenPanelStyle: (
vertical: boolean
) => React.CSSProperties = vertical => ({
height: 0,
width: 0,
overflow: "hidden",
opacity: 0,
padding: 0,
margin: 0,
pointerEvents: "none",
display: "block",
transform: vertical ? "translate3d(10px, 0, 0)" : "translate3d(0, 10px, 0)",
});
const animatedPanelStyle: React.CSSProperties = {
transition: "opacity .45s ease, transform .45s ease",
transformOrigin: "center",
};
const defaultTabBarRender = c => {c};
export const Tabs = React.forwardRef(function Tabs(
{
tabs = [],
destroyInactiveTabPanel = true,
activeId,
onActive,
defaultActiveId,
children,
animated = true,
placement,
ceiling,
addon,
maxHeight,
className,
tabBarRender = defaultTabBarRender,
tabBarStyle,
activeTabAutoScrollIntoView = true,
disableTabScrolling = false,
...props
}: TabsProps,
ref: React.Ref
) {
const { classPrefix } = useConfig();
// 如果都没有定义,获取第一个没被禁用的选项卡 id
if (
typeof activeId === "undefined" &&
typeof defaultActiveId === "undefined"
) {
const firstAvailable = tabs.find(x => !x.disabled);
// eslint-disable-next-line no-param-reassign
defaultActiveId = firstAvailable ? firstAvailable.id : null;
}
// 注意 useState 是个 Hooks,不能写在 if 里面
const [internalActiveId, setInternalActiveId] = useState(defaultActiveId);
// 非受控模式下,使用内部状态
if (typeof activeId === "undefined") {
// eslint-disable-next-line no-param-reassign
activeId = internalActiveId;
// eslint-disable-next-line no-param-reassign
onActive = (onActive => (tab: Tab, evt: React.SyntheticEvent) => {
setInternalActiveId(tab.id);
if (typeof onActive === "function") {
onActive(tab, evt);
}
})(onActive);
}
const panelRenderedSetRef = useRef>(new Set());
function getTabPanels() {
const panelRenderedSet = panelRenderedSetRef.current;
const panelChildren = [];
React.Children.forEach(children, (child, index) => {
if (isChildOfType(child, TabPanel)) {
const { props, key } = child;
const { style = {}, id } = props;
const active = activeId === props.id;
if (active && !panelRenderedSet.has(activeId)) {
panelRenderedSet.add(activeId);
}
if (!active) {
Object.assign(style, getHiddenPanelStyle(placement === "left"));
}
if (animated) {
Object.assign(style, animatedPanelStyle);
}
if (
child.props.forceRender ||
(destroyInactiveTabPanel && active) ||
(!destroyInactiveTabPanel && panelRenderedSet.has(props.id))
) {
panelChildren.push(
React.cloneElement(child, { key: key || id, style })
);
} else {
panelChildren.push(
);
}
} else if (React.isValidElement(child)) {
panelChildren.push(React.cloneElement(child, { key: index }));
} else {
panelChildren.push({child}
);
}
});
return panelChildren;
}
const containerClassName = classNames(`${classPrefix}-tabs`, {
// 垂直布局
[`${classPrefix}-tabs--vertical`]: placement === "left",
[`${classPrefix}-tabs--ceiling`]: ceiling,
[className]: className,
});
return (
{getTabPanels()}
);
});
Tabs.displayName = "Tabs";