@mijadesign/mjui-react-taro
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
210 lines (209 loc) • 9.27 kB
JavaScript
import { _ as __rest } from "./tslib.es6-iWu3F_1J.js";
import classNames from "classnames";
import React, { useRef, useEffect, useState } from "react";
import { useRtl, TabPane } from "@nutui/nutui-react-taro";
import { C as ComponentDefaults } from "./typings-DV9RBfhj.js";
import { u as usePropsValue, a as useForceUpdate } from "./use-props-value-DuhZMy4U.js";
import { View, ScrollView } from "@tarojs/components";
import Taro, { nextTick, createSelectorQuery } from "@tarojs/taro";
function requestAniFrame() {
if (typeof window !== "undefined") {
const _window = window;
return _window.requestAnimationFrame || _window.webkitRequestAnimationFrame || function(callback) {
_window.setTimeout(callback, 1e3 / 60);
};
}
return (callback) => {
setTimeout(callback, 1e3 / 60);
};
}
const raf = requestAniFrame();
const idCounter = {};
function uniqueId(prefix = "$nut$") {
if (!idCounter[prefix]) {
idCounter[prefix] = 0;
}
const id = ++idCounter[prefix];
if (prefix === "$nut$") {
return `${id}`;
}
return `${prefix}${id}`;
}
function useUuid() {
const idRef = useRef(uniqueId());
return idRef.current;
}
const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { tabStyle: {}, activeColor: "", direction: "horizontal", activeType: "line", actionButtonProps: {
fill: "outline"
}, duration: 300, autoHeight: false, contentAnimation: true });
const classPrefix = "nut-tabs";
const Tabs$1 = (props) => {
const rtl = useRtl();
const _a = Object.assign(Object.assign({}, defaultProps), props), { activeColor, tabStyle, direction, activeType, actionButtonProps, duration, align, title, name, children, onClick, onChange, className, autoHeight, value: outerValue, defaultValue: outerDefaultValue, contentAnimation } = _a, rest = __rest(_a, ["activeColor", "tabStyle", "direction", "activeType", "actionButtonProps", "duration", "align", "title", "name", "children", "onClick", "onChange", "className", "autoHeight", "value", "defaultValue", "contentAnimation"]);
const uuid = useUuid();
const [value, setValue] = usePropsValue({
value: outerValue,
defaultValue: outerDefaultValue,
onChange
});
const titleItemsRef = useRef([]);
const getTitles = () => {
const titles2 = [];
React.Children.forEach(children, (child, idx) => {
if (React.isValidElement(child)) {
const { props: props2 } = child;
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-${activeType}-${actionButtonProps.fill}`]: activeType === "button",
[`${classPrefix}-titles-${align}`]: align
});
const getRect = (selector) => {
return new Promise((resolve) => {
createSelectorQuery().select(selector).boundingClientRect().exec((rect = []) => {
resolve(rect[0]);
});
});
};
const getAllRect = (selector) => {
return new Promise((resolve) => {
createSelectorQuery().selectAll(selector).boundingClientRect().exec((rect = []) => {
resolve(rect[0]);
});
});
};
const scrollWithAnimation = useRef(false);
const [scrollLeft, setScrollLeft] = useState(0);
const [scrollTop, setScrollTop] = useState(0);
const scrollDirection = (to, direction2) => {
if (direction2 === "horizontal")
setScrollLeft(to);
else
setScrollTop(to);
};
const scrollIntoView = (index) => {
raf(() => {
Promise.all([
getRect(`#nut-tabs-titles-${name || uuid} .nut-tabs-list`),
getAllRect(`#nut-tabs-titles-${name || uuid} .nut-tabs-titles-item`)
]).then(([navRect, titleRects]) => {
const titleRect = titleRects[index];
if (!titleRect)
return;
let to = 0;
if (direction === "vertical") {
const top = titleRects.slice(0, index).reduce((prev, curr) => prev + curr.height, 0);
to = top - (navRect.height - titleRect.height) / 2;
} else {
const left = titleRects.slice(0, index).reduce((prev, curr) => prev + curr.width, 0);
to = left - (navRect.width - titleRect.width) / 2;
}
scrollDirection(to, direction);
nextTick(() => {
scrollWithAnimation.current = true;
});
});
});
};
const getContentStyle = () => {
let index = titles.current.findIndex((t) => String(t.value) === String(value));
index = index < 0 ? 0 : index;
if (!contentAnimation)
return {};
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) => String(t.value) === String(value));
index = index < 0 ? 0 : index;
scrollIntoView(index);
}, [value]);
const tabChange = (item) => {
onClick && onClick(item.value);
if (!item.disabled) {
setValue(item.value);
}
};
return React.createElement(
View,
Object.assign({ className: classes }, rest),
React.createElement(
ScrollView,
{ enableFlex: true, scrollX: direction === "horizontal", scrollY: direction === "vertical", scrollLeft, scrollTop, enhanced: true, showScrollbar: false, scrollWithAnimation: rtl && Taro.getEnv() !== "WEB" ? false : scrollWithAnimation.current, id: `nut-tabs-titles-${name || uuid}`, className: classesTitle, style: tabStyle },
React.createElement(View, { className: "nut-tabs-list" }, !!title && typeof title === "function" ? title() : titles.current.map((item, index) => {
return React.createElement(
View,
{ key: item.value, ref: (ref) => titleItemsRef.current.push(ref), id: `scrollIntoView${index}`, 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
}) },
activeType === "line" && React.createElement(View, { className: classNames(`${classPrefix}-titles-item-line`, `${classPrefix}-titles-item-line-${direction}`), style: { background: activeColor } }),
React.createElement(View, { className: classNames({
[`${classPrefix}-ellipsis`]: direction === "vertical"
}, `${classPrefix}-titles-item-text`), style: { color: activeColor } }, item.title)
);
}))
),
React.createElement(
View,
{ className: `${classPrefix}-content-wrap` },
React.createElement(View, { className: classNames(`${classPrefix}-content`, contentAnimation ? "" : `${classPrefix}-content-no-animate`), style: getContentStyle() }, React.Children.map(children, (child, idx) => {
if (!React.isValidElement(child))
return null;
const isActive = String(value) === String(child.props.value || idx);
return React.cloneElement(child, Object.assign(Object.assign({}, child.props), { className: classNames(child.props.className, isActive ? `${classPrefix}-content-active` : `${classPrefix}-content-inactive`), active: value === child.props.value, autoHeightClassName: autoHeight && String(value) !== String(child.props.value || idx) ? "inactive" : void 0 }));
}))
)
);
};
Tabs$1.displayName = "NutTabs";
Tabs$1.TabPane = TabPane;
const Tabs = (props) => {
const { items, fixWidth = false, className } = props, restProps = __rest(props, ["items", "fixWidth", "className"]);
const cls = classNames(className, { "nut-tabs-fix-width": !!fixWidth });
if (items) {
return React.createElement(Tabs$1, Object.assign({}, restProps), items.map((item) => {
return React.createElement(Tabs$1.TabPane, { className: cls, key: item.key, value: item.key, title: React.createElement(
React.Fragment,
null,
!!(item === null || item === void 0 ? void 0 : item.icon) && React.createElement("div", { className: "nut-tabs-titles-item-text-icon" }, item === null || item === void 0 ? void 0 : item.icon),
item === null || item === void 0 ? void 0 : item.label
) }, item === null || item === void 0 ? void 0 : item.children);
}));
}
return React.createElement(Tabs$1, Object.assign({}, restProps, { className: cls }));
};
Tabs.TabPane = Tabs$1.TabPane;
export {
Tabs as T
};