diff --git a/packages/core/src/js/feedback/FeedbackWidget.styles.ts b/packages/core/src/js/feedback/FeedbackWidget.styles.ts index f7adc5f214..2144b51dfa 100644 --- a/packages/core/src/js/feedback/FeedbackWidget.styles.ts +++ b/packages/core/src/js/feedback/FeedbackWidget.styles.ts @@ -3,15 +3,15 @@ import type { ViewStyle } from 'react-native'; import type { FeedbackWidgetStyles } from './FeedbackWidget.types'; const PURPLE = 'rgba(88, 74, 192, 1)'; -const FORGROUND_COLOR = '#2b2233'; -const BACKROUND_COLOR = '#ffffff'; +const FOREGROUND_COLOR = '#2b2233'; +const BACKGROUND_COLOR = '#ffffff'; const BORDER_COLOR = 'rgba(41, 35, 47, 0.13)'; const defaultStyles: FeedbackWidgetStyles = { container: { flex: 1, padding: 20, - backgroundColor: BACKROUND_COLOR, + backgroundColor: BACKGROUND_COLOR, }, title: { fontSize: 24, @@ -19,12 +19,12 @@ const defaultStyles: FeedbackWidgetStyles = { marginBottom: 20, textAlign: 'left', flex: 1, - color: FORGROUND_COLOR, + color: FOREGROUND_COLOR, }, label: { marginBottom: 4, fontSize: 16, - color: FORGROUND_COLOR, + color: FOREGROUND_COLOR, }, input: { height: 50, @@ -34,12 +34,12 @@ const defaultStyles: FeedbackWidgetStyles = { paddingHorizontal: 10, marginBottom: 15, fontSize: 16, - color: FORGROUND_COLOR, + color: FOREGROUND_COLOR, }, textArea: { height: 100, textAlignVertical: 'top', - color: FORGROUND_COLOR, + color: FOREGROUND_COLOR, }, screenshotButton: { backgroundColor: '#eee', @@ -72,7 +72,7 @@ const defaultStyles: FeedbackWidgetStyles = { marginBottom: 10, }, submitText: { - color: BACKROUND_COLOR, + color: BACKGROUND_COLOR, fontSize: 18, }, cancelButton: { @@ -80,7 +80,7 @@ const defaultStyles: FeedbackWidgetStyles = { alignItems: 'center', }, cancelText: { - color: FORGROUND_COLOR, + color: FOREGROUND_COLOR, fontSize: 16, }, titleContainer: { @@ -101,23 +101,22 @@ export const modalWrapper: ViewStyle = { bottom: 0, }; -export const modalBackground: ViewStyle = { - flex: 1, - justifyContent: 'flex-end', -}; - export const modalSheetContainer: ViewStyle = { backgroundColor: '#ffffff', borderTopLeftRadius: 16, borderTopRightRadius: 16, overflow: 'hidden', alignSelf: 'stretch', - height: '92%', shadowColor: '#000', shadowOffset: { width: 0, height: -3 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 5, + flex: 1, +}; + +export const topSpacer: ViewStyle = { + height: 64, // magic number }; export default defaultStyles; diff --git a/packages/core/src/js/feedback/FeedbackWidget.tsx b/packages/core/src/js/feedback/FeedbackWidget.tsx index bb6931e759..2d81a9e7e6 100644 --- a/packages/core/src/js/feedback/FeedbackWidget.tsx +++ b/packages/core/src/js/feedback/FeedbackWidget.tsx @@ -5,10 +5,6 @@ import type { KeyboardTypeOptions } from 'react-native'; import { Image, Keyboard, - KeyboardAvoidingView, - Platform, - SafeAreaView, - ScrollView, Text, TextInput, TouchableOpacity, @@ -222,97 +218,87 @@ export class FeedbackWidget extends React.Component - - - - - - {text.formTitle} - {config.showBranding && ( - - )} - + + + + {text.formTitle} + {config.showBranding && ( + + )} + - {config.showName && ( - <> - - {text.nameLabel} - {config.isNameRequired && ` ${text.isRequiredLabel}`} - - this.setState({ name: value })} - /> - - )} + {config.showName && ( + <> + + {text.nameLabel} + {config.isNameRequired && ` ${text.isRequiredLabel}`} + + this.setState({ name: value })} + /> + + )} - {config.showEmail && ( - <> - - {text.emailLabel} - {config.isEmailRequired && ` ${text.isRequiredLabel}`} - - this.setState({ email: value })} - /> - - )} + {config.showEmail && ( + <> + + {text.emailLabel} + {config.isEmailRequired && ` ${text.isRequiredLabel}`} + + this.setState({ email: value })} + /> + + )} - - {text.messageLabel} - {` ${text.isRequiredLabel}`} - - this.setState({ description: value })} - multiline - /> - {(config.enableScreenshot || imagePickerConfiguration.imagePicker) && ( - - {this.state.attachmentUri && ( - - )} - - - {!this.state.filename && !this.state.attachment - ? text.addScreenshotButtonLabel - : text.removeScreenshotButtonLabel} - - - + + {text.messageLabel} + {` ${text.isRequiredLabel}`} + + this.setState({ description: value })} + multiline + /> + {(config.enableScreenshot || imagePickerConfiguration.imagePicker) && ( + + {this.state.attachmentUri && ( + )} - - {text.submitButtonLabel} - - - - {text.cancelButtonLabel} + + + {!this.state.filename && !this.state.attachment + ? text.addScreenshotButtonLabel + : text.removeScreenshotButtonLabel} + - - - - + )} + + {text.submitButtonLabel} + + + + {text.cancelButtonLabel} + + + ); } diff --git a/packages/core/src/js/feedback/FeedbackWidgetManager.tsx b/packages/core/src/js/feedback/FeedbackWidgetManager.tsx index 48439a07f1..d10c356794 100644 --- a/packages/core/src/js/feedback/FeedbackWidgetManager.tsx +++ b/packages/core/src/js/feedback/FeedbackWidgetManager.tsx @@ -1,16 +1,16 @@ import { logger } from '@sentry/core'; import * as React from 'react'; -import { Animated, Dimensions, Easing, KeyboardAvoidingView, Modal, PanResponder, Platform } from 'react-native'; +import type { NativeScrollEvent, NativeSyntheticEvent} from 'react-native'; +import { Animated, Dimensions, Easing, Modal, PanResponder, Platform, ScrollView, View } from 'react-native'; import { notWeb } from '../utils/environment'; import { FeedbackWidget } from './FeedbackWidget'; -import { modalBackground, modalSheetContainer, modalWrapper } from './FeedbackWidget.styles'; +import { modalSheetContainer, modalWrapper, topSpacer } from './FeedbackWidget.styles'; import type { FeedbackWidgetStyles } from './FeedbackWidget.types'; import { getFeedbackOptions } from './integration'; import { isModalSupported } from './utils'; -const PULL_DOWN_CLOSE_THREESHOLD = 200; -const PULL_DOWN_ANDROID_ACTIVATION_HEIGHT = 150; +const PULL_DOWN_CLOSE_THRESHOLD = 200; const SLIDE_ANIMATION_DURATION = 200; const BACKGROUND_ANIMATION_DURATION = 200; @@ -50,6 +50,7 @@ interface FeedbackWidgetProviderState { isVisible: boolean; backgroundOpacity: Animated.Value; panY: Animated.Value; + isScrollAtTop: boolean; } class FeedbackWidgetProvider extends React.Component { @@ -57,15 +58,15 @@ class FeedbackWidgetProvider extends React.Component { - // On Android allow pulling down only from the top to avoid breaking native gestures - return notWeb() && (Platform.OS !== 'android' || evt.nativeEvent.pageY < PULL_DOWN_ANDROID_ACTIVATION_HEIGHT); + onStartShouldSetPanResponder: (_, gestureState) => { + return notWeb() && this.state.isScrollAtTop && gestureState.dy > 0; }, - onMoveShouldSetPanResponder: (evt, _gestureState) => { - return notWeb() && (Platform.OS !== 'android' || evt.nativeEvent.pageY < PULL_DOWN_ANDROID_ACTIVATION_HEIGHT); + onMoveShouldSetPanResponder: (_, gestureState) => { + return notWeb() && this.state.isScrollAtTop && gestureState.dy > 0; }, onPanResponderMove: (_, gestureState) => { if (gestureState.dy > 0) { @@ -73,7 +74,8 @@ class FeedbackWidgetProvider extends React.Component { - if (gestureState.dy > PULL_DOWN_CLOSE_THREESHOLD) { // Close on swipe below a certain threshold + if (gestureState.dy > PULL_DOWN_CLOSE_THRESHOLD) { + // Close on swipe below a certain threshold Animated.timing(this.state.panY, { toValue: Dimensions.get('screen').height, duration: SLIDE_ANIMATION_DURATION, @@ -81,7 +83,8 @@ class FeedbackWidgetProvider extends React.Component { this._handleClose(); }); - } else { // Animate it back to the original position + } else { + // Animate it back to the original position Animated.spring(this.state.panY, { toValue: 0, useNativeDriver: true, @@ -142,31 +145,35 @@ class FeedbackWidgetProvider extends React.Component {this.props.children} - {isVisible && ( + {isVisible && - - + + + - - + /> + + - )} + } ); } + private _handleScroll = (event: NativeSyntheticEvent): void => { + this.setState({ isScrollAtTop: event.nativeEvent.contentOffset.y <= 0 }); + }; + private _setVisibilityFunction = (visible: boolean): void => { const updateState = (): void => { this.setState({ isVisible: visible }); diff --git a/packages/core/test/feedback/__snapshots__/FeedbackWidget.test.tsx.snap b/packages/core/test/feedback/__snapshots__/FeedbackWidget.test.tsx.snap index 902c5a0d2f..937410c22d 100644 --- a/packages/core/test/feedback/__snapshots__/FeedbackWidget.test.tsx.snap +++ b/packages/core/test/feedback/__snapshots__/FeedbackWidget.test.tsx.snap @@ -1,1924 +1,1680 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`FeedbackWidget matches the snapshot with custom styles 1`] = ` - + + Report a Bug + + + + + Name + + + + Email + + + + Description + (required) + + + - - - - - - Report a Bug - - - - - Name - - - - Email - - - - Description - (required) - - - - - Send Bug Report - - - - - Cancel - - - - - + Send Bug Report + + + + + Cancel + - + `; exports[`FeedbackWidget matches the snapshot with custom styles and screenshot button 1`] = ` - + + Report a Bug + + + + + Name + + + + Email + + + + Description + (required) + + + - - - - - - Report a Bug - - - - - Name - - - - Email - - - - Description - (required) - - - - - - Add a screenshot - - - - - - Send Bug Report - - - - - Cancel - - - - - + } + > + Add a screenshot + + + + + + Send Bug Report + + + + + Cancel + - + `; exports[`FeedbackWidget matches the snapshot with custom texts 1`] = ` - + + Feedback Form + + + + + Name Label + + + + Email Label + + + + Message Label + (is required label) + + + - - - - - - Feedback Form - - - - - Name Label - - - - Email Label - - - - Message Label - (is required label) - - - - - Submit Button Label - - - - - Cancel Button Label - - - - - + Submit Button Label + + + + + Cancel Button Label + - + `; exports[`FeedbackWidget matches the snapshot with custom texts and screenshot button 1`] = ` - + + Feedback Form + + + + + Name Label + + + + Email Label + + + + Message Label + (is required label) + + + - - - - - - Feedback Form - - - - - Name Label - - - - Email Label - - - - Message Label - (is required label) - - - - - - Add Screenshot - - - - - - Submit Button Label - - - - - Cancel Button Label - - - - - + } + > + Add Screenshot + + + + + + Submit Button Label + + + + + Cancel Button Label + - + `; exports[`FeedbackWidget matches the snapshot with default configuration 1`] = ` - + + Report a Bug + + + + + Name + + + + Email + + + + Description + (required) + + + - - - - - - Report a Bug - - - - - Name - - - - Email - - - - Description - (required) - - - - - Send Bug Report - - - - - Cancel - - - - - + Send Bug Report + + + + + Cancel + - + `; exports[`FeedbackWidget matches the snapshot with default configuration and screenshot button 1`] = ` - + + Report a Bug + + + + + Name + + + + Email + + + + Description + (required) + + + - - - - - - Report a Bug - - - - - Name - - - - Email - - - - Description - (required) - - - - - - Add a screenshot - - - - - - Send Bug Report - - - - - Cancel - - - - - + } + > + Add a screenshot + + + + + + Send Bug Report + + + + + Cancel + - + `;