react-native-marked 1.6.14 → 2.0.0-rc.0

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 (78) hide show
  1. package/README.md +64 -8
  2. package/dist/commonjs/index.js +8 -0
  3. package/dist/commonjs/index.js.map +1 -1
  4. package/dist/commonjs/lib/Markdown.js +5 -1
  5. package/dist/commonjs/lib/Markdown.js.map +1 -1
  6. package/dist/commonjs/lib/Parser.js +50 -35
  7. package/dist/commonjs/lib/Parser.js.map +1 -1
  8. package/dist/commonjs/lib/Renderer.js +113 -45
  9. package/dist/commonjs/lib/Renderer.js.map +1 -1
  10. package/dist/commonjs/lib/__perf__/Markdown.perf-test.js +196 -0
  11. package/dist/commonjs/lib/__perf__/Markdown.perf-test.js.map +1 -0
  12. package/dist/module/index.js +2 -0
  13. package/dist/module/index.js.map +1 -1
  14. package/dist/module/lib/Markdown.js +4 -1
  15. package/dist/module/lib/Markdown.js.map +1 -1
  16. package/dist/module/lib/Parser.js +50 -32
  17. package/dist/module/lib/Parser.js.map +1 -1
  18. package/dist/module/lib/Renderer.js +112 -44
  19. package/dist/module/lib/Renderer.js.map +1 -1
  20. package/dist/module/lib/__perf__/Markdown.perf-test.js +188 -0
  21. package/dist/module/lib/__perf__/Markdown.perf-test.js.map +1 -0
  22. package/dist/typescript/components/MDImage.d.ts.map +1 -0
  23. package/dist/typescript/index.d.ts +7 -0
  24. package/dist/typescript/index.d.ts.map +1 -0
  25. package/dist/typescript/{src/lib → lib}/Markdown.d.ts +1 -1
  26. package/dist/typescript/lib/Markdown.d.ts.map +1 -0
  27. package/dist/typescript/lib/Parser.d.ts.map +1 -0
  28. package/dist/typescript/lib/Renderer.d.ts +32 -0
  29. package/dist/typescript/lib/Renderer.d.ts.map +1 -0
  30. package/dist/typescript/lib/__perf__/Markdown.perf-test.d.ts +2 -0
  31. package/dist/typescript/lib/__perf__/Markdown.perf-test.d.ts.map +1 -0
  32. package/dist/typescript/lib/types.d.ts +34 -0
  33. package/dist/typescript/lib/types.d.ts.map +1 -0
  34. package/dist/typescript/theme/colors.d.ts.map +1 -0
  35. package/dist/typescript/theme/spacing.d.ts.map +1 -0
  36. package/dist/typescript/theme/styles.d.ts.map +1 -0
  37. package/dist/typescript/theme/types.d.ts.map +1 -0
  38. package/dist/typescript/utils/handlers.d.ts.map +1 -0
  39. package/dist/typescript/utils/url.d.ts.map +1 -0
  40. package/package.json +1 -1
  41. package/src/index.ts +8 -0
  42. package/src/lib/Markdown.tsx +8 -1
  43. package/src/lib/Parser.tsx +50 -64
  44. package/src/lib/Renderer.tsx +135 -60
  45. package/src/lib/__perf__/Markdown.perf-test.tsx +186 -0
  46. package/src/lib/types.ts +48 -2
  47. package/dist/commonjs/utils/string.js +0 -17
  48. package/dist/commonjs/utils/string.js.map +0 -1
  49. package/dist/module/utils/string.js +0 -8
  50. package/dist/module/utils/string.js.map +0 -1
  51. package/dist/typescript/dangerfile.d.ts +0 -2
  52. package/dist/typescript/dangerfile.d.ts.map +0 -1
  53. package/dist/typescript/src/components/MDImage.d.ts.map +0 -1
  54. package/dist/typescript/src/index.d.ts +0 -3
  55. package/dist/typescript/src/index.d.ts.map +0 -1
  56. package/dist/typescript/src/lib/Markdown.d.ts.map +0 -1
  57. package/dist/typescript/src/lib/Parser.d.ts.map +0 -1
  58. package/dist/typescript/src/lib/Renderer.d.ts +0 -14
  59. package/dist/typescript/src/lib/Renderer.d.ts.map +0 -1
  60. package/dist/typescript/src/lib/types.d.ts +0 -13
  61. package/dist/typescript/src/lib/types.d.ts.map +0 -1
  62. package/dist/typescript/src/theme/colors.d.ts.map +0 -1
  63. package/dist/typescript/src/theme/spacing.d.ts.map +0 -1
  64. package/dist/typescript/src/theme/styles.d.ts.map +0 -1
  65. package/dist/typescript/src/theme/types.d.ts.map +0 -1
  66. package/dist/typescript/src/utils/handlers.d.ts.map +0 -1
  67. package/dist/typescript/src/utils/string.d.ts +0 -6
  68. package/dist/typescript/src/utils/string.d.ts.map +0 -1
  69. package/dist/typescript/src/utils/url.d.ts.map +0 -1
  70. package/src/utils/string.ts +0 -7
  71. /package/dist/typescript/{src/components → components}/MDImage.d.ts +0 -0
  72. /package/dist/typescript/{src/lib → lib}/Parser.d.ts +0 -0
  73. /package/dist/typescript/{src/theme → theme}/colors.d.ts +0 -0
  74. /package/dist/typescript/{src/theme → theme}/spacing.d.ts +0 -0
  75. /package/dist/typescript/{src/theme → theme}/styles.d.ts +0 -0
  76. /package/dist/typescript/{src/theme → theme}/types.d.ts +0 -0
  77. /package/dist/typescript/{src/utils → utils}/handlers.d.ts +0 -0
  78. /package/dist/typescript/{src/utils → utils}/url.d.ts +0 -0
