react-native-marked 1.1.2 → 1.1.4
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.
- package/dist/commonjs/lib/Markdown.js +1 -1
- package/dist/commonjs/lib/Markdown.js.map +1 -1
- package/dist/commonjs/lib/Parser.js +76 -53
- package/dist/commonjs/lib/Parser.js.map +1 -1
- package/dist/commonjs/lib/Renderer.js +17 -19
- package/dist/commonjs/lib/Renderer.js.map +1 -1
- package/dist/commonjs/theme/styles.js.map +1 -1
- package/dist/commonjs/utils/handlers.js +19 -0
- package/dist/commonjs/utils/handlers.js.map +1 -0
- package/dist/module/lib/Markdown.js +1 -1
- package/dist/module/lib/Markdown.js.map +1 -1
- package/dist/module/lib/Parser.js +76 -53
- package/dist/module/lib/Parser.js.map +1 -1
- package/dist/module/lib/Renderer.js +9 -8
- package/dist/module/lib/Renderer.js.map +1 -1
- package/dist/module/theme/styles.js.map +1 -1
- package/dist/module/utils/handlers.js +9 -0
- package/dist/module/utils/handlers.js.map +1 -0
- package/dist/typescript/lib/Markdown.d.ts +1 -1
- package/dist/typescript/lib/Parser.d.ts +4 -3
- package/dist/typescript/lib/Renderer.d.ts +6 -7
- package/dist/typescript/utils/handlers.d.ts +1 -0
- package/package.json +2 -2
- package/src/lib/Markdown.tsx +1 -1
- package/src/lib/Parser.tsx +98 -56
- package/src/lib/Renderer.tsx +20 -15
- package/src/theme/styles.ts +3 -1
- package/src/utils/handlers.ts +9 -0
package/src/lib/Parser.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import type { marked } from 'marked';
|
|
2
3
|
import Renderer from './Renderer';
|
|
3
4
|
import type { MarkedStyles } from '../theme/types';
|
|
@@ -21,35 +22,17 @@ class Parser {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
parse(tokens: marked.Token[]) {
|
|
24
|
-
const elements:
|
|
25
|
+
const elements: ReactNode[] = tokens.map((token) => {
|
|
25
26
|
switch (token.type) {
|
|
26
27
|
case 'space': {
|
|
27
28
|
return null;
|
|
28
29
|
}
|
|
29
30
|
case 'paragraph': {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (t.type === 'image') {
|
|
35
|
-
paragraphChildren.push(
|
|
36
|
-
this.renderer.getTextNode(
|
|
37
|
-
this.parseInline(tempTokens),
|
|
38
|
-
this.styles.text
|
|
39
|
-
)
|
|
40
|
-
);
|
|
41
|
-
paragraphChildren.push(this.parseInline([t]));
|
|
42
|
-
tempTokens = [];
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
tempTokens = [...tempTokens, t];
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
if (tempTokens.length > 0) {
|
|
49
|
-
paragraphChildren.push(
|
|
50
|
-
this.renderer.getTextNode(this.parseInline(tempTokens), {})
|
|
31
|
+
const paragraphChildren =
|
|
32
|
+
this.getNormalizedSiblingNodesForBlockAndInlineTokens(
|
|
33
|
+
token.tokens,
|
|
34
|
+
this.styles.text
|
|
51
35
|
);
|
|
52
|
-
}
|
|
53
36
|
|
|
54
37
|
return this.renderer.getViewNode(
|
|
55
38
|
paragraphChildren,
|
|
@@ -64,7 +47,10 @@ class Parser {
|
|
|
64
47
|
}
|
|
65
48
|
case 'heading': {
|
|
66
49
|
const styles = this.headingStylesMap[token.depth] ?? this.styles.text;
|
|
67
|
-
return this.renderer.getTextNode(
|
|
50
|
+
return this.renderer.getTextNode(
|
|
51
|
+
this.parseInline(token.tokens, styles),
|
|
52
|
+
styles
|
|
53
|
+
);
|
|
68
54
|
}
|
|
69
55
|
case 'code': {
|
|
70
56
|
return this.renderer.getCodeBlockNode(
|
|
@@ -78,19 +64,24 @@ class Parser {
|
|
|
78
64
|
}
|
|
79
65
|
case 'list': {
|
|
80
66
|
const li = token.items.map((item) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
67
|
+
const children = item.tokens.map((cItem) => {
|
|
68
|
+
if (cItem.type === 'text') {
|
|
69
|
+
/* getViewNode since tokens could contain a block like elements (i.e. img) */
|
|
70
|
+
const listChildren =
|
|
71
|
+
this.getNormalizedSiblingNodesForBlockAndInlineTokens(
|
|
72
|
+
// Note: Upstream types aren't available for this specific use-case
|
|
73
|
+
// @types/marked (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/marked/index.d.ts)
|
|
74
|
+
// @ts-ignore
|
|
75
|
+
cItem.tokens,
|
|
76
|
+
this.styles.li
|
|
77
|
+
);
|
|
78
|
+
return this.renderer.getViewNode(listChildren, this.styles.li);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Parse the nested token */
|
|
82
|
+
return this.parse([cItem]);
|
|
83
|
+
});
|
|
84
|
+
return this.renderer.getViewNode(children, this.styles.li);
|
|
94
85
|
});
|
|
95
86
|
return this.renderer.getListNode(
|
|
96
87
|
token.ordered,
|
|
@@ -99,51 +90,63 @@ class Parser {
|
|
|
99
90
|
this.styles.li
|
|
100
91
|
);
|
|
101
92
|
}
|
|
102
|
-
case 'html': {
|
|
103
|
-
return this.renderer.getTextNode(token.text.trim(), this.styles.text);
|
|
104
|
-
}
|
|
105
93
|
default:
|
|
106
|
-
|
|
107
|
-
return null;
|
|
94
|
+
return this.parseInline([token]);
|
|
108
95
|
}
|
|
109
96
|
});
|
|
110
|
-
return elements;
|
|
97
|
+
return elements.filter((element) => element !== null);
|
|
111
98
|
}
|
|
112
99
|
|
|
113
100
|
parseInline(tokens: marked.Token[], styles?: CustomStyleProp) {
|
|
114
|
-
const elements:
|
|
101
|
+
const elements: ReactNode[] = tokens.map((token) => {
|
|
115
102
|
if (!token) return null;
|
|
116
103
|
|
|
117
104
|
switch (token.type) {
|
|
118
105
|
case 'escape': {
|
|
119
106
|
return this.renderer.getTextNode(token.text, {
|
|
120
|
-
...styles,
|
|
121
107
|
...this.styles.text,
|
|
108
|
+
...styles,
|
|
122
109
|
});
|
|
123
110
|
}
|
|
124
111
|
case 'link': {
|
|
125
|
-
|
|
112
|
+
const linkStyle = {
|
|
126
113
|
...styles,
|
|
127
|
-
...this.styles.link,
|
|
128
|
-
}
|
|
114
|
+
...this.styles.link, // To override color property
|
|
115
|
+
};
|
|
116
|
+
return this.renderer.getLinkNode(
|
|
117
|
+
this.parseInline(token.tokens, linkStyle),
|
|
118
|
+
token.href,
|
|
119
|
+
linkStyle
|
|
120
|
+
);
|
|
129
121
|
}
|
|
130
122
|
case 'image': {
|
|
131
123
|
return this.renderer.getImageNode(token.href);
|
|
132
124
|
}
|
|
133
125
|
case 'strong': {
|
|
126
|
+
const boldStyle = {
|
|
127
|
+
...this.styles.strong,
|
|
128
|
+
...styles,
|
|
129
|
+
};
|
|
134
130
|
return this.renderer.getTextNode(
|
|
135
|
-
this.parseInline(token.tokens,
|
|
136
|
-
|
|
131
|
+
this.parseInline(token.tokens, boldStyle),
|
|
132
|
+
boldStyle
|
|
137
133
|
);
|
|
138
134
|
}
|
|
139
135
|
case 'em': {
|
|
136
|
+
const italicStyle = {
|
|
137
|
+
...this.styles.em,
|
|
138
|
+
...styles,
|
|
139
|
+
};
|
|
140
140
|
return this.renderer.getTextNode(
|
|
141
|
-
this.parseInline(token.tokens,
|
|
142
|
-
|
|
141
|
+
this.parseInline(token.tokens, italicStyle),
|
|
142
|
+
italicStyle
|
|
143
143
|
);
|
|
144
144
|
}
|
|
145
145
|
case 'codespan': {
|
|
146
|
-
return this.renderer.getTextNode(token.text,
|
|
146
|
+
return this.renderer.getTextNode(token.text, {
|
|
147
|
+
...this.styles.codespan,
|
|
148
|
+
...styles,
|
|
149
|
+
});
|
|
147
150
|
}
|
|
148
151
|
case 'br': {
|
|
149
152
|
return this.renderer.getTextNode('\n', {});
|
|
@@ -151,10 +154,15 @@ class Parser {
|
|
|
151
154
|
case 'del': {
|
|
152
155
|
return null;
|
|
153
156
|
}
|
|
154
|
-
case 'text':
|
|
157
|
+
case 'text':
|
|
158
|
+
case 'html': {
|
|
159
|
+
if (token.raw.trim().length < 1) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
155
163
|
return this.renderer.getTextNode(token.raw, {
|
|
156
|
-
...styles,
|
|
157
164
|
...this.styles.text,
|
|
165
|
+
...styles,
|
|
158
166
|
});
|
|
159
167
|
}
|
|
160
168
|
default: {
|
|
@@ -163,8 +171,42 @@ class Parser {
|
|
|
163
171
|
}
|
|
164
172
|
}
|
|
165
173
|
});
|
|
166
|
-
return elements;
|
|
174
|
+
return elements.filter((element) => element !== null);
|
|
167
175
|
}
|
|
176
|
+
|
|
177
|
+
private getNormalizedSiblingNodesForBlockAndInlineTokens = (
|
|
178
|
+
tokens: marked.Token[],
|
|
179
|
+
textStyle: TextStyleProp
|
|
180
|
+
): ReactNode[] => {
|
|
181
|
+
let tempTokens: marked.Token[] = [];
|
|
182
|
+
const siblingNodes: ReactNode[] = [];
|
|
183
|
+
tokens.forEach((t) => {
|
|
184
|
+
/**
|
|
185
|
+
* To avoid inlining images
|
|
186
|
+
* Note: to be extend for other token types
|
|
187
|
+
*/
|
|
188
|
+
if (t.type === 'image') {
|
|
189
|
+
const parsed = this.parseInline(tempTokens);
|
|
190
|
+
if (parsed.length > 0) {
|
|
191
|
+
siblingNodes.push(
|
|
192
|
+
this.renderer.getTextNode(this.parseInline(tempTokens), textStyle)
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
siblingNodes.push(this.parseInline([t]));
|
|
196
|
+
tempTokens = [];
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
tempTokens = [...tempTokens, t];
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
/* Remaining temp tokens if any */
|
|
203
|
+
if (tempTokens.length > 0) {
|
|
204
|
+
siblingNodes.push(
|
|
205
|
+
this.renderer.getTextNode(this.parseInline(tempTokens), {})
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return siblingNodes;
|
|
209
|
+
};
|
|
168
210
|
}
|
|
169
211
|
|
|
170
212
|
export default Parser;
|
package/src/lib/Renderer.tsx
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { ScrollView, View, Text } from 'react-native';
|
|
3
3
|
import MarkedList from '@jsamr/react-native-li';
|
|
4
4
|
import Disc from '@jsamr/counter-style/presets/disc';
|
|
5
5
|
import Decimal from '@jsamr/counter-style/presets/decimal';
|
|
6
6
|
import MDImage from './../components/MDImage';
|
|
7
7
|
import { generateRandomString } from '../utils/string';
|
|
8
8
|
import type { TextStyleProp, ViewStyleProp } from './types';
|
|
9
|
+
import { onLinkPress } from '../utils/handlers';
|
|
9
10
|
|
|
10
11
|
class Renderer {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
getTextNode = (
|
|
14
|
-
children: string | React.ReactNode[],
|
|
15
|
-
styles: TextStyleProp
|
|
16
|
-
) => {
|
|
12
|
+
getTextNode = (children: string | ReactNode[], styles: TextStyleProp) => {
|
|
17
13
|
return (
|
|
18
14
|
<Text key={generateRandomString()} style={styles}>
|
|
19
15
|
{children}
|
|
@@ -21,19 +17,23 @@ class Renderer {
|
|
|
21
17
|
);
|
|
22
18
|
};
|
|
23
19
|
|
|
24
|
-
getLinkNode = (
|
|
20
|
+
getLinkNode = (
|
|
21
|
+
children: string | ReactNode[],
|
|
22
|
+
href: string,
|
|
23
|
+
styles: TextStyleProp
|
|
24
|
+
) => {
|
|
25
25
|
return (
|
|
26
26
|
<Text
|
|
27
27
|
key={generateRandomString()}
|
|
28
|
-
onPress={
|
|
28
|
+
onPress={onLinkPress(href)}
|
|
29
29
|
style={styles}
|
|
30
30
|
>
|
|
31
|
-
{
|
|
31
|
+
{children}
|
|
32
32
|
</Text>
|
|
33
33
|
);
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
getViewNode(children:
|
|
36
|
+
getViewNode(children: ReactNode[] | null, styles: ViewStyleProp) {
|
|
37
37
|
return (
|
|
38
38
|
<View key={generateRandomString()} style={styles}>
|
|
39
39
|
{children}
|
|
@@ -47,13 +47,17 @@ class Renderer {
|
|
|
47
47
|
textStyle: TextStyleProp
|
|
48
48
|
) {
|
|
49
49
|
return (
|
|
50
|
-
<ScrollView
|
|
50
|
+
<ScrollView
|
|
51
|
+
key={generateRandomString()}
|
|
52
|
+
contentContainerStyle={containerStyle}
|
|
53
|
+
horizontal
|
|
54
|
+
>
|
|
51
55
|
<Text style={textStyle}>{text}</Text>
|
|
52
56
|
</ScrollView>
|
|
53
57
|
);
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
getBlockquoteNode(children:
|
|
60
|
+
getBlockquoteNode(children: ReactNode[], styles: ViewStyleProp) {
|
|
57
61
|
return (
|
|
58
62
|
<View key={generateRandomString()} style={styles}>
|
|
59
63
|
{children}
|
|
@@ -67,7 +71,7 @@ class Renderer {
|
|
|
67
71
|
|
|
68
72
|
getListNode(
|
|
69
73
|
ordered: boolean,
|
|
70
|
-
li:
|
|
74
|
+
li: ReactNode[],
|
|
71
75
|
listStyle: ViewStyleProp,
|
|
72
76
|
textStyle: TextStyleProp
|
|
73
77
|
) {
|
|
@@ -76,6 +80,7 @@ class Renderer {
|
|
|
76
80
|
counterRenderer={ordered ? Decimal : Disc}
|
|
77
81
|
markerTextStyle={textStyle}
|
|
78
82
|
markerBoxStyle={listStyle}
|
|
83
|
+
key={generateRandomString()}
|
|
79
84
|
>
|
|
80
85
|
{li.map((node) => node)}
|
|
81
86
|
</MarkedList>
|
package/src/theme/styles.ts
CHANGED