Skip to content

Commit 7ec9441

Browse files
authored
Feedback modal UI tweaks (#4492)
1 parent 07b3f54 commit 7ec9441

File tree

5 files changed

+96
-26
lines changed

5 files changed

+96
-26
lines changed

packages/core/src/js/feedback/FeedbackForm.styles.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { ViewStyle } from 'react-native';
2+
13
import type { FeedbackFormStyles } from './FeedbackForm.types';
24

35
const PURPLE = 'rgba(88, 74, 192, 1)';
@@ -77,10 +79,33 @@ const defaultStyles: FeedbackFormStyles = {
7779
width: 40,
7880
height: 40,
7981
},
80-
modalBackground: {
81-
flex: 1,
82-
justifyContent: 'center',
83-
},
82+
};
83+
84+
export const modalWrapper: ViewStyle = {
85+
position: 'absolute',
86+
top: 0,
87+
left: 0,
88+
right: 0,
89+
bottom: 0,
90+
};
91+
92+
export const modalBackground: ViewStyle = {
93+
flex: 1,
94+
justifyContent: 'flex-end',
95+
};
96+
97+
export const modalSheetContainer: ViewStyle = {
98+
backgroundColor: '#ffffff',
99+
borderTopLeftRadius: 16,
100+
borderTopRightRadius: 16,
101+
overflow: 'hidden',
102+
alignSelf: 'stretch',
103+
height: '92%',
104+
shadowColor: '#000',
105+
shadowOffset: { width: 0, height: -3 },
106+
shadowOpacity: 0.1,
107+
shadowRadius: 4,
108+
elevation: 5,
84109
};
85110

86111
export default defaultStyles;

packages/core/src/js/feedback/FeedbackForm.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Image,
88
Keyboard,
99
KeyboardAvoidingView,
10+
Platform,
1011
SafeAreaView,
1112
ScrollView,
1213
Text,
@@ -130,8 +131,11 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor
130131

