@bifrostui/react 2.0.0-alpha.17 → 2.0.0-alpha.18
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/DatePicker/DatePicker.d.ts +1 -1
- package/dist/Modal/Modal.miniapp.d.ts +1 -1
- package/dist/Tabs/TabIndicator.js +23 -12
- package/dist/Tabs/TabMask.d.ts +2 -4
- package/dist/Tabs/TabMask.js +12 -53
- package/dist/Tabs/Tabs.js +16 -4
- package/dist/Tabs/miniapp/TabIndicator.js +124 -14
- package/dist/Tabs/miniapp/Tabs.js +12 -36
- package/es/Modal/Modal.miniapp.d.ts +1 -1
- package/es/Tabs/TabIndicator.js +23 -12
- package/es/Tabs/TabMask.d.ts +2 -4
- package/es/Tabs/TabMask.js +13 -54
- package/es/Tabs/Tabs.js +17 -5
- package/es/Tabs/miniapp/TabIndicator.js +125 -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
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { DatePickerProps } from './DatePicker.types';
|
|
3
|
-
declare const DatePicker: React.ForwardRefExoticComponent<Omit<DatePickerProps<"div", Omit<import("../Picker").PickerProps<"div", import("..").DrawerProps>, "
|
|
3
|
+
declare const DatePicker: React.ForwardRefExoticComponent<Omit<DatePickerProps<"div", Omit<import("../Picker").PickerProps<"div", import("..").DrawerProps>, "defaultValue" | "onChange" | "value" | "onClose" | "onConfirm">>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
4
4
|
export default DatePicker;
|
|
@@ -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 | "open" | "
|
|
15
|
+
}, keyof import("@bifrostui/types").ICommonProps | "open" | "onClose" | "container" | "disableScrollLock" | "disablePortal" | "hideBackdrop" | "BackdropProps" | "keepMounted">, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
16
16
|
export default Modal;
|
|
@@ -43,23 +43,26 @@ const TabIndicator = ({
|
|
|
43
43
|
registrationVersion
|
|
44
44
|
}) => {
|
|
45
45
|
const indicatorRef = (0, import_react.useRef)(null);
|
|
46
|
+
const isFirstRender = (0, import_react.useRef)(true);
|
|
46
47
|
const getActiveTabElement = (0, import_utils.useEventCallback)(
|
|
47
48
|
(activeValue) => {
|
|
48
49
|
const tabRef = registeredTabs.current[activeValue];
|
|
49
50
|
return tabRef == null ? void 0 : tabRef.current;
|
|
50
51
|
}
|
|
51
52
|
);
|
|
52
|
-
const scrollIntoView = (0, import_utils.useEventCallback)(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const scrollIntoView = (0, import_utils.useEventCallback)(
|
|
54
|
+
(activeTab, animate2 = true) => {
|
|
55
|
+
const tabsEl = tabsContainerRef.current;
|
|
56
|
+
if (!tabsEl || !activeTab) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
(0, import_scroll.default)(
|
|
60
|
+
tabsEl,
|
|
61
|
+
activeTab.offsetLeft - (tabsEl.offsetWidth - activeTab.offsetWidth) / 2,
|
|
62
|
+
animate2 ? duration : 0
|
|
63
|
+
);
|
|
56
64
|
}
|
|
57
|
-
|
|
58
|
-
tabsEl,
|
|
59
|
-
activeTab.offsetLeft - (tabsEl.offsetWidth - activeTab.offsetWidth) / 2,
|
|
60
|
-
duration
|
|
61
|
-
);
|
|
62
|
-
});
|
|
65
|
+
);
|
|
63
66
|
const animate = (0, import_utils.useEventCallback)(() => {
|
|
64
67
|
const tabsEl = tabsContainerRef.current;
|
|
65
68
|
if (!tabsEl)
|
|
@@ -79,7 +82,15 @@ const TabIndicator = ({
|
|
|
79
82
|
indicator.style.visibility = "visible";
|
|
80
83
|
const maxScrollDistance = containerScrollWidth - containerWidth;
|
|
81
84
|
if (maxScrollDistance > 0 && !import_utils.isMini) {
|
|
82
|
-
scrollIntoView(activeTab);
|
|
85
|
+
scrollIntoView(activeTab, !isFirstRender.current);
|
|
86
|
+
}
|
|
87
|
+
if (isFirstRender.current) {
|
|
88
|
+
isFirstRender.current = false;
|
|
89
|
+
requestAnimationFrame(() => {
|
|
90
|
+
if (indicator) {
|
|
91
|
+
indicator.style.transition = "transform 0.3s ease-in-out";
|
|
92
|
+
}
|
|
93
|
+
});
|
|
83
94
|
}
|
|
84
95
|
} else {
|
|
85
96
|
indicator.style.visibility = "hidden";
|
|
@@ -103,7 +114,7 @@ const TabIndicator = ({
|
|
|
103
114
|
ref: indicatorRef,
|
|
104
115
|
className: (0, import_clsx.default)(`${rootClass}-indicator`),
|
|
105
116
|
style: {
|
|
106
|
-
transition: "
|
|
117
|
+
transition: "none",
|
|
107
118
|
transform: "translate(0px, 0px)",
|
|
108
119
|
visibility: "hidden"
|
|
109
120
|
},
|
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.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`,
|
|
@@ -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,21 @@ 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 isFirstRender = (0, import_react.useRef)(true);
|
|
78
|
+
const isInitializingRef = (0, import_react.useRef)(false);
|
|
79
|
+
const initVersionRef = (0, import_react.useRef)(0);
|
|
80
|
+
const isMountedRef = (0, import_react.useRef)(true);
|
|
75
81
|
const updateIndicatorPosition = (0, import_utils.useEventCallback)(() => {
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
const indicator = indicatorRef.current;
|
|
83
|
+
if (!indicator)
|
|
84
|
+
return;
|
|
85
|
+
if (!isValidTabValue(currentValue) || !registeredTabValues.includes(currentValue)) {
|
|
86
|
+
indicator.style.visibility = "hidden";
|
|
78
87
|
return;
|
|
79
88
|
}
|
|
80
89
|
const cachedPosition = positionCacheRef.current.get(currentValue);
|
|
81
90
|
const containerInfo = containerInfoRef.current;
|
|
82
|
-
if (!cachedPosition || !containerInfo) {
|
|
91
|
+
if (!cachedPosition || !containerInfo || !isInitializedRef.current) {
|
|
83
92
|
if (!isInitializedRef.current) {
|
|
84
93
|
initializePositions();
|
|
85
94
|
}
|
|
@@ -89,16 +98,41 @@ const TabIndicator = ({
|
|
|
89
98
|
const activeTabWidth = cachedPosition.width;
|
|
90
99
|
const indicatorWidth = indicatorWidthRef.current;
|
|
91
100
|
const x = activeTabLeft + (activeTabWidth - indicatorWidth) / 2;
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
indicator.style.transform = `translate(${x}px, 0px)`;
|
|
102
|
+
if (isFirstRender.current) {
|
|
103
|
+
import_taro.default.nextTick(() => {
|
|
104
|
+
if (!isMountedRef.current || !indicatorRef.current)
|
|
105
|
+
return;
|
|
106
|
+
indicatorRef.current.style.visibility = "visible";
|
|
107
|
+
import_taro.default.nextTick(() => {
|
|
108
|
+
if (!isMountedRef.current || !indicatorRef.current)
|
|
109
|
+
return;
|
|
110
|
+
indicatorRef.current.style.transition = "transform 0.3s ease-in-out";
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
isFirstRender.current = false;
|
|
114
|
+
} else {
|
|
115
|
+
indicator.style.visibility = "visible";
|
|
116
|
+
}
|
|
94
117
|
});
|
|
95
118
|
const initializePositions = (0, import_utils.useEventCallback)(() => __async(void 0, null, function* () {
|
|
119
|
+
if (!isMountedRef.current)
|
|
120
|
+
return;
|
|
121
|
+
if (isInitializingRef.current)
|
|
122
|
+
return;
|
|
123
|
+
isInitializingRef.current = true;
|
|
124
|
+
initVersionRef.current += 1;
|
|
125
|
+
const currentVersion = initVersionRef.current;
|
|
96
126
|
try {
|
|
97
127
|
const result = yield (0, import_queryBatch.batchQueryTabs)({
|
|
98
128
|
scrollViewId,
|
|
99
129
|
wrapperId,
|
|
100
130
|
tabValues: registeredTabValues
|
|
101
131
|
});
|
|
132
|
+
if (!isMountedRef.current)
|
|
133
|
+
return;
|
|
134
|
+
if (currentVersion !== initVersionRef.current)
|
|
135
|
+
return;
|
|
102
136
|
const { scrollView, scrollFields, wrapper, indicator, tabs } = result;
|
|
103
137
|
if (!scrollView || !wrapper || !indicator || !scrollFields) {
|
|
104
138
|
if (initRetryCountRef.current < maxInitRetries) {
|
|
@@ -107,8 +141,30 @@ const TabIndicator = ({
|
|
|
107
141
|
clearTimeout(animationTimerRef.current);
|
|
108
142
|
}
|
|
109
143
|
animationTimerRef.current = setTimeout(() => {
|
|
144
|
+
if (!isMountedRef.current)
|
|
145
|
+
return;
|
|
146
|
+
isInitializingRef.current = false;
|
|
110
147
|
initializePositions();
|
|
111
148
|
}, 100);
|
|
149
|
+
} else {
|
|
150
|
+
isInitializingRef.current = false;
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!indicator.width || indicator.width <= 0) {
|
|
155
|
+
if (initRetryCountRef.current < maxInitRetries) {
|
|
156
|
+
initRetryCountRef.current += 1;
|
|
157
|
+
if (animationTimerRef.current) {
|
|
158
|
+
clearTimeout(animationTimerRef.current);
|
|
159
|
+
}
|
|
160
|
+
animationTimerRef.current = setTimeout(() => {
|
|
161
|
+
if (!isMountedRef.current)
|
|
162
|
+
return;
|
|
163
|
+
isInitializingRef.current = false;
|
|
164
|
+
initializePositions();
|
|
165
|
+
}, 100);
|
|
166
|
+
} else {
|
|
167
|
+
isInitializingRef.current = false;
|
|
112
168
|
}
|
|
113
169
|
return;
|
|
114
170
|
}
|
|
@@ -121,9 +177,8 @@ const TabIndicator = ({
|
|
|
121
177
|
registeredTabValues.forEach((value, index) => {
|
|
122
178
|
const tabRect = tabs[index];
|
|
123
179
|
if (tabRect && tabRect.width > 0) {
|
|
124
|
-
const relativeLeft = tabRect.left - wrapper.left;
|
|
125
180
|
newCache.set(value, {
|
|
126
|
-
left:
|
|
181
|
+
left: tabRect.left - wrapper.left,
|
|
127
182
|
width: tabRect.width
|
|
128
183
|
});
|
|
129
184
|
}
|
|
@@ -135,40 +190,74 @@ const TabIndicator = ({
|
|
|
135
190
|
clearTimeout(animationTimerRef.current);
|
|
136
191
|
}
|
|
137
192
|
animationTimerRef.current = setTimeout(() => {
|
|
193
|
+
if (!isMountedRef.current)
|
|
194
|
+
return;
|
|
195
|
+
isInitializingRef.current = false;
|
|
138
196
|
initializePositions();
|
|
139
197
|
}, 100);
|
|
198
|
+
} else {
|
|
199
|
+
isInitializingRef.current = false;
|
|
140
200
|
}
|
|
141
201
|
return;
|
|
142
202
|
}
|
|
203
|
+
if (currentVersion !== initVersionRef.current || !isMountedRef.current) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
143
206
|
initRetryCountRef.current = 0;
|
|
144
207
|
positionCacheRef.current = newCache;
|
|
145
208
|
isInitializedRef.current = true;
|
|
209
|
+
isInitializingRef.current = false;
|
|
146
210
|
updateIndicatorPosition();
|
|
147
211
|
} catch (error) {
|
|
148
212
|
console.error("[TabIndicator] \u6279\u91CF\u67E5\u8BE2\u5931\u8D25:", error);
|
|
213
|
+
isInitializingRef.current = false;
|
|
214
|
+
if (isMountedRef.current && initRetryCountRef.current < maxInitRetries) {
|
|
215
|
+
initRetryCountRef.current += 1;
|
|
216
|
+
if (animationTimerRef.current) {
|
|
217
|
+
clearTimeout(animationTimerRef.current);
|
|
218
|
+
}
|
|
219
|
+
animationTimerRef.current = setTimeout(() => {
|
|
220
|
+
if (!isMountedRef.current)
|
|
221
|
+
return;
|
|
222
|
+
initializePositions();
|
|
223
|
+
}, 100);
|
|
224
|
+
}
|
|
149
225
|
}
|
|
150
226
|
}));
|
|
151
227
|
(0, import_react.useEffect)(() => {
|
|
152
228
|
if (registeredTabValues.length === 0) {
|
|
229
|
+
if (indicatorRef.current) {
|
|
230
|
+
indicatorRef.current.style.visibility = "hidden";
|
|
231
|
+
}
|
|
153
232
|
return void 0;
|
|
154
233
|
}
|
|
234
|
+
initVersionRef.current += 1;
|
|
155
235
|
if (animationTimerRef.current) {
|
|
156
236
|
clearTimeout(animationTimerRef.current);
|
|
237
|
+
animationTimerRef.current = null;
|
|
157
238
|
}
|
|
158
239
|
isInitializedRef.current = false;
|
|
240
|
+
isInitializingRef.current = false;
|
|
159
241
|
initRetryCountRef.current = 0;
|
|
160
242
|
import_taro.default.nextTick(() => {
|
|
243
|
+
if (!isMountedRef.current)
|
|
244
|
+
return;
|
|
161
245
|
initializePositions();
|
|
162
246
|
});
|
|
163
247
|
return () => {
|
|
164
248
|
if (animationTimerRef.current) {
|
|
165
249
|
clearTimeout(animationTimerRef.current);
|
|
250
|
+
animationTimerRef.current = null;
|
|
166
251
|
}
|
|
252
|
+
initVersionRef.current += 1;
|
|
253
|
+
isInitializingRef.current = false;
|
|
167
254
|
};
|
|
168
255
|
}, [registrationVersion, initializePositions]);
|
|
169
256
|
(0, import_react.useEffect)(() => {
|
|
170
|
-
if (!currentValue) {
|
|
171
|
-
|
|
257
|
+
if (!isValidTabValue(currentValue)) {
|
|
258
|
+
if (indicatorRef.current) {
|
|
259
|
+
indicatorRef.current.style.visibility = "hidden";
|
|
260
|
+
}
|
|
172
261
|
return;
|
|
173
262
|
}
|
|
174
263
|
updateIndicatorPosition();
|
|
@@ -176,10 +265,20 @@ const TabIndicator = ({
|
|
|
176
265
|
(0, import_react.useEffect)(() => {
|
|
177
266
|
var _a, _b;
|
|
178
267
|
const handleResize = () => {
|
|
268
|
+
if (!isMountedRef.current)
|
|
269
|
+
return;
|
|
270
|
+
initVersionRef.current += 1;
|
|
179
271
|
isInitializedRef.current = false;
|
|
272
|
+
isInitializingRef.current = false;
|
|
180
273
|
initRetryCountRef.current = 0;
|
|
181
274
|
positionCacheRef.current.clear();
|
|
275
|
+
if (animationTimerRef.current) {
|
|
276
|
+
clearTimeout(animationTimerRef.current);
|
|
277
|
+
animationTimerRef.current = null;
|
|
278
|
+
}
|
|
182
279
|
import_taro.default.nextTick(() => {
|
|
280
|
+
if (!isMountedRef.current)
|
|
281
|
+
return;
|
|
183
282
|
initializePositions();
|
|
184
283
|
});
|
|
185
284
|
};
|
|
@@ -189,15 +288,26 @@ const TabIndicator = ({
|
|
|
189
288
|
(_b2 = (_a2 = import_taro.default).offWindowResize) == null ? void 0 : _b2.call(_a2, handleResize);
|
|
190
289
|
};
|
|
191
290
|
}, [initializePositions]);
|
|
291
|
+
(0, import_react.useEffect)(() => {
|
|
292
|
+
isMountedRef.current = true;
|
|
293
|
+
return () => {
|
|
294
|
+
isMountedRef.current = false;
|
|
295
|
+
if (animationTimerRef.current) {
|
|
296
|
+
clearTimeout(animationTimerRef.current);
|
|
297
|
+
animationTimerRef.current = null;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
}, []);
|
|
192
301
|
return /* @__PURE__ */ import_react.default.createElement(
|
|
193
302
|
"div",
|
|
194
303
|
{
|
|
304
|
+
ref: indicatorRef,
|
|
195
305
|
id: `${wrapperId}-indicator`,
|
|
196
306
|
className: (0, import_clsx.default)(import_classes.tabIndicatorClass),
|
|
197
307
|
style: {
|
|
198
|
-
transition: "
|
|
199
|
-
transform,
|
|
200
|
-
visibility
|
|
308
|
+
transition: "none",
|
|
309
|
+
transform: "translate(0px, 0px)",
|
|
310
|
+
visibility: "hidden"
|
|
201
311
|
}
|
|
202
312
|
}
|
|
203
313
|
);
|
|
@@ -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
|
+
}, "open" | "container" | keyof import("@bifrostui/types").ICommonProps | "disablePortal" | "hideBackdrop" | "BackdropProps" | "onClose" | "disableScrollLock" | "keepMounted">, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
16
16
|
export default Modal;
|
package/es/Tabs/TabIndicator.js
CHANGED
|
@@ -11,23 +11,26 @@ const TabIndicator = ({
|
|
|
11
11
|
registrationVersion
|
|
12
12
|
}) => {
|
|
13
13
|
const indicatorRef = useRef(null);
|
|
14
|
+
const isFirstRender = useRef(true);
|
|
14
15
|
const getActiveTabElement = useEventCallback(
|
|
15
16
|
(activeValue) => {
|
|
16
17
|
const tabRef = registeredTabs.current[activeValue];
|
|
17
18
|
return tabRef == null ? void 0 : tabRef.current;
|
|
18
19
|
}
|
|
19
20
|
);
|
|
20
|
-
const scrollIntoView = useEventCallback(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
const scrollIntoView = useEventCallback(
|
|
22
|
+
(activeTab, animate2 = true) => {
|
|
23
|
+
const tabsEl = tabsContainerRef.current;
|
|
24
|
+
if (!tabsEl || !activeTab) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
scrollLeftTo(
|
|
28
|
+
tabsEl,
|
|
29
|
+
activeTab.offsetLeft - (tabsEl.offsetWidth - activeTab.offsetWidth) / 2,
|
|
30
|
+
animate2 ? duration : 0
|
|
31
|
+
);
|
|
24
32
|
}
|
|
25
|
-
|
|
26
|
-
tabsEl,
|
|
27
|
-
activeTab.offsetLeft - (tabsEl.offsetWidth - activeTab.offsetWidth) / 2,
|
|
28
|
-
duration
|
|
29
|
-
);
|
|
30
|
-
});
|
|
33
|
+
);
|
|
31
34
|
const animate = useEventCallback(() => {
|
|
32
35
|
const tabsEl = tabsContainerRef.current;
|
|
33
36
|
if (!tabsEl)
|
|
@@ -47,7 +50,15 @@ const TabIndicator = ({
|
|
|
47
50
|
indicator.style.visibility = "visible";
|
|
48
51
|
const maxScrollDistance = containerScrollWidth - containerWidth;
|
|
49
52
|
if (maxScrollDistance > 0 && !isMini) {
|
|
50
|
-
scrollIntoView(activeTab);
|
|
53
|
+
scrollIntoView(activeTab, !isFirstRender.current);
|
|
54
|
+
}
|
|
55
|
+
if (isFirstRender.current) {
|
|
56
|
+
isFirstRender.current = false;
|
|
57
|
+
requestAnimationFrame(() => {
|
|
58
|
+
if (indicator) {
|
|
59
|
+
indicator.style.transition = "transform 0.3s ease-in-out";
|
|
60
|
+
}
|
|
61
|
+
});
|
|
51
62
|
}
|
|
52
63
|
} else {
|
|
53
64
|
indicator.style.visibility = "hidden";
|
|
@@ -71,7 +82,7 @@ const TabIndicator = ({
|
|
|
71
82
|
ref: indicatorRef,
|
|
72
83
|
className: clsx(`${rootClass}-indicator`),
|
|
73
84
|
style: {
|
|
74
|
-
transition: "
|
|
85
|
+
transition: "none",
|
|
75
86
|
transform: "translate(0px, 0px)",
|
|
76
87
|
visibility: "hidden"
|
|
77
88
|
},
|
package/es/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/es/Tabs/TabMask.js
CHANGED
|
@@ -1,59 +1,18 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import clsx from "clsx";
|
|
3
|
-
import {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const tabsEl = tabsContainerRef.current;
|
|
11
|
-
const mask = maskRef.current;
|
|
12
|
-
if (!tabsEl || !mask)
|
|
13
|
-
return;
|
|
14
|
-
const { scrollLeft, scrollWidth, offsetWidth } = tabsEl;
|
|
15
|
-
let shouldShow = false;
|
|
16
|
-
if (position === "left") {
|
|
17
|
-
shouldShow = scrollLeft > 0;
|
|
18
|
-
} else {
|
|
19
|
-
const rightRange = Math.abs(
|
|
20
|
-
scrollWidth - (scrollLeft + offsetWidth)
|
|
21
|
-
);
|
|
22
|
-
shouldShow = rightRange > 1;
|
|
23
|
-
}
|
|
24
|
-
mask.style.opacity = shouldShow ? "1" : "0";
|
|
25
|
-
},
|
|
26
|
-
100,
|
|
27
|
-
{
|
|
28
|
-
trailing: true,
|
|
29
|
-
leading: true
|
|
30
|
-
}
|
|
3
|
+
import { tabMaskClass, tabMaskLeftClass, tabMaskRightClass } from "./classes";
|
|
4
|
+
const TabMask = ({ position }) => /* @__PURE__ */ React.createElement(
|
|
5
|
+
"div",
|
|
6
|
+
{
|
|
7
|
+
className: clsx(
|
|
8
|
+
tabMaskClass,
|
|
9
|
+
position === "left" ? tabMaskLeftClass : tabMaskRightClass
|
|
31
10
|
),
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return void 0;
|
|
38
|
-
updateMaskOpacity();
|
|
39
|
-
tabsEl.addEventListener("scroll", updateMaskOpacity);
|
|
40
|
-
return () => {
|
|
41
|
-
tabsEl.removeEventListener("scroll", updateMaskOpacity);
|
|
42
|
-
};
|
|
43
|
-
}, [tabsContainerRef, updateMaskOpacity]);
|
|
44
|
-
return /* @__PURE__ */ React.createElement(
|
|
45
|
-
"div",
|
|
46
|
-
{
|
|
47
|
-
ref: maskRef,
|
|
48
|
-
className: clsx(`${rootClass}-mask`, `${rootClass}-mask-${position}`),
|
|
49
|
-
style: {
|
|
50
|
-
opacity: 0
|
|
51
|
-
},
|
|
52
|
-
"aria-hidden": "true"
|
|
53
|
-
}
|
|
54
|
-
);
|
|
55
|
-
};
|
|
56
|
-
var TabMask_default = TabMask;
|
|
11
|
+
"aria-hidden": "true"
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
TabMask.displayName = "BuiTabsMask";
|
|
15
|
+
var TabMask_default = /* @__PURE__ */ React.memo(TabMask);
|
|
57
16
|
export {
|
|
58
17
|
TabMask_default as default
|
|
59
18
|
};
|
package/es/Tabs/Tabs.js
CHANGED
|
@@ -29,7 +29,7 @@ var __objRest = (source, exclude) => {
|
|
|
29
29
|
}
|
|
30
30
|
return target;
|
|
31
31
|
};
|
|
32
|
-
import React, { useMemo, useRef, useState } from "react";
|
|
32
|
+
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
33
33
|
import clsx from "clsx";
|
|
34
34
|
import { useValue, useEventCallback } from "@bifrostui/utils";
|
|
35
35
|
import Tab from "./Tab";
|
|
@@ -73,6 +73,7 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
73
73
|
{}
|
|
74
74
|
);
|
|
75
75
|
const [registrationVersion, setRegistrationVersion] = useState(0);
|
|
76
|
+
const [isScrollable, setIsScrollable] = useState(false);
|
|
76
77
|
if (process.env.NODE_ENV !== "production") {
|
|
77
78
|
if (tabs.length > 0 && React.Children.count(children) > 0) {
|
|
78
79
|
console.warn(
|
|
@@ -117,10 +118,21 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
117
118
|
}
|
|
118
119
|
return children;
|
|
119
120
|
}, [tabs, children]);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
const tabsEl = tabsRef.current;
|
|
123
|
+
if (!tabsEl)
|
|
124
|
+
return;
|
|
125
|
+
const checkScrollable = () => {
|
|
126
|
+
setIsScrollable(tabsEl.scrollWidth > tabsEl.offsetWidth);
|
|
127
|
+
};
|
|
128
|
+
checkScrollable();
|
|
129
|
+
const resizeObserver = new ResizeObserver(checkScrollable);
|
|
130
|
+
resizeObserver.observe(tabsEl);
|
|
131
|
+
return () => {
|
|
132
|
+
resizeObserver.disconnect();
|
|
133
|
+
};
|
|
134
|
+
}, [registrationVersion]);
|
|
135
|
+
return /* @__PURE__ */ React.createElement("div", __spreadProps(__spreadValues({ className: clsx(tabsRootClass, className) }, others), { ref }), isScrollable && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(TabMask, { position: "left" }), /* @__PURE__ */ React.createElement(TabMask, { position: "right" })), /* @__PURE__ */ React.createElement(
|
|
124
136
|
"div",
|
|
125
137
|
{
|
|
126
138
|
className: `${tabsRootClass}-tabs`,
|
|
@@ -18,12 +18,15 @@ var __async = (__this, __arguments, generator) => {
|
|
|
18
18
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
19
|
});
|
|
20
20
|
};
|
|
21
|
-
import React, { useEffect, useRef
|
|
21
|
+
import React, { useEffect, useRef } from "react";
|
|
22
22
|
import clsx from "clsx";
|
|
23
23
|
import Taro from "@tarojs/taro";
|
|
24
24
|
import { useEventCallback } from "@bifrostui/utils";
|
|
25
25
|
import { tabIndicatorClass } from "../classes";
|
|
26
26
|
import { batchQueryTabs } from "./utils/queryBatch";
|
|
27
|
+
const isValidTabValue = (value) => {
|
|
28
|
+
return value !== void 0 && value !== null;
|
|
29
|
+
};
|
|
27
30
|
const TabIndicator = ({
|
|
28
31
|
currentValue,
|
|
29
32
|
registeredTabValues,
|
|
@@ -31,8 +34,7 @@ const TabIndicator = ({
|
|
|
31
34
|
scrollViewId,
|
|
32
35
|
registrationVersion
|
|
33
36
|
}) => {
|
|
34
|
-
const
|
|
35
|
-
const [visibility, setVisibility] = useState("hidden");
|
|
37
|
+
const indicatorRef = useRef(null);
|
|
36
38
|
const animationTimerRef = useRef(null);
|
|
37
39
|
const positionCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
38
40
|
const containerInfoRef = useRef(null);
|
|
@@ -40,14 +42,21 @@ const TabIndicator = ({
|
|
|
40
42
|
const isInitializedRef = useRef(false);
|
|
41
43
|
const initRetryCountRef = useRef(0);
|
|
42
44
|
const maxInitRetries = 5;
|
|
45
|
+
const isFirstRender = useRef(true);
|
|
46
|
+
const isInitializingRef = useRef(false);
|
|
47
|
+
const initVersionRef = useRef(0);
|
|
48
|
+
const isMountedRef = useRef(true);
|
|
43
49
|
const updateIndicatorPosition = useEventCallback(() => {
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
const indicator = indicatorRef.current;
|
|
51
|
+
if (!indicator)
|
|
52
|
+
return;
|
|
53
|
+
if (!isValidTabValue(currentValue) || !registeredTabValues.includes(currentValue)) {
|
|
54
|
+
indicator.style.visibility = "hidden";
|
|
46
55
|
return;
|
|
47
56
|
}
|
|
48
57
|
const cachedPosition = positionCacheRef.current.get(currentValue);
|
|
49
58
|
const containerInfo = containerInfoRef.current;
|
|
50
|
-
if (!cachedPosition || !containerInfo) {
|
|
59
|
+
if (!cachedPosition || !containerInfo || !isInitializedRef.current) {
|
|
51
60
|
if (!isInitializedRef.current) {
|
|
52
61
|
initializePositions();
|
|
53
62
|
}
|
|
@@ -57,16 +66,41 @@ const TabIndicator = ({
|
|
|
57
66
|
const activeTabWidth = cachedPosition.width;
|
|
58
67
|
const indicatorWidth = indicatorWidthRef.current;
|
|
59
68
|
const x = activeTabLeft + (activeTabWidth - indicatorWidth) / 2;
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
indicator.style.transform = `translate(${x}px, 0px)`;
|
|
70
|
+
if (isFirstRender.current) {
|
|
71
|
+
Taro.nextTick(() => {
|
|
72
|
+
if (!isMountedRef.current || !indicatorRef.current)
|
|
73
|
+
return;
|
|
74
|
+
indicatorRef.current.style.visibility = "visible";
|
|
75
|
+
Taro.nextTick(() => {
|
|
76
|
+
if (!isMountedRef.current || !indicatorRef.current)
|
|
77
|
+
return;
|
|
78
|
+
indicatorRef.current.style.transition = "transform 0.3s ease-in-out";
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
isFirstRender.current = false;
|
|
82
|
+
} else {
|
|
83
|
+
indicator.style.visibility = "visible";
|
|
84
|
+
}
|
|
62
85
|
});
|
|
63
86
|
const initializePositions = useEventCallback(() => __async(void 0, null, function* () {
|
|
87
|
+
if (!isMountedRef.current)
|
|
88
|
+
return;
|
|
89
|
+
if (isInitializingRef.current)
|
|
90
|
+
return;
|
|
91
|
+
isInitializingRef.current = true;
|
|
92
|
+
initVersionRef.current += 1;
|
|
93
|
+
const currentVersion = initVersionRef.current;
|
|
64
94
|
try {
|
|
65
95
|
const result = yield batchQueryTabs({
|
|
66
96
|
scrollViewId,
|
|
67
97
|
wrapperId,
|
|
68
98
|
tabValues: registeredTabValues
|
|
69
99
|
});
|
|
100
|
+
if (!isMountedRef.current)
|
|
101
|
+
return;
|
|
102
|
+
if (currentVersion !== initVersionRef.current)
|
|
103
|
+
return;
|
|
70
104
|
const { scrollView, scrollFields, wrapper, indicator, tabs } = result;
|
|
71
105
|
if (!scrollView || !wrapper || !indicator || !scrollFields) {
|
|
72
106
|
if (initRetryCountRef.current < maxInitRetries) {
|
|
@@ -75,8 +109,30 @@ const TabIndicator = ({
|
|
|
75
109
|
clearTimeout(animationTimerRef.current);
|
|
76
110
|
}
|
|
77
111
|
animationTimerRef.current = setTimeout(() => {
|
|
112
|
+
if (!isMountedRef.current)
|
|
113
|
+
return;
|
|
114
|
+
isInitializingRef.current = false;
|
|
78
115
|
initializePositions();
|
|
79
116
|
}, 100);
|
|
117
|
+
} else {
|
|
118
|
+
isInitializingRef.current = false;
|
|
119
|
+
}
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (!indicator.width || indicator.width <= 0) {
|
|
123
|
+
if (initRetryCountRef.current < maxInitRetries) {
|
|
124
|
+
initRetryCountRef.current += 1;
|
|
125
|
+
if (animationTimerRef.current) {
|
|
126
|
+
clearTimeout(animationTimerRef.current);
|
|
127
|
+
}
|
|
128
|
+
animationTimerRef.current = setTimeout(() => {
|
|
129
|
+
if (!isMountedRef.current)
|
|
130
|
+
return;
|
|
131
|
+
isInitializingRef.current = false;
|
|
132
|
+
initializePositions();
|
|
133
|
+
}, 100);
|
|
134
|
+
} else {
|
|
135
|
+
isInitializingRef.current = false;
|
|
80
136
|
}
|
|
81
137
|
return;
|
|
82
138
|
}
|
|
@@ -89,9 +145,8 @@ const TabIndicator = ({
|
|
|
89
145
|
registeredTabValues.forEach((value, index) => {
|
|
90
146
|
const tabRect = tabs[index];
|
|
91
147
|
if (tabRect && tabRect.width > 0) {
|
|
92
|
-
const relativeLeft = tabRect.left - wrapper.left;
|
|
93
148
|
newCache.set(value, {
|
|
94
|
-
left:
|
|
149
|
+
left: tabRect.left - wrapper.left,
|
|
95
150
|
width: tabRect.width
|
|
96
151
|
});
|
|
97
152
|
}
|
|
@@ -103,40 +158,74 @@ const TabIndicator = ({
|
|
|
103
158
|
clearTimeout(animationTimerRef.current);
|
|
104
159
|
}
|
|
105
160
|
animationTimerRef.current = setTimeout(() => {
|
|
161
|
+
if (!isMountedRef.current)
|
|
162
|
+
return;
|
|
163
|
+
isInitializingRef.current = false;
|
|
106
164
|
initializePositions();
|
|
107
165
|
}, 100);
|
|
166
|
+
} else {
|
|
167
|
+
isInitializingRef.current = false;
|
|
108
168
|
}
|
|
109
169
|
return;
|
|
110
170
|
}
|
|
171
|
+
if (currentVersion !== initVersionRef.current || !isMountedRef.current) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
111
174
|
initRetryCountRef.current = 0;
|
|
112
175
|
positionCacheRef.current = newCache;
|
|
113
176
|
isInitializedRef.current = true;
|
|
177
|
+
isInitializingRef.current = false;
|
|
114
178
|
updateIndicatorPosition();
|
|
115
179
|
} catch (error) {
|
|
116
180
|
console.error("[TabIndicator] \u6279\u91CF\u67E5\u8BE2\u5931\u8D25:", error);
|
|
181
|
+
isInitializingRef.current = false;
|
|
182
|
+
if (isMountedRef.current && initRetryCountRef.current < maxInitRetries) {
|
|
183
|
+
initRetryCountRef.current += 1;
|
|
184
|
+
if (animationTimerRef.current) {
|
|
185
|
+
clearTimeout(animationTimerRef.current);
|
|
186
|
+
}
|
|
187
|
+
animationTimerRef.current = setTimeout(() => {
|
|
188
|
+
if (!isMountedRef.current)
|
|
189
|
+
return;
|
|
190
|
+
initializePositions();
|
|
191
|
+
}, 100);
|
|
192
|
+
}
|
|
117
193
|
}
|
|
118
194
|
}));
|
|
119
195
|
useEffect(() => {
|
|
120
196
|
if (registeredTabValues.length === 0) {
|
|
197
|
+
if (indicatorRef.current) {
|
|
198
|
+
indicatorRef.current.style.visibility = "hidden";
|
|
199
|
+
}
|
|
121
200
|
return void 0;
|
|
122
201
|
}
|
|
202
|
+
initVersionRef.current += 1;
|
|
123
203
|
if (animationTimerRef.current) {
|
|
124
204
|
clearTimeout(animationTimerRef.current);
|
|
205
|
+
animationTimerRef.current = null;
|
|
125
206
|
}
|
|
126
207
|
isInitializedRef.current = false;
|
|
208
|
+
isInitializingRef.current = false;
|
|
127
209
|
initRetryCountRef.current = 0;
|
|
128
210
|
Taro.nextTick(() => {
|
|
211
|
+
if (!isMountedRef.current)
|
|
212
|
+
return;
|
|
129
213
|
initializePositions();
|
|
130
214
|
});
|
|
131
215
|
return () => {
|
|
132
216
|
if (animationTimerRef.current) {
|
|
133
217
|
clearTimeout(animationTimerRef.current);
|
|
218
|
+
animationTimerRef.current = null;
|
|
134
219
|
}
|
|
220
|
+
initVersionRef.current += 1;
|
|
221
|
+
isInitializingRef.current = false;
|
|
135
222
|
};
|
|
136
223
|
}, [registrationVersion, initializePositions]);
|
|
137
224
|
useEffect(() => {
|
|
138
|
-
if (!currentValue) {
|
|
139
|
-
|
|
225
|
+
if (!isValidTabValue(currentValue)) {
|
|
226
|
+
if (indicatorRef.current) {
|
|
227
|
+
indicatorRef.current.style.visibility = "hidden";
|
|
228
|
+
}
|
|
140
229
|
return;
|
|
141
230
|
}
|
|
142
231
|
updateIndicatorPosition();
|
|
@@ -144,10 +233,20 @@ const TabIndicator = ({
|
|
|
144
233
|
useEffect(() => {
|
|
145
234
|
var _a, _b;
|
|
146
235
|
const handleResize = () => {
|
|
236
|
+
if (!isMountedRef.current)
|
|
237
|
+
return;
|
|
238
|
+
initVersionRef.current += 1;
|
|
147
239
|
isInitializedRef.current = false;
|
|
240
|
+
isInitializingRef.current = false;
|
|
148
241
|
initRetryCountRef.current = 0;
|
|
149
242
|
positionCacheRef.current.clear();
|
|
243
|
+
if (animationTimerRef.current) {
|
|
244
|
+
clearTimeout(animationTimerRef.current);
|
|
245
|
+
animationTimerRef.current = null;
|
|
246
|
+
}
|
|
150
247
|
Taro.nextTick(() => {
|
|
248
|
+
if (!isMountedRef.current)
|
|
249
|
+
return;
|
|
151
250
|
initializePositions();
|
|
152
251
|
});
|
|
153
252
|
};
|
|
@@ -157,15 +256,26 @@ const TabIndicator = ({
|
|
|
157
256
|
(_b2 = (_a2 = Taro).offWindowResize) == null ? void 0 : _b2.call(_a2, handleResize);
|
|
158
257
|
};
|
|
159
258
|
}, [initializePositions]);
|
|
259
|
+
useEffect(() => {
|
|
260
|
+
isMountedRef.current = true;
|
|
261
|
+
return () => {
|
|
262
|
+
isMountedRef.current = false;
|
|
263
|
+
if (animationTimerRef.current) {
|
|
264
|
+
clearTimeout(animationTimerRef.current);
|
|
265
|
+
animationTimerRef.current = null;
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}, []);
|
|
160
269
|
return /* @__PURE__ */ React.createElement(
|
|
161
270
|
"div",
|
|
162
271
|
{
|
|
272
|
+
ref: indicatorRef,
|
|
163
273
|
id: `${wrapperId}-indicator`,
|
|
164
274
|
className: clsx(tabIndicatorClass),
|
|
165
275
|
style: {
|
|
166
|
-
transition: "
|
|
167
|
-
transform,
|
|
168
|
-
visibility
|
|
276
|
+
transition: "none",
|
|
277
|
+
transform: "translate(0px, 0px)",
|
|
278
|
+
visibility: "hidden"
|
|
169
279
|
}
|
|
170
280
|
}
|
|
171
281
|
);
|
package/es/Tabs/miniapp/Tabs.js
CHANGED
|
@@ -25,7 +25,7 @@ import { ScrollView } from "@tarojs/components";
|
|
|
25
25
|
import { useValue, useEventCallback } from "@bifrostui/utils";
|
|
26
26
|
import Tab from "./Tab";
|
|
27
27
|
import TabIndicator from "./TabIndicator";
|
|
28
|
-
import TabMask from "
|
|
28
|
+
import TabMask from "../TabMask";
|
|
29
29
|
import { TabsContextProvider } from "./TabsContext";
|
|
30
30
|
import {
|
|
31
31
|
tabsRootClass,
|
|
@@ -72,8 +72,10 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
72
72
|
const [scrollLeft, setScrollLeft] = useState(0);
|
|
73
73
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
74
74
|
const [scrollWidth, setScrollWidth] = useState(0);
|
|
75
|
-
const scrollLeftUpdateTimerRef = React.useRef(null);
|
|
76
75
|
const lastScrollLeftRef = React.useRef(0);
|
|
76
|
+
const isFirstScroll = React.useRef(true);
|
|
77
|
+
const [scrollWithAnimation, setScrollWithAnimation] = React.useState(false);
|
|
78
|
+
const isScrollable = scrollWidth > containerWidth;
|
|
77
79
|
if (process.env.NODE_ENV !== "production") {
|
|
78
80
|
if (tabs.length > 0 && React.Children.count(children) > 0) {
|
|
79
81
|
console.warn(
|
|
@@ -113,14 +115,6 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
113
115
|
(e) => {
|
|
114
116
|
const { scrollLeft: newScrollLeft, scrollWidth: newScrollWidth } = e.detail;
|
|
115
117
|
lastScrollLeftRef.current = newScrollLeft;
|
|
116
|
-
if (scrollLeftUpdateTimerRef.current) {
|
|
117
|
-
clearTimeout(scrollLeftUpdateTimerRef.current);
|
|
118
|
-
}
|
|
119
|
-
scrollLeftUpdateTimerRef.current = setTimeout(() => {
|
|
120
|
-
if (Math.abs(lastScrollLeftRef.current - scrollLeft) > 1) {
|
|
121
|
-
setScrollLeft(lastScrollLeftRef.current);
|
|
122
|
-
}
|
|
123
|
-
}, 150);
|
|
124
118
|
if (newScrollWidth && newScrollWidth !== scrollWidth) {
|
|
125
119
|
setScrollWidth(newScrollWidth);
|
|
126
120
|
}
|
|
@@ -163,6 +157,12 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
163
157
|
);
|
|
164
158
|
setScrollLeft(finalScrollLeft);
|
|
165
159
|
lastScrollLeftRef.current = finalScrollLeft;
|
|
160
|
+
if (isFirstScroll.current) {
|
|
161
|
+
Taro.nextTick(() => {
|
|
162
|
+
setScrollWithAnimation(true);
|
|
163
|
+
});
|
|
164
|
+
isFirstScroll.current = false;
|
|
165
|
+
}
|
|
166
166
|
}));
|
|
167
167
|
React.useEffect(() => {
|
|
168
168
|
if (!currentValue || registeredTabValues.length === 0) {
|
|
@@ -196,38 +196,14 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
|
|
|
196
196
|
}
|
|
197
197
|
return children;
|
|
198
198
|
}, [tabs, children]);
|
|
199
|
-
React.
|
|
200
|
-
return () => {
|
|
201
|
-
if (scrollLeftUpdateTimerRef.current) {
|
|
202
|
-
clearTimeout(scrollLeftUpdateTimerRef.current);
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
}, []);
|
|
206
|
-
return /* @__PURE__ */ React.createElement("div", { className: clsx(tabsRootClass, className), style, ref }, /* @__PURE__ */ React.createElement(
|
|
207
|
-
TabMask,
|
|
208
|
-
{
|
|
209
|
-
position: "left",
|
|
210
|
-
scrollLeft,
|
|
211
|
-
containerWidth,
|
|
212
|
-
scrollWidth
|
|
213
|
-
}
|
|
214
|
-
), /* @__PURE__ */ React.createElement(
|
|
215
|
-
TabMask,
|
|
216
|
-
{
|
|
217
|
-
position: "right",
|
|
218
|
-
scrollLeft,
|
|
219
|
-
containerWidth,
|
|
220
|
-
scrollWidth
|
|
221
|
-
}
|
|
222
|
-
), /* @__PURE__ */ React.createElement(
|
|
199
|
+
return /* @__PURE__ */ React.createElement("div", { className: clsx(tabsRootClass, className), style, ref }, isScrollable && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(TabMask, { position: "left" }), /* @__PURE__ */ React.createElement(TabMask, { position: "right" })), /* @__PURE__ */ React.createElement(
|
|
223
200
|
ScrollView,
|
|
224
201
|
{
|
|
225
202
|
id: scrollViewId,
|
|
226
203
|
className: tabsScrollClass,
|
|
227
204
|
scrollX: true,
|
|
228
|
-
scrollWithAnimation
|
|
205
|
+
scrollWithAnimation,
|
|
229
206
|
scrollLeft,
|
|
230
|
-
scrollAnimationDuration: "200",
|
|
231
207
|
onScroll: handleScroll,
|
|
232
208
|
enhanced: true,
|
|
233
209
|
showScrollbar: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bifrostui/react",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.18",
|
|
4
4
|
"description": "React components for building mobile application",
|
|
5
5
|
"homepage": "http://bui.taopiaopiao.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"clsx": "^2.1.1",
|
|
44
44
|
"dayjs": "^1.11.7",
|
|
45
45
|
"swiper": "^8.1.5",
|
|
46
|
-
"@bifrostui/
|
|
47
|
-
"@bifrostui/types": "2.0.0-alpha.
|
|
48
|
-
"@bifrostui/
|
|
49
|
-
"@bifrostui/
|
|
46
|
+
"@bifrostui/icons": "2.0.0-alpha.18",
|
|
47
|
+
"@bifrostui/types": "2.0.0-alpha.18",
|
|
48
|
+
"@bifrostui/utils": "2.0.0-alpha.18",
|
|
49
|
+
"@bifrostui/styles": "2.0.0-alpha.18"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"@tarojs/components": "^3.0.0",
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export interface TabMaskProps {
|
|
3
|
-
/** 位置:左侧或右侧 */
|
|
4
|
-
position: 'left' | 'right';
|
|
5
|
-
/** 当前滚动位置 */
|
|
6
|
-
scrollLeft: number;
|
|
7
|
-
/** 容器宽度 */
|
|
8
|
-
containerWidth: number;
|
|
9
|
-
/** 滚动区域总宽度 */
|
|
10
|
-
scrollWidth: number;
|
|
11
|
-
}
|
|
12
|
-
declare const _default: React.NamedExoticComponent<TabMaskProps>;
|
|
13
|
-
export default _default;
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
var TabMask_exports = {};
|
|
29
|
-
__export(TabMask_exports, {
|
|
30
|
-
default: () => TabMask_default
|
|
31
|
-
});
|
|
32
|
-
module.exports = __toCommonJS(TabMask_exports);
|
|
33
|
-
var import_react = __toESM(require("react"));
|
|
34
|
-
var import_clsx = __toESM(require("clsx"));
|
|
35
|
-
var import_classes = require("../classes");
|
|
36
|
-
const TabMask = ({
|
|
37
|
-
position,
|
|
38
|
-
scrollLeft,
|
|
39
|
-
containerWidth,
|
|
40
|
-
scrollWidth
|
|
41
|
-
}) => {
|
|
42
|
-
const shouldShow = import_react.default.useMemo(() => {
|
|
43
|
-
if (position === "left") {
|
|
44
|
-
return scrollLeft > 0;
|
|
45
|
-
}
|
|
46
|
-
const rightRange = Math.abs(scrollWidth - (scrollLeft + containerWidth));
|
|
47
|
-
return rightRange > 1;
|
|
48
|
-
}, [position, scrollLeft, containerWidth, scrollWidth]);
|
|
49
|
-
return /* @__PURE__ */ import_react.default.createElement(
|
|
50
|
-
"div",
|
|
51
|
-
{
|
|
52
|
-
className: (0, import_clsx.default)(
|
|
53
|
-
import_classes.tabMaskClass,
|
|
54
|
-
position === "left" ? import_classes.tabMaskLeftClass : import_classes.tabMaskRightClass
|
|
55
|
-
),
|
|
56
|
-
style: {
|
|
57
|
-
opacity: shouldShow ? 1 : 0,
|
|
58
|
-
transition: "opacity 0.1s ease-in-out"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
);
|
|
62
|
-
};
|
|
63
|
-
TabMask.displayName = "BuiTabsMask";
|
|
64
|
-
var TabMask_default = /* @__PURE__ */ import_react.default.memo(TabMask, (prevProps, nextProps) => {
|
|
65
|
-
return prevProps.position === nextProps.position && prevProps.scrollLeft === nextProps.scrollLeft && prevProps.containerWidth === nextProps.containerWidth && prevProps.scrollWidth === nextProps.scrollWidth;
|
|
66
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export interface TabMaskProps {
|
|
3
|
-
/** 位置:左侧或右侧 */
|
|
4
|
-
position: 'left' | 'right';
|
|
5
|
-
/** 当前滚动位置 */
|
|
6
|
-
scrollLeft: number;
|
|
7
|
-
/** 容器宽度 */
|
|
8
|
-
containerWidth: number;
|
|
9
|
-
/** 滚动区域总宽度 */
|
|
10
|
-
scrollWidth: number;
|
|
11
|
-
}
|
|
12
|
-
declare const _default: React.NamedExoticComponent<TabMaskProps>;
|
|
13
|
-
export default _default;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import clsx from "clsx";
|
|
3
|
-
import { tabMaskClass, tabMaskLeftClass, tabMaskRightClass } from "../classes";
|
|
4
|
-
const TabMask = ({
|
|
5
|
-
position,
|
|
6
|
-
scrollLeft,
|
|
7
|
-
containerWidth,
|
|
8
|
-
scrollWidth
|
|
9
|
-
}) => {
|
|
10
|
-
const shouldShow = React.useMemo(() => {
|
|
11
|
-
if (position === "left") {
|
|
12
|
-
return scrollLeft > 0;
|
|
13
|
-
}
|
|
14
|
-
const rightRange = Math.abs(scrollWidth - (scrollLeft + containerWidth));
|
|
15
|
-
return rightRange > 1;
|
|
16
|
-
}, [position, scrollLeft, containerWidth, scrollWidth]);
|
|
17
|
-
return /* @__PURE__ */ React.createElement(
|
|
18
|
-
"div",
|
|
19
|
-
{
|
|
20
|
-
className: clsx(
|
|
21
|
-
tabMaskClass,
|
|
22
|
-
position === "left" ? tabMaskLeftClass : tabMaskRightClass
|
|
23
|
-
),
|
|
24
|
-
style: {
|
|
25
|
-
opacity: shouldShow ? 1 : 0,
|
|
26
|
-
transition: "opacity 0.1s ease-in-out"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
);
|
|
30
|
-
};
|
|
31
|
-
TabMask.displayName = "BuiTabsMask";
|
|
32
|
-
var TabMask_default = /* @__PURE__ */ React.memo(TabMask, (prevProps, nextProps) => {
|
|
33
|
-
return prevProps.position === nextProps.position && prevProps.scrollLeft === nextProps.scrollLeft && prevProps.containerWidth === nextProps.containerWidth && prevProps.scrollWidth === nextProps.scrollWidth;
|
|
34
|
-
});
|
|
35
|
-
export {
|
|
36
|
-
TabMask_default as default
|
|
37
|
-
};
|