Skip to content

Commit 7a331b6

Browse files
committed
Adds dynamic theming support
1 parent 0a37f7f commit 7a331b6

File tree

4 files changed

+214
-144
lines changed

4 files changed

+214
-144
lines changed

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import * as React from 'react';
2-
import { Image, Text, TouchableOpacity } from 'react-native';
2+
import type { NativeEventSubscription} from 'react-native';
3+
import { Appearance, Image, Text, TouchableOpacity } from 'react-native';
34

45
import { defaultButtonConfiguration } from './defaults';
56
import { defaultButtonStyles } from './FeedbackWidget.styles';
7+
import { getTheme } from './FeedbackWidget.theme';
68
import type { FeedbackButtonProps, FeedbackButtonStyles, FeedbackButtonTextConfiguration } from './FeedbackWidget.types';
79
import { feedbackIcon } from './icons';
810
import { lazyLoadFeedbackIntegration } from './lazy';
@@ -18,20 +20,41 @@ const showFeedbackWidget = (): void => {
1820
* Implements a feedback button that opens the FeedbackForm.
1921
*/
2022
export class FeedbackButton extends React.Component<FeedbackButtonProps> {
23+
private _themeListener: NativeEventSubscription;
24+
2125
public constructor(props: FeedbackButtonProps) {
2226
super(props);
2327
lazyLoadFeedbackIntegration();
2428
}
2529

30+
/**
31+
* Adds a listener for theme changes.
32+
*/
33+
public componentDidMount(): void {
34+
this._themeListener = Appearance.addChangeListener(() => {
35+
this.forceUpdate();
36+
});
37+
}
38+
39+
/**
40+
* Removes the theme listener.
41+
*/
42+
public componentWillUnmount(): void {
43+
if (this._themeListener) {
44+
this._themeListener.remove();
45+
}
46+
}
47+
2648
/**
2749
* Renders the feedback button.
2850
*/
2951
public render(): React.ReactNode {
52+
const theme = getTheme();
3053
const text: FeedbackButtonTextConfiguration = { ...defaultButtonConfiguration, ...this.props };
3154
const styles: FeedbackButtonStyles = {
32-
triggerButton: { ...defaultButtonStyles.triggerButton, ...this.props.styles?.triggerButton },
33-
triggerText: { ...defaultButtonStyles.triggerText, ...this.props.styles?.triggerText },
34-
triggerIcon: { ...defaultButtonStyles.triggerIcon, ...this.props.styles?.triggerIcon },
55+
triggerButton: { ...defaultButtonStyles(theme).triggerButton, ...this.props.styles?.triggerButton },
56+
triggerText: { ...defaultButtonStyles(theme).triggerText, ...this.props.styles?.triggerText },
57+
triggerIcon: { ...defaultButtonStyles(theme).triggerIcon, ...this.props.styles?.triggerIcon },
3558
};
3659

3760
return (

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

Lines changed: 140 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,135 @@
11
import type { ViewStyle } from 'react-native';
22

3-
import { getTheme } from './FeedbackWidget.theme';
3+
import type { FeedbackWidgetTheme } from './FeedbackWidget.theme';
44
import type { FeedbackButtonStyles, FeedbackWidgetStyles } from './FeedbackWidget.types';
55

6-
const defaultStyles: FeedbackWidgetStyles = {
7-
container: {
8-
flex: 1,
9-
padding: 20,
10-
backgroundColor: getTheme().background,
11-
},
12-
title: {
13-
fontSize: 24,
14-
fontWeight: 'bold',
15-
marginBottom: 20,
16-
textAlign: 'left',
17-
flex: 1,
18-
color: getTheme().foreground,
19-
},
20-
label: {
21-
marginBottom: 4,
22-
fontSize: 16,
23-
color: getTheme().foreground,
24-
},
25-
input: {
26-
height: 50,
27-
borderColor: getTheme().border,
28-
borderWidth: 1,
29-
borderRadius: 5,
30-
paddingHorizontal: 10,
31-
marginBottom: 15,
32-
fontSize: 16,
33-
color: getTheme().foreground,
34-
},
35-
textArea: {
36-
height: 100,
37-
textAlignVertical: 'top',
38-
color: getTheme().foreground,
39-
},
40-
screenshotButton: {
41-
backgroundColor: getTheme().background,
42-
padding: 15,
43-
borderRadius: 5,
44-
alignItems: 'center',
45-
flex: 1,
46-
borderWidth: 1,
47-
borderColor: getTheme().border,
48-
},
49-
screenshotContainer: {
50-
flexDirection: 'row',
51-
alignItems: 'center',
52-
width: '100%',
53-
marginBottom: 20,
54-
},
55-
screenshotThumbnail: {
56-
width: 50,
57-
height: 50,
58-
borderRadius: 5,
59-
marginRight: 10,
60-
},
61-
screenshotText: {
62-
color: getTheme().foreground,
63-
fontSize: 16,
64-
},
65-
submitButton: {
66-
backgroundColor: getTheme().accentBackground,
67-
paddingVertical: 15,
68-
borderRadius: 5,
69-
alignItems: 'center',
70-
marginBottom: 10,
71-
},
72-
submitText: {
73-
color: getTheme().accentForeground,
74-
fontSize: 18,
75-
},
76-
cancelButton: {
77-
backgroundColor: getTheme().background,
78-
padding: 15,
79-
borderRadius: 5,
80-
alignItems: 'center',
81-
borderWidth: 1,
82-
borderColor: getTheme().border,
83-
},
84-
cancelText: {
85-
color: getTheme().foreground,
86-
fontSize: 16,
87-
},
88-
titleContainer: {
89-
flexDirection: 'row',
90-
width: '100%',
91-
},
92-
sentryLogo: {
93-
width: 40,
94-
height: 40,
95-
tintColor: getTheme().sentryLogo,
96-
},
6+
const defaultStyles = (theme: FeedbackWidgetTheme): FeedbackWidgetStyles => {
7+
return {
8+
container: {
9+
flex: 1,
10+
padding: 20,
11+
backgroundColor: theme.background,
12+
},
13+
title: {
14+
fontSize: 24,
15+
fontWeight: 'bold',
16+
marginBottom: 20,
17+
textAlign: 'left',
18+
flex: 1,
19+
color: theme.foreground,
20+
},
21+
label: {
22+
marginBottom: 4,
23+
fontSize: 16,
24+
color: theme.foreground,
25+
},
26+
input: {
27+
height: 50,
28+
borderColor: theme.border,
29+
borderWidth: 1,
30+
borderRadius: 5,
31+
paddingHorizontal: 10,
32+
marginBottom: 15,
33+
fontSize: 16,
34+
color: theme.foreground,
35+
},
36+
textArea: {
37+
height: 100,
38+
textAlignVertical: 'top',
39+
color: theme.foreground,
40+
},
41+
screenshotButton: {
42+
backgroundColor: theme.background,
43+
padding: 15,
44+
borderRadius: 5,
45+
alignItems: 'center',
46+
flex: 1,
47+
borderWidth: 1,
48+
borderColor: theme.border,
49+
},
50+
screenshotContainer: {
51+
flexDirection: 'row',
52+
alignItems: 'center',
53+
width: '100%',
54+
marginBottom: 20,
55+
},
56+
screenshotThumbnail: {
57+
width: 50,
58+
height: 50,
59+
borderRadius: 5,
60+
marginRight: 10,
61+
},
62+
screenshotText: {
63+
color: theme.foreground,
64+
fontSize: 16,
65+
},
66+
submitButton: {
67+
backgroundColor: theme.accentBackground,
68+
paddingVertical: 15,
69+
borderRadius: 5,
70+
alignItems: 'center',
71+
marginBottom: 10,
72+
},
73+
submitText: {
74+
color: theme.accentForeground,
75+
fontSize: 18,
76+
},
77+
cancelButton: {
78+
backgroundColor: theme.background,
79+
padding: 15,
80+
borderRadius: 5,
81+
alignItems: 'center',
82+
borderWidth: 1,
83+
borderColor: theme.border,
84+
},
85+
cancelText: {
86+
color: theme.foreground,
87+
fontSize: 16,
88+
},
89+
titleContainer: {
90+
flexDirection: 'row',
91+
width: '100%',
92+
},
93+
sentryLogo: {
94+
width: 40,
95+
height: 40,
96+
tintColor: theme.sentryLogo,
97+
},
98+
};
9799
};
98100

99-
export const defaultButtonStyles: FeedbackButtonStyles = {
100-
triggerButton: {
101-
position: 'absolute',
102-
bottom: 30,
103-
right: 30,
104-
backgroundColor: getTheme().background,
105-
padding: 15,
106-
borderRadius: 40,
107-
justifyContent: 'center',
108-
alignItems: 'center',
109-
elevation: 5,
110-
shadowColor: getTheme().border,
111-
shadowOffset: { width: 1, height: 2 },
112-
shadowOpacity: 0.5,
113-
shadowRadius: 3,
114-
flexDirection: 'row',
115-
borderWidth: 1,
116-
borderColor: getTheme().border,
117-
},
118-
triggerText: {
119-
color: getTheme().foreground,
120-
fontSize: 18,
121-
},
122-
triggerIcon: {
123-
width: 24,
124-
height: 24,
125-
padding: 2,
126-
marginEnd: 6,
127-
tintColor: getTheme().sentryLogo,
128-
},
101+
export const defaultButtonStyles = (theme: FeedbackWidgetTheme): FeedbackButtonStyles => {
102+
return {
103+
triggerButton: {
104+
position: 'absolute',
105+
bottom: 30,
106+
right: 30,
107+
backgroundColor: theme.background,
108+
padding: 15,
109+
borderRadius: 40,
110+
justifyContent: 'center',
111+
alignItems: 'center',
112+
elevation: 5,
113+
shadowColor: theme.border,
114+
shadowOffset: { width: 1, height: 2 },
115+
shadowOpacity: 0.5,
116+
shadowRadius: 3,
117+
flexDirection: 'row',
118+
borderWidth: 1,
119+
borderColor: theme.border,
120+
},
121+
triggerText: {
122+
color: theme.foreground,
123+
fontSize: 18,
124+
},
125+
triggerIcon: {
126+
width: 24,
127+
height: 24,
128+
padding: 2,
129+
marginEnd: 6,
130+
tintColor: theme.sentryLogo,
131+
},
132+
};
129133
};
130134

131135
export const modalWrapper: ViewStyle = {
@@ -136,18 +140,20 @@ export const modalWrapper: ViewStyle = {
136140
bottom: 0,
137141
};
138142

139-
export const modalSheetContainer: ViewStyle = {
140-
backgroundColor: getTheme().background,
141-
borderTopLeftRadius: 16,
142-
borderTopRightRadius: 16,
143-
overflow: 'hidden',
144-
alignSelf: 'stretch',
145-
shadowColor: '#000',
146-
shadowOffset: { width: 0, height: -3 },
147-
shadowOpacity: 0.1,
148-
shadowRadius: 4,
149-
elevation: 5,
150-
flex: 1,
143+
export const modalSheetContainer = (theme: FeedbackWidgetTheme): ViewStyle => {
144+
return {
145+
backgroundColor: theme.background,
146+
borderTopLeftRadius: 16,
147+
borderTopRightRadius: 16,
148+
overflow: 'hidden',
149+
alignSelf: 'stretch',
150+
shadowColor: '#000',
151+
shadowOffset: { width: 0, height: -3 },
152+
shadowOpacity: 0.1,
153+
shadowRadius: 4,
154+
elevation: 5,
155+
flex: 1,
156+
};
151157
};
152158

153159
export const topSpacer: ViewStyle = {

0 commit comments

Comments
 (0)