131132
return (
132133
<SafeAreaView style={[styles.container, { padding: 0 }]}>
133-
<KeyboardAvoidingView behavior={'padding'} style={[styles.container, { padding: 0 }]}>
134-
<ScrollView>
134+
<KeyboardAvoidingView
135+
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
136+
style={[styles.container, { padding: 0 }]}
137+
>
138+
<ScrollView bounces={false}>
135139
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
136140
<View style={styles.container}>
137141
<View style={styles.titleContainer}>

packages/core/src/js/feedback/FeedbackForm.types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,6 @@ export interface FeedbackFormStyles {
204204
screenshotText?: TextStyle;
205205
titleContainer?: ViewStyle;
206206
sentryLogo?: ImageStyle;
207-
modalBackground?: ViewStyle;
208207
}
209208

210209
/**

packages/core/src/js/feedback/FeedbackFormManager.tsx

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { logger } from '@sentry/core';
22
import * as React from 'react';
3-
import { Modal, View } from 'react-native';
3+
import { Animated, KeyboardAvoidingView, Modal, Platform, View } from 'react-native';
44

55
import { FeedbackForm } from './FeedbackForm';
6-
import defaultStyles from './FeedbackForm.styles';
6+
import { modalBackground, modalSheetContainer, modalWrapper } from './FeedbackForm.styles';
77
import type { FeedbackFormStyles } from './FeedbackForm.types';
88
import { getFeedbackOptions } from './integration';
99
import { isModalSupported } from './utils';
@@ -40,16 +40,37 @@ interface FeedbackFormProviderProps {
4040
styles?: FeedbackFormStyles;
4141
}
4242

43+
interface FeedbackFormProviderState {
44+
isVisible: boolean;
45+
backgroundOpacity: Animated.Value;
46+
}
47+
4348
class FeedbackFormProvider extends React.Component<FeedbackFormProviderProps> {
44-
public state = {
49+
public state: FeedbackFormProviderState = {
4550
isVisible: false,
51+
backgroundOpacity: new Animated.Value(0),
4652
};
4753

4854
public constructor(props: FeedbackFormProviderProps) {
4955
super(props);
5056
FeedbackFormManager.initialize(this._setVisibilityFunction);
5157
}
5258

59+
/**
60+
* Animates the background opacity when the modal is shown.
61+
*/
62+
public componentDidUpdate(_prevProps: any, prevState: FeedbackFormProviderState): void {
63+
if (!prevState.isVisible && this.state.isVisible) {
64+
Animated.timing(this.state.backgroundOpacity, {
65+
toValue: 1,
66+
duration: 300,
67+
useNativeDriver: true,
68+
}).start();
69+
} else if (prevState.isVisible && !this.state.isVisible) {
70+
this.state.backgroundOpacity.setValue(0);
71+
}
72+
}
73+
5374
/**
5475
* Renders the feedback form modal.
5576
*/
@@ -59,25 +80,34 @@ class FeedbackFormProvider extends React.Component<FeedbackFormProviderProps> {
5980
return <>{this.props.children}</>;
6081
}
6182

62-
const { isVisible } = this.state;
63-
const styles: FeedbackFormStyles = { ...defaultStyles, ...this.props.styles };
83+
const { isVisible, backgroundOpacity } = this.state;
84+
85+
const backgroundColor = backgroundOpacity.interpolate({
86+
inputRange: [0, 1],
87+
outputRange: ['rgba(0, 0, 0, 0)', 'rgba(0, 0, 0, 0.9)'],
88+
});
6489

6590
// Wrapping the `Modal` component in a `View` component is necessary to avoid
6691
// issues like https://github.com/software-mansion/react-native-reanimated/issues/6035
6792
return (
6893
<>
6994
{this.props.children}
7095
{isVisible && (
71-
<View>
96+
<Animated.View style={[modalWrapper, { backgroundColor }]} >
7297
<Modal visible={isVisible} transparent animationType="slide" onRequestClose={this._handleClose} testID="feedback-form-modal">
73-
<View style={styles.modalBackground}>
74-
<FeedbackForm {...getFeedbackOptions()}
75-
onFormClose={this._handleClose}
76-
onFormSubmitted={this._handleClose}
77-
/>
78-
</View>
98+
<KeyboardAvoidingView
99+
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
100+
style={modalBackground}
101+
>
102+
<View style={modalSheetContainer}>
103+
<FeedbackForm {...getFeedbackOptions()}
104+
onFormClose={this._handleClose}
105+
onFormSubmitted={this._handleClose}
106+
/>
107+
</View>
108+
</KeyboardAvoidingView>
79109
</Modal>
80-
</View>
110+
</Animated.View>
81111
)}
82112
</>
83113
);

packages/core/test/feedback/__snapshots__/FeedbackForm.test.tsx.snap

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ exports[`FeedbackForm matches the snapshot with custom styles 1`] = `
3131
]
3232
}
3333
>
34-
<RCTScrollView>
34+
<RCTScrollView
35+
bounces={false}
36+
>
3537
<View>
3638
<View
3739
accessibilityState={
@@ -299,7 +301,9 @@ exports[`FeedbackForm matches the snapshot with custom styles and screenshot but
299301
]
300302
}
301303
>
302-
<RCTScrollView>
304+
<RCTScrollView
305+
bounces={false}
306+
>
303307
<View>
304308
<View
305309
accessibilityState={
@@ -617,7 +621,9 @@ exports[`FeedbackForm matches the snapshot with custom texts 1`] = `
617621
]
618622
}
619623
>
620-
<RCTScrollView>
624+
<RCTScrollView
625+
bounces={false}
626+
>
621627
<View>
622628
<View
623629
accessibilityState={
@@ -916,7 +922,9 @@ exports[`FeedbackForm matches the snapshot with custom texts and screenshot butt
916922
]
917923
}
918924
>
919-
<RCTScrollView>
925+
<RCTScrollView
926+
bounces={false}
927+
>
920928
<View>
921929
<View
922930
accessibilityState={
@@ -1265,7 +1273,9 @@ exports[`FeedbackForm matches the snapshot with default configuration 1`] = `
12651273
]
12661274
}
12671275
>
1268-
<RCTScrollView>
1276+
<RCTScrollView
1277+
bounces={false}
1278+
>
12691279
<View>
12701280
<View
12711281
accessibilityState={
@@ -1564,7 +1574,9 @@ exports[`FeedbackForm matches the snapshot with default configuration and screen
15641574
]
15651575
}
15661576
>
1567-
<RCTScrollView>
1577+
<RCTScrollView
1578+
bounces={false}
1579+
>
15681580
<View>
15691581
<View
15701582
accessibilityState={

0 commit comments

Comments
 (0)