Skip to content

Commit 9d23997

Browse files
feat: use rn enriched instead of markdown display
1 parent 45c90fb commit 9d23997

2 files changed

Lines changed: 122 additions & 245 deletions

File tree

components/chat-screen/MarkdownComponent.tsx

Lines changed: 122 additions & 244 deletions
Original file line numberDiff line numberDiff line change
@@ -1,263 +1,141 @@
1-
import React, { memo } from 'react';
2-
import Markdown from 'react-native-markdown-display';
3-
import { Platform, View, TouchableOpacity, Text, TextStyle, ViewStyle } from 'react-native';
1+
import React, { memo, useMemo } from 'react';
2+
import {
3+
EnrichedMarkdownText,
4+
type MarkdownStyle,
5+
} from 'react-native-enriched-markdown';
6+
import { Platform } from 'react-native';
47
import { fontFamily, fontSizes, lineHeights } from '../../styles/fontStyles';
58
import { useTheme } from '../../context/ThemeContext';
6-
import CopyIcon from '../../assets/icons/copy.svg';
7-
import Clipboard from '@react-native-clipboard/clipboard';
8-
import Toast from 'react-native-toast-message';
99

1010
interface Props {
1111
text: string;
1212
isUser?: boolean;
1313
isThinking?: boolean;
1414
}
1515

