@hero-design/rn 8.130.2 → 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/es/index.js CHANGED
@@ -4977,7 +4977,7 @@ var swagLightGlobalPalette = _objectSpread2(_objectSpread2({}, globalPalette$1),
4977
4977
  });
4978
4978
 
4979
4979
  var ehWorkBrandSystemPalette = {
4980
- primary: '#460078',
4980
+ primary: '#7622d7',
4981
4981
  onPrimary: '#fdfbff',
4982
4982
  secondary: '#b382fd',
4983
4983
  onSecondary: palette$4.white,
@@ -5006,6 +5006,7 @@ var swagSystemPalette = _objectSpread2(_objectSpread2({}, ehWorkSystemPalette),
5006
5006
 
5007
5007
  var ehJobsSystemPalette = _objectSpread2(_objectSpread2({}, swagSystemPalette), {}, {
5008
5008
  name: 'ehJobs',
5009
+ primary: '#7622d7',
5009
5010
  secondary: '#40d1ff',
5010
5011
  onSecondary: '#460078',
5011
5012
  secondaryHighlightedSurface: '#ecfaff',
@@ -7136,7 +7137,11 @@ var getTabsTheme = function getTabsTheme(theme) {
7136
7137
  headerBottom: theme.colors.secondaryOutline,
7137
7138
  indicator: theme.colors.primary,
7138
7139
  text: theme.colors.onDefaultGlobalSurface,
7139
- 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
7140
7145
  };
7141
7146
  var space = {
7142
7147
  flatListHorizontalPadding: theme.space.small,
@@ -7144,14 +7149,17 @@ var getTabsTheme = function getTabsTheme(theme) {
7144
7149
  itemVerticalPadding: theme.space.small,
7145
7150
  itemMargin: theme.space.smallMedium,
7146
7151
  outlineHorizontalPadding: theme.space.small,
7147
- outlineVerticalPadding: theme.space.xsmall,
7148
- tabIndicatorBottom: -theme.space.xxsmall
7152
+ tabIndicatorBottom: -theme.space.xxsmall,
7153
+ highlightedItemMargin: theme.space.xsmall,
7154
+ highlightedBarTopPadding: theme.space.xxsmall
7149
7155
  };
7150
7156
  var radii = {
7151
- outline: theme.radii.xlarge
7157
+ highlightedOutline: theme.radii.medium
7152
7158
  };
7153
7159
  var borderWidths = {
7154
- headerBottom: theme.borderWidths.medium
7160
+ headerBottom: theme.borderWidths.medium,
7161
+ highlightedHeaderBottom: theme.borderWidths.base,
7162
+ highlightedActiveBorder: theme.borderWidths.base
7155
7163
  };
7156
7164
  var sizes = {
7157
7165
  indicator: theme.sizes.xxsmall
@@ -28110,43 +28118,85 @@ var HeaderTabWrapper = index$c(View)(function (_ref) {
28110
28118
  backgroundColor: theme.__hd__.tabs.colors.headerBackground
28111
28119
  };
28112
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
+ };
28113
28126
  var HeaderTabItem = index$c(Animated.View)(function (_ref2) {
28114
28127
  var theme = _ref2.theme,
28115
- isFirstItem = _ref2.isFirstItem;
28128
+ isFirstItem = _ref2.isFirstItem,
28129
+ themeVariant = _ref2.themeVariant;
28116
28130
  return {
28117
- marginLeft: isFirstItem ? 0 : theme.__hd__.tabs.space.itemMargin,
28118
- 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'
28119
28135
  };
28120
28136
  });
28121
- var HeaderTabItemOutlineWrapper = index$c(View)(function (_ref3) {
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) {
28122
28142
  var theme = _ref3.theme;
28123
- return _objectSpread2({
28124
- paddingVertical: theme.__hd__.tabs.space.itemVerticalPadding
28125
- }, StyleSheet$1.absoluteFillObject);
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
+ };
28126
28152
  });
28127
- var HeaderTabItemOutline = index$c(Animated.View)(function (_ref4) {
28128
- var theme = _ref4.theme,
28129
- themeActive = _ref4.themeActive;
28153
+ var HeaderTabPillBody = index$c(Animated.View)(function (_ref4) {
28154
+ var theme = _ref4.theme;
28130
28155
  return {
28131
- borderRadius: theme.__hd__.tabs.radii.outline,
28132
- backgroundColor: themeActive ? theme.__hd__.tabs.colors.activeBackground : undefined
28156
+ position: 'absolute',
28157
+ top: 0,
28158
+ bottom: 0,
28159
+ left: 0,
28160
+ width: 1,
28161
+ backgroundColor: theme.__hd__.tabs.colors.highlightedActiveBackground
28133
28162
  };
28134
28163
  });
28135
- var HeaderTabItemWrapper = index$c(View)(function (_ref5) {
28164
+ var HeaderTabPillRight = index$c(Animated.View)(function (_ref5) {
28136
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;
28137
28188
  return _objectSpread2({
28138
28189
  paddingHorizontal: theme.__hd__.tabs.space.outlineHorizontalPadding,
28139
- paddingVertical: theme.__hd__.tabs.space.outlineVerticalPadding,
28140
28190
  position: 'relative',
28141
28191
  justifyContent: 'center'
28142
28192
  }, !isAndroid8 && {
28143
28193
  alignItems: 'center'
28144
28194
  });
28145
28195
  });
28146
- var HeaderTabItemIndicator = index$c(Animated.View)(function (_ref6) {
28147
- var theme = _ref6.theme;
28196
+ var HeaderTabItemIndicator = index$c(Animated.View)(function (_ref8) {
28197
+ var theme = _ref8.theme;
28148
28198
  return {
28149
- width: '100%',
28199
+ width: 1,
28150
28200
  height: theme.__hd__.tabs.sizes.indicator,
28151
28201
  position: 'absolute',
28152
28202
  bottom: theme.__hd__.tabs.space.tabIndicatorBottom,
@@ -28227,109 +28277,204 @@ var TabWithBadge = function TabWithBadge(_ref) {
28227
28277
  return /*#__PURE__*/React__default.createElement(View, null, tabItem);
28228
28278
  };
28229
28279
 
28230
- var useAnimatedValueArray = function useAnimatedValueArray(initialValues) {
28231
- var refs = React__default.useRef([]);
28232
- refs.current.length = initialValues.length;
28233
- initialValues.forEach(function (initialValue, i) {
28234
- var _refs$current$i;
28235
- refs.current[i] = (_refs$current$i = refs.current[i]) !== null && _refs$current$i !== void 0 ? _refs$current$i : new Animated.Value(initialValue);
28236
- });
28237
- return refs.current;
28238
- };
28239
-
28240
- var useInitHighlightedAnimation = function useInitHighlightedAnimation(_ref) {
28241
- var _ref$selectedIndex = _ref.selectedIndex,
28242
- selectedIndex = _ref$selectedIndex === void 0 ? 0 : _ref$selectedIndex,
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,
28243
28320
  tabsLength = _ref.tabsLength,
28244
- variant = _ref.variant;
28245
- var tabsAnims = useAnimatedValueArray(Array.from({
28246
- length: tabsLength
28247
- }).map(function (_, i) {
28248
- return i === selectedIndex ? 1 : 0;
28249
- }));
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.
28250
28338
  React__default.useEffect(function () {
28251
- if (variant !== 'highlighted') {
28252
- return;
28253
- }
28254
- var animation = Animated.parallel(_toConsumableArray(Array.from({
28339
+ layoutsRef.current = Array.from({
28255
28340
  length: tabsLength
28256
- }).map(function (_, i) {
28257
- return Animated.timing(tabsAnims[i], {
28258
- toValue: i === selectedIndex ? 1 : 0,
28259
- duration: 150,
28260
- useNativeDriver: Platform.OS !== 'web'
28261
- });
28262
- })));
28263
- animation.start();
28264
- return function () {
28265
- animation.stop();
28266
- };
28267
- }, [selectedIndex]);
28268
- return {
28269
- tabsAnims: tabsAnims
28270
- };
28271
- };
28272
-
28273
- var TRANSLATE_DISTANCE = 30;
28274
- var animateOpacity = function animateOpacity(animatedValue, toValue) {
28275
- return Animated.timing(animatedValue, {
28276
- toValue: toValue,
28277
- duration: 150,
28278
- easing: Easing.ease,
28279
- useNativeDriver: Platform.OS !== 'web'
28280
- });
28281
- };
28282
- var animateTranslateX = function animateTranslateX(animatedValue, toValue) {
28283
- return Animated.spring(animatedValue, {
28284
- toValue: toValue,
28285
- useNativeDriver: Platform.OS !== 'web'
28286
- });
28287
- };
28288
- var useInitUnderlinedAnimation = function useInitUnderlinedAnimation(_ref) {
28289
- var tabsLength = _ref.tabsLength,
28290
- _ref$selectedIndex = _ref.selectedIndex,
28291
- selectedIndex = _ref$selectedIndex === void 0 ? 0 : _ref$selectedIndex,
28292
- variant = _ref.variant;
28293
- var previousIndex = React__default.useRef(0);
28294
- var translateXAnims = useAnimatedValueArray(Array.from({
28295
- length: tabsLength
28296
- }).map(function () {
28297
- return 0;
28298
- }));
28299
- var opacityAnims = useAnimatedValueArray(Array.from({
28300
- length: tabsLength
28301
- }).map(function (_, i) {
28302
- return selectedIndex !== undefined && selectedIndex === i ? 1 : 0;
28303
- }));
28304
- var underlinedTranslateX = translateXAnims.map(function (anim) {
28305
- return anim.interpolate({
28306
- inputRange: [-1, 0, 1],
28307
- outputRange: [-TRANSLATE_DISTANCE, 0, TRANSLATE_DISTANCE]
28341
+ }, function (_, i) {
28342
+ return layoutsRef.current[i];
28308
28343
  });
28309
- });
28310
- var underlinedOpacity = opacityAnims.map(function (anim) {
28311
- return anim.interpolate({
28312
- inputRange: [0, 1],
28313
- outputRange: [0, 1]
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;
28314
28395
  });
28315
- });
28396
+ }, [indicatorX, indicatorScaleX, pillX, pillBodyScaleX, pillRightOffset, pillCapWidth]);
28397
+ // Animate to selected tab whenever selectedIndex changes.
28316
28398
  React__default.useEffect(function () {
28317
- if (variant === 'underlined' && selectedIndex !== undefined && previousIndex.current !== selectedIndex) {
28318
- // Prepare for translateX into the right position.
28319
- if (selectedIndex > previousIndex.current) {
28320
- translateXAnims[selectedIndex].setValue(-1);
28321
- } else {
28322
- translateXAnims[selectedIndex].setValue(1);
28323
- }
28324
- // Split animations into 2 sets of parallel animations to prevent race condition.
28325
- Animated.parallel([animateOpacity(opacityAnims[selectedIndex], 1), animateTranslateX(translateXAnims[selectedIndex], 0)]).start();
28326
- Animated.parallel([animateOpacity(opacityAnims[previousIndex.current], 0), animateTranslateX(translateXAnims[previousIndex.current], selectedIndex > previousIndex.current ? 1 : -1)]).start();
28327
- 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;
28328
28405
  }
28329
- }, [selectedIndex, variant, opacityAnims, translateXAnims]);
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
+ };
28330
28472
  return {
28331
- underlinedTranslateX: underlinedTranslateX,
28332
- underlinedOpacity: underlinedOpacity
28473
+ indicatorStyle: indicatorStyle,
28474
+ pillLeftStyle: pillLeftStyle,
28475
+ pillBodyStyle: pillBodyStyle,
28476
+ pillRightStyle: pillRightStyle,
28477
+ onTabLayout: onTabLayout
28333
28478
  };
28334
28479
  };
28335
28480
 
@@ -28349,7 +28494,7 @@ var getTabItem$1 = function getTabItem(_ref) {
28349
28494
  }
28350
28495
  if (typeof item === 'string') {
28351
28496
  return /*#__PURE__*/React__default.createElement(Typography.Body, {
28352
- variant: active ? 'regular-bold' : 'regular',
28497
+ variant: active ? 'small-bold' : 'small',
28353
28498
  numberOfLines: 1,
28354
28499
  style: {
28355
28500
  color: color
@@ -28360,130 +28505,167 @@ var getTabItem$1 = function getTabItem(_ref) {
28360
28505
  color: color
28361
28506
  });
28362
28507
  };
28363
- var ScrollableTabHeader = function ScrollableTabHeader(_ref2) {
28364
- var onTabPress = _ref2.onTabPress,
28365
- selectedIndex = _ref2.selectedIndex,
28366
- tabs = _ref2.tabs,
28367
- barStyle = _ref2.barStyle,
28368
- testID = _ref2.testID,
28369
- _ref2$insets = _ref2.insets,
28370
- insets = _ref2$insets === void 0 ? {
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 ? {
28371
28557
  top: 0,
28372
28558
  bottom: 0,
28373
28559
  right: 0,
28374
28560
  left: 0
28375
- } : _ref2$insets,
28376
- _ref2$variant = _ref2.variant,
28377
- variant = _ref2$variant === void 0 ? 'highlighted' : _ref2$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;
28378
28565
  var theme = useTheme$1();
28379
- var flatListRef = React__default.useRef(null);
28380
- // Init underlined animation data
28381
- var _useInitUnderlinedAni = useInitUnderlinedAnimation({
28382
- tabsLength: tabs.length,
28383
- selectedIndex: selectedIndex,
28384
- variant: variant
28385
- }),
28386
- underlinedTranslateX = _useInitUnderlinedAni.underlinedTranslateX,
28387
- underlinedOpacity = _useInitUnderlinedAni.underlinedOpacity;
28388
- // Init highlighted animation data
28389
- var _useInitHighlightedAn = useInitHighlightedAnimation({
28566
+ var scrollViewRef = React__default.useRef(null);
28567
+ var isHighlighted = variant === 'highlighted';
28568
+ var _useIndicatorAnimatio = useIndicatorAnimation({
28390
28569
  selectedIndex: selectedIndex,
28391
28570
  tabsLength: tabs.length,
28392
- variant: variant
28571
+ pillCapWidth: theme.__hd__.tabs.radii.highlightedOutline
28393
28572
  }),
28394
- tabsAnims = _useInitHighlightedAn.tabsAnims;
28395
- React__default.useEffect(function () {
28396
- if (selectedIndex !== undefined && selectedIndex !== -1) {
28397
- var _flatListRef$current;
28398
- (_flatListRef$current = flatListRef.current) === null || _flatListRef$current === void 0 || _flatListRef$current.scrollToIndex({
28399
- index: selectedIndex,
28400
- viewPosition: 0.5
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
28401
28585
  });
28402
28586
  }
28403
- return function () {
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
28404
28603
  };
28405
- }, [selectedIndex]);
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]);
28406
28619
  return /*#__PURE__*/React__default.createElement(HeaderTabWrapper, {
28620
+ testID: "tab-header-wrapper",
28407
28621
  themeInsets: insets,
28408
- style: barStyle
28409
- }, /*#__PURE__*/React__default.createElement(FlatList, {
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,
28410
28629
  testID: testID,
28411
- ref: flatListRef,
28412
28630
  horizontal: true,
28413
- data: tabs,
28414
- keyExtractor: function keyExtractor(tab) {
28415
- return String(tab.key);
28416
- },
28417
28631
  showsHorizontalScrollIndicator: false,
28418
- onScrollToIndexFailed: function onScrollToIndexFailed(_ref3) {
28419
- var index = _ref3.index;
28420
- setTimeout(function () {
28421
- var _flatListRef$current2;
28422
- return (_flatListRef$current2 = flatListRef.current) === null || _flatListRef$current2 === void 0 ? void 0 : _flatListRef$current2.scrollToIndex({
28423
- index: index,
28424
- viewPosition: 0.5
28425
- });
28426
- }, 100);
28427
- },
28632
+ contentContainerStyle: contentContainerStyle,
28633
+ style: scrollViewStyle
28634
+ }, /*#__PURE__*/React__default.createElement(View, {
28428
28635
  style: {
28429
- borderBottomColor: theme.__hd__.tabs.colors.headerBottom,
28430
- borderBottomWidth: theme.__hd__.tabs.sizes.indicator
28431
- },
28432
- contentContainerStyle: _objectSpread2({
28433
- paddingHorizontal: theme.__hd__.tabs.space.flatListHorizontalPadding
28434
- }, Platform.OS === 'android' && {
28435
- borderBottomColor: theme.__hd__.tabs.colors.headerBottom,
28436
- borderBottomWidth: theme.__hd__.tabs.sizes.indicator
28437
- }),
28438
- renderItem: function renderItem(_ref4) {
28439
- var tab = _ref4.item,
28440
- index = _ref4.index;
28441
- var key = tab.key,
28442
- tabItemTestID = tab.testID,
28443
- activeItem = tab.activeItem,
28444
- originalInactiveItem = tab.inactiveItem,
28445
- badge = tab.badge;
28446
- var active = selectedIndex === index;
28447
- var activeAnimated = tabsAnims[index];
28448
- var outlineScale = activeAnimated.interpolate({
28449
- inputRange: [0, 1],
28450
- outputRange: [0.5, 1]
28451
- });
28452
- var inactiveItem = originalInactiveItem !== null && originalInactiveItem !== void 0 ? originalInactiveItem : activeItem;
28453
- var tabItem = getTabItem$1({
28454
- item: active ? activeItem : inactiveItem,
28455
- color: active ? theme.__hd__.tabs.colors.active : theme.__hd__.tabs.colors.inactive,
28456
- active: active
28457
- });
28458
- return /*#__PURE__*/React__default.createElement(TouchableWithoutFeedback, {
28459
- key: key,
28460
- onPress: function onPress() {
28461
- onTabPress(key);
28462
- },
28463
- testID: tabItemTestID
28464
- }, /*#__PURE__*/React__default.createElement(HeaderTabItem, {
28465
- isFirstItem: index === 0
28466
- }, variant === 'highlighted' && /*#__PURE__*/React__default.createElement(HeaderTabItemOutlineWrapper, null, /*#__PURE__*/React__default.createElement(HeaderTabItemOutline, {
28467
- themeActive: active,
28468
- style: {
28469
- flex: 1,
28470
- transform: [{
28471
- scaleX: outlineScale
28472
- }]
28473
- }
28474
- })), /*#__PURE__*/React__default.createElement(HeaderTabItemWrapper, null, /*#__PURE__*/React__default.createElement(TabWithBadge, {
28475
- config: badge,
28476
- tabItem: tabItem
28477
- })), variant === 'underlined' && /*#__PURE__*/React__default.createElement(HeaderTabItemIndicator, {
28478
- style: {
28479
- opacity: underlinedOpacity[index],
28480
- transform: [{
28481
- translateX: underlinedTranslateX[index]
28482
- }]
28483
- }
28484
- })));
28636
+ flexDirection: 'row',
28637
+ position: 'relative'
28485
28638
  }
28486
- }));
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
+ })))));
28487
28669
  };
28488
28670
 
28489
28671
  var useHandlePageScroll = function useHandlePageScroll() {