@bifrostui/react 2.0.0-alpha.17 → 2.0.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Modal/Modal.miniapp.d.ts +1 -1
- package/dist/Tabs/TabIndicator.d.ts +0 -2
- package/dist/Tabs/TabIndicator.js +83 -37
- package/dist/Tabs/TabMask.d.ts +2 -4
- package/dist/Tabs/TabMask.js +12 -53
- package/dist/Tabs/Tabs.css +1 -1
- package/dist/Tabs/Tabs.js +17 -6
- package/dist/Tabs/index.css +1 -1
- package/dist/Tabs/miniapp/TabIndicator.js +109 -14
- package/dist/Tabs/miniapp/Tabs.js +12 -36
- package/es/Modal/Modal.miniapp.d.ts +1 -1
- package/es/Tabs/TabIndicator.d.ts +0 -2
- package/es/Tabs/TabIndicator.js +84 -38
- package/es/Tabs/TabMask.d.ts +2 -4
- package/es/Tabs/TabMask.js +13 -54
- package/es/Tabs/Tabs.css +1 -1
- package/es/Tabs/Tabs.js +18 -7
- package/es/Tabs/index.css +1 -1
- package/es/Tabs/miniapp/TabIndicator.js +110 -15
- package/es/Tabs/miniapp/Tabs.js +12 -36
- package/package.json +5 -5
- package/dist/Tabs/miniapp/TabMask.d.ts +0 -13
- package/dist/Tabs/miniapp/TabMask.js +0 -66
- package/es/Tabs/miniapp/TabMask.d.ts +0 -13
- package/es/Tabs/miniapp/TabMask.js +0 -37
|
@@ -12,5 +12,5 @@ declare const Modal: React.ForwardRefExoticComponent<Omit<ViewProps & {
|
|
|
12
12
|
keepMounted?: boolean;
|
|
13
13
|
} & import("@bifrostui/types").ICommonProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
14
14
|
ref?: React.Ref<HTMLDivElement>;
|
|
15
|
-
}, keyof import("@bifrostui/types").ICommonProps | "
|
|
15
|
+
}, "open" | "container" | keyof import("@bifrostui/types").ICommonProps | "disablePortal" | "hideBackdrop" | "BackdropProps" | "onClose" | "disableScrollLock" | "keepMounted">, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
16
16
|
export default Modal;
|
|
@@ -6,8 +6,6 @@ export interface TabIndicatorProps {
|
|
|
6
6
|
registeredTabs: React.MutableRefObject<Record<string, React.RefObject<HTMLElement>>>;
|
|
7
7
|
/** tabs 容器的引用 */
|
|
8
8
|
tabsContainerRef: React.RefObject<HTMLDivElement>;
|
|
9
|
-
/** 注册版本号,每次 tab 注册/取消注册时递增 */
|
|
10
|
-
registrationVersion: number;
|
|
11
9
|
}
|
|
12
10
|
declare const TabIndicator: React.FC<TabIndicatorProps>;
|
|
13
11
|
export default TabIndicator;
|
|
@@ -36,77 +36,123 @@ var import_utils = require("@bifrostui/utils");
|
|
|
36
36
|
var import_scroll = __toESM(require("./utils/scroll"));
|
|
37
37
|
const rootClass = "bui-tabs";
|
|
38
38
|
const duration = 300;
|
|
39
|
+
const DEFAULT_INDICATOR_WIDTH = 24;
|
|
39
40
|
const TabIndicator = ({
|
|
40
41
|
currentValue,
|
|
41
42
|
registeredTabs,
|
|
42
|
-
tabsContainerRef
|
|
43
|
-
registrationVersion
|
|
43
|
+
tabsContainerRef
|
|
44
44
|
}) => {
|
|
45
45
|
const indicatorRef = (0, import_react.useRef)(null);
|
|
46
|
+
const hasRenderedOnce = (0, import_react.useRef)(false);
|
|
47
|
+
const indicatorWidthCache = (0, import_react.useRef)(null);
|
|
48
|
+
const [indicatorStyle, setIndicatorStyle] = (0, import_react.useState)(
|
|
49
|
+
null
|
|
50
|
+
);
|
|
46
51
|
const getActiveTabElement = (0, import_utils.useEventCallback)(
|
|
47
52
|
(activeValue) => {
|
|
48
53
|
const tabRef = registeredTabs.current[activeValue];
|
|
49
54
|
return tabRef == null ? void 0 : tabRef.current;
|
|
50
55
|
}
|
|
51
56
|
);
|
|
52
|
-
const scrollIntoView = (0, import_utils.useEventCallback)(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
const scrollIntoView = (0, import_utils.useEventCallback)(
|
|
58
|
+
(activeTab, animate = true) => {
|
|
59
|
+
const tabsEl = tabsContainerRef.current;
|
|
60
|
+
if (!tabsEl || !activeTab) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
(0, import_scroll.default)(
|
|
64
|
+
tabsEl,
|
|
65
|
+
activeTab.offsetLeft - (tabsEl.offsetWidth - activeTab.offsetWidth) / 2,
|
|
66
|
+
animate ? duration : 0
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
const getIndicatorWidth = (0, import_utils.useEventCallback)(() => {
|
|
71
|
+
if (indicatorWidthCache.current !== null) {
|
|
72
|
+
return indicatorWidthCache.current;
|
|
56
73
|
}
|
|
57
|
-
(0, import_scroll.default)(
|
|
58
|
-
tabsEl,
|
|
59
|
-
activeTab.offsetLeft - (tabsEl.offsetWidth - activeTab.offsetWidth) / 2,
|
|
60
|
-
duration
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
const animate = (0, import_utils.useEventCallback)(() => {
|
|
64
|
-
const tabsEl = tabsContainerRef.current;
|
|
65
|
-
if (!tabsEl)
|
|
66
|
-
return;
|
|
67
74
|
const indicator = indicatorRef.current;
|
|
68
75
|
if (!indicator)
|
|
76
|
+
return DEFAULT_INDICATOR_WIDTH;
|
|
77
|
+
const cssValue = getComputedStyle(indicator).getPropertyValue(
|
|
78
|
+
"--bui-tabs-indicator-width"
|
|
79
|
+
);
|
|
80
|
+
const parsed = Number.parseFloat(cssValue);
|
|
81
|
+
const width = Number.isNaN(parsed) ? DEFAULT_INDICATOR_WIDTH : parsed;
|
|
82
|
+
indicatorWidthCache.current = width;
|
|
83
|
+
return width;
|
|
84
|
+
});
|
|
85
|
+
const getTabsMeta = (0, import_utils.useEventCallback)(() => {
|
|
86
|
+
const tabsNode = tabsContainerRef.current;
|
|
87
|
+
let tabsMeta = null;
|
|
88
|
+
if (tabsNode) {
|
|
89
|
+
const rect = tabsNode.getBoundingClientRect();
|
|
90
|
+
tabsMeta = {
|
|
91
|
+
clientWidth: tabsNode.clientWidth,
|
|
92
|
+
scrollLeft: tabsNode.scrollLeft,
|
|
93
|
+
scrollWidth: tabsNode.scrollWidth,
|
|
94
|
+
left: rect.left
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
let tabMeta = null;
|
|
98
|
+
const activeTab = getActiveTabElement(currentValue);
|
|
99
|
+
if (activeTab) {
|
|
100
|
+
tabMeta = activeTab.getBoundingClientRect();
|
|
101
|
+
}
|
|
102
|
+
return { tabsMeta, tabMeta };
|
|
103
|
+
});
|
|
104
|
+
const updateIndicatorState = (0, import_utils.useEventCallback)(() => {
|
|
105
|
+
const { tabsMeta, tabMeta } = getTabsMeta();
|
|
106
|
+
if (!tabMeta || !tabsMeta) {
|
|
107
|
+
setIndicatorStyle(null);
|
|
69
108
|
return;
|
|
109
|
+
}
|
|
110
|
+
const tabLeft = tabMeta.left - tabsMeta.left + tabsMeta.scrollLeft;
|
|
111
|
+
const tabWidth = tabMeta.width;
|
|
112
|
+
const indicatorWidth = getIndicatorWidth();
|
|
113
|
+
const leftPosition = tabLeft + (tabWidth - indicatorWidth) / 2;
|
|
114
|
+
const newIndicatorStyle = {
|
|
115
|
+
left: leftPosition
|
|
116
|
+
};
|
|
117
|
+
if (indicatorStyle === null) {
|
|
118
|
+
setIndicatorStyle(newIndicatorStyle);
|
|
119
|
+
} else {
|
|
120
|
+
const dLeft = Math.abs(indicatorStyle.left - newIndicatorStyle.left);
|
|
121
|
+
if (dLeft >= 1) {
|
|
122
|
+
setIndicatorStyle(newIndicatorStyle);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
70
125
|
const activeTab = getActiveTabElement(currentValue);
|
|
71
126
|
if (activeTab) {
|
|
72
|
-
const
|
|
73
|
-
const activeTabWidth = activeTab.offsetWidth;
|
|
74
|
-
const containerWidth = tabsEl.offsetWidth;
|
|
75
|
-
const containerScrollWidth = tabsEl.scrollWidth;
|
|
76
|
-
const activeLineWidth = indicator.offsetWidth;
|
|
77
|
-
const x = activeTabLeft + (activeTabWidth - activeLineWidth) / 2;
|
|
78
|
-
indicator.style.transform = `translate(${x}px, 0px)`;
|
|
79
|
-
indicator.style.visibility = "visible";
|
|
80
|
-
const maxScrollDistance = containerScrollWidth - containerWidth;
|
|
127
|
+
const maxScrollDistance = tabsMeta.scrollWidth - tabsMeta.clientWidth;
|
|
81
128
|
if (maxScrollDistance > 0 && !import_utils.isMini) {
|
|
82
|
-
scrollIntoView(activeTab);
|
|
129
|
+
scrollIntoView(activeTab, hasRenderedOnce.current);
|
|
83
130
|
}
|
|
84
|
-
|
|
85
|
-
indicator.style.visibility = "hidden";
|
|
131
|
+
hasRenderedOnce.current = true;
|
|
86
132
|
}
|
|
87
133
|
});
|
|
88
134
|
(0, import_react.useEffect)(() => {
|
|
89
|
-
|
|
90
|
-
}
|
|
135
|
+
updateIndicatorState();
|
|
136
|
+
});
|
|
91
137
|
(0, import_react.useEffect)(() => {
|
|
92
138
|
const handleResize = (0, import_utils.debounce)(() => {
|
|
93
|
-
|
|
139
|
+
indicatorWidthCache.current = null;
|
|
140
|
+
updateIndicatorState();
|
|
94
141
|
}, 100);
|
|
95
142
|
window.addEventListener("resize", handleResize);
|
|
96
143
|
return () => {
|
|
97
144
|
window.removeEventListener("resize", handleResize);
|
|
98
145
|
};
|
|
99
|
-
}, [
|
|
146
|
+
}, [updateIndicatorState]);
|
|
147
|
+
if (!indicatorStyle) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
100
150
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
101
151
|
"div",
|
|
102
152
|
{
|
|
103
153
|
ref: indicatorRef,
|
|
104
154
|
className: (0, import_clsx.default)(`${rootClass}-indicator`),
|
|
105
|
-
style:
|
|
106
|
-
transition: "transform 0.3s ease-in-out",
|
|
107
|
-
transform: "translate(0px, 0px)",
|
|
108
|
-
visibility: "hidden"
|
|
109
|
-
},
|
|
155
|
+
style: indicatorStyle,
|
|
110
156
|
"aria-hidden": "true"
|
|
111
157
|
}
|
|
112
158
|
);
|
package/dist/Tabs/TabMask.d.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export interface TabMaskProps {
|
|
3
|
-
/** Tabs 容器的引用,用于监听滚动 */
|
|
4
|
-
tabsContainerRef: React.RefObject<HTMLDivElement>;
|
|
5
3
|
/** 位置:左侧或右侧 */
|
|
6
4
|
position: 'left' | 'right';
|
|
7
5
|
}
|
|
8
|
-
declare const
|
|
9
|
-
export default
|
|
6
|
+
declare const _default: React.NamedExoticComponent<TabMaskProps>;
|
|
7
|
+
export default _default;
|
package/dist/Tabs/TabMask.js
CHANGED
|
@@ -32,57 +32,16 @@ __export(TabMask_exports, {
|
|
|
32
32
|
module.exports = __toCommonJS(TabMask_exports);
|
|
33
33
|
var import_react = __toESM(require("react"));
|
|
34
34
|
var import_clsx = __toESM(require("clsx"));
|
|
35
|
-
var
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const tabsEl = tabsContainerRef.current;
|
|
43
|
-
const mask = maskRef.current;
|
|
44
|
-
if (!tabsEl || !mask)
|
|
45
|
-
return;
|
|
46
|
-
const { scrollLeft, scrollWidth, offsetWidth } = tabsEl;
|
|
47
|
-
let shouldShow = false;
|
|
48
|
-
if (position === "left") {
|
|
49
|
-
shouldShow = scrollLeft > 0;
|
|
50
|
-
} else {
|
|
51
|
-
const rightRange = Math.abs(
|
|
52
|
-
scrollWidth - (scrollLeft + offsetWidth)
|
|
53
|
-
);
|
|
54
|
-
shouldShow = rightRange > 1;
|
|
55
|
-
}
|
|
56
|
-
mask.style.opacity = shouldShow ? "1" : "0";
|
|
57
|
-
},
|
|
58
|
-
100,
|
|
59
|
-
{
|
|
60
|
-
trailing: true,
|
|
61
|
-
leading: true
|
|
62
|
-
}
|
|
35
|
+
var import_classes = require("./classes");
|
|
36
|
+
const TabMask = ({ position }) => /* @__PURE__ */ import_react.default.createElement(
|
|
37
|
+
"div",
|
|
38
|
+
{
|
|
39
|
+
className: (0, import_clsx.default)(
|
|
40
|
+
import_classes.tabMaskClass,
|
|
41
|
+
position === "left" ? import_classes.tabMaskLeftClass : import_classes.tabMaskRightClass
|
|
63
42
|
),
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return void 0;
|
|
70
|
-
updateMaskOpacity();
|
|
71
|
-
tabsEl.addEventListener("scroll", updateMaskOpacity);
|
|
72
|
-
return () => {
|
|
73
|
-
tabsEl.removeEventListener("scroll", updateMaskOpacity);
|
|
74
|
-
};
|
|
75
|
-
}, [tabsContainerRef, updateMaskOpacity]);
|
|
76
|
-
return /* @__PURE__ */ import_react.default.createElement(
|
|
77
|
-
"div",
|
|
78
|
-
{
|
|
79
|
-
ref: maskRef,
|
|
80
|
-
className: (0, import_clsx.default)(`${rootClass}-mask`, `${rootClass}-mask-${position}`),
|
|
81
|
-
style: {
|
|
82
|
-
opacity: 0
|
|
83
|
-
},
|
|
84
|
-
"aria-hidden": "true"
|
|
85
|
-
}
|
|
86
|
-
);
|
|
87
|
-
};
|
|
88
|
-
var TabMask_default = TabMask;
|
|
43
|
+
"aria-hidden": "true"
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
TabMask.displayName = "BuiTabsMask";
|
|
47
|
+
var TabMask_default = /* @__PURE__ */ import_react.default.memo(TabMask);
|
package/dist/Tabs/Tabs.css
CHANGED
|
@@ -49,7 +49,6 @@ xhs-page {
|
|
|
49
49
|
position: absolute;
|
|
50
50
|
top: unset;
|
|
51
51
|
bottom: var(--bui-tabs-indicator-bottom, 0);
|
|
52
|
-
left: 0;
|
|
53
52
|
width: var(--bui-tabs-indicator-width);
|
|
54
53
|
height: var(--bui-tabs-indicator-height);
|
|
55
54
|
color: var(--bui-color-primary);
|
|
@@ -58,6 +57,7 @@ xhs-page {
|
|
|
58
57
|
box-shadow: var(--bui-tabs-indicator-box-shadow);
|
|
59
58
|
z-index: 1;
|
|
60
59
|
pointer-events: none;
|
|
60
|
+
transition: left 0.3s ease-in-out;
|
|
61
61
|
}
|
|
62
62
|
.bui-tabs-content {
|
|
63
63
|
padding: var(--bui-spacing-lg);
|
package/dist/Tabs/Tabs.js
CHANGED
|
@@ -103,6 +103,7 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
|
|
|
103
103
|
{}
|
|
104
104
|
);
|
|
105
105
|
const [registrationVersion, setRegistrationVersion] = (0, import_react.useState)(0);
|
|
106
|
+
const [isScrollable, setIsScrollable] = (0, import_react.useState)(false);
|
|
106
107
|
if (process.env.NODE_ENV !== "production") {
|
|
107
108
|
if (tabs.length > 0 && import_react.default.Children.count(children) > 0) {
|
|
108
109
|
console.warn(
|
|
@@ -147,10 +148,21 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
|
|
|
147
148
|
}
|
|
148
149
|
return children;
|
|
149
150
|
}, [tabs, children]);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
(0, import_react.useEffect)(() => {
|
|
152
|
+
const tabsEl = tabsRef.current;
|
|
153
|
+
if (!tabsEl)
|
|
154
|
+
return;
|
|
155
|
+
const checkScrollable = () => {
|
|
156
|
+
setIsScrollable(tabsEl.scrollWidth > tabsEl.offsetWidth);
|
|
157
|
+
};
|
|
158
|
+
checkScrollable();
|
|
159
|
+
const resizeObserver = new ResizeObserver(checkScrollable);
|
|
160
|
+
resizeObserver.observe(tabsEl);
|
|
161
|
+
return () => {
|
|
162
|
+
resizeObserver.disconnect();
|
|
163
|
+
};
|
|
164
|
+
}, [registrationVersion]);
|
|
165
|
+
return /* @__PURE__ */ import_react.default.createElement("div", __spreadProps(__spreadValues({ className: (0, import_clsx.default)(import_classes.tabsRootClass, className) }, others), { ref }), isScrollable && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_TabMask.default, { position: "left" }), /* @__PURE__ */ import_react.default.createElement(import_TabMask.default, { position: "right" })), /* @__PURE__ */ import_react.default.createElement(
|
|
154
166
|
"div",
|
|
155
167
|
{
|
|
156
168
|
className: `${import_classes.tabsRootClass}-tabs`,
|
|
@@ -163,8 +175,7 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
|
|
|
163
175
|
{
|
|
164
176
|
currentValue,
|
|
165
177
|
registeredTabs,
|
|
166
|
-
tabsContainerRef: tabsRef
|
|
167
|
-
registrationVersion
|
|
178
|
+
tabsContainerRef: tabsRef
|
|
168
179
|
}
|
|
169
180
|
),
|
|
170
181
|
/* @__PURE__ */ import_react.default.createElement(import_TabsContext.TabsContextProvider, { value: contextValue }, renderedTabs)
|
package/dist/Tabs/index.css
CHANGED
|
@@ -49,7 +49,6 @@ xhs-page {
|
|
|
49
49
|
position: absolute;
|
|
50
50
|
top: unset;
|
|
51
51
|
bottom: var(--bui-tabs-indicator-bottom, 0);
|
|
52
|
-
left: 0;
|
|
53
52
|
width: var(--bui-tabs-indicator-width);
|
|
54
53
|
height: var(--bui-tabs-indicator-height);
|
|
55
54
|
color: var(--bui-color-primary);
|
|
@@ -58,6 +57,7 @@ xhs-page {
|
|
|
58
57
|
box-shadow: var(--bui-tabs-indicator-box-shadow);
|
|
59
58
|
z-index: 1;
|
|
60
59
|
pointer-events: none;
|
|
60
|
+
transition: left 0.3s ease-in-out;
|
|
61
61
|
}
|
|
62
62
|
.bui-tabs-content {
|
|
63
63
|
padding: var(--bui-spacing-lg);
|
|
@@ -56,6 +56,9 @@ var import_taro = __toESM(require("@tarojs/taro"));
|
|
|
56
56
|
var import_utils = require("@bifrostui/utils");
|
|
57
57
|
var import_classes = require("../classes");
|
|
58
58
|
var import_queryBatch = require("./utils/queryBatch");
|
|
59
|
+
const isValidTabValue = (value) => {
|
|
60
|
+
return value !== void 0 && value !== null;
|
|
61
|
+
};
|
|
59
62
|
const TabIndicator = ({
|
|
60
63
|
currentValue,
|
|
61
64
|
registeredTabValues,
|
|
@@ -63,8 +66,7 @@ const TabIndicator = ({
|
|
|
63
66
|
scrollViewId,
|
|
64
67
|
registrationVersion
|
|
65
68
|
}) => {
|
|
66
|
-
const
|
|
67
|
-
const [visibility, setVisibility] = (0, import_react.useState)("hidden");
|
|
69
|
+
const indicatorRef = (0, import_react.useRef)(null);
|
|
68
70
|
const animationTimerRef = (0, import_react.useRef)(null);
|
|
69
71
|
const positionCacheRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
70
72
|
const containerInfoRef = (0, import_react.useRef)(null);
|
|
@@ -72,14 +74,20 @@ const TabIndicator = ({
|
|
|
72
74
|
const isInitializedRef = (0, import_react.useRef)(false);
|
|
73
75
|
const initRetryCountRef = (0, import_react.useRef)(0);
|
|
74
76
|
const maxInitRetries = 5;
|
|
77
|
+
const isInitializingRef = (0, import_react.useRef)(false);
|
|
78
|
+
const initVersionRef = (0, import_react.useRef)(0);
|
|
79
|
+
const isMountedRef = (0, import_react.useRef)(true);
|
|
75
80
|
const updateIndicatorPosition = (0, import_utils.useEventCallback)(() => {
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
const indicator = indicatorRef.current;
|
|
82
|
+
if (!indicator)
|
|
83
|
+
return;
|
|
84
|
+
if (!isValidTabValue(currentValue) || !registeredTabValues.includes(currentValue)) {
|
|
85
|
+
indicator.style.opacity = "0";
|
|
78
86
|
return;
|
|
79
87
|
}
|
|
80
88
|
const cachedPosition = positionCacheRef.current.get(currentValue);
|
|
81
89
|
const containerInfo = containerInfoRef.current;
|
|
82
|
-
if (!cachedPosition || !containerInfo) {
|
|
90
|
+
if (!cachedPosition || !containerInfo || !isInitializedRef.current) {
|
|
83
91
|
if (!isInitializedRef.current) {
|
|
84
92
|
initializePositions();
|
|
85
93
|
}
|
|
@@ -89,16 +97,27 @@ const TabIndicator = ({
|
|
|
89
97
|
const activeTabWidth = cachedPosition.width;
|
|
90
98
|
const indicatorWidth = indicatorWidthRef.current;
|
|
91
99
|
const x = activeTabLeft + (activeTabWidth - indicatorWidth) / 2;
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
indicator.style.transform = `translate(${x}px, 0px)`;
|
|
101
|
+
indicator.style.opacity = "1";
|
|
94
102
|
});
|
|
95
103
|
const initializePositions = (0, import_utils.useEventCallback)(() => __async(void 0, null, function* () {
|
|
104
|
+
if (!isMountedRef.current)
|
|
105
|
+
return;
|
|
106
|
+
if (isInitializingRef.current)
|
|
107
|
+
return;
|
|
108
|
+
isInitializingRef.current = true;
|
|
109
|
+
initVersionRef.current += 1;
|
|
110
|
+
const currentVersion = initVersionRef.current;
|
|
96
111
|
try {
|
|
97
112
|
const result = yield (0, import_queryBatch.batchQueryTabs)({
|
|
98
113
|
scrollViewId,
|
|
99
114
|
wrapperId,
|
|
100
115
|
tabValues: registeredTabValues
|
|
101
116
|
});
|
|
117
|
+
if (!isMountedRef.current)
|
|
118
|
+
return;
|
|
119
|
+
if (currentVersion !== initVersionRef.current)
|
|
120
|
+
return;
|
|
102
121
|
const { scrollView, scrollFields, wrapper, indicator, tabs } = result;
|
|
103
122
|
if (!scrollView || !wrapper || !indicator || !scrollFields) {
|
|
104
123
|
if (initRetryCountRef.current < maxInitRetries) {
|
|
@@ -107,8 +126,30 @@ const TabIndicator = ({
|
|
|
107
126
|
clearTimeout(animationTimerRef.current);
|
|
108
127
|
}
|
|
109
128
|
animationTimerRef.current = setTimeout(() => {
|
|
129
|
+
if (!isMountedRef.current)
|
|
130
|
+
return;
|
|
131
|
+
isInitializingRef.current = false;
|
|
132
|
+
initializePositions();
|
|
133
|
+
}, 100);
|
|
134
|
+
} else {
|
|
135
|
+
isInitializingRef.current = false;
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (!indicator.width || indicator.width <= 0) {
|
|
140
|
+
if (initRetryCountRef.current < maxInitRetries) {
|
|
141
|
+
initRetryCountRef.current += 1;
|
|
142
|
+
if (animationTimerRef.current) {
|
|
143
|
+
clearTimeout(animationTimerRef.current);
|
|
144
|
+
}
|
|
145
|
+
animationTimerRef.current = setTimeout(() => {
|
|
146
|
+
if (!isMountedRef.current)
|
|
147
|
+
return;
|
|
148
|
+
isInitializingRef.current = false;
|
|
110
149
|
initializePositions();
|
|
111
150
|
}, 100);
|
|
151
|
+
} else {
|
|
152
|
+
isInitializingRef.current = false;
|
|
112
153
|
}
|
|
113
154
|
return;
|
|
114
155
|
}
|
|
@@ -121,9 +162,8 @@ const TabIndicator = ({
|
|
|
121
162
|
registeredTabValues.forEach((value, index) => {
|
|
122
163
|
const tabRect = tabs[index];
|
|
123
164
|
if (tabRect && tabRect.width > 0) {
|
|
124
|
-
const relativeLeft = tabRect.left - wrapper.left;
|
|
125
165
|
newCache.set(value, {
|
|
126
|
-
left:
|
|
166
|
+
left: tabRect.left - wrapper.left,
|
|
127
167
|
width: tabRect.width
|
|
128
168
|
});
|
|
129
169
|
}
|
|
@@ -135,40 +175,74 @@ const TabIndicator = ({
|
|
|
135
175
|
clearTimeout(animationTimerRef.current);
|
|
136
176
|
}
|
|
137
177
|
animationTimerRef.current = setTimeout(() => {
|
|
178
|
+
if (!isMountedRef.current)
|
|
179
|
+
return;
|
|
180
|
+
isInitializingRef.current = false;
|
|
138
181
|
initializePositions();
|
|
139
182
|
}, 100);
|
|
183
|
+
} else {
|
|
184
|
+
isInitializingRef.current = false;
|
|
140
185
|
}
|
|
141
186
|
return;
|
|
142
187
|
}
|
|
188
|
+
if (currentVersion !== initVersionRef.current || !isMountedRef.current) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
143
191
|
initRetryCountRef.current = 0;
|
|
144
192
|
positionCacheRef.current = newCache;
|
|
145
193
|
isInitializedRef.current = true;
|
|
194
|
+
isInitializingRef.current = false;
|
|
146
195
|
updateIndicatorPosition();
|
|
147
196
|
} catch (error) {
|
|
148
197
|
console.error("[TabIndicator] \u6279\u91CF\u67E5\u8BE2\u5931\u8D25:", error);
|
|
198
|
+
isInitializingRef.current = false;
|
|
199
|
+
if (isMountedRef.current && initRetryCountRef.current < maxInitRetries) {
|
|
200
|
+
initRetryCountRef.current += 1;
|
|
201
|
+
if (animationTimerRef.current) {
|
|
202
|
+
clearTimeout(animationTimerRef.current);
|
|
203
|
+
}
|
|
204
|
+
animationTimerRef.current = setTimeout(() => {
|
|
205
|
+
if (!isMountedRef.current)
|
|
206
|
+
return;
|
|
207
|
+
initializePositions();
|
|
208
|
+
}, 100);
|
|
209
|
+
}
|
|
149
210
|
}
|
|
150
211
|
}));
|
|
151
212
|
(0, import_react.useEffect)(() => {
|
|
152
213
|
if (registeredTabValues.length === 0) {
|
|
214
|
+
if (indicatorRef.current) {
|
|
215
|
+
indicatorRef.current.style.opacity = "0";
|
|
216
|
+
}
|
|
153
217
|
return void 0;
|
|
154
218
|
}
|
|
219
|
+
initVersionRef.current += 1;
|
|
155
220
|
if (animationTimerRef.current) {
|
|
156
221
|
clearTimeout(animationTimerRef.current);
|
|
222
|
+
animationTimerRef.current = null;
|
|
157
223
|
}
|
|
158
224
|
isInitializedRef.current = false;
|
|
225
|
+
isInitializingRef.current = false;
|
|
159
226
|
initRetryCountRef.current = 0;
|
|
160
227
|
import_taro.default.nextTick(() => {
|
|
228
|
+
if (!isMountedRef.current)
|
|
229
|
+
return;
|
|
161
230
|
initializePositions();
|
|
162
231
|
});
|
|
163
232
|
return () => {
|
|
164
233
|
if (animationTimerRef.current) {
|
|
165
234
|
clearTimeout(animationTimerRef.current);
|
|
235
|
+
animationTimerRef.current = null;
|
|
166
236
|
}
|
|
237
|
+
initVersionRef.current += 1;
|
|
238
|
+
isInitializingRef.current = false;
|
|
167
239
|
};
|
|
168
240
|
}, [registrationVersion, initializePositions]);
|
|
169
241
|
(0, import_react.useEffect)(() => {
|
|
170
|
-
if (!currentValue) {
|
|
171
|
-
|
|
242
|
+
if (!isValidTabValue(currentValue)) {
|
|
243
|
+
if (indicatorRef.current) {
|
|
244
|
+
indicatorRef.current.style.opacity = "0";
|
|
245
|
+
}
|
|
172
246
|
return;
|
|
173
247
|
}
|
|
174
248
|
updateIndicatorPosition();
|
|
@@ -176,10 +250,20 @@ const TabIndicator = ({
|
|
|
176
250
|
(0, import_react.useEffect)(() => {
|
|
177
251
|
var _a, _b;
|
|
178
252
|
const handleResize = () => {
|
|
253
|
+
if (!isMountedRef.current)
|
|
254
|
+
return;
|
|
255
|
+
initVersionRef.current += 1;
|
|
179
256
|
isInitializedRef.current = false;
|
|
257
|
+
isInitializingRef.current = false;
|
|
180
258
|
initRetryCountRef.current = 0;
|
|
181
259
|
positionCacheRef.current.clear();
|
|
260
|
+
if (animationTimerRef.current) {
|
|
261
|
+
clearTimeout(animationTimerRef.current);
|
|
262
|
+
animationTimerRef.current = null;
|
|
263
|
+
}
|
|
182
264
|
import_taro.default.nextTick(() => {
|
|
265
|
+
if (!isMountedRef.current)
|
|
266
|
+
return;
|
|
183
267
|
initializePositions();
|
|
184
268
|
});
|
|
185
269
|
};
|
|
@@ -189,15 +273,26 @@ const TabIndicator = ({
|
|
|
189
273
|
(_b2 = (_a2 = import_taro.default).offWindowResize) == null ? void 0 : _b2.call(_a2, handleResize);
|
|
190
274
|
};
|
|
191
275
|
}, [initializePositions]);
|
|
276
|
+
(0, import_react.useEffect)(() => {
|
|
277
|
+
isMountedRef.current = true;
|
|
278
|
+
return () => {
|
|
279
|
+
isMountedRef.current = false;
|
|
280
|
+
if (animationTimerRef.current) {
|
|
281
|
+
clearTimeout(animationTimerRef.current);
|
|
282
|
+
animationTimerRef.current = null;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}, []);
|
|
192
286
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
193
287
|
"div",
|
|
194
288
|
{
|
|
289
|
+
ref: indicatorRef,
|
|
195
290
|
id: `${wrapperId}-indicator`,
|
|
196
291
|
className: (0, import_clsx.default)(import_classes.tabIndicatorClass),
|
|
197
292
|
style: {
|
|
198
|
-
transition: "transform 0.3s ease-in-out",
|
|
199
|
-
transform,
|
|
200
|
-
|
|
293
|
+
transition: "transform 0.3s ease-in-out, opacity 0.3s ease-in-out",
|
|
294
|
+
transform: "translate(0px, 0px)",
|
|
295
|
+
opacity: 0
|
|
201
296
|
}
|
|
202
297
|
}
|
|
203
298
|
);
|
|
@@ -57,7 +57,7 @@ var import_components = require("@tarojs/components");
|
|
|
57
57
|
var import_utils = require("@bifrostui/utils");
|
|
58
58
|
var import_Tab = __toESM(require("./Tab"));
|
|
59
59
|
var import_TabIndicator = __toESM(require("./TabIndicator"));
|
|
60
|
-
var import_TabMask = __toESM(require("
|
|
60
|
+
var import_TabMask = __toESM(require("../TabMask"));
|
|
61
61
|
var import_TabsContext = require("./TabsContext");
|
|
62
62
|
var import_classes = require("../classes");
|
|
63
63
|
var import_queryBatch = require("./utils/queryBatch");
|
|
@@ -97,8 +97,10 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
|
|
|
97
97
|
const [scrollLeft, setScrollLeft] = (0, import_react.useState)(0);
|
|
98
98
|
const [containerWidth, setContainerWidth] = (0, import_react.useState)(0);
|
|
99
99
|
const [scrollWidth, setScrollWidth] = (0, import_react.useState)(0);
|
|
100
|
-
const scrollLeftUpdateTimerRef = import_react.default.useRef(null);
|
|
101
100
|
const lastScrollLeftRef = import_react.default.useRef(0);
|
|
101
|
+
const isFirstScroll = import_react.default.useRef(true);
|
|
102
|
+
const [scrollWithAnimation, setScrollWithAnimation] = import_react.default.useState(false);
|
|
103
|
+
const isScrollable = scrollWidth > containerWidth;
|
|
102
104
|
if (process.env.NODE_ENV !== "production") {
|
|
103
105
|
if (tabs.length > 0 && import_react.default.Children.count(children) > 0) {
|
|
104
106
|
console.warn(
|
|
@@ -138,14 +140,6 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
|
|
|
138
140
|
(e) => {
|
|
139
141
|
const { scrollLeft: newScrollLeft, scrollWidth: newScrollWidth } = e.detail;
|
|
140
142
|
lastScrollLeftRef.current = newScrollLeft;
|
|
141
|
-
if (scrollLeftUpdateTimerRef.current) {
|
|
142
|
-
clearTimeout(scrollLeftUpdateTimerRef.current);
|
|
143
|
-
}
|
|
144
|
-
scrollLeftUpdateTimerRef.current = setTimeout(() => {
|
|
145
|
-
if (Math.abs(lastScrollLeftRef.current - scrollLeft) > 1) {
|
|
146
|
-
setScrollLeft(lastScrollLeftRef.current);
|
|
147
|
-
}
|
|
148
|
-
}, 150);
|
|
149
143
|
if (newScrollWidth && newScrollWidth !== scrollWidth) {
|
|
150
144
|
setScrollWidth(newScrollWidth);
|
|
151
145
|
}
|
|
@@ -188,6 +182,12 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
|
|
|
188
182
|
);
|
|
189
183
|
setScrollLeft(finalScrollLeft);
|
|
190
184
|
lastScrollLeftRef.current = finalScrollLeft;
|
|
185
|
+
if (isFirstScroll.current) {
|
|
186
|
+
import_taro.default.nextTick(() => {
|
|
187
|
+
setScrollWithAnimation(true);
|
|
188
|
+
});
|
|
189
|
+
isFirstScroll.current = false;
|
|
190
|
+
}
|
|
191
191
|
}));
|
|
192
192
|
import_react.default.useEffect(() => {
|
|
193
193
|
if (!currentValue || registeredTabValues.length === 0) {
|
|
@@ -221,38 +221,14 @@ const Tabs = /* @__PURE__ */ import_react.default.forwardRef((props, ref) => {
|
|
|
221
221
|
}
|
|
222
222
|
return children;
|
|
223
223
|
}, [tabs, children]);
|
|
224
|
-
import_react.default.
|
|
225
|
-
return () => {
|
|
226
|
-
if (scrollLeftUpdateTimerRef.current) {
|
|
227
|
-
clearTimeout(scrollLeftUpdateTimerRef.current);
|
|
228
|
-
}
|
|
229
|
-
};
|
|
230
|
-
}, []);
|
|
231
|
-
return /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_clsx.default)(import_classes.tabsRootClass, className), style, ref }, /* @__PURE__ */ import_react.default.createElement(
|
|
232
|
-
import_TabMask.default,
|
|
233
|
-
{
|
|
234
|
-
position: "left",
|
|
235
|
-
scrollLeft,
|
|
236
|
-
containerWidth,
|
|
237
|
-
scrollWidth
|
|
238
|
-
}
|
|
239
|
-
), /* @__PURE__ */ import_react.default.createElement(
|
|
240
|
-
import_TabMask.default,
|
|
241
|
-
{
|
|
242
|
-
position: "right",
|
|
243
|
-
scrollLeft,
|
|
244
|
-
containerWidth,
|
|
245
|
-
scrollWidth
|
|
246
|
-
}
|
|
247
|
-
), /* @__PURE__ */ import_react.default.createElement(
|
|
224
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_clsx.default)(import_classes.tabsRootClass, className), style, ref }, isScrollable && /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement(import_TabMask.default, { position: "left" }), /* @__PURE__ */ import_react.default.createElement(import_TabMask.default, { position: "right" })), /* @__PURE__ */ import_react.default.createElement(
|
|
248
225
|
import_components.ScrollView,
|
|
249
226
|
{
|
|
250
227
|
id: scrollViewId,
|
|
251
228
|
className: import_classes.tabsScrollClass,
|
|
252
229
|
scrollX: true,
|
|
253
|
-
scrollWithAnimation
|
|
230
|
+
scrollWithAnimation,
|
|
254
231
|
scrollLeft,
|
|
255
|
-
scrollAnimationDuration: "200",
|
|
256
232
|
onScroll: handleScroll,
|
|
257
233
|
enhanced: true,
|
|
258
234
|
showScrollbar: false,
|
|
@@ -12,5 +12,5 @@ declare const Modal: React.ForwardRefExoticComponent<Omit<ViewProps & {
|
|
|
12
12
|
keepMounted?: boolean;
|
|
13
13
|
} & import("@bifrostui/types").ICommonProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
14
14
|
ref?: React.Ref<HTMLDivElement>;
|
|
15
|
-
}, keyof import("@bifrostui/types").ICommonProps | "
|
|
15
|
+
}, keyof import("@bifrostui/types").ICommonProps | "keepMounted" | "container" | "disablePortal" | "open" | "hideBackdrop" | "BackdropProps" | "onClose" | "disableScrollLock">, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
16
16
|
export default Modal;
|