react-native-marked 8.2.0 → 8.3.1

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.
Files changed (94) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +374 -354
  3. package/dist/commonjs/components/MDImage.js +3 -3
  4. package/dist/commonjs/components/MDImage.js.map +1 -1
  5. package/dist/commonjs/components/MDList.js.map +1 -1
  6. package/dist/commonjs/components/MDSvg.js.map +1 -1
  7. package/dist/commonjs/components/MDTable.js.map +1 -1
  8. package/dist/commonjs/hooks/useMarkdown.js +4 -2
  9. package/dist/commonjs/hooks/useMarkdown.js.map +1 -1
  10. package/dist/commonjs/hooks/useMarkdownWithComponents.js +7 -1
  11. package/dist/commonjs/hooks/useMarkdownWithComponents.js.map +1 -1
  12. package/dist/commonjs/index.js.map +1 -1
  13. package/dist/commonjs/lib/Markdown.js +4 -2
  14. package/dist/commonjs/lib/Markdown.js.map +1 -1
  15. package/dist/commonjs/lib/Parser.js +7 -7
  16. package/dist/commonjs/lib/Parser.js.map +1 -1
  17. package/dist/commonjs/lib/ReactComponentRegistry.js.map +1 -1
  18. package/dist/commonjs/lib/ReactComponentTokenizer.js.map +1 -1
  19. package/dist/commonjs/lib/Renderer.js +7 -5
  20. package/dist/commonjs/lib/Renderer.js.map +1 -1
  21. package/dist/commonjs/lib/types.js.map +1 -1
  22. package/dist/commonjs/theme/colors.js.map +1 -1
  23. package/dist/commonjs/theme/spacing.js.map +1 -1
  24. package/dist/commonjs/theme/styles.js +4 -0
  25. package/dist/commonjs/theme/styles.js.map +1 -1
  26. package/dist/commonjs/theme/types.js.map +1 -1
  27. package/dist/commonjs/utils/handlers.js.map +1 -1
  28. package/dist/commonjs/utils/svg.js.map +1 -1
  29. package/dist/commonjs/utils/table.js.map +1 -1
  30. package/dist/commonjs/utils/url.js.map +1 -1
  31. package/dist/module/components/MDImage.js +3 -3
  32. package/dist/module/components/MDImage.js.map +1 -1
  33. package/dist/module/components/MDList.js.map +1 -1
  34. package/dist/module/components/MDSvg.js.map +1 -1
  35. package/dist/module/components/MDTable.js.map +1 -1
  36. package/dist/module/hooks/useMarkdown.js +4 -2
  37. package/dist/module/hooks/useMarkdown.js.map +1 -1
  38. package/dist/module/hooks/useMarkdownWithComponents.js +7 -1
  39. package/dist/module/hooks/useMarkdownWithComponents.js.map +1 -1
  40. package/dist/module/index.js.map +1 -1
  41. package/dist/module/lib/Markdown.js +4 -2
  42. package/dist/module/lib/Markdown.js.map +1 -1
  43. package/dist/module/lib/Parser.js +7 -7
  44. package/dist/module/lib/Parser.js.map +1 -1
  45. package/dist/module/lib/ReactComponentRegistry.js.map +1 -1
  46. package/dist/module/lib/ReactComponentTokenizer.js.map +1 -1
  47. package/dist/module/lib/Renderer.js +7 -5
  48. package/dist/module/lib/Renderer.js.map +1 -1
  49. package/dist/module/lib/types.js.map +1 -1
  50. package/dist/module/theme/colors.js.map +1 -1
  51. package/dist/module/theme/spacing.js.map +1 -1
  52. package/dist/module/theme/styles.js +4 -0
  53. package/dist/module/theme/styles.js.map +1 -1
  54. package/dist/module/theme/types.js.map +1 -1
  55. package/dist/module/utils/handlers.js.map +1 -1
  56. package/dist/module/utils/svg.js.map +1 -1
  57. package/dist/module/utils/table.js.map +1 -1
  58. package/dist/module/utils/url.js.map +1 -1
  59. package/dist/typescript/hooks/useMarkdown.d.ts +3 -0
  60. package/dist/typescript/hooks/useMarkdown.d.ts.map +1 -1
  61. package/dist/typescript/hooks/useMarkdownWithComponents.d.ts.map +1 -1
  62. package/dist/typescript/index.d.ts +2 -2
  63. package/dist/typescript/index.d.ts.map +1 -1
  64. package/dist/typescript/lib/Markdown.d.ts +1 -1
  65. package/dist/typescript/lib/Markdown.d.ts.map +1 -1
  66. package/dist/typescript/lib/Renderer.d.ts +8 -1
  67. package/dist/typescript/lib/Renderer.d.ts.map +1 -1
  68. package/dist/typescript/lib/types.d.ts +6 -0
  69. package/dist/typescript/lib/types.d.ts.map +1 -1
  70. package/dist/typescript/theme/styles.d.ts.map +1 -1
  71. package/dist/typescript/theme/types.d.ts +1 -0
  72. package/dist/typescript/theme/types.d.ts.map +1 -1
  73. package/package.json +178 -175
  74. package/src/components/MDImage.tsx +90 -90
  75. package/src/components/MDList.tsx +46 -46
  76. package/src/components/MDSvg.tsx +108 -108
  77. package/src/components/MDTable.tsx +60 -60
  78. package/src/hooks/useMarkdown.ts +56 -51
  79. package/src/hooks/useMarkdownWithComponents.tsx +94 -89
  80. package/src/index.ts +44 -43
  81. package/src/lib/Markdown.tsx +55 -53
  82. package/src/lib/Parser.tsx +316 -316
  83. package/src/lib/ReactComponentRegistry.tsx +52 -52
  84. package/src/lib/ReactComponentTokenizer.ts +149 -149
  85. package/src/lib/Renderer.tsx +247 -238
  86. package/src/lib/types.ts +93 -87
  87. package/src/theme/colors.ts +31 -31
  88. package/src/theme/spacing.ts +10 -10
  89. package/src/theme/styles.ts +206 -198
  90. package/src/theme/types.ts +34 -33
  91. package/src/utils/handlers.ts +9 -9
  92. package/src/utils/svg.ts +14 -14
  93. package/src/utils/table.ts +29 -29
  94. package/src/utils/url.ts +22 -22