@@ -1,20 +1,20 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { TextStyle, ViewStyle, ImageStyle } from "react-native";
3
3
  import type { marked } from "marked";
4
- import Renderer from "./Renderer";
5
4
  import type { MarkedStyles } from "../theme/types";
6
- import type { ParserOptions } from "./types";
5
+ import type { RendererInterface, ParserOptions } from "./types";
7
6
  import { getValidURL } from "./../utils/url";
8
7
 
9
8
  class Parser {
10
- private renderer;
9
+ private renderer: RendererInterface;
11
10
  private styles: MarkedStyles;
12
11
  private headingStylesMap: Record<number, TextStyle | undefined>;
13
12
  private baseUrl: string;
13
+
14
14
  constructor(options: ParserOptions) {
15
15
  this.styles = { ...options.styles };
16
16
  this.baseUrl = options.baseUrl ?? "";
17
- this.renderer = new Renderer();
17
+ this.renderer = options.renderer;
18
18
  this.headingStylesMap = {
19
19
  1: this.styles.h1,
20
20
  2: this.styles.h2,
@@ -48,43 +48,36 @@ class Parser {
48
48
  return null;
49
49
  }
50
50
  case "paragraph": {
51
- const paragraphChildren =
52
- this.getNormalizedSiblingNodesForBlockAndInlineTokens(
53
- token.tokens,
54
- this.styles.text,
55
- );
56
-
57
- return this.renderer.getViewNode(
58
- paragraphChildren,
59
- this.styles.paragraph,
51
+ const children = this.getNormalizedSiblingNodesForBlockAndInlineTokens(
52
+ token.tokens,
53
+ this.styles.text,
60
54
  );
55
+
56
+ return this.renderer.paragraph(children, this.styles.paragraph);
61
57
  }
62
58
  case "blockquote": {
63
- return this.renderer.getBlockquoteNode(
64
- this._parse(token.tokens),
65
- this.styles.blockquote,
66
- );
59
+ const children = this.parse(token.tokens);
60
+ return this.renderer.blockquote(children, this.styles.blockquote);
67
61
  }
68
62
  case "heading": {
69
63
  const styles = this.headingStylesMap[token.depth];
70
- return this.renderer.getTextNode(
71
- this._parse(token.tokens, styles),
72
- styles,
73
- );
64
+ const children = this._parse(token.tokens, styles);
65
+ return this.renderer.heading(children, styles);
74
66
  }
75
67
  case "code": {
76
- return this.renderer.getCodeBlockNode(
68
+ return this.renderer.code(
77
69
  token.text,
70
+ token.lang,
78
71
  this.styles.code,
79
72
  this.styles.em,
80
73
  );
81
74
  }
82
75
  case "hr": {
83
- return this.renderer.getViewNode(null, this.styles.hr);
76
+ return this.renderer.hr(this.styles.hr);
84
77
  }
85
78
  case "list": {
86
79
  const li = token.items.map((item) => {
87
- const children = item.tokens.map((cItem) => {
80
+ const children = item.tokens.flatMap((cItem) => {
88
81
  if (cItem.type === "text") {
89
82
  /* getViewNode since tokens could contain a block like elements (i.e. img) */
90
83
  const childTokens = (cItem as marked.Tokens.Text).tokens || [];
@@ -93,15 +86,18 @@ class Parser {
93
86
  childTokens,
94
87
  this.styles.li,
95
88
  );
96
- return this.renderer.getViewNode(listChildren, this.styles.li);
89
+ // return this.renderer.listItem(listChildren, this.styles.li);
90
+ return listChildren;
97
91
  }
98
92
 
99
93
  /* Parse the nested token */
100
94
  return this._parseToken(cItem);
101
95
  });
102
- return this.renderer.getViewNode(children, this.styles.li);
96
+
97
+ return this.renderer.listItem(children, this.styles.li);
103
98
  });
104
- return this.renderer.getListNode(
99
+
100
+ return this.renderer.list(
105
101
  token.ordered,
106
102
  li,
107
103
  this.styles.list,
@@ -109,7 +105,7 @@ class Parser {
109
105
  );
110
106
  }
111
107
  case "escape": {
112
- return this.renderer.getTextNode(token.text, {
108
+ return this.renderer.escape(token.text, {
113
109
  ...this.styles.text,
114
110
  ...styles,
115
111
  });
@@ -122,14 +118,11 @@ class Parser {
122
118
  ...this.styles.link, // To override color property
123
119
  };
124
120
  const href = getValidURL(this.baseUrl, token.href);
125
- return this.renderer.getTextLinkNode(
126
- this._parse(token.tokens, linkStyle),
127
- href,
128
- linkStyle,
129
- );
121
+ const children = this._parse(token.tokens, linkStyle);
122
+ return this.renderer.link(children, href, linkStyle);
130
123
  }
131
124
  case "image": {
132
- return this.renderer.getImageNode(
125
+ return this.renderer.image(
133
126
  token.href,
134
127
  token.text || token.title,
135
128
  this.styles.image,
@@ -140,49 +133,44 @@ class Parser {
140
133
  ...this.styles.strong,
141
134
  ...styles,
142
135
  };
143
- return this.renderer.getTextNode(
144
- this._parse(token.tokens, boldStyle),
145
- boldStyle,
146
- );
136
+ const children = this._parse(token.tokens, boldStyle);
137
+ return this.renderer.strong(children, boldStyle);
147
138
  }
148
139
  case "em": {
149
140
  const italicStyle = {
150
141
  ...this.styles.em,
151
142
  ...styles,
152
143
  };
153
- return this.renderer.getTextNode(
154
- this._parse(token.tokens, italicStyle),
155
- italicStyle,
156
- );
144
+ const children = this._parse(token.tokens, italicStyle);
145
+ return this.renderer.em(children, italicStyle);
157
146
  }
158
147
  case "codespan": {
159
- return this.renderer.getTextNode(token.text, {
148
+ return this.renderer.codespan(token.text, {
160
149
  ...this.styles.codespan,
161
150
  ...styles,
162
151
  });
163
152
  }
164
153
  case "br": {
165
- return this.renderer.getTextNode("\n", {});
154
+ return this.renderer.br();
166
155
  }
167
156
  case "del": {
168
157
  const strikethroughStyle = {
169
158
  ...this.styles.strikethrough,
170
159
  ...styles,
171
160
  };
172
- return this.renderer.getTextNode(
173
- this._parse(token.tokens, strikethroughStyle),
174
- strikethroughStyle,
175
- );
161
+ const children = this._parse(token.tokens, strikethroughStyle);
162
+ return this.renderer.del(children, strikethroughStyle);
176
163
  }
177
164
  case "text":
165
+ return this.renderer.text(token.raw, {
166
+ ...this.styles.text,
167
+ ...styles,
168
+ });
178
169
  case "html": {
179
- if (token.type === "html") {
180
- console.warn(
181
- "react-native-marked: rendering html from markdown is not supported",
182
- );
183
- }
184
-
185
- return this.renderer.getTextNode(token.raw, {
170
+ console.warn(
171
+ "react-native-marked: rendering html from markdown is not supported",
172
+ );
173
+ return this.renderer.html(token.raw, {
186
174
  ...this.styles.text,
187
175
  ...styles,
188
176
  });
@@ -196,10 +184,10 @@ class Parser {
196
184
  }
197
185
  }
198
186
 
199
- private getNormalizedSiblingNodesForBlockAndInlineTokens = (
187
+ private getNormalizedSiblingNodesForBlockAndInlineTokens(
200
188
  tokens: marked.Token[],
201
189
  textStyle?: TextStyle,
202
- ): ReactNode[] => {
190
+ ): ReactNode[] {
203
191
  let tokenRenderQueue: marked.Token[] = [];
204
192
  const siblingNodes: ReactNode[] = [];
205
193
  tokens.forEach((t) => {
@@ -216,9 +204,9 @@ class Parser {
216
204
  t.tokens[0].type === "image")
217
205
  ) {
218
206
  // Render existing inline tokens in the queue
219
- const parsed = this._parse(tokenRenderQueue);
207
+ const parsed = this.parse(tokenRenderQueue);
220
208
  if (parsed.length > 0) {
221
- siblingNodes.push(this.renderer.getTextNode(parsed, textStyle));
209
+ siblingNodes.push(this.renderer.text(parsed, textStyle));
222
210
  }
223
211
 
224
212
  // Render the current block token
@@ -228,7 +216,7 @@ class Parser {
228
216
  const imageToken = t.tokens[0] as marked.Tokens.Image;
229
217
  const href = getValidURL(this.baseUrl, t.href);
230
218
  siblingNodes.push(
231
- this.renderer.getImageLinkNode(
219
+ this.renderer.linkImage(
232
220
  href,
233
221
  imageToken.href,
234
222
  imageToken.text || imageToken.title,
@@ -245,13 +233,11 @@ class Parser {
245
233
 
246
234
  /* Remaining temp tokens if any */
247
235
  if (tokenRenderQueue.length > 0) {
248
- siblingNodes.push(
249
- this.renderer.getTextNode(this._parse(tokenRenderQueue), {}),
250
- );
236
+ siblingNodes.push(this.renderer.text(this.parse(tokenRenderQueue), {}));
251
237
  }
252
238
 
253
239
  return siblingNodes;
254
- };
240
+ }
255
241
  }
256
242
 
257
243
  export default Parser;
@@ -11,110 +11,185 @@ import {
11
11
  import MarkedList from "@jsamr/react-native-li";
12
12
  import Disc from "@jsamr/counter-style/presets/disc";
13
13
  import Decimal from "@jsamr/counter-style/presets/decimal";
14
+ import { Slugger } from "marked";
14
15
  import MDImage from "./../components/MDImage";
15
- import { generateRandomString } from "../utils/string";
16
16
  import { onLinkPress } from "../utils/handlers";
17
+ import type { RendererInterface } from "./types";
17
18
 
18
- class Renderer {
19
- getTextNode = (children: string | ReactNode[], styles?: TextStyle) => {
19
+ class Renderer implements RendererInterface {
20
+ private slugPrefix = "react-native-marked-ele";
21
+ private slugger: Slugger;
22
+ constructor() {
23
+ this.slugger = new Slugger();
24
+ }
25
+
26
+ paragraph(children: ReactNode[], styles?: ViewStyle): ReactNode {
27
+ return this.getViewNode(children, styles);
28
+ }
29
+
30
+ blockquote(children: ReactNode[], styles?: ViewStyle): ReactNode {
31
+ return this.getBlockquoteNode(children, styles);
32
+ }
33
+
34
+ heading(text: string | ReactNode[], styles?: TextStyle): ReactNode {
35
+ return this.getTextNode(text, styles);
36
+ }
37
+
38
+ code(
39
+ text: string,
40
+ _language?: string,
41
+ containerStyle?: ViewStyle,
42
+ textStyle?: TextStyle,
43
+ ): ReactNode {
20
44
  return (
21
- <Text key={generateRandomString()} style={styles}>
22
- {children}
23
- </Text>
45
+ <ScrollView
46
+ horizontal
47
+ key={this.getKey()}
48
+ contentContainerStyle={containerStyle}
49
+ >
50
+ <Text style={textStyle}>{text}</Text>
51
+ </ScrollView>
52
+ );
53
+ }
54
+
55
+ hr(styles?: ViewStyle): ReactNode {
56
+ return this.getViewNode(null, styles);
57
+ }
58
+
59
+ listItem(children: ReactNode[], styles?: ViewStyle): ReactNode {
60
+ return this.getViewNode(children, styles);
61
+ }
62
+
63
+ list(
64
+ ordered: boolean,
65
+ li: ReactNode[],
66
+ listStyle?: ViewStyle,
67
+ textStyle?: TextStyle,
68
+ ): ReactNode {
69
+ return (
70
+ <MarkedList
71
+ counterRenderer={ordered ? Decimal : Disc}
72
+ markerTextStyle={textStyle}
73
+ markerBoxStyle={listStyle}
74
+ key={this.getKey()}
75
+ >
76
+ {li.map((node) => node)}
77
+ </MarkedList>
24
78
  );
25
- };
79
+ }
80
+
81
+ escape(text: string, styles?: TextStyle): ReactNode {
82
+ return this.getTextNode(text, styles);
83
+ }
26
84
 
27
- getTextLinkNode = (
85
+ link(
28
86
  children: string | ReactNode[],
29
87
  href: string,
30
88
  styles?: TextStyle,
31
- ) => {
89
+ ): ReactNode {
32
90
  return (
33
91
  <Text
34
92
  accessibilityRole="link"
35
93
  accessibilityHint="Opens in a new window"
36
- key={generateRandomString()}
94
+ key={this.getKey()}
37
95
  onPress={onLinkPress(href)}
38
96
  style={styles}
39
97
  >
40
98
  {children}
41
99
  </Text>
42
100
  );
43
- };
101
+ }
102
+
103
+ image(uri: string, alt?: string, style?: ImageStyle): ReactNode {
104
+ return <MDImage key={this.getKey()} uri={uri} alt={alt} style={style} />;
105
+ }
106
+
107
+ strong(children: ReactNode[], styles?: TextStyle): ReactNode {
108
+ return this.getTextNode(children, styles);
109
+ }
44
110
 
45
- getImageLinkNode = (
111
+ em(children: ReactNode[], styles?: TextStyle): ReactNode {
112
+ return this.getTextNode(children, styles);
113
+ }
114
+
115
+ codespan(text: string, styles?: TextStyle): ReactNode {
116
+ return this.getTextNode(text, styles);
117
+ }
118
+
119
+ br(): ReactNode {
120
+ return this.getTextNode("\n", {});
121
+ }
122
+
123
+ del(children: ReactNode[], styles?: TextStyle): ReactNode {
124
+ return this.getTextNode(children, styles);
125
+ }
126
+
127
+ text(text: string | ReactNode[], styles?: TextStyle): ReactNode {
128
+ return this.getTextNode(text, styles);
129
+ }
130
+
131
+ html(text: string | ReactNode[], styles?: TextStyle): ReactNode {
132
+ return this.getTextNode(text, styles);
133
+ }
134
+
135
+ linkImage(
46
136
  href: string,
47
137
  imageUrl: string,
48
138
  alt?: string,
49
139
  style?: ImageStyle,
50
- ) => {
51
- const imageNode = this.getImageNode(imageUrl, alt, style);
140
+ ): ReactNode {
141
+ const imageNode = this.image(imageUrl, alt, style);
52
142
  return (
53
143
  <TouchableHighlight
54
144
  accessibilityRole="link"
55
145
  accessibilityHint="Opens in a new window"
56
146
  onPress={onLinkPress(href)}
57
- key={generateRandomString()}
147
+ key={this.getKey()}
58
148
  >
59
149
  {imageNode}
60
150
  </TouchableHighlight>
61
151
  );
62
- };
63
-
64
- getViewNode(children: ReactNode[] | null, styles?: ViewStyle) {
65
- return (
66
- <View key={generateRandomString()} style={styles}>
67
- {children}
68
- </View>
69
- );
70
152
  }
71
153
 
72
- getCodeBlockNode(
73
- text: string,
74
- containerStyle?: ViewStyle,
75
- textStyle?: TextStyle,
76
- ) {
77
- return (
78
- <ScrollView
79
- horizontal
80
- key={generateRandomString()}
81
- contentContainerStyle={containerStyle}
82
- >
83
- <Text style={textStyle}>{text}</Text>
84
- </ScrollView>
85
- );
154
+ getKey(): string {
155
+ return this.slugger.slug(this.slugPrefix);
86
156
  }
87
157
 
88
- getBlockquoteNode(children: ReactNode[], styles?: ViewStyle) {
158
+ private getTextNode(
159
+ children: string | ReactNode[],
160
+ styles?: TextStyle,
161
+ ): ReactNode {
89
162
  return (
90
- <View key={generateRandomString()} style={styles}>
163
+ <Text key={this.getKey()} style={styles}>
91
164
  {children}
92
- </View>
165
+ </Text>
93
166
  );
94
167
  }
95
168
 
96
- getImageNode(uri: string, alt?: string, style?: ImageStyle) {
97
- return (
98
- <MDImage key={generateRandomString()} uri={uri} alt={alt} style={style} />
99
- );
169
+ private getViewNode(
170
+ children: ReactNode[] | null,
171
+ styles?: ViewStyle,
172
+ ): ReactNode {
173
+ {
174
+ return (
175
+ <View key={this.getKey()} style={styles}>
176
+ {children}
177
+ </View>
178
+ );
179
+ }
100
180
  }
101
181
 
102
- getListNode(
103
- ordered: boolean,
104
- li: ReactNode[],
105
- listStyle?: ViewStyle,
106
- textStyle?: TextStyle,
107
- ) {
108
- return (
109
- <MarkedList
110
- counterRenderer={ordered ? Decimal : Disc}
111
- markerTextStyle={textStyle}
112
- markerBoxStyle={listStyle}
113
- key={generateRandomString()}
114
- >
115
- {li.map((node) => node)}
116
- </MarkedList>
117
- );
182
+ private getBlockquoteNode(
183
+ children: ReactNode[],
184
+ styles?: ViewStyle,
185
+ ): ReactNode {
186
+ {
187
+ return (
188
+ <View key={this.getKey()} style={styles}>
189
+ {children}
190
+ </View>
191
+ );
192
+ }
118
193
  }
119
194
  }
120
195
 
@@ -0,0 +1,186 @@
1
+ import React from "react";
2
+ import { screen } from "@testing-library/react-native";
3
+ import { measurePerformance } from "reassure";
4
+ import Markdown from "../Markdown";
5
+
6
+ const mdString = `Markdown Quick Reference
7
+ ========================
8
+
9
+ This guide is a very brief overview, with examples, of the syntax that [Markdown] supports. It is itself written in Markdown and you can copy the samples over to the left-hand pane for experimentation. It's shown as *text* and not *rendered HTML*.
10
+
11
+ [Markdown]: http://daringfireball.net/projects/markdown/
12
+
13
+
14
+ Simple Text Formatting
15
+ ======================
16
+
17
+ First thing is first. You can use *stars* or _underscores_ for italics. **Double stars** and __double underscores__ for bold. ***Three together*** for ___both___.
18
+
19
+ Paragraphs are pretty easy too. Just have a blank line between chunks of text.
20
+
21
+ > This chunk of text is in a block quote. Its multiple lines will all be
22
+ > indented a bit from the rest of the text.
23
+ >
24
+ > > Multiple levels of block quotes also work.
25
+
26
+ Sometimes you want to include code, such as when you are explaining how \`<h1>\` HTML tags work, or maybe you are a programmer and you are discussing \`someMethod()\`.
27
+
28
+ If you want to include code and have new
29
+ lines preserved, indent the line with a tab
30
+ or at least four spaces:
31
+
32
+ Extra spaces work here too.
33
+ This is also called preformatted text and it is useful for showing examples.
34
+ The text will stay as text, so any *markdown* or <u>HTML</u> you add will
35
+ not show up formatted. This way you can show markdown examples in a
36
+ markdown document.
37
+
38
+ > You can also use preformatted text with your blockquotes
39
+ > as long as you add at least five spaces.
40
+
41
+
42
+ Headings
43
+ ========
44
+
45
+ There are a couple of ways to make headings. Using three or more equals signs on a line under a heading makes it into an "h1" style. Three or more hyphens under a line makes it "h2" (slightly smaller). You can also use multiple pound symbols (\`#\`) before and after a heading. Pounds after the title are ignored. Here are some examples:
46
+
47
+ This is H1
48
+ ==========
49
+
50
+ This is H2
51
+ ----------
52
+
53
+ # This is H1
54
+ ## This is H2
55
+ ### This is H3 with some extra pounds ###
56
+ #### You get the idea ####
57
+ ##### I don't need extra pounds at the end
58
+ ###### H6 is the max
59
+
60
+
61
+ Links
62
+ =====
63
+
64
+ Let's link to a few sites. First, let's use the bare URL, like <https://www.github.com>. Great for text, but ugly for HTML.
65
+ Next is an inline link to [Google](https://www.google.com). A little nicer.
66
+ This is a reference-style link to [Wikipedia] [1].
67
+ Lastly, here's a pretty link to [Yahoo]. The reference-style and pretty links both automatically use the links defined below, but they could be defined *anywhere* in the markdown and are removed from the HTML. The names are also case insensitive, so you can use [YaHoO] and have it link properly.
68
+
69
+ [1]: https://www.wikipedia.org
70
+ [Yahoo]: https://www.yahoo.com
71
+
72
+ Title attributes may be added to links by adding text after a link.
73
+ This is the [inline link](https://www.bing.com "Bing") with a "Bing" title.
74
+ You can also go to [W3C] [2] and maybe visit a [friend].
75
+
76
+ [2]: https://w3c.org (The W3C puts out specs for web-based things)
77
+ [Friend]: https://facebook.com "Facebook!"
78
+
79
+ Email addresses in plain text are not linked: test@example.com.
80
+ Email addresses wrapped in angle brackets are linked: <test@example.com>.
81
+ They are also obfuscated so that email harvesting spam robots hopefully won't get them.
82
+
83
+
84
+ Lists
85
+ =====
86
+
87
+ * This is a bulleted list
88
+ * Great for shopping lists
89
+ - You can also use hyphens
90
+ + Or plus symbols
91
+
92
+ The above is an "unordered" list. Now, on for a bit of order.
93
+
94
+ 1. Numbered lists are also easy
95
+ 2. Just start with a number
96
+ 3738762. However, the actual number doesn't matter when converted to HTML.
97
+ 1. This will still show up as 4.
98
+
99
+ You might want a few advanced lists:
100
+
101
+ - This top-level list is wrapped in paragraph tags
102
+ - This generates an extra space between each top-level item.
103
+
104
+ - You do it by adding a blank line
105
+
106
+ - This nested list also has blank lines between the list items.
107
+
108
+ - How to create nested lists
109
+ 1. Start your regular list
110
+ 2. Indent nested lists with two spaces
111
+ 3. Further nesting means you should indent with two more spaces
112
+ * This line is indented with four spaces.
113
+
114
+ - List items can be quite lengthy. You can keep typing and either continue
115
+ them on the next line with no indentation.
116
+
117
+ - Alternately, if that looks ugly, you can also
118
+ indent the next line a bit for a prettier look.
119
+
120
+ - You can put large blocks of text in your list by just indenting with two spaces.
121
+
122
+ This is formatted the same as code, but you can inspect the HTML and find that it's just wrapped in a \`<p>\` tag and *won't* be shown as preformatted text.
123
+
124
+ You can keep adding more and more paragraphs to a single list item by adding the traditional blank line and then keep on indenting the paragraphs with two spaces.
125
+
126
+ You really only need to indent the first line,
127
+ but that looks ugly.
128
+
129
+ - Lists support blockquotes
130
+
131
+ > Just like this example here. By the way, you can
132
+ > nest lists inside blockquotes!
133
+ > - Fantastic!
134
+
135
+ - Lists support preformatted text
136
+
137
+ You just need to indent an additional four spaces.
138
+
139
+
140
+ Even More
141
+ =========
142
+
143
+ Horizontal Rule
144
+ ---------------
145
+
146
+ If you need a horizontal rule you just need to put at least three hyphens, asterisks, or underscores on a line by themselves. You can also even put spaces between the characters.
147
+
148
+ ---
149
+ ****************************
150
+ _ _ _ _ _ _ _
151
+
152
+ Those three all produced horizontal lines. Keep in mind that three hyphens under any text turns that text into a heading, so add a blank like if you use hyphens.
153
+
154
+ Images
155
+ ------
156
+
157
+ Images work exactly like links, but they have exclamation points in front. They work with references and titles too.
158
+
159
+ ![Google Logo](https://www.google.com/images/errors/logo_sm.gif) and ![Happy].
160
+
161
+ [Happy]: https://wpclipart.com/smiley/happy/simple_colors/smiley_face_simple_green_small.png ("Smiley face")
162
+
163
+
164
+ Inline HTML
165
+ -----------
166
+
167
+ If markdown is too limiting, you can just insert your own <strike>crazy</strike> HTML. Span-level HTML <u>can *still* use markdown</u>. Block level elements must be separated from text by a blank line and must not have any spaces before the opening and closing HTML.
168
+
169
+ <div style='font-family: "Comic Sans MS", "Comic Sans", cursive;'>
170
+ It is a pity, but markdown does **not** work in here for most markdown parsers.
171
+ [Marked] handles it pretty well.
172
+ </div>
173
+ `;
174
+
175
+ describe("Perf test", () => {
176
+ it("Renders markdown", async () => {
177
+ const scenario = async () => {
178
+ await screen.queryByText("Markdown Quick Reference");
179
+ await screen.queryByText("Inline HTML");
180
+ await screen.queryByText(
181
+ "If markdown is too limiting, you can just insert your own <strike>crazy</strike> HTML. Span-level HTML <u>can *still* use markdown</u>. Block level elements must be separated from text by a blank line and must not have any spaces before the opening and closing HTML.",
182
+ );
183
+ };
184
+ measurePerformance(<Markdown value={mdString} />, { scenario });
185
+ });
186
+ });