@bifrostui/react 2.0.0-alpha.15 → 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/es/Tabs/Tab.css CHANGED
@@ -17,7 +17,6 @@
17
17
  .bui-tab-active {
18
18
  color: var(--bui-tab-active-color);
19
19
  font-weight: var(--bui-font-weight-bold);
20
- font-family: var(--bui-tab-active-font-family);
21
20
  }
22
21
  .bui-tab-disabled {
23
22
  opacity: 0.5;
@@ -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((activeTab) => {
21
- const tabsEl = tabsContainerRef.current;
22
- if (!tabsEl || !activeTab) {
23
- return;
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
- scrollLeftTo(
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: "transform 0.3s ease-in-out",
85
+ transition: "none",
75
86
  transform: "translate(0px, 0px)",
76
87
  visibility: "hidden"
77
88
  },
@@ -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 TabMask: React.FC<TabMaskProps>;
9
- export default TabMask;
6
+ declare const _default: React.NamedExoticComponent<TabMaskProps>;
7
+ export default _default;
@@ -1,59 +1,18 @@
1
- import React, { useEffect, useMemo, useRef } from "react";
1
+ import React from "react";
2
2
  import clsx from "clsx";
3
- import { throttle } from "@bifrostui/utils";
4
- const rootClass = "bui-tabs";
5
- const TabMask = ({ tabsContainerRef, position }) => {
6
- const maskRef = useRef(null);
7
- const updateMaskOpacity = useMemo(
8
- () => throttle(
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
- [tabsContainerRef, position]
33
- );
34
- useEffect(() => {
35
- const tabsEl = tabsContainerRef.current;
36
- if (!tabsEl)
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.css CHANGED
@@ -16,7 +16,6 @@ xhs-page {
16
16
  --bui-tab-height: 100%;
17
17
  --bui-tab-padding: var(--bui-spacing-lg) var(--bui-spacing-lg) 10px;
18
18
  --bui-tab-active-color: var(--bui-color-fg-default);
19
- --bui-tab-active-font-family: var(--bui-font-family-accent, inherit);
20
19
  }
21
20
  .bui-tabs {
22
21
  position: relative;
package/es/Tabs/Tabs.js CHANGED
@@ -1,4 +1,6 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
2
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
4
6
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -14,6 +16,7 @@ var __spreadValues = (a, b) => {
14
16
  }
15
17
  return a;
16
18
  };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
17
20
  var __objRest = (source, exclude) => {
18
21
  var target = {};
19
22
  for (var prop in source)
@@ -26,7 +29,7 @@ var __objRest = (source, exclude) => {
26
29
  }
27
30
  return target;
28
31
  };
29
- import React, { useMemo, useRef, useState } from "react";
32
+ import React, { useEffect, useMemo, useRef, useState } from "react";
30
33
  import clsx from "clsx";
31
34
  import { useValue, useEventCallback } from "@bifrostui/utils";
32
35
  import Tab from "./Tab";
@@ -70,6 +73,7 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
70
73
  {}
71
74
  );
72
75
  const [registrationVersion, setRegistrationVersion] = useState(0);
76
+ const [isScrollable, setIsScrollable] = useState(false);
73
77
  if (process.env.NODE_ENV !== "production") {
74
78
  if (tabs.length > 0 && React.Children.count(children) > 0) {
75
79
  console.warn(
@@ -114,10 +118,21 @@ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
114
118
  }
115
119
  return children;
116
120
  }, [tabs, children]);
117
- if (process.env.NODE_ENV !== "production") {
118
- console.count("Tabs render......");
119
- }
120
- return /* @__PURE__ */ React.createElement("div", __spreadValues({ ref, className: clsx(tabsRootClass, className) }, others), /* @__PURE__ */ React.createElement(TabMask, { tabsContainerRef: tabsRef, position: "left" }), /* @__PURE__ */ React.createElement(TabMask, { tabsContainerRef: tabsRef, position: "right" }), /* @__PURE__ */ React.createElement(
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(
121
136
  "div",
122
137
  {
123
138
  className: `${tabsRootClass}-tabs`,
package/es/Tabs/index.css CHANGED
@@ -16,7 +16,6 @@ xhs-page {
16
16
  --bui-tab-height: 100%;
17
17
  --bui-tab-padding: var(--bui-spacing-lg) var(--bui-spacing-lg) 10px;
18
18
  --bui-tab-active-color: var(--bui-color-fg-default);
19
- --bui-tab-active-font-family: var(--bui-font-family-accent, inherit);
20
19
  }
21
20
  .bui-tabs {
22
21
  position: relative;
@@ -107,7 +106,6 @@ xhs-page {
107
106
  .bui-tab-active {
108
107
  color: var(--bui-tab-active-color);
109
108
  font-weight: var(--bui-font-weight-bold);
110
- font-family: var(--bui-tab-active-font-family);
111
109
  }
112
110
  .bui-tab-disabled {
113
111
  opacity: 0.5;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import { TabProps } from '../Tab.types';
3
3
  import '../Tab.less';
4
- declare const _default: React.NamedExoticComponent<TabProps<"div", {}>>;
4
+ declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Omit<TabProps<"div", {}>, "ref"> & React.RefAttributes<HTMLDivElement>>>;
5
5
  export default _default;
@@ -1,10 +1,10 @@
1
- import React, { useEffect } from "react";
1
+ import React, { useEffect, useRef } from "react";
2
2
  import clsx from "clsx";
3
- import { useContextSelector } from "@bifrostui/utils";
3
+ import { useContextSelector, useForkRef } from "@bifrostui/utils";
4
4
  import TabsContext from "./TabsContext";
5
5
  import { tabRootClass, tabActiveClass, tabDisabledClass } from "../classes";
6
6
  import "../Tab.css";
7
- const Tab = (props) => {
7
+ const Tab = /* @__PURE__ */ React.forwardRef((props, ref) => {
8
8
  const {
9
9
  className,
10
10
  children,
@@ -13,6 +13,8 @@ const Tab = (props) => {
13
13
  onClick,
14
14
  style
15
15
  } = props;
16
+ const innerRef = useRef(null);
17
+ const handleRef = useForkRef(ref, innerRef);
16
18
  const isActive = useContextSelector(
17
19
  TabsContext,
18
20
  (ctx) => ctx.value === index
@@ -53,6 +55,7 @@ const Tab = (props) => {
53
55
  "div",
54
56
  {
55
57
  id: tabId,
58
+ ref: handleRef,
56
59
  className: rootCls,
57
60
  style,
58
61
  onClick: (e) => {
@@ -64,7 +67,7 @@ const Tab = (props) => {
64
67
  },
65
68
  children
66
69
  );
67
- };
70
+ });
68
71
  Tab.displayName = "BuiTab";
69
72
  var Tab_default = /* @__PURE__ */ React.memo(Tab, (prevProps, nextProps) => {
70
73
  return prevProps.index === nextProps.index && prevProps.disabled === nextProps.disabled && prevProps.className === nextProps.className && prevProps.children === nextProps.children;
@@ -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, useState } from "react";
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 [transform, setTransform] = useState("translate(0px, 0px)");
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
- if (!currentValue || !registeredTabValues.includes(currentValue)) {
45
- setVisibility("hidden");
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
- setTransform(`translate(${x}px, 0px)`);
61
- setVisibility("visible");
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: relativeLeft,
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
- setVisibility("hidden");
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: "transform 0.3s ease-in-out",
167
- transform,
168
- visibility
276
+ transition: "none",
277
+ transform: "translate(0px, 0px)",
278
+ visibility: "hidden"
169
279
  }
170
280
  }
171
281
  );
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import { TabsProps } from '../Tabs.types';
3
3
  import '../Tabs.less';
4
- declare const Tabs: React.FC<TabsProps>;
4
+ declare const Tabs: React.ForwardRefExoticComponent<Omit<TabsProps<"div", {}>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
5
  export default Tabs;
@@ -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 "./TabMask";
28
+ import TabMask from "../TabMask";
29
29
  import { TabsContextProvider } from "./TabsContext";
30
30
  import {
31
31
  tabsRootClass,
@@ -37,7 +37,7 @@ import {
37
37
  batchQueryForScroll
38
38
  } from "./utils/queryBatch";
39
39
  import "../Tabs.css";
40
- const Tabs = (props) => {
40
+ const Tabs = /* @__PURE__ */ React.forwardRef((props, ref) => {
41
41
  const {
42
42
  children,
43
43
  className,
@@ -72,8 +72,10 @@ const Tabs = (props) => {
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 = (props) => {
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 = (props) => {
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 = (props) => {
196
196
  }
197
197
  return children;
198
198
  }, [tabs, children]);
199
- React.useEffect(() => {
200
- return () => {
201
- if (scrollLeftUpdateTimerRef.current) {
202
- clearTimeout(scrollLeftUpdateTimerRef.current);
203
- }
204
- };
205
- }, []);
206
- return /* @__PURE__ */ React.createElement("div", { className: clsx(tabsRootClass, className), style }, /* @__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: true,
205
+ scrollWithAnimation,
229
206
  scrollLeft,
230
- scrollAnimationDuration: "200",
231
207
  onScroll: handleScroll,
232
208
  enhanced: true,
233
209
  showScrollbar: false,
@@ -245,7 +221,7 @@ const Tabs = (props) => {
245
221
  }
246
222
  ), /* @__PURE__ */ React.createElement(TabsContextProvider, { value: contextValue }, renderedTabs))
247
223
  ));
248
- };
224
+ });
249
225
  Tabs.displayName = "BuiTabs";
250
226
  var Tabs_default = Tabs;
251
227
  export {