Skip to content

Commit b935bbe

Browse files
feat: replace colors from theme with semantics (#3494)
This pull request refactors several UI components to improve theme consistency and maintainability. The main change is replacing inline style definitions and direct color references with a `useStyles` hook that leverages theme primitives and semantic values. This ensures a more consistent look and feel across the app and simplifies style management. **Theme and Style Refactoring** * Replaced inline `StyleSheet.create` style definitions and direct color references with a `useStyles` hook in multiple components (`AITypingIndicatorView.tsx`, `AutoCompleteSuggestionHeader.tsx`, `AutoCompleteSuggestionItem.tsx`, `Channel.tsx`, `ChannelListHeaderErrorIndicator.tsx`, `ChannelListHeaderNetworkDownIndicator.tsx`, and `ChannelListMessenger.tsx`). The new hook uses theme primitives and semantic values for colors, typography, and spacing, improving consistency and maintainability. [[1]](diffhunk://#diff-aeaea0f9815187563af3206aaa50ba5c56b6b7451dda0ef5a076d6c22b42c206L27-R63) [[2]](diffhunk://#diff-14f7c5e1822d3e2c5cb9ccbc7640ee23f22c04a46ee68c503fe5f0524d421ed4R25) [[3]](diffhunk://#diff-a4f2ceb110b81b30f42c543fc864dc3ffee1cedcd45eb92c434292d3fc82752dL220-R221) [[4]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R2168-R2188) [[5]](diffhunk://#diff-000521785a651a6155bc977e73c05c1a65215f80f66ab8101e5a8aa1b60b3c19R27-R55) [[6]](diffhunk://#diff-10acc569ea31efee66b73f4ded73d9c969dc185ba4583013a253ca40191dbdc1L1-R49) [[7]](diffhunk://#diff-3e4a3e88d671a515eb1ccb29c38764f56daa521f3baa28f1dd0a6fc01e790c1fR36) * Removed direct usage of color variables (e.g., `black`, `grey_dark`, `white`) in favor of semantic theme values throughout the affected components. [[1]](diffhunk://#diff-a4f2ceb110b81b30f42c543fc864dc3ffee1cedcd45eb92c434292d3fc82752dL38-R37) [[2]](diffhunk://#diff-a4f2ceb110b81b30f42c543fc864dc3ffee1cedcd45eb92c434292d3fc82752dL50) [[3]](diffhunk://#diff-a4f2ceb110b81b30f42c543fc864dc3ffee1cedcd45eb92c434292d3fc82752dL62-R63) [[4]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85L2083-R2075) [[5]](diffhunk://#diff-000521785a651a6155bc977e73c05c1a65215f80f66ab8101e5a8aa1b60b3c19R27-R55) [[6]](diffhunk://#diff-10acc569ea31efee66b73f4ded73d9c969dc185ba4583013a253ca40191dbdc1L1-R49) **Component-Specific Improvements** * Updated `AITypingIndicatorView`, `AutoCompleteSuggestionHeader`, and `AutoCompleteSuggestionItem` to use theme-based spacing, font sizes, font weights, and line heights, ensuring visual consistency. [[1]](diffhunk://#diff-aeaea0f9815187563af3206aaa50ba5c56b6b7451dda0ef5a076d6c22b42c206L27-R63) [[2]](diffhunk://#diff-14f7c5e1822d3e2c5cb9ccbc7640ee23f22c04a46ee68c503fe5f0524d421ed4R123-R127) [[3]](diffhunk://#diff-a4f2ceb110b81b30f42c543fc864dc3ffee1cedcd45eb92c434292d3fc82752dL220-R221) * Improved error and network status indicators (`ChannelListHeaderErrorIndicator.tsx`, `ChannelListHeaderNetworkDownIndicator.tsx`) with semantic background and text colors, and theme-based padding and font styles. [[1]](diffhunk://#diff-000521785a651a6155bc977e73c05c1a65215f80f66ab8101e5a8aa1b60b3c19R27-R55) [[2]](diffhunk://#diff-10acc569ea31efee66b73f4ded73d9c969dc185ba4583013a253ca40191dbdc1L1-R49) * Updated `Channel.tsx` and `ChannelListMessenger.tsx` to use theme primitives for typography and spacing, and moved style logic into the `useStyles` hook. [[1]](diffhunk://#diff-f7139f4cdb523365cfc277d72b827a3432325b9c6460cf14628f9df67d0e4d85R2168-R2188) [[2]](diffhunk://#diff-3e4a3e88d671a515eb1ccb29c38764f56daa521f3baa28f1dd0a6fc01e790c1fL93-R95) **General Code Cleanup** * Removed redundant imports and style definitions, replacing them with memoized hooks for improved performance and readability. [[1]](diffhunk://#diff-aeaea0f9815187563af3206aaa50ba5c56b6b7451dda0ef5a076d6c22b42c206L1-R1) [[2]](diffhunk://#diff-14f7c5e1822d3e2c5cb9ccbc7640ee23f22c04a46ee68c503fe5f0524d421ed4L1-R1) [[3]](diffhunk://#diff-3e4a3e88d671a515eb1ccb29c38764f56daa521f3baa28f1dd0a6fc01e790c1fL1-R1) **Minor Theming Adjustments** * Fixed header text color in Giphy attachment to use semantic outgoing chat text. These changes collectively make the UI more robust and easier to maintain by centralizing style management and improving theme integration across components. --------- Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io>
1 parent 8b55d62 commit b935bbe

35 files changed

+573
-554
lines changed
Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22

33
import { StyleSheet, Text, View } from 'react-native';
44

@@ -7,6 +7,7 @@ import { Channel } from 'stream-chat';
77
import { AIStates, useAIState } from './hooks/useAIState';
88

99
import { useChannelContext, useTheme, useTranslationContext } from '../../contexts';
10+
import { primitives } from '../../theme';
1011

1112
export type AITypingIndicatorViewProps = {
1213
channel?: Channel;
@@ -24,22 +25,39 @@ export const AITypingIndicatorView = ({
2425
[AIStates.Generating]: t('Generating...'),
2526
};
2627

27-
const {
28-
theme: {
29-
aiTypingIndicatorView: { container, text },
30-
colors: { black, grey_gainsboro },
31-
},
32-
} = useTheme();
28+
const styles = useStyles();
3329

3430
return aiState in allowedStates ? (
35-
<View style={[styles.container, { backgroundColor: grey_gainsboro }, container]}>
36-
<Text style={[{ color: black }, text]}>{allowedStates[aiState]}</Text>
31+
<View style={styles.container}>
32+
<Text style={styles.text}>{allowedStates[aiState]}</Text>
3733
</View>
3834
) : null;
3935
};
4036

4137
AITypingIndicatorView.displayName = 'AITypingIndicatorView{messageSimple{content}}';
4238

43-
const styles = StyleSheet.create({
44-
container: { paddingHorizontal: 16, paddingVertical: 18 },
45-
});
39+
const useStyles = () => {
40+
const {
41+
theme: {
42+
aiTypingIndicatorView: { container, text },
43+
semantics,
44+
},
45+
} = useTheme();
46+
return useMemo(() => {
47+
return StyleSheet.create({
48+
container: {
49+
backgroundColor: semantics.backgroundCoreSurface,
50+
paddingHorizontal: primitives.spacingMd,
51+
paddingVertical: primitives.spacingLg,
52+
...container,
53+
},
54+
text: {
55+
color: semantics.textPrimary,
56+
fontSize: primitives.typographyFontSizeMd,
57+
fontWeight: primitives.typographyFontWeightSemiBold,
58+
lineHeight: primitives.typographyLineHeightNormal,
59+
...text,
60+
},
61+
});
62+
}, [container, text, semantics]);
63+
};

package/src/components/Attachment/Giphy/Giphy.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ const useStyles = () => {
248248
gap: primitives.spacingXs,
249249
},
250250
headerText: {
251+
color: semantics.chatTextOutgoing,
251252
fontSize: primitives.typographyFontSizeSm,
252253
fontWeight: primitives.typographyFontWeightSemiBold,
253254
lineHeight: primitives.typographyLineHeightTight,

package/src/components/AutoCompleteInput/AutoCompleteSuggestionHeader.tsx

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22
import { StyleSheet, Text, View } from 'react-native';
33

44
import { useTheme } from '../../contexts/themeContext/ThemeContext';
@@ -22,6 +22,7 @@ export const CommandsHeader: React.FC<AutoCompleteSuggestionHeaderProps> = () =>
2222
},
2323
},
2424
} = useTheme();
25+
const styles = useStyles();
2526

2627
return (
2728
<View style={[styles.container, container]}>
@@ -38,19 +39,20 @@ export const CommandsHeader: React.FC<AutoCompleteSuggestionHeaderProps> = () =>
3839
export const EmojiHeader: React.FC<AutoCompleteSuggestionHeaderProps> = ({ queryText }) => {
3940
const {
4041
theme: {
41-
colors: { accent_blue, grey },
4242
messageInput: {
4343
suggestions: {
4444
header: { container, title },
4545
},
4646
},
47+
semantics,
4748
},
4849
} = useTheme();
50+
const styles = useStyles();
4951

5052
return (
5153
<View style={[styles.container, container]}>
52-
<Smile pathFill={accent_blue} />
53-
<Text style={[styles.title, { color: grey }, title]} testID='emojis-header-title'>
54+
<Smile pathFill={semantics.accentPrimary} />
55+
<Text style={[styles.title, title]} testID='emojis-header-title'>
5456
{`Emoji matching "${queryText}"`}
5557
</Text>
5658
</View>
@@ -102,16 +104,24 @@ export const AutoCompleteSuggestionHeader = (props: AutoCompleteSuggestionHeader
102104
AutoCompleteSuggestionHeader.displayName =
103105
'AutoCompleteSuggestionHeader{messageInput{suggestions{Header}}}';
104106

105-
const styles = StyleSheet.create({
106-
container: {
107-
alignItems: 'center',
108-
flexDirection: 'row',
109-
padding: 8,
110-
},
111-
title: {
112-
fontSize: primitives.typographyFontSizeSm,
113-
lineHeight: primitives.typographyLineHeightNormal,
114-
fontWeight: primitives.typographyFontWeightMedium,
115-
paddingLeft: 8,
116-
},
117-
});
107+
const useStyles = () => {
108+
const {
109+
theme: { semantics },
110+
} = useTheme();
111+
return useMemo(() => {
112+
return StyleSheet.create({
113+
container: {
114+
alignItems: 'center',
115+
flexDirection: 'row',
116+
padding: 8,
117+
},
118+
title: {
119+
fontSize: primitives.typographyFontSizeSm,
120+
lineHeight: primitives.typographyLineHeightNormal,
121+
fontWeight: primitives.typographyFontWeightMedium,
122+
paddingLeft: 8,
123+
color: semantics.textSecondary,
124+
},
125+
});
126+
}, [semantics]);
127+
};

package/src/components/AutoCompleteInput/AutoCompleteSuggestionItem.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ export const MentionSuggestionItem = (item: UserSuggestion) => {
2121
const { id, name, online } = item;
2222
const {
2323
theme: {
24-
colors: { black },
2524
messageInput: {
2625
suggestions: {
2726
mention: { column, container: mentionContainer, name: nameStyle },
@@ -35,7 +34,7 @@ export const MentionSuggestionItem = (item: UserSuggestion) => {
3534
<View style={[styles.container, mentionContainer]}>
3635
<UserAvatar user={item} size='md' showOnlineIndicator={online} />
3736
<View style={[styles.column, column]}>
38-
<Text style={[styles.name, { color: black }, nameStyle]} testID='mentions-item-name'>
37+
<Text style={[styles.name, nameStyle]} testID='mentions-item-name'>
3938
{name || id}
4039
</Text>
4140
</View>
@@ -47,7 +46,6 @@ export const EmojiSuggestionItem = (item: Emoji) => {
4746
const { native, name } = item;
4847
const {
4948
theme: {
50-
colors: { black },
5149
messageInput: {
5250
suggestions: {
5351
emoji: { container: emojiContainer, text },
@@ -59,10 +57,10 @@ export const EmojiSuggestionItem = (item: Emoji) => {
5957

6058
return (
6159
<View style={[styles.container, emojiContainer]}>
62-
<Text style={[styles.text, { color: black }, text]} testID='emojis-item-unicode'>
60+
<Text style={[styles.text, text]} testID='emojis-item-unicode'>
6361
{native}
6462
</Text>
65-
<Text style={[styles.text, { color: black }, text]} testID='emojis-item-name'>
63+
<Text style={[styles.text, text]} testID='emojis-item-name'>
6664
{` ${name}`}
6765
</Text>
6866
</View>
@@ -217,7 +215,10 @@ const useStyles = () => {
217215
fontWeight: '600',
218216
},
219217
text: {
220-
fontSize: 14,
218+
fontSize: primitives.typographyFontSizeMd,
219+
fontWeight: primitives.typographyFontWeightRegular,
220+
color: semantics.textPrimary,
221+
lineHeight: primitives.typographyLineHeightNormal,
221222
},
222223
title: {
223224
fontSize: primitives.typographyFontSizeMd,

package/src/components/Channel/Channel.tsx

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ import {
9999
ChannelUnreadStateStoreType,
100100
} from '../../state-store/channel-unread-state';
101101
import { MessageInputHeightStore } from '../../state-store/message-input-height-store';
102+
import { primitives } from '../../theme';
102103
import { FileTypes } from '../../types/types';
103104
import { addReactionToLocalState } from '../../utils/addReactionToLocalState';
104105
import { compressedImageURI } from '../../utils/compressImage';
@@ -232,10 +233,6 @@ export type MarkReadFunctionOptions = {
232233
updateChannelUnreadState?: boolean;
233234
};
234235

235-
const styles = StyleSheet.create({
236-
selectChannel: { fontWeight: 'bold', padding: 16 },
237-
});
238-
239236
export const reactionData: ReactionData[] = [
240237
{
241238
Icon: ({ size = 12 }: { size?: number }) => <Emoji item={'👍'} size={size} />,
@@ -794,12 +791,7 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
794791
? DefaultStopMessageStreamingButton
795792
: StopMessageStreamingButtonOverride;
796793

797-
const {
798-
theme: {
799-
channel: { selectChannel },
800-
colors: { black },
801-
},
802-
} = useTheme();
794+
const styles = useStyles();
803795
const [deleted, setDeleted] = useState<boolean>(false);
804796
const [error, setError] = useState<Error | boolean>(false);
805797
const [lastRead, setLastRead] = useState<Date | undefined>();
@@ -2080,7 +2072,7 @@ const ChannelWithContext = (props: PropsWithChildren<ChannelPropsWithContext>) =
20802072

20812073
if (!channel?.cid || !channel.watch) {
20822074
return (
2083-
<Text style={[styles.selectChannel, { color: black }, selectChannel]} testID='no-channel'>
2075+
<Text style={styles.selectChannel} testID='no-channel'>
20842076
{t('Please select a channel first')}
20852077
</Text>
20862078
);
@@ -2173,3 +2165,24 @@ export const Channel = (props: PropsWithChildren<ChannelProps>) => {
21732165
/>
21742166
);
21752167
};
2168+
2169+
const useStyles = () => {
2170+
const {
2171+
theme: {
2172+
channel: { selectChannel },
2173+
semantics,
2174+
},
2175+
} = useTheme();
2176+
return useMemo(() => {
2177+
return StyleSheet.create({
2178+
selectChannel: {
2179+
fontWeight: primitives.typographyFontWeightSemiBold,
2180+
fontSize: primitives.typographyFontSizeMd,
2181+
lineHeight: primitives.typographyLineHeightNormal,
2182+
padding: primitives.spacingMd,
2183+
color: semantics.textPrimary,
2184+
...selectChannel,
2185+
},
2186+
});
2187+
}, [selectChannel, semantics]);
2188+
};
Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,21 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22
import { GestureResponderEvent, StyleSheet, Text, TouchableOpacity } from 'react-native';
33

44
import { useTheme } from '../../contexts/themeContext/ThemeContext';
55
import { useTranslationContext } from '../../contexts/translationContext/TranslationContext';
6-
7-
const styles = StyleSheet.create({
8-
container: {
9-
alignItems: 'center',
10-
justifyContent: 'center',
11-
padding: 3,
12-
width: '100%',
13-
},
14-
errorText: {
15-
fontSize: 12,
16-
padding: 3,
17-
},
18-
});
6+
import { primitives } from '../../theme';
197

208
export type HeaderErrorProps = {
219
onPress?: (event: GestureResponderEvent) => void;
2210
};
2311

2412
export const ChannelListHeaderErrorIndicator = ({ onPress = () => null }: HeaderErrorProps) => {
25-
const {
26-
theme: {
27-
channelListHeaderErrorIndicator: { container, errorText },
28-
colors: { grey_dark, white },
29-
},
30-
} = useTheme();
13+
const styles = useStyles();
3114
const { t } = useTranslationContext();
3215

3316
return (
34-
<TouchableOpacity
35-
onPress={onPress}
36-
style={[styles.container, { backgroundColor: `${grey_dark}E6` }, container]}
37-
>
38-
<Text style={[styles.errorText, { color: white }, errorText]} testID='channel-loading-error'>
17+
<TouchableOpacity onPress={onPress} style={styles.container}>
18+
<Text style={styles.errorText} testID='channel-loading-error'>
3919
{t('Error while loading, please reload/refresh')}
4020
</Text>
4121
</TouchableOpacity>
@@ -44,3 +24,32 @@ export const ChannelListHeaderErrorIndicator = ({ onPress = () => null }: Header
4424

4525
ChannelListHeaderErrorIndicator.displayName =
4626
'ChannelListHeaderErrorIndicator{channelListHeaderErrorIndicator}';
27+
28+
const useStyles = () => {
29+
const {
30+
theme: {
31+
channelListHeaderErrorIndicator: { container, errorText },
32+
semantics,
33+
},
34+
} = useTheme();
35+
return useMemo(() => {
36+
return StyleSheet.create({
37+
container: {
38+
alignItems: 'center',
39+
justifyContent: 'center',
40+
width: '100%',
41+
backgroundColor: semantics.backgroundCoreSurface,
42+
paddingVertical: primitives.spacingXs,
43+
paddingHorizontal: primitives.spacingSm,
44+
...container,
45+
},
46+
errorText: {
47+
fontSize: primitives.typographyFontSizeXs,
48+
fontWeight: primitives.typographyFontWeightSemiBold,
49+
lineHeight: primitives.typographyLineHeightTight,
50+
color: semantics.chatTextSystem,
51+
...errorText,
52+
},
53+
});
54+
}, [container, errorText, semantics]);
55+
};

0 commit comments

Comments
 (0)