16-
interface MarkdownNode {
17-
content?: string;
18-
literal?: string;
19-
key: string;
20-
}
21-
22-
interface CodeBlockProps {
23-
style: TextStyle;
24-
isUser: boolean;
25-
rawText: string;
26-
}
27-
28-
const CodeBlockWithCopy = memo(({ style, isUser, rawText }: CodeBlockProps) => {
29-
const { theme } = useTheme();
30-
31-
const handleCopy = () => {
32-
if (rawText) {
33-
Clipboard.setString(rawText);
34-
Toast.show({
35-
type: 'defaultToast',
36-
text1: 'Code copied to clipboard',
37-
});
38-
}
39-
};
40-
41-
const copyButtonStyle: ViewStyle = {
42-
position: 'absolute',
43-
bottom: 15,
44-
right: 8,
45-
padding: 6,
46-
backgroundColor: isUser
47-
? theme.bg.overlay
48-
: theme.bg.overlay,
49-
borderRadius: 4,
50-
};
51-
52-
const iconStyle = {
53-
color: isUser ? theme.text.contrastPrimary : theme.text.defaultSecondary
54-
};
55-
56-
return (
57-
<View style={{ position: 'relative' }}>
58-
<Text style={style}>{rawText}</Text>
59-
<TouchableOpacity onPress={handleCopy} style={copyButtonStyle}>
60-
<CopyIcon
61-
width={14}
62-
height={14}
63-
style={iconStyle}
64-
/>
65-
</TouchableOpacity>
66-
</View>
67-
);
68-
});
69-
7016
const MarkdownComponent = memo(
7117
({ text, isUser = false, isThinking = false }: Props) => {
7218
const { theme } = useTheme();
73-
const baseColor = isUser ? theme.text.primary : theme.text.primary;
19+
const baseColor = theme.text.primary;
7420
const baseFontSize = isThinking ? fontSizes.sm : fontSizes.md;
21+
const monoFont = Platform.select({ ios: 'Menlo', default: 'monospace' });
7522

76-
const customRules = {
77-
code_block: (node: MarkdownNode, _children: React.ReactNode, _parent: unknown, styles: any) => {
78-
const rawText = node.content || node.literal || '';
79-
return (
80-
<CodeBlockWithCopy
81-
key={node.key}
82-
style={styles.code_block}
83-
isUser={isUser}
84-
rawText={rawText}
85-
/>
86-
);
87-
},
88-
fence: (node: MarkdownNode, _children: React.ReactNode, _parent: unknown, styles: any) => {
89-
const rawText = node.content || node.literal || '';
90-
return (
91-
<CodeBlockWithCopy
92-
key={node.key}
93-
style={styles.fence}
94-
isUser={isUser}
95-
rawText={rawText}
96-
/>
97-
);
98-
},
99-
};
23+
const markdownStyle: MarkdownStyle = useMemo(
24+
() => ({
25+
paragraph: {
26+
fontFamily: fontFamily.regular,
27+
fontSize: baseFontSize,
28+
color: baseColor,
29+
lineHeight: Platform.select({
30+
ios: lineHeights.md,
31+
android: lineHeights.md + 2,
32+
default: lineHeights.md,
33+
}),
34+
marginBottom: 12,
35+
},
36+
h1: {
37+
fontFamily: fontFamily.bold,
38+
fontSize: fontSizes.xxl,
39+
color: baseColor,
40+
lineHeight: 36,
41+
marginTop: 16,
42+
marginBottom: 8,
43+
},
44+
h2: {
45+
fontFamily: fontFamily.bold,
46+
fontSize: fontSizes.xl,
47+
color: baseColor,
48+
lineHeight: 30,
49+
marginTop: 14,
50+
marginBottom: 6,
51+
},
52+
h3: {
53+
fontFamily: fontFamily.bold,
54+
fontSize: fontSizes.lg,
55+
color: baseColor,
56+
lineHeight: 26,
57+
marginTop: 12,
58+
marginBottom: 4,
59+
},
60+
h4: {
61+
fontFamily: fontFamily.bold,
62+
fontSize: 17,
63+
color: baseColor,
64+
lineHeight: 24,
65+
marginTop: 10,
66+
marginBottom: 4,
67+
},
68+
strong: {
69+
color: baseColor,
70+
},
71+
em: {
72+
color: theme.text.defaultSecondary,
73+
},
74+
link: {
75+
color: theme.bg.main,
76+
underline: true,
77+
},
78+
code: {
79+
fontFamily: monoFont,
80+
fontSize: baseFontSize - 1,
81+
color: baseColor,
82+
backgroundColor: isUser
83+
? 'rgba(255,255,255,0.2)'
84+
: 'rgba(0,0,0,0.06)',
85+
borderColor: isUser
86+
? 'rgba(255,255,255,0.1)'
87+
: 'rgba(0,0,0,0.08)',
88+
},
89+
codeBlock: {
90+
fontFamily: monoFont,
91+
fontSize: 13,
92+
color: baseColor,
93+
backgroundColor: isUser
94+
? 'rgba(255,255,255,0.12)'
95+
: 'rgba(0,0,0,0.05)',
96+
borderRadius: 10,
97+
padding: 14,
98+
marginTop: 8,
99+
marginBottom: 12,
100+
},
101+
blockquote: {
102+
fontFamily: fontFamily.regular,
103+
fontSize: baseFontSize,
104+
color: theme.text.defaultSecondary,
105+
borderColor: theme.bg.main,
106+
borderWidth: 3,
107+
gapWidth: 14,
108+
marginTop: 8,
109+
marginBottom: 12,
110+
},
111+
list: {
112+
fontSize: baseFontSize,
113+
fontFamily: fontFamily.regular,
114+
color: baseColor,
115+
lineHeight: lineHeights.md,
116+
bulletColor: theme.text.defaultTertiary,
117+
bulletSize: 5,
118+
markerColor: theme.text.defaultSecondary,
119+
gapWidth: 10,
120+
marginLeft: 20,
121+
marginBottom: 12,
122+
},
123+
thematicBreak: {
124+
color: theme.border.soft,
125+
height: 1,
126+
marginTop: 20,
127+
marginBottom: 20,
128+
},
129+
}),
130+
[baseColor, baseFontSize, isUser, monoFont, theme]
131+
);
100132

101133
return (
102-
<Markdown
103-
rules={customRules}
104-
style={{
105-
body: {
106-
color: baseColor,
107-
fontSize: baseFontSize,
108-
fontFamily: fontFamily.regular,
109-
lineHeight: lineHeights.md,
110-
},
111-
paragraph: {
112-
fontFamily: fontFamily.regular,
113-
lineHeight: lineHeights.md,
114-
},
115-
heading1: {
116-
fontSize: fontSizes.xxl,
117-
color: baseColor,
118-
marginBottom: 8,
119-
fontFamily: fontFamily.bold,
120-
lineHeight: 24,
121-
},
122-
heading2: {
123-
fontSize: 20,
124-
color: baseColor,
125-
fontFamily: fontFamily.bold,
126-
lineHeight: 24,
127-
},
128-
heading3: {
129-
fontSize: 18,
130-
color: baseColor,
131-
fontFamily: fontFamily.bold,
132-
lineHeight: 24,
133-
},
134-
heading4: {
135-
fontSize: 17,
136-
color: baseColor,
137-
fontFamily: fontFamily.bold,
138-
lineHeight: 24,
139-
},
140-
strong: {
141-
fontSize: 16,
142-
color: baseColor,
143-
fontFamily: fontFamily.bold,
144-
lineHeight: 24,
145-
},
146-
em: {
147-
color: baseColor,
148-
fontFamily: fontFamily.regularItalic,
149-
lineHeight: 24,
150-
},
151-
bullet_list: {
152-
fontFamily: fontFamily.regular,
153-
lineHeight: 24,
154-
},
155-
ordered_list: {
156-
fontFamily: fontFamily.regular,
157-
lineHeight: 24,
158-
},
159-
list_item: {
160-
flexDirection: 'row',
161-
alignItems: 'flex-start',
162-
fontFamily: fontFamily.regular,
163-
lineHeight: 24,
164-
},
165-
bullet_list_icon: {
166-
color: baseColor,
167-
marginRight: 8,
168-
fontSize: 30,
169-
fontFamily: fontFamily.regular,
170-
lineHeight: 30,
171-
},
172-
bullet_list_content: {
173-
flex: 1,
174-
color: baseColor,
175-
fontSize: 16,
176-
fontFamily: fontFamily.regular,
177-
lineHeight: 24,
178-
},
179-
ordered_list_icon: {
180-
color: baseColor,
181-
marginRight: 8,
182-
fontSize: 16,
183-
fontFamily: fontFamily.bold,
184-
lineHeight: 24,
185-
},
186-
ordered_list_content: {
187-
flex: 1,
188-
color: baseColor,
189-
fontSize: 16,
190-
fontFamily: fontFamily.regular,
191-
lineHeight: 24,
192-
},
193-
code_inline: {
194-
backgroundColor: isUser
195-
? 'rgba(255,255,255,0.2)'
196-
: 'rgba(0,0,0,0.1)',
197-
color: baseColor,
198-
fontSize: 15,
199-
paddingHorizontal: 4,
200-
paddingVertical: 2,
201-
borderRadius: 4,
202-
fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
203-
},
204-
code_block: {
205-
backgroundColor: isUser
206-
? 'rgba(255,255,255,0.15)'
207-
: 'rgba(0,0,0,0.08)',
208-
color: baseColor,
209-
fontSize: 12,
210-
padding: 12,
211-
borderRadius: 8,
212-
marginTop: 8,
213-
marginBottom: 8,
214-
fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
215-
borderLeftWidth: 3,
216-
},
217-
fence: {
218-
backgroundColor: isUser
219-
? 'rgba(255,255,255,0.15)'
220-
: 'rgba(0,0,0,0.08)',
221-
color: baseColor,
222-
fontSize: 12,
223-
padding: 12,
224-
borderRadius: 8,
225-
marginTop: 8,
226-
marginBottom: 8,
227-
fontFamily: Platform.OS === 'ios' ? 'Menlo' : 'monospace',
228-
borderLeftWidth: 3,
229-
},
230-
link: {
231-
textDecorationLine: 'underline',
232-
fontFamily: fontFamily.regular,
233-
fontSize: 16,
234-
lineHeight: 24,
235-
},
236-
blockquote: {
237-
borderLeftWidth: 4,
238-
paddingLeft: 12,
239-
paddingRight: 12,
240-
paddingTop: 8,
241-
paddingBottom: 8,
242-
marginTop: 8,
243-
marginBottom: 8,
244-
borderRadius: 4,
245-
fontFamily: fontFamily.regular,
246-
},
247-
hr: {
248-
backgroundColor: isUser
249-
? 'rgba(255,255,255,0.3)'
250-
: 'rgba(0,0,0,0.2)',
251-
height: 1,
252-
marginTop: 16,
253-
marginBottom: 16,
254-
lineHeight: 24,
255-
fontFamily: fontFamily.regular,
256-
},
257-
}}
258-
>
259-
{text}
260-
</Markdown>
134+
<EnrichedMarkdownText
135+
markdown={text}
136+
markdownStyle={markdownStyle}
137+
selectable={true}
138+
/>
261139
);
262140
}
263141
);

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
"react-native-image-picker": "^8.2.1",
8686
"react-native-keyboard-controller": "1.18.5",
8787
"react-native-loading-spinner-overlay": "^3.0.1",
88-
"react-native-markdown-display": "^7.0.2",
8988
"react-native-pdfium": "file:./react-native-pdfium-0.1.3.tgz",
9089
"react-native-rag": "^0.8.0",
9190
"react-native-reanimated": "~4.1.1",

0 commit comments

Comments
 (0)