├── .gitignore
├── .npmignore
├── .prettierrc
├── LICENSE
├── README.md
├── README.v1.3.6.md
├── bin
├── copy-to-run.js
├── data.json
├── example.js
├── test.js
└── watch.js
├── doc
└── example
│ ├── simple-with-custom-renderer.md
│ ├── simple-with-custom-rules.md
│ ├── simple-with-custom-styles.md
│ └── simple.md
├── example
├── .babelrc
├── .buckconfig
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .watchmanconfig
├── App.js
├── android
│ ├── app
│ │ ├── BUCK
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ ├── MainActivity.java
│ │ │ │ └── MainApplication.java
│ │ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── keystores
│ │ ├── BUCK
│ │ └── debug.keystore.properties
│ └── settings.gradle
├── app.json
├── index.js
├── ios
│ ├── example-tvOS
│ │ └── Info.plist
│ ├── example-tvOSTests
│ │ └── Info.plist
│ ├── example.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ ├── example-tvOS.xcscheme
│ │ │ └── example.xcscheme
│ ├── example
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.xib
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ └── main.m
│ └── exampleTests
│ │ ├── Info.plist
│ │ └── exampleTests.m
├── package.json
├── react-native-markdown-renderer
│ ├── index.d.ts
│ ├── index.js
│ └── lib
│ │ ├── AstRenderer.js
│ │ ├── data
│ │ └── PlatformEnum.js
│ │ ├── parser.js
│ │ ├── plugin
│ │ ├── PluginContainer.js
│ │ └── blockPlugin.js
│ │ ├── renderRules.js
│ │ ├── styles.js
│ │ └── util
│ │ ├── Token.js
│ │ ├── applyStyle.js
│ │ ├── cleanupTokens.js
│ │ ├── flattenInlineTokens.js
│ │ ├── getTokenTypeByToken.js
│ │ ├── getUniqueID.js
│ │ ├── groupTextTokens.js
│ │ ├── hasParents.js
│ │ ├── openUrl.js
│ │ ├── splitTextNonTextNodes.js
│ │ ├── stringToTokens.js
│ │ └── tokensToAST.js
├── src
│ ├── code.js
│ ├── copy
│ │ ├── all.js
│ │ └── linkedimg.js
│ ├── copyAll.js
│ ├── copyAllCheckboxPlugin.js
│ ├── customMarkdownStyle.js
│ └── pluginRules.js
└── yarn.lock
├── export.json
├── package.json
└── src
├── index.d.ts
├── index.js
└── lib
├── AstRenderer.js
├── data
└── PlatformEnum.js
├── parser.js
├── plugin
├── PluginContainer.js
└── blockPlugin.js
├── renderRules.js
├── styles.js
└── util
├── Token.js
├── applyStyle.js
├── cleanupTokens.js
├── flattenInlineTokens.js
├── getTokenTypeByToken.js
├── getUniqueID.js
├── groupTextTokens.js
├── hasParents.js
├── openUrl.js
├── splitTextNonTextNodes.js
├── stringToTokens.js
└── tokensToAST.js
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /.idea
3 | package-lock.json
4 | /.DS_Store
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /example
2 | /.idea
3 | /bin
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": false,
3 | "printWidth": 120,
4 | "tabWidth": 2,
5 | "singleQuote": true,
6 | "trailingComma": "es5"
7 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Mient-jan Stelling
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Native Markdown Renderer [](https://badge.fury.io/js/react-native-markdown-renderer) [](https://snyk.io/test/github/mientjan/react-native-markdown-renderer)
2 |
3 | Is a 100% compatible CommonMark renderer, a react-native markdown renderer done right. This is __not__
4 | a web-view markdown renderer but a renderer that uses native components for all its elements. These components can be overwritten when needed as seen in the examples.
5 |
6 | ### Quick links
7 | - [Documentation](https://github.com/mientjan/react-native-markdown-renderer/wiki/)
8 | - [Examples](https://github.com/mientjan/react-native-markdown-renderer/wiki/Examples)
9 | - [Example App](https://github.com/mientjan/react-native-markdown-renderer/wiki/ExampleApp)
10 |
11 |
12 | ### Syntax Support
13 |
14 | To give a summary of the supported syntax react-native-markdown-renderer supports.
15 |
16 | - Tables
17 | - Heading 1 > 6
18 | - Horizontal Rules
19 | - Typographic replacements
20 | - Emphasis ( **bold**, *italic*, ~~strikethrough~~ )
21 | - Blockquotes
22 | - Lists
23 | - Ordered
24 | 57. Unordered
25 | 2. foo
26 | 3. bar
27 | - Code Blocks
28 | - Syntax highlighting
29 | - Links
30 | - Images
31 | - Plugins for **extra** syntax support, [see plugins](https://www.npmjs.com/browse/keyword/markdown-it-plugin). Because this markdown-renderer uses markdown-it as its base it also supports all its plugins and subsequent extra language support.
32 |
33 | ### Tested on:
34 |
35 | | [] | react | react-native | version |
36 | | -- | ----- | ------------ | ------- |
37 | | v | 16.2 | 0.50.4 | 3.0.0 |
38 | | v | 16.0.0-alpha.12 | 0.45.1 | 2.0.5 |
39 | | v | 16.0.0-alpha.6 | 0.44.0 | 2.0.5 |
40 | | x | 15.x | ^0.46.4 | 2.0.5 |
41 |
42 | ### Todo
43 | - ~~add styleSheet support~~
44 | - ~~add plugin support~~
45 | - ~~add support for seperate rules~~
46 |
47 | ### How to:
48 |
49 | #### npm
50 | ```npm
51 | npm install -S react-native-markdown-renderer
52 | ```
53 | #### yarn
54 | ```npm
55 | yarn add react-native-markdown-renderer
56 | ```
57 |
58 | See [WIKI](https://github.com/mientjan/react-native-markdown-renderer/wiki/) for examples and documentation
59 |
60 | ---
61 |
62 | # Syntax Support
63 |
64 | __Advertisement :)__
65 |
66 | - __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
67 | resize in browser.
68 | - __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly
69 | i18n with plurals support and easy syntax.
70 |
71 | You will like those projects!
72 |
73 | ---
74 |
75 | # h1 Heading 8-)
76 | ## h2 Heading
77 | ### h3 Heading
78 | #### h4 Heading
79 | ##### h5 Heading
80 | ###### h6 Heading
81 |
82 |
83 | ### Horizontal Rules
84 |
85 | ___
86 |
87 | ---
88 |
89 |
90 | ### Typographic replacements
91 |
92 | Enable typographer option to see result.
93 |
94 | (c) (C) (r) (R) (tm) (TM) (p) (P) +-
95 |
96 | test.. test... test..... test?..... test!....
97 |
98 | !!!!!! ???? ,, -- ---
99 |
100 | "Smartypants, double quotes" and 'single quotes'
101 |
102 |
103 | ## Emphasis
104 |
105 | **This is bold text**
106 |
107 | __This is bold text__
108 |
109 | *This is italic text*
110 |
111 | _This is italic text_
112 |
113 | ~~Strikethrough~~
114 |
115 |
116 | ## Blockquotes
117 |
118 |
119 | > Blockquotes can also be nested...
120 | >> ...by using additional greater-than signs right next to each other...
121 | > > > ...or with spaces between arrows.
122 |
123 |
124 | ## Lists
125 |
126 | Unordered
127 |
128 | + Create a list by starting a line with `+`, `-`, or `*`
129 | + Sub-lists are made by indenting 2 spaces:
130 | - Marker character change forces new list start:
131 | * Ac tristique libero volutpat at
132 | + Facilisis in pretium nisl aliquet
133 | - Nulla volutpat aliquam velit
134 | + Very easy!
135 |
136 | Ordered
137 |
138 | 1. Lorem ipsum dolor sit amet
139 | 2. Consectetur adipiscing elit
140 | 3. Integer molestie lorem at massa
141 |
142 |
143 | 1. You can use sequential numbers...
144 | 1. ...or keep all the numbers as `1.`
145 |
146 | Start numbering with offset:
147 |
148 | 57. foo
149 | 1. bar
150 |
151 |
152 | ## Code
153 |
154 | Inline `code`
155 |
156 | Indented code
157 |
158 | // Some comments
159 | line 1 of code
160 | line 2 of code
161 | line 3 of code
162 |
163 |
164 | Block code "fences"
165 |
166 | ```
167 | Sample text here...
168 | ```
169 |
170 | Syntax highlighting
171 |
172 | ``` js
173 | var foo = function (bar) {
174 | return bar++;
175 | };
176 |
177 | console.log(foo(5));
178 | ```
179 |
180 | ## Tables
181 |
182 | | Option | Description |
183 | | ------ | ----------- |
184 | | data | path to data files to supply the data that will be passed into templates. |
185 | | engine | engine to be used for processing templates. Handlebars is the default. |
186 | | ext | extension to be used for dest files. |
187 |
188 | Right aligned columns
189 |
190 | | Option | Description |
191 | | ------:| -----------:|
192 | | data | path to data files to supply the data that will be passed into templates. |
193 | | engine | engine to be used for processing templates. Handlebars is the default. |
194 | | ext | extension to be used for dest files. |
195 |
196 |
197 | ## Links
198 |
199 | [link text](http://dev.nodeca.com)
200 |
201 | [link with title](http://nodeca.github.io/pica/demo/ "title text!")
202 |
203 | Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
204 |
205 |
206 | ## Images
207 |
208 | 
209 | 
210 |
211 | Like links, Images also have a footnote style syntax
212 |
213 | ![Alt text][id]
214 |
215 | With a reference later in the document defining the URL location:
216 |
217 | [id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
218 |
--------------------------------------------------------------------------------
/README.v1.3.6.md:
--------------------------------------------------------------------------------
1 | # React Native Markdown Renderer [](https://badge.fury.io/js/react-native-markdown-renderer) [](https://snyk.io/test/github/mientjan/react-native-markdown-renderer)
2 |
3 | Is a 100% compatible CommonMark renderer, a react-native markdown renderer done right. This is __not__
4 | a web-view markdown renderer but a renderer that uses native components for all its elements. These components can be overwritten when needed as seen in the examples.
5 |
6 | To give a summary of the supported syntax react-native-markdown-renderer supports.
7 |
8 | - Tables
9 | - Heading 1 > 6
10 | - Horizontal Rules
11 | - Typographic replacements
12 | - Emphasis ( **bold**, *italic*, ~~strikethrough~~ )
13 | - Blockquotes
14 | - Lists
15 | - Ordered
16 | 57. Unordered
17 | 2. foo
18 | 3. bar
19 | - Code Blocks
20 | - Syntax highlighting
21 | - Links
22 | - Images
23 | - Plugins for extra syntax support, [see plugins](https://www.npmjs.com/browse/keyword/markdown-it-plugin). Because this markdown-renderer uses markdown-it as its base it also supports all its plugins and subsequent extra language support.
24 |
25 |
26 | ### tested on:
27 |
28 | | [] | react | react-native |
29 | | ---- | ---- | ------- |
30 | | v | 16.0.0-alpha.12 | 0.45.1 |
31 | | v | 16.0.0-alpha.6 | 0.44.0 |
32 | | v | ^15.6.1 | ^0.46.4 |
33 |
34 | ### todo
35 | - add styleSheet support
36 | - add styleSheet inheritance support
37 | - ~~adding plugin support~~
38 |
39 | ### How to:
40 |
41 | #### npm
42 | ```npm
43 | npm install -S react-native-markdown-renderer
44 | ```
45 | #### yarn
46 | ```npm
47 | yarn add react-native-markdown-renderer
48 | ```
49 |
50 | ### Example:
51 | ##### Simple example
52 | ```js
53 |
54 | import react from 'react';
55 | import {View, PureComponent} from 'react-native';
56 | import Markdown from 'react-native-markdown-renderer';
57 |
58 | const copy = `# h1 Heading 8-)
59 |
60 | | Option | Description |
61 | | ------ | ----------- |
62 | | data | path to data files to supply the data that will be passed into templates. |
63 | | engine | engine to be used for processing templates. Handlebars is the default. |
64 | | ext | extension to be used for dest files. |
65 | `;
66 |
67 | export default class Page extends PureComponent {
68 |
69 | static propTypes = {};
70 | static defaultProps = {};
71 |
72 | render() {
73 |
74 | return (
75 | {copy}
76 | );
77 | }
78 | }
79 | ```
80 |
81 | ##### If you want to use your own native elements and styling, and want to add extra plugins:
82 | ```js
83 |
84 | import react from 'react';
85 | import {View, PureComponent, Text} from 'react-native';
86 | import Markdown, { AstRenderer, defaultRenderFunctions, PluginContainer, blockPlugin} from 'react-native-markdown-renderer';
87 |
88 | const copy = `# h1 Heading 8-)
89 |
90 | | Option | Description |
91 | | ------ | ----------- |
92 | | data | path to data files to supply the data that will be passed into templates. |
93 | | engine | engine to be used for processing templates. Handlebars is the default. |
94 | | ext | extension to be used for dest files. |
95 |
96 | [block]
97 | I'm in a block
98 | [/block]
99 | `;
100 |
101 | /**
102 | * i'm overriding the default h1 render function.
103 | */
104 | const renderer = new AstRenderer({
105 | ...defaultRenderFunctions,
106 | h1: (node, children, parents) => {
107 | return {children};
108 | },
109 | // added custom block element defined by plugin
110 | block: (node, children, parents) => {
111 | return {children};
112 | }
113 | });
114 |
115 | export default class Page extends PureComponent {
116 |
117 | static propTypes = {};
118 | static defaultProps = {};
119 |
120 | render() {
121 |
122 | const plugins = [
123 | new PluginContainer(blockPlugin, 'block', {})
124 | ];
125 |
126 | return (
127 | {copy}
128 | );
129 | }
130 | }
131 | ```
132 |
133 | ---
134 |
135 |
136 | # Syntax Support
137 |
138 | __Advertisement :)__
139 |
140 | - __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
141 | resize in browser.
142 | - __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly
143 | i18n with plurals support and easy syntax.
144 |
145 | You will like those projects!
146 |
147 | ---
148 |
149 | # h1 Heading 8-)
150 | ## h2 Heading
151 | ### h3 Heading
152 | #### h4 Heading
153 | ##### h5 Heading
154 | ###### h6 Heading
155 |
156 |
157 | ### Horizontal Rules
158 |
159 | ___
160 |
161 | ---
162 |
163 |
164 | ### Typographic replacements
165 |
166 | Enable typographer option to see result.
167 |
168 | (c) (C) (r) (R) (tm) (TM) (p) (P) +-
169 |
170 | test.. test... test..... test?..... test!....
171 |
172 | !!!!!! ???? ,, -- ---
173 |
174 | "Smartypants, double quotes" and 'single quotes'
175 |
176 |
177 | ## Emphasis
178 |
179 | **This is bold text**
180 |
181 | __This is bold text__
182 |
183 | *This is italic text*
184 |
185 | _This is italic text_
186 |
187 | ~~Strikethrough~~
188 |
189 |
190 | ## Blockquotes
191 |
192 |
193 | > Blockquotes can also be nested...
194 | >> ...by using additional greater-than signs right next to each other...
195 | > > > ...or with spaces between arrows.
196 |
197 |
198 | ## Lists
199 |
200 | Unordered
201 |
202 | + Create a list by starting a line with `+`, `-`, or `*`
203 | + Sub-lists are made by indenting 2 spaces:
204 | - Marker character change forces new list start:
205 | * Ac tristique libero volutpat at
206 | + Facilisis in pretium nisl aliquet
207 | - Nulla volutpat aliquam velit
208 | + Very easy!
209 |
210 | Ordered
211 |
212 | 1. Lorem ipsum dolor sit amet
213 | 2. Consectetur adipiscing elit
214 | 3. Integer molestie lorem at massa
215 |
216 |
217 | 1. You can use sequential numbers...
218 | 1. ...or keep all the numbers as `1.`
219 |
220 | Start numbering with offset:
221 |
222 | 57. foo
223 | 1. bar
224 |
225 |
226 | ## Code
227 |
228 | Inline `code`
229 |
230 | Indented code
231 |
232 | // Some comments
233 | line 1 of code
234 | line 2 of code
235 | line 3 of code
236 |
237 |
238 | Block code "fences"
239 |
240 | ```
241 | Sample text here...
242 | ```
243 |
244 | Syntax highlighting
245 |
246 | ``` js
247 | var foo = function (bar) {
248 | return bar++;
249 | };
250 |
251 | console.log(foo(5));
252 | ```
253 |
254 | ## Tables
255 |
256 | | Option | Description |
257 | | ------ | ----------- |
258 | | data | path to data files to supply the data that will be passed into templates. |
259 | | engine | engine to be used for processing templates. Handlebars is the default. |
260 | | ext | extension to be used for dest files. |
261 |
262 | Right aligned columns
263 |
264 | | Option | Description |
265 | | ------:| -----------:|
266 | | data | path to data files to supply the data that will be passed into templates. |
267 | | engine | engine to be used for processing templates. Handlebars is the default. |
268 | | ext | extension to be used for dest files. |
269 |
270 |
271 | ## Links
272 |
273 | [link text](http://dev.nodeca.com)
274 |
275 | [link with title](http://nodeca.github.io/pica/demo/ "title text!")
276 |
277 | Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
278 |
279 |
280 | ## Images
281 |
282 | 
283 | 
284 |
285 | Like links, Images also have a footnote style syntax
286 |
287 | ![Alt text][id]
288 |
289 | With a reference later in the document defining the URL location:
290 |
291 | [id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
292 |
--------------------------------------------------------------------------------
/bin/copy-to-run.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs-extra");
2 | const path = require("path");
3 |
4 | const location = path.join(__dirname, "../src");
5 | const destination = path.join(
6 | location,
7 | "../example/react-native-markdown-renderer"
8 | );
9 |
10 | fs.remove(destination, err => {
11 | fs.copy(location, destination, err => {
12 | if (err) return console.error(err);
13 |
14 | console.log("to %s ", destination);
15 | console.log("success!");
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/bin/data.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "type": "paragraph",
4 | "tag": "p",
5 | "attrs": null,
6 | "map": [2, 3],
7 | "nesting": 1,
8 | "level": 0,
9 | "children": null,
10 | "content": "",
11 | "markup": "",
12 | "info": "",
13 | "meta": null,
14 | "block": true,
15 | "hidden": false
16 | },
17 | {
18 | "type": "text",
19 | "tag": "",
20 | "attrs": null,
21 | "map": null,
22 | "nesting": 0,
23 | "level": 0,
24 | "children": null,
25 | "content": "image:",
26 | "markup": "",
27 | "info": "",
28 | "meta": null,
29 | "block": false,
30 | "hidden": false
31 | },
32 | {
33 | "type": "paragraph",
34 | "tag": "p",
35 | "attrs": null,
36 | "map": null,
37 | "nesting": -1,
38 | "level": 0,
39 | "children": null,
40 | "content": "",
41 | "markup": "",
42 | "info": "",
43 | "meta": null,
44 | "block": true,
45 | "hidden": false
46 | },
47 | {
48 | "type": "paragraph",
49 | "tag": "p",
50 | "attrs": null,
51 | "map": [4, 5],
52 | "nesting": 1,
53 | "level": 0,
54 | "children": null,
55 | "content": "",
56 | "markup": "",
57 | "info": "",
58 | "meta": null,
59 | "block": true,
60 | "hidden": false
61 | },
62 | {
63 | "type": "image",
64 | "tag": "img",
65 | "attrs": [["src", "https://octodex.github.com/images/minion.png"], ["alt", ""]],
66 | "map": null,
67 | "nesting": 0,
68 | "level": 0,
69 | "children": [
70 | {
71 | "type": "text",
72 | "tag": "",
73 | "attrs": null,
74 | "map": null,
75 | "nesting": 0,
76 | "level": 0,
77 | "children": null,
78 | "content": "Minion",
79 | "markup": "",
80 | "info": "",
81 | "meta": null,
82 | "block": false,
83 | "hidden": false
84 | }
85 | ],
86 | "content": "Minion",
87 | "markup": "",
88 | "info": "",
89 | "meta": null,
90 | "block": false,
91 | "hidden": false
92 | },
93 | {
94 | "type": "paragraph",
95 | "tag": "p",
96 | "attrs": null,
97 | "map": null,
98 | "nesting": -1,
99 | "level": 0,
100 | "children": null,
101 | "content": "",
102 | "markup": "",
103 | "info": "",
104 | "meta": null,
105 | "block": true,
106 | "hidden": false
107 | },
108 | {
109 | "type": "paragraph",
110 | "tag": "p",
111 | "attrs": null,
112 | "map": [6, 7],
113 | "nesting": 1,
114 | "level": 0,
115 | "children": null,
116 | "content": "",
117 | "markup": "",
118 | "info": "",
119 | "meta": null,
120 | "block": true,
121 | "hidden": false
122 | },
123 | {
124 | "type": "text",
125 | "tag": "",
126 | "attrs": null,
127 | "map": null,
128 | "nesting": 0,
129 | "level": 0,
130 | "children": null,
131 | "content": "copy",
132 | "markup": "",
133 | "info": "",
134 | "meta": null,
135 | "block": false,
136 | "hidden": false
137 | },
138 | {
139 | "type": "paragraph",
140 | "tag": "p",
141 | "attrs": null,
142 | "map": null,
143 | "nesting": -1,
144 | "level": 0,
145 | "children": null,
146 | "content": "",
147 | "markup": "",
148 | "info": "",
149 | "meta": null,
150 | "block": true,
151 | "hidden": false
152 | },
153 | {
154 | "type": "paragraph",
155 | "tag": "p",
156 | "attrs": null,
157 | "map": [8, 9],
158 | "nesting": 1,
159 | "level": 0,
160 | "children": null,
161 | "content": "",
162 | "markup": "",
163 | "info": "",
164 | "meta": null,
165 | "block": true,
166 | "hidden": false
167 | },
168 | {
169 | "type": "blocklink",
170 | "tag": "a",
171 | "attrs": [["href", "http://dev.nodeca.com"]],
172 | "map": null,
173 | "nesting": 1,
174 | "level": 1,
175 | "children": null,
176 | "content": "",
177 | "markup": "",
178 | "info": "",
179 | "meta": null,
180 | "block": false,
181 | "hidden": false
182 | },
183 | {
184 | "type": "image",
185 | "tag": "img",
186 | "attrs": [["src", "https://octodex.github.com/images/minion.png"], ["alt", ""]],
187 | "map": null,
188 | "nesting": 0,
189 | "level": 1,
190 | "children": [
191 | {
192 | "type": "text",
193 | "tag": "",
194 | "attrs": null,
195 | "map": null,
196 | "nesting": 0,
197 | "level": 0,
198 | "children": null,
199 | "content": "Minion",
200 | "markup": "",
201 | "info": "",
202 | "meta": null,
203 | "block": false,
204 | "hidden": false
205 | }
206 | ],
207 | "content": "Minion",
208 | "markup": "",
209 | "info": "",
210 | "meta": null,
211 | "block": false,
212 | "hidden": false
213 | },
214 | {
215 | "type": "blocklink",
216 | "tag": "a",
217 | "attrs": null,
218 | "map": null,
219 | "nesting": -1,
220 | "level": 0,
221 | "children": null,
222 | "content": "",
223 | "markup": "",
224 | "info": "",
225 | "meta": null,
226 | "block": false,
227 | "hidden": false
228 | },
229 | {
230 | "type": "paragraph",
231 | "tag": "p",
232 | "attrs": null,
233 | "map": null,
234 | "nesting": -1,
235 | "level": 0,
236 | "children": null,
237 | "content": "",
238 | "markup": "",
239 | "info": "",
240 | "meta": null,
241 | "block": true,
242 | "hidden": false
243 | },
244 | {
245 | "type": "paragraph",
246 | "tag": "p",
247 | "attrs": null,
248 | "map": [10, 11],
249 | "nesting": 1,
250 | "level": 0,
251 | "children": null,
252 | "content": "",
253 | "markup": "",
254 | "info": "",
255 | "meta": null,
256 | "block": true,
257 | "hidden": false
258 | },
259 | {
260 | "type": "text",
261 | "tag": "",
262 | "attrs": null,
263 | "map": null,
264 | "nesting": 0,
265 | "level": 0,
266 | "children": null,
267 | "content": "copy",
268 | "markup": "",
269 | "info": "",
270 | "meta": null,
271 | "block": false,
272 | "hidden": false
273 | },
274 | {
275 | "type": "paragraph",
276 | "tag": "p",
277 | "attrs": null,
278 | "map": null,
279 | "nesting": -1,
280 | "level": 0,
281 | "children": null,
282 | "content": "",
283 | "markup": "",
284 | "info": "",
285 | "meta": null,
286 | "block": true,
287 | "hidden": false
288 | },
289 | {
290 | "type": "paragraph",
291 | "tag": "p",
292 | "attrs": null,
293 | "map": [12, 13],
294 | "nesting": 1,
295 | "level": 0,
296 | "children": null,
297 | "content": "",
298 | "markup": "",
299 | "info": "",
300 | "meta": null,
301 | "block": true,
302 | "hidden": false
303 | },
304 | {
305 | "type": "text",
306 | "tag": "",
307 | "attrs": null,
308 | "map": null,
309 | "nesting": 0,
310 | "level": 0,
311 | "children": null,
312 | "content": "Inline ",
313 | "markup": "",
314 | "info": "",
315 | "meta": null,
316 | "block": false,
317 | "hidden": false
318 | },
319 | {
320 | "type": "code_inline",
321 | "tag": "code",
322 | "attrs": null,
323 | "map": null,
324 | "nesting": 0,
325 | "level": 0,
326 | "children": null,
327 | "content": "code",
328 | "markup": "`",
329 | "info": "",
330 | "meta": null,
331 | "block": false,
332 | "hidden": false
333 | },
334 | {
335 | "type": "paragraph",
336 | "tag": "p",
337 | "attrs": null,
338 | "map": null,
339 | "nesting": -1,
340 | "level": 0,
341 | "children": null,
342 | "content": "",
343 | "markup": "",
344 | "info": "",
345 | "meta": null,
346 | "block": true,
347 | "hidden": false
348 | },
349 | {
350 | "type": "paragraph",
351 | "tag": "p",
352 | "attrs": null,
353 | "map": [14, 15],
354 | "nesting": 1,
355 | "level": 0,
356 | "children": null,
357 | "content": "",
358 | "markup": "",
359 | "info": "",
360 | "meta": null,
361 | "block": true,
362 | "hidden": false
363 | },
364 | {
365 | "type": "text",
366 | "tag": "",
367 | "attrs": null,
368 | "map": null,
369 | "nesting": 0,
370 | "level": 0,
371 | "children": null,
372 | "content": "Indented code",
373 | "markup": "",
374 | "info": "",
375 | "meta": null,
376 | "block": false,
377 | "hidden": false
378 | },
379 | {
380 | "type": "paragraph",
381 | "tag": "p",
382 | "attrs": null,
383 | "map": null,
384 | "nesting": -1,
385 | "level": 0,
386 | "children": null,
387 | "content": "",
388 | "markup": "",
389 | "info": "",
390 | "meta": null,
391 | "block": true,
392 | "hidden": false
393 | },
394 | {
395 | "type": "code_block",
396 | "tag": "code",
397 | "attrs": null,
398 | "map": [16, 20],
399 | "nesting": 0,
400 | "level": 0,
401 | "children": null,
402 | "content": "// Some comments\nline 1 of code\nline 2 of code\nline 3 of code\n",
403 | "markup": "",
404 | "info": "",
405 | "meta": null,
406 | "block": true,
407 | "hidden": false
408 | },
409 | {
410 | "type": "paragraph",
411 | "tag": "p",
412 | "attrs": null,
413 | "map": [22, 23],
414 | "nesting": 1,
415 | "level": 0,
416 | "children": null,
417 | "content": "",
418 | "markup": "",
419 | "info": "",
420 | "meta": null,
421 | "block": true,
422 | "hidden": false
423 | },
424 | {
425 | "type": "text",
426 | "tag": "",
427 | "attrs": null,
428 | "map": null,
429 | "nesting": 0,
430 | "level": 0,
431 | "children": null,
432 | "content": "Block code “fences”",
433 | "markup": "",
434 | "info": "",
435 | "meta": null,
436 | "block": false,
437 | "hidden": false
438 | },
439 | {
440 | "type": "paragraph",
441 | "tag": "p",
442 | "attrs": null,
443 | "map": null,
444 | "nesting": -1,
445 | "level": 0,
446 | "children": null,
447 | "content": "",
448 | "markup": "",
449 | "info": "",
450 | "meta": null,
451 | "block": true,
452 | "hidden": false
453 | },
454 | {
455 | "type": "fence",
456 | "tag": "code",
457 | "attrs": null,
458 | "map": [24, 27],
459 | "nesting": 0,
460 | "level": 0,
461 | "children": null,
462 | "content": "Sample text here...\n",
463 | "markup": "```",
464 | "info": "",
465 | "meta": null,
466 | "block": true,
467 | "hidden": false
468 | },
469 | {
470 | "type": "paragraph",
471 | "tag": "p",
472 | "attrs": null,
473 | "map": [28, 29],
474 | "nesting": 1,
475 | "level": 0,
476 | "children": null,
477 | "content": "",
478 | "markup": "",
479 | "info": "",
480 | "meta": null,
481 | "block": true,
482 | "hidden": false
483 | },
484 | {
485 | "type": "text",
486 | "tag": "",
487 | "attrs": null,
488 | "map": null,
489 | "nesting": 0,
490 | "level": 0,
491 | "children": null,
492 | "content": "Syntax highlighting",
493 | "markup": "",
494 | "info": "",
495 | "meta": null,
496 | "block": false,
497 | "hidden": false
498 | },
499 | {
500 | "type": "paragraph",
501 | "tag": "p",
502 | "attrs": null,
503 | "map": null,
504 | "nesting": -1,
505 | "level": 0,
506 | "children": null,
507 | "content": "",
508 | "markup": "",
509 | "info": "",
510 | "meta": null,
511 | "block": true,
512 | "hidden": false
513 | },
514 | {
515 | "type": "fence",
516 | "tag": "code",
517 | "attrs": null,
518 | "map": [30, 37],
519 | "nesting": 0,
520 | "level": 0,
521 | "children": null,
522 | "content": "var foo = function (bar) {\n\treturn bar++;\n};\n\nconsole.log(foo(5));\n",
523 | "markup": "```",
524 | "info": " js",
525 | "meta": null,
526 | "block": true,
527 | "hidden": false
528 | }
529 | ]
530 |
--------------------------------------------------------------------------------
/bin/example.js:
--------------------------------------------------------------------------------
1 | const hello = `
2 | # Syntax Support
3 |
4 | __Advertisement :)__
5 |
6 | This is a text. Click [here](https://google.com) to open a link. Let's add some more text to see how this behaves.
7 |
8 | - __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
9 | resize in browser.
10 | - __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly
11 | i18n with plurals support and easy syntax.
12 |
13 | You will like those projects!
14 |
15 | ---
16 |
17 | # h1 Heading 8-)
18 | ## h2 Heading
19 | ### h3 Heading
20 | #### h4 Heading
21 | ##### h5 Heading
22 | ###### h6 Heading
23 |
24 |
25 | ### Horizontal Rules
26 |
27 | ___
28 |
29 | ---
30 |
31 |
32 | ### Typographic replacements
33 |
34 | Enable typographer option to see result.
35 |
36 | (c) (C) (r) (R) (tm) (TM) (p) (P) +-
37 |
38 | test.. test... test..... test?..... test!....
39 |
40 | !!!!!! ???? ,, -- ---
41 |
42 | "Smartypants, double quotes" and 'single quotes'
43 |
44 |
45 | ## Emphasis
46 |
47 | **This is bold text**
48 |
49 | __This is bold text__
50 |
51 | *This is italic text*
52 |
53 | _This is italic text_
54 |
55 | ~~Strikethrough~~
56 |
57 |
58 | ## Blockquotes
59 |
60 |
61 | > Blockquotes can also be nested...
62 | >> ...by using additional greater-than signs right next to each other...
63 | > > > ...or with spaces between arrows.
64 |
65 |
66 | ## Lists
67 |
68 | Unordered
69 |
70 | + Create a list by starting a line with \`+\`, \`-\`, or \`*\`
71 | + Sub-lists are made by indenting 2 spaces:
72 | - Marker character change forces new list start:
73 | * Ac tristique libero volutpat at
74 | + Facilisis in pretium nisl aliquet
75 | - Nulla volutpat aliquam velit
76 | + Very easy!
77 |
78 | Ordered
79 |
80 | 1. Lorem ipsum dolor sit amet
81 | 2. Consectetur adipiscing elit
82 | 3. Integer molestie lorem at massa
83 |
84 |
85 | 1. You can use sequential numbers...
86 | 1. ...or keep all the numbers as \`1.\`
87 |
88 | Start numbering with offset:
89 |
90 | 57. foo
91 | 1. bar
92 |
93 |
94 | ## Code
95 |
96 | Inline \`code\`
97 |
98 | Indented code
99 |
100 | // Some comments
101 | line 1 of code
102 | line 2 of code
103 | line 3 of code
104 |
105 |
106 | Block code "fences"
107 |
108 | \`\`\`
109 | Sample text here...
110 | \`\`\`
111 |
112 | Syntax highlighting
113 |
114 | \`\`\` js
115 | var foo = function (bar) {
116 | return bar++;
117 | };
118 |
119 | console.log(foo(5));
120 | \`\`\`
121 |
122 | ## Tables
123 |
124 | | Option | Description |
125 | | ------ | ----------- |
126 | | data | path to data files to supply the data that will be passed into templates. |
127 | | engine | engine to be used for processing templates. Handlebars is the default. |
128 | | ext | extension to be used for dest files. |
129 |
130 | Right aligned columns
131 |
132 | | Option | Description |
133 | | ------:| -----------:|
134 | | data | path to data files to supply the data that will be passed into templates. |
135 | | engine | engine to be used for processing templates. Handlebars is the default. |
136 | | ext | extension to be used for dest files. |
137 |
138 |
139 | ## Links
140 |
141 | [link text](http://dev.nodeca.com)
142 |
143 | [link with title](http://nodeca.github.io/pica/demo/ "title text!")
144 |
145 | Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
146 |
147 |
148 | ## Images
149 |
150 | 
151 | 
152 |
153 | Like links, Images also have a footnote style syntax
154 |
155 | ![Alt text][id]
156 |
157 | With a reference later in the document defining the URL location:
158 |
159 | [id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
160 | `;
161 |
162 | module.exports = hello;
--------------------------------------------------------------------------------
/bin/test.js:
--------------------------------------------------------------------------------
1 | const MarkdownIt = require('markdown-it');
2 | const copy = require('./example');
3 | const fs = require('fs');
4 |
5 | console.log(copy);
6 |
7 | const md = MarkdownIt({
8 | typographer: true,
9 | })
10 |
11 | fs.writeFile('./export.json', JSON.stringify(md.parse(copy, {})), err => {
12 | if(err) console.log('err', err);
13 | })
--------------------------------------------------------------------------------
/bin/watch.js:
--------------------------------------------------------------------------------
1 | const chokidar = require('chokidar');
2 | const fs = require('fs-extra');
3 | const path = require('path');
4 |
5 | const location = path.join(__dirname, '../src');
6 | const destination = path.join(location, '../example/react-native-markdown-renderer');
7 |
8 | const watcher = chokidar.watch(location + '/**/*');
9 | watcher.on('change', dir => {
10 |
11 |
12 | console.log('Updating %s by removing it', destination);
13 |
14 | fs.remove(destination, err => {
15 |
16 | console.log('Copy %s ', location);
17 |
18 | fs.copy(location, destination, err => {
19 | if (err) return console.error(err)
20 |
21 | console.log('to %s ', destination);
22 | console.log('success!')
23 | })
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/doc/example/simple-with-custom-renderer.md:
--------------------------------------------------------------------------------
1 | # Simple Implementation with custom styles
2 |
3 | docs for v3.0.0
4 |
5 | So to describe what i customized
6 | - Heading1 has a **fontSize** of 32, **backgroundColor** black and a **color** white.
7 | - all headers have a **border** at the bottom, of width 1 with a black color.
8 |
9 |
10 | ```jsx
11 | import react from 'react';
12 | import {View, PureComponent, Text} from 'react-native';
13 | import Markdown, { AstRenderer } from 'react-native-markdown-renderer';
14 | import { StyleSheet } from 'react-native';
15 |
16 | const styles = StyleSheet.create({
17 | heading: {
18 | borderBottomWidth: 1,
19 | borderColor: '#000000',
20 | },
21 | heading1: {
22 | fontSize: 32,
23 | backgroundColor: '#000000',
24 | color: '#FFFFFF',
25 | },
26 | heading2: {
27 | fontSize: 24,
28 | },
29 | heading3: {
30 | fontSize: 18,
31 | },
32 | heading4: {
33 | fontSize: 16,
34 | },
35 | heading5: {
36 | fontSize: 13,
37 | },
38 | heading6: {
39 | fontSize: 11,
40 | }
41 | });
42 |
43 | const copy = `
44 | # h1 Heading 8-)
45 | ## h2 Heading 8-)
46 | ### h3 Heading 8-)
47 |
48 | | Option | Description |
49 | | ------ | ----------- |
50 | | data | path to data files to supply the data that will be passed into templates. |
51 | | engine | engine to be used for processing templates. Handlebars is the default. |
52 | | ext | extension to be used for dest files. |
53 | `;
54 |
55 | export default class Page extends PureComponent {
56 | render() {
57 | return (
58 | {copy}
59 | );
60 | }
61 | }
62 | ```
--------------------------------------------------------------------------------
/doc/example/simple-with-custom-rules.md:
--------------------------------------------------------------------------------
1 | # Simple Implementation with custom Rules
2 |
3 | docs for v3.0.0
4 |
5 | So to describe what i customized
6 | - header1 will always look like ```[ h1 Heading 8-)]```
7 | - header2 will always look like ```[ h2 Heading 8-)]```
8 | - header3 will always look like ```[ h3 Heading 8-)]```
9 |
10 |
11 | ```jsx
12 | import react from 'react';
13 | import {View, PureComponent, Text} from 'react-native';
14 | import Markdown, {getUniqueID} from 'react-native-markdown-renderer';
15 |
16 | const rules = {
17 | heading1: (node, children, parent, styles) =>
18 |
19 | [{children}]
20 | ,
21 | heading2: (node, children, parent, styles) =>
22 |
23 | [{children}]
24 | ,
25 | heading3: (node, children, parent, styles) =>
26 |
27 | [{children}]
28 | ,
29 | });
30 |
31 | const copy = `
32 | # h1 Heading 8-)
33 | ## h2 Heading 8-)
34 | ### h3 Heading 8-)
35 |
36 | | Option | Description |
37 | | ------ | ----------- |
38 | | data | path to data files to supply the data that will be passed into templates. |
39 | | engine | engine to be used for processing templates. Handlebars is the default. |
40 | | ext | extension to be used for dest files. |
41 | `;
42 |
43 | export default class Page extends PureComponent {
44 | render() {
45 | return (
46 | {copy}
47 | );
48 | }
49 | }
50 | ```
--------------------------------------------------------------------------------
/doc/example/simple-with-custom-styles.md:
--------------------------------------------------------------------------------
1 | # Simple Implementation with custom styles
2 |
3 | docs for v3.0.0
4 |
5 | So to describe what i customized
6 | - Heading1 has a **fontSize** of 32, **backgroundColor** black and a **color** white.
7 | - all headers have a **border** at the bottom, of width 1 with a black color.
8 |
9 |
10 | ```jsx
11 | import react from 'react';
12 | import {View, PureComponent, Text} from 'react-native';
13 | import Markdown from 'react-native-markdown-renderer';
14 | import { StyleSheet } from 'react-native';
15 |
16 | const styles = StyleSheet.create({
17 | heading: {
18 | borderBottomWidth: 1,
19 | borderColor: '#000000',
20 | },
21 | heading1: {
22 | fontSize: 32,
23 | backgroundColor: '#000000',
24 | color: '#FFFFFF',
25 | },
26 | heading2: {
27 | fontSize: 24,
28 | },
29 | heading3: {
30 | fontSize: 18,
31 | },
32 | heading4: {
33 | fontSize: 16,
34 | },
35 | heading5: {
36 | fontSize: 13,
37 | },
38 | heading6: {
39 | fontSize: 11,
40 | }
41 | });
42 |
43 | const copy = `
44 | # h1 Heading 8-)
45 | ## h2 Heading 8-)
46 | ### h3 Heading 8-)
47 |
48 | | Option | Description |
49 | | ------ | ----------- |
50 | | data | path to data files to supply the data that will be passed into templates. |
51 | | engine | engine to be used for processing templates. Handlebars is the default. |
52 | | ext | extension to be used for dest files. |
53 | `;
54 |
55 | export default class Page extends PureComponent {
56 | render() {
57 | return (
58 | {copy}
59 | );
60 | }
61 | }
62 | ```
--------------------------------------------------------------------------------
/doc/example/simple.md:
--------------------------------------------------------------------------------
1 | # Basic Implementation
2 |
3 | docs for v3.0.0
4 |
5 | ```js
6 | import react from 'react';
7 | import {PureComponent} from 'react-native';
8 | import Markdown from 'react-native-markdown-renderer';
9 |
10 | const copy = `# h1 Heading 8-)
11 |
12 | | Option | Description |
13 | | ------ | ----------- |
14 | | data | path to data files to supply the data that will be passed into templates. |
15 | | engine | engine to be used for processing templates. Handlebars is the default. |
16 | | ext | extension to be used for dest files. |
17 | `;
18 |
19 | export default class Page extends PureComponent {
20 |
21 | static propTypes = {};
22 | static defaultProps = {};
23 |
24 | render() {
25 | return (
26 | {copy}
27 | );
28 | }
29 | }
30 | ```
31 |
32 |
33 | - updating docs Mient-jan Stelling 1/19/18, 13:00
34 | - updating readme Mient-jan Stelling 1/19/18, 12:59
35 | - Merge branch 'release/3.0.0' Mient-jan Stelling 1/19/18, 12:55
36 | - fixed issue where headers would now break to new line. Mient-jan Stelling 1/19/18, 12:54
37 | - fixed issue where images would not render. Mient-jan Stelling 1/19/18, 12:33
38 | - fixed issue where you could not set a general fontSize fo all copy. #17 Mient-jan Stelling 1/19/18, 12:06
39 | - adding small function so example wont break when starting it. Mient-jan Stelling 1/18/18, 18:55
40 | - updating to 3.0.0 because of breaking changes Mient-jan Stelling 1/18/18, 18:48
41 | - updating package.json to new react and react-native versions Mient-jan Stelling 1/18/18, 18:47
42 | - refactoring code so it will be easier to add plugins Mient-jan Stelling 1/18/18, 18:46
43 | - updating example code base Mient-jan Stelling 1/18/18, 18:39
44 | - adding watcher, for better development of component Mient-jan Stelling 1/18/18, 18:36
45 | - converting to new rule names, ul = bullet_list li = ordered_list a = link br = softbreak h1 <> h6 = heading1 <> heading6 Mient-jan Stelling 1/16/18, 14:13
46 | - adding type convert function for better support of new of writing tags. Mient-jan Stelling 1/16/18, 11:57
--------------------------------------------------------------------------------
/example/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react-native"]
3 | }
4 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | ; We fork some components by platform
3 | .*/*[.]android.js
4 |
5 | ; Ignore "BUCK" generated dirs
6 | /\.buckd/
7 |
8 | ; Ignore unexpected extra "@providesModule"
9 | .*/node_modules/.*/node_modules/fbjs/.*
10 |
11 | ; Ignore duplicate module providers
12 | ; For RN Apps installed via npm, "Libraries" folder is inside
13 | ; "node_modules/react-native" but in the source repo it is in the root
14 | .*/Libraries/react-native/React.js
15 |
16 | ; Ignore polyfills
17 | .*/Libraries/polyfills/.*
18 |
19 | ; Ignore metro
20 | .*/node_modules/metro/.*
21 |
22 | [include]
23 |
24 | [libs]
25 | node_modules/react-native/Libraries/react-native/react-native-interface.js
26 | node_modules/react-native/flow/
27 | node_modules/react-native/flow-github/
28 |
29 | [options]
30 | emoji=true
31 |
32 | module.system=haste
33 |
34 | munge_underscores=true
35 |
36 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
37 |
38 | module.file_ext=.js
39 | module.file_ext=.jsx
40 | module.file_ext=.json
41 | module.file_ext=.native.js
42 |
43 | suppress_type=$FlowIssue
44 | suppress_type=$FlowFixMe
45 | suppress_type=$FlowFixMeProps
46 | suppress_type=$FlowFixMeState
47 |
48 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
49 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
50 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
51 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
52 |
53 | [version]
54 | ^0.67.0
55 |
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | *.pbxproj -text
2 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | # Bundle artifact
56 | *.jsbundle
57 |
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/App.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | */
5 |
6 | import React, { Component } from 'react';
7 | import { Platform, Picker, ScrollView, StyleSheet, Text, View, Dimensions } from 'react-native';
8 |
9 | import Markdown, {
10 | AstRenderer,
11 | getUniqueID,
12 | PluginContainer,
13 | renderRules,
14 | styles,
15 | } from './react-native-markdown-renderer';
16 | //
17 | import markdownItCheckbox from 'markdown-it-checkbox';
18 | import { TabViewAnimated, SceneMap, TabBar } from 'react-native-tab-view';
19 |
20 | import copyAll from './src/copyAll';
21 | import customMarkdownStyle from './src/customMarkdownStyle';
22 | import copyAllCheckboxPlugin from './src/copyAllCheckboxPlugin';
23 | import pluginRules from './src/pluginRules';
24 | import all from './src/copy/all';
25 | import linkedimg from './src/copy/linkedimg';
26 |
27 | import MarkdownIt from 'markdown-it';
28 |
29 | const md = MarkdownIt({
30 | typographer: true,
31 | linkify: true,
32 | });
33 |
34 | md.linkify.tlds('.py', false); // disables .py as top level domain
35 | // Reload with full tlds list
36 | md.linkify.tlds('onion', true) // Add unofficial `.onion` domain
37 | md.linkify.add('git:', 'http:') // Add `git:` protocol as "alias"
38 | md.linkify.add('ftp:', null) // Disable `ftp:` ptotocol
39 | md.linkify.set({ fuzzyIP: true }); // Enable IPs in fuzzy links (without schema)
40 |
41 | md.linkify.add('@', {
42 | validate: function (text, pos, self) {
43 | var tail = text.slice(pos);
44 |
45 | if (!self.re.twitter) {
46 | self.re.twitter = new RegExp(
47 | '^([a-zA-Z0-9_]){1,15}(?!_)(?=$|' + self.re.src_ZPCc + ')'
48 | );
49 | }
50 | if (self.re.twitter.test(tail)) {
51 | // Linkifier allows punctuation chars before prefix,
52 | // but we additionally disable `@` ("@@mention" is invalid)
53 | if (pos >= 2 && tail[pos - 2] === '@') {
54 | return false;
55 | }
56 | return tail.match(self.re.twitter)[0].length;
57 | }
58 | return 0;
59 | },
60 | normalize: function (match) {
61 | match.url = 'https://twitter.com/' + match.url.replace(/^@/, '');
62 | }
63 | });
64 |
65 | const routes = {
66 | all: () => (
67 |
68 | (
77 |
78 | {node.content}
79 |
80 | ),
81 | }}
82 | plugins={[
83 | new PluginContainer(
84 | (md, name, options) => {
85 | const parse = state => {
86 | const Token = state.Token;
87 |
88 | for (let i = 0; i < state.tokens.length; i++) {
89 | const block = state.tokens[i];
90 | if (block.type !== 'inline') {
91 | continue;
92 | }
93 |
94 | for (let j = 0; j < block.children.length; j++) {
95 | const token = block.children[j];
96 | if (token.type !== 'text') {
97 | continue;
98 | }
99 |
100 | if (token.content === name) {
101 | const newToken = new Token(name, '', token.nesting);
102 |
103 | newToken.content = token.content;
104 | block.children = md.utils.arrayReplaceAt(block.children, j, [newToken]);
105 | }
106 | }
107 | }
108 | };
109 |
110 | md.core.ruler.after('inline', name, parse);
111 | },
112 | 'foo',
113 | {}
114 | ),
115 | ]}
116 | />
117 |
118 | ),
119 | linkedimg: () => (
120 |
121 |
122 |
123 | ),
124 | };
125 |
126 | const initialLayout = {
127 | height: 0,
128 | width: Dimensions.get('window').width,
129 | };
130 |
131 | export default class App extends Component {
132 | state = {
133 | index: 0,
134 | routes: [{ key: 'all', title: 'All' }, { key: 'linkedimg', title: 'Linked Images' }],
135 | };
136 |
137 | handleIndexChange = index => this.setState({ index });
138 | renderHeader = props => ;
139 | renderScene = SceneMap(routes);
140 |
141 | render() {
142 | return (
143 |
150 | );
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/example/android/app/BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | lib_deps = []
12 |
13 | for jarfile in glob(['libs/*.jar']):
14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
15 | lib_deps.append(':' + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
21 | for aarfile in glob(['libs/*.aar']):
22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
23 | lib_deps.append(':' + name)
24 | android_prebuilt_aar(
25 | name = name,
26 | aar = aarfile,
27 | )
28 |
29 | android_library(
30 | name = "all-libs",
31 | exported_deps = lib_deps,
32 | )
33 |
34 | android_library(
35 | name = "app-code",
36 | srcs = glob([
37 | "src/main/java/**/*.java",
38 | ]),
39 | deps = [
40 | ":all-libs",
41 | ":build_config",
42 | ":res",
43 | ],
44 | )
45 |
46 | android_build_config(
47 | name = "build_config",
48 | package = "com.example",
49 | )
50 |
51 | android_resource(
52 | name = "res",
53 | package = "com.example",
54 | res = "src/main/res",
55 | )
56 |
57 | android_binary(
58 | name = "app",
59 | keystore = "//android/keystores:debug",
60 | manifest = "src/main/AndroidManifest.xml",
61 | package_type = "debug",
62 | deps = [
63 | ":app-code",
64 | ],
65 | )
66 |
--------------------------------------------------------------------------------
/example/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: "com.android.application"
2 |
3 | import com.android.build.OutputFile
4 |
5 | /**
6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
7 | * and bundleReleaseJsAndAssets).
8 | * These basically call `react-native bundle` with the correct arguments during the Android build
9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
10 | * bundle directly from the development server. Below you can see all the possible configurations
11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the
12 | * `apply from: "../../node_modules/react-native/react.gradle"` line.
13 | *
14 | * project.ext.react = [
15 | * // the name of the generated asset file containing your JS bundle
16 | * bundleAssetName: "index.android.bundle",
17 | *
18 | * // the entry file for bundle generation
19 | * entryFile: "index.android.js",
20 | *
21 | * // whether to bundle JS and assets in debug mode
22 | * bundleInDebug: false,
23 | *
24 | * // whether to bundle JS and assets in release mode
25 | * bundleInRelease: true,
26 | *
27 | * // whether to bundle JS and assets in another build variant (if configured).
28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
29 | * // The configuration property can be in the following formats
30 | * // 'bundleIn${productFlavor}${buildType}'
31 | * // 'bundleIn${buildType}'
32 | * // bundleInFreeDebug: true,
33 | * // bundleInPaidRelease: true,
34 | * // bundleInBeta: true,
35 | *
36 | * // whether to disable dev mode in custom build variants (by default only disabled in release)
37 | * // for example: to disable dev mode in the staging build type (if configured)
38 | * devDisabledInStaging: true,
39 | * // The configuration property can be in the following formats
40 | * // 'devDisabledIn${productFlavor}${buildType}'
41 | * // 'devDisabledIn${buildType}'
42 | *
43 | * // the root of your project, i.e. where "package.json" lives
44 | * root: "../../",
45 | *
46 | * // where to put the JS bundle asset in debug mode
47 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
48 | *
49 | * // where to put the JS bundle asset in release mode
50 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release",
51 | *
52 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
53 | * // require('./image.png')), in debug mode
54 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
55 | *
56 | * // where to put drawable resources / React Native assets, e.g. the ones you use via
57 | * // require('./image.png')), in release mode
58 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
59 | *
60 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means
61 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
62 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle
63 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
64 | * // for example, you might want to remove it from here.
65 | * inputExcludes: ["android/**", "ios/**"],
66 | *
67 | * // override which node gets called and with what additional arguments
68 | * nodeExecutableAndArgs: ["node"],
69 | *
70 | * // supply additional arguments to the packager
71 | * extraPackagerArgs: []
72 | * ]
73 | */
74 |
75 | project.ext.react = [
76 | entryFile: "index.js"
77 | ]
78 |
79 | apply from: "../../node_modules/react-native/react.gradle"
80 |
81 | /**
82 | * Set this to true to create two separate APKs instead of one:
83 | * - An APK that only works on ARM devices
84 | * - An APK that only works on x86 devices
85 | * The advantage is the size of the APK is reduced by about 4MB.
86 | * Upload all the APKs to the Play Store and people will download
87 | * the correct one based on the CPU architecture of their device.
88 | */
89 | def enableSeparateBuildPerCPUArchitecture = false
90 |
91 | /**
92 | * Run Proguard to shrink the Java bytecode in release builds.
93 | */
94 | def enableProguardInReleaseBuilds = false
95 |
96 | android {
97 | compileSdkVersion 23
98 | buildToolsVersion "23.0.1"
99 |
100 | defaultConfig {
101 | applicationId "com.example"
102 | minSdkVersion 16
103 | targetSdkVersion 22
104 | versionCode 1
105 | versionName "1.0"
106 | ndk {
107 | abiFilters "armeabi-v7a", "x86"
108 | }
109 | }
110 | splits {
111 | abi {
112 | reset()
113 | enable enableSeparateBuildPerCPUArchitecture
114 | universalApk false // If true, also generate a universal APK
115 | include "armeabi-v7a", "x86"
116 | }
117 | }
118 | buildTypes {
119 | release {
120 | minifyEnabled enableProguardInReleaseBuilds
121 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
122 | }
123 | }
124 | // applicationVariants are e.g. debug, release
125 | applicationVariants.all { variant ->
126 | variant.outputs.each { output ->
127 | // For each separate APK per architecture, set a unique version code as described here:
128 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
129 | def versionCodes = ["armeabi-v7a":1, "x86":2]
130 | def abi = output.getFilter(OutputFile.ABI)
131 | if (abi != null) { // null for the universal-debug, universal-release variants
132 | output.versionCodeOverride =
133 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
134 | }
135 | }
136 | }
137 | }
138 |
139 | dependencies {
140 | compile fileTree(dir: "libs", include: ["*.jar"])
141 | compile "com.android.support:appcompat-v7:23.0.1"
142 | compile "com.facebook.react:react-native:+" // From node_modules
143 | }
144 |
145 | // Run this once to be able to run the application with BUCK
146 | // puts all compile dependencies into folder libs for BUCK to use
147 | task copyDownloadableDepsToLibs(type: Copy) {
148 | from configurations.compile
149 | into 'libs'
150 | }
151 |
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Disabling obfuscation is useful if you collect stack traces from production crashes
20 | # (unless you are using a system that supports de-obfuscate the stack traces).
21 | -dontobfuscate
22 |
23 | # React Native
24 |
25 | # Keep our interfaces so they can be used by other ProGuard rules.
26 | # See http://sourceforge.net/p/proguard/bugs/466/
27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
30 |
31 | # Do not strip any method/class that is annotated with @DoNotStrip
32 | -keep @com.facebook.proguard.annotations.DoNotStrip class *
33 | -keep @com.facebook.common.internal.DoNotStrip class *
34 | -keepclassmembers class * {
35 | @com.facebook.proguard.annotations.DoNotStrip *;
36 | @com.facebook.common.internal.DoNotStrip *;
37 | }
38 |
39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
40 | void set*(***);
41 | *** get*();
42 | }
43 |
44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; }
46 | -keepclassmembers,includedescriptorclasses class * { native ; }
47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; }
48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; }
49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; }
50 |
51 | -dontwarn com.facebook.react.**
52 |
53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
55 | -dontwarn android.text.StaticLayout
56 |
57 | # okhttp
58 |
59 | -keepattributes Signature
60 | -keepattributes *Annotation*
61 | -keep class okhttp3.** { *; }
62 | -keep interface okhttp3.** { *; }
63 | -dontwarn okhttp3.**
64 |
65 | # okio
66 |
67 | -keep class sun.misc.Unsafe { *; }
68 | -dontwarn java.nio.file.*
69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
70 | -dontwarn okio.**
71 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
13 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import com.facebook.react.ReactActivity;
4 |
5 | public class MainActivity extends ReactActivity {
6 |
7 | /**
8 | * Returns the name of the main component registered from JavaScript.
9 | * This is used to schedule rendering of the component.
10 | */
11 | @Override
12 | protected String getMainComponentName() {
13 | return "example";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/example/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.example;
2 |
3 | import android.app.Application;
4 |
5 | import com.facebook.react.ReactApplication;
6 | import com.facebook.react.ReactNativeHost;
7 | import com.facebook.react.ReactPackage;
8 | import com.facebook.react.shell.MainReactPackage;
9 | import com.facebook.soloader.SoLoader;
10 |
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | public class MainApplication extends Application implements ReactApplication {
15 |
16 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
17 | @Override
18 | public boolean getUseDeveloperSupport() {
19 | return BuildConfig.DEBUG;
20 | }
21 |
22 | @Override
23 | protected List getPackages() {
24 | return Arrays.asList(
25 | new MainReactPackage()
26 | );
27 | }
28 |
29 | @Override
30 | protected String getJSMainModuleName() {
31 | return "index";
32 | }
33 | };
34 |
35 | @Override
36 | public ReactNativeHost getReactNativeHost() {
37 | return mReactNativeHost;
38 | }
39 |
40 | @Override
41 | public void onCreate() {
42 | super.onCreate();
43 | SoLoader.init(this, /* native exopackage */ false);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mientjan/react-native-markdown-renderer/260fad084a11006201cc657fdc64f54d4625fd38/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mientjan/react-native-markdown-renderer/260fad084a11006201cc657fdc64f54d4625fd38/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mientjan/react-native-markdown-renderer/260fad084a11006201cc657fdc64f54d4625fd38/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mientjan/react-native-markdown-renderer/260fad084a11006201cc657fdc64f54d4625fd38/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | example
3 |
4 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:3.0.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | mavenLocal()
18 | jcenter()
19 | maven {
20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
21 | url "$rootDir/../node_modules/react-native/android"
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
20 | android.useDeprecatedNdk=true
21 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mientjan/react-native-markdown-renderer/260fad084a11006201cc657fdc64f54d4625fd38/example/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Jun 18 16:01:11 CEST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/example/android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/example/android/keystores/BUCK:
--------------------------------------------------------------------------------
1 | keystore(
2 | name = "debug",
3 | properties = "debug.keystore.properties",
4 | store = "debug.keystore",
5 | visibility = [
6 | "PUBLIC",
7 | ],
8 | )
9 |
--------------------------------------------------------------------------------
/example/android/keystores/debug.keystore.properties:
--------------------------------------------------------------------------------
1 | key.store=debug.keystore
2 | key.alias=androiddebugkey
3 | key.store.password=android
4 | key.alias.password=android
5 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'example'
2 |
3 | include ':app'
4 |
--------------------------------------------------------------------------------
/example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "displayName": "example"
4 | }
--------------------------------------------------------------------------------
/example/index.js:
--------------------------------------------------------------------------------
1 | import { AppRegistry } from 'react-native';
2 | import App from './App';
3 |
4 | AppRegistry.registerComponent('example', () => App);
5 |
--------------------------------------------------------------------------------
/example/ios/example-tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UIViewControllerBasedStatusBarAppearance
38 |
39 | NSLocationWhenInUseUsageDescription
40 |
41 | NSAppTransportSecurity
42 |
43 |
44 | NSExceptionDomains
45 |
46 | localhost
47 |
48 | NSExceptionAllowsInsecureHTTPLoads
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/example/ios/example-tvOSTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/example.xcodeproj/xcshareddata/xcschemes/example-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/example/ios/example.xcodeproj/xcshareddata/xcschemes/example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
43 |
49 |
50 |
51 |
52 |
53 |
58 |
59 |
61 |
67 |
68 |
69 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
82 |
92 |
94 |
100 |
101 |
102 |
103 |
104 |
105 |
111 |
113 |
119 |
120 |
121 |
122 |
124 |
125 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 |
10 | @interface AppDelegate : UIResponder
11 |
12 | @property (nonatomic, strong) UIWindow *window;
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/example/ios/example/AppDelegate.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import "AppDelegate.h"
9 |
10 | #import
11 | #import
12 |
13 | @implementation AppDelegate
14 |
15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
16 | {
17 | NSURL *jsCodeLocation;
18 |
19 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
20 |
21 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
22 | moduleName:@"example"
23 | initialProperties:nil
24 | launchOptions:launchOptions];
25 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
26 |
27 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
28 | UIViewController *rootViewController = [UIViewController new];
29 | rootViewController.view = rootView;
30 | self.window.rootViewController = rootViewController;
31 | [self.window makeKeyAndVisible];
32 | return YES;
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/example/ios/example/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example/ios/example/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/example/ios/example/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/example/ios/example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | example
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UIViewControllerBasedStatusBarAppearance
40 |
41 | NSLocationWhenInUseUsageDescription
42 |
43 | NSAppTransportSecurity
44 |
45 |
46 | NSExceptionDomains
47 |
48 | localhost
49 |
50 | NSExceptionAllowsInsecureHTTPLoads
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/example/ios/example/main.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 |
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/example/ios/exampleTests/exampleTests.m:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2015-present, Facebook, Inc.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | #import
9 | #import
10 |
11 | #import
12 | #import
13 |
14 | #define TIMEOUT_SECONDS 600
15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
16 |
17 | @interface exampleTests : XCTestCase
18 |
19 | @end
20 |
21 | @implementation exampleTests
22 |
23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
24 | {
25 | if (test(view)) {
26 | return YES;
27 | }
28 | for (UIView *subview in [view subviews]) {
29 | if ([self findSubviewInView:subview matching:test]) {
30 | return YES;
31 | }
32 | }
33 | return NO;
34 | }
35 |
36 | - (void)testRendersWelcomeScreen
37 | {
38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
40 | BOOL foundElement = NO;
41 |
42 | __block NSString *redboxError = nil;
43 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
44 | if (level >= RCTLogLevelError) {
45 | redboxError = message;
46 | }
47 | });
48 |
49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
52 |
53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
55 | return YES;
56 | }
57 | return NO;
58 | }];
59 | }
60 |
61 | RCTSetLogFunction(RCTDefaultLogFunction);
62 |
63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
65 | }
66 |
67 |
68 | @end
69 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "start": "node node_modules/react-native/local-cli/cli.js start",
7 | "ios": "react-native run-ios",
8 | "android": "react-native run-android",
9 | "dev": "node ../bin/watch",
10 | "test": "jest"
11 | },
12 | "dependencies": {
13 | "linkify-it": "^2.0.3",
14 | "markdown-it-checkbox": "^1.1.0",
15 | "prop-types": "^15.6.1",
16 | "react": "16.3.1",
17 | "react-native": "0.55.2",
18 | "react-native-fit-image": "^1.5.4",
19 | "react-native-markdown-renderer": "^3.2.0",
20 | "react-native-tab-view": "0.0.77"
21 | },
22 | "devDependencies": {
23 | "babel-jest": "22.4.3",
24 | "babel-preset-react-native": "4.0.0",
25 | "jest": "22.4.3",
26 | "markdown-it": "^8.4.1",
27 | "react-test-renderer": "16.3.1"
28 | },
29 | "jest": {
30 | "preset": "react-native"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/index.d.ts:
--------------------------------------------------------------------------------
1 | // tslint:disable:max-classes-per-file
2 | import { MarkdownIt, Token } from 'markdown-it';
3 | import { ComponentType, ReactNode } from 'react';
4 | import { StyleSheet, View } from 'react-native';
5 |
6 | export function applyStyle(children: any[], styles: any, type: string): any;
7 |
8 | export function getUniqueID(): string;
9 | export function openUrl(url: string): void;
10 |
11 | export function hasParents(parents: any[], type: string): boolean;
12 |
13 | export type RenderFunction = (
14 | node: any,
15 | children: ReactNode[],
16 | parent: ReactNode,
17 | styles: any,
18 | ) => ReactNode;
19 |
20 | export interface RenderRules {
21 | [name: string]: RenderFunction;
22 | }
23 |
24 | export const renderRules: RenderRules;
25 |
26 | export interface MarkdownParser {
27 | parse: (value: string, options: any) => Token[];
28 | }
29 |
30 | export interface ASTNode {
31 | type: string;
32 | sourceType: string; // original source token name
33 | key: string;
34 | content: string;
35 | tokenIndex: number;
36 | index: number;
37 | attributes: Record;
38 | children: ASTNode[];
39 | }
40 |
41 | export class AstRenderer {
42 | constructor(renderRules: RenderRules, style?: any);
43 | getRenderFunction(type: string): RenderFunction;
44 | renderNode(node: any, parentNodes: ReadonlyArray): ReactNode;
45 | render(nodes: ReadonlyArray): View;
46 | }
47 |
48 | export function parser(
49 | source: string,
50 | renderer: (node: ASTNode) => View,
51 | parser: MarkdownParser,
52 | ): any;
53 |
54 | export function stringToTokens(
55 | source: string,
56 | markdownIt: MarkdownParser,
57 | ): Token[];
58 |
59 | export function tokensToAST(tokens: ReadonlyArray): ASTNode[];
60 |
61 | interface PluginContainerResult extends Array {
62 | 0: A;
63 | }
64 |
65 | export class PluginContainer {
66 | constructor(plugin: A, ...options: any[]);
67 | toArray(): PluginContainerResult;
68 | }
69 |
70 | export function blockPlugin(md: any, name: string, options: object): any;
71 |
72 | export const styles: any;
73 |
74 | export interface MarkdownProps {
75 | rules?: RenderRules;
76 | style?: StyleSheet.NamedStyles;
77 | renderer?: AstRenderer;
78 | markdownit?: MarkdownIt;
79 | plugins?: Array>;
80 | }
81 |
82 | type MarkdownStatic = React.ComponentType;
83 | export const Markdown: MarkdownStatic;
84 | export type Markdown = MarkdownStatic;
85 |
86 | export default Markdown;
87 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Base Markdown component
3 | * @author Mient-jan Stelling
4 | */
5 | import React, { Component } from 'react';
6 | import PropTypes from 'prop-types';
7 | import { View } from 'react-native';
8 | import parser from './lib/parser';
9 | import applyStyle from './lib/util/applyStyle';
10 | import getUniqueID from './lib/util/getUniqueID';
11 | import hasParents from './lib/util/hasParents';
12 | import openUrl from './lib/util/openUrl';
13 | import tokensToAST from './lib/util/tokensToAST';
14 | import renderRules from './lib/renderRules';
15 | import AstRenderer from './lib/AstRenderer';
16 | import MarkdownIt from 'markdown-it';
17 | import PluginContainer from './lib/plugin/PluginContainer';
18 | import blockPlugin from './lib/plugin/blockPlugin';
19 | import { styles } from './lib/styles';
20 | import { stringToTokens } from './lib/util/stringToTokens';
21 | /**
22 | *
23 | */
24 | export {
25 | applyStyle,
26 | getUniqueID,
27 | openUrl,
28 | hasParents,
29 | renderRules,
30 | AstRenderer,
31 | parser,
32 | stringToTokens,
33 | tokensToAST,
34 | MarkdownIt,
35 | PluginContainer,
36 | blockPlugin,
37 | styles,
38 | };
39 |
40 | /**
41 | * react-native-markdown-renderer
42 | */
43 | export default class Markdown extends Component {
44 | /**
45 | * Definition of the prop types
46 | */
47 | static propTypes = {
48 | children: PropTypes.node.isRequired,
49 | renderer: PropTypes.oneOfType([PropTypes.func, PropTypes.instanceOf(AstRenderer)]),
50 | rules: (props, propName, componentName) => {
51 | let invalidProps = [];
52 | const prop = props[propName];
53 |
54 | if (!prop) {
55 | return;
56 | }
57 |
58 | if (typeof prop === 'object') {
59 | invalidProps = Object.keys(prop).filter(key => typeof prop[key] !== 'function');
60 | }
61 |
62 | if (typeof prop !== 'object') {
63 | return new Error(
64 | `Invalid prop \`${propName}\` supplied to \`${componentName}\`. Must be of shape {[index:string]:function} `
65 | );
66 | } else if (invalidProps.length > 0) {
67 | return new Error(
68 | `Invalid prop \`${propName}\` supplied to \`${componentName}\`. These ` +
69 | `props are not of type function \`${invalidProps.join(', ')}\` `
70 | );
71 | }
72 | },
73 | markdownit: PropTypes.instanceOf(MarkdownIt),
74 | plugins: PropTypes.arrayOf(PropTypes.instanceOf(PluginContainer)),
75 | style: PropTypes.any,
76 | };
77 |
78 | /**
79 | * Default Props
80 | */
81 | static defaultProps = {
82 | renderer: null,
83 | rules: null,
84 | plugins: [],
85 | style: null,
86 | markdownit: MarkdownIt({
87 | typographer: true,
88 | }),
89 | };
90 |
91 | copy = '';
92 | renderer = null;
93 | markdownParser = null;
94 |
95 | /**
96 | * Only when the copy changes will the markdown render again.
97 | * @param nextProps
98 | * @param nextState
99 | * @return {boolean}
100 | */
101 | shouldComponentUpdate(nextProps, nextState) {
102 | const copy = this.getCopyFromChildren(nextProps.children);
103 |
104 | if (copy !== this.copy) {
105 | this.copy = copy;
106 | return true;
107 | }
108 |
109 | if (
110 | nextProps.renderer !== this.props.renderer ||
111 | nextProps.style !== this.props.style ||
112 | nextProps.plugins !== this.props.plugins ||
113 | nextProps.rules !== this.props.rules ||
114 | nextProps.markdownit !== this.props.markdownit
115 | ) {
116 | return true;
117 | }
118 |
119 | return false;
120 | }
121 |
122 | /**
123 | *
124 | * @param props
125 | */
126 | updateSettings(props = this.props) {
127 | const { renderer, rules, style, plugins, markdownit } = props;
128 |
129 | if (renderer && rules) {
130 | console.warn(
131 | 'react-native-markdown-renderer you are using renderer and rules at the same time. This is not possible, props.rules is ignored'
132 | );
133 | }
134 |
135 | if (renderer && style) {
136 | console.warn(
137 | 'react-native-markdown-renderer you are using renderer and style at the same time. This is not possible, props.style is ignored'
138 | );
139 | }
140 |
141 | // these checks are here to prevent extra overhead.
142 | if (renderer) {
143 | if (typeof renderer === 'function') {
144 | if (!this.renderer || this.renderer.render !== renderer) {
145 | this.renderer = {
146 | render: renderer,
147 | };
148 | }
149 | } else if (renderer instanceof AstRenderer) {
150 | if (this.renderer !== renderer) {
151 | this.renderer = renderer;
152 | }
153 | } else {
154 | throw new Error('Provided renderer is not compatible with function or AstRenderer. please change');
155 | }
156 | } else {
157 | if (!this.renderer || this.props.renderer || this.props.rules !== rules || this.props.style !== style) {
158 | this.renderer = new AstRenderer(
159 | {
160 | ...renderRules,
161 | ...(rules || {}),
162 | },
163 | {
164 | ...styles,
165 | ...style,
166 | }
167 | );
168 | }
169 | }
170 |
171 | if (!this.markdownParser || this.props.markdownit !== markdownit || plugins !== this.props.plugins) {
172 | let md = markdownit;
173 | if (plugins && plugins.length > 0) {
174 | plugins.forEach(plugin => {
175 | md = md.use.apply(md, plugin.toArray());
176 | });
177 | }
178 |
179 | this.markdownParser = md;
180 | }
181 | }
182 |
183 | /**
184 | *
185 | */
186 | componentWillMount() {
187 | this.updateSettings(this.props);
188 | }
189 |
190 | /**
191 | *
192 | * @param nextProps
193 | */
194 | componentWillReceiveProps(nextProps) {
195 | this.updateSettings(nextProps);
196 | }
197 |
198 | /**
199 | *
200 | * @param children
201 | * @return {string}
202 | */
203 | getCopyFromChildren(children = this.props.children) {
204 | return children instanceof Array ? children.join('') : children;
205 | }
206 |
207 | /**
208 | *
209 | * @return {View}
210 | */
211 | render() {
212 | const copy = (this.copy = this.getCopyFromChildren());
213 | return parser(copy, this.renderer.render, this.markdownParser);
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/AstRenderer.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from "react";
2 | import { Text, View } from "react-native";
3 | import getUniqueID from "./util/getUniqueID";
4 |
5 | export function rootRenderRule(children, styles) {
6 | return {children};
7 | }
8 |
9 | /**
10 | *
11 | */
12 | export default class AstRenderer {
13 | /**
14 | *
15 | * @param {Object.} renderRules
16 | * @param {any} style
17 | */
18 | constructor(renderRules, style) {
19 | this._renderRules = renderRules;
20 | this._style = style;
21 | }
22 |
23 | /**
24 | *
25 | * @param {string} type
26 | * @return {string}
27 | */
28 | getRenderFunction = type => {
29 | const renderFunction = this._renderRules[type];
30 |
31 | if (!renderFunction) {
32 | throw new Error(
33 | `${type} renderRule not defined example: `
34 | );
35 | }
36 | return renderFunction;
37 | };
38 |
39 | /**
40 | *
41 | * @param node
42 | * @param parentNodes
43 | * @return {*}
44 | */
45 | renderNode = (node, parentNodes) => {
46 | const renderFunction = this.getRenderFunction(node.type);
47 |
48 | const parents = [...parentNodes];
49 | parents.unshift(node);
50 |
51 | if (node.type === "text") {
52 | return renderFunction(node, [], parentNodes, this._style);
53 | }
54 |
55 | const children = node.children.map(value => {
56 | return this.renderNode(value, parents);
57 | });
58 |
59 | return renderFunction(node, children, parentNodes, this._style);
60 | };
61 |
62 | /**
63 | *
64 | * @param nodes
65 | * @return {*}
66 | */
67 | render = nodes => {
68 | const children = nodes.map(value => this.renderNode(value, []));
69 | return rootRenderRule(children, this._style);
70 | };
71 | }
72 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/data/PlatformEnum.js:
--------------------------------------------------------------------------------
1 | export default {
2 | IOS: "ios",
3 | ANDROID: "android"
4 | };
5 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/parser.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import tokensToAST from './util/tokensToAST';
4 | import { stringToTokens } from './util/stringToTokens';
5 | import { cleanupTokens } from './util/cleanupTokens';
6 | import groupTextTokens from './util/groupTextTokens';
7 |
8 | /**
9 | *
10 | * @param {string} source
11 | * @param {function} [renderer]
12 | * @param {AstRenderer} [markdownIt]
13 | * @return {View}
14 | */
15 | export default function parser(source, renderer, markdownIt) {
16 | let tokens = stringToTokens(source, markdownIt);
17 | tokens = cleanupTokens(tokens);
18 | tokens = groupTextTokens(tokens);
19 |
20 | const astTree = tokensToAST(tokens);
21 |
22 | return renderer(astTree);
23 | }
24 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/plugin/PluginContainer.js:
--------------------------------------------------------------------------------
1 | export default class PluginContainer {
2 | constructor(plugin, ...options) {
3 | this.plugin = plugin;
4 | this.options = options;
5 | }
6 |
7 | toArray() {
8 | return [this.plugin, ...this.options];
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/plugin/blockPlugin.js:
--------------------------------------------------------------------------------
1 | /* code is still in beta, thats why im disabling linter */
2 | /* eslint-disable */
3 |
4 | /**
5 | * How to use?
6 | * new PluginContainer(blockPlugin, '__name_of_block__', {})
7 | * @param md
8 | * @param name
9 | * @param options
10 | */
11 | export default function blockPlugin(md, name, options) {
12 | function validateDefault(params) {
13 | return params.trim().split(' ', 2)[0] === name;
14 | }
15 |
16 | function renderDefault(tokens, idx, _options, env, self) {
17 | return self.renderToken(tokens, idx, _options, env, self);
18 | }
19 |
20 | options = options || {};
21 |
22 | let min_markers = 1;
23 | let marker_str = options.marker || `[${name}]`;
24 | let marker_end_str = options.marker_end || `[/${name}]`;
25 | let marker_char = marker_str.charCodeAt(0);
26 | let marker_len = marker_str.length;
27 | let marker_end_len = marker_end_str.length;
28 |
29 | let validate = options.validate || validateDefault;
30 | let render = options.render || renderDefault;
31 |
32 | function container(state, startLine, endLine, silent) {
33 | var pos,
34 | nextLine,
35 | marker_count,
36 | markup,
37 | params,
38 | token,
39 | old_parent,
40 | old_line_max,
41 | auto_closed = false,
42 | start = state.bMarks[startLine] + state.tShift[startLine],
43 | max = state.eMarks[startLine];
44 |
45 | // Check out the first character quickly,
46 | // this should filter out most of non-containers
47 | //
48 | if (marker_char !== state.src.charCodeAt(start)) {
49 | return false;
50 | }
51 |
52 | // Check out the rest of the marker string
53 | //
54 | for (pos = start + 1; pos <= max; pos++) {
55 | if (marker_str[(pos - start) % marker_len] !== state.src[pos]) {
56 | break;
57 | }
58 | }
59 |
60 | marker_count = Math.floor((pos - start) / marker_len);
61 | if (marker_count < min_markers) {
62 | return false;
63 | }
64 | pos -= (pos - start) % marker_len;
65 |
66 | markup = state.src.slice(start, pos);
67 | params = state.src.slice(pos, max);
68 |
69 | // if (!validate(params)) {
70 | // return false;
71 | // }
72 |
73 | // Since start is found, we can report success here in validation mode
74 | //
75 | if (silent) {
76 | return true;
77 | }
78 |
79 | // Search for the end of the block
80 | //
81 | nextLine = startLine;
82 |
83 | for (;;) {
84 | nextLine++;
85 | if (nextLine >= endLine) {
86 | // unclosed block should be autoclosed by end of document.
87 | // also block seems to be autoclosed by end of parent
88 | break;
89 | }
90 |
91 | start = state.bMarks[nextLine] + state.tShift[nextLine];
92 | max = state.eMarks[nextLine];
93 |
94 | if (start < max && state.sCount[nextLine] < state.blkIndent) {
95 | // non-empty line with negative indent should stop the list:
96 | // - ```
97 | // test
98 | break;
99 | }
100 |
101 | if (marker_char !== state.src.charCodeAt(start)) {
102 | continue;
103 | }
104 |
105 | if (state.sCount[nextLine] - state.blkIndent >= 4) {
106 | // closing fence should be indented less than 4 spaces
107 | continue;
108 | }
109 |
110 | for (pos = start + 1; pos <= max; pos++) {
111 | if (marker_end_str[(pos - start) % marker_end_len] !== state.src[pos]) {
112 | break;
113 | }
114 | }
115 |
116 | // closing code fence must be at least as long as the opening one
117 | if (Math.floor((pos - start) / marker_end_len) < marker_count) {
118 | continue;
119 | }
120 |
121 | // make sure tail has spaces only
122 | pos -= (pos - start) % marker_end_len;
123 | pos = state.skipSpaces(pos);
124 |
125 | if (pos < max) {
126 | continue;
127 | }
128 |
129 | // found!
130 | auto_closed = true;
131 | break;
132 | }
133 |
134 | old_parent = state.parentType;
135 | old_line_max = state.lineMax;
136 | state.parentType = 'container';
137 |
138 | // this will prevent lazy continuations from ever going past our end marker
139 | state.lineMax = nextLine;
140 |
141 | token = state.push(`container_${name}_open`, name, 1);
142 | token.markup = markup;
143 | token.block = true;
144 | token.info = params;
145 | token.map = [startLine, nextLine];
146 |
147 | state.md.block.tokenize(state, startLine + 1, nextLine);
148 |
149 | token = state.push(`container_${name}_close`, name, -1);
150 | token.markup = state.src.slice(start, pos);
151 | token.block = true;
152 |
153 | state.parentType = old_parent;
154 | state.lineMax = old_line_max;
155 | state.line = nextLine + (auto_closed ? 1 : 0);
156 |
157 | return true;
158 | }
159 |
160 | md.block.ruler.before('fence', 'container_checklist', container, {
161 | alt: ['paragraph', 'reference', 'blockquote', 'list'],
162 | });
163 |
164 | md.renderer.rules['container_' + name + '_open'] = render;
165 | md.renderer.rules['container_' + name + '_close'] = render;
166 | }
167 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/renderRules.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import { Text, TouchableWithoutFeedback, View } from 'react-native';
3 |
4 | import FitImage from 'react-native-fit-image';
5 | import openUrl from './util/openUrl';
6 | import hasParents from './util/hasParents';
7 | import applyStyle from './util/applyStyle';
8 |
9 | const renderRules = {
10 | // when unknown elements are introduced, so it wont break
11 | unknown: (node, children, parent, styles) => {
12 | return (
13 |
14 | {node.type}
15 |
16 | );
17 | },
18 |
19 | textgroup: (node, children, parent, styles) => {
20 | return (
21 |
22 | {children}
23 |
24 | );
25 | },
26 |
27 | inline: (node, children, parent, styles) => {
28 | return {children};
29 | },
30 |
31 | text: (node, children, parent, styles) => {
32 | return {node.content};
33 | },
34 | span: (node, children, parent, styles) => {
35 | return {children};
36 | },
37 |
38 | strong: (node, children, parent, styles) => {
39 | return (
40 |
41 | {children}
42 |
43 | );
44 | },
45 |
46 | s: (node, children, parent, styles) => {
47 | return (
48 |
49 | {children}
50 |
51 | );
52 | },
53 | // a
54 | link: (node, children, parent, styles) => {
55 | return (
56 | openUrl(node.attributes.href)}>
57 | {children}
58 |
59 | );
60 | },
61 | // a with a non text element nested inside
62 | blocklink: (node, children, parent, styles) => {
63 | return (
64 | openUrl(node.attributes.href)} style={styles.blocklink}>
65 | {children}
66 |
67 | );
68 | },
69 | em: (node, children, parent, styles) => {
70 | return (
71 |
72 | {children}
73 |
74 | );
75 | },
76 |
77 | heading1: (node, children, parent, styles) => {
78 | return (
79 |
80 | {applyStyle(children, [styles.heading, styles.heading1], 'Text')}
81 |
82 | );
83 | },
84 |
85 | heading2: (node, children, parent, styles) => {
86 | children = applyStyle(children, [styles.heading, styles.heading2], 'Text');
87 | return (
88 |
89 | {children}
90 |
91 | );
92 | },
93 | heading3: (node, children, parent, styles) => (
94 |
95 | {applyStyle(children, [styles.heading, styles.heading3], 'Text')}
96 |
97 | ),
98 | heading4: (node, children, parent, styles) => (
99 |
100 | {applyStyle(children, [styles.heading, styles.heading4], 'Text')}
101 |
102 | ),
103 | heading5: (node, children, parent, styles) => (
104 |
105 | {applyStyle(children, [styles.heading, styles.heading5], 'Text')}
106 |
107 | ),
108 | heading6: (node, children, parent, styles) => (
109 |
110 | {applyStyle(children, [styles.heading, styles.heading6], 'Text')}
111 |
112 | ),
113 |
114 | paragraph: (node, children, parent, styles) => (
115 |
116 | {children}
117 |
118 | ),
119 |
120 | hardbreak: (node, children, parent, styles) => ,
121 |
122 | blockquote: (node, children, parent, styles) => (
123 |
124 | {children}
125 |
126 | ),
127 | code_inline: (node, children, parent, styles) => {
128 | return (
129 |
130 | {node.content}
131 |
132 | );
133 | },
134 | code_block: (node, children, parent, styles) => {
135 | return (
136 |
137 | {node.content}
138 |
139 | );
140 | },
141 | fence: (node, children, parent, styles) => {
142 | return (
143 |
144 | {node.content}
145 |
146 | );
147 | },
148 | pre: (node, children, parent, styles) => (
149 |
150 | {children}
151 |
152 | ),
153 | // ul
154 | bullet_list: (node, children, parent, styles) => {
155 | return (
156 |
157 | {children}
158 |
159 | );
160 | },
161 | ordered_list: (node, children, parent, styles) => {
162 | return (
163 |
164 | {children}
165 |
166 | );
167 | },
168 | // li
169 | list_item: (node, children, parent, styles) => {
170 | if (hasParents(parent, 'bullet_list')) {
171 | return (
172 |
173 | {'\u00B7'}
174 | {children}
175 |
176 | );
177 | }
178 |
179 | if (hasParents(parent, 'ordered_list')) {
180 | return (
181 |
182 | {node.index + 1}{node.markup}
183 | {children}
184 |
185 | );
186 | }
187 |
188 | return (
189 |
190 | {children}
191 |
192 | );
193 | },
194 | table: (node, children, parent, styles) => (
195 |
196 | {children}
197 |
198 | ),
199 | thead: (node, children, parent, styles) => (
200 |
201 | {children}
202 |
203 | ),
204 | tbody: (node, children, parent, styles) => {children},
205 | th: (node, children, parent, styles) => {
206 | return (
207 |
208 | {children}
209 |
210 | );
211 | },
212 | tr: (node, children, parent, styles) => {
213 | return (
214 |
215 | {children}
216 |
217 | );
218 | },
219 | td: (node, children, parent, styles) => {
220 | return (
221 |
222 | {children}
223 |
224 | );
225 | },
226 | hr: (node, children, parent, styles) => {
227 | return ;
228 | },
229 |
230 | // br
231 | softbreak: (node, children, parent, styles) => {'\n'},
232 | image: (node, children, parent, styles) => {
233 | return ;
234 | },
235 | };
236 |
237 | export default renderRules;
238 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/styles.js:
--------------------------------------------------------------------------------
1 | import { Platform, StyleSheet } from 'react-native';
2 | import PlatformEnum from './data/PlatformEnum';
3 |
4 | /**
5 | *
6 | */
7 | export const styles = StyleSheet.create({
8 | root: {},
9 | view: {},
10 | codeBlock: {
11 | borderWidth: 1,
12 | borderColor: '#CCCCCC',
13 | backgroundColor: '#f5f5f5',
14 | padding: 10,
15 | borderRadius: 4,
16 | },
17 | codeInline: {
18 | borderWidth: 1,
19 | borderColor: '#CCCCCC',
20 | backgroundColor: '#f5f5f5',
21 | padding: 10,
22 | borderRadius: 4,
23 | },
24 | del: {
25 | backgroundColor: '#000000',
26 | },
27 | em: {
28 | fontStyle: 'italic',
29 | },
30 | headingContainer: {
31 | flexDirection: 'row',
32 | },
33 | heading: {},
34 | heading1: {
35 | fontSize: 32,
36 | },
37 | heading2: {
38 | fontSize: 24,
39 | },
40 | heading3: {
41 | fontSize: 18,
42 | },
43 | heading4: {
44 | fontSize: 16,
45 | },
46 | heading5: {
47 | fontSize: 13,
48 | },
49 | heading6: {
50 | fontSize: 11,
51 | },
52 | hr: {
53 | backgroundColor: '#000000',
54 | height: 1,
55 | },
56 | blockquote: {
57 | paddingHorizontal: 20,
58 | paddingVertical: 10,
59 | margin: 20,
60 | backgroundColor: '#CCCCCC',
61 | },
62 | inlineCode: {
63 | borderRadius: 3,
64 | borderWidth: 1,
65 | fontFamily: 'Courier',
66 | fontWeight: 'bold',
67 | },
68 | list: {},
69 | listItem: {
70 | flex: 1,
71 | flexWrap: 'wrap',
72 | // backgroundColor: 'green',
73 | },
74 | listUnordered: {},
75 |
76 | listUnorderedItem: {
77 | flexDirection: 'row',
78 | justifyContent: 'flex-start',
79 | },
80 |
81 | listUnorderedItemIcon: {
82 | marginLeft: 10,
83 | marginRight: 10,
84 | ...Platform.select({
85 | [PlatformEnum.IOS]: {
86 | lineHeight: 36,
87 | },
88 | [PlatformEnum.ANDROID]: {
89 | lineHeight: 30,
90 | },
91 | }),
92 | },
93 | listUnorderedItemText: {
94 | fontSize: 20,
95 | lineHeight: 20,
96 | },
97 |
98 | listOrdered: {},
99 | listOrderedItem: {
100 | flexDirection: 'row',
101 | },
102 | listOrderedItemIcon: {
103 | marginLeft: 10,
104 | marginRight: 10,
105 | ...Platform.select({
106 | [PlatformEnum.IOS]: {
107 | lineHeight: 36,
108 | },
109 | [PlatformEnum.ANDROID]: {
110 | lineHeight: 30,
111 | },
112 | }),
113 | },
114 | listOrderedItemText: {
115 | fontWeight: 'bold',
116 | lineHeight: 20,
117 | },
118 | paragraph: {
119 | marginTop: 10,
120 | marginBottom: 10,
121 | flexWrap: 'wrap',
122 | flexDirection: 'row',
123 | alignItems: 'flex-start',
124 | justifyContent: 'flex-start',
125 | },
126 | hardbreak: {
127 | width: '100%',
128 | height: 1,
129 | },
130 | strong: {
131 | fontWeight: 'bold',
132 | },
133 | table: {
134 | borderWidth: 1,
135 | borderColor: '#000000',
136 | borderRadius: 3,
137 | },
138 | tableHeader: {},
139 | tableHeaderCell: {
140 | flex: 1,
141 | // color: '#000000',
142 | padding: 5,
143 | // backgroundColor: 'green',
144 | },
145 | tableRow: {
146 | borderBottomWidth: 1,
147 | borderColor: '#000000',
148 | flexDirection: 'row',
149 | },
150 | tableRowCell: {
151 | flex: 1,
152 | padding: 5,
153 | },
154 | text: {},
155 | strikethrough: {
156 | textDecorationLine: 'line-through',
157 | },
158 | link: {
159 | textDecorationLine: 'underline',
160 | },
161 | blocklink: {
162 | flex: 1,
163 | borderColor: '#000000',
164 | borderBottomWidth: 1,
165 |
166 | },
167 | u: {
168 | borderColor: '#000000',
169 | borderBottomWidth: 1,
170 | },
171 | image: {
172 | flex: 1,
173 | },
174 | });
175 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/Token.js:
--------------------------------------------------------------------------------
1 | export default class Token {
2 | constructor(type, nesting = 0, children = null, block = false) {
3 | this.type = type;
4 | this.nesting = nesting;
5 | this.children = children;
6 | this.block = block;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/applyStyle.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Text } from 'react-native';
3 |
4 | /**
5 | *
6 | * @param Array children
7 | * @param Array styles
8 | * @param {string} type
9 | */
10 | export default function applyStyle(children, styles, type) {
11 | if (!(styles instanceof Array)) {
12 | styles = [styles];
13 | }
14 |
15 | return children.map(child => {
16 | if (child.type.displayName === type) {
17 | return ;
18 | }
19 |
20 | return child;
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/cleanupTokens.js:
--------------------------------------------------------------------------------
1 | import getTokenTypeByToken from './getTokenTypeByToken';
2 | import flattenInlineTokens from './flattenInlineTokens';
3 |
4 | export function cleanupTokens(tokens) {
5 | tokens = flattenInlineTokens(tokens);
6 | tokens.forEach(token => {
7 | token.type = getTokenTypeByToken(token);
8 |
9 | // set image and hardbreak to block elements
10 | if (token.type === 'image' || token.type === 'hardbreak') {
11 | token.block = true;
12 | }
13 | });
14 |
15 | /**
16 | * changing a link token to a blocklink to fix issue where link tokens with
17 | * nested non text tokens breaks component
18 | */
19 | const stack = [];
20 | tokens = tokens.reduce((acc, token, index) => {
21 | if (token.type === 'link' && token.nesting === 1) {
22 | stack.push(token);
23 | } else if (stack.length > 0 && token.type === 'link' && token.nesting === -1) {
24 | if (stack.some(stackToken => stackToken.block)) {
25 | stack[0].type = 'blocklink';
26 | stack[0].block = true;
27 | token.type = 'blocklink';
28 | token.block = true;
29 | }
30 |
31 | stack.push(token);
32 |
33 | while (stack.length) {
34 | acc.push(stack.shift());
35 | }
36 | } else if (stack.length > 0) {
37 | stack.push(token);
38 | } else {
39 | acc.push(token);
40 | }
41 |
42 | return acc;
43 | }, []);
44 |
45 | return tokens;
46 | }
47 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/flattenInlineTokens.js:
--------------------------------------------------------------------------------
1 | export default function flattenTokens(tokens) {
2 | return tokens.reduce((acc, curr) => {
3 | if (curr.type === 'inline' && curr.children && curr.children.length > 0) {
4 | const children = flattenTokens(curr.children);
5 | while (children.length) {
6 | acc.push(children.shift());
7 | }
8 | } else {
9 | acc.push(curr);
10 | }
11 |
12 | return acc;
13 | }, []);
14 | }
15 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/getTokenTypeByToken.js:
--------------------------------------------------------------------------------
1 | const regSelectOpenClose = /_open|_close/g;
2 | const regSelectHofH1 = /\w/g;
3 |
4 | /**
5 | *
6 | * @example {
7 | "type": "heading_open",
8 | "tag": "h1",
9 | "attrs": null,
10 | "map": [
11 | 1,
12 | 2
13 | ],
14 | "nesting": 1,
15 | "level": 0,
16 | "children": null,
17 | "content": "",
18 | "markup": "#",
19 | "info": "",
20 | "meta": null,
21 | "block": true,
22 | "hidden": false
23 | }
24 | * @param token
25 | * @return {String}
26 | */
27 | export default function getTokenTypeByToken(token) {
28 | let cleanedType = "unknown";
29 |
30 | if (token.type) {
31 | cleanedType = token.type.replace(regSelectOpenClose, "");
32 | }
33 |
34 | switch (cleanedType) {
35 | case "heading": {
36 | cleanedType = `${cleanedType}${token.tag.substr(1)}`;
37 | break;
38 | }
39 | }
40 |
41 | return cleanedType;
42 | }
43 |
44 |
45 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/getUniqueID.js:
--------------------------------------------------------------------------------
1 |
2 | let uuid = new Date().getTime();
3 | export default function getUniqueID() {
4 | uuid++;
5 | return `rnmr_${uuid.toString(16)}`;
6 | }
7 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/groupTextTokens.js:
--------------------------------------------------------------------------------
1 | // import getIsTextType from './getIsTextType';
2 | import Token from './Token';
3 | // import getIsInlineTextType from './getIsInlineTextType';
4 |
5 | export default function groupTextTokens(tokens) {
6 | const result = [];
7 |
8 | let hasGroup = false;
9 | tokens.forEach((token, index) => {
10 | if (!token.block && !hasGroup) {
11 | hasGroup = true;
12 | result.push(new Token('textgroup', 1));
13 | result.push(token);
14 | } else if (!token.block && hasGroup) {
15 | result.push(token);
16 | } else if (token.block && hasGroup) {
17 | hasGroup = false;
18 | result.push(new Token('textgroup', -1));
19 | result.push(token);
20 | } else {
21 | result.push(token);
22 | }
23 | });
24 |
25 | return result;
26 | }
27 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/hasParents.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Array} parents
4 | * @param {string} type
5 | * @return {boolean}
6 | */
7 | export default function hasParents(parents, type) {
8 | return parents.findIndex(el => el.type === type) > -1;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/openUrl.js:
--------------------------------------------------------------------------------
1 | import { Linking } from 'react-native';
2 |
3 | export default function openUrl(url) {
4 | if (url) {
5 | Linking.openURL(url);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/splitTextNonTextNodes.js:
--------------------------------------------------------------------------------
1 | export default function splitTextNonTextNodes(children) {
2 | return children.reduce(
3 | (acc, curr) => {
4 | if (curr.type.displayName === "Text") {
5 | acc.textNodes.push(curr);
6 | } else {
7 | acc.nonTextNodes.push(curr);
8 | }
9 |
10 | return acc;
11 | },
12 | { textNodes: [], nonTextNodes: [] }
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/stringToTokens.js:
--------------------------------------------------------------------------------
1 | export function stringToTokens(source, markdownIt) {
2 | let result = [];
3 | try {
4 | result = markdownIt.parse(source, {});
5 | } catch (err) {
6 | console.warn(err);
7 | }
8 |
9 | return result;
10 | }
11 |
--------------------------------------------------------------------------------
/example/react-native-markdown-renderer/lib/util/tokensToAST.js:
--------------------------------------------------------------------------------
1 | import getUniqueID from './getUniqueID';
2 | import getTokenTypeByToken from './getTokenTypeByToken';
3 |
4 | /**
5 | *
6 | * @param {{type: string, tag:string, content: string, children: *, attrs: Array, meta, info, block: boolean}} token
7 | * @param {number} tokenIndex
8 | * @return {{type: string, content, tokenIndex: *, index: number, attributes: {}, children: *}}
9 | */
10 | function createNode(token, tokenIndex) {
11 | const type = getTokenTypeByToken(token);
12 | const content = token.content;
13 |
14 | let attributes = {};
15 |
16 | if (token.attrs) {
17 | attributes = token.attrs.reduce((prev, curr) => {
18 | const [name, value] = curr;
19 | return { ...prev, [name]: value };
20 | }, {});
21 | }
22 |
23 | return {
24 | type,
25 | sourceType: token.type,
26 | sourceInfo: token.info,
27 | sourceMeta: token.meta,
28 | block: token.block,
29 | markup: token.markup,
30 | key: getUniqueID(),
31 | content,
32 | tokenIndex,
33 | index: 0,
34 | attributes,
35 | children: tokensToAST(token.children),
36 | };
37 | }
38 |
39 | /**
40 | *
41 | * @param {Array<{type: string, tag:string, content: string, children: *, attrs: Array}>}tokens
42 | * @return {Array}
43 | */
44 | export default function tokensToAST(tokens) {
45 | let stack = [];
46 | let children = [];
47 |
48 | if (!tokens || tokens.length === 0) {
49 | return [];
50 | }
51 |
52 | for (let i = 0; i < tokens.length; i++) {
53 | const token = tokens[i];
54 | const astNode = createNode(token, i);
55 |
56 | if (!(astNode.type === 'text' && astNode.children.length === 0 && astNode.content === '')) {
57 | astNode.index = children.length;
58 |
59 | if (token.nesting === 1) {
60 | children.push(astNode);
61 | stack.push(children);
62 | children = astNode.children;
63 | } else if (token.nesting === -1) {
64 | children = stack.pop();
65 | } else if (token.nesting === 0) {
66 | children.push(astNode);
67 | }
68 | }
69 | }
70 |
71 | return children;
72 | }
73 |
--------------------------------------------------------------------------------
/example/src/code.js:
--------------------------------------------------------------------------------
1 | const markdownText = `
2 | Inline \`code\`
3 |
4 | Indented code
5 |
6 | // Some comments
7 | line 1 of code
8 | line 2 of code
9 | line 3 of code
10 |
11 |
12 | Block code "fences"
13 |
14 | \`\`\`
15 | Sample text here...
16 | \`\`\`
17 |
18 | Syntax highlighting
19 |
20 | \`\`\` js
21 | var foo = function (bar) {
22 | return bar++;
23 | };
24 |
25 | console.log(foo(5));
26 | \`\`\`
27 | `;
28 |
29 | export default markdownText;
--------------------------------------------------------------------------------
/example/src/copy/all.js:
--------------------------------------------------------------------------------
1 | const copy = `
2 | # Syntax Support
3 | foo
4 |
5 | a \nb
6 |
7 | # code inline
8 |
9 | **Foo Bar**
10 |
11 | Hello \`code inline\` code_inline
12 |
13 | __Advertisement :)__
14 |
15 | This is a text. Click [here](https://google.com) to open a link. Let's add some more text to see how this behaves.
16 |
17 | # h1 Heading 8-)
18 | ## h2 Heading
19 | ### h3 Heading
20 | #### h4 Heading
21 | ##### h5 Heading
22 | ###### h6 Heading
23 |
24 | - __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
25 | resize in browser.
26 | - __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly
27 | i18n with plurals support and easy syntax.
28 |
29 | You will like those projects!
30 |
31 | ---
32 |
33 | # h1 Heading 8-)
34 | ## h2 Heading
35 | ### h3 Heading
36 | #### h4 Heading
37 | ##### h5 Heading
38 | ###### h6 Heading
39 |
40 |
41 | ### Horizontal Rules
42 |
43 | ___
44 |
45 | ---
46 |
47 |
48 | ### Typographic replacements
49 |
50 | Enable typographer option to see result.
51 |
52 | (c) (C) (r) (R) (tm) (TM) (p) (P) +-
53 |
54 | test.. test... test..... test?..... test!....
55 |
56 | !!!!!! ???? ,, -- ---
57 |
58 | "Smartypants, double quotes" and 'single quotes'
59 |
60 |
61 | ## Emphasis
62 |
63 | **This is bold text**
64 |
65 | __This is bold text__
66 |
67 | *This is italic text*
68 |
69 | _This is italic text_
70 |
71 | ~~Strikethrough~~
72 |
73 |
74 | ## Blockquotes
75 |
76 |
77 | > Blockquotes can also be nested...
78 |
79 | >> ...by using additional greater-than signs right next to each other...
80 |
81 | > > > ...or with spaces between arrows.
82 |
83 |
84 | ## Lists
85 |
86 | Unordered
87 |
88 | + Create a list by starting a line with \`+\`, \`-\`, or \`*\`
89 | + Sub-lists are made by indenting 2 spaces:
90 | - Marker character change forces new list start:
91 | * Ac tristique libero volutpat at
92 | + Facilisis in pretium nisl aliquet
93 | - Nulla volutpat aliquam velit
94 | + Very easy!
95 |
96 | Ordered
97 |
98 | 1. Lorem ipsum dolor sit amet
99 | 2. Consectetur adipiscing elit
100 | 3. Integer molestie lorem at massa
101 |
102 |
103 | 1. You can use sequential numbers...
104 | 1. ...or keep all the numbers as \`1.\`
105 |
106 | Start numbering with offset:
107 |
108 | 57. foo
109 | 1. bar
110 |
111 |
112 | ## Code
113 |
114 | Inline \`code\`
115 |
116 | Indented code
117 |
118 | // Some comments
119 | line 1 of code
120 | line 2 of code
121 | line 3 of code
122 |
123 |
124 | Block code "fences"
125 |
126 | \`\`\`
127 | Sample text here...
128 | \`\`\`
129 |
130 | Syntax highlighting
131 |
132 | \`\`\` js
133 | var foo = function (bar) {
134 | return bar++;
135 | };
136 |
137 | console.log(foo(5));
138 | \`\`\`
139 |
140 | ## Tables
141 |
142 | | Option | Description |
143 | | ------ | ----------- |
144 | | data | path to data files to supply the data that will be passed into templates. |
145 | | engine | engine to be used for processing templates. Handlebars is the default. |
146 | | ext | extension to be used for dest files. |
147 |
148 | Right aligned columns
149 |
150 | | Option | Description |
151 | | ------:| -----------:|
152 | | data | path to data files to supply the data that will be passed into templates. |
153 | | engine | engine to be used for processing templates. Handlebars is the default. |
154 | | ext | extension to be used for dest files. |
155 |
156 |
157 | ## Links
158 |
159 | [link text](http://dev.nodeca.com)
160 |
161 | [link with title](http://nodeca.github.io/pica/demo/ "title text!")
162 |
163 | Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
164 |
165 |
166 | ## Images
167 |
168 | 
169 | 
170 |
171 | Like links, Images also have a footnote style syntax
172 |
173 | ![Alt text][id]
174 |
175 | With a reference later in the document defining the URL location:
176 |
177 | [id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
178 | `;
179 |
180 |
181 | export default copy;
--------------------------------------------------------------------------------
/example/src/copy/linkedimg.js:
--------------------------------------------------------------------------------
1 |
2 | const copy = `
3 | 
4 | [](https://google.com)
5 | [](https://google.com)
6 |
7 | ## Links
8 |
9 | @hello
10 |
11 | `;
12 | const copy2 = `
13 | **tes
14 | t**
15 |
16 | ## Linked Images
17 | [](https://google.com)
18 | [](https://google.com)
19 |
20 |
21 | ## Links
22 |
23 | [link text](http://dev.nodeca.com)
24 |
25 | [link with title](http://nodeca.github.io/pica/demo/ "title text!")
26 |
27 | Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
28 |
29 |
30 | ## Images
31 |
32 | 
33 | 
34 |
35 | Like links, Images also have a footnote style syntax
36 |
37 | ![Alt text][id]
38 |
39 | With a reference later in the document defining the URL location:
40 |
41 | [id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
42 | `;
43 | export default copy;
--------------------------------------------------------------------------------
/example/src/copyAll.js:
--------------------------------------------------------------------------------
1 | const markdownText = `
2 | [](https://google.com)
3 | 
4 |
5 | `;
6 | const markdownText2 = `
7 | # Syntax Support
8 |
9 | __Advertisement :)__
10 |
11 | This is a text. Click [here](https://google.com) to open a link. Let's add some more text to see how this behaves.
12 |
13 | - __[pica](https://nodeca.github.io/pica/demo/)__ - high quality and fast image
14 | resize in browser.
15 | - __[babelfish](https://github.com/nodeca/babelfish/)__ - developer friendly
16 | i18n with plurals support and easy syntax.
17 |
18 | You will like those projects!
19 |
20 | ---
21 |
22 | # h1 Heading 8-)
23 | ## h2 Heading
24 | ### h3 Heading
25 | #### h4 Heading
26 | ##### h5 Heading
27 | ###### h6 Heading
28 |
29 |
30 | ### Horizontal Rules
31 |
32 | ___
33 |
34 | ---
35 |
36 |
37 | ### Typographic replacements
38 |
39 | Enable typographer option to see result.
40 |
41 | (c) (C) (r) (R) (tm) (TM) (p) (P) +-
42 |
43 | test.. test... test..... test?..... test!....
44 |
45 | !!!!!! ???? ,, -- ---
46 |
47 | "Smartypants, double quotes" and 'single quotes'
48 |
49 |
50 | ## Emphasis
51 |
52 | **This is bold text**
53 |
54 | __This is bold text__
55 |
56 | *This is italic text*
57 |
58 | _This is italic text_
59 |
60 | ~~Strikethrough~~
61 |
62 |
63 | ## Blockquotes
64 |
65 |
66 | > Blockquotes can also be nested...
67 |
68 | >> ...by using additional greater-than signs right next to each other...
69 |
70 | > > > ...or with spaces between arrows.
71 |
72 |
73 | ## Lists
74 |
75 | Unordered
76 |
77 | + Create a list by starting a line with \`+\`, \`-\`, or \`*\`
78 | + Sub-lists are made by indenting 2 spaces:
79 | - Marker character change forces new list start:
80 | * Ac tristique libero volutpat at
81 | + Facilisis in pretium nisl aliquet
82 | - Nulla volutpat aliquam velit
83 | + Very easy!
84 |
85 | Ordered
86 |
87 | 1. Lorem ipsum dolor sit amet
88 | 2. Consectetur adipiscing elit
89 | 3. Integer molestie lorem at massa
90 |
91 |
92 | 1. You can use sequential numbers...
93 | 1. ...or keep all the numbers as \`1.\`
94 |
95 | Start numbering with offset:
96 |
97 | 57. foo
98 | 1. bar
99 |
100 |
101 | ## Code
102 |
103 | Inline \`code\`
104 |
105 | Indented code
106 |
107 | // Some comments
108 | line 1 of code
109 | line 2 of code
110 | line 3 of code
111 |
112 |
113 | Block code "fences"
114 |
115 | \`\`\`
116 | Sample text here...
117 | \`\`\`
118 |
119 | Syntax highlighting
120 |
121 | \`\`\` js
122 | var foo = function (bar) {
123 | return bar++;
124 | };
125 |
126 | console.log(foo(5));
127 | \`\`\`
128 |
129 | ## Tables
130 |
131 | | Option | Description |
132 | | ------ | ----------- |
133 | | data | path to data files to supply the data that will be passed into templates. |
134 | | engine | engine to be used for processing templates. Handlebars is the default. |
135 | | ext | extension to be used for dest files. |
136 |
137 | Right aligned columns
138 |
139 | | Option | Description |
140 | | ------:| -----------:|
141 | | data | path to data files to supply the data that will be passed into templates. |
142 | | engine | engine to be used for processing templates. Handlebars is the default. |
143 | | ext | extension to be used for dest files. |
144 |
145 |
146 | ## Links
147 |
148 | [link text](http://dev.nodeca.com)
149 |
150 | [link with title](http://nodeca.github.io/pica/demo/ "title text!")
151 |
152 | Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
153 |
154 |
155 | ## Images
156 |
157 | 
158 | 
159 |
160 | Like links, Images also have a footnote style syntax
161 |
162 | ![Alt text][id]
163 |
164 | With a reference later in the document defining the URL location:
165 |
166 | [id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
167 | `;
168 |
169 | export default markdownText;
--------------------------------------------------------------------------------
/example/src/copyAllCheckboxPlugin.js:
--------------------------------------------------------------------------------
1 | const markdownText = `
2 |
3 |
4 | ## Images
5 |
6 | 
7 | 
8 |
9 |
10 | + Selected third parties include:
11 | - Service providers assigned to carrying out your service contract when placing a booking on the company. Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at
12 | - Service providers assigned to carrying out your service contract when placing a booking on the company. Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at
13 | - Service providers assigned to carrying out your service contract when placing a booking on the company. Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at Ac tristique libero volutpat at
14 |
15 | + Sub-lists are made by indenting 2 spaces:
16 | - Marker character change forces new list start:
17 | * Ac tristique libero volutpat at
18 | + Facilisis in pretium nisl aliquet
19 | - Nulla volutpat aliquam velit
20 | + Very easy!
21 |
22 | # Syntax __Support__
23 |
24 | __Advertisement :)__
25 |
26 | * [ ] unchecked
27 | * [x] checked
28 | `;
29 |
30 | export default markdownText;
31 |
--------------------------------------------------------------------------------
/example/src/customMarkdownStyle.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from "react-native";
2 |
3 | /**
4 | *
5 | */
6 | const customMarkdownStyle = StyleSheet.create({
7 | view: {},
8 | codeBlock: {
9 | fontFamily: "Courier",
10 | fontWeight: "500"
11 | },
12 | del: {
13 | backgroundColor: "#000000"
14 | },
15 | em: {
16 | fontStyle: "italic"
17 | },
18 |
19 | text: { fontSize: 20 },
20 | strikethrough: {
21 | textDecorationLine: "line-through",
22 | color: "#FF0000"
23 | },
24 | a: {
25 | textDecorationLine: "underline",
26 | color: "#FF0000"
27 | },
28 | u: {
29 | borderColor: "#000000",
30 | borderBottomWidth: 1
31 | }
32 | });
33 |
34 | export default customMarkdownStyle;
35 |
--------------------------------------------------------------------------------
/example/src/pluginRules.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { StyleSheet, Text, View, ScrollView, Picker } from "react-native";
3 |
4 | const rules = {
5 | checkbox: (node, children, parents, style) => {
6 | return (
7 |
11 | {children}
12 |
13 | );
14 | },
15 | checkbox_input: (node, children, parents, style) => {
16 | return (
17 |
27 | );
28 | },
29 | label: (node, children, parents, style) => {
30 | return {children};
31 | }
32 | };
33 | export default rules;
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-markdown-renderer",
3 | "version": "3.2.8",
4 | "description": "Markdown renderer for react-native, with CommonMark spec support + adds syntax extensions & sugar (URL autolinking, typographer).",
5 | "main": "src/index.js",
6 | "types": "src/index.d.ts",
7 | "scripts": {},
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/mientjan/react-native-markdown-renderer.git"
11 | },
12 | "keywords": [
13 | "react",
14 | "react-native",
15 | "native",
16 | "markdown",
17 | "commonmark",
18 | "markdown-it"
19 | ],
20 | "author": "Mient-jan Stelling",
21 | "license": "MIT",
22 | "bugs": {
23 | "url": "https://github.com/mientjan/react-native-markdown-renderer/issues"
24 | },
25 | "homepage": "https://github.com/mientjan/react-native-markdown-renderer#readme",
26 | "dependencies": {
27 | "@types/markdown-it": "^0.0.4",
28 | "@types/react-native": ">=0.50.0",
29 | "markdown-it": "^8.4.0",
30 | "prop-types": "^15.5.10",
31 | "react-native-fit-image": "^1.5.2"
32 | },
33 | "peerDependencies": {
34 | "react": "^16.2.0",
35 | "react-native": "^0.50.4"
36 | },
37 | "devDependencies": {
38 | "chokidar": "^2.0.0",
39 | "fs-extra": "^5.0.0"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | // tslint:disable:max-classes-per-file
2 | import { MarkdownIt, Token } from 'markdown-it';
3 | import { ComponentType, ReactNode } from 'react';
4 | import { StyleSheet, View } from 'react-native';
5 |
6 | export function applyStyle(children: any[], styles: any, type: string): any;
7 |
8 | export function getUniqueID(): string;
9 | export function openUrl(url: string): void;
10 |
11 | export function hasParents(parents: any[], type: string): boolean;
12 |
13 | export type RenderFunction = (
14 | node: any,
15 | children: ReactNode[],
16 | parent: ReactNode,
17 | styles: any,
18 | ) => ReactNode;
19 |
20 | export interface RenderRules {
21 | [name: string]: RenderFunction;
22 | }
23 |
24 | export const renderRules: RenderRules;
25 |
26 | export interface MarkdownParser {
27 | parse: (value: string, options: any) => Token[];
28 | }
29 |
30 | export interface ASTNode {
31 | type: string;
32 | sourceType: string; // original source token name
33 | key: string;
34 | content: string;
35 | tokenIndex: number;
36 | index: number;
37 | attributes: Record;
38 | children: ASTNode[];
39 | }
40 |
41 | export class AstRenderer {
42 | constructor(renderRules: RenderRules, style?: any);
43 | getRenderFunction(type: string): RenderFunction;
44 | renderNode(node: any, parentNodes: ReadonlyArray): ReactNode;
45 | render(nodes: ReadonlyArray): View;
46 | }
47 |
48 | export function parser(
49 | source: string,
50 | renderer: (node: ASTNode) => View,
51 | parser: MarkdownParser,
52 | ): any;
53 |
54 | export function stringToTokens(
55 | source: string,
56 | markdownIt: MarkdownParser,
57 | ): Token[];
58 |
59 | export function tokensToAST(tokens: ReadonlyArray): ASTNode[];
60 |
61 | interface PluginContainerResult extends Array {
62 | 0: A;
63 | }
64 |
65 | export class PluginContainer {
66 | constructor(plugin: A, ...options: any[]);
67 | toArray(): PluginContainerResult;
68 | }
69 |
70 | export function blockPlugin(md: any, name: string, options: object): any;
71 |
72 | export const styles: any;
73 |
74 | export interface MarkdownProps {
75 | rules?: RenderRules;
76 | style?: StyleSheet.NamedStyles;
77 | renderer?: AstRenderer;
78 | markdownit?: MarkdownIt;
79 | plugins?: Array>;
80 | }
81 |
82 | type MarkdownStatic = React.ComponentType;
83 | export const Markdown: MarkdownStatic;
84 | export type Markdown = MarkdownStatic;
85 |
86 | export default Markdown;
87 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Base Markdown component
3 | * @author Mient-jan Stelling
4 | */
5 | import React, { Component } from 'react';
6 | import PropTypes from 'prop-types';
7 | import { View } from 'react-native';
8 | import parser from './lib/parser';
9 | import applyStyle from './lib/util/applyStyle';
10 | import getUniqueID from './lib/util/getUniqueID';
11 | import hasParents from './lib/util/hasParents';
12 | import openUrl from './lib/util/openUrl';
13 | import tokensToAST from './lib/util/tokensToAST';
14 | import renderRules from './lib/renderRules';
15 | import AstRenderer from './lib/AstRenderer';
16 | import MarkdownIt from 'markdown-it';
17 | import PluginContainer from './lib/plugin/PluginContainer';
18 | import blockPlugin from './lib/plugin/blockPlugin';
19 | import { styles } from './lib/styles';
20 | import { stringToTokens } from './lib/util/stringToTokens';
21 | /**
22 | *
23 | */
24 | export {
25 | applyStyle,
26 | getUniqueID,
27 | openUrl,
28 | hasParents,
29 | renderRules,
30 | AstRenderer,
31 | parser,
32 | stringToTokens,
33 | tokensToAST,
34 | MarkdownIt,
35 | PluginContainer,
36 | blockPlugin,
37 | styles,
38 | };
39 |
40 | /**
41 | * react-native-markdown-renderer
42 | */
43 | export default class Markdown extends Component {
44 | /**
45 | * Definition of the prop types
46 | */
47 | static propTypes = {
48 | children: PropTypes.node.isRequired,
49 | renderer: PropTypes.oneOfType([PropTypes.func, PropTypes.instanceOf(AstRenderer)]),
50 | rules: (props, propName, componentName) => {
51 | let invalidProps = [];
52 | const prop = props[propName];
53 |
54 | if (!prop) {
55 | return;
56 | }
57 |
58 | if (typeof prop === 'object') {
59 | invalidProps = Object.keys(prop).filter(key => typeof prop[key] !== 'function');
60 | }
61 |
62 | if (typeof prop !== 'object') {
63 | return new Error(
64 | `Invalid prop \`${propName}\` supplied to \`${componentName}\`. Must be of shape {[index:string]:function} `
65 | );
66 | } else if (invalidProps.length > 0) {
67 | return new Error(
68 | `Invalid prop \`${propName}\` supplied to \`${componentName}\`. These ` +
69 | `props are not of type function \`${invalidProps.join(', ')}\` `
70 | );
71 | }
72 | },
73 | markdownit: PropTypes.instanceOf(MarkdownIt),
74 | plugins: PropTypes.arrayOf(PropTypes.instanceOf(PluginContainer)),
75 | style: PropTypes.any,
76 | };
77 |
78 | /**
79 | * Default Props
80 | */
81 | static defaultProps = {
82 | renderer: null,
83 | rules: null,
84 | plugins: [],
85 | style: null,
86 | markdownit: MarkdownIt({
87 | typographer: true,
88 | }),
89 | };
90 |
91 | copy = '';
92 | renderer = null;
93 | markdownParser = null;
94 |
95 | /**
96 | * Only when the copy changes will the markdown render again.
97 | * @param nextProps
98 | * @param nextState
99 | * @return {boolean}
100 | */
101 | shouldComponentUpdate(nextProps, nextState) {
102 | const copy = this.getCopyFromChildren(nextProps.children);
103 |
104 | if (copy !== this.copy) {
105 | this.copy = copy;
106 | return true;
107 | }
108 |
109 | if (
110 | nextProps.renderer !== this.props.renderer ||
111 | nextProps.style !== this.props.style ||
112 | nextProps.plugins !== this.props.plugins ||
113 | nextProps.rules !== this.props.rules ||
114 | nextProps.markdownit !== this.props.markdownit
115 | ) {
116 | return true;
117 | }
118 |
119 | return false;
120 | }
121 |
122 | /**
123 | *
124 | * @param props
125 | */
126 | updateSettings(props = this.props) {
127 | const { renderer, rules, style, plugins, markdownit } = props;
128 |
129 | if (renderer && rules) {
130 | console.warn(
131 | 'react-native-markdown-renderer you are using renderer and rules at the same time. This is not possible, props.rules is ignored'
132 | );
133 | }
134 |
135 | if (renderer && style) {
136 | console.warn(
137 | 'react-native-markdown-renderer you are using renderer and style at the same time. This is not possible, props.style is ignored'
138 | );
139 | }
140 |
141 | // these checks are here to prevent extra overhead.
142 | if (renderer) {
143 | if (typeof renderer === 'function') {
144 | if (!this.renderer || this.renderer.render !== renderer) {
145 | this.renderer = {
146 | render: renderer,
147 | };
148 | }
149 | } else if (renderer instanceof AstRenderer) {
150 | if (this.renderer !== renderer) {
151 | this.renderer = renderer;
152 | }
153 | } else {
154 | throw new Error('Provided renderer is not compatible with function or AstRenderer. please change');
155 | }
156 | } else {
157 | if (!this.renderer || this.props.renderer || this.props.rules !== rules || this.props.style !== style) {
158 | this.renderer = new AstRenderer(
159 | {
160 | ...renderRules,
161 | ...(rules || {}),
162 | },
163 | {
164 | ...styles,
165 | ...style,
166 | }
167 | );
168 | }
169 | }
170 |
171 | if (!this.markdownParser || this.props.markdownit !== markdownit || plugins !== this.props.plugins) {
172 | let md = markdownit;
173 | if (plugins && plugins.length > 0) {
174 | plugins.forEach(plugin => {
175 | md = md.use.apply(md, plugin.toArray());
176 | });
177 | }
178 |
179 | this.markdownParser = md;
180 | }
181 | }
182 |
183 | /**
184 | *
185 | */
186 | componentWillMount() {
187 | this.updateSettings(this.props);
188 | }
189 |
190 | /**
191 | *
192 | * @param nextProps
193 | */
194 | componentWillReceiveProps(nextProps) {
195 | this.updateSettings(nextProps);
196 | }
197 |
198 | /**
199 | *
200 | * @param children
201 | * @return {string}
202 | */
203 | getCopyFromChildren(children = this.props.children) {
204 | return children instanceof Array ? children.join('') : children;
205 | }
206 |
207 | /**
208 | *
209 | * @return {View}
210 | */
211 | render() {
212 | const copy = (this.copy = this.getCopyFromChildren());
213 | return parser(copy, this.renderer.render, this.markdownParser);
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/src/lib/AstRenderer.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from "react";
2 | import { Text, View } from "react-native";
3 | import getUniqueID from "./util/getUniqueID";
4 |
5 | export function rootRenderRule(children, styles) {
6 | return {children};
7 | }
8 |
9 | /**
10 | *
11 | */
12 | export default class AstRenderer {
13 | /**
14 | *
15 | * @param {Object.} renderRules
16 | * @param {any} style
17 | */
18 | constructor(renderRules, style) {
19 | this._renderRules = renderRules;
20 | this._style = style;
21 | }
22 |
23 | /**
24 | *
25 | * @param {string} type
26 | * @return {string}
27 | */
28 | getRenderFunction = type => {
29 | const renderFunction = this._renderRules[type];
30 |
31 | if (!renderFunction) {
32 | throw new Error(
33 | `${type} renderRule not defined example: `
34 | );
35 | }
36 | return renderFunction;
37 | };
38 |
39 | /**
40 | *
41 | * @param node
42 | * @param parentNodes
43 | * @return {*}
44 | */
45 | renderNode = (node, parentNodes) => {
46 | const renderFunction = this.getRenderFunction(node.type);
47 |
48 | const parents = [...parentNodes];
49 | parents.unshift(node);
50 |
51 | if (node.type === "text") {
52 | return renderFunction(node, [], parentNodes, this._style);
53 | }
54 |
55 | const children = node.children.map(value => {
56 | return this.renderNode(value, parents);
57 | });
58 |
59 | return renderFunction(node, children, parentNodes, this._style);
60 | };
61 |
62 | /**
63 | *
64 | * @param nodes
65 | * @return {*}
66 | */
67 | render = nodes => {
68 | const children = nodes.map(value => this.renderNode(value, []));
69 | return rootRenderRule(children, this._style);
70 | };
71 | }
72 |
--------------------------------------------------------------------------------
/src/lib/data/PlatformEnum.js:
--------------------------------------------------------------------------------
1 | export default {
2 | IOS: "ios",
3 | ANDROID: "android"
4 | };
5 |
--------------------------------------------------------------------------------
/src/lib/parser.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { View } from 'react-native';
3 | import tokensToAST from './util/tokensToAST';
4 | import { stringToTokens } from './util/stringToTokens';
5 | import { cleanupTokens } from './util/cleanupTokens';
6 | import groupTextTokens from './util/groupTextTokens';
7 |
8 | /**
9 | *
10 | * @param {string} source
11 | * @param {function} [renderer]
12 | * @param {AstRenderer} [markdownIt]
13 | * @return {View}
14 | */
15 | export default function parser(source, renderer, markdownIt) {
16 | let tokens = stringToTokens(source, markdownIt);
17 | tokens = cleanupTokens(tokens);
18 | tokens = groupTextTokens(tokens);
19 |
20 | const astTree = tokensToAST(tokens);
21 |
22 | return renderer(astTree);
23 | }
24 |
--------------------------------------------------------------------------------
/src/lib/plugin/PluginContainer.js:
--------------------------------------------------------------------------------
1 | export default class PluginContainer {
2 | constructor(plugin, ...options) {
3 | this.plugin = plugin;
4 | this.options = options;
5 | }
6 |
7 | toArray() {
8 | return [this.plugin, ...this.options];
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/plugin/blockPlugin.js:
--------------------------------------------------------------------------------
1 | /* code is still in beta, thats why im disabling linter */
2 | /* eslint-disable */
3 |
4 | /**
5 | * How to use?
6 | * new PluginContainer(blockPlugin, '__name_of_block__', {})
7 | * @param md
8 | * @param name
9 | * @param options
10 | */
11 | export default function blockPlugin(md, name, options) {
12 | function validateDefault(params) {
13 | return params.trim().split(' ', 2)[0] === name;
14 | }
15 |
16 | function renderDefault(tokens, idx, _options, env, self) {
17 | return self.renderToken(tokens, idx, _options, env, self);
18 | }
19 |
20 | options = options || {};
21 |
22 | let min_markers = 1;
23 | let marker_str = options.marker || `[${name}]`;
24 | let marker_end_str = options.marker_end || `[/${name}]`;
25 | let marker_char = marker_str.charCodeAt(0);
26 | let marker_len = marker_str.length;
27 | let marker_end_len = marker_end_str.length;
28 |
29 | let validate = options.validate || validateDefault;
30 | let render = options.render || renderDefault;
31 |
32 | function container(state, startLine, endLine, silent) {
33 | var pos,
34 | nextLine,
35 | marker_count,
36 | markup,
37 | params,
38 | token,
39 | old_parent,
40 | old_line_max,
41 | auto_closed = false,
42 | start = state.bMarks[startLine] + state.tShift[startLine],
43 | max = state.eMarks[startLine];
44 |
45 | // Check out the first character quickly,
46 | // this should filter out most of non-containers
47 | //
48 | if (marker_char !== state.src.charCodeAt(start)) {
49 | return false;
50 | }
51 |
52 | // Check out the rest of the marker string
53 | //
54 | for (pos = start + 1; pos <= max; pos++) {
55 | if (marker_str[(pos - start) % marker_len] !== state.src[pos]) {
56 | break;
57 | }
58 | }
59 |
60 | marker_count = Math.floor((pos - start) / marker_len);
61 | if (marker_count < min_markers) {
62 | return false;
63 | }
64 | pos -= (pos - start) % marker_len;
65 |
66 | markup = state.src.slice(start, pos);
67 | params = state.src.slice(pos, max);
68 |
69 | // if (!validate(params)) {
70 | // return false;
71 | // }
72 |
73 | // Since start is found, we can report success here in validation mode
74 | //
75 | if (silent) {
76 | return true;
77 | }
78 |
79 | // Search for the end of the block
80 | //
81 | nextLine = startLine;
82 |
83 | for (;;) {
84 | nextLine++;
85 | if (nextLine >= endLine) {
86 | // unclosed block should be autoclosed by end of document.
87 | // also block seems to be autoclosed by end of parent
88 | break;
89 | }
90 |
91 | start = state.bMarks[nextLine] + state.tShift[nextLine];
92 | max = state.eMarks[nextLine];
93 |
94 | if (start < max && state.sCount[nextLine] < state.blkIndent) {
95 | // non-empty line with negative indent should stop the list:
96 | // - ```
97 | // test
98 | break;
99 | }
100 |
101 | if (marker_char !== state.src.charCodeAt(start)) {
102 | continue;
103 | }
104 |
105 | if (state.sCount[nextLine] - state.blkIndent >= 4) {
106 | // closing fence should be indented less than 4 spaces
107 | continue;
108 | }
109 |
110 | for (pos = start + 1; pos <= max; pos++) {
111 | if (marker_end_str[(pos - start) % marker_end_len] !== state.src[pos]) {
112 | break;
113 | }
114 | }
115 |
116 | // closing code fence must be at least as long as the opening one
117 | if (Math.floor((pos - start) / marker_end_len) < marker_count) {
118 | continue;
119 | }
120 |
121 | // make sure tail has spaces only
122 | pos -= (pos - start) % marker_end_len;
123 | pos = state.skipSpaces(pos);
124 |
125 | if (pos < max) {
126 | continue;
127 | }
128 |
129 | // found!
130 | auto_closed = true;
131 | break;
132 | }
133 |
134 | old_parent = state.parentType;
135 | old_line_max = state.lineMax;
136 | state.parentType = 'container';
137 |
138 | // this will prevent lazy continuations from ever going past our end marker
139 | state.lineMax = nextLine;
140 |
141 | token = state.push(`container_${name}_open`, name, 1);
142 | token.markup = markup;
143 | token.block = true;
144 | token.info = params;
145 | token.map = [startLine, nextLine];
146 |
147 | state.md.block.tokenize(state, startLine + 1, nextLine);
148 |
149 | token = state.push(`container_${name}_close`, name, -1);
150 | token.markup = state.src.slice(start, pos);
151 | token.block = true;
152 |
153 | state.parentType = old_parent;
154 | state.lineMax = old_line_max;
155 | state.line = nextLine + (auto_closed ? 1 : 0);
156 |
157 | return true;
158 | }
159 |
160 | md.block.ruler.before('fence', 'container_checklist', container, {
161 | alt: ['paragraph', 'reference', 'blockquote', 'list'],
162 | });
163 |
164 | md.renderer.rules['container_' + name + '_open'] = render;
165 | md.renderer.rules['container_' + name + '_close'] = render;
166 | }
167 |
--------------------------------------------------------------------------------
/src/lib/renderRules.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import { Text, TouchableWithoutFeedback, View } from 'react-native';
3 |
4 | import FitImage from 'react-native-fit-image';
5 | import openUrl from './util/openUrl';
6 | import hasParents from './util/hasParents';
7 | import applyStyle from './util/applyStyle';
8 |
9 | const renderRules = {
10 | // when unknown elements are introduced, so it wont break
11 | unknown: (node, children, parent, styles) => {
12 | return (
13 |
14 | {node.type}
15 |
16 | );
17 | },
18 |
19 | textgroup: (node, children, parent, styles) => {
20 | return (
21 |
22 | {children}
23 |
24 | );
25 | },
26 |
27 | inline: (node, children, parent, styles) => {
28 | return {children};
29 | },
30 |
31 | text: (node, children, parent, styles) => {
32 | return {node.content};
33 | },
34 | span: (node, children, parent, styles) => {
35 | return {children};
36 | },
37 |
38 | strong: (node, children, parent, styles) => {
39 | return (
40 |
41 | {children}
42 |
43 | );
44 | },
45 |
46 | s: (node, children, parent, styles) => {
47 | return (
48 |
49 | {children}
50 |
51 | );
52 | },
53 | // a
54 | link: (node, children, parent, styles) => {
55 | return (
56 | openUrl(node.attributes.href)}>
57 | {children}
58 |
59 | );
60 | },
61 | // a with a non text element nested inside
62 | blocklink: (node, children, parent, styles) => {
63 | return (
64 | openUrl(node.attributes.href)} style={styles.blocklink}>
65 | {children}
66 |
67 | );
68 | },
69 | em: (node, children, parent, styles) => {
70 | return (
71 |
72 | {children}
73 |
74 | );
75 | },
76 |
77 | heading1: (node, children, parent, styles) => {
78 | return (
79 |
80 | {applyStyle(children, [styles.heading, styles.heading1], 'Text')}
81 |
82 | );
83 | },
84 |
85 | heading2: (node, children, parent, styles) => {
86 | children = applyStyle(children, [styles.heading, styles.heading2], 'Text');
87 | return (
88 |
89 | {children}
90 |
91 | );
92 | },
93 | heading3: (node, children, parent, styles) => (
94 |
95 | {applyStyle(children, [styles.heading, styles.heading3], 'Text')}
96 |
97 | ),
98 | heading4: (node, children, parent, styles) => (
99 |
100 | {applyStyle(children, [styles.heading, styles.heading4], 'Text')}
101 |
102 | ),
103 | heading5: (node, children, parent, styles) => (
104 |
105 | {applyStyle(children, [styles.heading, styles.heading5], 'Text')}
106 |
107 | ),
108 | heading6: (node, children, parent, styles) => (
109 |
110 | {applyStyle(children, [styles.heading, styles.heading6], 'Text')}
111 |
112 | ),
113 |
114 | paragraph: (node, children, parent, styles) => (
115 |
116 | {children}
117 |
118 | ),
119 |
120 | hardbreak: (node, children, parent, styles) => ,
121 |
122 | blockquote: (node, children, parent, styles) => (
123 |
124 | {children}
125 |
126 | ),
127 | code_inline: (node, children, parent, styles) => {
128 | return (
129 |
130 | {node.content}
131 |
132 | );
133 | },
134 | code_block: (node, children, parent, styles) => {
135 | return (
136 |
137 | {node.content}
138 |
139 | );
140 | },
141 | fence: (node, children, parent, styles) => {
142 | return (
143 |
144 | {node.content}
145 |
146 | );
147 | },
148 | pre: (node, children, parent, styles) => (
149 |
150 | {children}
151 |
152 | ),
153 | // ul
154 | bullet_list: (node, children, parent, styles) => {
155 | return (
156 |
157 | {children}
158 |
159 | );
160 | },
161 | ordered_list: (node, children, parent, styles) => {
162 | return (
163 |
164 | {children}
165 |
166 | );
167 | },
168 | // li
169 | list_item: (node, children, parent, styles) => {
170 | if (hasParents(parent, 'bullet_list')) {
171 | return (
172 |
173 | {'\u00B7'}
174 | {children}
175 |
176 | );
177 | }
178 |
179 | if (hasParents(parent, 'ordered_list')) {
180 | return (
181 |
182 | {node.index + 1}{node.markup}
183 | {children}
184 |
185 | );
186 | }
187 |
188 | return (
189 |
190 | {children}
191 |
192 | );
193 | },
194 | table: (node, children, parent, styles) => (
195 |
196 | {children}
197 |
198 | ),
199 | thead: (node, children, parent, styles) => (
200 |
201 | {children}
202 |
203 | ),
204 | tbody: (node, children, parent, styles) => {children},
205 | th: (node, children, parent, styles) => {
206 | return (
207 |
208 | {children}
209 |
210 | );
211 | },
212 | tr: (node, children, parent, styles) => {
213 | return (
214 |
215 | {children}
216 |
217 | );
218 | },
219 | td: (node, children, parent, styles) => {
220 | return (
221 |
222 | {children}
223 |
224 | );
225 | },
226 | hr: (node, children, parent, styles) => {
227 | return ;
228 | },
229 |
230 | // br
231 | softbreak: (node, children, parent, styles) => {'\n'},
232 | image: (node, children, parent, styles) => {
233 | return ;
234 | },
235 | };
236 |
237 | export default renderRules;
238 |
--------------------------------------------------------------------------------
/src/lib/styles.js:
--------------------------------------------------------------------------------
1 | import { Platform, StyleSheet } from 'react-native';
2 | import PlatformEnum from './data/PlatformEnum';
3 |
4 | /**
5 | *
6 | */
7 | export const styles = StyleSheet.create({
8 | root: {},
9 | view: {},
10 | codeBlock: {
11 | borderWidth: 1,
12 | borderColor: '#CCCCCC',
13 | backgroundColor: '#f5f5f5',
14 | padding: 10,
15 | borderRadius: 4,
16 | },
17 | codeInline: {
18 | borderWidth: 1,
19 | borderColor: '#CCCCCC',
20 | backgroundColor: '#f5f5f5',
21 | padding: 10,
22 | borderRadius: 4,
23 | },
24 | del: {
25 | backgroundColor: '#000000',
26 | },
27 | em: {
28 | fontStyle: 'italic',
29 | },
30 | headingContainer: {
31 | flexDirection: 'row',
32 | },
33 | heading: {},
34 | heading1: {
35 | fontSize: 32,
36 | },
37 | heading2: {
38 | fontSize: 24,
39 | },
40 | heading3: {
41 | fontSize: 18,
42 | },
43 | heading4: {
44 | fontSize: 16,
45 | },
46 | heading5: {
47 | fontSize: 13,
48 | },
49 | heading6: {
50 | fontSize: 11,
51 | },
52 | hr: {
53 | backgroundColor: '#000000',
54 | height: 1,
55 | },
56 | blockquote: {
57 | paddingHorizontal: 20,
58 | paddingVertical: 10,
59 | margin: 20,
60 | backgroundColor: '#CCCCCC',
61 | },
62 | inlineCode: {
63 | borderRadius: 3,
64 | borderWidth: 1,
65 | fontFamily: 'Courier',
66 | fontWeight: 'bold',
67 | },
68 | list: {},
69 | listItem: {
70 | flex: 1,
71 | flexWrap: 'wrap',
72 | // backgroundColor: 'green',
73 | },
74 | listUnordered: {},
75 |
76 | listUnorderedItem: {
77 | flexDirection: 'row',
78 | justifyContent: 'flex-start',
79 | },
80 |
81 | listUnorderedItemIcon: {
82 | marginLeft: 10,
83 | marginRight: 10,
84 | ...Platform.select({
85 | [PlatformEnum.IOS]: {
86 | lineHeight: 36,
87 | },
88 | [PlatformEnum.ANDROID]: {
89 | lineHeight: 30,
90 | },
91 | }),
92 | },
93 | listUnorderedItemText: {
94 | fontSize: 20,
95 | lineHeight: 20,
96 | },
97 |
98 | listOrdered: {},
99 | listOrderedItem: {
100 | flexDirection: 'row',
101 | },
102 | listOrderedItemIcon: {
103 | marginLeft: 10,
104 | marginRight: 10,
105 | ...Platform.select({
106 | [PlatformEnum.IOS]: {
107 | lineHeight: 36,
108 | },
109 | [PlatformEnum.ANDROID]: {
110 | lineHeight: 30,
111 | },
112 | }),
113 | },
114 | listOrderedItemText: {
115 | fontWeight: 'bold',
116 | lineHeight: 20,
117 | },
118 | paragraph: {
119 | marginTop: 10,
120 | marginBottom: 10,
121 | flexWrap: 'wrap',
122 | flexDirection: 'row',
123 | alignItems: 'flex-start',
124 | justifyContent: 'flex-start',
125 | },
126 | hardbreak: {
127 | width: '100%',
128 | height: 1,
129 | },
130 | strong: {
131 | fontWeight: 'bold',
132 | },
133 | table: {
134 | borderWidth: 1,
135 | borderColor: '#000000',
136 | borderRadius: 3,
137 | },
138 | tableHeader: {},
139 | tableHeaderCell: {
140 | flex: 1,
141 | // color: '#000000',
142 | padding: 5,
143 | // backgroundColor: 'green',
144 | },
145 | tableRow: {
146 | borderBottomWidth: 1,
147 | borderColor: '#000000',
148 | flexDirection: 'row',
149 | },
150 | tableRowCell: {
151 | flex: 1,
152 | padding: 5,
153 | },
154 | text: {},
155 | strikethrough: {
156 | textDecorationLine: 'line-through',
157 | },
158 | link: {
159 | textDecorationLine: 'underline',
160 | },
161 | blocklink: {
162 | flex: 1,
163 | borderColor: '#000000',
164 | borderBottomWidth: 1,
165 |
166 | },
167 | u: {
168 | borderColor: '#000000',
169 | borderBottomWidth: 1,
170 | },
171 | image: {
172 | flex: 1,
173 | },
174 | });
175 |
--------------------------------------------------------------------------------
/src/lib/util/Token.js:
--------------------------------------------------------------------------------
1 | export default class Token {
2 | constructor(type, nesting = 0, children = null, block = false) {
3 | this.type = type;
4 | this.nesting = nesting;
5 | this.children = children;
6 | this.block = block;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/lib/util/applyStyle.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Text } from 'react-native';
3 |
4 | /**
5 | *
6 | * @param Array children
7 | * @param Array styles
8 | * @param {string} type
9 | */
10 | export default function applyStyle(children, styles, type) {
11 | if (!(styles instanceof Array)) {
12 | styles = [styles];
13 | }
14 |
15 | return children.map(child => {
16 | if (child.type.displayName === type) {
17 | return ;
18 | }
19 |
20 | return child;
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/util/cleanupTokens.js:
--------------------------------------------------------------------------------
1 | import getTokenTypeByToken from './getTokenTypeByToken';
2 | import flattenInlineTokens from './flattenInlineTokens';
3 |
4 | export function cleanupTokens(tokens) {
5 | tokens = flattenInlineTokens(tokens);
6 | tokens.forEach(token => {
7 | token.type = getTokenTypeByToken(token);
8 |
9 | // set image and hardbreak to block elements
10 | if (token.type === 'image' || token.type === 'hardbreak') {
11 | token.block = true;
12 | }
13 | });
14 |
15 | /**
16 | * changing a link token to a blocklink to fix issue where link tokens with
17 | * nested non text tokens breaks component
18 | */
19 | const stack = [];
20 | tokens = tokens.reduce((acc, token, index) => {
21 | if (token.type === 'link' && token.nesting === 1) {
22 | stack.push(token);
23 | } else if (stack.length > 0 && token.type === 'link' && token.nesting === -1) {
24 | if (stack.some(stackToken => stackToken.block)) {
25 | stack[0].type = 'blocklink';
26 | stack[0].block = true;
27 | token.type = 'blocklink';
28 | token.block = true;
29 | }
30 |
31 | stack.push(token);
32 |
33 | while (stack.length) {
34 | acc.push(stack.shift());
35 | }
36 | } else if (stack.length > 0) {
37 | stack.push(token);
38 | } else {
39 | acc.push(token);
40 | }
41 |
42 | return acc;
43 | }, []);
44 |
45 | return tokens;
46 | }
47 |
--------------------------------------------------------------------------------
/src/lib/util/flattenInlineTokens.js:
--------------------------------------------------------------------------------
1 | export default function flattenTokens(tokens) {
2 | return tokens.reduce((acc, curr) => {
3 | if (curr.type === 'inline' && curr.children && curr.children.length > 0) {
4 | const children = flattenTokens(curr.children);
5 | while (children.length) {
6 | acc.push(children.shift());
7 | }
8 | } else {
9 | acc.push(curr);
10 | }
11 |
12 | return acc;
13 | }, []);
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/util/getTokenTypeByToken.js:
--------------------------------------------------------------------------------
1 | const regSelectOpenClose = /_open|_close/g;
2 | const regSelectHofH1 = /\w/g;
3 |
4 | /**
5 | *
6 | * @example {
7 | "type": "heading_open",
8 | "tag": "h1",
9 | "attrs": null,
10 | "map": [
11 | 1,
12 | 2
13 | ],
14 | "nesting": 1,
15 | "level": 0,
16 | "children": null,
17 | "content": "",
18 | "markup": "#",
19 | "info": "",
20 | "meta": null,
21 | "block": true,
22 | "hidden": false
23 | }
24 | * @param token
25 | * @return {String}
26 | */
27 | export default function getTokenTypeByToken(token) {
28 | let cleanedType = "unknown";
29 |
30 | if (token.type) {
31 | cleanedType = token.type.replace(regSelectOpenClose, "");
32 | }
33 |
34 | switch (cleanedType) {
35 | case "heading": {
36 | cleanedType = `${cleanedType}${token.tag.substr(1)}`;
37 | break;
38 | }
39 | }
40 |
41 | return cleanedType;
42 | }
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/lib/util/getUniqueID.js:
--------------------------------------------------------------------------------
1 |
2 | let uuid = new Date().getTime();
3 | export default function getUniqueID() {
4 | uuid++;
5 | return `rnmr_${uuid.toString(16)}`;
6 | }
7 |
--------------------------------------------------------------------------------
/src/lib/util/groupTextTokens.js:
--------------------------------------------------------------------------------
1 | // import getIsTextType from './getIsTextType';
2 | import Token from './Token';
3 | // import getIsInlineTextType from './getIsInlineTextType';
4 |
5 | export default function groupTextTokens(tokens) {
6 | const result = [];
7 |
8 | let hasGroup = false;
9 | tokens.forEach((token, index) => {
10 | if (!token.block && !hasGroup) {
11 | hasGroup = true;
12 | result.push(new Token('textgroup', 1));
13 | result.push(token);
14 | } else if (!token.block && hasGroup) {
15 | result.push(token);
16 | } else if (token.block && hasGroup) {
17 | hasGroup = false;
18 | result.push(new Token('textgroup', -1));
19 | result.push(token);
20 | } else {
21 | result.push(token);
22 | }
23 | });
24 |
25 | return result;
26 | }
27 |
--------------------------------------------------------------------------------
/src/lib/util/hasParents.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param {Array} parents
4 | * @param {string} type
5 | * @return {boolean}
6 | */
7 | export default function hasParents(parents, type) {
8 | return parents.findIndex(el => el.type === type) > -1;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/util/openUrl.js:
--------------------------------------------------------------------------------
1 | import { Linking } from 'react-native';
2 |
3 | export default function openUrl(url) {
4 | if (url) {
5 | Linking.openURL(url);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/lib/util/splitTextNonTextNodes.js:
--------------------------------------------------------------------------------
1 | export default function splitTextNonTextNodes(children) {
2 | return children.reduce(
3 | (acc, curr) => {
4 | if (curr.type.displayName === "Text") {
5 | acc.textNodes.push(curr);
6 | } else {
7 | acc.nonTextNodes.push(curr);
8 | }
9 |
10 | return acc;
11 | },
12 | { textNodes: [], nonTextNodes: [] }
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/util/stringToTokens.js:
--------------------------------------------------------------------------------
1 | export function stringToTokens(source, markdownIt) {
2 | let result = [];
3 | try {
4 | result = markdownIt.parse(source, {});
5 | } catch (err) {
6 | console.warn(err);
7 | }
8 |
9 | return result;
10 | }
11 |
--------------------------------------------------------------------------------
/src/lib/util/tokensToAST.js:
--------------------------------------------------------------------------------
1 | import getUniqueID from './getUniqueID';
2 | import getTokenTypeByToken from './getTokenTypeByToken';
3 |
4 | /**
5 | *
6 | * @param {{type: string, tag:string, content: string, children: *, attrs: Array, meta, info, block: boolean}} token
7 | * @param {number} tokenIndex
8 | * @return {{type: string, content, tokenIndex: *, index: number, attributes: {}, children: *}}
9 | */
10 | function createNode(token, tokenIndex) {
11 | const type = getTokenTypeByToken(token);
12 | const content = token.content;
13 |
14 | let attributes = {};
15 |
16 | if (token.attrs) {
17 | attributes = token.attrs.reduce((prev, curr) => {
18 | const [name, value] = curr;
19 | return { ...prev, [name]: value };
20 | }, {});
21 | }
22 |
23 | return {
24 | type,
25 | sourceType: token.type,
26 | sourceInfo: token.info,
27 | sourceMeta: token.meta,
28 | block: token.block,
29 | markup: token.markup,
30 | key: getUniqueID(),
31 | content,
32 | tokenIndex,
33 | index: 0,
34 | attributes,
35 | children: tokensToAST(token.children),
36 | };
37 | }
38 |
39 | /**
40 | *
41 | * @param {Array<{type: string, tag:string, content: string, children: *, attrs: Array}>}tokens
42 | * @return {Array}
43 | */
44 | export default function tokensToAST(tokens) {
45 | let stack = [];
46 | let children = [];
47 |
48 | if (!tokens || tokens.length === 0) {
49 | return [];
50 | }
51 |
52 | for (let i = 0; i < tokens.length; i++) {
53 | const token = tokens[i];
54 | const astNode = createNode(token, i);
55 |
56 | if (!(astNode.type === 'text' && astNode.children.length === 0 && astNode.content === '')) {
57 | astNode.index = children.length;
58 |
59 | if (token.nesting === 1) {
60 | children.push(astNode);
61 | stack.push(children);
62 | children = astNode.children;
63 | } else if (token.nesting === -1) {
64 | children = stack.pop();
65 | } else if (token.nesting === 0) {
66 | children.push(astNode);
67 | }
68 | }
69 | }
70 |
71 | return children;
72 | }
73 |
--------------------------------------------------------------------------------