package/README.md CHANGED
@@ -1,354 +1,374 @@
1
- # react-native-marked
2
-
3
- [![GitHub license](https://img.shields.io/github/license/gmsgowtham/react-native-marked)](https://github.com/gmsgowtham/react-native-marked/blob/main/LICENSE)
4
- [![CI](https://github.com/gmsgowtham/react-native-marked/actions/workflows/build.yml/badge.svg)](https://github.com/gmsgowtham/react-native-marked/actions/workflows/build.yml)
5
- [![Coverage Status](https://coveralls.io/repos/github/gmsgowtham/react-native-marked/badge.svg?branch=main)](https://coveralls.io/github/gmsgowtham/react-native-marked?branch=main)
6
- [![npm](https://img.shields.io/npm/v/react-native-marked)](https://www.npmjs.com/package/react-native-marked)
7
- [![npm](https://img.shields.io/npm/dw/react-native-marked)](https://www.npmjs.com/package/react-native-marked)
8
-
9
- Markdown renderer for React Native powered by
10
- [marked.js](https://marked.js.org/) with built-in theming support
11
-
12
- ## Installation
13
-
14
- #### For React Native 0.76 and above, please use the latest version.
15
- ```sh
16
- yarn add react-native-marked react-native-svg
17
- ```
18
-
19
- #### For React Native 0.75 and below, please use version 6.
20
- ```sh
21
- yarn add react-native-marked@6.0.7 react-native-svg
22
- ```
23
-
24
- ## Usage
25
-
26
- ### Using Component
27
-
28
- ```tsx
29
- import * as React from "react";
30
- import Markdown from "react-native-marked";
31
-
32
- const ExampleComponent = () => {
33
- return (
34
- <Markdown
35
- value={`# Hello world`}
36
- flatListProps={{
37
- initialNumToRender: 8,
38
- }}
39
- />
40
- );
41
- };
42
-
43
- export default ExampleComponent;
44
- ```
45
-
46
- #### [Props](https://github.com/gmsgowtham/react-native-marked/blob/main/src/lib/types.ts#L17)
47
-
48
- | Prop | Description | Type | Optional? |
49
- |---------------|----------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|
50
- | value | Markdown value | string | false |
51
- | flatListProps | Props for customizing the underlying FlatList used | `Omit<FlatListProps<ReactNode>, 'data' \| 'renderItem' \| 'horizontal'>`<br><br><br>(`'data'`, `'renderItem'`, and `'horizontal'` props are omitted and cannot be overridden.) | true |
52
- | styles | Styles for parsed components | [MarkedStyles](src/theme/types.ts) | true |
53
- | theme | Props for customizing colors and spacing for all components,and it will get overridden with custom component style applied via 'styles' prop | [UserTheme](src/theme/types.ts) | true |
54
- | baseUrl | A prefix url for any relative link | string | true |
55
- | renderer | Custom component Renderer | [RendererInterface](src/lib/types.ts) | true |
56
- | hooks | Hooks run during parsing to transform tokens | [Marked Hooks](https://marked.js.org/using_pro#hooks) | true |
57
-
58
-
59
- ### Using hook
60
-
61
- `useMarkdown` hook will return list of elements that can be rendered using a list component of your choice.
62
-
63
- ```tsx
64
- import React, { Fragment } from "react";
65
- import { ScrollView, useColorScheme } from "react-native";
66
- import { useMarkdown, type useMarkdownHookOptions } from "react-native-marked";
67
-
68
- const CustomComponent = () => {
69
- const colorScheme = useColorScheme();
70
- const options: useMarkdownHookOptions = {
71
- colorScheme
72
- }
73
- const elements = useMarkdown("# Hello world", options);
74
- return (
75
- <ScrollView>
76
- {elements.map((element, index) => {
77
- return <Fragment key={`demo_${index}`}>{element}</Fragment>
78
- })}
79
- </ScrollView>
80
- );
81
- };
82
- ```
83
-
84
- #### Options
85
-
86
- | Option | Description | Type | Optional? |
87
- |-------------|----------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------|-----------|
88
- | colorScheme | Device color scheme ("dark" or "light") | ColorSchemeName | false |
89
- | styles | Styles for parsed components | [MarkedStyles](src/theme/types.ts) | true |
90
- | theme | Props for customizing colors and spacing for all components,and it will get overridden with custom component style applied via 'styles' prop | [UserTheme](src/theme/types.ts) | true |
91
- | baseUrl | A prefix url for any relative link | string | true |
92
- | renderer | Custom component Renderer | [RendererInterface](src/lib/types.ts) | true |
93
- | tokenizer | Generate custom tokens | [MarkedTokenizer<CustomToken>](src/lib/types.ts) | true |
94
- | hooks | Hooks run during parsing to transform tokens |
95
- [Marked Hooks](https://marked.js.org/using_pro#hooks) | true |
96
-
97
-
98
- ## Examples
99
-
100
- - CodeSandbox: https://codesandbox.io/s/react-native-marked-l2hpi3?file=/src/App.js
101
-
102
- ## Supported elements
103
-
104
- - [x] Headings (1 to 6)
105
- - [x] Paragraph
106
- - [x] Emphasis (bold, italic, and strikethrough)
107
- - [x] Link
108
- - [x] Image
109
- - [x] Blockquote
110
- - [x] Inline Code
111
- - [x] Code Block
112
- - [x] List (ordered, unordered)
113
- - [x] Horizontal Rule
114
- - [x] Table
115
- - [x] React Components (via `useMarkdownWithComponents`)
116
- - [ ] HTML
117
-
118
- Ref: [CommonMark](https://commonmark.org/help/)
119
-
120
- > HTML will be treated as plain text. Please refer [issue#290](https://github.com/gmsgowtham/react-native-marked/issues/290) for a potential solution
121
-
122
- ## Advanced
123
-
124
- ### Embedding React Components in Markdown
125
-
126
- You can embed React components directly in your markdown using JSX-style syntax. This is useful for adding interactive elements like buttons, custom info boxes, or any other React component.
127
-
128
- ```tsx
129
- import React, { Fragment } from "react";
130
- import { Pressable, ScrollView, Text, View } from "react-native";
131
- import {
132
- ReactComponentRegistryProvider,
133
- useMarkdownWithComponents,
134
- type ReactComponentRegistry,
135
- } from "react-native-marked";
136
-
137
- // Define your components
138
- const components: ReactComponentRegistry = {
139
- Button: ({ props }) => (
140
- <Pressable onPress={() => console.log("Pressed!")}>
141
- <Text>{String(props.label ?? "Click me")}</Text>
142
- </Pressable>
143
- ),
144
- InfoBox: ({ props, children }) => (
145
- <View style={{ backgroundColor: "#E3F2FD", padding: 16 }}>
146
- {props.title && <Text style={{ fontWeight: "bold" }}>{String(props.title)}</Text>}
147
- <Text>{children}</Text>
148
- </View>
149
- ),
150
- };
151
-
152
- const markdown = `
153
- # Hello World
154
-
155
- Click the button below:
156
-
157
- <Button label="Get Started" />
158
-
159
- <InfoBox title="Note">
160
- This is an info box with **markdown** content.
161
- </InfoBox>
162
- `;
163
-
164
- function MarkdownContent() {
165
- const elements = useMarkdownWithComponents(markdown);
166
- return (
167
- <ScrollView>
168
- {elements.map((element, index) => (
169
- <Fragment key={index}>{element}</Fragment>
170
- ))}
171
- </ScrollView>
172
- );
173
- }
174
-
175
- export default function App() {
176
- return (
177
- <ReactComponentRegistryProvider components={components}>
178
- <MarkdownContent />
179
- </ReactComponentRegistryProvider>
180
- );
181
- }
182
- ```
183
-
184
- #### Component Syntax
185
-
186
- - **Self-closing:** `<ComponentName prop="value" />`
187
- - **With children:** `<ComponentName>content</ComponentName>`
188
- - **Props:** Supports string (`"value"`), number (`{42}`), and boolean (`{true}`) props
189
-
190
- #### Component Registry
191
-
192
- Components must be registered via `ReactComponentRegistryProvider`. Unregistered components are automatically removed from the output.
193
-
194
- ### Using custom components
195
-
196
- > Custom components can be used to override elements, i.e. Code Highlighting, Fast Image integration
197
-
198
- #### Example
199
-
200
- ```tsx
201
- import React, { ReactNode, Fragment } from "react";
202
- import { Text, ScrollView } from "react-native";
203
- import type { ImageStyle, TextStyle } from "react-native";
204
- import Markdown, { Renderer, useMarkdown } from "react-native-marked";
205
- import type { RendererInterface } from "react-native-marked";
206
- import FastImage from "react-native-fast-image";
207
-
208
- class CustomRenderer extends Renderer implements RendererInterface {
209
- constructor() {
210
- super();
211
- }
212
-
213
- codespan(text: string, _styles?: TextStyle): ReactNode {
214
- return (
215
- <Text key={this.getKey()} style={{ backgroundColor: "#ff0000" }}>
216
- {text}
217
- </Text>
218
- );
219
- }
220
-
221
- image(uri: string, _alt?: string, _style?: ImageStyle): ReactNode {
222
- return (
223
- <FastImage
224
- key={this.getKey()}
225
- style={{ width: 200, height: 200 }}
226
- source={{ uri: uri }}
227
- resizeMode={FastImage.resizeMode.contain}
228
- />
229
- );
230
- }
231
- }
232
-
233
- const renderer = new CustomRenderer();
234
-
235
- const ExampleComponent = () => {
236
- return (
237
- <Markdown
238
- value={"`Hello world`"}
239
- flatListProps={{
240
- initialNumToRender: 8,
241
- }}
242
- renderer={renderer}
243
- />
244
- );
245
- };
246
-
247
- // Alternate using hook
248
- const ExampleComponentWithHook = () => {
249
- const elements = useMarkdown("`Hello world`", { renderer });
250
-
251
- return (
252
- <ScrollView>
253
- {elements.map((element, index) => {
254
- return <Fragment key={`demo_${index}`}>{element}</Fragment>
255
- })}
256
- </ScrollView>
257
- )
258
- }
259
-
260
- export default ExampleComponent;
261
- ```
262
-
263
- > Please refer to [RendererInterface](src/lib/types.ts) for all the overrides
264
-
265
- > Note:
266
- >
267
- > For `key` property for a component, you can use the `getKey` method from Renderer class.
268
-
269
- #### Example
270
-
271
- Overriding default codespan tokenizer to include LaTeX.
272
-
273
- ```tsx
274
-
275
- import React, { ReactNode } from "react";
276
- import Markdown, { Renderer, MarkedTokenizer, MarkedLexer } from "react-native-marked";
277
- import type { RendererInterface, CustomToken } from "react-native-marked";
278
-
279
- class CustomTokenizer extends Tokenizer {
280
- codespan(src: string): Tokens.Codespan | undefined {
281
- const match = src.match(/^\$+([^\$\n]+?)\$+/);
282
- if (match?.[1]) {
283
- return {
284
- type: "codespan",
285
- raw: match[0],
286
- text: match[1].trim(),
287
- };
288
- }
289
-
290
- return super.codespan(src);
291
- }
292
- }
293
-
294
- class CustomRenderer extends Renderer implements RendererInterface {
295
- codespan(text: string, styles?: TextStyle): ReactNode {
296
- return (
297
- <Text style={styles} key={"key-1"}>
298
- {text}
299
- </Text>
300
- )
301
- }
302
- }
303
-
304
- const renderer = new CustomRenderer();
305
- const tokenizer = new CustomTokenizer();
306
-
307
- const ExampleComponent = () => {
308
- return (
309
- <Markdown
310
- value={"$ latex code $\n\n` other code `"}
311
- flatListProps={{
312
- initialNumToRender: 8,
313
- }}
314
- renderer={renderer}
315
- tokenizer={tokenizer}
316
- />
317
- );
318
- };
319
- ```
320
-
321
- #### Example
322
-
323
- ## Screenshots
324
-
325
- | Dark Theme | Light Theme |
326
- |:-------------------------------------------------------------:|:----------------------------------------------------------------:|
327
- | ![Dark theme](assets/dark-theme-01.png?raw=true 'Dark Theme') | ![Light theme](assets/light-theme-01.png?raw=true 'Light Theme') |
328
-
329
- ## Contributing
330
-
331
- See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
332
- repository and the development workflow.
333
-
334
- ## License
335
-
336
- MIT
337
-
338
- ---
339
-
340
- Made with
341
- [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
342
-
343
- ## Built using
344
-
345
- - [Marked](https://marked.js.org/)
346
- - [@jsamr/react-native-li](https://github.com/jsamr/react-native-li)
347
- - [react-native-reanimated-table](https://github.com/dohooo/react-native-reanimated-table)
348
- - [react-native-svg](https://github.com/software-mansion/react-native-svg)
349
- - [svg-parser](https://github.com/Rich-Harris/svg-parser)
350
- - [github-slugger](https://github.com/Flet/github-slugger)
351
- - [html-entities](https://github.com/mdevils/html-entities)
352
-
353
-
354
- <a href="https://www.buymeacoffee.com/gmsgowtham" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="width: 120px !important;" ></a>
1
+ # react-native-marked
2
+
3
+ [![GitHub license](https://img.shields.io/github/license/gmsgowtham/react-native-marked)](https://github.com/gmsgowtham/react-native-marked/blob/main/LICENSE)
4
+ [![CI](https://github.com/gmsgowtham/react-native-marked/actions/workflows/build.yml/badge.svg)](https://github.com/gmsgowtham/react-native-marked/actions/workflows/build.yml)
5
+ [![Coverage Status](https://coveralls.io/repos/github/gmsgowtham/react-native-marked/badge.svg?branch=main)](https://coveralls.io/github/gmsgowtham/react-native-marked?branch=main)
6
+ [![npm](https://img.shields.io/npm/v/react-native-marked)](https://www.npmjs.com/package/react-native-marked)
7
+ [![npm](https://img.shields.io/npm/dw/react-native-marked)](https://www.npmjs.com/package/react-native-marked)
8
+
9
+ Markdown renderer for React Native powered by
10
+ [marked.js](https://marked.js.org/) with built-in theming support
11
+
12
+ 📚 Documentation: https://gmsgowtham.github.io/react-native-marked/
13
+
14
+ ## Installation
15
+
16
+ #### For React Native 0.76 and above, please use the latest version.
17
+ ```sh
18
+ yarn add react-native-marked react-native-svg
19
+ ```
20
+
21
+ #### For React Native 0.75 and below, please use version 6.
22
+ ```sh
23
+ yarn add react-native-marked@6.0.7 react-native-svg
24
+ ```
25
+
26
+ ## Usage
27
+
28
+ ### Using Component
29
+
30
+ ```tsx
31
+ import * as React from "react";
32
+ import Markdown from "react-native-marked";
33
+
34
+ const ExampleComponent = () => {
35
+ return (
36
+ <Markdown
37
+ value={`# Hello world`}
38
+ flatListProps={{
39
+ initialNumToRender: 8,
40
+ }}
41
+ />
42
+ );
43
+ };
44
+
45
+ export default ExampleComponent;
46
+ ```
47
+
48
+ #### [Props](https://github.com/gmsgowtham/react-native-marked/blob/main/src/lib/types.ts#L17)
49
+
50
+ | Prop | Description | Type | Optional? |
51
+ |---------------|----------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|
52
+ | value | Markdown value | string | false |
53
+ | flatListProps | Props for customizing the underlying FlatList used | `Omit<FlatListProps<ReactNode>, 'data' \| 'renderItem' \| 'horizontal'>`<br><br><br>(`'data'`, `'renderItem'`, and `'horizontal'` props are omitted and cannot be overridden.) | true |
54
+ | styles | Styles for parsed components | [MarkedStyles](src/theme/types.ts) | true |
55
+ | theme | Props for customizing colors and spacing for all components,and it will get overridden with custom component style applied via 'styles' prop | [UserTheme](src/theme/types.ts) | true |
56
+ | baseUrl | A prefix url for any relative link | string | true |
57
+ | renderer | Custom component Renderer | [RendererInterface](src/lib/types.ts) | true |
58
+ | hooks | Hooks run during parsing to transform tokens | [Marked Hooks](https://marked.js.org/using_pro#hooks) | true |
59
+ | selectable | Whether Text elements are selectable. Defaults to `true`. When a custom `renderer` is provided, this prop is ignored — configure via `new Renderer({ selectable })`. | boolean | true |
60
+
61
+
62
+ ### Using hook
63
+
64
+ `useMarkdown` hook will return list of elements that can be rendered using a list component of your choice.
65
+
66
+ ```tsx
67
+ import React, { Fragment } from "react";
68
+ import { ScrollView, useColorScheme } from "react-native";
69
+ import { useMarkdown, type useMarkdownHookOptions } from "react-native-marked";
70
+
71
+ const CustomComponent = () => {
72
+ const colorScheme = useColorScheme();
73
+ const options: useMarkdownHookOptions = {
74
+ colorScheme
75
+ }
76
+ const elements = useMarkdown("# Hello world", options);
77
+ return (
78
+ <ScrollView>
79
+ {elements.map((element, index) => {
80
+ return <Fragment key={`demo_${index}`}>{element}</Fragment>
81
+ })}
82
+ </ScrollView>
83
+ );
84
+ };
85
+ ```
86
+
87
+ #### Options
88
+
89
+ | Option | Description | Type | Optional? |
90
+ |-------------|----------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------|-----------|
91
+ | colorScheme | Device color scheme ("dark" or "light") | ColorSchemeName | false |
92
+ | styles | Styles for parsed components | [MarkedStyles](src/theme/types.ts) | true |
93
+ | theme | Props for customizing colors and spacing for all components,and it will get overridden with custom component style applied via 'styles' prop | [UserTheme](src/theme/types.ts) | true |
94
+ | baseUrl | A prefix url for any relative link | string | true |
95
+ | renderer | Custom component Renderer | [RendererInterface](src/lib/types.ts) | true |
96
+ | tokenizer | Generate custom tokens | [MarkedTokenizer<CustomToken>](src/lib/types.ts) | true |
97
+ | hooks | Hooks run during parsing to transform tokens | [Marked Hooks](https://marked.js.org/using_pro#hooks) | true |
98
+ | selectable | Whether Text elements are selectable. Defaults to `true`. When a custom `renderer` is provided, this option is ignored — configure via `new Renderer({ selectable })`. | boolean | true |
99
+
100
+
101
+ ## Examples
102
+
103
+ - CodeSandbox: https://codesandbox.io/s/react-native-marked-l2hpi3?file=/src/App.js
104
+
105
+ ## Supported elements
106
+
107
+ - [x] Headings (1 to 6)
108
+ - [x] Paragraph
109
+ - [x] Emphasis (bold, italic, and strikethrough)
110
+ - [x] Link
111
+ - [x] Image
112
+ - [x] Blockquote
113
+ - [x] Inline Code
114
+ - [x] Code Block
115
+ - [x] List (ordered, unordered)
116
+ - [x] Horizontal Rule
117
+ - [x] Table
118
+ - [x] React Components (via `useMarkdownWithComponents`)
119
+ - [ ] HTML
120
+
121
+ Ref: [CommonMark](https://commonmark.org/help/)
122
+
123
+ > HTML will be treated as plain text. Please refer [issue#290](https://github.com/gmsgowtham/react-native-marked/issues/290) for a potential solution
124
+
125
+ ### Styling code blocks and inline code
126
+
127
+ Use `code` for the block container (`ViewStyle`) and `codeText` / `codespan` for the text (`TextStyle`) to guarantee `fontFamily` (and other `TextStyle` props) are applied:
128
+
129
+ ```tsx
130
+ <Markdown
131
+ value={"```js\nconsole.log('hello')\n```\n\nUse `inline` code"}
132
+ styles={{
133
+ code: { backgroundColor: "#f6f8fa", padding: 16 }, // ViewStyle – container
134
+ codeText: { fontFamily: "Menlo", fontSize: 14 }, // TextStyle – code block text
135
+ codespan: { fontFamily: "Menlo", backgroundColor: "#f6f8fa" }, // TextStyle – inline
136
+ }}
137
+ />
138
+ ```
139
+
140
+ `codeText` was introduced to replace the previous `em`-based fallback for code blocks and ensures all `TextStyle` props win over parent styles.
141
+
142
+ ## Advanced
143
+
144
+ ### Embedding React Components in Markdown
145
+
146
+ You can embed React components directly in your markdown using JSX-style syntax. This is useful for adding interactive elements like buttons, custom info boxes, or any other React component.
147
+
148
+ ```tsx
149
+ import React, { Fragment } from "react";
150
+ import { Pressable, ScrollView, Text, View } from "react-native";
151
+ import {
152
+ ReactComponentRegistryProvider,
153
+ useMarkdownWithComponents,
154
+ type ReactComponentRegistry,
155
+ } from "react-native-marked";
156
+
157
+ // Define your components
158
+ const components: ReactComponentRegistry = {
159
+ Button: ({ props }) => (
160
+ <Pressable onPress={() => console.log("Pressed!")}>
161
+ <Text>{String(props.label ?? "Click me")}</Text>
162
+ </Pressable>
163
+ ),
164
+ InfoBox: ({ props, children }) => (
165
+ <View style={{ backgroundColor: "#E3F2FD", padding: 16 }}>
166
+ {props.title && <Text style={{ fontWeight: "bold" }}>{String(props.title)}</Text>}
167
+ <Text>{children}</Text>
168
+ </View>
169
+ ),
170
+ };
171
+
172
+ const markdown = `
173
+ # Hello World
174
+
175
+ Click the button below:
176
+
177
+ <Button label="Get Started" />
178
+
179
+ <InfoBox title="Note">
180
+ This is an info box with **markdown** content.
181
+ </InfoBox>
182
+ `;
183
+
184
+ function MarkdownContent() {
185
+ const elements = useMarkdownWithComponents(markdown);
186
+ return (
187
+ <ScrollView>
188
+ {elements.map((element, index) => (
189
+ <Fragment key={index}>{element}</Fragment>
190
+ ))}
191
+ </ScrollView>
192
+ );
193
+ }
194
+
195
+ export default function App() {
196
+ return (
197
+ <ReactComponentRegistryProvider components={components}>
198
+ <MarkdownContent />
199
+ </ReactComponentRegistryProvider>
200
+ );
201
+ }
202
+ ```
203
+
204
+ #### Component Syntax
205
+
206
+ - **Self-closing:** `<ComponentName prop="value" />`
207
+ - **With children:** `<ComponentName>content</ComponentName>`
208
+ - **Props:** Supports string (`"value"`), number (`{42}`), and boolean (`{true}`) props
209
+
210
+ #### Component Registry
211
+
212
+ Components must be registered via `ReactComponentRegistryProvider`. Unregistered components are automatically removed from the output.
213
+
214
+ ### Using custom components
215
+
216
+ > Custom components can be used to override elements, i.e. Code Highlighting, Fast Image integration
217
+
218
+ #### Example
219
+
220
+ ```tsx
221
+ import React, { ReactNode, Fragment } from "react";
222
+ import { Text, ScrollView } from "react-native";
223
+ import type { ImageStyle, TextStyle } from "react-native";
224
+ import Markdown, { Renderer, useMarkdown } from "react-native-marked";
225
+ import type { RendererInterface } from "react-native-marked";
226
+ import FastImage from "react-native-fast-image";
227
+
228
+ class CustomRenderer extends Renderer implements RendererInterface {
229
+ constructor() {
230
+ super();
231
+ }
232
+
233
+ codespan(text: string, _styles?: TextStyle): ReactNode {
234
+ return (
235
+ <Text key={this.getKey()} style={{ backgroundColor: "#ff0000" }}>
236
+ {text}
237
+ </Text>
238
+ );
239
+ }
240
+
241
+ image(uri: string, _alt?: string, _style?: ImageStyle): ReactNode {
242
+ return (
243
+ <FastImage
244
+ key={this.getKey()}
245
+ style={{ width: 200, height: 200 }}
246
+ source={{ uri: uri }}
247
+ resizeMode={FastImage.resizeMode.contain}
248
+ />
249
+ );
250
+ }
251
+ }
252
+
253
+ const renderer = new CustomRenderer();
254
+
255
+ const ExampleComponent = () => {
256
+ return (
257
+ <Markdown
258
+ value={"`Hello world`"}
259
+ flatListProps={{
260
+ initialNumToRender: 8,
261
+ }}
262
+ renderer={renderer}
263
+ />
264
+ );
265
+ };
266
+
267
+ // Alternate using hook
268
+ const ExampleComponentWithHook = () => {
269
+ const elements = useMarkdown("`Hello world`", { renderer });
270
+
271
+ return (
272
+ <ScrollView>
273
+ {elements.map((element, index) => {
274
+ return <Fragment key={`demo_${index}`}>{element}</Fragment>
275
+ })}
276
+ </ScrollView>
277
+ )
278
+ }
279
+
280
+ export default ExampleComponent;
281
+ ```
282
+
283
+ > Please refer to [RendererInterface](src/lib/types.ts) for all the overrides
284
+
285
+ > Note:
286
+ >
287
+ > For `key` property for a component, you can use the `getKey` method from Renderer class.
288
+
289
+ #### Example
290
+
291
+ Overriding default codespan tokenizer to include LaTeX.
292
+
293
+ ```tsx
294
+
295
+ import React, { ReactNode } from "react";
296
+ import Markdown, { Renderer, MarkedTokenizer, MarkedLexer } from "react-native-marked";
297
+ import type { RendererInterface, CustomToken } from "react-native-marked";
298
+
299
+ class CustomTokenizer extends Tokenizer {
300
+ codespan(src: string): Tokens.Codespan | undefined {
301
+ const match = src.match(/^\$+([^\$\n]+?)\$+/);
302
+ if (match?.[1]) {
303
+ return {
304
+ type: "codespan",
305
+ raw: match[0],
306
+ text: match[1].trim(),
307
+ };
308
+ }
309
+
310
+ return super.codespan(src);
311
+ }
312
+ }
313
+
314
+ class CustomRenderer extends Renderer implements RendererInterface {
315
+ codespan(text: string, styles?: TextStyle): ReactNode {
316
+ return (
317
+ <Text style={styles} key={"key-1"}>
318
+ {text}
319
+ </Text>
320
+ )
321
+ }
322
+ }
323
+
324
+ const renderer = new CustomRenderer();
325
+ const tokenizer = new CustomTokenizer();
326
+
327
+ const ExampleComponent = () => {
328
+ return (
329
+ <Markdown
330
+ value={"$ latex code $\n\n` other code `"}
331
+ flatListProps={{
332
+ initialNumToRender: 8,
333
+ }}
334
+ renderer={renderer}
335
+ tokenizer={tokenizer}
336
+ />
337
+ );
338
+ };
339
+ ```
340
+
341
+ #### Example
342
+
343
+ ## Screenshots
344
+
345
+ | Dark Theme | Light Theme |
346
+ |:-------------------------------------------------------------:|:----------------------------------------------------------------:|
347
+ | ![Dark theme](assets/dark-theme-01.png?raw=true 'Dark Theme') | ![Light theme](assets/light-theme-01.png?raw=true 'Light Theme') |
348
+
349
+ ## Contributing
350
+
351
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the
352
+ repository and the development workflow.
353
+
354
+ ## License
355
+
356
+ MIT
357
+
358
+ ---
359
+
360
+ Made with
361
+ [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
362
+
363
+ ## Built using
364
+
365
+ - [Marked](https://marked.js.org/)
366
+ - [@jsamr/react-native-li](https://github.com/jsamr/react-native-li)
367
+ - [react-native-reanimated-table](https://github.com/dohooo/react-native-reanimated-table)
368
+ - [react-native-svg](https://github.com/software-mansion/react-native-svg)
369
+ - [svg-parser](https://github.com/Rich-Harris/svg-parser)
370
+ - [github-slugger](https://github.com/Flet/github-slugger)
371
+ - [html-entities](https://github.com/mdevils/html-entities)
372
+
373
+
374
+ <a href="https://www.buymeacoffee.com/gmsgowtham" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="width: 120px !important;" ></a>