@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
166 lines (165 loc) • 7 kB
JavaScript
import { _ as __rest } from "./tslib.es6.js";
import React__default, { useRef, useEffect } from "react";
import classNames from "classnames";
import { JoySmile } from "@nutui/icons-react";
import { C as ComponentDefaults } from "./typings.js";
import TabPane__default from "./TabPane.js";
import { r as requestAniFrame } from "./raf.js";
import { u as usePropsValue, a as useForceUpdate } from "./use-props-value.js";
import { a as useRtl } from "./configprovider2.js";
const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { tabStyle: {}, activeColor: "", direction: "horizontal", activeType: "line", duration: 300, autoHeight: false });
const classPrefix = "nut-tabs";
const Tabs = (props) => {
const rtl = useRtl();
const _a = Object.assign(Object.assign({}, defaultProps), props), { activeColor, tabStyle, direction, activeType, duration, align, title, children, onClick, onChange, className, autoHeight, value: outerValue, defaultValue: outerDefaultValue } = _a, rest = __rest(_a, ["activeColor", "tabStyle", "direction", "activeType", "duration", "align", "title", "children", "onClick", "onChange", "className", "autoHeight", "value", "defaultValue"]);
const [value, setValue] = usePropsValue({
value: outerValue,
defaultValue: outerDefaultValue,
finalValue: 0,
onChange
});
const titleItemsRef = useRef([]);
const navRef = useRef(null);
const scrollDirection = (nav, to, duration2, direction2) => {
let count = 0;
const from = direction2 === "horizontal" ? nav.scrollLeft : nav.scrollTop;
const frames = Math.round(duration2 * 1e3 / 16);
function animate() {
if (direction2 === "horizontal") {
nav.scrollLeft += (to - from) / frames;
} else {
nav.scrollTop += (to - from) / frames;
}
if (++count < frames) {
requestAniFrame(animate);
}
}
animate();
};
const scrollIntoView = (index, immediate) => {
const nav = navRef.current;
const titleItem = titleItemsRef.current;
const titlesLength = titles.current.length;
const itemLength = titleItemsRef.current.length;
if (!nav || !titleItem || !titleItem[itemLength - titlesLength + index]) {
return;
}
const title2 = titleItem[itemLength - titlesLength + index];
let to = 0;
if (direction === "vertical") {
const runTop = title2.offsetTop - nav.offsetTop + 10;
to = runTop - (nav.offsetHeight - title2.offsetHeight) / 2;
} else {
to = title2.offsetLeft - (nav.offsetWidth - title2.offsetWidth) / 2;
}
scrollDirection(nav, to, 0.3, direction);
};
const getTitles = () => {
const titles2 = [];
React__default.Children.forEach(children, (child, idx) => {
if (React__default.isValidElement(child)) {
const props2 = child === null || child === void 0 ? void 0 : child.props;
if ((props2 === null || props2 === void 0 ? void 0 : props2.title) || (props2 === null || props2 === void 0 ? void 0 : props2.value)) {
titles2.push({
title: props2.title,
value: props2.value || idx,
disabled: props2.disabled
});
}
}
});
return titles2;
};
const titles = useRef(getTitles());
const forceUpdate = useForceUpdate();
useEffect(() => {
titles.current = getTitles();
let current = "";
titles.current.forEach((title2) => {
if (title2.value === value) {
current = value;
}
});
if (current !== "" && current !== value) {
setValue(current);
} else {
forceUpdate();
}
}, [children]);
const classes = classNames(classPrefix, `${classPrefix}-${direction}`, className);
const classesTitle = classNames(`${classPrefix}-titles`, {
[`${classPrefix}-titles-${activeType}`]: activeType,
[`${classPrefix}-titles-scrollable`]: true,
[`${classPrefix}-titles-${align}`]: align
});
const tabsActiveStyle = {
color: activeType === "smile" ? activeColor : "",
background: activeType === "line" ? activeColor : ""
};
const getContentStyle = () => {
let index = titles.current.findIndex((t) => t.value == value);
index = index < 0 ? 0 : index;
return {
transform: direction === "horizontal" ? `translate3d(${rtl ? "" : "-"}${index * 100}%, 0, 0)` : `translate3d( 0,-${index * 100}%, 0)`,
transitionDuration: `${duration}ms`
};
};
useEffect(() => {
let index = titles.current.findIndex((t) => t.value == value);
index = index < 0 ? 0 : index;
setTimeout(() => {
scrollIntoView(index);
});
}, [value]);
const tabChange = (item) => {
onClick && onClick(item.value);
if (item.disabled) {
return;
}
setValue(item.value);
};
return React__default.createElement(
"div",
Object.assign({ className: classes }, rest),
React__default.createElement("div", { className: classesTitle, style: Object.assign({}, tabStyle), ref: navRef }, !!title && typeof title === "function" ? title() : titles.current.map((item) => {
return React__default.createElement(
"div",
{ onClick: () => {
tabChange(item);
}, className: classNames(`${classPrefix}-titles-item`, {
[`nut-tabs-titles-item-active`]: !item.disabled && String(item.value) === String(value),
[`nut-tabs-titles-item-disabled`]: item.disabled,
[`nut-tabs-titles-item-${align}`]: align
}), ref: (ref) => titleItemsRef.current.push(ref), key: item.value },
activeType === "line" && React__default.createElement("div", { className: classNames(`${classPrefix}-titles-item-line`, {
[`${classPrefix}-titles-item-line-${direction}`]: true
}), style: tabsActiveStyle }),
activeType === "smile" && React__default.createElement(
"div",
{ className: `${classPrefix}-titles-item-smile`, style: tabsActiveStyle },
React__default.createElement(JoySmile, { color: activeColor, width: 40, height: 20 })
),
React__default.createElement("div", { className: classNames(`${classPrefix}-ellipsis`, `${classPrefix}-titles-item-text`) }, item.title)
);
})),
React__default.createElement(
"div",
{ className: `${classPrefix}-content-wrap` },
React__default.createElement("div", { className: `${classPrefix}-content`, style: getContentStyle() }, React__default.Children.map(children, (child, idx) => {
if (!React__default.isValidElement(child)) {
return null;
}
let childProps = Object.assign(Object.assign({}, child.props), { active: value === child.props.value });
if (String(value) !== String(child.props.value || idx) && autoHeight) {
childProps = Object.assign(Object.assign({}, childProps), { autoHeightClassName: "inactive" });
}
return React__default.cloneElement(child, childProps);
}))
)
);
};
Tabs.displayName = "NutTabs";
Tabs.TabPane = TabPane__default;
export {
Tabs as T
};