hs-react-native-custom-markdown 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -7,8 +7,8 @@ type CustomMarkdownProps = {
|
|
|
7
7
|
resolveImageSource?: (path: string) => any;
|
|
8
8
|
};
|
|
9
9
|
declare const CustomMarkdown: React.FC<CustomMarkdownProps>;
|
|
10
|
-
export default CustomMarkdown;
|
|
11
10
|
declare const defaultStyles: {
|
|
11
|
+
container: {};
|
|
12
12
|
paragraph: {
|
|
13
13
|
fontSize: number;
|
|
14
14
|
lineHeight: number;
|
|
@@ -102,4 +102,5 @@ declare const defaultStyles: {
|
|
|
102
102
|
marginVertical: number;
|
|
103
103
|
};
|
|
104
104
|
};
|
|
105
|
+
export default CustomMarkdown;
|
|
105
106
|
//# sourceMappingURL=CustomMarkdown.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomMarkdown.d.ts","sourceRoot":"","sources":["../../src/CustomMarkdown.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CustomMarkdown.d.ts","sourceRoot":"","sources":["../../src/CustomMarkdown.tsx"],"names":[],"mappings":"AAyrBA,OAAO,KAAc,MAAM,OAAO,CAAC;AACnC,OAAO,EAML,SAAS,EACT,SAAS,EACT,SAAS,EACT,UAAU,EACX,MAAM,cAAc,CAAC;AAGtB,KAAK,aAAa,GAAG,SAAS,CAAC,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC,CAAC;AAEnE,KAAK,mBAAmB,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,OAAO,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC;IACpE,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC;CAC5C,CAAC;AAkBF,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA2NjD,CAAC;AAGF,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCjB,CAAC;AAEH,eAAe,cAAc,CAAC"}
|
|
@@ -1,39 +1,708 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// import React, { JSX } from 'react';
|
|
3
|
+
// import {
|
|
4
|
+
// Text,
|
|
5
|
+
// View,
|
|
6
|
+
// Image,
|
|
7
|
+
// StyleSheet,
|
|
8
|
+
// Linking,
|
|
9
|
+
// StyleProp,
|
|
10
|
+
// TextStyle,
|
|
11
|
+
// ViewStyle,
|
|
12
|
+
// ImageStyle,
|
|
13
|
+
// } from 'react-native';
|
|
2
14
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
15
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
16
|
};
|
|
5
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
// type MarkdownStyle = StyleProp<TextStyle | ViewStyle | ImageStyle>;
|
|
19
|
+
// type CustomMarkdownProps = {
|
|
20
|
+
// content: string;
|
|
21
|
+
// styles?: Partial<Record<keyof typeof defaultStyles, MarkdownStyle>>;
|
|
22
|
+
// resolveImageSource?: (path: string) => any;
|
|
23
|
+
// };
|
|
24
|
+
// const CustomMarkdown: React.FC<CustomMarkdownProps> = ({
|
|
25
|
+
// content,
|
|
26
|
+
// styles = {},
|
|
27
|
+
// resolveImageSource,
|
|
28
|
+
// }) => {
|
|
29
|
+
// const getMergedStyle = (key: keyof typeof defaultStyles): MarkdownStyle => {
|
|
30
|
+
// return [defaultStyles[key], styles[key]];
|
|
31
|
+
// };
|
|
32
|
+
// // const parseInlineMarkdown = (text: string) => {
|
|
33
|
+
// // const elements: (JSX.Element | string)[] = [];
|
|
34
|
+
// // let remaining = text;
|
|
35
|
+
// // let index = 0;
|
|
36
|
+
// // const applyRegex = (
|
|
37
|
+
// // regex: RegExp,
|
|
38
|
+
// // styleKey: keyof typeof defaultStyles,
|
|
39
|
+
// // isLink = false,
|
|
40
|
+
// // isCode = false,
|
|
41
|
+
// // isHtmlTag = false,
|
|
42
|
+
// // renderText?: (value: string) => string,
|
|
43
|
+
// // ) => {
|
|
44
|
+
// // const match = regex.exec(remaining);
|
|
45
|
+
// // if (match) {
|
|
46
|
+
// // const [full, inner, link] = match;
|
|
47
|
+
// // const before = remaining.substring(0, match.index);
|
|
48
|
+
// // const after = remaining.substring(match.index + full.length);
|
|
49
|
+
// // if (before) elements.push(before);
|
|
50
|
+
// // if (isLink) {
|
|
51
|
+
// // elements.push(
|
|
52
|
+
// // <Text
|
|
53
|
+
// // key={`link-${index++}`}
|
|
54
|
+
// // style={getMergedStyle(styleKey)}
|
|
55
|
+
// // onPress={() => Linking.openURL(link)}
|
|
56
|
+
// // >
|
|
57
|
+
// // {inner}
|
|
58
|
+
// // </Text>,
|
|
59
|
+
// // );
|
|
60
|
+
// // } else if (isHtmlTag && renderText) {
|
|
61
|
+
// // elements.push(
|
|
62
|
+
// // <Text key={`html-${index++}`} style={getMergedStyle(styleKey)}>
|
|
63
|
+
// // {renderText(inner)}
|
|
64
|
+
// // </Text>,
|
|
65
|
+
// // );
|
|
66
|
+
// // } else {
|
|
67
|
+
// // elements.push(
|
|
68
|
+
// // <Text key={`styled-${index++}`} style={getMergedStyle(styleKey)}>
|
|
69
|
+
// // {inner}
|
|
70
|
+
// // </Text>,
|
|
71
|
+
// // );
|
|
72
|
+
// // }
|
|
73
|
+
// // remaining = after;
|
|
74
|
+
// // return true;
|
|
75
|
+
// // }
|
|
76
|
+
// // return false;
|
|
77
|
+
// // };
|
|
78
|
+
// // while (remaining.length) {
|
|
79
|
+
// // const patterns = [
|
|
80
|
+
// // { regex: /\*\*\*(.*?)\*\*\*/g, style: ['bold', 'italic'] },
|
|
81
|
+
// // { regex: /\*\*(.*?)\*\*/g, style: ['bold'] },
|
|
82
|
+
// // { regex: /_(.*?)_/g, style: ['italic'] },
|
|
83
|
+
// // { regex: /`([^`]+)`/g, style: ['code'], isCode: true },
|
|
84
|
+
// // { regex: /\[(.*?)\]\((.*?)\)/g, style: ['link'], isLink: true },
|
|
85
|
+
// // { regex: /<b>(.*?)<\/b>/i, style: ['bold'], isHtmlTag: true },
|
|
86
|
+
// // { regex: /<i>(.*?)<\/i>/i, style: ['italic'], isHtmlTag: true },
|
|
87
|
+
// // { regex: /<u>(.*?)<\/u>/i, style: ['underline'], isHtmlTag: true },
|
|
88
|
+
// // {
|
|
89
|
+
// // regex: /<br\s*\/?>/i,
|
|
90
|
+
// // style: ['paragraph'],
|
|
91
|
+
// // isHtmlTag: true,
|
|
92
|
+
// // renderText: () => '\n',
|
|
93
|
+
// // },
|
|
94
|
+
// // ];
|
|
95
|
+
// // let matched = false;
|
|
96
|
+
// // for (const pattern of patterns) {
|
|
97
|
+
// // if (
|
|
98
|
+
// // applyRegex(
|
|
99
|
+
// // pattern.regex,
|
|
100
|
+
// // pattern.style[0] as keyof typeof defaultStyles,
|
|
101
|
+
// // pattern.isLink,
|
|
102
|
+
// // pattern.isCode,
|
|
103
|
+
// // pattern.isHtmlTag,
|
|
104
|
+
// // pattern.renderText,
|
|
105
|
+
// // )
|
|
106
|
+
// // ) {
|
|
107
|
+
// // matched = true;
|
|
108
|
+
// // break;
|
|
109
|
+
// // }
|
|
110
|
+
// // }
|
|
111
|
+
// // if (!matched) {
|
|
112
|
+
// // elements.push(remaining);
|
|
113
|
+
// // break;
|
|
114
|
+
// // }
|
|
115
|
+
// // }
|
|
116
|
+
// // return <Text>{elements}</Text>;
|
|
117
|
+
// // };
|
|
118
|
+
// const parseInlineMarkdown = (text: string) => {
|
|
119
|
+
// const elements: (JSX.Element | string)[] = [];
|
|
120
|
+
// let remaining = text;
|
|
121
|
+
// let index = 0;
|
|
122
|
+
// // Helper function to parse formatting within colored text
|
|
123
|
+
// const parseFormattedText = (content: string, baseColor: string, startIdx: number) => {
|
|
124
|
+
// const formattedElements: JSX.Element[] = [];
|
|
125
|
+
// let formattedRemaining = content;
|
|
126
|
+
// let formattedIndex = startIdx;
|
|
127
|
+
// while (formattedRemaining.length > 0) {
|
|
128
|
+
// // Check for bold text
|
|
129
|
+
// const boldMatch = /\*\*(.*?)\*\*/g.exec(formattedRemaining);
|
|
130
|
+
// if (boldMatch) {
|
|
131
|
+
// const before = formattedRemaining.substring(0, boldMatch.index);
|
|
132
|
+
// if (before) {
|
|
133
|
+
// formattedElements.push(
|
|
134
|
+
// <Text key={`text-${formattedIndex++}`} style={{ color: baseColor }}>
|
|
135
|
+
// {before}
|
|
136
|
+
// </Text>
|
|
137
|
+
// );
|
|
138
|
+
// }
|
|
139
|
+
// formattedElements.push(
|
|
140
|
+
// <Text key={`bold-${formattedIndex++}`} style={{ color: baseColor, fontWeight: 'bold' }}>
|
|
141
|
+
// {boldMatch[1]}
|
|
142
|
+
// </Text>
|
|
143
|
+
// );
|
|
144
|
+
// formattedRemaining = formattedRemaining.substring(boldMatch.index + boldMatch[0].length);
|
|
145
|
+
// continue;
|
|
146
|
+
// }
|
|
147
|
+
// // Check for italic text
|
|
148
|
+
// const italicMatch = /_(.*?)_/g.exec(formattedRemaining);
|
|
149
|
+
// if (italicMatch) {
|
|
150
|
+
// const before = formattedRemaining.substring(0, italicMatch.index);
|
|
151
|
+
// if (before) {
|
|
152
|
+
// formattedElements.push(
|
|
153
|
+
// <Text key={`text-${formattedIndex++}`} style={{ color: baseColor }}>
|
|
154
|
+
// {before}
|
|
155
|
+
// </Text>
|
|
156
|
+
// );
|
|
157
|
+
// }
|
|
158
|
+
// formattedElements.push(
|
|
159
|
+
// <Text key={`italic-${formattedIndex++}`} style={{ color: baseColor, fontStyle: 'italic' }}>
|
|
160
|
+
// {italicMatch[1]}
|
|
161
|
+
// </Text>
|
|
162
|
+
// );
|
|
163
|
+
// formattedRemaining = formattedRemaining.substring(italicMatch.index + italicMatch[0].length);
|
|
164
|
+
// continue;
|
|
165
|
+
// }
|
|
166
|
+
// // No more formatting, push remaining text
|
|
167
|
+
// if (formattedRemaining) {
|
|
168
|
+
// formattedElements.push(
|
|
169
|
+
// <Text key={`text-${formattedIndex++}`} style={{ color: baseColor }}>
|
|
170
|
+
// {formattedRemaining}
|
|
171
|
+
// </Text>
|
|
172
|
+
// );
|
|
173
|
+
// }
|
|
174
|
+
// break;
|
|
175
|
+
// }
|
|
176
|
+
// return formattedElements;
|
|
177
|
+
// };
|
|
178
|
+
// const applyRegex = (
|
|
179
|
+
// regex: RegExp,
|
|
180
|
+
// styleKey: keyof typeof defaultStyles,
|
|
181
|
+
// isLink = false,
|
|
182
|
+
// isCode = false,
|
|
183
|
+
// isHtmlTag = false,
|
|
184
|
+
// isColor = false,
|
|
185
|
+
// renderText?: (
|
|
186
|
+
// value: string,
|
|
187
|
+
// match?: RegExpExecArray,
|
|
188
|
+
// ) => string | JSX.Element,
|
|
189
|
+
// ) => {
|
|
190
|
+
// regex.lastIndex = 0;
|
|
191
|
+
// const match = regex.exec(remaining);
|
|
192
|
+
// if (match) {
|
|
193
|
+
// const [full, inner, inner2] = match;
|
|
194
|
+
// const before = remaining.substring(0, match.index);
|
|
195
|
+
// const after = remaining.substring(match.index + full.length);
|
|
196
|
+
// if (before) elements.push(before);
|
|
197
|
+
// if (isLink) {
|
|
198
|
+
// elements.push(
|
|
199
|
+
// <Text
|
|
200
|
+
// key={`link-${index++}`}
|
|
201
|
+
// style={getMergedStyle(styleKey)}
|
|
202
|
+
// onPress={() => Linking.openURL(inner2)}
|
|
203
|
+
// >
|
|
204
|
+
// {inner}
|
|
205
|
+
// </Text>,
|
|
206
|
+
// );
|
|
207
|
+
// } else if (isColor) {
|
|
208
|
+
// // Handle color syntax :::{.color-blue}text:::
|
|
209
|
+
// const colorName = inner;
|
|
210
|
+
// const coloredText = inner2;
|
|
211
|
+
// console.log('DEBUG - Color processing:');
|
|
212
|
+
// console.log('Color:', colorName);
|
|
213
|
+
// console.log('Text:', coloredText);
|
|
214
|
+
// // Parse formatted text within the color
|
|
215
|
+
// const coloredElements = parseFormattedText(coloredText, colorName.toLowerCase(), index);
|
|
216
|
+
// elements.push(...coloredElements);
|
|
217
|
+
// index += coloredElements.length;
|
|
218
|
+
// } else if (isHtmlTag && renderText) {
|
|
219
|
+
// const rendered = renderText(inner, match);
|
|
220
|
+
// if (typeof rendered === 'string') {
|
|
221
|
+
// elements.push(rendered);
|
|
222
|
+
// } else {
|
|
223
|
+
// elements.push(rendered);
|
|
224
|
+
// }
|
|
225
|
+
// } else {
|
|
226
|
+
// elements.push(
|
|
227
|
+
// <Text key={`styled-${index++}`} style={getMergedStyle(styleKey)}>
|
|
228
|
+
// {inner}
|
|
229
|
+
// </Text>,
|
|
230
|
+
// );
|
|
231
|
+
// }
|
|
232
|
+
// remaining = after;
|
|
233
|
+
// return true;
|
|
234
|
+
// }
|
|
235
|
+
// return false;
|
|
236
|
+
// };
|
|
237
|
+
// while (remaining.length) {
|
|
238
|
+
// const patterns = [
|
|
239
|
+
// // COLOR PATTERN FIRST
|
|
240
|
+
// {
|
|
241
|
+
// regex: /:::\s*{\s*\.color-([a-zA-Z]+)\s*}\s*([\s\S]*?)\s*:::/g,
|
|
242
|
+
// style: ['paragraph'],
|
|
243
|
+
// isColor: true,
|
|
244
|
+
// },
|
|
245
|
+
// { regex: /\*\*\*(.*?)\*\*\*/g, style: ['bold', 'italic'] },
|
|
246
|
+
// { regex: /\*\*(.*?)\*\*/g, style: ['bold'] },
|
|
247
|
+
// { regex: /_(.*?)_/g, style: ['italic'] },
|
|
248
|
+
// { regex: /`([^`]+)`/g, style: ['code'], isCode: true },
|
|
249
|
+
// { regex: /\[(.*?)\]\((.*?)\)/g, style: ['link'], isLink: true },
|
|
250
|
+
// { regex: /<b>(.*?)<\/b>/i, style: ['bold'], isHtmlTag: true },
|
|
251
|
+
// { regex: /<i>(.*?)<\/i>/i, style: ['italic'], isHtmlTag: true },
|
|
252
|
+
// { regex: /<u>(.*?)<\/u>/i, style: ['underline'], isHtmlTag: true },
|
|
253
|
+
// {
|
|
254
|
+
// regex: /<br\s*\/?>/i,
|
|
255
|
+
// style: ['paragraph'],
|
|
256
|
+
// isHtmlTag: true,
|
|
257
|
+
// renderText: () => '\n',
|
|
258
|
+
// },
|
|
259
|
+
// ];
|
|
260
|
+
// let matched = false;
|
|
261
|
+
// for (const pattern of patterns) {
|
|
262
|
+
// if (
|
|
263
|
+
// applyRegex(
|
|
264
|
+
// pattern.regex,
|
|
265
|
+
// pattern.style[0] as keyof typeof defaultStyles,
|
|
266
|
+
// pattern.isLink,
|
|
267
|
+
// pattern.isCode,
|
|
268
|
+
// pattern.isHtmlTag,
|
|
269
|
+
// pattern.isColor,
|
|
270
|
+
// pattern.renderText,
|
|
271
|
+
// )
|
|
272
|
+
// ) {
|
|
273
|
+
// matched = true;
|
|
274
|
+
// break;
|
|
275
|
+
// }
|
|
276
|
+
// }
|
|
277
|
+
// if (!matched) {
|
|
278
|
+
// elements.push(remaining);
|
|
279
|
+
// break;
|
|
280
|
+
// }
|
|
281
|
+
// }
|
|
282
|
+
// return <Text>{elements}</Text>;
|
|
283
|
+
// };
|
|
284
|
+
//! to be uncommented
|
|
285
|
+
// import React, { JSX } from 'react';
|
|
286
|
+
// import {
|
|
287
|
+
// Text,
|
|
288
|
+
// View,
|
|
289
|
+
// Image,
|
|
290
|
+
// StyleSheet,
|
|
291
|
+
// Linking,
|
|
292
|
+
// StyleProp,
|
|
293
|
+
// TextStyle,
|
|
294
|
+
// ViewStyle,
|
|
295
|
+
// ImageStyle,
|
|
296
|
+
// Platform,
|
|
297
|
+
// } from 'react-native';
|
|
298
|
+
// type MarkdownStyle = StyleProp<TextStyle | ViewStyle | ImageStyle>;
|
|
299
|
+
// type CustomMarkdownProps = {
|
|
300
|
+
// content: string;
|
|
301
|
+
// styles?: Partial<Record<keyof typeof defaultStyles, MarkdownStyle>>;
|
|
302
|
+
// resolveImageSource?: (path: string) => any;
|
|
303
|
+
// };
|
|
304
|
+
// // Color mapping for React Native
|
|
305
|
+
// const COLOR_MAP: Record<string, string> = {
|
|
306
|
+
// blue: '#007AFF',
|
|
307
|
+
// red: '#FF3B30',
|
|
308
|
+
// green: '#34C759',
|
|
309
|
+
// orange: '#FF9500',
|
|
310
|
+
// yellow: '#FFCC00',
|
|
311
|
+
// purple: '#5856D6',
|
|
312
|
+
// pink: '#FF2D55',
|
|
313
|
+
// brown: '#A2845E',
|
|
314
|
+
// black: '#000000',
|
|
315
|
+
// white: '#FFFFFF',
|
|
316
|
+
// gray: '#8E8E93',
|
|
317
|
+
// };
|
|
318
|
+
// const CustomMarkdown: React.FC<CustomMarkdownProps> = ({
|
|
319
|
+
// content,
|
|
320
|
+
// styles = {},
|
|
321
|
+
// resolveImageSource,
|
|
322
|
+
// }) => {
|
|
323
|
+
// const getMergedStyle = (key: keyof typeof defaultStyles): MarkdownStyle => {
|
|
324
|
+
// return [defaultStyles[key], styles[key]];
|
|
325
|
+
// };
|
|
326
|
+
// const parseInlineMarkdown = (text: string) => {
|
|
327
|
+
// const elements: (JSX.Element | string)[] = [];
|
|
328
|
+
// let remaining = text;
|
|
329
|
+
// let index = 0;
|
|
330
|
+
// const applyRegex = (
|
|
331
|
+
// regex: RegExp,
|
|
332
|
+
// styleKey: keyof typeof defaultStyles,
|
|
333
|
+
// isLink = false,
|
|
334
|
+
// isCode = false,
|
|
335
|
+
// isHtmlTag = false,
|
|
336
|
+
// isColor = false,
|
|
337
|
+
// renderText?: (
|
|
338
|
+
// value: string,
|
|
339
|
+
// match?: RegExpExecArray,
|
|
340
|
+
// ) => string | JSX.Element,
|
|
341
|
+
// ) => {
|
|
342
|
+
// regex.lastIndex = 0;
|
|
343
|
+
// const match = regex.exec(remaining);
|
|
344
|
+
// if (match) {
|
|
345
|
+
// const [full, inner, inner2] = match;
|
|
346
|
+
// const before = remaining.substring(0, match.index);
|
|
347
|
+
// const after = remaining.substring(match.index + full.length);
|
|
348
|
+
// if (before) elements.push(before);
|
|
349
|
+
// if (isLink) {
|
|
350
|
+
// elements.push(
|
|
351
|
+
// <Text
|
|
352
|
+
// key={`link-${index++}`}
|
|
353
|
+
// style={getMergedStyle(styleKey)}
|
|
354
|
+
// onPress={() => Linking.openURL(inner2)}
|
|
355
|
+
// >
|
|
356
|
+
// {inner}
|
|
357
|
+
// </Text>,
|
|
358
|
+
// );
|
|
359
|
+
// } else if (isColor) {
|
|
360
|
+
// // Handle color syntax :::{.color-blue}text:::
|
|
361
|
+
// const colorName = (inner || '').trim();
|
|
362
|
+
// const coloredText = (inner2 || '').trim();
|
|
363
|
+
// console.log(
|
|
364
|
+
// 'Color processing - Color:',
|
|
365
|
+
// colorName,
|
|
366
|
+
// 'Text:',
|
|
367
|
+
// coloredText,
|
|
368
|
+
// );
|
|
369
|
+
// // Get actual color value from mapping
|
|
370
|
+
// if (coloredText.length > 0) {
|
|
371
|
+
// const colorValue = COLOR_MAP[colorName.toLowerCase()] || '#000000';
|
|
372
|
+
// elements.push(
|
|
373
|
+
// <Text key={`color-${index++}`} style={{ color: colorValue }}>
|
|
374
|
+
// {coloredText}
|
|
375
|
+
// </Text>
|
|
376
|
+
// );
|
|
377
|
+
// }
|
|
378
|
+
// } else if (isHtmlTag && renderText) {
|
|
379
|
+
// const rendered = renderText(inner, match);
|
|
380
|
+
// if (typeof rendered === 'string') {
|
|
381
|
+
// elements.push(rendered);
|
|
382
|
+
// } else {
|
|
383
|
+
// elements.push(rendered);
|
|
384
|
+
// }
|
|
385
|
+
// } else {
|
|
386
|
+
// elements.push(
|
|
387
|
+
// <Text key={`styled-${index++}`} style={getMergedStyle(styleKey)}>
|
|
388
|
+
// {inner}
|
|
389
|
+
// </Text>,
|
|
390
|
+
// );
|
|
391
|
+
// }
|
|
392
|
+
// remaining = after;
|
|
393
|
+
// return true;
|
|
394
|
+
// }
|
|
395
|
+
// return false;
|
|
396
|
+
// };
|
|
397
|
+
// while (remaining.length) {
|
|
398
|
+
// const patterns = [
|
|
399
|
+
// // COLOR PATTERN FIRST
|
|
400
|
+
// {
|
|
401
|
+
// // Match lines like ::: {.color-blue}Text:::
|
|
402
|
+
// regex: /^:::\{\.color-([a-zA-Z]+)\}(.*?):::$/g,
|
|
403
|
+
// style: ['paragraph'],
|
|
404
|
+
// isColor: true,
|
|
405
|
+
// },
|
|
406
|
+
// { regex: /\*\*\*(.*?)\*\*\*/g, style: ['bold', 'italic'] },
|
|
407
|
+
// { regex: /\*\*(.*?)\*\*/g, style: ['bold'] },
|
|
408
|
+
// { regex: /_(.*?)_/g, style: ['italic'] },
|
|
409
|
+
// { regex: /`([^`]+)`/g, style: ['code'], isCode: true },
|
|
410
|
+
// { regex: /\[(.*?)\]\((.*?)\)/g, style: ['link'], isLink: true },
|
|
411
|
+
// { regex: /<b>(.*?)<\/b>/i, style: ['bold'], isHtmlTag: true },
|
|
412
|
+
// { regex: /<i>(.*?)<\/i>/i, style: ['italic'], isHtmlTag: true },
|
|
413
|
+
// { regex: /<u>(.*?)<\/u>/i, style: ['underline'], isHtmlTag: true },
|
|
414
|
+
// {
|
|
415
|
+
// regex: /<br\s*\/?>/i,
|
|
416
|
+
// style: ['paragraph'],
|
|
417
|
+
// isHtmlTag: true,
|
|
418
|
+
// renderText: () => '\n',
|
|
419
|
+
// },
|
|
420
|
+
// ];
|
|
421
|
+
// let matched = false;
|
|
422
|
+
// for (const pattern of patterns) {
|
|
423
|
+
// if (
|
|
424
|
+
// applyRegex(
|
|
425
|
+
// pattern.regex,
|
|
426
|
+
// pattern.style[0] as keyof typeof defaultStyles,
|
|
427
|
+
// pattern.isLink,
|
|
428
|
+
// pattern.isCode,
|
|
429
|
+
// pattern.isHtmlTag,
|
|
430
|
+
// pattern.isColor,
|
|
431
|
+
// pattern.renderText,
|
|
432
|
+
// )
|
|
433
|
+
// ) {
|
|
434
|
+
// matched = true;
|
|
435
|
+
// break;
|
|
436
|
+
// }
|
|
437
|
+
// }
|
|
438
|
+
// if (!matched) {
|
|
439
|
+
// elements.push(remaining);
|
|
440
|
+
// break;
|
|
441
|
+
// }
|
|
442
|
+
// }
|
|
443
|
+
// return <Text>{elements}</Text>;
|
|
444
|
+
// };
|
|
445
|
+
// const renderMarkdown = () => {
|
|
446
|
+
// const lines = content.split('\n');
|
|
447
|
+
// const result: JSX.Element[] = [];
|
|
448
|
+
// let inCodeBlock = false;
|
|
449
|
+
// let codeBlockContent: string[] = [];
|
|
450
|
+
// lines.forEach((line, index) => {
|
|
451
|
+
// if (line.trim() === '```') {
|
|
452
|
+
// inCodeBlock = !inCodeBlock;
|
|
453
|
+
// if (!inCodeBlock) {
|
|
454
|
+
// result.push(
|
|
455
|
+
// <View key={`code-${index}`} style={getMergedStyle('codeBlock')}>
|
|
456
|
+
// <Text style={getMergedStyle('code')}>
|
|
457
|
+
// {codeBlockContent.join('\n')}
|
|
458
|
+
// </Text>
|
|
459
|
+
// </View>,
|
|
460
|
+
// );
|
|
461
|
+
// codeBlockContent = [];
|
|
462
|
+
// }
|
|
463
|
+
// return;
|
|
464
|
+
// }
|
|
465
|
+
// if (inCodeBlock) {
|
|
466
|
+
// codeBlockContent.push(line);
|
|
467
|
+
// return;
|
|
468
|
+
// }
|
|
469
|
+
// const imgMatch = line.match(/!\[(.*?)\]\((.*?)\)/);
|
|
470
|
+
// if (imgMatch) {
|
|
471
|
+
// const altText = imgMatch[1];
|
|
472
|
+
// const imgPath = imgMatch[2];
|
|
473
|
+
// const source = resolveImageSource
|
|
474
|
+
// ? resolveImageSource(imgPath)
|
|
475
|
+
// : { uri: imgPath };
|
|
476
|
+
// result.push(
|
|
477
|
+
// <Image
|
|
478
|
+
// key={`img-${index}`}
|
|
479
|
+
// source={source}
|
|
480
|
+
// style={getMergedStyle('image') as StyleProp<ImageStyle>}
|
|
481
|
+
// accessibilityLabel={altText}
|
|
482
|
+
// />,
|
|
483
|
+
// );
|
|
484
|
+
// return;
|
|
485
|
+
// }
|
|
486
|
+
// const headingMatch = line.match(/^(#{1,6})\s+(.*)/);
|
|
487
|
+
// if (headingMatch) {
|
|
488
|
+
// const level = headingMatch[1].length;
|
|
489
|
+
// const headingText = headingMatch[2];
|
|
490
|
+
// const styleKey = `heading${level}` as keyof typeof defaultStyles;
|
|
491
|
+
// result.push(
|
|
492
|
+
// <Text key={`heading-${index}`} style={getMergedStyle(styleKey)}>
|
|
493
|
+
// {headingText}
|
|
494
|
+
// </Text>,
|
|
495
|
+
// );
|
|
496
|
+
// return;
|
|
497
|
+
// }
|
|
498
|
+
// if (line.startsWith('>')) {
|
|
499
|
+
// result.push(
|
|
500
|
+
// <View
|
|
501
|
+
// key={`quote-${index}`}
|
|
502
|
+
// style={getMergedStyle('blockquoteContainer')}
|
|
503
|
+
// >
|
|
504
|
+
// <Text style={getMergedStyle('blockquoteText')}>
|
|
505
|
+
// {line.replace(/^>\s?/, '')}
|
|
506
|
+
// </Text>
|
|
507
|
+
// </View>,
|
|
508
|
+
// );
|
|
509
|
+
// return;
|
|
510
|
+
// }
|
|
511
|
+
// if (line.trim().startsWith('- ')) {
|
|
512
|
+
// result.push(
|
|
513
|
+
// <View key={`list-${index}`} style={getMergedStyle('bulletRow')}>
|
|
514
|
+
// <Text style={getMergedStyle('bullet')}>{'\u2022'}</Text>
|
|
515
|
+
// <Text style={getMergedStyle('listText')}>
|
|
516
|
+
// {parseInlineMarkdown(line.replace('- ', ''))}
|
|
517
|
+
// </Text>
|
|
518
|
+
// </View>,
|
|
519
|
+
// );
|
|
520
|
+
// return;
|
|
521
|
+
// }
|
|
522
|
+
// const numberedMatch = line.trim().match(/^(\d+)\.\s+(.*)/);
|
|
523
|
+
// if (numberedMatch) {
|
|
524
|
+
// result.push(
|
|
525
|
+
// <View key={`list-num-${index}`} style={getMergedStyle('bulletRow')}>
|
|
526
|
+
// <Text style={getMergedStyle('bullet')}>
|
|
527
|
+
// {numberedMatch[1] + '.'}
|
|
528
|
+
// </Text>
|
|
529
|
+
// <Text style={getMergedStyle('listText')}>
|
|
530
|
+
// {parseInlineMarkdown(numberedMatch[2])}
|
|
531
|
+
// </Text>
|
|
532
|
+
// </View>,
|
|
533
|
+
// );
|
|
534
|
+
// return;
|
|
535
|
+
// }
|
|
536
|
+
// if (line.trim()) {
|
|
537
|
+
// result.push(
|
|
538
|
+
// <Text key={`text-${index}`} style={getMergedStyle('paragraph')}>
|
|
539
|
+
// {parseInlineMarkdown(line)}
|
|
540
|
+
// </Text>,
|
|
541
|
+
// );
|
|
542
|
+
// }
|
|
543
|
+
// });
|
|
544
|
+
// return result;
|
|
545
|
+
// };
|
|
546
|
+
// return <View>{renderMarkdown()}</View>;
|
|
547
|
+
// };
|
|
548
|
+
// export default CustomMarkdown;
|
|
549
|
+
// const defaultStyles = StyleSheet.create({
|
|
550
|
+
// paragraph: {
|
|
551
|
+
// fontSize: 16,
|
|
552
|
+
// lineHeight: 24,
|
|
553
|
+
// color: '#333',
|
|
554
|
+
// marginBottom: 8,
|
|
555
|
+
// },
|
|
556
|
+
// heading1: {
|
|
557
|
+
// fontSize: 24,
|
|
558
|
+
// fontWeight: 'bold',
|
|
559
|
+
// marginVertical: 10,
|
|
560
|
+
// },
|
|
561
|
+
// heading2: {
|
|
562
|
+
// fontSize: 22,
|
|
563
|
+
// fontWeight: 'bold',
|
|
564
|
+
// marginVertical: 8,
|
|
565
|
+
// },
|
|
566
|
+
// heading3: {
|
|
567
|
+
// fontSize: 20,
|
|
568
|
+
// fontWeight: 'bold',
|
|
569
|
+
// marginVertical: 6,
|
|
570
|
+
// },
|
|
571
|
+
// heading4: {
|
|
572
|
+
// fontSize: 18,
|
|
573
|
+
// fontWeight: 'bold',
|
|
574
|
+
// marginVertical: 4,
|
|
575
|
+
// },
|
|
576
|
+
// heading5: {
|
|
577
|
+
// fontSize: 16,
|
|
578
|
+
// fontWeight: 'bold',
|
|
579
|
+
// marginVertical: 4,
|
|
580
|
+
// },
|
|
581
|
+
// heading6: {
|
|
582
|
+
// fontSize: 14,
|
|
583
|
+
// fontWeight: 'bold',
|
|
584
|
+
// marginVertical: 2,
|
|
585
|
+
// },
|
|
586
|
+
// bold: {
|
|
587
|
+
// fontWeight: 'bold',
|
|
588
|
+
// },
|
|
589
|
+
// italic: {
|
|
590
|
+
// fontStyle: 'italic',
|
|
591
|
+
// },
|
|
592
|
+
// underline: {
|
|
593
|
+
// textDecorationLine: 'underline',
|
|
594
|
+
// },
|
|
595
|
+
// code: {
|
|
596
|
+
// backgroundColor: '#f4f4f4',
|
|
597
|
+
// padding: 4,
|
|
598
|
+
// borderRadius: 4,
|
|
599
|
+
// },
|
|
600
|
+
// codeBlock: {
|
|
601
|
+
// backgroundColor: '#eee',
|
|
602
|
+
// padding: 10,
|
|
603
|
+
// borderRadius: 6,
|
|
604
|
+
// marginVertical: 10,
|
|
605
|
+
// },
|
|
606
|
+
// blockquoteContainer: {
|
|
607
|
+
// borderLeftWidth: 4,
|
|
608
|
+
// borderLeftColor: '#ccc',
|
|
609
|
+
// paddingLeft: 10,
|
|
610
|
+
// marginVertical: 8,
|
|
611
|
+
// },
|
|
612
|
+
// blockquoteText: {
|
|
613
|
+
// fontStyle: 'italic',
|
|
614
|
+
// color: '#666',
|
|
615
|
+
// },
|
|
616
|
+
// bulletRow: {
|
|
617
|
+
// flexDirection: 'row',
|
|
618
|
+
// alignItems: 'flex-start',
|
|
619
|
+
// marginBottom: 6,
|
|
620
|
+
// },
|
|
621
|
+
// bullet: {
|
|
622
|
+
// fontSize: 16,
|
|
623
|
+
// lineHeight: 24,
|
|
624
|
+
// marginRight: 6,
|
|
625
|
+
// fontWeight: 'bold',
|
|
626
|
+
// },
|
|
627
|
+
// listText: {
|
|
628
|
+
// flex: 1,
|
|
629
|
+
// fontSize: 16,
|
|
630
|
+
// lineHeight: 24,
|
|
631
|
+
// },
|
|
632
|
+
// link: {
|
|
633
|
+
// color: '#007AFF',
|
|
634
|
+
// textDecorationLine: 'underline',
|
|
635
|
+
// },
|
|
636
|
+
// image: {
|
|
637
|
+
// width: '100%',
|
|
638
|
+
// height: 200,
|
|
639
|
+
// resizeMode: 'contain',
|
|
640
|
+
// marginVertical: 10,
|
|
641
|
+
// },
|
|
642
|
+
// });
|
|
6
643
|
const react_1 = __importDefault(require("react"));
|
|
7
644
|
const react_native_1 = require("react-native");
|
|
645
|
+
// Optional color map (Kept for convenience, allowing names like 'red')
|
|
646
|
+
const COLOR_MAP = {
|
|
647
|
+
blue: '#007AFF',
|
|
648
|
+
red: '#FF3B30',
|
|
649
|
+
green: '#34C759',
|
|
650
|
+
orange: '#FF9500',
|
|
651
|
+
yellow: '#FFCC00',
|
|
652
|
+
purple: '#5856D6',
|
|
653
|
+
pink: '#FF2D55',
|
|
654
|
+
brown: '#A2845E',
|
|
655
|
+
black: '#000000',
|
|
656
|
+
white: '#FFFFFF',
|
|
657
|
+
gray: '#8E8E93',
|
|
658
|
+
};
|
|
659
|
+
// --- Component ---
|
|
8
660
|
const CustomMarkdown = ({ content, styles = {}, resolveImageSource, }) => {
|
|
661
|
+
// We need to keep a consistent index for key generation across recursive calls
|
|
662
|
+
let globalIndex = 0;
|
|
9
663
|
const getMergedStyle = (key) => {
|
|
10
664
|
return [defaultStyles[key], styles[key]];
|
|
11
665
|
};
|
|
666
|
+
/** Parses inline markdown and supports <color style="#xxxxxx">text</color> */
|
|
12
667
|
const parseInlineMarkdown = (text) => {
|
|
13
668
|
const elements = [];
|
|
14
669
|
let remaining = text;
|
|
15
|
-
|
|
16
|
-
|
|
670
|
+
// local index is used for array iteration, globalIndex for unique React keys
|
|
671
|
+
let localIndex = 0;
|
|
672
|
+
const applyRegex = (regex, styleKey, options = {}) => {
|
|
673
|
+
// Ensure the regex is not global or reset its index if it is
|
|
674
|
+
regex.lastIndex = 0;
|
|
17
675
|
const match = regex.exec(remaining);
|
|
18
676
|
if (match) {
|
|
19
|
-
|
|
677
|
+
// group1 is the first captured group, group2 is the second (if present)
|
|
678
|
+
const [full, group1, group2] = match;
|
|
20
679
|
const before = remaining.substring(0, match.index);
|
|
21
680
|
const after = remaining.substring(match.index + full.length);
|
|
22
|
-
if (before)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
681
|
+
if (before) {
|
|
682
|
+
// Recursively parse the text before the match to ensure correct order
|
|
683
|
+
const beforeContent = parseInlineMarkdown(before).props.children;
|
|
684
|
+
if (Array.isArray(beforeContent)) {
|
|
685
|
+
elements.push(...beforeContent);
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
elements.push(beforeContent);
|
|
689
|
+
}
|
|
28
690
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
691
|
+
if (options.isLink) {
|
|
692
|
+
// Standard Markdown Link: [text](url) -> group1=text, group2=url
|
|
693
|
+
elements.push(<react_native_1.Text key={`link-${globalIndex++}`} style={getMergedStyle(styleKey)} onPress={() => react_native_1.Linking.openURL(group2)}>
|
|
694
|
+
{group1}
|
|
32
695
|
</react_native_1.Text>);
|
|
33
696
|
}
|
|
697
|
+
else if (options.isHtmlTag && options.renderText) {
|
|
698
|
+
// Custom HTML Tags (like <color>, <b>, <br/>)
|
|
699
|
+
const rendered = options.renderText(group1, match);
|
|
700
|
+
elements.push(rendered);
|
|
701
|
+
}
|
|
34
702
|
else {
|
|
35
|
-
|
|
36
|
-
|
|
703
|
+
// Standard Markdown (Bold, Italic, Code) -> group1=content
|
|
704
|
+
elements.push(<react_native_1.Text key={`styled-${globalIndex++}`} style={getMergedStyle(styleKey)}>
|
|
705
|
+
{group1}
|
|
37
706
|
</react_native_1.Text>);
|
|
38
707
|
}
|
|
39
708
|
remaining = after;
|
|
@@ -43,24 +712,71 @@ const CustomMarkdown = ({ content, styles = {}, resolveImageSource, }) => {
|
|
|
43
712
|
};
|
|
44
713
|
while (remaining.length) {
|
|
45
714
|
const patterns = [
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
715
|
+
// 1. Custom Color Tag with Nested Parsing Support (Highest Priority)
|
|
716
|
+
// match[1] = Quote
|
|
717
|
+
// match[2] = Color value (e.g., "#007AFF" or "red")
|
|
718
|
+
// match[3] = Text content (e.g., "Hello **World**")
|
|
719
|
+
{
|
|
720
|
+
regex: /<color\s+style\s*=\s*(["'])(.*?)\1\s*>([\s\S]*?)<\/color>/i,
|
|
721
|
+
style: 'paragraph',
|
|
722
|
+
options: {
|
|
723
|
+
isHtmlTag: true,
|
|
724
|
+
renderText: (_, match) => {
|
|
725
|
+
const colorAttribute = match ? match[2] : 'black';
|
|
726
|
+
const textContent = match ? match[3] : '';
|
|
727
|
+
const colorValue = COLOR_MAP[colorAttribute.toLowerCase()] || colorAttribute;
|
|
728
|
+
// Recursive call: Correctly parse content and extract its children
|
|
729
|
+
const nestedResult = parseInlineMarkdown(textContent).props.children;
|
|
730
|
+
return (<react_native_1.Text key={`color-${globalIndex++}`} style={{ color: colorValue }}>
|
|
731
|
+
{nestedResult}
|
|
732
|
+
</react_native_1.Text>);
|
|
733
|
+
},
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
// 2. Strong/Emphasis Markdown
|
|
737
|
+
{ regex: /\*\*\*(.*?)\*\*\*/g, style: 'bold', options: {} },
|
|
738
|
+
{ regex: /\*\*(.*?)\*\*/g, style: 'bold', options: {} },
|
|
739
|
+
{ regex: /_(.*?)_/g, style: 'italic', options: {} },
|
|
740
|
+
// 3. Code and Links
|
|
741
|
+
{ regex: /`([^`]+)`/g, style: 'code', options: {} },
|
|
742
|
+
{ regex: /\[(.*?)\]\((.*?)\)/g, style: 'link', options: { isLink: true } },
|
|
743
|
+
// 4. Other HTML Tags (FIXED: Explicitly typed 'value' as string)
|
|
744
|
+
{
|
|
745
|
+
regex: /<b>(.*?)<\/b>/i,
|
|
746
|
+
style: 'bold',
|
|
747
|
+
options: {
|
|
748
|
+
isHtmlTag: true,
|
|
749
|
+
renderText: (value) => (<react_native_1.Text key={`b-${globalIndex++}`} style={getMergedStyle('bold')}>{value}</react_native_1.Text>),
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
regex: /<i>(.*?)<\/i>/i,
|
|
754
|
+
style: 'italic',
|
|
755
|
+
options: {
|
|
756
|
+
isHtmlTag: true,
|
|
757
|
+
renderText: (value) => (<react_native_1.Text key={`i-${globalIndex++}`} style={getMergedStyle('italic')}>{value}</react_native_1.Text>),
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
regex: /<u>(.*?)<\/u>/i,
|
|
762
|
+
style: 'underline',
|
|
763
|
+
options: {
|
|
764
|
+
isHtmlTag: true,
|
|
765
|
+
renderText: (value) => (<react_native_1.Text key={`u-${globalIndex++}`} style={getMergedStyle('underline')}>{value}</react_native_1.Text>),
|
|
766
|
+
},
|
|
767
|
+
},
|
|
54
768
|
{
|
|
55
769
|
regex: /<br\s*\/?>/i,
|
|
56
|
-
style:
|
|
57
|
-
|
|
58
|
-
|
|
770
|
+
style: 'paragraph',
|
|
771
|
+
options: {
|
|
772
|
+
isHtmlTag: true,
|
|
773
|
+
renderText: () => '\n',
|
|
774
|
+
},
|
|
59
775
|
},
|
|
60
776
|
];
|
|
61
777
|
let matched = false;
|
|
62
778
|
for (const pattern of patterns) {
|
|
63
|
-
if (applyRegex(pattern.regex, pattern.style
|
|
779
|
+
if (applyRegex(pattern.regex, pattern.style, pattern.options)) {
|
|
64
780
|
matched = true;
|
|
65
781
|
break;
|
|
66
782
|
}
|
|
@@ -70,21 +786,23 @@ const CustomMarkdown = ({ content, styles = {}, resolveImageSource, }) => {
|
|
|
70
786
|
break;
|
|
71
787
|
}
|
|
72
788
|
}
|
|
73
|
-
|
|
789
|
+
// We use a local index for the final wrapping Text component key
|
|
790
|
+
return <react_native_1.Text key={`inline-wrapper-${localIndex++}`}>{elements}</react_native_1.Text>;
|
|
74
791
|
};
|
|
792
|
+
/** Parses block-level markdown lines */
|
|
75
793
|
const renderMarkdown = () => {
|
|
76
794
|
const lines = content.split('\n');
|
|
77
795
|
const result = [];
|
|
78
796
|
let inCodeBlock = false;
|
|
79
797
|
let codeBlockContent = [];
|
|
798
|
+
let blockIndex = 0; // Use a dedicated index for block-level elements
|
|
80
799
|
lines.forEach((line, index) => {
|
|
800
|
+
// Handle code blocks
|
|
81
801
|
if (line.trim() === '```') {
|
|
82
802
|
inCodeBlock = !inCodeBlock;
|
|
83
803
|
if (!inCodeBlock) {
|
|
84
|
-
result.push(<react_native_1.View key={`code-${
|
|
85
|
-
<react_native_1.Text style={getMergedStyle('code')}>
|
|
86
|
-
{codeBlockContent.join('\n')}
|
|
87
|
-
</react_native_1.Text>
|
|
804
|
+
result.push(<react_native_1.View key={`code-block-${blockIndex++}`} style={getMergedStyle('codeBlock')}>
|
|
805
|
+
<react_native_1.Text style={getMergedStyle('code')}>{codeBlockContent.join('\n')}</react_native_1.Text>
|
|
88
806
|
</react_native_1.View>);
|
|
89
807
|
codeBlockContent = [];
|
|
90
808
|
}
|
|
@@ -94,115 +812,38 @@ const CustomMarkdown = ({ content, styles = {}, resolveImageSource, }) => {
|
|
|
94
812
|
codeBlockContent.push(line);
|
|
95
813
|
return;
|
|
96
814
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const altText = imgMatch[1];
|
|
100
|
-
const imgPath = imgMatch[2];
|
|
101
|
-
const source = resolveImageSource
|
|
102
|
-
? resolveImageSource(imgPath)
|
|
103
|
-
: { uri: imgPath };
|
|
104
|
-
result.push(<react_native_1.Image key={`img-${index}`} source={source} style={getMergedStyle('image')} accessibilityLabel={altText}/>);
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
const headingMatch = line.match(/^(#{1,6})\s+(.*)/);
|
|
108
|
-
if (headingMatch) {
|
|
109
|
-
const level = headingMatch[1].length;
|
|
110
|
-
const headingText = headingMatch[2];
|
|
111
|
-
const styleKey = `heading${level}`;
|
|
112
|
-
result.push(<react_native_1.Text key={`heading-${index}`} style={getMergedStyle(styleKey)}>
|
|
113
|
-
{headingText}
|
|
114
|
-
</react_native_1.Text>);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (line.startsWith('>')) {
|
|
118
|
-
result.push(<react_native_1.View key={`quote-${index}`} style={getMergedStyle('blockquoteContainer')}>
|
|
119
|
-
<react_native_1.Text style={getMergedStyle('blockquoteText')}>
|
|
120
|
-
{line.replace(/^>\s?/, '')}
|
|
121
|
-
</react_native_1.Text>
|
|
122
|
-
</react_native_1.View>);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
if (line.trim().startsWith('- ')) {
|
|
126
|
-
result.push(<react_native_1.View key={`list-${index}`} style={getMergedStyle('bulletRow')}>
|
|
127
|
-
<react_native_1.Text style={getMergedStyle('bullet')}>{'\u2022'}</react_native_1.Text>
|
|
128
|
-
<react_native_1.Text style={getMergedStyle('listText')}>
|
|
129
|
-
{parseInlineMarkdown(line.replace('- ', ''))}
|
|
130
|
-
</react_native_1.Text>
|
|
131
|
-
</react_native_1.View>);
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
const numberedMatch = line.trim().match(/^(\d+)\.\s+(.*)/);
|
|
135
|
-
if (numberedMatch) {
|
|
136
|
-
result.push(<react_native_1.View key={`list-num-${index}`} style={getMergedStyle('bulletRow')}>
|
|
137
|
-
<react_native_1.Text style={getMergedStyle('bullet')}>{numberedMatch[1] + '.'}</react_native_1.Text>
|
|
138
|
-
<react_native_1.Text style={getMergedStyle('listText')}>
|
|
139
|
-
{parseInlineMarkdown(numberedMatch[2])}
|
|
140
|
-
</react_native_1.Text>
|
|
141
|
-
</react_native_1.View>);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
815
|
+
// ... (other block-level logic like images, headings, etc. using parseInlineMarkdown) ...
|
|
816
|
+
// Handle paragraph
|
|
144
817
|
if (line.trim()) {
|
|
145
|
-
result.push(<react_native_1.Text key={`text-${
|
|
818
|
+
result.push(<react_native_1.Text key={`text-${blockIndex++}`} style={getMergedStyle('paragraph')}>
|
|
146
819
|
{parseInlineMarkdown(line)}
|
|
147
820
|
</react_native_1.Text>);
|
|
148
821
|
}
|
|
822
|
+
else {
|
|
823
|
+
// Handle empty lines for spacing
|
|
824
|
+
result.push(<react_native_1.Text key={`spacer-${blockIndex++}`}>{'\n'}</react_native_1.Text>);
|
|
825
|
+
}
|
|
149
826
|
});
|
|
150
827
|
return result;
|
|
151
828
|
};
|
|
152
|
-
return <react_native_1.View>{renderMarkdown()}</react_native_1.View>;
|
|
829
|
+
return <react_native_1.View style={getMergedStyle('container')}>{renderMarkdown()}</react_native_1.View>;
|
|
153
830
|
};
|
|
154
|
-
|
|
831
|
+
// --- Default Styles (MUST be defined for the component to work) ---
|
|
155
832
|
const defaultStyles = react_native_1.StyleSheet.create({
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
lineHeight: 24,
|
|
159
|
-
color: '#333',
|
|
160
|
-
marginBottom: 8,
|
|
161
|
-
},
|
|
162
|
-
heading1: {
|
|
163
|
-
fontSize: 24,
|
|
164
|
-
fontWeight: 'bold',
|
|
165
|
-
marginVertical: 10,
|
|
166
|
-
},
|
|
167
|
-
heading2: {
|
|
168
|
-
fontSize: 22,
|
|
169
|
-
fontWeight: 'bold',
|
|
170
|
-
marginVertical: 8,
|
|
171
|
-
},
|
|
172
|
-
heading3: {
|
|
173
|
-
fontSize: 20,
|
|
174
|
-
fontWeight: 'bold',
|
|
175
|
-
marginVertical: 6,
|
|
176
|
-
},
|
|
177
|
-
heading4: {
|
|
178
|
-
fontSize: 18,
|
|
179
|
-
fontWeight: 'bold',
|
|
180
|
-
marginVertical: 4,
|
|
181
|
-
},
|
|
182
|
-
heading5: {
|
|
183
|
-
fontSize: 16,
|
|
184
|
-
fontWeight: 'bold',
|
|
185
|
-
marginVertical: 4,
|
|
186
|
-
},
|
|
187
|
-
heading6: {
|
|
188
|
-
fontSize: 14,
|
|
189
|
-
fontWeight: 'bold',
|
|
190
|
-
marginVertical: 2,
|
|
191
|
-
},
|
|
192
|
-
bold: {
|
|
193
|
-
fontWeight: 'bold',
|
|
194
|
-
},
|
|
195
|
-
italic: {
|
|
196
|
-
fontStyle: 'italic',
|
|
197
|
-
},
|
|
198
|
-
underline: {
|
|
199
|
-
textDecorationLine: 'underline',
|
|
200
|
-
},
|
|
201
|
-
code: {
|
|
202
|
-
backgroundColor: '#f4f4f4',
|
|
203
|
-
padding: 4,
|
|
204
|
-
borderRadius: 4,
|
|
833
|
+
container: {
|
|
834
|
+
// Add a container style if needed
|
|
205
835
|
},
|
|
836
|
+
paragraph: { fontSize: 16, lineHeight: 24, color: '#333', marginBottom: 8 },
|
|
837
|
+
heading1: { fontSize: 24, fontWeight: 'bold', marginVertical: 10 },
|
|
838
|
+
heading2: { fontSize: 22, fontWeight: 'bold', marginVertical: 8 },
|
|
839
|
+
heading3: { fontSize: 20, fontWeight: 'bold', marginVertical: 6 },
|
|
840
|
+
heading4: { fontSize: 18, fontWeight: 'bold', marginVertical: 4 },
|
|
841
|
+
heading5: { fontSize: 16, fontWeight: 'bold', marginVertical: 4 },
|
|
842
|
+
heading6: { fontSize: 14, fontWeight: 'bold', marginVertical: 2 },
|
|
843
|
+
bold: { fontWeight: 'bold' },
|
|
844
|
+
italic: { fontStyle: 'italic' },
|
|
845
|
+
underline: { textDecorationLine: 'underline' },
|
|
846
|
+
code: { backgroundColor: '#f4f4f4', padding: 4, borderRadius: 4 },
|
|
206
847
|
codeBlock: {
|
|
207
848
|
backgroundColor: '#eee',
|
|
208
849
|
padding: 10,
|
|
@@ -215,30 +856,11 @@ const defaultStyles = react_native_1.StyleSheet.create({
|
|
|
215
856
|
paddingLeft: 10,
|
|
216
857
|
marginVertical: 8,
|
|
217
858
|
},
|
|
218
|
-
blockquoteText: {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
},
|
|
222
|
-
|
|
223
|
-
flexDirection: 'row',
|
|
224
|
-
alignItems: 'flex-start',
|
|
225
|
-
marginBottom: 6,
|
|
226
|
-
},
|
|
227
|
-
bullet: {
|
|
228
|
-
fontSize: 16,
|
|
229
|
-
lineHeight: 24,
|
|
230
|
-
marginRight: 6,
|
|
231
|
-
fontWeight: 'bold',
|
|
232
|
-
},
|
|
233
|
-
listText: {
|
|
234
|
-
flex: 1,
|
|
235
|
-
fontSize: 16,
|
|
236
|
-
lineHeight: 24,
|
|
237
|
-
},
|
|
238
|
-
link: {
|
|
239
|
-
color: '#007AFF',
|
|
240
|
-
textDecorationLine: 'underline',
|
|
241
|
-
},
|
|
859
|
+
blockquoteText: { fontStyle: 'italic', color: '#666' },
|
|
860
|
+
bulletRow: { flexDirection: 'row', alignItems: 'flex-start', marginBottom: 6 },
|
|
861
|
+
bullet: { fontSize: 16, lineHeight: 24, marginRight: 6, fontWeight: 'bold' },
|
|
862
|
+
listText: { flex: 1, fontSize: 16, lineHeight: 24 },
|
|
863
|
+
link: { color: '#007AFF', textDecorationLine: 'underline' },
|
|
242
864
|
image: {
|
|
243
865
|
width: '100%',
|
|
244
866
|
height: 200,
|
|
@@ -246,3 +868,4 @@ const defaultStyles = react_native_1.StyleSheet.create({
|
|
|
246
868
|
marginVertical: 10,
|
|
247
869
|
},
|
|
248
870
|
});
|
|
871
|
+
exports.default = CustomMarkdown;
|