@pagopa/io-app-design-system 5.11.11 → 5.11.12

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.
@@ -6,9 +6,9 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.ForceScrollDownView = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _reactNative = require("react-native");
9
+ var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
9
10
  var _core = require("../../core");
10
11
  var _buttons = require("../buttons");
11
- var _ScaleInOutAnimation = require("../common/ScaleInOutAnimation");
12
12
  var _layout = require("../layout");
13
13
  var _jsxRuntime = require("react/jsx-runtime");
14
14
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
@@ -25,109 +25,81 @@ const ForceScrollDownView = ({
25
25
  style,
26
26
  contentContainerStyle,
27
27
  scrollEnabled = true,
28
- onThresholdCrossed
28
+ onThresholdCrossed,
29
+ animatedRef
29
30
  }) => {
30
- const scrollViewRef = (0, _react.useRef)(null);
31
+ const internalAnimatedRef = (0, _reactNativeReanimated.useAnimatedRef)();
32
+ const scrollViewRef = animatedRef ?? internalAnimatedRef;
31
33
  const {
32
34
  footerActionsInlineMeasurements,
33
35
  handleFooterActionsInlineMeasurements
34
36
  } = (0, _layout.useFooterActionsInlineMeasurements)();
35
37
  const threshold = footerActions ? footerActionsInlineMeasurements.safeBottomAreaHeight : customThreshold;
36
38
 
37
- /**
38
- * The height of the scroll view, used to determine whether or not the scrollable content fits inside
39
- * the scroll view and whether the "scroll to bottom" button should be displayed.
40
- */
41
- const [scrollViewHeight, setScrollViewHeight] = (0, _react.useState)(0);
42
-
43
- /**
44
- * The height of the scrollable content, used to determine whether or not the "scroll to bottom" button
45
- * should be displayed.
46
- */
47
- const [contentHeight, setContentHeight] = (0, _react.useState)(0);
48
-
49
- /**
50
- * Whether or not the scroll view has crossed the threshold from the bottom.
51
- */
52
- const [isThresholdCrossed, setThresholdCrossed] = (0, _react.useState)(false);
53
-
54
39
  /**
55
40
  * Whether or not the "scroll to bottom" button should be visible. This is controlled by the threshold
56
41
  * and the current scroll position.
57
42
  */
58
- const [isButtonVisible, setButtonVisible] = (0, _react.useState)(true);
43
+ // const [isButtonVisible, setButtonVisible] = useState(true);
59
44
 
60
- /**
61
- * A callback that is called whenever the scroll view is scrolled. It checks whether or not the
62
- * scroll view has crossed the threshold from the bottom and updates the state accordingly.
63
- * The callback is designed to update button visibility only when crossing the threshold.
64
- */
65
- const handleScroll = (0, _react.useCallback)(event => {
66
- const {
67
- layoutMeasurement,
68
- contentOffset,
69
- contentSize
70
- } = event.nativeEvent;
71
- const thresholdCrossed = layoutMeasurement.height + contentOffset.y >= contentSize.height - (threshold ?? 0);
72
- if (isThresholdCrossed !== thresholdCrossed) {
73
- setThresholdCrossed(thresholdCrossed);
74
- setButtonVisible(!thresholdCrossed);
45
+ const isButtonVisible = (0, _reactNativeReanimated.useSharedValue)(1);
46
+ const scrollViewHeight = (0, _reactNativeReanimated.useSharedValue)(0);
47
+ const contentHeight = (0, _reactNativeReanimated.useSharedValue)(0);
48
+ const offsetY = (0, _reactNativeReanimated.useScrollViewOffset)(scrollViewRef);
49
+ (0, _reactNativeReanimated.useAnimatedReaction)(() => scrollViewHeight.value + Math.max(offsetY.value, 0) >= contentHeight.value - (threshold ?? 0), (crossed, previous) => {
50
+ if (crossed !== previous) {
51
+ // eslint-disable-next-line functional/immutable-data
52
+ isButtonVisible.value = (0, _reactNativeReanimated.withSpring)(crossed && scrollEnabled ? 0 : 1, _core.IOSpringValues.button);
53
+ if (onThresholdCrossed) {
54
+ (0, _reactNativeReanimated.runOnJS)(onThresholdCrossed)(crossed);
55
+ }
75
56
  }
76
- }, [threshold, isThresholdCrossed]);
77
-
78
- /**
79
- * A side effect that calls the `onThresholdCrossed` callback whenever the value of `isThresholdCrossed` changes.
80
- */
81
- (0, _react.useEffect)(() => {
82
- onThresholdCrossed?.(isThresholdCrossed);
83
- }, [onThresholdCrossed, isThresholdCrossed]);
57
+ });
84
58
 
85
59
  /**
86
60
  * A callback that is called whenever the size of the scrollable content changes. It updates the
87
61
  * state with the new content height.
88
62
  */
89
- const handleContentSizeChange = (0, _react.useCallback)((_contentWidth, contentHeight) => {
90
- setContentHeight(contentHeight);
91
- }, []);
63
+ const handleContentSizeChange = (0, _react.useCallback)(
64
+ // eslint-disable-next-line functional/immutable-data
65
+ (_w, h) => contentHeight.value = h, [contentHeight]);
92
66
 
93
67
  /**
94
68
  * A callback that is called whenever the size of the scroll view changes. It updates the state
95
69
  * with the new scroll view height.
96
70
  */
97
- const handleLayout = (0, _react.useCallback)(event => {
98
- setScrollViewHeight(event.nativeEvent.layout.height);
99
- }, []);
71
+ const handleLayout = (0, _react.useCallback)(event =>
72
+ // eslint-disable-next-line functional/immutable-data
73
+ scrollViewHeight.value = event.nativeEvent.layout.height, [scrollViewHeight]);
100
74
 
101
75
  /**
102
76
  * A callback that is called when the "scroll to bottom" button is pressed. It scrolls the
103
77
  * scroll view to the bottom and hides the button.
104
78
  */
105
79
  const handleScrollDownPress = (0, _react.useCallback)(() => {
106
- setButtonVisible(false);
107
- scrollViewRef.current?.scrollToEnd();
108
- }, [scrollViewRef]);
80
+ (0, _reactNativeReanimated.runOnUI)(() => {
81
+ "worklet";
109
82
 
110
- /**
111
- * Whether or not the "scroll to bottom" button needs to be displayed. It is only displayed
112
- * when the scrollable content cannot fit inside the scroll view and the button is enabled
113
- * (`scrollEnabled` is `true`).
114
- */
115
- const needsScroll = (0, _react.useMemo)(() => scrollViewHeight > 0 && contentHeight > 0 && scrollViewHeight < contentHeight, [scrollViewHeight, contentHeight]);
83
+ // eslint-disable-next-line functional/immutable-data
84
+ isButtonVisible.value = (0, _reactNativeReanimated.withSpring)(0, _core.IOSpringValues.button);
85
+ const targetY = Math.max(0, contentHeight.value - scrollViewHeight.value);
86
+ (0, _reactNativeReanimated.scrollTo)(scrollViewRef, 0, targetY, true);
87
+ })();
88
+ }, [scrollViewRef, contentHeight, scrollViewHeight, isButtonVisible]);
116
89
 
