@hero-design/rn 8.130.3 → 8.131.0
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/CHANGELOG.md +6 -0
- package/es/index.js +405 -224
- package/lib/index.js +405 -224
- package/package.json +1 -1
- package/src/components/Tabs/ScrollableTabsHeader/ScrollableTabsHeader.tsx +217 -131
- package/src/components/Tabs/ScrollableTabsHeader/hooks/useIndicatorAnimation.ts +242 -0
- package/src/components/Tabs/StyledScrollableTabs.tsx +68 -21
- package/src/components/Tabs/index.tsx +2 -0
- package/src/theme/components/tabs.ts +9 -2
- package/types/components/Tabs/ScrollableTabsHeader/ScrollableTabsHeader.d.ts +1 -1
- package/types/components/Tabs/ScrollableTabsHeader/hooks/useIndicatorAnimation.d.ts +75 -0
- package/types/components/Tabs/StyledScrollableTabs.d.ts +13 -8
- package/types/components/Tabs/index.d.ts +3 -1
- package/types/theme/components/tabs.d.ts +9 -2
- package/src/components/Tabs/ScrollableTabsHeader/hooks/useInitHighlightedAnimation.ts +0 -45
- package/types/components/Tabs/ScrollableTabsHeader/hooks/useInitHighlightedAnimation.d.ts +0 -9
package/es/index.js
CHANGED
|
@@ -7137,7 +7137,11 @@ var getTabsTheme = function getTabsTheme(theme) {
|
|
|
7137
7137
|
headerBottom: theme.colors.secondaryOutline,
|
|
7138
7138
|
indicator: theme.colors.primary,
|
|
7139
7139
|
text: theme.colors.onDefaultGlobalSurface,
|
|
7140
|
-
headerBackground: theme.colors.defaultGlobalSurface
|
|
7140
|
+
headerBackground: theme.colors.defaultGlobalSurface,
|
|
7141
|
+
highlightedActiveText: theme.colors.primary,
|
|
7142
|
+
highlightedActiveBorder: theme.colors.primary,
|
|
7143
|
+
highlightedActiveBackground: theme.colors.neutralGlobalSurface,
|
|
7144
|
+
highlightedDisabledText: theme.colors.disabledOnDefaultGlobalSurface
|
|
7141
7145
|
};
|
|
7142
7146
|
var space = {
|
|
7143
7147
|
flatListHorizontalPadding: theme.space.small,
|
|
@@ -7145,14 +7149,17 @@ var getTabsTheme = function getTabsTheme(theme) {
|
|
|
7145
7149
|
itemVerticalPadding: theme.space.small,
|
|
7146
7150
|
itemMargin: theme.space.smallMedium,
|
|
7147
7151
|
outlineHorizontalPadding: theme.space.small,
|
|
7148
|
-
|
|
7149
|
-
|
|
7152
|
+
tabIndicatorBottom: -theme.space.xxsmall,
|
|
7153
|
+
highlightedItemMargin: theme.space.xsmall,
|
|
7154
|
+
highlightedBarTopPadding: theme.space.xxsmall
|
|
7150
7155
|
};
|
|
7151
7156
|
var radii = {
|
|
7152
|
-
|
|
7157
|
+
highlightedOutline: theme.radii.medium
|
|
7153
7158
|
};
|
|
7154
7159
|
var borderWidths = {
|
|
7155
|
-
headerBottom: theme.borderWidths.medium
|
|
7160
|
+
headerBottom: theme.borderWidths.medium,
|
|
7161
|
+
highlightedHeaderBottom: theme.borderWidths.base,
|
|
7162
|
+
highlightedActiveBorder: theme.borderWidths.base
|
|
7156
7163
|
};
|
|
7157
7164
|
var sizes = {
|
|
7158
7165
|
indicator: theme.sizes.xxsmall
|
|
@@ -28111,43 +28118,85 @@ var HeaderTabWrapper = index$c(View)(function (_ref) {
|
|
|
28111
28118
|
backgroundColor: theme.__hd__.tabs.colors.headerBackground
|
|
28112
28119
|
};
|
|
28113
28120
|
});
|
|
28121
|
+
var getItemMarginLeft = function getItemMarginLeft(isFirstItem, themeVariant, highlightedMargin, defaultMargin) {
|
|
28122
|
+
if (isFirstItem) return 0;
|
|
28123
|
+
if (themeVariant === 'highlighted') return highlightedMargin;
|
|
28124
|
+
return defaultMargin;
|
|
28125
|
+
};
|
|
28114
28126
|
var HeaderTabItem = index$c(Animated.View)(function (_ref2) {
|
|
28115
28127
|
var theme = _ref2.theme,
|
|
28116
|
-
isFirstItem = _ref2.isFirstItem
|
|
28128
|
+
isFirstItem = _ref2.isFirstItem,
|
|
28129
|
+
themeVariant = _ref2.themeVariant;
|
|
28117
28130
|
return {
|
|
28118
|
-
marginLeft: isFirstItem
|
|
28119
|
-
paddingVertical: theme.__hd__.tabs.space.itemVerticalPadding
|
|
28131
|
+
marginLeft: getItemMarginLeft(isFirstItem, themeVariant, theme.__hd__.tabs.space.highlightedItemMargin, theme.__hd__.tabs.space.itemMargin),
|
|
28132
|
+
paddingVertical: theme.__hd__.tabs.space.itemVerticalPadding,
|
|
28133
|
+
alignItems: 'center',
|
|
28134
|
+
justifyContent: 'center'
|
|
28120
28135
|
};
|
|
28121
28136
|
});
|
|
28122
|
-
|
|
28137
|
+
// Three-piece pill: left cap + body + right cap, all native-driver animated.
|
|
28138
|
+
// Splitting into pieces keeps border-radius on fixed-width views so scaleX
|
|
28139
|
+
// never distorts the rounded corners. Cap width equals the border-radius so
|
|
28140
|
+
// the rounded edge is fully contained within the cap piece.
|
|
28141
|
+
var HeaderTabPillLeft = index$c(Animated.View)(function (_ref3) {
|
|
28123
28142
|
var theme = _ref3.theme;
|
|
28124
|
-
return
|
|
28125
|
-
|
|
28126
|
-
|
|
28143
|
+
return {
|
|
28144
|
+
position: 'absolute',
|
|
28145
|
+
top: 0,
|
|
28146
|
+
bottom: 0,
|
|
28147
|
+
left: 0,
|
|
28148
|
+
width: theme.__hd__.tabs.radii.highlightedOutline,
|
|
28149
|
+
borderTopLeftRadius: theme.__hd__.tabs.radii.highlightedOutline,
|
|
28150
|
+
backgroundColor: theme.__hd__.tabs.colors.highlightedActiveBackground
|
|
28151
|
+
};
|
|
28127
28152
|
});
|
|
28128
|
-
var
|
|
28129
|
-
var theme = _ref4.theme
|
|
28130
|
-
themeActive = _ref4.themeActive;
|
|
28153
|
+
var HeaderTabPillBody = index$c(Animated.View)(function (_ref4) {
|
|
28154
|
+
var theme = _ref4.theme;
|
|
28131
28155
|
return {
|
|
28132
|
-
|
|
28133
|
-
|
|
28156
|
+
position: 'absolute',
|
|
28157
|
+
top: 0,
|
|
28158
|
+
bottom: 0,
|
|
28159
|
+
left: 0,
|
|
28160
|
+
width: 1,
|
|
28161
|
+
backgroundColor: theme.__hd__.tabs.colors.highlightedActiveBackground
|
|
28134
28162
|
};
|
|
28135
28163
|
});
|
|
28136
|
-
var
|
|
28164
|
+
var HeaderTabPillRight = index$c(Animated.View)(function (_ref5) {
|
|
28137
28165
|
var theme = _ref5.theme;
|
|
28166
|
+
return {
|
|
28167
|
+
position: 'absolute',
|
|
28168
|
+
top: 0,
|
|
28169
|
+
bottom: 0,
|
|
28170
|
+
left: 0,
|
|
28171
|
+
width: theme.__hd__.tabs.radii.highlightedOutline,
|
|
28172
|
+
borderTopRightRadius: theme.__hd__.tabs.radii.highlightedOutline,
|
|
28173
|
+
backgroundColor: theme.__hd__.tabs.colors.highlightedActiveBackground
|
|
28174
|
+
};
|
|
28175
|
+
});
|
|
28176
|
+
var HeaderTabItemActiveBorder = index$c(Animated.View)(function (_ref6) {
|
|
28177
|
+
var theme = _ref6.theme;
|
|
28178
|
+
return {
|
|
28179
|
+
position: 'absolute',
|
|
28180
|
+
bottom: 0,
|
|
28181
|
+
width: 1,
|
|
28182
|
+
height: theme.__hd__.tabs.borderWidths.highlightedActiveBorder,
|
|
28183
|
+
backgroundColor: theme.__hd__.tabs.colors.highlightedActiveBorder
|
|
28184
|
+
};
|
|
28185
|
+
});
|
|
28186
|
+
var HeaderTabItemWrapper = index$c(View)(function (_ref7) {
|
|
28187
|
+
var theme = _ref7.theme;
|
|
28138
28188
|
return _objectSpread2({
|
|
28139
28189
|
paddingHorizontal: theme.__hd__.tabs.space.outlineHorizontalPadding,
|
|
28140
|
-
paddingVertical: theme.__hd__.tabs.space.outlineVerticalPadding,
|
|
28141
28190
|
position: 'relative',
|
|
28142
28191
|
justifyContent: 'center'
|
|
28143
28192
|
}, !isAndroid8 && {
|
|
28144
28193
|
alignItems: 'center'
|
|
28145
28194
|
});
|
|
28146
28195
|
});
|
|
28147
|
-
var HeaderTabItemIndicator = index$c(Animated.View)(function (
|
|
28148
|
-
var theme =
|
|
28196
|
+
var HeaderTabItemIndicator = index$c(Animated.View)(function (_ref8) {
|
|
28197
|
+
var theme = _ref8.theme;
|
|
28149
28198
|
return {
|
|
28150
|
-
width:
|
|
28199
|
+
width: 1,
|
|
28151
28200
|
height: theme.__hd__.tabs.sizes.indicator,
|
|
28152
28201
|
position: 'absolute',
|
|
28153
28202
|
bottom: theme.__hd__.tabs.space.tabIndicatorBottom,
|
|
@@ -28228,109 +28277,204 @@ var TabWithBadge = function TabWithBadge(_ref) {
|
|
|
28228
28277
|
return /*#__PURE__*/React__default.createElement(View, null, tabItem);
|
|
28229
28278
|
};
|
|
28230
28279
|
|
|
28231
|
-
|
|
28232
|
-
|
|
28233
|
-
|
|
28234
|
-
|
|
28235
|
-
|
|
28236
|
-
|
|
28237
|
-
|
|
28238
|
-
|
|
28239
|
-
|
|
28240
|
-
|
|
28241
|
-
|
|
28242
|
-
|
|
28243
|
-
|
|
28280
|
+
/**
|
|
28281
|
+
* Drives two visual layers that slide to the selected tab on every press:
|
|
28282
|
+
*
|
|
28283
|
+
* Layer 1 — bottom border / underline (indicatorStyle)
|
|
28284
|
+
* ─────────────────────────────────────────────────────
|
|
28285
|
+
* Uses the "width:1 + scaleX" trick: the element has a fixed stylesheet
|
|
28286
|
+
* width of 1px and scaleX is set to the target pixel width, giving a visual
|
|
28287
|
+
* width of 1 × scaleX pixels without touching any layout property.
|
|
28288
|
+
* Both translateX and scaleX are transform properties → native driver.
|
|
28289
|
+
* Caveat: scaleX also scales border-radius, so this layer has no border-radius.
|
|
28290
|
+
*
|
|
28291
|
+
* Layer 2 — pill background (pillLeftStyle / pillBodyStyle / pillRightStyle)
|
|
28292
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
28293
|
+
* The pill is split into three absolutely-positioned children so that
|
|
28294
|
+
* border-radius is never distorted by scale:
|
|
28295
|
+
*
|
|
28296
|
+
* ┌──────────────────────────────────────────────────────┐
|
|
28297
|
+
* │ [cap-left 8px] [body width-1 + scaleX] [cap-right 8px] │
|
|
28298
|
+
* └──────────────────────────────────────────────────────┘
|
|
28299
|
+
*
|
|
28300
|
+
* cap-left — fixed 8px wide, borderTopLeftRadius:8, translateX = pillX
|
|
28301
|
+
* body — width:1 + scaleX trick (scaleX = tabWidth - 16),
|
|
28302
|
+
* transformOrigin 'left center',
|
|
28303
|
+
* translateX = pillX + 8 (via Animated.add)
|
|
28304
|
+
* cap-right — fixed 8px wide, borderTopRightRadius:8,
|
|
28305
|
+
* translateX = pillX + tabWidth - 8 (via Animated.add)
|
|
28306
|
+
*
|
|
28307
|
+
* All four animated values use the native driver (translateX and scaleX are
|
|
28308
|
+
* transform properties). `width` is never animated, so no JS driver needed.
|
|
28309
|
+
*
|
|
28310
|
+
* Driver summary:
|
|
28311
|
+
* indicatorX native translateX — slides the bottom border
|
|
28312
|
+
* indicatorScaleX native scaleX — stretches the bottom border
|
|
28313
|
+
* pillX native translateX — slides all three pill pieces
|
|
28314
|
+
* pillBodyScaleX native scaleX — stretches the pill body
|
|
28315
|
+
* pillRightOffsetX native translateX — positions the right cap
|
|
28316
|
+
* (Animated.add: pillX + tabWidth - 8)
|
|
28317
|
+
*/
|
|
28318
|
+
var useIndicatorAnimation = function useIndicatorAnimation(_ref) {
|
|
28319
|
+
var selectedIndex = _ref.selectedIndex,
|
|
28244
28320
|
tabsLength = _ref.tabsLength,
|
|
28245
|
-
|
|
28246
|
-
|
|
28247
|
-
|
|
28248
|
-
|
|
28249
|
-
|
|
28250
|
-
|
|
28321
|
+
pillCapWidth = _ref.pillCapWidth;
|
|
28322
|
+
// Layer 1 — native driver (bottom border / underline).
|
|
28323
|
+
var indicatorX = React__default.useRef(new Animated.Value(0)).current;
|
|
28324
|
+
var indicatorScaleX = React__default.useRef(new Animated.Value(1)).current;
|
|
28325
|
+
// Layer 2 — native driver (pill background, three-piece split).
|
|
28326
|
+
// pillX: left edge of the pill (shared by all three pieces as base).
|
|
28327
|
+
// pillBodyScaleX: scaleX for the body piece (tabWidth - 2 * CAP_WIDTH).
|
|
28328
|
+
// pillRightOffset: additional x offset for the right cap (tabWidth - CAP_WIDTH).
|
|
28329
|
+
var pillX = React__default.useRef(new Animated.Value(0)).current;
|
|
28330
|
+
var pillBodyScaleX = React__default.useRef(new Animated.Value(1)).current;
|
|
28331
|
+
var pillRightOffset = React__default.useRef(new Animated.Value(0)).current;
|
|
28332
|
+
// Stable ref so callbacks don't capture stale closures.
|
|
28333
|
+
var layoutsRef = React__default.useRef([]);
|
|
28334
|
+
var runningAnimRef = React__default.useRef(null);
|
|
28335
|
+
var pendingIndexRef = React__default.useRef(undefined);
|
|
28336
|
+
var initializedRef = React__default.useRef(false);
|
|
28337
|
+
// Resize layout cache when tabsLength changes.
|
|
28251
28338
|
React__default.useEffect(function () {
|
|
28252
|
-
|
|
28253
|
-
return;
|
|
28254
|
-
}
|
|
28255
|
-
var animation = Animated.parallel(_toConsumableArray(Array.from({
|
|
28339
|
+
layoutsRef.current = Array.from({
|
|
28256
28340
|
length: tabsLength
|
|
28257
|
-
}
|
|
28258
|
-
return
|
|
28259
|
-
toValue: i === selectedIndex ? 1 : 0,
|
|
28260
|
-
duration: 150,
|
|
28261
|
-
useNativeDriver: Platform.OS !== 'web'
|
|
28262
|
-
});
|
|
28263
|
-
})));
|
|
28264
|
-
animation.start();
|
|
28265
|
-
return function () {
|
|
28266
|
-
animation.stop();
|
|
28267
|
-
};
|
|
28268
|
-
}, [selectedIndex]);
|
|
28269
|
-
return {
|
|
28270
|
-
tabsAnims: tabsAnims
|
|
28271
|
-
};
|
|
28272
|
-
};
|
|
28273
|
-
|
|
28274
|
-
var TRANSLATE_DISTANCE = 30;
|
|
28275
|
-
var animateOpacity = function animateOpacity(animatedValue, toValue) {
|
|
28276
|
-
return Animated.timing(animatedValue, {
|
|
28277
|
-
toValue: toValue,
|
|
28278
|
-
duration: 150,
|
|
28279
|
-
easing: Easing.ease,
|
|
28280
|
-
useNativeDriver: Platform.OS !== 'web'
|
|
28281
|
-
});
|
|
28282
|
-
};
|
|
28283
|
-
var animateTranslateX = function animateTranslateX(animatedValue, toValue) {
|
|
28284
|
-
return Animated.spring(animatedValue, {
|
|
28285
|
-
toValue: toValue,
|
|
28286
|
-
useNativeDriver: Platform.OS !== 'web'
|
|
28287
|
-
});
|
|
28288
|
-
};
|
|
28289
|
-
var useInitUnderlinedAnimation = function useInitUnderlinedAnimation(_ref) {
|
|
28290
|
-
var tabsLength = _ref.tabsLength,
|
|
28291
|
-
_ref$selectedIndex = _ref.selectedIndex,
|
|
28292
|
-
selectedIndex = _ref$selectedIndex === void 0 ? 0 : _ref$selectedIndex,
|
|
28293
|
-
variant = _ref.variant;
|
|
28294
|
-
var previousIndex = React__default.useRef(0);
|
|
28295
|
-
var translateXAnims = useAnimatedValueArray(Array.from({
|
|
28296
|
-
length: tabsLength
|
|
28297
|
-
}).map(function () {
|
|
28298
|
-
return 0;
|
|
28299
|
-
}));
|
|
28300
|
-
var opacityAnims = useAnimatedValueArray(Array.from({
|
|
28301
|
-
length: tabsLength
|
|
28302
|
-
}).map(function (_, i) {
|
|
28303
|
-
return selectedIndex !== undefined && selectedIndex === i ? 1 : 0;
|
|
28304
|
-
}));
|
|
28305
|
-
var underlinedTranslateX = translateXAnims.map(function (anim) {
|
|
28306
|
-
return anim.interpolate({
|
|
28307
|
-
inputRange: [-1, 0, 1],
|
|
28308
|
-
outputRange: [-TRANSLATE_DISTANCE, 0, TRANSLATE_DISTANCE]
|
|
28341
|
+
}, function (_, i) {
|
|
28342
|
+
return layoutsRef.current[i];
|
|
28309
28343
|
});
|
|
28310
|
-
});
|
|
28311
|
-
var
|
|
28312
|
-
|
|
28313
|
-
|
|
28314
|
-
|
|
28344
|
+
}, [tabsLength]);
|
|
28345
|
+
var animateTo = React__default.useCallback(function (index, animate) {
|
|
28346
|
+
var _runningAnimRef$curre;
|
|
28347
|
+
var layout = layoutsRef.current[index];
|
|
28348
|
+
if (!layout) return;
|
|
28349
|
+
(_runningAnimRef$curre = runningAnimRef.current) === null || _runningAnimRef$curre === void 0 || _runningAnimRef$curre.stop();
|
|
28350
|
+
runningAnimRef.current = null;
|
|
28351
|
+
// Layer 1: bottom-border element has width:1, so scaleX = pixel width.
|
|
28352
|
+
var indicatorScaleXValue = layout.width;
|
|
28353
|
+
// Layer 2 body: width:1 element, scaleX fills space between the two caps.
|
|
28354
|
+
var bodyScaleX = Math.max(layout.width - pillCapWidth * 2, 0);
|
|
28355
|
+
// Layer 2 right cap: offset from pillX to reach the right edge.
|
|
28356
|
+
// Clamped to 0 so the right cap never slides left of the pill's origin
|
|
28357
|
+
// when the tab is narrower than one cap width.
|
|
28358
|
+
var rightOffset = Math.max(layout.width - pillCapWidth, 0);
|
|
28359
|
+
if (!animate || !initializedRef.current) {
|
|
28360
|
+
// First render — snap all values immediately without animation.
|
|
28361
|
+
indicatorX.setValue(layout.x);
|
|
28362
|
+
indicatorScaleX.setValue(indicatorScaleXValue);
|
|
28363
|
+
pillX.setValue(layout.x);
|
|
28364
|
+
pillBodyScaleX.setValue(bodyScaleX);
|
|
28365
|
+
pillRightOffset.setValue(rightOffset);
|
|
28366
|
+
initializedRef.current = true;
|
|
28367
|
+
return;
|
|
28368
|
+
}
|
|
28369
|
+
// All five animations run on the native driver (UI thread):
|
|
28370
|
+
// indicatorX — slides the bottom border
|
|
28371
|
+
// indicatorScaleX — stretches the bottom border
|
|
28372
|
+
// pillX — slides all three pill pieces together
|
|
28373
|
+
// pillBodyScaleX — resizes the body piece to fill between caps
|
|
28374
|
+
// pillRightOffset — keeps the right cap at the pill's right edge
|
|
28375
|
+
var anim = Animated.parallel([Animated.timing(indicatorX, {
|
|
28376
|
+
toValue: layout.x,
|
|
28377
|
+
useNativeDriver: true
|
|
28378
|
+
}), Animated.timing(indicatorScaleX, {
|
|
28379
|
+
toValue: indicatorScaleXValue,
|
|
28380
|
+
useNativeDriver: true
|
|
28381
|
+
}), Animated.timing(pillX, {
|
|
28382
|
+
toValue: layout.x,
|
|
28383
|
+
useNativeDriver: true
|
|
28384
|
+
}), Animated.timing(pillBodyScaleX, {
|
|
28385
|
+
toValue: bodyScaleX,
|
|
28386
|
+
useNativeDriver: true
|
|
28387
|
+
}), Animated.timing(pillRightOffset, {
|
|
28388
|
+
toValue: rightOffset,
|
|
28389
|
+
useNativeDriver: true
|
|
28390
|
+
})]);
|
|
28391
|
+
runningAnimRef.current = anim;
|
|
28392
|
+
anim.start(function (_ref2) {
|
|
28393
|
+
var finished = _ref2.finished;
|
|
28394
|
+
if (finished) runningAnimRef.current = null;
|
|
28315
28395
|
});
|
|
28316
|
-
});
|
|
28396
|
+
}, [indicatorX, indicatorScaleX, pillX, pillBodyScaleX, pillRightOffset, pillCapWidth]);
|
|
28397
|
+
// Animate to selected tab whenever selectedIndex changes.
|
|
28317
28398
|
React__default.useEffect(function () {
|
|
28318
|
-
if (
|
|
28319
|
-
|
|
28320
|
-
|
|
28321
|
-
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
}
|
|
28325
|
-
// Split animations into 2 sets of parallel animations to prevent race condition.
|
|
28326
|
-
Animated.parallel([animateOpacity(opacityAnims[selectedIndex], 1), animateTranslateX(translateXAnims[selectedIndex], 0)]).start();
|
|
28327
|
-
Animated.parallel([animateOpacity(opacityAnims[previousIndex.current], 0), animateTranslateX(translateXAnims[previousIndex.current], selectedIndex > previousIndex.current ? 1 : -1)]).start();
|
|
28328
|
-
previousIndex.current = selectedIndex;
|
|
28399
|
+
if (selectedIndex === undefined) return;
|
|
28400
|
+
if (layoutsRef.current[selectedIndex]) {
|
|
28401
|
+
animateTo(selectedIndex, initializedRef.current);
|
|
28402
|
+
} else {
|
|
28403
|
+
// Layout not yet measured — store as pending and resolve in onTabLayout.
|
|
28404
|
+
pendingIndexRef.current = selectedIndex;
|
|
28329
28405
|
}
|
|
28330
|
-
}, [selectedIndex,
|
|
28406
|
+
}, [selectedIndex, animateTo]);
|
|
28407
|
+
// Stop any in-flight animation on unmount.
|
|
28408
|
+
React__default.useEffect(function () {
|
|
28409
|
+
return function () {
|
|
28410
|
+
var _runningAnimRef$curre2;
|
|
28411
|
+
(_runningAnimRef$curre2 = runningAnimRef.current) === null || _runningAnimRef$curre2 === void 0 || _runningAnimRef$curre2.stop();
|
|
28412
|
+
};
|
|
28413
|
+
}, []);
|
|
28414
|
+
var onTabLayout = React__default.useCallback(function (index, event) {
|
|
28415
|
+
var _event$nativeEvent$la = event.nativeEvent.layout,
|
|
28416
|
+
x = _event$nativeEvent$la.x,
|
|
28417
|
+
width = _event$nativeEvent$la.width;
|
|
28418
|
+
var prev = layoutsRef.current[index];
|
|
28419
|
+
// Skip if layout hasn't meaningfully changed (sub-pixel tolerance).
|
|
28420
|
+
if (prev && Math.abs(prev.x - x) < 0.5 && Math.abs(prev.width - width) < 0.5) {
|
|
28421
|
+
return;
|
|
28422
|
+
}
|
|
28423
|
+
layoutsRef.current[index] = {
|
|
28424
|
+
x: x,
|
|
28425
|
+
width: width
|
|
28426
|
+
};
|
|
28427
|
+
// Animate if this tab is the selected one (covers the pending case where
|
|
28428
|
+
// selectedIndex was set before the layout was measured).
|
|
28429
|
+
if (index === selectedIndex || index === pendingIndexRef.current) {
|
|
28430
|
+
if (index === pendingIndexRef.current) pendingIndexRef.current = undefined;
|
|
28431
|
+
animateTo(index, initializedRef.current);
|
|
28432
|
+
}
|
|
28433
|
+
// If no tab is selected yet, snap indicators to tab 0 on its first
|
|
28434
|
+
// layout so they appear at a sensible default position.
|
|
28435
|
+
if (!initializedRef.current && index === 0 && selectedIndex === undefined) {
|
|
28436
|
+
indicatorScaleX.setValue(width);
|
|
28437
|
+
pillX.setValue(x);
|
|
28438
|
+
pillBodyScaleX.setValue(Math.max(width - pillCapWidth * 2, 0));
|
|
28439
|
+
pillRightOffset.setValue(Math.max(width - pillCapWidth, 0));
|
|
28440
|
+
initializedRef.current = true;
|
|
28441
|
+
}
|
|
28442
|
+
}, [animateTo, selectedIndex, pillCapWidth]);
|
|
28443
|
+
// Layer 1: transformOrigin 'left center' pins scaleX expansion to left edge.
|
|
28444
|
+
var indicatorStyle = {
|
|
28445
|
+
transformOrigin: 'left center',
|
|
28446
|
+
transform: [{
|
|
28447
|
+
translateX: indicatorX
|
|
28448
|
+
}, {
|
|
28449
|
+
scaleX: indicatorScaleX
|
|
28450
|
+
}]
|
|
28451
|
+
};
|
|
28452
|
+
// Layer 2: three pieces, all absolutely positioned, all native driver.
|
|
28453
|
+
// Animated.add computes derived positions without creating JS-driver nodes.
|
|
28454
|
+
var pillLeftStyle = {
|
|
28455
|
+
transform: [{
|
|
28456
|
+
translateX: pillX
|
|
28457
|
+
}]
|
|
28458
|
+
};
|
|
28459
|
+
var pillBodyStyle = {
|
|
28460
|
+
transformOrigin: 'left center',
|
|
28461
|
+
transform: [{
|
|
28462
|
+
translateX: Animated.add(pillX, pillCapWidth)
|
|
28463
|
+
}, {
|
|
28464
|
+
scaleX: pillBodyScaleX
|
|
28465
|
+
}]
|
|
28466
|
+
};
|
|
28467
|
+
var pillRightStyle = {
|
|
28468
|
+
transform: [{
|
|
28469
|
+
translateX: Animated.add(pillX, pillRightOffset)
|
|
28470
|
+
}]
|
|
28471
|
+
};
|
|
28331
28472
|
return {
|
|
28332
|
-
|
|
28333
|
-
|
|
28473
|
+
indicatorStyle: indicatorStyle,
|
|
28474
|
+
pillLeftStyle: pillLeftStyle,
|
|
28475
|
+
pillBodyStyle: pillBodyStyle,
|
|
28476
|
+
pillRightStyle: pillRightStyle,
|
|
28477
|
+
onTabLayout: onTabLayout
|
|
28334
28478
|
};
|
|
28335
28479
|
};
|
|
28336
28480
|
|
|
@@ -28350,7 +28494,7 @@ var getTabItem$1 = function getTabItem(_ref) {
|
|
|
28350
28494
|
}
|
|
28351
28495
|
if (typeof item === 'string') {
|
|
28352
28496
|
return /*#__PURE__*/React__default.createElement(Typography.Body, {
|
|
28353
|
-
variant: active ? '
|
|
28497
|
+
variant: active ? 'small-bold' : 'small',
|
|
28354
28498
|
numberOfLines: 1,
|
|
28355
28499
|
style: {
|
|
28356
28500
|
color: color
|
|
@@ -28361,130 +28505,167 @@ var getTabItem$1 = function getTabItem(_ref) {
|
|
|
28361
28505
|
color: color
|
|
28362
28506
|
});
|
|
28363
28507
|
};
|
|
28364
|
-
var
|
|
28365
|
-
var
|
|
28366
|
-
|
|
28367
|
-
|
|
28368
|
-
|
|
28369
|
-
|
|
28370
|
-
|
|
28371
|
-
|
|
28508
|
+
var TabItemComponent = /*#__PURE__*/React__default.memo(function (_ref2) {
|
|
28509
|
+
var _tab$inactiveItem;
|
|
28510
|
+
var tab = _ref2.tab,
|
|
28511
|
+
index = _ref2.index,
|
|
28512
|
+
active = _ref2.active,
|
|
28513
|
+
variant = _ref2.variant,
|
|
28514
|
+
onTabPress = _ref2.onTabPress,
|
|
28515
|
+
onLayout = _ref2.onLayout;
|
|
28516
|
+
var theme = useTheme$1();
|
|
28517
|
+
var isHighlighted = variant === 'highlighted';
|
|
28518
|
+
var getTextColor = function getTextColor() {
|
|
28519
|
+
if (isHighlighted) {
|
|
28520
|
+
if (tab.disabled) return theme.__hd__.tabs.colors.highlightedDisabledText;
|
|
28521
|
+
if (active) return theme.__hd__.tabs.colors.highlightedActiveText;
|
|
28522
|
+
}
|
|
28523
|
+
return active ? theme.__hd__.tabs.colors.active : theme.__hd__.tabs.colors.inactive;
|
|
28524
|
+
};
|
|
28525
|
+
var inactiveItem = (_tab$inactiveItem = tab.inactiveItem) !== null && _tab$inactiveItem !== void 0 ? _tab$inactiveItem : tab.activeItem;
|
|
28526
|
+
var tabItem = getTabItem$1({
|
|
28527
|
+
item: active ? tab.activeItem : inactiveItem,
|
|
28528
|
+
color: getTextColor(),
|
|
28529
|
+
active: active
|
|
28530
|
+
});
|
|
28531
|
+
var handlePress = React__default.useCallback(function () {
|
|
28532
|
+
return onTabPress(tab.key);
|
|
28533
|
+
}, [onTabPress, tab.key]);
|
|
28534
|
+
return /*#__PURE__*/React__default.createElement(TouchableWithoutFeedback, {
|
|
28535
|
+
key: tab.key,
|
|
28536
|
+
onPress: handlePress,
|
|
28537
|
+
testID: tab.testID,
|
|
28538
|
+
disabled: tab.disabled
|
|
28539
|
+
}, /*#__PURE__*/React__default.createElement(HeaderTabItem, {
|
|
28540
|
+
testID: "tab-item-".concat(index),
|
|
28541
|
+
isFirstItem: index === 0,
|
|
28542
|
+
themeVariant: variant,
|
|
28543
|
+
onLayout: onLayout
|
|
28544
|
+
}, /*#__PURE__*/React__default.createElement(HeaderTabItemWrapper, null, /*#__PURE__*/React__default.createElement(TabWithBadge, {
|
|
28545
|
+
config: tab.badge,
|
|
28546
|
+
tabItem: tabItem
|
|
28547
|
+
}))));
|
|
28548
|
+
});
|
|
28549
|
+
var ScrollableTabHeader = function ScrollableTabHeader(_ref3) {
|
|
28550
|
+
var onTabPress = _ref3.onTabPress,
|
|
28551
|
+
rawSelectedIndex = _ref3.selectedIndex,
|
|
28552
|
+
tabs = _ref3.tabs,
|
|
28553
|
+
barStyle = _ref3.barStyle,
|
|
28554
|
+
testID = _ref3.testID,
|
|
28555
|
+
_ref3$insets = _ref3.insets,
|
|
28556
|
+
insets = _ref3$insets === void 0 ? {
|
|
28372
28557
|
top: 0,
|
|
28373
28558
|
bottom: 0,
|
|
28374
28559
|
right: 0,
|
|
28375
28560
|
left: 0
|
|
28376
|
-
} :
|
|
28377
|
-
|
|
28378
|
-
variant =
|
|
28561
|
+
} : _ref3$insets,
|
|
28562
|
+
_ref3$variant = _ref3.variant,
|
|
28563
|
+
variant = _ref3$variant === void 0 ? 'highlighted' : _ref3$variant;
|
|
28564
|
+
var selectedIndex = rawSelectedIndex !== undefined && rawSelectedIndex >= 0 ? rawSelectedIndex : undefined;
|
|
28379
28565
|
var theme = useTheme$1();
|
|
28380
|
-
var
|
|
28381
|
-
|
|
28382
|
-
var
|
|
28383
|
-
tabsLength: tabs.length,
|
|
28384
|
-
selectedIndex: selectedIndex,
|
|
28385
|
-
variant: variant
|
|
28386
|
-
}),
|
|
28387
|
-
underlinedTranslateX = _useInitUnderlinedAni.underlinedTranslateX,
|
|
28388
|
-
underlinedOpacity = _useInitUnderlinedAni.underlinedOpacity;
|
|
28389
|
-
// Init highlighted animation data
|
|
28390
|
-
var _useInitHighlightedAn = useInitHighlightedAnimation({
|
|
28566
|
+
var scrollViewRef = React__default.useRef(null);
|
|
28567
|
+
var isHighlighted = variant === 'highlighted';
|
|
28568
|
+
var _useIndicatorAnimatio = useIndicatorAnimation({
|
|
28391
28569
|
selectedIndex: selectedIndex,
|
|
28392
28570
|
tabsLength: tabs.length,
|
|
28393
|
-
|
|
28571
|
+
pillCapWidth: theme.__hd__.tabs.radii.highlightedOutline
|
|
28394
28572
|
}),
|
|
28395
|
-
|
|
28396
|
-
|
|
28397
|
-
|
|
28398
|
-
|
|
28399
|
-
|
|
28400
|
-
|
|
28401
|
-
|
|
28573
|
+
indicatorStyle = _useIndicatorAnimatio.indicatorStyle,
|
|
28574
|
+
pillLeftStyle = _useIndicatorAnimatio.pillLeftStyle,
|
|
28575
|
+
pillBodyStyle = _useIndicatorAnimatio.pillBodyStyle,
|
|
28576
|
+
pillRightStyle = _useIndicatorAnimatio.pillRightStyle,
|
|
28577
|
+
onTabLayout = _useIndicatorAnimatio.onTabLayout;
|
|
28578
|
+
// Scroll to the selected tab after its layout is known.
|
|
28579
|
+
var handleTabLayout = React__default.useCallback(function (index, event) {
|
|
28580
|
+
if (index === selectedIndex) {
|
|
28581
|
+
var _scrollViewRef$curren;
|
|
28582
|
+
(_scrollViewRef$curren = scrollViewRef.current) === null || _scrollViewRef$curren === void 0 || _scrollViewRef$curren.scrollTo({
|
|
28583
|
+
x: event.nativeEvent.layout.x,
|
|
28584
|
+
animated: true
|
|
28402
28585
|
});
|
|
28403
28586
|
}
|
|
28404
|
-
|
|
28587
|
+
onTabLayout(index, event);
|
|
28588
|
+
}, [selectedIndex, onTabLayout]);
|
|
28589
|
+
// Memoize per-tab layout handlers so TabItemComponent memo is not broken.
|
|
28590
|
+
var tabLayoutHandlers = React__default.useMemo(function () {
|
|
28591
|
+
return tabs.map(function (_, i) {
|
|
28592
|
+
return function (event) {
|
|
28593
|
+
return handleTabLayout(i, event);
|
|
28594
|
+
};
|
|
28595
|
+
});
|
|
28596
|
+
},
|
|
28597
|
+
// Handlers only need to change when tab count or selection changes.
|
|
28598
|
+
[tabs, handleTabLayout]);
|
|
28599
|
+
var scrollViewStyle = React__default.useMemo(function () {
|
|
28600
|
+
return {
|
|
28601
|
+
borderBottomColor: theme.__hd__.tabs.colors.headerBottom,
|
|
28602
|
+
borderBottomWidth: isHighlighted ? theme.__hd__.tabs.borderWidths.highlightedHeaderBottom : theme.__hd__.tabs.sizes.indicator
|
|
28405
28603
|
};
|
|
28406
|
-
}, [
|
|
28604
|
+
}, [theme, isHighlighted]);
|
|
28605
|
+
var contentContainerStyle = React__default.useMemo(function () {
|
|
28606
|
+
return _objectSpread2({
|
|
28607
|
+
paddingHorizontal: theme.__hd__.tabs.space.flatListHorizontalPadding,
|
|
28608
|
+
position: 'relative'
|
|
28609
|
+
}, Platform.OS === 'android' && {
|
|
28610
|
+
borderBottomColor: theme.__hd__.tabs.colors.headerBottom,
|
|
28611
|
+
borderBottomWidth: isHighlighted ? theme.__hd__.tabs.borderWidths.highlightedHeaderBottom : theme.__hd__.tabs.sizes.indicator
|
|
28612
|
+
});
|
|
28613
|
+
}, [theme, isHighlighted]);
|
|
28614
|
+
var wrapperStyle = React__default.useMemo(function () {
|
|
28615
|
+
return [isHighlighted && {
|
|
28616
|
+
paddingTop: theme.__hd__.tabs.space.highlightedBarTopPadding
|
|
28617
|
+
}, barStyle];
|
|
28618
|
+
}, [isHighlighted, theme, barStyle]);
|
|
28407
28619
|
return /*#__PURE__*/React__default.createElement(HeaderTabWrapper, {
|
|
28620
|
+
testID: "tab-header-wrapper",
|
|
28408
28621
|
themeInsets: insets,
|
|
28409
|
-
style:
|
|
28410
|
-
}, /*#__PURE__*/React__default.createElement(
|
|
28622
|
+
style: wrapperStyle
|
|
28623
|
+
}, /*#__PURE__*/React__default.createElement(View, {
|
|
28624
|
+
style: isHighlighted ? {
|
|
28625
|
+
overflow: 'hidden'
|
|
28626
|
+
} : undefined
|
|
28627
|
+
}, /*#__PURE__*/React__default.createElement(ScrollView, {
|
|
28628
|
+
ref: scrollViewRef,
|
|
28411
28629
|
testID: testID,
|
|
28412
|
-
ref: flatListRef,
|
|
28413
28630
|
horizontal: true,
|
|
28414
|
-
data: tabs,
|
|
28415
|
-
keyExtractor: function keyExtractor(tab) {
|
|
28416
|
-
return String(tab.key);
|
|
28417
|
-
},
|
|
28418
28631
|
showsHorizontalScrollIndicator: false,
|
|
28419
|
-
|
|
28420
|
-
|
|
28421
|
-
|
|
28422
|
-
var _flatListRef$current2;
|
|
28423
|
-
return (_flatListRef$current2 = flatListRef.current) === null || _flatListRef$current2 === void 0 ? void 0 : _flatListRef$current2.scrollToIndex({
|
|
28424
|
-
index: index,
|
|
28425
|
-
viewPosition: 0.5
|
|
28426
|
-
});
|
|
28427
|
-
}, 100);
|
|
28428
|
-
},
|
|
28632
|
+
contentContainerStyle: contentContainerStyle,
|
|
28633
|
+
style: scrollViewStyle
|
|
28634
|
+
}, /*#__PURE__*/React__default.createElement(View, {
|
|
28429
28635
|
style: {
|
|
28430
|
-
|
|
28431
|
-
|
|
28432
|
-
},
|
|
28433
|
-
contentContainerStyle: _objectSpread2({
|
|
28434
|
-
paddingHorizontal: theme.__hd__.tabs.space.flatListHorizontalPadding
|
|
28435
|
-
}, Platform.OS === 'android' && {
|
|
28436
|
-
borderBottomColor: theme.__hd__.tabs.colors.headerBottom,
|
|
28437
|
-
borderBottomWidth: theme.__hd__.tabs.sizes.indicator
|
|
28438
|
-
}),
|
|
28439
|
-
renderItem: function renderItem(_ref4) {
|
|
28440
|
-
var tab = _ref4.item,
|
|
28441
|
-
index = _ref4.index;
|
|
28442
|
-
var key = tab.key,
|
|
28443
|
-
tabItemTestID = tab.testID,
|
|
28444
|
-
activeItem = tab.activeItem,
|
|
28445
|
-
originalInactiveItem = tab.inactiveItem,
|
|
28446
|
-
badge = tab.badge;
|
|
28447
|
-
var active = selectedIndex === index;
|
|
28448
|
-
var activeAnimated = tabsAnims[index];
|
|
28449
|
-
var outlineScale = activeAnimated.interpolate({
|
|
28450
|
-
inputRange: [0, 1],
|
|
28451
|
-
outputRange: [0.5, 1]
|
|
28452
|
-
});
|
|
28453
|
-
var inactiveItem = originalInactiveItem !== null && originalInactiveItem !== void 0 ? originalInactiveItem : activeItem;
|
|
28454
|
-
var tabItem = getTabItem$1({
|
|
28455
|
-
item: active ? activeItem : inactiveItem,
|
|
28456
|
-
color: active ? theme.__hd__.tabs.colors.active : theme.__hd__.tabs.colors.inactive,
|
|
28457
|
-
active: active
|
|
28458
|
-
});
|
|
28459
|
-
return /*#__PURE__*/React__default.createElement(TouchableWithoutFeedback, {
|
|
28460
|
-
key: key,
|
|
28461
|
-
onPress: function onPress() {
|
|
28462
|
-
onTabPress(key);
|
|
28463
|
-
},
|
|
28464
|
-
testID: tabItemTestID
|
|
28465
|
-
}, /*#__PURE__*/React__default.createElement(HeaderTabItem, {
|
|
28466
|
-
isFirstItem: index === 0
|
|
28467
|
-
}, variant === 'highlighted' && /*#__PURE__*/React__default.createElement(HeaderTabItemOutlineWrapper, null, /*#__PURE__*/React__default.createElement(HeaderTabItemOutline, {
|
|
28468
|
-
themeActive: active,
|
|
28469
|
-
style: {
|
|
28470
|
-
flex: 1,
|
|
28471
|
-
transform: [{
|
|
28472
|
-
scaleX: outlineScale
|
|
28473
|
-
}]
|
|
28474
|
-
}
|
|
28475
|
-
})), /*#__PURE__*/React__default.createElement(HeaderTabItemWrapper, null, /*#__PURE__*/React__default.createElement(TabWithBadge, {
|
|
28476
|
-
config: badge,
|
|
28477
|
-
tabItem: tabItem
|
|
28478
|
-
})), variant === 'underlined' && /*#__PURE__*/React__default.createElement(HeaderTabItemIndicator, {
|
|
28479
|
-
style: {
|
|
28480
|
-
opacity: underlinedOpacity[index],
|
|
28481
|
-
transform: [{
|
|
28482
|
-
translateX: underlinedTranslateX[index]
|
|
28483
|
-
}]
|
|
28484
|
-
}
|
|
28485
|
-
})));
|
|
28636
|
+
flexDirection: 'row',
|
|
28637
|
+
position: 'relative'
|
|
28486
28638
|
}
|
|
28487
|
-
}
|
|
28639
|
+
}, isHighlighted && /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(HeaderTabPillLeft, {
|
|
28640
|
+
testID: "tab-pill-background",
|
|
28641
|
+
style: pillLeftStyle
|
|
28642
|
+
}), /*#__PURE__*/React__default.createElement(HeaderTabPillBody, {
|
|
28643
|
+
style: pillBodyStyle
|
|
28644
|
+
}), /*#__PURE__*/React__default.createElement(HeaderTabPillRight, {
|
|
28645
|
+
testID: "tab-pill-background-right",
|
|
28646
|
+
style: pillRightStyle
|
|
28647
|
+
})), tabs.map(function (tab, index) {
|
|
28648
|
+
return /*#__PURE__*/React__default.createElement(TabItemComponent, {
|
|
28649
|
+
key: tab.key,
|
|
28650
|
+
tab: tab,
|
|
28651
|
+
index: index,
|
|
28652
|
+
active: selectedIndex === index,
|
|
28653
|
+
variant: variant,
|
|
28654
|
+
onTabPress: onTabPress,
|
|
28655
|
+
onLayout: tabLayoutHandlers[index]
|
|
28656
|
+
});
|
|
28657
|
+
}), isHighlighted ? /*#__PURE__*/React__default.createElement(HeaderTabItemActiveBorder, {
|
|
28658
|
+
testID: "tab-active-border",
|
|
28659
|
+
style: _objectSpread2({
|
|
28660
|
+
position: 'absolute',
|
|
28661
|
+
bottom: 0
|
|
28662
|
+
}, indicatorStyle)
|
|
28663
|
+
}) : /*#__PURE__*/React__default.createElement(HeaderTabItemIndicator, {
|
|
28664
|
+
testID: "tab-underline-indicator",
|
|
28665
|
+
style: _objectSpread2({
|
|
28666
|
+
position: 'absolute'
|
|
28667
|
+
}, indicatorStyle)
|
|
28668
|
+
})))));
|
|
28488
28669
|
};
|
|
28489
28670
|
|
|
28490
28671
|
var useHandlePageScroll = function useHandlePageScroll() {
|