@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
@@ -2,4 +2,4 @@
2
2
  src/index.ts → lib/index.js, es/index.js...
3
3
  (!) Plugin replace: @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
4
4
  (!) Plugin node-resolve: preferring built-in module 'events' over local alternative at '/home/runner/work/hero-design/hero-design/node_modules/events/events.js', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning
5
- created lib/index.js, es/index.js in 57.2s
5
+ created lib/index.js, es/index.js in 1m 0.6s
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @hero-design/rn
2
2
 
3
+ ## 8.61.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2786](https://github.com/Thinkei/hero-design/pull/2786) [`f5f4d1d55`](https://github.com/Thinkei/hero-design/commit/f5f4d1d55601f9ae3e37438f0928e9a6173ae260) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - [Radio.Group] Update indicator color and add inactiveIntent prop
8
+
9
+ ## 8.60.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#2747](https://github.com/Thinkei/hero-design/pull/2747) [`28106e711`](https://github.com/Thinkei/hero-design/commit/28106e711ef6a127e4bfa0890535489649ff516c) Thanks [@vinhphan-eh](https://github.com/vinhphan-eh)! - [FAB][fab.actiongroup][Scrollables with FAB] Update animations using Animated
14
+
3
15
  ## 8.59.0
4
16
 
5
17
  ### Minor Changes
package/es/index.js CHANGED
@@ -2934,11 +2934,17 @@ var getProgressTheme = function getProgressTheme(theme) {
2934
2934
 
2935
2935
  var getRadioTheme = function getRadioTheme(theme) {
2936
2936
  var colors = {
2937
- circle: theme.colors.onDefaultGlobalSurface
2937
+ circle: theme.colors.primary,
2938
+ checked: theme.colors.highlightedSurface,
2939
+ intents: {
2940
+ light: theme.colors.defaultGlobalSurface,
2941
+ dark: theme.colors.neutralGlobalSurface
2942
+ }
2938
2943
  };
2939
2944
  var space = {
2940
2945
  circleLeftMargin: theme.space.small,
2941
- groupTopMargin: theme.space.xsmall
2946
+ groupTopMarginSmall: theme.space.xsmall,
2947
+ groupTopMarginMedium: theme.space.medium
2942
2948
  };
2943
2949
  var boundingBoxSize = theme.sizes.large;
2944
2950
  var innerPadding = theme.space.xsmall;
@@ -14386,7 +14392,8 @@ var Error$1 = function Error(_ref2) {
14386
14392
  }, nativeProps));
14387
14393
  };
14388
14394
 