117
90
  /**
118
- * Whether or not to render the "scroll to bottom" button. It is only rendered when the scroll view
119
- * is enabled, needs to be scrolled, and the button is visible (`isButtonVisible` is `true`).
91
+ * The "scroll to bottom" button component. It is wrapped in a reanimated View
92
+ * and has animated style applied to it.
120
93
  */
121
- const shouldRenderScrollButton = scrollEnabled && needsScroll && isButtonVisible;
122
94
 
123
- /**
124
- * The "scroll to bottom" button component. It is wrapped in a reanimated view and has enter and exit
125
- * animations applied to it.
126
- */
127
- const scrollDownButton = /*#__PURE__*/(0, _jsxRuntime.jsx)(_ScaleInOutAnimation.ScaleInOutAnimation, {
128
- springConfig: _core.IOSpringValues.button,
129
- style: styles.scrollDownButton,
130
- visible: shouldRenderScrollButton,
95
+ const buttonTransitionStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
96
+ opacity: isButtonVisible.value,
97
+ transform: [{
98
+ scale: (0, _reactNativeReanimated.interpolate)(isButtonVisible.value, [0, 1], [0.5, 1])
99
+ }]
100
+ }));
101
+ const scrollDownButton = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
102
+ style: [styles.scrollDownButton, buttonTransitionStyle],
131
103
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_buttons.IconButtonSolid, {
132
104
  testID: "ScrollDownButton",
133
105
  accessibilityLabel: "Scroll to bottom",
@@ -136,13 +108,11 @@ const ForceScrollDownView = ({
136
108
  })
137
109
  });
