From a7d05f9125cb31ccdb791db75b1121b8e95c3f2d Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 20 Dec 2023 10:43:33 +0100 Subject: [PATCH 1/7] Migrate Icon and FloatingActionButton to function component --- ios/Podfile.lock | 31 +--- package-lock.json | 14 +- package.json | 2 +- src/components/FloatingActionButton.js | 132 ------------------ .../FloatingActionButton/FabPlusIcon.js | 74 ++++++++++ src/components/FloatingActionButton/index.js | 86 ++++++++++++ src/styles/utils/index.ts | 8 -- tests/ui/UnreadIndicatorsTest.js | 5 + 8 files changed, 176 insertions(+), 176 deletions(-) delete mode 100644 src/components/FloatingActionButton.js create mode 100644 src/components/FloatingActionButton/FabPlusIcon.js create mode 100644 src/components/FloatingActionButton/index.js diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0fac30a26430..eebd6ad532d4 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -777,35 +777,10 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (3.5.4): - - DoubleConversion - - FBLazyVector - - glog - - hermes-engine - - RCT-Folly - - RCTRequired - - RCTTypeSafety - - React-callinvoker + - RNReanimated (3.6.1): + - RCT-Folly (= 2021.07.22.00) - React-Core - - React-Core/DevSupport - - React-Core/RCTWebSocket - - React-CoreModules - - React-cxxreact - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-RCTActionSheet - - React-RCTAnimation - - React-RCTAppDelegate - - React-RCTBlob - - React-RCTImage - - React-RCTLinking - - React-RCTNetwork - - React-RCTSettings - - React-RCTText - ReactCommon/turbomodule/core - - Yoga - RNScreens (3.21.0): - React-Core - React-RCTImage @@ -1280,7 +1255,7 @@ SPEC CHECKSUMS: rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64 RNPermissions: 9b086c8f05b2e2faa587fdc31f4c5ab4509728aa RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87 + RNReanimated: fdbaa9c964bbab7fac50c90862b6cc5f041679b9 RNScreens: d037903436160a4b039d32606668350d2a808806 RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d diff --git a/package-lock.json b/package-lock.json index 1c2ae325575d..5b4c8c737681 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,7 +100,7 @@ "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "3.5.4", + "react-native-reanimated": "^3.6.1", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", @@ -44555,9 +44555,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.4.tgz", - "integrity": "sha512-8we9LLDO1o4Oj9/DICeEJ2K1tjfqkJagqQUglxeUAkol/HcEJ6PGxIrpBcNryLqCDYEcu6FZWld/FzizBIw6bg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.6.1.tgz", + "integrity": "sha512-F4vG9Yf9PKmE3GaWtVGUpzj3SM6YY2cx1yRHCwiMd1uY7W0gU017LfcVUorboJnj0y5QZqEriEK1Usq2Y8YZqg==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -84872,9 +84872,9 @@ "requires": {} }, "react-native-reanimated": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.5.4.tgz", - "integrity": "sha512-8we9LLDO1o4Oj9/DICeEJ2K1tjfqkJagqQUglxeUAkol/HcEJ6PGxIrpBcNryLqCDYEcu6FZWld/FzizBIw6bg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.6.1.tgz", + "integrity": "sha512-F4vG9Yf9PKmE3GaWtVGUpzj3SM6YY2cx1yRHCwiMd1uY7W0gU017LfcVUorboJnj0y5QZqEriEK1Usq2Y8YZqg==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", diff --git a/package.json b/package.json index 7281ab12cfa7..25e818c3cfcb 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,7 @@ "react-native-plaid-link-sdk": "10.8.0", "react-native-qrcode-svg": "^6.2.0", "react-native-quick-sqlite": "^8.0.0-beta.2", - "react-native-reanimated": "3.5.4", + "react-native-reanimated": "^3.6.1", "react-native-render-html": "6.3.1", "react-native-safe-area-context": "4.4.1", "react-native-screens": "3.21.0", diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js deleted file mode 100644 index 791eb150f8c9..000000000000 --- a/src/components/FloatingActionButton.js +++ /dev/null @@ -1,132 +0,0 @@ -import PropTypes from 'prop-types'; -import React, {PureComponent} from 'react'; -import {Animated, Easing, View} from 'react-native'; -import compose from '@libs/compose'; -import Icon from './Icon'; -import * as Expensicons from './Icon/Expensicons'; -import PressableWithFeedback from './Pressable/PressableWithFeedback'; -import Tooltip from './Tooltip/PopoverAnchorTooltip'; -import withLocalize, {withLocalizePropTypes} from './withLocalize'; -import withStyleUtils, {withStyleUtilsPropTypes} from './withStyleUtils'; -import withTheme, {withThemePropTypes} from './withTheme'; -import withThemeStyles, {withThemeStylesPropTypes} from './withThemeStyles'; - -const AnimatedIcon = Animated.createAnimatedComponent(Icon); -AnimatedIcon.displayName = 'AnimatedIcon'; - -const AnimatedPressable = Animated.createAnimatedComponent(PressableWithFeedback); -AnimatedPressable.displayName = 'AnimatedPressable'; - -const propTypes = { - // Callback to fire on request to toggle the FloatingActionButton - onPress: PropTypes.func.isRequired, - - // Current state (active or not active) of the component - isActive: PropTypes.bool.isRequired, - - // Ref for the button - buttonRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - - ...withLocalizePropTypes, - ...withThemePropTypes, - ...withThemeStylesPropTypes, - ...withStyleUtilsPropTypes, -}; - -const defaultProps = { - buttonRef: () => {}, -}; - -class FloatingActionButton extends PureComponent { - constructor(props) { - super(props); - this.animatedValue = new Animated.Value(props.isActive ? 1 : 0); - } - - componentDidUpdate(prevProps) { - if (prevProps.isActive === this.props.isActive) { - return; - } - - this.animateFloatingActionButton(); - } - - /** - * Animates the floating action button - * Method is called when the isActive prop changes - */ - animateFloatingActionButton() { - const animationFinalValue = this.props.isActive ? 1 : 0; - - Animated.timing(this.animatedValue, { - toValue: animationFinalValue, - duration: 340, - easing: Easing.inOut(Easing.ease), - useNativeDriver: false, - }).start(); - } - - render() { - const rotate = this.animatedValue.interpolate({ - inputRange: [0, 1], - outputRange: ['0deg', '135deg'], - }); - - const backgroundColor = this.animatedValue.interpolate({ - inputRange: [0, 1], - outputRange: [this.props.theme.success, this.props.theme.buttonDefaultBG], - }); - - const fill = this.animatedValue.interpolate({ - inputRange: [0, 1], - outputRange: [this.props.theme.textLight, this.props.theme.textDark], - }); - - return ( - - - { - this.fabPressable = el; - if (this.props.buttonRef) { - this.props.buttonRef.current = el; - } - }} - accessibilityLabel={this.props.accessibilityLabel} - role={this.props.role} - pressDimmingValue={1} - onPress={(e) => { - // Drop focus to avoid blue focus ring. - this.fabPressable.blur(); - this.props.onPress(e); - }} - onLongPress={() => {}} - style={[this.props.themeStyles.floatingActionButton, this.props.StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]} - > - - - - - ); - } -} - -FloatingActionButton.propTypes = propTypes; -FloatingActionButton.defaultProps = defaultProps; - -const FloatingActionButtonWithLocalize = withLocalize(FloatingActionButton); - -const FloatingActionButtonWithLocalizeWithRef = React.forwardRef((props, ref) => ( - -)); - -FloatingActionButtonWithLocalizeWithRef.displayName = 'FloatingActionButtonWithLocalizeWithRef'; - -export default compose(withThemeStyles, withTheme, withStyleUtils)(FloatingActionButtonWithLocalizeWithRef); diff --git a/src/components/FloatingActionButton/FabPlusIcon.js b/src/components/FloatingActionButton/FabPlusIcon.js new file mode 100644 index 000000000000..500606522b3b --- /dev/null +++ b/src/components/FloatingActionButton/FabPlusIcon.js @@ -0,0 +1,74 @@ +import PropTypes from 'prop-types'; +import React, {useEffect} from 'react'; +import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useSharedValue, withTiming} from 'react-native-reanimated'; +import Svg, {Path} from 'react-native-svg'; +import useTheme from '@hooks/useTheme'; +import variables from '@styles/variables'; + +const AnimatedPath = Animated.createAnimatedComponent(Path); + +const adapter = createAnimatedPropAdapter( + (props) => { + // eslint-disable-next-line rulesdir/prefer-underscore-method + if (Object.keys(props).includes('fill')) { + // eslint-disable-next-line no-param-reassign + props.fill = {type: 0, payload: processColor(props.fill)}; + } + // eslint-disable-next-line rulesdir/prefer-underscore-method + if (Object.keys(props).includes('stroke')) { + // eslint-disable-next-line no-param-reassign + props.stroke = {type: 0, payload: processColor(props.stroke)}; + } + }, + ['fill', 'stroke'], +); +adapter.propTypes = { + fill: PropTypes.string, + stroke: PropTypes.string, +}; + +const propTypes = { + /* Current state (active or not active) of the component */ + isActive: PropTypes.bool.isRequired, +}; + +function FabPlusIcon({isActive}) { + const {textLight, textDark} = useTheme(); + const sharedValue = useSharedValue(isActive ? 1 : 0); + + useEffect(() => { + sharedValue.value = withTiming(isActive ? 1 : 0, { + duration: 340, + easing: Easing.inOut(Easing.ease), + }); + }, [isActive, sharedValue]); + + const animatedProps = useAnimatedProps( + () => { + const fill = interpolateColor(sharedValue.value, [0, 1], [textLight, textDark]); + + return { + fill, + }; + }, + [], + adapter, + ); + + return ( + + + + ); +} + +FabPlusIcon.propTypes = propTypes; +FabPlusIcon.displayName = 'FabPlusIcon'; + +export default FabPlusIcon; diff --git a/src/components/FloatingActionButton/index.js b/src/components/FloatingActionButton/index.js new file mode 100644 index 000000000000..6922c8b1949b --- /dev/null +++ b/src/components/FloatingActionButton/index.js @@ -0,0 +1,86 @@ +import PropTypes from 'prop-types'; +import React, {useEffect, useRef} from 'react'; +import {View} from 'react-native'; +import Animated, {Easing, interpolateColor, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; +import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; +import Tooltip from '@components/Tooltip/PopoverAnchorTooltip'; +import useLocalize from '@hooks/useLocalize'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import FabPlusIcon from './FabPlusIcon'; + +const AnimatedPressable = Animated.createAnimatedComponent(PressableWithFeedback); +AnimatedPressable.displayName = 'AnimatedPressable'; + +const propTypes = { + /* Callback to fire on request to toggle the FloatingActionButton */ + onPress: PropTypes.func.isRequired, + + /* Current state (active or not active) of the component */ + isActive: PropTypes.bool.isRequired, + + /* An accessibility label for the button */ + accessibilityLabel: PropTypes.string.isRequired, + + /* An accessibility role for the button */ + role: PropTypes.string.isRequired, +}; + +const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibilityLabel, role}, ref) => { + const {success, buttonDefaultBG} = useTheme(); + const styles = useThemeStyles(); + const borderRadius = styles.floatingActionButton.borderRadius; + const {translate} = useLocalize(); + const fabPressable = useRef(null); + const sharedValue = useSharedValue(isActive ? 1 : 0); + const buttonRef = ref; + + useEffect(() => { + sharedValue.value = withTiming(isActive ? 1 : 0, { + duration: 340, + easing: Easing.inOut(Easing.ease), + }); + }, [isActive, sharedValue]); + + const animatedStyle = useAnimatedStyle(() => { + const backgroundColor = interpolateColor(sharedValue.value, [0, 1], [success, buttonDefaultBG]); + + return { + transform: [{rotate: `${sharedValue.value * 135}deg`}], + backgroundColor, + borderRadius, + }; + }); + + return ( + + + { + fabPressable.current = el; + if (buttonRef) { + buttonRef.current = el; + } + }} + accessibilityLabel={accessibilityLabel} + role={role} + pressDimmingValue={1} + onPress={(e) => { + // Drop focus to avoid blue focus ring. + fabPressable.current.blur(); + onPress(e); + }} + onLongPress={() => {}} + style={[styles.floatingActionButton, animatedStyle]} + > + + + + + ); +}); + +FloatingActionButton.propTypes = propTypes; +FloatingActionButton.displayName = 'FloatingActionButton'; + +export default FloatingActionButton; diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index de87d2b5dd59..6f3d55e5acb0 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -446,13 +446,6 @@ function getBackgroundColorWithOpacityStyle(backgroundColor: string, opacity: nu return {}; } -function getAnimatedFABStyle(rotate: Animated.Value, backgroundColor: Animated.Value): Animated.WithAnimatedValue { - return { - transform: [{rotate}], - backgroundColor, - }; -} - function getWidthAndHeightStyle(width: number, height?: number): ViewStyle { return { width, @@ -1015,7 +1008,6 @@ const staticStyleUtils = { combineStyles, displayIfTrue, getAmountFontSizeAndLineHeight, - getAnimatedFABStyle, getAutoCompleteSuggestionContainerStyle, getAvatarBorderRadius, getAvatarBorderStyle, diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 93bb2cb94d30..f4d054ab15e8 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -31,6 +31,11 @@ jest.setTimeout(30000); jest.mock('../../src/libs/Notification/LocalNotification'); jest.mock('../../src/components/Icon/Expensicons'); +jest.mock('react-native-reanimated', () => ({ + ...jest.requireActual('react-native-reanimated/mock'), + createAnimatedPropAdapter: jest.fn, +})); + beforeAll(() => { // In this test, we are generically mocking the responses of all API requests by mocking fetch() and having it // return 200. In other tests, we might mock HttpUtils.xhr() with a more specific mock data response (which means From 1ca211550fa96799569207938599244172616c94 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:04:26 +0100 Subject: [PATCH 2/7] fix bug: black color of the + icon on web --- src/components/FloatingActionButton/FabPlusIcon.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/FloatingActionButton/FabPlusIcon.js b/src/components/FloatingActionButton/FabPlusIcon.js index 500606522b3b..67e5df5dbe3e 100644 --- a/src/components/FloatingActionButton/FabPlusIcon.js +++ b/src/components/FloatingActionButton/FabPlusIcon.js @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React, {useEffect} from 'react'; +import {Platform} from 'react-native'; import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useSharedValue, withTiming} from 'react-native-reanimated'; import Svg, {Path} from 'react-native-svg'; import useTheme from '@hooks/useTheme'; @@ -51,8 +52,8 @@ function FabPlusIcon({isActive}) { fill, }; }, - [], - adapter, + undefined, + Platform.OS === 'web' ? undefined : adapter, ); return ( From df210d5cde63b96ef292db4039df9cb76a91ebbb Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:38:45 +0100 Subject: [PATCH 3/7] fix bug: the animation of the + icon not working on web --- .../index.js => FloatingActionButton.js} | 52 ++++++++++++- .../FloatingActionButton/FabPlusIcon.js | 75 ------------------- 2 files changed, 48 insertions(+), 79 deletions(-) rename src/components/{FloatingActionButton/index.js => FloatingActionButton.js} (60%) delete mode 100644 src/components/FloatingActionButton/FabPlusIcon.js diff --git a/src/components/FloatingActionButton/index.js b/src/components/FloatingActionButton.js similarity index 60% rename from src/components/FloatingActionButton/index.js rename to src/components/FloatingActionButton.js index 6922c8b1949b..98862d422cd0 100644 --- a/src/components/FloatingActionButton/index.js +++ b/src/components/FloatingActionButton.js @@ -1,17 +1,41 @@ import PropTypes from 'prop-types'; import React, {useEffect, useRef} from 'react'; import {View} from 'react-native'; -import Animated, {Easing, interpolateColor, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; +import {Platform} from 'react-native'; +import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; +import Svg, {Path} from 'react-native-svg'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import Tooltip from '@components/Tooltip/PopoverAnchorTooltip'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import FabPlusIcon from './FabPlusIcon'; +import variables from '@styles/variables'; + +const AnimatedPath = Animated.createAnimatedComponent(Path); const AnimatedPressable = Animated.createAnimatedComponent(PressableWithFeedback); AnimatedPressable.displayName = 'AnimatedPressable'; +const adapter = createAnimatedPropAdapter( + (props) => { + // eslint-disable-next-line rulesdir/prefer-underscore-method + if (Object.keys(props).includes('fill')) { + // eslint-disable-next-line no-param-reassign + props.fill = {type: 0, payload: processColor(props.fill)}; + } + // eslint-disable-next-line rulesdir/prefer-underscore-method + if (Object.keys(props).includes('stroke')) { + // eslint-disable-next-line no-param-reassign + props.stroke = {type: 0, payload: processColor(props.stroke)}; + } + }, + ['fill', 'stroke'], +); +adapter.propTypes = { + fill: PropTypes.string, + stroke: PropTypes.string, +}; + const propTypes = { /* Callback to fire on request to toggle the FloatingActionButton */ onPress: PropTypes.func.isRequired, @@ -27,7 +51,7 @@ const propTypes = { }; const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibilityLabel, role}, ref) => { - const {success, buttonDefaultBG} = useTheme(); + const {success, buttonDefaultBG, textLight, textDark} = useTheme(); const styles = useThemeStyles(); const borderRadius = styles.floatingActionButton.borderRadius; const {translate} = useLocalize(); @@ -52,6 +76,18 @@ const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibility }; }); + const animatedProps = useAnimatedProps( + () => { + const fill = interpolateColor(sharedValue.value, [0, 1], [textLight, textDark]); + + return { + fill, + }; + }, + undefined, + Platform.OS === 'web' ? undefined : adapter, + ); + return ( @@ -73,7 +109,15 @@ const FloatingActionButton = React.forwardRef(({onPress, isActive, accessibility onLongPress={() => {}} style={[styles.floatingActionButton, animatedStyle]} > - + + + diff --git a/src/components/FloatingActionButton/FabPlusIcon.js b/src/components/FloatingActionButton/FabPlusIcon.js deleted file mode 100644 index 67e5df5dbe3e..000000000000 --- a/src/components/FloatingActionButton/FabPlusIcon.js +++ /dev/null @@ -1,75 +0,0 @@ -import PropTypes from 'prop-types'; -import React, {useEffect} from 'react'; -import {Platform} from 'react-native'; -import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useSharedValue, withTiming} from 'react-native-reanimated'; -import Svg, {Path} from 'react-native-svg'; -import useTheme from '@hooks/useTheme'; -import variables from '@styles/variables'; - -const AnimatedPath = Animated.createAnimatedComponent(Path); - -const adapter = createAnimatedPropAdapter( - (props) => { - // eslint-disable-next-line rulesdir/prefer-underscore-method - if (Object.keys(props).includes('fill')) { - // eslint-disable-next-line no-param-reassign - props.fill = {type: 0, payload: processColor(props.fill)}; - } - // eslint-disable-next-line rulesdir/prefer-underscore-method - if (Object.keys(props).includes('stroke')) { - // eslint-disable-next-line no-param-reassign - props.stroke = {type: 0, payload: processColor(props.stroke)}; - } - }, - ['fill', 'stroke'], -); -adapter.propTypes = { - fill: PropTypes.string, - stroke: PropTypes.string, -}; - -const propTypes = { - /* Current state (active or not active) of the component */ - isActive: PropTypes.bool.isRequired, -}; - -function FabPlusIcon({isActive}) { - const {textLight, textDark} = useTheme(); - const sharedValue = useSharedValue(isActive ? 1 : 0); - - useEffect(() => { - sharedValue.value = withTiming(isActive ? 1 : 0, { - duration: 340, - easing: Easing.inOut(Easing.ease), - }); - }, [isActive, sharedValue]); - - const animatedProps = useAnimatedProps( - () => { - const fill = interpolateColor(sharedValue.value, [0, 1], [textLight, textDark]); - - return { - fill, - }; - }, - undefined, - Platform.OS === 'web' ? undefined : adapter, - ); - - return ( - - - - ); -} - -FabPlusIcon.propTypes = propTypes; -FabPlusIcon.displayName = 'FabPlusIcon'; - -export default FabPlusIcon; From 677e29252d34ff85678bed8e243dcc1ebd1c96c3 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:53:04 +0100 Subject: [PATCH 4/7] add displayName to AnimatedPath --- src/components/FloatingActionButton.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js index 98862d422cd0..f52260045336 100644 --- a/src/components/FloatingActionButton.js +++ b/src/components/FloatingActionButton.js @@ -12,6 +12,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; const AnimatedPath = Animated.createAnimatedComponent(Path); +AnimatedPath.displayName = 'AnimatedPath'; const AnimatedPressable = Animated.createAnimatedComponent(PressableWithFeedback); AnimatedPressable.displayName = 'AnimatedPressable'; From 3354e9e840a997816a38db87abbdfd49f8be03c9 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Dec 2023 13:59:03 +0100 Subject: [PATCH 5/7] Migrate Icon/index.tsx to function component --- src/components/Icon/index.tsx | 112 ++++++++++++++++------------------ 1 file changed, 54 insertions(+), 58 deletions(-) diff --git a/src/components/Icon/index.tsx b/src/components/Icon/index.tsx index 59b1639dce33..5f82421c0e8e 100644 --- a/src/components/Icon/index.tsx +++ b/src/components/Icon/index.tsx @@ -1,8 +1,8 @@ -import React, {PureComponent} from 'react'; +import React from 'react'; import {StyleProp, View, ViewStyle} from 'react-native'; -import withStyleUtils, {WithStyleUtilsProps} from '@components/withStyleUtils'; -import withTheme, {WithThemeProps} from '@components/withTheme'; -import withThemeStyles, {type WithThemeStylesProps} from '@components/withThemeStyles'; +import useStyleUtils from '@hooks/useStyleUtils'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import IconWrapperStyles from './IconWrapperStyles'; @@ -41,67 +41,63 @@ type IconProps = { /** Additional styles to add to the Icon */ additionalStyles?: StyleProp; -} & WithThemeStylesProps & - WithThemeProps & - WithStyleUtilsProps; - -// We must use a class component to create an animatable component with the Animated API -// eslint-disable-next-line react/prefer-stateless-function -class Icon extends PureComponent { - // eslint-disable-next-line react/static-property-placement - public static defaultProps = { - width: variables.iconSizeNormal, - height: variables.iconSizeNormal, - fill: undefined, - small: false, - inline: false, - additionalStyles: [], - hovered: false, - pressed: false, - }; - - render() { - const width = this.props.small ? variables.iconSizeSmall : this.props.width; - const height = this.props.small ? variables.iconSizeSmall : this.props.height; - const iconStyles = [this.props.StyleUtils.getWidthAndHeightStyle(width ?? 0, height), IconWrapperStyles, this.props.themeStyles.pAbsolute, this.props.additionalStyles]; - const fill = this.props.fill ?? this.props.theme.icon; - - if (this.props.inline) { - return ( - - - - - - ); - } +}; +function Icon({ + src, + width = variables.iconSizeNormal, + height = variables.iconSizeNormal, + fill = undefined, + small = false, + inline = false, + hovered = false, + pressed = false, + additionalStyles = [], +}: IconProps) { + const theme = useTheme(); + const StyleUtils = useStyleUtils(); + const styles = useThemeStyles(); + const iconWidth = small ? variables.iconSizeSmall : width; + const iconHeight = small ? variables.iconSizeSmall : height; + const iconStyles = [StyleUtils.getWidthAndHeightStyle(width ?? 0, height), IconWrapperStyles, styles.pAbsolute, additionalStyles]; + const iconFill = fill ?? theme.icon; + const IconComponent = src; + + if (inline) { return ( - + + + ); } + + return ( + + + + ); } -export type {SrcProps}; +Icon.displayName = 'Icon'; -export default withTheme(withThemeStyles(withStyleUtils(Icon))); +export default Icon; From 9885e6930c3d9448be9aff4922b7e253ff529130 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:02:27 +0100 Subject: [PATCH 6/7] export type {SrcProps} from Icon component --- src/components/Icon/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Icon/index.tsx b/src/components/Icon/index.tsx index 5f82421c0e8e..932ea17541b9 100644 --- a/src/components/Icon/index.tsx +++ b/src/components/Icon/index.tsx @@ -100,4 +100,6 @@ function Icon({ Icon.displayName = 'Icon'; +export type {SrcProps}; + export default Icon; From 6b6634d6e5acda5669c679b018e946b979ab20f5 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:05:58 +0100 Subject: [PATCH 7/7] fix lint errors --- src/components/FloatingActionButton.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js index f52260045336..59e741001063 100644 --- a/src/components/FloatingActionButton.js +++ b/src/components/FloatingActionButton.js @@ -1,15 +1,14 @@ import PropTypes from 'prop-types'; import React, {useEffect, useRef} from 'react'; -import {View} from 'react-native'; -import {Platform} from 'react-native'; +import {Platform, View} from 'react-native'; import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated'; import Svg, {Path} from 'react-native-svg'; -import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; -import Tooltip from '@components/Tooltip/PopoverAnchorTooltip'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; +import PressableWithFeedback from './Pressable/PressableWithFeedback'; +import Tooltip from './Tooltip/PopoverAnchorTooltip'; const AnimatedPath = Animated.createAnimatedComponent(Path); AnimatedPath.displayName = 'AnimatedPath';