@hero-design/rn 8.59.0 → 8.61.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.
Files changed (35) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/es/index.js +220 -112
  4. package/lib/index.js +220 -112
  5. package/package.json +1 -1
  6. package/src/components/AnimatedScroller/AnimatedFAB.tsx +99 -49
  7. package/src/components/AnimatedScroller/AnimatedScrollable.tsx +18 -3
  8. package/src/components/AnimatedScroller/__tests__/ScrollablesWithFAB.spec.tsx +30 -9
  9. package/src/components/AnimatedScroller/__tests__/__snapshots__/ScrollablesWithFAB.spec.tsx.snap +474 -447
  10. package/src/components/FAB/ActionGroup/ActionItem.tsx +3 -1
  11. package/src/components/FAB/ActionGroup/__tests__/__snapshots__/index.spec.tsx.snap +216 -211
  12. package/src/components/FAB/ActionGroup/index.tsx +34 -28
  13. package/src/components/FAB/FAB.tsx +102 -41
  14. package/src/components/FAB/StyledFAB.tsx +10 -8
  15. package/src/components/FAB/__tests__/__snapshots__/StyledFAB.spec.tsx.snap +34 -38
  16. package/src/components/FAB/__tests__/__snapshots__/index.spec.tsx.snap +191 -170
  17. package/src/components/Radio/Radio.tsx +16 -4
  18. package/src/components/Radio/RadioGroup.tsx +10 -3
  19. package/src/components/Radio/StyledRadio.tsx +20 -3
  20. package/src/components/Radio/__tests__/Radio.spec.tsx +46 -13
  21. package/src/components/Radio/__tests__/RadioGroup.spec.tsx +40 -7
  22. package/src/components/Radio/__tests__/__snapshots__/Radio.spec.tsx.snap +446 -77
  23. package/src/components/Radio/__tests__/__snapshots__/RadioGroup.spec.tsx.snap +946 -112
  24. package/src/components/Radio/types.ts +6 -1
  25. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +8 -2
  26. package/src/theme/components/radio.ts +8 -2
  27. package/types/components/AnimatedScroller/AnimatedFAB.d.ts +3 -1
  28. package/types/components/AnimatedScroller/AnimatedScrollable.d.ts +1 -1
  29. package/types/components/FAB/StyledFAB.d.ts +4 -6
  30. package/types/components/Radio/Radio.d.ts +9 -1
  31. package/types/components/Radio/RadioGroup.d.ts +5 -1
  32. package/types/components/Radio/StyledRadio.d.ts +11 -1
  33. package/types/components/Radio/index.d.ts +1 -1
  34. package/types/components/Radio/types.d.ts +1 -0
  35. package/types/theme/components/radio.d.ts +7 -1
package/lib/index.js CHANGED
@@ -2964,11 +2964,17 @@ var getProgressTheme = function getProgressTheme(theme) {
2964
2964
 
2965
2965
  var getRadioTheme = function getRadioTheme(theme) {
2966
2966
  var colors = {
2967
- circle: theme.colors.onDefaultGlobalSurface
2967
+ circle: theme.colors.primary,
2968
+ checked: theme.colors.highlightedSurface,
2969
+ intents: {
2970
+ light: theme.colors.defaultGlobalSurface,
2971
+ dark: theme.colors.neutralGlobalSurface
2972
+ }
2968
2973
  };
2969
2974
  var space = {
2970
2975
  circleLeftMargin: theme.space.small,
2971
- groupTopMargin: theme.space.xsmall
2976
+ groupTopMarginSmall: theme.space.xsmall,
2977
+ groupTopMarginMedium: theme.space.medium
2972
2978
  };
2973
2979
  var boundingBoxSize = theme.sizes.large;
2974
2980
  var innerPadding = theme.space.xsmall;
@@ -14416,7 +14422,8 @@ var Error$1 = function Error(_ref2) {
14416
14422
  }, nativeProps));
14417
14423
  };
14418
14424
 