138
110
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
139
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
111
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNativeReanimated.default.ScrollView, {
140
112
  testID: "ScrollView",
141
113
  ref: scrollViewRef,
142
114
  scrollEnabled: scrollEnabled,
143
115
  style: style,
144
- onScroll: handleScroll,
145
- scrollEventThrottle: 8,
146
116
  onLayout: handleLayout,
147
117
  onContentSizeChange: handleContentSizeChange,
148
118
  contentContainerStyle: contentContainerStyle,
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_core","_buttons","_ScaleInOutAnimation","_layout","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ForceScrollDownView","footerActions","children","threshold","customThreshold","style","contentContainerStyle","scrollEnabled","onThresholdCrossed","scrollViewRef","useRef","footerActionsInlineMeasurements","handleFooterActionsInlineMeasurements","useFooterActionsInlineMeasurements","safeBottomAreaHeight","scrollViewHeight","setScrollViewHeight","useState","contentHeight","setContentHeight","isThresholdCrossed","setThresholdCrossed","isButtonVisible","setButtonVisible","handleScroll","useCallback","event","layoutMeasurement","contentOffset","contentSize","nativeEvent","thresholdCrossed","height","y","useEffect","handleContentSizeChange","_contentWidth","handleLayout","layout","handleScrollDownPress","current","scrollToEnd","needsScroll","useMemo","shouldRenderScrollButton","scrollDownButton","jsx","ScaleInOutAnimation","springConfig","IOSpringValues","button","styles","visible","IconButtonSolid","testID","accessibilityLabel","icon","onPress","jsxs","Fragment","ScrollView","ref","onScroll","scrollEventThrottle","onLayout","onContentSizeChange","FooterActions","onMeasure","fixed","exports","StyleSheet","create","position","zIndex","right","IOVisualCostants","scrollDownButtonRight","bottom","scrollDownButtonBottom"],"sourceRoot":"../../../../src","sources":["components/templates/ForceScrollDownView.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_core","_buttons","_layout","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ForceScrollDownView","footerActions","children","threshold","customThreshold","style","contentContainerStyle","scrollEnabled","onThresholdCrossed","animatedRef","internalAnimatedRef","useAnimatedRef","scrollViewRef","footerActionsInlineMeasurements","handleFooterActionsInlineMeasurements","useFooterActionsInlineMeasurements","safeBottomAreaHeight","isButtonVisible","useSharedValue","scrollViewHeight","contentHeight","offsetY","useScrollViewOffset","useAnimatedReaction","value","Math","max","crossed","previous","withSpring","IOSpringValues","button","runOnJS","handleContentSizeChange","useCallback","_w","h","handleLayout","event","nativeEvent","layout","height","handleScrollDownPress","runOnUI","targetY","scrollTo","buttonTransitionStyle","useAnimatedStyle","opacity","transform","scale","interpolate","scrollDownButton","jsx","View","styles","IconButtonSolid","testID","accessibilityLabel","icon","onPress","jsxs","Fragment","ScrollView","ref","onLayout","onContentSizeChange","FooterActions","onMeasure","fixed","exports","StyleSheet","create","position","zIndex","right","IOVisualCostants","scrollDownButtonRight","bottom","scrollDownButtonBottom"],"sourceRoot":"../../../../src","sources":["components/templates/ForceScrollDownView.tsx"],"mappings":"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","ignoreList":[]}
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
 
3
- import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
- import { ScrollView, StyleSheet } from "react-native";
3
+ import React, { useCallback } from "react";
4
+ import { StyleSheet } from "react-native";
5
+ import Animated, { interpolate, runOnJS, runOnUI, scrollTo, useAnimatedReaction, useAnimatedRef, useAnimatedStyle, useScrollViewOffset, useSharedValue, withSpring } from "react-native-reanimated";
5
6
  import { IOSpringValues, IOVisualCostants } from "../../core";
6
7
  import { IconButtonSolid } from "../buttons";
7
- import { ScaleInOutAnimation } from "../common/ScaleInOutAnimation";
8
8
  import { FooterActions, useFooterActionsInlineMeasurements } from "../layout";
9
9
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
10
10
  /**
@@ -20,109 +20,81 @@ const ForceScrollDownView = ({
20
20
  style,
21
21
  contentContainerStyle,
22
22
  scrollEnabled = true,
23
- onThresholdCrossed
23
+ onThresholdCrossed,
24
+ animatedRef
24
25
  }) => {
25
- const scrollViewRef = useRef(null);
26
+ const internalAnimatedRef = useAnimatedRef();
27
+ const scrollViewRef = animatedRef ?? internalAnimatedRef;
26
28
  const {
27
29
  footerActionsInlineMeasurements,
28
30
  handleFooterActionsInlineMeasurements
29
31
  } = useFooterActionsInlineMeasurements();
30
32
  const threshold = footerActions ? footerActionsInlineMeasurements.safeBottomAreaHeight : customThreshold;
31
33
 
32
- /**
33
- * The height of the scroll view, used to determine whether or not the scrollable content fits inside
34
- * the scroll view and whether the "scroll to bottom" button should be displayed.
35
- */
36
- const [scrollViewHeight, setScrollViewHeight] = useState(0);
37
-
38
- /**
39
- * The height of the scrollable content, used to determine whether or not the "scroll to bottom" button
40
- * should be displayed.
41
- */
42
- const [contentHeight, setContentHeight] = useState(0);
43
-
44
- /**
45
- * Whether or not the scroll view has crossed the threshold from the bottom.
46
- */
47
- const [isThresholdCrossed, setThresholdCrossed] = useState(false);
48
-
49
34
  /**
50
35
  * Whether or not the "scroll to bottom" button should be visible. This is controlled by the threshold
51
36
  * and the current scroll position.
52
37
  */
53
- const [isButtonVisible, setButtonVisible] = useState(true);
38
+ // const [isButtonVisible, setButtonVisible] = useState(true);
54
39
 
55
- /**
56
- * A callback that is called whenever the scroll view is scrolled. It checks whether or not the
57
- * scroll view has crossed the threshold from the bottom and updates the state accordingly.
58
- * The callback is designed to update button visibility only when crossing the threshold.
59
- */
60
- const handleScroll = useCallback(event => {
61
- const {
62
- layoutMeasurement,
63
- contentOffset,
64
- contentSize
65
- } = event.nativeEvent;
66
- const thresholdCrossed = layoutMeasurement.height + contentOffset.y >= contentSize.height - (threshold ?? 0);
67
- if (isThresholdCrossed !== thresholdCrossed) {
68
- setThresholdCrossed(thresholdCrossed);
69
- setButtonVisible(!thresholdCrossed);
40
+ const isButtonVisible = useSharedValue(1);
41
+ const scrollViewHeight = useSharedValue(0);
42
+ const contentHeight = useSharedValue(0);
43
+ const offsetY = useScrollViewOffset(scrollViewRef);
44
+ useAnimatedReaction(() => scrollViewHeight.value + Math.max(offsetY.value, 0) >= contentHeight.value - (threshold ?? 0), (crossed, previous) => {
45
+ if (crossed !== previous) {
46
+ // eslint-disable-next-line functional/immutable-data
47
+ isButtonVisible.value = withSpring(crossed && scrollEnabled ? 0 : 1, IOSpringValues.button);
48
+ if (onThresholdCrossed) {
49
+ runOnJS(onThresholdCrossed)(crossed);
50
+ }
70
51
  }
71
- }, [threshold, isThresholdCrossed]);
72
-
73
- /**
74
- * A side effect that calls the `onThresholdCrossed` callback whenever the value of `isThresholdCrossed` changes.
75
- */
76
- useEffect(() => {
77
- onThresholdCrossed?.(isThresholdCrossed);
78
- }, [onThresholdCrossed, isThresholdCrossed]);
52
+ });
79
53
 
80
54
  /**
81
55
  * A callback that is called whenever the size of the scrollable content changes. It updates the
82
56
  * state with the new content height.
83
57
  */
84
- const handleContentSizeChange = useCallback((_contentWidth, contentHeight) => {
85
- setContentHeight(contentHeight);
86
- }, []);
58
+ const handleContentSizeChange = useCallback(
59
+ // eslint-disable-next-line functional/immutable-data
60
+ (_w, h) => contentHeight.value = h, [contentHeight]);
87
61
 
88
62
  /**
89
63
  * A callback that is called whenever the size of the scroll view changes. It updates the state
90
64
  * with the new scroll view height.
91
65
  */
92
- const handleLayout = useCallback(event => {
93
- setScrollViewHeight(event.nativeEvent.layout.height);
94
- }, []);
66
+ const handleLayout = useCallback(event =>
67
+ // eslint-disable-next-line functional/immutable-data
68
+ scrollViewHeight.value = event.nativeEvent.layout.height, [scrollViewHeight]);
95
69
 
96
70
  /**
97
71
  * A callback that is called when the "scroll to bottom" button is pressed. It scrolls the
98
72
  * scroll view to the bottom and hides the button.
99
73
  */
100
74
  const handleScrollDownPress = useCallback(() => {
101
- setButtonVisible(false);
102
- scrollViewRef.current?.scrollToEnd();
103
- }, [scrollViewRef]);
75
+ runOnUI(() => {
76
+ "worklet";
104
77
 
105
- /**
106
- * Whether or not the "scroll to bottom" button needs to be displayed. It is only displayed
107
- * when the scrollable content cannot fit inside the scroll view and the button is enabled
108
- * (`scrollEnabled` is `true`).
109
- */
110
- const needsScroll = useMemo(() => scrollViewHeight > 0 && contentHeight > 0 && scrollViewHeight < contentHeight, [scrollViewHeight, contentHeight]);
78
+ // eslint-disable-next-line functional/immutable-data
79
+ isButtonVisible.value = withSpring(0, IOSpringValues.button);
80
+ const targetY = Math.max(0, contentHeight.value - scrollViewHeight.value);
81
+ scrollTo(scrollViewRef, 0, targetY, true);
82
+ })();
83
+ }, [scrollViewRef, contentHeight, scrollViewHeight, isButtonVisible]);
111
84
 
112
85
  /**
113
- * Whether or not to render the "scroll to bottom" button. It is only rendered when the scroll view
114
- * is enabled, needs to be scrolled, and the button is visible (`isButtonVisible` is `true`).
86
+ * The "scroll to bottom" button component. It is wrapped in a reanimated View
87
+ * and has animated style applied to it.
115
88
  */
116
- const shouldRenderScrollButton = scrollEnabled && needsScroll && isButtonVisible;
117
89
 