14389
- var StyledFAB$1 = index$9(TouchableHighlight)(function (_ref) {
14395
+ var AnimatedTouchableHighlight = Animated.createAnimatedComponent(TouchableHighlight);
14396
+ var StyledFAB$1 = index$9(AnimatedTouchableHighlight)(function (_ref) {
14390
14397
  var theme = _ref.theme,
14391
14398
  themeActive = _ref.themeActive;
14392
14399
  return {
@@ -14401,7 +14408,8 @@ var StyledFAB$1 = index$9(TouchableHighlight)(function (_ref) {
14401
14408
  shadowColor: theme.__hd__.fab.shadows.color,
14402
14409
  shadowOffset: theme.__hd__.fab.shadows.offset,
14403
14410
  shadowRadius: theme.__hd__.fab.shadows.radius,
14404
- shadowOpacity: theme.__hd__.fab.shadows.opacity
14411
+ shadowOpacity: theme.__hd__.fab.shadows.opacity,
14412
+ height: theme.__hd__.fab.sizes.height
14405
14413
  };
14406
14414
  });
14407
14415
  var StyledFABIcon = index$9(Icon)(function (_ref2) {
@@ -14493,16 +14501,14 @@ var IconWithTextContent = function IconWithTextContent(_ref2) {
14493
14501
  testID: "styled-fab-icon"
14494
14502
  })), /*#__PURE__*/React.createElement(StyledFABText, null, title));
14495
14503
  };
14496
- var defaultAnimation = {
14497
- create: {
14498
- type: 'easeInEaseOut',
14499
- property: 'opacity'
14500
- },
14501
- update: {
14502
- type: 'spring',
14503
- springDamping: Platform.OS === 'ios' ? 0.7 : 1.2
14504
- },
14505
- duration: Platform.OS === 'ios' ? 300 : 400
14504
+ var animateWidth = function animateWidth() {
14505
+ LayoutAnimation.configureNext({
14506
+ duration: Platform.OS === 'ios' ? 200 : 400,
14507
+ update: {
14508
+ type: 'spring',
14509
+ springDamping: Platform.OS === 'ios' ? 1 : 1.5
14510
+ }
14511
+ });
14506
14512
  };
14507
14513
  var FAB$1 = /*#__PURE__*/forwardRef(function (_ref3, ref) {
14508
14514
  var _StyleSheet$flatten, _StyleSheet$flatten2;
@@ -14514,61 +14520,99 @@ var FAB$1 = /*#__PURE__*/forwardRef(function (_ref3, ref) {
14514
14520
  active = _ref3.active,
14515
14521
  style = _ref3.style;
14516
14522
  var theme = useTheme();
14517
- var _React$useState = React.useState(false),
14518
- _React$useState2 = _slicedToArray(_React$useState, 2),
14519
- canAnimate = _React$useState2[0],
14520
- setCanAnimate = _React$useState2[1];
14521
- var _React$useState3 = React.useState({
14523
+ var _React$useState = React.useState({
14522
14524
  hideTitle: false,
14523
14525
  hideButton: false
14524
14526
  }),
14525
- _React$useState4 = _slicedToArray(_React$useState3, 2),
14526
- displayState = _React$useState4[0],
14527
- setDisplayState = _React$useState4[1];
14527
+ _React$useState2 = _slicedToArray(_React$useState, 2),
14528
+ displayState = _React$useState2[0],
14529
+ setDisplayState = _React$useState2[1];
14528
14530
  var isIconOnly = displayState.hideTitle || active || !title;
14531
+ var animatedValues = {
14532
+ opacity: React.useRef(new Animated.Value(1)).current,
14533
+ width: React.useRef(new Animated.Value(1)).current,
14534
+ translateY: React.useRef(new Animated.Value(0)).current
14535
+ };
14536
+ var marginBottom = Number((_StyleSheet$flatten = StyleSheet$1.flatten(style)) === null || _StyleSheet$flatten === void 0 ? void 0 : _StyleSheet$flatten.marginBottom) || 0;
14537
+ var _React$useState3 = React.useState(0),
14538
+ _React$useState4 = _slicedToArray(_React$useState3, 2),
14539
+ buttonWidth = _React$useState4[0],
14540
+ setButtonWidth = _React$useState4[1];
14541
+ var hasSetButtonWidth = buttonWidth > 0;
14529
14542
  React.useImperativeHandle(ref, function () {
14530
14543
  return {
14531
14544
  show: function show() {
14545
+ Animated.spring(animatedValues.translateY, {
14546
+ toValue: 0,
14547
+ useNativeDriver: true
14548
+ }).start();
14532
14549
  setDisplayState({
14533
14550
  hideButton: false,
14534
14551
  hideTitle: false
14535
14552
  });
14553
+ animateWidth();
14554
+ Animated.spring(animatedValues.opacity, {
14555
+ toValue: 1,
14556
+ useNativeDriver: true
14557
+ }).start();
14536
14558
  },
14537
14559
  collapse: function collapse() {
14560
+ Animated.parallel([Animated.spring(animatedValues.opacity, {
14561
+ toValue: 1,
14562
+ useNativeDriver: true
14563
+ }), Animated.spring(animatedValues.translateY, {
14564
+ toValue: 0,
14565
+ useNativeDriver: true
14566
+ })]).start();
14567
+ animateWidth();
14538
14568
  setDisplayState({
14539
14569
  hideButton: false,
14540
14570
  hideTitle: true
14541
14571
  });
14542
14572
  },
14543
14573
  hide: function hide() {
14544
- setDisplayState(function (previousState) {
14545
- return _objectSpread2(_objectSpread2({}, previousState), {}, {
14546
- hideButton: true
14574
+ Animated.stagger(20, [Animated.spring(animatedValues.opacity, {
14575
+ toValue: 0,
14576
+ useNativeDriver: true
14577
+ }), Animated.spring(animatedValues.translateY, {
14578
+ toValue: 1,
14579
+ useNativeDriver: true
14580
+ })]).start(function () {
14581
+ animateWidth();
14582
+ setDisplayState(function (previousState) {
14583
+ return _objectSpread2(_objectSpread2({}, previousState), {}, {
14584
+ hideButton: true
14585
+ });
14547
14586
  });
14548
14587
  });
14549
14588
  }
14550
14589
  };
14551
14590
  }, []);
14552
- React.useEffect(function () {
14553
- if (canAnimate) {
14554
- LayoutAnimation.configureNext(defaultAnimation);
14555
- }
14556
- }, [isIconOnly, displayState.hideButton, canAnimate]);
14557
- var marginBottom = Number((_StyleSheet$flatten = StyleSheet$1.flatten(style)) === null || _StyleSheet$flatten === void 0 ? void 0 : _StyleSheet$flatten.marginBottom) || 0;
14558
- return /*#__PURE__*/React.createElement(StyledFAB$1
14559
- /** Add a small timeout before executing animation to prevent flakiness */, {
14560
- onLayout: function onLayout() {
14561
- return setTimeout(function () {
14562
- return setCanAnimate(true);
14563
- }, 500);
14591
+ return /*#__PURE__*/React.createElement(StyledFAB$1, {
14592
+ onLayout: function onLayout(event) {
14593
+ return !hasSetButtonWidth && !active && setButtonWidth(event.nativeEvent.layout.width);
14564
14594
  },
14565
14595
  underlayColor: theme.__hd__.fab.colors.buttonPressedBackground,
14566
14596
  onPress: onPress,
14567
14597
  style: [style, {
14568
- bottom: displayState.hideButton ? -(marginBottom + theme.__hd__.fab.sizes.height * 2) : (_StyleSheet$flatten2 = StyleSheet$1.flatten(style)) === null || _StyleSheet$flatten2 === void 0 ? void 0 : _StyleSheet$flatten2.bottom
14598
+ bottom: displayState.hideButton ? -(marginBottom + theme.__hd__.fab.sizes.height * 2) : (_StyleSheet$flatten2 = StyleSheet$1.flatten(style)) === null || _StyleSheet$flatten2 === void 0 ? void 0 : _StyleSheet$flatten2.bottom,
14599
+ transform: [{
14600
+ translateY: animatedValues.translateY.interpolate({
14601
+ inputRange: [0, 1],
14602
+ outputRange: [0, marginBottom + theme.__hd__.fab.sizes.height * 2]
14603
+ })
14604
+ }]
14569
14605
  }],
14570
14606
  testID: testID,
14571
14607
  themeActive: active
14608
+ }, /*#__PURE__*/React.createElement(Animated.View, {
14609
+ style: {
14610
+ flexDirection: 'row',
14611
+ opacity: animatedValues.opacity.interpolate({
14612
+ inputRange: [0, 1],
14613
+ outputRange: [0, 1]
14614
+ })
14615
+ }
14572
14616
  }, isIconOnly ? /*#__PURE__*/React.createElement(IconOnlyContent, {
14573
14617
  animated: animated,
14574
14618
  active: active,
@@ -14576,7 +14620,7 @@ var FAB$1 = /*#__PURE__*/forwardRef(function (_ref3, ref) {
14576
14620
  }) : /*#__PURE__*/React.createElement(IconWithTextContent, {
14577
14621
  icon: icon,
14578
14622
  title: title
14579
- }));
14623
+ })));
14580
14624
  });
14581
14625
  FAB$1.displayName = 'FAB';
14582
14626
 
@@ -14626,7 +14670,9 @@ var ActionItem = function ActionItem(_ref) {
14626
14670
  Animated.spring(animatedValue.current, {
14627
14671
  toValue: active ? 1 : 0,
14628
14672
  useNativeDriver: Platform.OS !== 'web',
14629
- delay: index * 20
14673
+ delay: index * 30,
14674
+ speed: 10,
14675
+ bounciness: 10
14630
14676
  }).start();
14631
14677
  }, [active, index]);
14632
14678
  return /*#__PURE__*/React.createElement(Animated.View, {
@@ -14703,8 +14749,9 @@ var ActionGroup = /*#__PURE__*/forwardRef(function (_ref, ref) {
14703
14749
  _ref$fabIcon = _ref.fabIcon,
14704
14750
  fabIcon = _ref$fabIcon === void 0 ? 'add' : _ref$fabIcon;
14705
14751
  useDeprecation("FAB.ActionGroup's headerTitle prop will be removed in the next major release. Please remove it.", headerTitle !== undefined);
14752
+ var theme = useTheme();
14706
14753
  var fabRef = useRef(null);
14707
- var tranlateXAnimation = useRef(new Animated.Value(active ? 1 : 0));
14754
+ var animatedValue = useRef(new Animated.Value(active ? 1 : 0));
14708
14755
  React.useImperativeHandle(ref, function () {
14709
14756
  return {
14710
14757
  showFAB: function showFAB() {
@@ -14722,28 +14769,28 @@ var ActionGroup = /*#__PURE__*/forwardRef(function (_ref, ref) {
14722
14769
  };
14723
14770
  }, [fabRef]);
14724
14771
  React.useEffect(function () {
14725
- Animated.spring(tranlateXAnimation.current, {
14772
+ Animated.spring(animatedValue.current, {
14726
14773
  toValue: active ? 1 : 0,
14774
+ delay: 100,
14727
14775
  useNativeDriver: Platform.OS !== 'web'
14728
14776
  }).start();
14777
+ if (active) {
14778
+ var _fabRef$current4;
14779
+ (_fabRef$current4 = fabRef.current) === null || _fabRef$current4 === void 0 || _fabRef$current4.collapse();
14780
+ } else {
14781
+ var _fabRef$current5;
14782
+ (_fabRef$current5 = fabRef.current) === null || _fabRef$current5 === void 0 || _fabRef$current5.show();
14783
+ }
14729
14784
  }, [active]);
14730
- var interpolatedActionGroupOpacityAnimation = tranlateXAnimation.current.interpolate({
14785
+ var actionGroupOpacity = animatedValue.current.interpolate({
14731
14786
  inputRange: [0, 1],
14732
14787
  outputRange: [0, 1]
14733
14788
  });
14734
- var interpolatedFABOpacityAnimation = tranlateXAnimation.current.interpolate({
14735
- inputRange: [0, 1],
14736
- outputRange: [1, 0]
14737
- });
14738
14789
  return /*#__PURE__*/React.createElement(StyledContainer$2, {
14739
14790
  testID: testID,
14740
14791
  pointerEvents: "box-none",
14741
14792
  style: style
14742
- }, /*#__PURE__*/React.createElement(Animated.View, {
14743
- style: {
14744
- opacity: interpolatedFABOpacityAnimation
14745
- }
14746
- }, /*#__PURE__*/React.createElement(StyledFAB, {
14793
+ }, /*#__PURE__*/React.createElement(Animated.View, null, /*#__PURE__*/React.createElement(StyledFAB, {
14747
14794
  key: "fab",
14748
14795
  testID: "fab",
14749
14796
  icon: fabIcon,
@@ -14767,7 +14814,7 @@ var ActionGroup = /*#__PURE__*/forwardRef(function (_ref, ref) {
14767
14814
  testID: "action-group",
14768
14815
  pointerEvents: "box-none",
14769
14816
  style: {
14770
- opacity: interpolatedActionGroupOpacityAnimation
14817
+ opacity: actionGroupOpacity
14771
14818
  }
14772
14819
  }, /*#__PURE__*/React.createElement(Box, {
14773
14820
  style: [style, {
@@ -14780,7 +14827,13 @@ var ActionGroup = /*#__PURE__*/forwardRef(function (_ref, ref) {
14780
14827
  index: active ? index : items.length - index,
14781
14828
  active: active
14782
14829
  }));
14783
- }))), /*#__PURE__*/React.createElement(StyledFAB, {
14830
+ }))), active && /*#__PURE__*/React.createElement(StyledFAB
14831
+ // This FAB is moved up a bit compared to the original FAB,
14832
+ // set marginBottom to negative value to compensate for it
14833
+ , {
14834
+ style: {
14835
+ marginBottom: -theme.space.xxsmall
14836
+ },
14784
14837
  key: "fab-in-portal",
14785
14838
  testID: "fab-in-portal",
14786
14839
  icon: fabIcon,
@@ -16098,9 +16151,18 @@ var InnerCircle = index$9(View)(function (_ref2) {
16098
16151
  };
16099
16152
  });
16100
16153
  var Spacer = index$9(View)(function (_ref3) {
16101
- var theme = _ref3.theme;
16154
+ var theme = _ref3.theme,
16155
+ themeIntent = _ref3.themeIntent;
16156
+ return {
16157
+ marginTop: themeIntent === 'light' ? theme.__hd__.radio.space.groupTopMarginSmall : theme.__hd__.radio.space.groupTopMarginMedium
16158
+ };
16159
+ });
16160
+ var StyledRadio = index$9(List.Item)(function (_ref4) {
16161
+ var theme = _ref4.theme,
16162
+ themeIntent = _ref4.themeIntent,
16163
+ themeChecked = _ref4.themeChecked;
16102
16164
  return {
16103
- marginTop: theme.__hd__.radio.space.groupTopMargin
16165
+ backgroundColor: themeChecked ? theme.__hd__.radio.colors.checked : theme.__hd__.radio.colors.intents[themeIntent]
16104
16166
  };
16105
16167
  });
16106
16168
 
@@ -16117,17 +16179,23 @@ var Radio = function Radio(_ref2) {
16117
16179
  checked = _ref2$checked === void 0 ? false : _ref2$checked,
16118
16180
  onPress = _ref2.onPress,
16119
16181
  style = _ref2.style,
16120
- testID = _ref2.testID;
16121
- return /*#__PURE__*/React.createElement(List.BasicItem, {
16182
+ subText = _ref2.subText,
16183
+ testID = _ref2.testID,
16184
+ _ref2$inactiveIntent = _ref2.inactiveIntent,
16185
+ inactiveIntent = _ref2$inactiveIntent === void 0 ? 'light' : _ref2$inactiveIntent;
16186
+ return /*#__PURE__*/React.createElement(StyledRadio, {
16122
16187
  onPress: onPress,
16123
16188
  selected: checked,
16124
16189
  title: text,
16190
+ subtitle: subText,
16125
16191
  suffix: /*#__PURE__*/React.createElement(RadioCircle, {
16126
16192
  checked: checked,
16127
16193
  text: text
16128
16194
  }),
16129
16195
  style: style,
16130
- testID: testID
16196
+ testID: testID,
16197
+ themeIntent: inactiveIntent,
16198
+ themeChecked: checked
16131
16199
  });
16132
16200
  };
16133
16201
 
@@ -16148,19 +16216,25 @@ var RadioGroup = function RadioGroup(_ref) {
16148
16216
  options = _ref.options,
16149
16217
  keyExtractor = _ref.keyExtractor,
16150
16218
  style = _ref.style,
16151
- testID = _ref.testID;
16219
+ testID = _ref.testID,
16220
+ _ref$inactiveIntent = _ref.inactiveIntent,
16221
+ inactiveIntent = _ref$inactiveIntent === void 0 ? 'light' : _ref$inactiveIntent;
16152
16222
  return /*#__PURE__*/React.createElement(View, {
16153
16223
  style: style,
16154
16224
  testID: testID
16155
16225
  }, options.map(function (option, index) {
16156
16226
  return /*#__PURE__*/React.createElement(React.Fragment, {
16157
16227
  key: getKey(option, index, keyExtractor)
16158
- }, index !== 0 && /*#__PURE__*/React.createElement(Spacer, null), /*#__PURE__*/React.createElement(Radio, {
16228
+ }, index !== 0 && /*#__PURE__*/React.createElement(Spacer, {
16229
+ themeIntent: inactiveIntent
16230
+ }), /*#__PURE__*/React.createElement(Radio, {
16159
16231
  text: option.text,
16232
+ subText: option.subText,
16160
16233
  checked: option.value === value,
16161
16234
  onPress: function onPress() {
16162
16235
  return _onPress(option.value);
16163
- }
16236
+ },
16237
+ inactiveIntent: inactiveIntent
16164
16238
  }));
16165
16239
  }));
16166
16240
  };
@@ -35554,8 +35628,9 @@ var index = Object.assign(RichTextEditorWithRef, {
35554
35628
  Toolbar: EditorToolbar
35555
35629
  });
35556
35630
 
35557
- var COLLAPSE_BREAKPOINT = 10;
35558
- var SHOW_AND_HIDE_BREAKPOINT = 200;
35631
+ var LAST_BREAKPOINT = 100;
35632
+ var MIDDLE_BREAKPOINT = 250;
35633
+ var MAX_ANIMATABLE_SCROLL_DISTANCE = 400;
35559
35634
  var REF_ACTIONS_BY_COMPONENT = {
35560
35635
  FAB: {
35561
35636
  show: 'show',
@@ -35570,27 +35645,23 @@ var REF_ACTIONS_BY_COMPONENT = {
35570
35645
  };
35571
35646
  var AnimatedFAB = function AnimatedFAB(_ref) {
35572
35647
  var fabProps = _ref.fabProps,
35573
- contentOffsetY = _ref.contentOffsetY;
35648
+ contentOffsetY = _ref.contentOffsetY,
35649
+ contentHeight = _ref.contentHeight,
35650
+ layoutHeight = _ref.layoutHeight;
35574
35651
  var component = 'items' in fabProps ? 'ActionGroup' : 'FAB';
35575
- var _React$useState = React.useState('down'),
35576
- _React$useState2 = _slicedToArray(_React$useState, 2),
35577
- currentScrollDirection = _React$useState2[0],
35578
- setCurrentScrollDirection = _React$useState2[1];
35579
- var _React$useState3 = React.useState(0),
35580
- _React$useState4 = _slicedToArray(_React$useState3, 2),
35581
- lastScrollY = _React$useState4[0],
35582
- setLastScrollY = _React$useState4[1];
35583
- var _React$useState5 = React.useState('show'),
35584
- _React$useState6 = _slicedToArray(_React$useState5, 2),
35585
- fabState = _React$useState6[0],
35586
- setFabState = _React$useState6[1];
35587
- var _React$useState7 = React.useState(SHOW_AND_HIDE_BREAKPOINT),
35588
- _React$useState8 = _slicedToArray(_React$useState7, 2),
35589
- remainingScrollOffset = _React$useState8[0],
35590
- setRemainingScrollOffset = _React$useState8[1];
35591
35652
  var ref = React.useRef(null);
35653
+ var currentContentHeight = React.useRef(0);
35654
+ var currentLayoutHeight = React.useRef(0);
35655
+ /** fabState is used to avoid calling duplicated animations. */
35656
+ var fabState = React.useRef('show');
35657
+ /** remainingScrollOffset determines whether to animate the FAB. */
35658
+ var remainingScrollOffset = React.useRef(MAX_ANIMATABLE_SCROLL_DISTANCE);
35659
+ /** currentScrollDirection is used to determine the scroll direction. */
35660
+ var currentScrollDirection = React.useRef('down');
35661
+ /** lastScrollY is the scrollY from the preview scroll event. */
35662
+ var lastScrollY = React.useRef(0);
35592
35663
  var animateFab = React.useCallback(function (newState) {
35593
- if (fabState !== newState) {
35664
+ if (fabState.current !== newState) {
35594
35665
  if (newState === 'show') {
35595
35666
  var _ref$current;
35596
35667
  (_ref$current = ref.current) === null || _ref$current === void 0 || _ref$current[REF_ACTIONS_BY_COMPONENT[component].show]();
@@ -35601,37 +35672,64 @@ var AnimatedFAB = function AnimatedFAB(_ref) {
35601
35672
  var _ref$current3;
35602
35673
  (_ref$current3 = ref.current) === null || _ref$current3 === void 0 || _ref$current3[REF_ACTIONS_BY_COMPONENT[component].collapse]();
35603
35674
  }
35604
- setFabState(newState);
35605
- }
35606
- }, [fabState, component]);
35607
- // Listen to ScrollView's contentOffsetY value
35608
- contentOffsetY.addListener(function (_ref2) {
35609
- var value = _ref2.value;
35610
- if (value < 0) {
35611
- return;
35612
- }
35613
- var newScrollDirection = value > lastScrollY ? 'down' : 'up';
35614
- var isScrollingDown = newScrollDirection === 'down';
35615
- if (newScrollDirection !== currentScrollDirection || lastScrollY === 0) {
35616
- setLastScrollY(value);
35617
- setCurrentScrollDirection(newScrollDirection);
35618
- }
35619
- var offsetFromLastDirection = Math.abs(value - lastScrollY);
35620
- var offsetDiff = Math.round(Math.max(remainingScrollOffset - offsetFromLastDirection, 0));
35621
- if (remainingScrollOffset > 0) {
35622
- if (offsetDiff === SHOW_AND_HIDE_BREAKPOINT) {
35623
- animateFab(isScrollingDown ? 'show' : 'hide');
35624
- } else if (offsetDiff <= SHOW_AND_HIDE_BREAKPOINT && offsetDiff > COLLAPSE_BREAKPOINT) {
35625
- animateFab('collapse');
35626
- } else if (offsetDiff <= COLLAPSE_BREAKPOINT) {
35627
- animateFab(isScrollingDown ? 'hide' : 'show');
35628
- }
35629
- setRemainingScrollOffset(offsetDiff);
35675
+ fabState.current = newState;
35630
35676
  }
35631
- });
35677
+ }, [component]);
35632
35678
  React.useEffect(function () {
35633
- setRemainingScrollOffset(SHOW_AND_HIDE_BREAKPOINT);
35634
- }, [currentScrollDirection]);
35679
+ contentHeight.addListener(function (_ref2) {
35680
+ var value = _ref2.value;
35681
+ if (value > 0 && value !== currentContentHeight.current) {
35682
+ currentContentHeight.current = value;
35683
+ }
35684
+ });
35685
+ layoutHeight.addListener(function (_ref3) {
35686
+ var value = _ref3.value;
35687
+ if (value > 0 && value !== currentLayoutHeight.current) {
35688
+ currentLayoutHeight.current = value;
35689
+ }
35690
+ });
35691
+ // Listen to ScrollView's contentOffsetY value
35692
+ contentOffsetY.addListener(function (_ref4) {
35693
+ var value = _ref4.value;
35694
+ if (value < 0 ||
35695
+ // Prevent calling the function if the scroll is not significant
35696
+ value > 0 && Math.abs(value - lastScrollY.current) < 5) {
35697
+ return;
35698
+ }
35699
+ // Scroll up to top, bouncing included.
35700
+ if (value === 0 && lastScrollY.current !== 0) {
35701
+ animateFab('show');
35702
+ }
35703
+ var newScrollDirection = value >= lastScrollY.current ? 'down' : 'up';
35704
+ if (newScrollDirection !== currentScrollDirection.current) {
35705
+ // If scroll direction changes, reset all values
35706
+ currentScrollDirection.current = newScrollDirection;
35707
+ remainingScrollOffset.current = MAX_ANIMATABLE_SCROLL_DISTANCE;
35708
+ }
35709
+ var hasReachedBottom = value + currentLayoutHeight.current >= currentContentHeight.current;
35710
+ // Scroll down to bottom, bouncing included.
35711
+ if (hasReachedBottom) {
35712
+ animateFab('hide');
35713
+ return;
35714
+ }
35715
+ if (remainingScrollOffset.current) {
35716
+ var offsetDiff = Math.round(Math.max(Math.abs(value - lastScrollY.current), 0));
35717
+ var newRemainingScrollOffset = Math.max(remainingScrollOffset.current - offsetDiff, 0);
35718
+ if (newRemainingScrollOffset <= LAST_BREAKPOINT) {
35719
+ animateFab(currentScrollDirection.current === 'down' ? 'hide' : 'show');
35720
+ } else if (newRemainingScrollOffset <= MIDDLE_BREAKPOINT) {
35721
+ animateFab('collapse');
35722
+ }
35723
+ remainingScrollOffset.current = newRemainingScrollOffset;
35724
+ }
35725
+ lastScrollY.current = value;
35726
+ });
35727
+ return function () {
35728
+ contentOffsetY.removeAllListeners();
35729
+ contentHeight.removeAllListeners();
35730
+ layoutHeight.removeAllListeners();
35731
+ };
35732
+ }, [contentHeight, contentOffsetY, layoutHeight]);
35635
35733
  return component === 'FAB' ? /*#__PURE__*/React.createElement(FAB, _extends$1({
35636
35734
  ref: ref
35637
35735
  }, fabProps)) : /*#__PURE__*/React.createElement(ActionGroup, _extends$1({
@@ -35643,6 +35741,8 @@ function AnimatedScroller(_ref) {
35643
35741
  var ScrollComponent = _ref.ScrollComponent,
35644
35742
  fabProps = _ref.fabProps;
35645
35743
  var contentOffsetY = React.useRef(new Animated.Value(0)).current;
35744
+ var contentHeight = React.useRef(new Animated.Value(0)).current;
35745
+ var layoutHeight = React.useRef(new Animated.Value(0)).current;
35646
35746
  // Common props for all ScrollView, FlatList and SectionList.
35647
35747
  var _ScrollComponent$prop = ScrollComponent.props,
35648
35748
  onScroll = _ScrollComponent$prop.onScroll,
@@ -35653,6 +35753,12 @@ function AnimatedScroller(_ref) {
35653
35753
  nativeEvent: {
35654
35754
  contentOffset: {
35655
35755
  y: contentOffsetY
35756
+ },
35757
+ contentSize: {
35758
+ height: contentHeight
35759
+ },
35760
+ layoutMeasurement: {
35761
+ height: layoutHeight
35656
35762
  }
35657
35763
  }
35658
35764
  }], {
@@ -35661,7 +35767,9 @@ function AnimatedScroller(_ref) {
35661
35767
  })
35662
35768
  })), !!fabProps && /*#__PURE__*/React.createElement(AnimatedFAB, {
35663
35769
  fabProps: fabProps,
35664
- contentOffsetY: contentOffsetY
35770
+ contentOffsetY: contentOffsetY,
35771
+ contentHeight: contentHeight,
35772
+ layoutHeight: layoutHeight
35665
35773
  }));
35666
35774
  }
35667
35775