14419
- var StyledFAB$1 = index$9(reactNative.TouchableHighlight)(function (_ref) {
14425
+ var AnimatedTouchableHighlight = reactNative.Animated.createAnimatedComponent(reactNative.TouchableHighlight);
14426
+ var StyledFAB$1 = index$9(AnimatedTouchableHighlight)(function (_ref) {
14420
14427
  var theme = _ref.theme,
14421
14428
  themeActive = _ref.themeActive;
14422
14429
  return {
@@ -14431,7 +14438,8 @@ var StyledFAB$1 = index$9(reactNative.TouchableHighlight)(function (_ref) {
14431
14438
  shadowColor: theme.__hd__.fab.shadows.color,
14432
14439
  shadowOffset: theme.__hd__.fab.shadows.offset,
14433
14440
  shadowRadius: theme.__hd__.fab.shadows.radius,
14434
- shadowOpacity: theme.__hd__.fab.shadows.opacity
14441
+ shadowOpacity: theme.__hd__.fab.shadows.opacity,
14442
+ height: theme.__hd__.fab.sizes.height
14435
14443
  };
14436
14444
  });
14437
14445
  var StyledFABIcon = index$9(Icon)(function (_ref2) {
@@ -14523,16 +14531,14 @@ var IconWithTextContent = function IconWithTextContent(_ref2) {
14523
14531
  testID: "styled-fab-icon"
14524
14532
  })), /*#__PURE__*/React__default["default"].createElement(StyledFABText, null, title));
14525
14533
  };
14526
- var defaultAnimation = {
14527
- create: {
14528
- type: 'easeInEaseOut',
14529
- property: 'opacity'
14530
- },
14531
- update: {
14532
- type: 'spring',
14533
- springDamping: reactNative.Platform.OS === 'ios' ? 0.7 : 1.2
14534
- },
14535
- duration: reactNative.Platform.OS === 'ios' ? 300 : 400
14534
+ var animateWidth = function animateWidth() {
14535
+ reactNative.LayoutAnimation.configureNext({
14536
+ duration: reactNative.Platform.OS === 'ios' ? 200 : 400,
14537
+ update: {
14538
+ type: 'spring',
14539
+ springDamping: reactNative.Platform.OS === 'ios' ? 1 : 1.5
14540
+ }
14541
+ });
14536
14542
  };
14537
14543
  var FAB$1 = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
14538
14544
  var _StyleSheet$flatten, _StyleSheet$flatten2;
@@ -14544,61 +14550,99 @@ var FAB$1 = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
14544
14550
  active = _ref3.active,
14545
14551
  style = _ref3.style;
14546
14552
  var theme = useTheme();
14547
- var _React$useState = React__default["default"].useState(false),
14548
- _React$useState2 = _slicedToArray(_React$useState, 2),
14549
- canAnimate = _React$useState2[0],
14550
- setCanAnimate = _React$useState2[1];
14551
- var _React$useState3 = React__default["default"].useState({
14553
+ var _React$useState = React__default["default"].useState({
14552
14554
  hideTitle: false,
14553
14555
  hideButton: false
14554
14556
  }),
14555
- _React$useState4 = _slicedToArray(_React$useState3, 2),
14556
- displayState = _React$useState4[0],
14557
- setDisplayState = _React$useState4[1];
14557
+ _React$useState2 = _slicedToArray(_React$useState, 2),
14558
+ displayState = _React$useState2[0],
14559
+ setDisplayState = _React$useState2[1];
14558
14560
  var isIconOnly = displayState.hideTitle || active || !title;
14561
+ var animatedValues = {
14562
+ opacity: React__default["default"].useRef(new reactNative.Animated.Value(1)).current,
14563
+ width: React__default["default"].useRef(new reactNative.Animated.Value(1)).current,
14564
+ translateY: React__default["default"].useRef(new reactNative.Animated.Value(0)).current
14565
+ };
14566
+ var marginBottom = Number((_StyleSheet$flatten = reactNative.StyleSheet.flatten(style)) === null || _StyleSheet$flatten === void 0 ? void 0 : _StyleSheet$flatten.marginBottom) || 0;
14567
+ var _React$useState3 = React__default["default"].useState(0),
14568
+ _React$useState4 = _slicedToArray(_React$useState3, 2),
14569
+ buttonWidth = _React$useState4[0],
14570
+ setButtonWidth = _React$useState4[1];
14571
+ var hasSetButtonWidth = buttonWidth > 0;
14559
14572
  React__default["default"].useImperativeHandle(ref, function () {
14560
14573
  return {
14561
14574
  show: function show() {
14575
+ reactNative.Animated.spring(animatedValues.translateY, {
14576
+ toValue: 0,
14577
+ useNativeDriver: true
14578
+ }).start();
14562
14579
  setDisplayState({
14563
14580
  hideButton: false,
14564
14581
  hideTitle: false
14565
14582
  });
14583
+ animateWidth();
14584
+ reactNative.Animated.spring(animatedValues.opacity, {
14585
+ toValue: 1,
14586
+ useNativeDriver: true
14587
+ }).start();
14566
14588
  },
14567
14589
  collapse: function collapse() {
14590
+ reactNative.Animated.parallel([reactNative.Animated.spring(animatedValues.opacity, {
14591
+ toValue: 1,
14592
+ useNativeDriver: true
14593
+ }), reactNative.Animated.spring(animatedValues.translateY, {
14594
+ toValue: 0,
14595
+ useNativeDriver: true
14596
+ })]).start();
14597
+ animateWidth();
14568
14598
  setDisplayState({
14569
14599
  hideButton: false,
14570
14600
  hideTitle: true
14571
14601
  });
14572
14602
  },
14573
14603
  hide: function hide() {
14574
- setDisplayState(function (previousState) {
14575
- return _objectSpread2(_objectSpread2({}, previousState), {}, {
14576
- hideButton: true
14604
+ reactNative.Animated.stagger(20, [reactNative.Animated.spring(animatedValues.opacity, {
14605
+ toValue: 0,
14606
+ useNativeDriver: true
14607
+ }), reactNative.Animated.spring(animatedValues.translateY, {
14608
+ toValue: 1,
14609
+ useNativeDriver: true
14610
+ })]).start(function () {
14611
+ animateWidth();
14612
+ setDisplayState(function (previousState) {
14613
+ return _objectSpread2(_objectSpread2({}, previousState), {}, {
14614
+ hideButton: true
14615
+ });
14577
14616
  });
14578
14617
  });
14579
14618
  }
14580
14619
  };
14581
14620
  }, []);
14582
- React__default["default"].useEffect(function () {
14583
- if (canAnimate) {
14584
- reactNative.LayoutAnimation.configureNext(defaultAnimation);
14585
- }
14586
- }, [isIconOnly, displayState.hideButton, canAnimate]);
14587
- var marginBottom = Number((_StyleSheet$flatten = reactNative.StyleSheet.flatten(style)) === null || _StyleSheet$flatten === void 0 ? void 0 : _StyleSheet$flatten.marginBottom) || 0;
14588
- return /*#__PURE__*/React__default["default"].createElement(StyledFAB$1
14589
- /** Add a small timeout before executing animation to prevent flakiness */, {
14590
- onLayout: function onLayout() {
14591
- return setTimeout(function () {
14592
- return setCanAnimate(true);
14593
- }, 500);
14621
+ return /*#__PURE__*/React__default["default"].createElement(StyledFAB$1, {
14622
+ onLayout: function onLayout(event) {
14623
+ return !hasSetButtonWidth && !active && setButtonWidth(event.nativeEvent.layout.width);
14594
14624
  },
14595
14625
  underlayColor: theme.__hd__.fab.colors.buttonPressedBackground,
14596
14626
  onPress: onPress,
14597
14627
  style: [style, {
14598
- bottom: displayState.hideButton ? -(marginBottom + theme.__hd__.fab.sizes.height * 2) : (_StyleSheet$flatten2 = reactNative.StyleSheet.flatten(style)) === null || _StyleSheet$flatten2 === void 0 ? void 0 : _StyleSheet$flatten2.bottom
14628
+ bottom: displayState.hideButton ? -(marginBottom + theme.__hd__.fab.sizes.height * 2) : (_StyleSheet$flatten2 = reactNative.StyleSheet.flatten(style)) === null || _StyleSheet$flatten2 === void 0 ? void 0 : _StyleSheet$flatten2.bottom,
14629
+ transform: [{
14630
+ translateY: animatedValues.translateY.interpolate({
14631
+ inputRange: [0, 1],
14632
+ outputRange: [0, marginBottom + theme.__hd__.fab.sizes.height * 2]
14633
+ })
14634
+ }]
14599
14635
  }],
14600
14636
  testID: testID,
14601
14637
  themeActive: active
14638
+ }, /*#__PURE__*/React__default["default"].createElement(reactNative.Animated.View, {
14639
+ style: {
14640
+ flexDirection: 'row',
14641
+ opacity: animatedValues.opacity.interpolate({
14642
+ inputRange: [0, 1],
14643
+ outputRange: [0, 1]
14644
+ })
14645
+ }
14602
14646
  }, isIconOnly ? /*#__PURE__*/React__default["default"].createElement(IconOnlyContent, {
14603
14647
  animated: animated,
14604
14648
  active: active,
@@ -14606,7 +14650,7 @@ var FAB$1 = /*#__PURE__*/React.forwardRef(function (_ref3, ref) {
14606
14650
  }) : /*#__PURE__*/React__default["default"].createElement(IconWithTextContent, {
14607
14651
  icon: icon,
14608
14652
  title: title
14609
- }));
14653
+ })));
14610
14654
  });
14611
14655
  FAB$1.displayName = 'FAB';
14612
14656
 
@@ -14656,7 +14700,9 @@ var ActionItem = function ActionItem(_ref) {
14656
14700
  reactNative.Animated.spring(animatedValue.current, {
14657
14701
  toValue: active ? 1 : 0,
14658
14702
  useNativeDriver: reactNative.Platform.OS !== 'web',
14659
- delay: index * 20
14703
+ delay: index * 30,
14704
+ speed: 10,
14705
+ bounciness: 10
14660
14706
  }).start();
14661
14707
  }, [active, index]);
14662
14708
  return /*#__PURE__*/React__default["default"].createElement(reactNative.Animated.View, {
@@ -14733,8 +14779,9 @@ var ActionGroup = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
14733
14779
  _ref$fabIcon = _ref.fabIcon,
14734
14780
  fabIcon = _ref$fabIcon === void 0 ? 'add' : _ref$fabIcon;
14735
14781
  useDeprecation("FAB.ActionGroup's headerTitle prop will be removed in the next major release. Please remove it.", headerTitle !== undefined);
14782
+ var theme = useTheme();
14736
14783
  var fabRef = React.useRef(null);
14737
- var tranlateXAnimation = React.useRef(new reactNative.Animated.Value(active ? 1 : 0));
14784
+ var animatedValue = React.useRef(new reactNative.Animated.Value(active ? 1 : 0));
14738
14785
  React__default["default"].useImperativeHandle(ref, function () {
14739
14786
  return {
14740
14787
  showFAB: function showFAB() {
@@ -14752,28 +14799,28 @@ var ActionGroup = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
14752
14799
  };
14753
14800
  }, [fabRef]);
14754
14801
  React__default["default"].useEffect(function () {
14755
- reactNative.Animated.spring(tranlateXAnimation.current, {
14802
+ reactNative.Animated.spring(animatedValue.current, {
14756
14803
  toValue: active ? 1 : 0,
14804
+ delay: 100,
14757
14805
  useNativeDriver: reactNative.Platform.OS !== 'web'
14758
14806
  }).start();
14807
+ if (active) {
14808
+ var _fabRef$current4;
14809
+ (_fabRef$current4 = fabRef.current) === null || _fabRef$current4 === void 0 || _fabRef$current4.collapse();
14810
+ } else {
14811
+ var _fabRef$current5;
14812
+ (_fabRef$current5 = fabRef.current) === null || _fabRef$current5 === void 0 || _fabRef$current5.show();
14813
+ }
14759
14814
  }, [active]);
14760
- var interpolatedActionGroupOpacityAnimation = tranlateXAnimation.current.interpolate({
14815
+ var actionGroupOpacity = animatedValue.current.interpolate({
14761
14816
  inputRange: [0, 1],
14762
14817
  outputRange: [0, 1]
14763
14818
  });
14764
- var interpolatedFABOpacityAnimation = tranlateXAnimation.current.interpolate({
14765
- inputRange: [0, 1],
14766
- outputRange: [1, 0]
14767
- });
14768
14819
  return /*#__PURE__*/React__default["default"].createElement(StyledContainer$2, {
14769
14820
  testID: testID,
14770
14821
  pointerEvents: "box-none",
14771
14822
  style: style
14772
- }, /*#__PURE__*/React__default["default"].createElement(reactNative.Animated.View, {
14773
- style: {
14774
- opacity: interpolatedFABOpacityAnimation
14775
- }
14776
- }, /*#__PURE__*/React__default["default"].createElement(StyledFAB, {
14823
+ }, /*#__PURE__*/React__default["default"].createElement(reactNative.Animated.View, null, /*#__PURE__*/React__default["default"].createElement(StyledFAB, {
14777
14824
  key: "fab",
14778
14825
  testID: "fab",
14779
14826
  icon: fabIcon,
@@ -14797,7 +14844,7 @@ var ActionGroup = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
14797
14844
  testID: "action-group",
14798
14845
  pointerEvents: "box-none",
14799
14846
  style: {
14800
- opacity: interpolatedActionGroupOpacityAnimation
14847
+ opacity: actionGroupOpacity
14801
14848
  }
14802
14849
  }, /*#__PURE__*/React__default["default"].createElement(Box, {
14803
14850
  style: [style, {
@@ -14810,7 +14857,13 @@ var ActionGroup = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
14810
14857
  index: active ? index : items.length - index,
14811
14858
  active: active
14812
14859
  }));
14813
- }))), /*#__PURE__*/React__default["default"].createElement(StyledFAB, {
14860
+ }))), active && /*#__PURE__*/React__default["default"].createElement(StyledFAB
14861
+ // This FAB is moved up a bit compared to the original FAB,
14862
+ // set marginBottom to negative value to compensate for it
14863
+ , {
14864
+ style: {
14865
+ marginBottom: -theme.space.xxsmall
14866
+ },
14814
14867
  key: "fab-in-portal",
14815
14868
  testID: "fab-in-portal",
14816
14869
  icon: fabIcon,
@@ -16128,9 +16181,18 @@ var InnerCircle = index$9(reactNative.View)(function (_ref2) {
16128
16181
  };
16129
16182
  });
16130
16183
  var Spacer = index$9(reactNative.View)(function (_ref3) {
16131
- var theme = _ref3.theme;
16184
+ var theme = _ref3.theme,
16185
+ themeIntent = _ref3.themeIntent;
16186
+ return {
16187
+ marginTop: themeIntent === 'light' ? theme.__hd__.radio.space.groupTopMarginSmall : theme.__hd__.radio.space.groupTopMarginMedium
16188
+ };
16189
+ });
16190
+ var StyledRadio = index$9(List.Item)(function (_ref4) {
16191
+ var theme = _ref4.theme,
16192
+ themeIntent = _ref4.themeIntent,
16193
+ themeChecked = _ref4.themeChecked;
16132
16194
  return {
16133
- marginTop: theme.__hd__.radio.space.groupTopMargin
16195
+ backgroundColor: themeChecked ? theme.__hd__.radio.colors.checked : theme.__hd__.radio.colors.intents[themeIntent]
16134
16196
  };
16135
16197
  });
16136
16198
 
@@ -16147,17 +16209,23 @@ var Radio = function Radio(_ref2) {
16147
16209
  checked = _ref2$checked === void 0 ? false : _ref2$checked,
16148
16210
  onPress = _ref2.onPress,
16149
16211
  style = _ref2.style,
16150
- testID = _ref2.testID;
16151
- return /*#__PURE__*/React__default["default"].createElement(List.BasicItem, {
16212
+ subText = _ref2.subText,
16213
+ testID = _ref2.testID,
16214
+ _ref2$inactiveIntent = _ref2.inactiveIntent,
16215
+ inactiveIntent = _ref2$inactiveIntent === void 0 ? 'light' : _ref2$inactiveIntent;
16216
+ return /*#__PURE__*/React__default["default"].createElement(StyledRadio, {
16152
16217
  onPress: onPress,
16153
16218
  selected: checked,
16154
16219
  title: text,
16220
+ subtitle: subText,
16155
16221
  suffix: /*#__PURE__*/React__default["default"].createElement(RadioCircle, {
16156
16222
  checked: checked,
16157
16223
  text: text
16158
16224
  }),
16159
16225
  style: style,
16160
- testID: testID
16226
+ testID: testID,
16227
+ themeIntent: inactiveIntent,
16228
+ themeChecked: checked
16161
16229
  });
16162
16230
  };
16163
16231
 
@@ -16178,19 +16246,25 @@ var RadioGroup = function RadioGroup(_ref) {
16178
16246
  options = _ref.options,
16179
16247
  keyExtractor = _ref.keyExtractor,
16180
16248
  style = _ref.style,
16181
- testID = _ref.testID;
16249
+ testID = _ref.testID,
16250
+ _ref$inactiveIntent = _ref.inactiveIntent,
16251
+ inactiveIntent = _ref$inactiveIntent === void 0 ? 'light' : _ref$inactiveIntent;
16182
16252
  return /*#__PURE__*/React__default["default"].createElement(reactNative.View, {
16183
16253
  style: style,
16184
16254
  testID: testID
16185
16255
  }, options.map(function (option, index) {
16186
16256
  return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, {
16187
16257
  key: getKey(option, index, keyExtractor)
16188
- }, index !== 0 && /*#__PURE__*/React__default["default"].createElement(Spacer, null), /*#__PURE__*/React__default["default"].createElement(Radio, {
16258
+ }, index !== 0 && /*#__PURE__*/React__default["default"].createElement(Spacer, {
16259
+ themeIntent: inactiveIntent
16260
+ }), /*#__PURE__*/React__default["default"].createElement(Radio, {
16189
16261
  text: option.text,
16262
+ subText: option.subText,
16190
16263
  checked: option.value === value,
16191
16264
  onPress: function onPress() {
16192
16265
  return _onPress(option.value);
16193
- }
16266
+ },
16267
+ inactiveIntent: inactiveIntent
16194
16268
  }));
16195
16269
  }));
16196
16270
  };
@@ -35584,8 +35658,9 @@ var index = Object.assign(RichTextEditorWithRef, {
35584
35658
  Toolbar: EditorToolbar
35585
35659
  });
35586
35660
 
35587
- var COLLAPSE_BREAKPOINT = 10;
35588
- var SHOW_AND_HIDE_BREAKPOINT = 200;
35661
+ var LAST_BREAKPOINT = 100;
35662
+ var MIDDLE_BREAKPOINT = 250;
35663
+ var MAX_ANIMATABLE_SCROLL_DISTANCE = 400;
35589
35664
  var REF_ACTIONS_BY_COMPONENT = {
35590
35665
  FAB: {
35591
35666
  show: 'show',
@@ -35600,27 +35675,23 @@ var REF_ACTIONS_BY_COMPONENT = {
35600
35675
  };
35601
35676
  var AnimatedFAB = function AnimatedFAB(_ref) {
35602
35677
  var fabProps = _ref.fabProps,
35603
- contentOffsetY = _ref.contentOffsetY;
35678
+ contentOffsetY = _ref.contentOffsetY,
35679
+ contentHeight = _ref.contentHeight,
35680
+ layoutHeight = _ref.layoutHeight;
35604
35681
  var component = 'items' in fabProps ? 'ActionGroup' : 'FAB';
35605
- var _React$useState = React__default["default"].useState('down'),
35606
- _React$useState2 = _slicedToArray(_React$useState, 2),
35607
- currentScrollDirection = _React$useState2[0],
35608
- setCurrentScrollDirection = _React$useState2[1];
35609
- var _React$useState3 = React__default["default"].useState(0),
35610
- _React$useState4 = _slicedToArray(_React$useState3, 2),
35611
- lastScrollY = _React$useState4[0],
35612
- setLastScrollY = _React$useState4[1];
35613
- var _React$useState5 = React__default["default"].useState('show'),
35614
- _React$useState6 = _slicedToArray(_React$useState5, 2),
35615
- fabState = _React$useState6[0],
35616
- setFabState = _React$useState6[1];
35617
- var _React$useState7 = React__default["default"].useState(SHOW_AND_HIDE_BREAKPOINT),
35618
- _React$useState8 = _slicedToArray(_React$useState7, 2),
35619
- remainingScrollOffset = _React$useState8[0],
35620
- setRemainingScrollOffset = _React$useState8[1];
35621
35682
  var ref = React__default["default"].useRef(null);
35683
+ var currentContentHeight = React__default["default"].useRef(0);
35684
+ var currentLayoutHeight = React__default["default"].useRef(0);
35685
+ /** fabState is used to avoid calling duplicated animations. */
35686
+ var fabState = React__default["default"].useRef('show');
35687
+ /** remainingScrollOffset determines whether to animate the FAB. */
35688
+ var remainingScrollOffset = React__default["default"].useRef(MAX_ANIMATABLE_SCROLL_DISTANCE);
35689
+ /** currentScrollDirection is used to determine the scroll direction. */
35690
+ var currentScrollDirection = React__default["default"].useRef('down');
35691
+ /** lastScrollY is the scrollY from the preview scroll event. */
35692
+ var lastScrollY = React__default["default"].useRef(0);
35622
35693
  var animateFab = React__default["default"].useCallback(function (newState) {
35623
- if (fabState !== newState) {
35694
+ if (fabState.current !== newState) {
35624
35695
  if (newState === 'show') {
35625
35696
  var _ref$current;
35626
35697
  (_ref$current = ref.current) === null || _ref$current === void 0 || _ref$current[REF_ACTIONS_BY_COMPONENT[component].show]();
@@ -35631,37 +35702,64 @@ var AnimatedFAB = function AnimatedFAB(_ref) {
35631
35702
  var _ref$current3;
35632
35703
  (_ref$current3 = ref.current) === null || _ref$current3 === void 0 || _ref$current3[REF_ACTIONS_BY_COMPONENT[component].collapse]();
35633
35704
  }
35634
- setFabState(newState);
35635
- }
35636
- }, [fabState, component]);
35637
- // Listen to ScrollView's contentOffsetY value
35638
- contentOffsetY.addListener(function (_ref2) {
35639
- var value = _ref2.value;
35640
- if (value < 0) {
35641
- return;
35642
- }
35643
- var newScrollDirection = value > lastScrollY ? 'down' : 'up';
35644
- var isScrollingDown = newScrollDirection === 'down';
35645
- if (newScrollDirection !== currentScrollDirection || lastScrollY === 0) {
35646
- setLastScrollY(value);
35647
- setCurrentScrollDirection(newScrollDirection);
35648
- }
35649
- var offsetFromLastDirection = Math.abs(value - lastScrollY);
35650
- var offsetDiff = Math.round(Math.max(remainingScrollOffset - offsetFromLastDirection, 0));
35651
- if (remainingScrollOffset > 0) {
35652
- if (offsetDiff === SHOW_AND_HIDE_BREAKPOINT) {
35653
- animateFab(isScrollingDown ? 'show' : 'hide');
35654
- } else if (offsetDiff <= SHOW_AND_HIDE_BREAKPOINT && offsetDiff > COLLAPSE_BREAKPOINT) {
35655
- animateFab('collapse');
35656
- } else if (offsetDiff <= COLLAPSE_BREAKPOINT) {
35657
- animateFab(isScrollingDown ? 'hide' : 'show');
35658
- }
35659
- setRemainingScrollOffset(offsetDiff);
35705
+ fabState.current = newState;
35660
35706
  }
35661
- });
35707
+ }, [component]);
35662
35708
  React__default["default"].useEffect(function () {
35663
- setRemainingScrollOffset(SHOW_AND_HIDE_BREAKPOINT);
35664
- }, [currentScrollDirection]);
35709
+ contentHeight.addListener(function (_ref2) {
35710
+ var value = _ref2.value;
35711
+ if (value > 0 && value !== currentContentHeight.current) {
35712
+ currentContentHeight.current = value;
35713
+ }
35714
+ });
35715
+ layoutHeight.addListener(function (_ref3) {
35716
+ var value = _ref3.value;
35717
+ if (value > 0 && value !== currentLayoutHeight.current) {
35718
+ currentLayoutHeight.current = value;
35719
+ }
35720
+ });
35721
+ // Listen to ScrollView's contentOffsetY value
35722
+ contentOffsetY.addListener(function (_ref4) {
35723
+ var value = _ref4.value;
35724
+ if (value < 0 ||
35725
+ // Prevent calling the function if the scroll is not significant
35726
+ value > 0 && Math.abs(value - lastScrollY.current) < 5) {
35727
+ return;
35728
+ }
35729
+ // Scroll up to top, bouncing included.
35730
+ if (value === 0 && lastScrollY.current !== 0) {
35731
+ animateFab('show');
35732
+ }
35733
+ var newScrollDirection = value >= lastScrollY.current ? 'down' : 'up';
35734
+ if (newScrollDirection !== currentScrollDirection.current) {
35735
+ // If scroll direction changes, reset all values
35736
+ currentScrollDirection.current = newScrollDirection;
35737
+ remainingScrollOffset.current = MAX_ANIMATABLE_SCROLL_DISTANCE;
35738
+ }
35739
+ var hasReachedBottom = value + currentLayoutHeight.current >= currentContentHeight.current;
35740
+ // Scroll down to bottom, bouncing included.
35741
+ if (hasReachedBottom) {
35742
+ animateFab('hide');
35743
+ return;
35744
+ }
35745
+ if (remainingScrollOffset.current) {
35746
+ var offsetDiff = Math.round(Math.max(Math.abs(value - lastScrollY.current), 0));
35747
+ var newRemainingScrollOffset = Math.max(remainingScrollOffset.current - offsetDiff, 0);
35748
+ if (newRemainingScrollOffset <= LAST_BREAKPOINT) {
35749
+ animateFab(currentScrollDirection.current === 'down' ? 'hide' : 'show');
35750
+ } else if (newRemainingScrollOffset <= MIDDLE_BREAKPOINT) {
35751
+ animateFab('collapse');
35752
+ }
35753
+ remainingScrollOffset.current = newRemainingScrollOffset;
35754
+ }
35755
+ lastScrollY.current = value;
35756
+ });
35757
+ return function () {
35758
+ contentOffsetY.removeAllListeners();
35759
+ contentHeight.removeAllListeners();
35760
+ layoutHeight.removeAllListeners();
35761
+ };
35762
+ }, [contentHeight, contentOffsetY, layoutHeight]);
35665
35763
  return component === 'FAB' ? /*#__PURE__*/React__default["default"].createElement(FAB, _extends$1({
35666
35764
  ref: ref
35667
35765
  }, fabProps)) : /*#__PURE__*/React__default["default"].createElement(ActionGroup, _extends$1({
@@ -35673,6 +35771,8 @@ function AnimatedScroller(_ref) {
35673
35771
  var ScrollComponent = _ref.ScrollComponent,
35674
35772
  fabProps = _ref.fabProps;
35675
35773
  var contentOffsetY = React__default["default"].useRef(new reactNative.Animated.Value(0)).current;
35774
+ var contentHeight = React__default["default"].useRef(new reactNative.Animated.Value(0)).current;
35775
+ var layoutHeight = React__default["default"].useRef(new reactNative.Animated.Value(0)).current;
35676
35776
  // Common props for all ScrollView, FlatList and SectionList.
35677
35777
  var _ScrollComponent$prop = ScrollComponent.props,
35678
35778
  onScroll = _ScrollComponent$prop.onScroll,
@@ -35683,6 +35783,12 @@ function AnimatedScroller(_ref) {
35683
35783
  nativeEvent: {
35684
35784
  contentOffset: {
35685
35785
  y: contentOffsetY
35786
+ },
35787
+ contentSize: {
35788
+ height: contentHeight
35789
+ },
35790
+ layoutMeasurement: {
35791
+ height: layoutHeight
35686
35792
  }
35687
35793
  }
35688
35794
  }], {
@@ -35691,7 +35797,9 @@ function AnimatedScroller(_ref) {
35691
35797
  })
35692
35798
  })), !!fabProps && /*#__PURE__*/React__default["default"].createElement(AnimatedFAB, {
35693
35799
  fabProps: fabProps,
35694
- contentOffsetY: contentOffsetY
35800
+ contentOffsetY: contentOffsetY,
35801
+ contentHeight: contentHeight,
35802
+ layoutHeight: layoutHeight
35695
35803
  }));
35696
35804
  }
35697
35805
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hero-design/rn",
3
- "version": "8.59.0",
3
+ "version": "8.61.0",
4
4
  "license": "MIT",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",