118
- /**
119
- * The "scroll to bottom" button component. It is wrapped in a reanimated view and has enter and exit
120
- * animations applied to it.
121
- */
122
- const scrollDownButton = /*#__PURE__*/_jsx(ScaleInOutAnimation, {
123
- springConfig: IOSpringValues.button,
124
- style: styles.scrollDownButton,
125
- visible: shouldRenderScrollButton,
90
+ const buttonTransitionStyle = useAnimatedStyle(() => ({
91
+ opacity: isButtonVisible.value,
92
+ transform: [{
93
+ scale: interpolate(isButtonVisible.value, [0, 1], [0.5, 1])
94
+ }]
95
+ }));
96
+ const scrollDownButton = /*#__PURE__*/_jsx(Animated.View, {
97
+ style: [styles.scrollDownButton, buttonTransitionStyle],
126
98
  children: /*#__PURE__*/_jsx(IconButtonSolid, {
127
99
  testID: "ScrollDownButton",
128
100
  accessibilityLabel: "Scroll to bottom",
@@ -131,13 +103,11 @@ const ForceScrollDownView = ({
131
103
  })
132
104
  });
133
105
  return /*#__PURE__*/_jsxs(_Fragment, {
134
- children: [/*#__PURE__*/_jsxs(ScrollView, {
106
+ children: [/*#__PURE__*/_jsxs(Animated.ScrollView, {
135
107
  testID: "ScrollView",
136
108
  ref: scrollViewRef,
137
109
  scrollEnabled: scrollEnabled,
138
110
  style: style,
139
- onScroll: handleScroll,
140
- scrollEventThrottle: 8,
141
111
  onLayout: handleLayout,
142
112
  onContentSizeChange: handleContentSizeChange,
143
113
  contentContainerStyle: contentContainerStyle,
@@ -1 +1 @@
1
- {"version":3,"names":["React","useCallback","useEffect","useMemo","useRef","useState","ScrollView","StyleSheet","IOSpringValues","IOVisualCostants","IconButtonSolid","ScaleInOutAnimation","FooterActions","useFooterActionsInlineMeasurements","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","ForceScrollDownView","footerActions","children","threshold","customThreshold","style","contentContainerStyle","scrollEnabled","onThresholdCrossed","scrollViewRef","footerActionsInlineMeasurements","handleFooterActionsInlineMeasurements","safeBottomAreaHeight","scrollViewHeight","setScrollViewHeight","contentHeight","setContentHeight","isThresholdCrossed","setThresholdCrossed","isButtonVisible","setButtonVisible","handleScroll","event","layoutMeasurement","contentOffset","contentSize","nativeEvent","thresholdCrossed","height","y","handleContentSizeChange","_contentWidth","handleLayout","layout","handleScrollDownPress","current","scrollToEnd","needsScroll","shouldRenderScrollButton","scrollDownButton","springConfig","button","styles","visible","testID","accessibilityLabel","icon","onPress","ref","onScroll","scrollEventThrottle","onLayout","onContentSizeChange","onMeasure","fixed","create","position","zIndex","right","scrollDownButtonRight","bottom","scrollDownButtonBottom"],"sourceRoot":"../../../../src","sources":["components/templates/ForceScrollDownView.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","useCallback","StyleSheet","Animated","interpolate","runOnJS","runOnUI","scrollTo","useAnimatedReaction","useAnimatedRef","useAnimatedStyle","useScrollViewOffset","useSharedValue","withSpring","IOSpringValues","IOVisualCostants","IconButtonSolid","FooterActions","useFooterActionsInlineMeasurements","jsx","_jsx","jsxs","_jsxs","Fragment","_Fragment","ForceScrollDownView","footerActions","children","threshold","customThreshold","style","contentContainerStyle","scrollEnabled","onThresholdCrossed","animatedRef","internalAnimatedRef","scrollViewRef","footerActionsInlineMeasurements","handleFooterActionsInlineMeasurements","safeBottomAreaHeight","isButtonVisible","scrollViewHeight","contentHeight","offsetY","value","Math","max","crossed","previous","button","handleContentSizeChange","_w","h","handleLayout","event","nativeEvent","layout","height","handleScrollDownPress","targetY","buttonTransitionStyle","opacity","transform","scale","scrollDownButton","View","styles","testID","accessibilityLabel","icon","onPress","ScrollView","ref","onLayout","onContentSizeChange","onMeasure","fixed","create","position","zIndex","right","scrollDownButtonRight","bottom","scrollDownButtonBottom"],"sourceRoot":"../../../../src","sources":["components/templates/ForceScrollDownView.tsx"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,6 @@
1
1
  import React, { ComponentProps, ReactNode } from "react";
2
2
  import { ScrollViewProps } from "react-native";
3
+ import Animated, { AnimatedRef } from "react-native-reanimated";
3
4
  import { FooterActions } from "../layout";
4
5
  type ForceScrollDownViewActions = {
5
6
  /**
@@ -27,6 +28,11 @@ export type ForceScrollDownView = {
27
28
  * is passed a boolean indicating whether the threshold has been crossed (`true`) or not (`false`).
28
29
  */
29
30
  onThresholdCrossed?: (crossed: boolean) => void;
31
+ /**
32
+ * Optional Animated ref to be used with `useScrollViewOffset`
33
+ * (outside this component)
34
+ */
35
+ animatedRef?: AnimatedRef<Animated.ScrollView>;
30
36
  } & ForceScrollDownViewSlot & Pick<ScrollViewProps, "style" | "contentContainerStyle" | "scrollEnabled" | "testID">;
31
37
  /**
32
38
  * A React Native component that displays a scroll view with a button that scrolls to the bottom of the content
@@ -34,6 +40,6 @@ export type ForceScrollDownView = {
34
40
  * configurable by the `threshold` prop. The button, and the scrolling, can also be disabled by setting the
35
41
  * `scrollEnabled` prop to `false`.
36
42
  */
37
- declare const ForceScrollDownView: ({ footerActions, children, threshold: customThreshold, style, contentContainerStyle, scrollEnabled, onThresholdCrossed }: ForceScrollDownView) => React.JSX.Element;
43
+ declare const ForceScrollDownView: ({ footerActions, children, threshold: customThreshold, style, contentContainerStyle, scrollEnabled, onThresholdCrossed, animatedRef }: ForceScrollDownView) => React.JSX.Element;
38
44
  export { ForceScrollDownView };
39
45
  //# sourceMappingURL=ForceScrollDownView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ForceScrollDownView.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/ForceScrollDownView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACZ,cAAc,EACd,SAAS,EAMV,MAAM,OAAO,CAAC;AACf,OAAO,EAKL,eAAe,EAEhB,MAAM,cAAc,CAAC;AAItB,OAAO,EAAE,aAAa,EAAsC,MAAM,WAAW,CAAC;AAE9E,KAAK,0BAA0B,GAAG;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,KAAK,CAAC;IAClB,aAAa,EAAE,IAAI,CACjB,cAAc,CAAC,OAAO,aAAa,CAAC,EACpC,OAAO,GAAG,WAAW,CACtB,CAAC;CACH,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,KAAK,CAAC;CACvB,CAAC;AAEF,KAAK,uBAAuB,GACxB,0BAA0B,GAC1B,6BAA6B,CAAC;AAElC,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACjD,GAAG,uBAAuB,GACzB,IAAI,CACF,eAAe,EACf,OAAO,GAAG,uBAAuB,GAAG,eAAe,GAAG,QAAQ,CAC/D,CAAC;AAEJ;;;;;GAKG;AACH,QAAA,MAAM,mBAAmB,GAAI,0HAQ1B,mBAAmB,sBA4JrB,CAAC;AAWF,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
1
+ {"version":3,"file":"ForceScrollDownView.d.ts","sourceRoot":"","sources":["../../../../src/components/templates/ForceScrollDownView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,cAAc,EAAE,SAAS,EAAe,MAAM,OAAO,CAAC;AACtE,OAAO,EAAqB,eAAe,EAAc,MAAM,cAAc,CAAC;AAC9E,OAAO,QAAQ,EAAE,EACf,WAAW,EAWZ,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,aAAa,EAAsC,MAAM,WAAW,CAAC;AAE9E,KAAK,0BAA0B,GAAG;IAChC;;OAEG;IACH,SAAS,CAAC,EAAE,KAAK,CAAC;IAClB,aAAa,EAAE,IAAI,CACjB,cAAc,CAAC,OAAO,aAAa,CAAC,EACpC,OAAO,GAAG,WAAW,CACtB,CAAC;CACH,CAAC;AAEF,KAAK,6BAA6B,GAAG;IACnC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,KAAK,CAAC;CACvB,CAAC;AAEF,KAAK,uBAAuB,GACxB,0BAA0B,GAC1B,6BAA6B,CAAC;AAElC,MAAM,MAAM,mBAAmB,GAAG;IAChC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;CAChD,GAAG,uBAAuB,GACzB,IAAI,CACF,eAAe,EACf,OAAO,GAAG,uBAAuB,GAAG,eAAe,GAAG,QAAQ,CAC/D,CAAC;AAEJ;;;;;GAKG;AACH,QAAA,MAAM,mBAAmB,GAAI,uIAS1B,mBAAmB,sBAyHrB,CAAC;AAWF,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagopa/io-app-design-system",
3
- "version": "5.11.11",
3
+ "version": "5.11.12",
4
4
  "description": "The library defining the core components of the design system of @pagopa/io-app",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -1,23 +1,20 @@
1
- import React, {
2
- ComponentProps,
3
- ReactNode,
4
- useCallback,
5
- useEffect,
6
- useMemo,
7
- useRef,
8
- useState
9
- } from "react";
10
- import {
11
- LayoutChangeEvent,
12
- NativeScrollEvent,
13
- NativeSyntheticEvent,
14
- ScrollView,
15
- ScrollViewProps,
16
- StyleSheet
17
- } from "react-native";
1
+ import React, { ComponentProps, ReactNode, useCallback } from "react";
2
+ import { LayoutChangeEvent, ScrollViewProps, StyleSheet } from "react-native";
3
+ import Animated, {
4
+ AnimatedRef,
5
+ interpolate,
6
+ runOnJS,
7
+ runOnUI,
8
+ scrollTo,
9
+ useAnimatedReaction,
10
+ useAnimatedRef,
11
+ useAnimatedStyle,
12
+ useScrollViewOffset,
13
+ useSharedValue,
14
+ withSpring
15
+ } from "react-native-reanimated";
18
16
  import { IOSpringValues, IOVisualCostants } from "../../core";
19
17
  import { IconButtonSolid } from "../buttons";
20
- import { ScaleInOutAnimation } from "../common/ScaleInOutAnimation";
21
18
  import { FooterActions, useFooterActionsInlineMeasurements } from "../layout";
22
19
 
23
20
  type ForceScrollDownViewActions = {
@@ -54,6 +51,11 @@ export type ForceScrollDownView = {
54
51
  * is passed a boolean indicating whether the threshold has been crossed (`true`) or not (`false`).
55
52
  */
56
53
  onThresholdCrossed?: (crossed: boolean) => void;
54
+ /**
55
+ * Optional Animated ref to be used with `useScrollViewOffset`
56
+ * (outside this component)
57
+ */
58
+ animatedRef?: AnimatedRef<Animated.ScrollView>;
57
59
  } & ForceScrollDownViewSlot &
58
60
  Pick<
59
61
  ScrollViewProps,
@@ -73,9 +75,11 @@ const ForceScrollDownView = ({
73
75
  style,
74
76
  contentContainerStyle,
75
77
  scrollEnabled = true,
76
- onThresholdCrossed
78
+ onThresholdCrossed,
79
+ animatedRef
77
80
  }: ForceScrollDownView) => {
78
- const scrollViewRef = useRef<ScrollView>(null);
81
+ const internalAnimatedRef = useAnimatedRef<Animated.ScrollView>();
82
+ const scrollViewRef = animatedRef ?? internalAnimatedRef;
79
83
 
80
84
  const {
81
85
  footerActionsInlineMeasurements,
@@ -86,134 +90,98 @@ const ForceScrollDownView = ({
86
90
  ? footerActionsInlineMeasurements.safeBottomAreaHeight
87
91
  : customThreshold;
88
92
 
89
- /**
90
- * The height of the scroll view, used to determine whether or not the scrollable content fits inside
91
- * the scroll view and whether the "scroll to bottom" button should be displayed.
92
- */
93
- const [scrollViewHeight, setScrollViewHeight] = useState<number>(0);
94
-
95
- /**
96
- * The height of the scrollable content, used to determine whether or not the "scroll to bottom" button
97
- * should be displayed.
98
- */
99
- const [contentHeight, setContentHeight] = useState<number>(0);
100
-
101
- /**
102
- * Whether or not the scroll view has crossed the threshold from the bottom.
103
- */
104
- const [isThresholdCrossed, setThresholdCrossed] = useState(false);
105
-
106
93
  /**
107
94
  * Whether or not the "scroll to bottom" button should be visible. This is controlled by the threshold
108
95
  * and the current scroll position.
109
96
  */
110
- const [isButtonVisible, setButtonVisible] = useState(true);
97
+ // const [isButtonVisible, setButtonVisible] = useState(true);
111
98
 
112
- /**
113
- * A callback that is called whenever the scroll view is scrolled. It checks whether or not the
114
- * scroll view has crossed the threshold from the bottom and updates the state accordingly.
115
- * The callback is designed to update button visibility only when crossing the threshold.
116
- */
117
- const handleScroll = useCallback(
118
- (event: NativeSyntheticEvent<NativeScrollEvent>) => {
119
- const { layoutMeasurement, contentOffset, contentSize } =
120
- event.nativeEvent;
121
-
122
- const thresholdCrossed =
123
- layoutMeasurement.height + contentOffset.y >=
124
- contentSize.height - (threshold ?? 0);
125
-
126
- if (isThresholdCrossed !== thresholdCrossed) {
127
- setThresholdCrossed(thresholdCrossed);
128
- setButtonVisible(!thresholdCrossed);
99
+ const isButtonVisible = useSharedValue(1);
100
+ const scrollViewHeight = useSharedValue(0);
101
+ const contentHeight = useSharedValue(0);
102
+ const offsetY = useScrollViewOffset(scrollViewRef);
103
+
104
+ useAnimatedReaction(
105
+ () =>
106
+ scrollViewHeight.value + Math.max(offsetY.value, 0) >=
107
+ contentHeight.value - (threshold ?? 0),
108
+ (crossed, previous) => {
109
+ if (crossed !== previous) {
110
+ // eslint-disable-next-line functional/immutable-data
111
+ isButtonVisible.value = withSpring(
112
+ crossed && scrollEnabled ? 0 : 1,
113
+ IOSpringValues.button
114
+ );
115
+ if (onThresholdCrossed) {
116
+ runOnJS(onThresholdCrossed)(crossed);
117
+ }
129
118
  }
130
- },
131
- [threshold, isThresholdCrossed]
119
+ }
132
120
  );
133
121
 
134
- /**
135
- * A side effect that calls the `onThresholdCrossed` callback whenever the value of `isThresholdCrossed` changes.
136
- */
137
- useEffect(() => {
138
- onThresholdCrossed?.(isThresholdCrossed);
139
- }, [onThresholdCrossed, isThresholdCrossed]);
140
-
141
122
  /**
142
123
  * A callback that is called whenever the size of the scrollable content changes. It updates the
143
124
  * state with the new content height.
144
125
  */
145
126
  const handleContentSizeChange = useCallback(
146
- (_contentWidth: number, contentHeight: number) => {
147
- setContentHeight(contentHeight);
148
- },
149
- []
127
+ // eslint-disable-next-line functional/immutable-data
128
+ (_w: number, h: number) => (contentHeight.value = h),
129
+ [contentHeight]
150
130
  );
151
131
 
152
132
  /**
153
133
  * A callback that is called whenever the size of the scroll view changes. It updates the state
154
134
  * with the new scroll view height.
155
135
  */
156
- const handleLayout = useCallback((event: LayoutChangeEvent) => {
157
- setScrollViewHeight(event.nativeEvent.layout.height);
158
- }, []);
136
+ const handleLayout = useCallback(
137
+ (event: LayoutChangeEvent) =>
138
+ // eslint-disable-next-line functional/immutable-data
139
+ (scrollViewHeight.value = event.nativeEvent.layout.height),
140
+ [scrollViewHeight]
141
+ );
159
142
 
160
143
  /**
161
144
  * A callback that is called when the "scroll to bottom" button is pressed. It scrolls the
162
145
  * scroll view to the bottom and hides the button.
163
146
  */
164
147
  const handleScrollDownPress = useCallback(() => {
165
- setButtonVisible(false);
166
- scrollViewRef.current?.scrollToEnd();
167
- }, [scrollViewRef]);
148
+ runOnUI(() => {
149
+ "worklet";
150
+ // eslint-disable-next-line functional/immutable-data
151
+ isButtonVisible.value = withSpring(0, IOSpringValues.button);
152
+ const targetY = Math.max(0, contentHeight.value - scrollViewHeight.value);
153
+ scrollTo(scrollViewRef, 0, targetY, true);
154
+ })();
155
+ }, [scrollViewRef, contentHeight, scrollViewHeight, isButtonVisible]);
168
156
 
169
157
  /**
170
- * Whether or not the "scroll to bottom" button needs to be displayed. It is only displayed
171
- * when the scrollable content cannot fit inside the scroll view and the button is enabled
172
- * (`scrollEnabled` is `true`).
158
+ * The "scroll to bottom" button component. It is wrapped in a reanimated View
159
+ * and has animated style applied to it.
173
160
  */
174
- const needsScroll = useMemo(
175
- () =>
176
- scrollViewHeight > 0 &&
177
- contentHeight > 0 &&
178
- scrollViewHeight < contentHeight,
179
- [scrollViewHeight, contentHeight]
180
- );
181
161
 
182
- /**
183
- * Whether or not to render the "scroll to bottom" button. It is only rendered when the scroll view
184
- * is enabled, needs to be scrolled, and the button is visible (`isButtonVisible` is `true`).
185
- */
186
- const shouldRenderScrollButton =
187
- scrollEnabled && needsScroll && isButtonVisible;
162
+ const buttonTransitionStyle = useAnimatedStyle(() => ({
163
+ opacity: isButtonVisible.value,
164
+ transform: [{ scale: interpolate(isButtonVisible.value, [0, 1], [0.5, 1]) }]
165
+ }));
188
166
 
189
- /**
190
- * The "scroll to bottom" button component. It is wrapped in a reanimated view and has enter and exit
191
- * animations applied to it.
192
- */
193
167
  const scrollDownButton = (
194
- <ScaleInOutAnimation
195
- springConfig={IOSpringValues.button}
196
- style={styles.scrollDownButton}
197
- visible={shouldRenderScrollButton}
198
- >
168
+ <Animated.View style={[styles.scrollDownButton, buttonTransitionStyle]}>
199
169
  <IconButtonSolid
200
170
  testID={"ScrollDownButton"}
201
171
  accessibilityLabel="Scroll to bottom"
202
172
  icon="arrowBottom"
203
173
  onPress={handleScrollDownPress}
204
174
  />
205
- </ScaleInOutAnimation>
175
+ </Animated.View>
206
176
  );
207
177
 
208
178
  return (
209
179
  <>
210
- <ScrollView
180
+ <Animated.ScrollView
211
181
  testID={"ScrollView"}
212
182
  ref={scrollViewRef}
213
183
  scrollEnabled={scrollEnabled}
214
184
  style={style}
215
- onScroll={handleScroll}
216
- scrollEventThrottle={8}
217
185
  onLayout={handleLayout}
218
186
  onContentSizeChange={handleContentSizeChange}
219
187
  contentContainerStyle={contentContainerStyle}
@@ -226,7 +194,7 @@ const ForceScrollDownView = ({
226
194
  fixed={false}
227
195
  />
228
196
  )}
229
- </ScrollView>
197
+ </Animated.ScrollView>
230
198
  {scrollDownButton}
231
199
  </>
232
200
  );
@@ -1,115 +0,0 @@
1
- "use strict";
2
-
3
- var _reactNative = require("@testing-library/react-native");
4
- var _react = _interopRequireDefault(require("react"));
5
- var _reactNative2 = require("react-native");
6
- var _ForceScrollDownView = require("../ForceScrollDownView");
7
- var _jsxRuntime = require("react/jsx-runtime");
8
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
- /* eslint-disable functional/immutable-data */
10
-
11
- const tContent = "Some content";
12
- describe("ForceScrollDownView", () => {
13
- jest.useFakeTimers();
14
- it("should match snapshot", () => {
15
- const tChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative2.Text, {
16
- children: tContent
17
- });
18
- const component = (0, _reactNative.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_ForceScrollDownView.ForceScrollDownView, {
19
- threshold: 100,
20
- children: tChildren
21
- }));
22
- expect(component).toMatchSnapshot();
23
- });
24
- it("renders the content correctly", () => {
25
- const tChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative2.Text, {
26
- children: tContent
27
- });
28
- const {
29
- getByText
30
- } = (0, _reactNative.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_ForceScrollDownView.ForceScrollDownView, {
31
- threshold: 100,
32
- children: tChildren
33
- }));
34
- expect(getByText(tContent)).toBeDefined();
35
- });
36
- it("displays the scroll down button when necessary", async () => {
37
- const tChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative2.Text, {
38
- children: tContent
39
- });
40
- const tScreenHeight = 1000;
41
- const {
42
- getByTestId,
43
- queryByTestId
44
- } = (0, _reactNative.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_ForceScrollDownView.ForceScrollDownView, {
45
- threshold: 100,
46
- children: tChildren
47
- }));
48
- const scrollView = getByTestId("ScrollView");
49
-
50
- // Update scroll view height
51
- (0, _reactNative.fireEvent)(scrollView, "layout", {
52
- nativeEvent: {
53
- layout: {
54
- height: tScreenHeight
55
- }
56
- }
57
- });
58
-
59
- // Update scroll view content height
60
- (0, _reactNative.fireEvent)(scrollView, "contentSizeChange", null, tScreenHeight - 500);
61
-
62
- // Button should not be visible because content does not need scrolling
63
- const buttonBefore = queryByTestId("ScrollDownButton");
64
- expect(buttonBefore).toBeNull();
65
-
66
- // Increase content height to force button to be shown
67
- (0, _reactNative.fireEvent)(scrollView, "contentSizeChange", null, tScreenHeight + 500);
68
- jest.advanceTimersByTime(500);
69
-
70
- // Button should be visible now beacuse content needs scrolling
71
- const buttonAfter = queryByTestId("ScrollDownButton");
72
- expect(buttonAfter).not.toBeNull();
73
- });
74
- it("scrolls to the bottom when the button is pressed", () => {
75
- const tChildren = /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative2.Text, {
76
- children: tContent
77
- });
78
- const tScreenHeight = 1000;
79
- const {
80
- getByTestId,
81
- queryByTestId
82
- } = (0, _reactNative.render)(/*#__PURE__*/(0, _jsxRuntime.jsx)(_ForceScrollDownView.ForceScrollDownView, {
83
- threshold: 100,
84
- children: tChildren
85
- }));
86
- const scrollView = getByTestId("ScrollView");
87
-
88
- // Update scroll view height
89
- (0, _reactNative.fireEvent)(scrollView, "layout", {
90
- nativeEvent: {
91
- layout: {
92
- height: tScreenHeight
93
- }
94
- }
95
- });
96
-
97
- // Update scroll view content height
98
- (0, _reactNative.fireEvent)(scrollView, "contentSizeChange", null, tScreenHeight + 500);
99
-
100
- // Button should be visible
101
- const buttonBefore = getByTestId("ScrollDownButton");
102
- expect(buttonBefore).not.toBeNull();
103
-
104
- // Fire button press event
105
- _reactNative.fireEvent.press(buttonBefore);
106
-
107
- // Wait for the scroll animation
108
- jest.advanceTimersByTime(500);
109
-
110
- // Button should not be visible after scrolling
111
- const buttonAfter = queryByTestId("ScrollDownButton");
112
- expect(buttonAfter).toBeNull();
113
- });
114
- });
115
- //# sourceMappingURL=ForceScrollDownView.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["_reactNative","require","_react","_interopRequireDefault","_reactNative2","_ForceScrollDownView","_jsxRuntime","e","__esModule","default","tContent","describe","jest","useFakeTimers","it","tChildren","jsx","Text","children","component","render","ForceScrollDownView","threshold","expect","toMatchSnapshot","getByText","toBeDefined","tScreenHeight","getByTestId","queryByTestId","scrollView","fireEvent","nativeEvent","layout","height","buttonBefore","toBeNull","advanceTimersByTime","buttonAfter","not","press"],"sourceRoot":"../../../../../src","sources":["components/templates/__test__/ForceScrollDownView.test.tsx"],"mappings":"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","ignoreList":[]}
@@ -1,18 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`ForceScrollDownView should match snapshot 1`] = `
4
- <RCTScrollView
5
- onContentSizeChange={[Function]}
6
- onLayout={[Function]}
7
- onScroll={[Function]}
8
- scrollEnabled={true}
9
- scrollEventThrottle={8}
10
- testID="ScrollView"
11
- >
12
- <View>
13
- <Text>
14
- Some content
15
- </Text>
16
- </View>
17
- </RCTScrollView>
18
- `;
@@ -1,113 +0,0 @@
1
- "use strict";
2
-
3
- /* eslint-disable functional/immutable-data */
4
- import { fireEvent, render } from "@testing-library/react-native";
5
- import React from "react";
6
- import { Text } from "react-native";
7
- import { ForceScrollDownView } from "../ForceScrollDownView";
8
- import { jsx as _jsx } from "react/jsx-runtime";
9
- const tContent = "Some content";
10
- describe("ForceScrollDownView", () => {
11
- jest.useFakeTimers();
12
- it("should match snapshot", () => {
13
- const tChildren = /*#__PURE__*/_jsx(Text, {
14
- children: tContent
15
- });
16
- const component = render(/*#__PURE__*/_jsx(ForceScrollDownView, {
17
- threshold: 100,
18
- children: tChildren
19
- }));
20
- expect(component).toMatchSnapshot();
21
- });
22
- it("renders the content correctly", () => {
23
- const tChildren = /*#__PURE__*/_jsx(Text, {
24
- children: tContent
25
- });
26
- const {
27
- getByText
28
- } = render(/*#__PURE__*/_jsx(ForceScrollDownView, {
29
- threshold: 100,
30
- children: tChildren
31
- }));
32
- expect(getByText(tContent)).toBeDefined();
33
- });
34
- it("displays the scroll down button when necessary", async () => {
35
- const tChildren = /*#__PURE__*/_jsx(Text, {
36
- children: tContent
37
- });
38
- const tScreenHeight = 1000;
39
- const {
40
- getByTestId,
41
- queryByTestId
42
- } = render(/*#__PURE__*/_jsx(ForceScrollDownView, {
43
- threshold: 100,
44
- children: tChildren
45
- }));
46
- const scrollView = getByTestId("ScrollView");
47
-
48
- // Update scroll view height
49
- fireEvent(scrollView, "layout", {
50
- nativeEvent: {
51
- layout: {
52
- height: tScreenHeight
53
- }
54
- }
55
- });
56
-
57
- // Update scroll view content height
58
- fireEvent(scrollView, "contentSizeChange", null, tScreenHeight - 500);
59
-
60
- // Button should not be visible because content does not need scrolling
61
- const buttonBefore = queryByTestId("ScrollDownButton");
62
- expect(buttonBefore).toBeNull();
63
-
64
- // Increase content height to force button to be shown
65
- fireEvent(scrollView, "contentSizeChange", null, tScreenHeight + 500);
66
- jest.advanceTimersByTime(500);
67
-
68
- // Button should be visible now beacuse content needs scrolling
69
- const buttonAfter = queryByTestId("ScrollDownButton");
70
- expect(buttonAfter).not.toBeNull();
71
- });
72
- it("scrolls to the bottom when the button is pressed", () => {
73
- const tChildren = /*#__PURE__*/_jsx(Text, {
74
- children: tContent
75
- });
76
- const tScreenHeight = 1000;
77
- const {
78
- getByTestId,
79
- queryByTestId
80
- } = render(/*#__PURE__*/_jsx(ForceScrollDownView, {
81
- threshold: 100,
82
- children: tChildren
83
- }));
84
- const scrollView = getByTestId("ScrollView");
85
-
86
- // Update scroll view height
87
- fireEvent(scrollView, "layout", {
88
- nativeEvent: {
89
- layout: {
90
- height: tScreenHeight
91
- }
92
- }
93
- });
94
-
95
- // Update scroll view content height
96
- fireEvent(scrollView, "contentSizeChange", null, tScreenHeight + 500);
97
-
98
- // Button should be visible
99
- const buttonBefore = getByTestId("ScrollDownButton");
100
- expect(buttonBefore).not.toBeNull();
101
-
102
- // Fire button press event
103
- fireEvent.press(buttonBefore);
104
-
105
- // Wait for the scroll animation
106
- jest.advanceTimersByTime(500);
107
-
108
- // Button should not be visible after scrolling
109
- const buttonAfter = queryByTestId("ScrollDownButton");
110
- expect(buttonAfter).toBeNull();
111
- });
112
- });
113
- //# sourceMappingURL=ForceScrollDownView.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["fireEvent","render","React","Text","ForceScrollDownView","jsx","_jsx","tContent","describe","jest","useFakeTimers","it","tChildren","children","component","threshold","expect","toMatchSnapshot","getByText","toBeDefined","tScreenHeight","getByTestId","queryByTestId","scrollView","nativeEvent","layout","height","buttonBefore","toBeNull","advanceTimersByTime","buttonAfter","not","press"],"sourceRoot":"../../../../../src","sources":["components/templates/__test__/ForceScrollDownView.test.tsx"],"mappings":"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","ignoreList":[]}
@@ -1,18 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`ForceScrollDownView should match snapshot 1`] = `
4
- <RCTScrollView
5
- onContentSizeChange={[Function]}
6
- onLayout={[Function]}
7
- onScroll={[Function]}
8
- scrollEnabled={true}
9
- scrollEventThrottle={8}
10
- testID="ScrollView"
11
- >
12
- <View>
13
- <Text>
14
- Some content
15
- </Text>
16
- </View>
17
- </RCTScrollView>
18
- `;
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ForceScrollDownView.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ForceScrollDownView.test.d.ts","sourceRoot":"","sources":["../../../../../src/components/templates/__test__/ForceScrollDownView.test.tsx"],"names":[],"mappings":""}
@@ -1,106 +0,0 @@
1
- /* eslint-disable functional/immutable-data */
2
- import { fireEvent, render } from "@testing-library/react-native";
3
- import React from "react";
4
- import { Text } from "react-native";
5
- import { ForceScrollDownView } from "../ForceScrollDownView";
6
-
7
- const tContent = "Some content";
8
-
9
- describe("ForceScrollDownView", () => {
10
- jest.useFakeTimers();
11
-
12
- it("should match snapshot", () => {
13
- const tChildren = <Text>{tContent}</Text>;
14
-
15
- const component = render(
16
- <ForceScrollDownView threshold={100}>{tChildren}</ForceScrollDownView>
17
- );
18
-
19
- expect(component).toMatchSnapshot();
20
- });
21
-
22
- it("renders the content correctly", () => {
23
- const tChildren = <Text>{tContent}</Text>;
24
-
25
- const { getByText } = render(
26
- <ForceScrollDownView threshold={100}>{tChildren}</ForceScrollDownView>
27
- );
28
-
29
- expect(getByText(tContent)).toBeDefined();
30
- });
31
-
32
- it("displays the scroll down button when necessary", async () => {
33
- const tChildren = <Text>{tContent}</Text>;
34
-
35
- const tScreenHeight = 1000;
36
-
37
- const { getByTestId, queryByTestId } = render(
38
- <ForceScrollDownView threshold={100}>{tChildren}</ForceScrollDownView>
39
- );
40
-
41
- const scrollView = getByTestId("ScrollView");
42
-
43
- // Update scroll view height
44
- fireEvent(scrollView, "layout", {
45
- nativeEvent: {
46
- layout: {
47
- height: tScreenHeight
48
- }
49
- }
50
- });
51
-
52
- // Update scroll view content height
53
- fireEvent(scrollView, "contentSizeChange", null, tScreenHeight - 500);
54
-
55
- // Button should not be visible because content does not need scrolling
56
- const buttonBefore = queryByTestId("ScrollDownButton");
57
- expect(buttonBefore).toBeNull();
58
-
59
- // Increase content height to force button to be shown
60
- fireEvent(scrollView, "contentSizeChange", null, tScreenHeight + 500);
61
-
62
- jest.advanceTimersByTime(500);
63
-
64
- // Button should be visible now beacuse content needs scrolling
65
- const buttonAfter = queryByTestId("ScrollDownButton");
66
- expect(buttonAfter).not.toBeNull();
67
- });
68
-
69
- it("scrolls to the bottom when the button is pressed", () => {
70
- const tChildren = <Text>{tContent}</Text>;
71
-
72
- const tScreenHeight = 1000;
73
-
74
- const { getByTestId, queryByTestId } = render(
75
- <ForceScrollDownView threshold={100}>{tChildren}</ForceScrollDownView>
76
- );
77
-
78
- const scrollView = getByTestId("ScrollView");
79
-
80
- // Update scroll view height
81
- fireEvent(scrollView, "layout", {
82
- nativeEvent: {
83
- layout: {
84
- height: tScreenHeight
85
- }
86
- }
87
- });
88
-
89
- // Update scroll view content height
90
- fireEvent(scrollView, "contentSizeChange", null, tScreenHeight + 500);
91
-
92
- // Button should be visible
93
- const buttonBefore = getByTestId("ScrollDownButton");
94
- expect(buttonBefore).not.toBeNull();
95
-
96
- // Fire button press event
97
- fireEvent.press(buttonBefore);
98
-
99
- // Wait for the scroll animation
100
- jest.advanceTimersByTime(500);
101
-
102
- // Button should not be visible after scrolling
103
- const buttonAfter = queryByTestId("ScrollDownButton");
104
- expect(buttonAfter).toBeNull();
105
- });
106
- });
@@ -1,18 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`ForceScrollDownView should match snapshot 1`] = `
4
- <RCTScrollView
5
- onContentSizeChange={[Function]}
6
- onLayout={[Function]}
7
- onScroll={[Function]}
8
- scrollEnabled={true}
9
- scrollEventThrottle={8}
10
- testID="ScrollView"
11
- >
12
- <View>
13
- <Text>
14
- Some content
15
- </Text>
16
- </View>
17
- </RCTScrollView>
18
- `;