@cosmicmedia/react-native-markdown-display

中文文档
1.1.7发布于 2023/08/09MITTypeScriptCommonJS近 30 天下载 6336

Markdown renderer for react-native, with CommonMark spec support + adds syntax extensions & sugar (URL autolinking, typographer), originally created by Mient-jan Stelling as react-native-markdown-renderer

原始使用文档
文档目录10 节
  1. Compatibility with react-native-markdown-renderer
  2. Install
  3. Get Started
  4. Props and Functions
  5. How to style stuff
  6. Styles
  7. Rules
  8. All rules and their associated styles:
  9. Pre Processing
  10. Other Notes

React Native Markdown Display npm version Known Vulnerabilities

This is a fork of jonasmerlin/react-native-markdown-display that itself is a fork of iamacup/react-native-markdown-display. This is used for our own React Native application for rendering rich text. It may be of some use to you too!

It a 100% compatible CommonMark renderer, a react-native markdown renderer done right. This is not a web-view markdown renderer but a renderer that uses native components for all its elements. These components can be overwritten and styled as needed.

Compatibility with react-native-markdown-renderer

This is intended to be a replacement for react-native-markdown-renderer, with a variety of bug fixes and enhancements - Due to how the new style rules work, there may be some tweaking needed, see how to style stuff section below

Install

Yarn

yarn add @cosmicmedia/react-native-markdown-display

NPM

npm install -S @cosmicmedia/react-native-markdown-display

Get Started

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar} from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `# h1 Heading 8-)

**This is some bold text!**

This is normal text
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown>{copy}</Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Props and Functions

The <Markdown> object takes the following common props:

PropertyDefaultRequiredDescription
childrenN/AtrueThe markdown string to render, or the pre-processed tree
stylesourcefalseAn object to override the styling for the various rules, see style section below for more info
mergeStyletruefalseIf true, when a style is supplied, the individual items are merged with the default styles instead of overwriting them
rulessourcefalseAn object of rules that specify how to render each markdown item, see rules section below for more info
onLinkPressimport { Linking } from 'react-native'; and Linking.openURL(url);falseA handler function to change click behaviour, see handling links section below for more info
debugPrintTreefalsefalseWill print the AST tree to the console to help you see what the markdown is being translated to

And some additional, less used options:

PropertyDefaultRequiredDescription
rendererinstanceOf(AstRenderer)falseUsed to specify a custom renderer, you can not use the rules or styles props with a custom renderer.
markdownitinstanceOf(MarkdownIt)falseA custom markdownit instance with your configuration, default is MarkdownIt({typographer: true})
maxTopLevelChildrennullfalseIf defined as a number will only render out first n many top level children, then will try to render out topLevelMaxExceededItem
topLevelMaxExceededItem<Text key="dotdotdot">...</Text>falseWill render when maxTopLevelChildren is hit. Make sure to give it a key!
allowedImageHandlers['data:image/png;base64', 'data:image/gif;base64', 'data:image/jpeg;base64', 'https://', 'http://']falseAny image that does not start with one of these will have the defaultImageHandler value prepended to it (unless defaultImageHandler is null in which case it won't try to render anything)
defaultImageHandlerhttp://falseWill be prepended to an image url if it does not start with something in the allowedImageHandlers array, if this is set to null, it won't try to recover but will just not render anything instead.

Syntax Support

Headings

  # h1 Heading 8-)
  ## h2 Heading
  ### h3 Heading
  #### h4 Heading
  ##### h5 Heading
  ###### h6 Heading
iOSAndroid

Horizontal Rules

  Some text above
  ___

  Some text in the middle

  ---

  Some text below
iOSAndroid

Emphasis

  **This is bold text**

  __This is bold text__

  *This is italic text*

  _This is italic text_

  ~~Strikethrough~~
iOSAndroid

Blockquotes

  > Blockquotes can also be nested...
  >> ...by using additional greater-than signs right next to each other...
  > > > ...or with spaces between arrows.
iOSAndroid

Lists

  Unordered

  + Create a list by starting a line with `+`, `-`, or `*`
  + Sub-lists are made by indenting 2 spaces:
    - Marker character change forces new list start:
      * Ac tristique libero volutpat at
      + Facilisis in pretium nisl aliquet. This is a very long list item that will surely wrap onto the next line.
      - Nulla volutpat aliquam velit
  + Very easy!

  Ordered

  1. Lorem ipsum dolor sit amet
  2. Consectetur adipiscing elit. This is a very long list item that will surely wrap onto the next line.
  3. Integer molestie lorem at massa

  Start numbering with offset:

  57. foo
  58. bar
iOSAndroid

Code

  Inline \`code\`

Indented code

      // Some comments
      line 1 of code
      line 2 of code
      line 3 of code

Block code "fences"

\`\`\`
Sample text here...
\`\`\`

Syntax highlighting

\`\`\` js
var foo = function (bar) {
return bar++;
};

console.log(foo(5));
\`\`\`

iOSAndroid

Tables


| Option | Description                                                               |
| ------ | ------------------------------------------------------------------------- |
| data   | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default.    |
| ext    | extension to be used for dest files.                                      |

Right aligned columns

| Option |                                                               Description |
| -----: | ------------------------------------------------------------------------: |
|   data | path to data files to supply the data that will be passed into templates. |
| engine |    engine to be used for processing templates. Handlebars is the default. |
|    ext |                                      extension to be used for dest files. |

iOSAndroid

Links


[link text](https://www.google.com)

[link with title](https://www.google.com 'title text!')

Autoconverted link https://www.google.com (enable linkify to see)

iOSAndroid

Images


![Minion](https://octodex.github.com/images/minion.png)
![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg 'The Stormtroopocat')

Like links, Images also have a footnote style syntax

![Alt text][id]

With a reference later in the document defining the URL location:

[id]: https://octodex.github.com/images/dojocat.jpg 'The Dojocat'

iOSAndroid

Typographic Replacements


Enable typographer option to see result.

(c) (C) (r) (R) (tm) (TM) (p) (P) +-

test.. test... test..... test?..... test!....

!!!!!! ???? ,, -- ---

"Smartypants, double quotes" and 'single quotes'

iOSAndroid

Plugins and Extensions

Plugins for extra syntax support can be added using any markdown-it compatible plugins - see plugins for documentation from markdown-it. An example for integration follows:

Step 1

Identify the new components and integrate the plugin with a rendered component. We can use the debugPrintTree property to see what rules we are rendering:

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar } from 'react-native';

import Markdown, { MarkdownIt } from 'react-native-markdown-display';
import blockEmbedPlugin from 'markdown-it-block-embed';

const markdownItInstance =
    MarkdownIt({typographer: true})
      .use(blockEmbedPlugin, {
        containerClassName: "video-embed"
      });

const copy = `
# Some header

@[youtube](lJIrF4YjHfQ)
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
              debugPrintTree
              markdownit={markdownItInstance}
            >
              {copy}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

In the console, we will see the following rendered tree:

body
-heading1
--textgroup
---text
-video

With the following error message:

Warning, unknown render rule encountered: video. 'unknown' render rule used (by default, returns null - nothing rendered)

Step 2

We need to create the render rules and styles to handle this new 'video' component

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar} from 'react-native';

import Markdown, {MarkdownIt} from 'react-native-markdown-display';
import blockEmbedPlugin from 'markdown-it-block-embed';

const markdownItInstance = MarkdownIt({typographer: true}).use(
  blockEmbedPlugin,
  {
    containerClassName: 'video-embed',
  },
);

const copy = `
# Some header

@[youtube](lJIrF4YjHfQ)
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown
            debugPrintTree
            markdownit={markdownItInstance}
            style={{
              video: {
                color: 'red',
              },
            }}
            rules={{
              video: (node, children, parent, styles) => {
                // examine the node properties to see what video we need to render
                console.log(node); // expected output of this is in readme.md below this code snip

                return (
                  <Text key={node.key} style={styles.video}>
                    Return a video component instead of this text component!
                  </Text>
                );
              },
            }}>
            {copy}
          </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

And all of the video properties needed to render something meaningful are on the node, like this:

{type: "video", sourceType: "video", sourceInfo: {…}, sourceMeta: null, block: true, …}
  attributes: {}
  block: true
  children: []
  content: ""
  index: 1
  key: "rnmr_1720a98f540_video"
  markup: "@[youtube](lJIrF4YjHfQ)"
  sourceInfo:
    service: YouTubeService
      env: PluginEnvironment {md: MarkdownIt, options: {…}, services: {…}}
      name: "youtube"
      options:
        height: 390
        width: 640
      serviceName: "youtube"
      videoID: "lJIrF4YjHfQ"
      videoReference: "lJIrF4YjHfQ"
  sourceMeta: null
  sourceType: "video"
  tokenIndex: 5
  type: "video"

Other Debugging

You can do some additional debugging of what the markdown instance is spitting out like this:

import Markdown, {MarkdownIt} from 'react-native-markdown-display';
import blockEmbedPlugin from 'markdown-it-block-embed';

const markdownItInstance = MarkdownIt({typographer: true}).use(
  blockEmbedPlugin,
  {
    containerClassName: 'video-embed',
  },
);

const copy = `
# Some header

@[youtube](lJIrF4YjHfQ)
`;

// this shows you the tree that is used by the react-native-markdown-display
const astTree = markdownItInstance.parse(copy, {});
console.log(astTree);

//this contains the html that would be generated - not used by react-native-markdown-display but useful for reference
const html = markdownItInstance.render(copy);
console.log(html);

The above code will output something like this:

astTree:

(4) [Token, Token, Token, Token]

0: Token {type: "heading_open", tag: "h1", attrs: null, map: Array(2), nesting: 1, …}
1: Token {type: "inline", tag: "", attrs: null, map: Array(2), nesting: 0, …}
2: Token {type: "heading_close", tag: "h1", attrs: null, map: null, nesting: -1, …}
3: Token {type: "video", tag: "div", attrs: null, map: Array(2), nesting: 0, …}

length: 4
html:


<h1>Some header</h1>
<div class="video-embed block-embed-service-youtube"><iframe type="text/html" src="//www.youtube.com/embed/lJIrF4YjHfQ" frameborder="0" width="640" height="390" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>

All Markdown for Testing

This is all of the markdown in one place for testing that your applied styles work in all cases

Headings

  # h1 Heading 8-)
  ## h2 Heading
  ### h3 Heading
  #### h4 Heading
  ##### h5 Heading
  ###### h6 Heading


Horizontal Rules

  Some text above
  ___

  Some text in the middle

  ---

  Some text below


Emphasis

  **This is bold text**

  __This is bold text__

  *This is italic text*

  _This is italic text_

  ~~Strikethrough~~


Blockquotes

  > Blockquotes can also be nested...
  >> ...by using additional greater-than signs right next to each other...
  > > > ...or with spaces between arrows.


Lists

  Unordered

  + Create a list by starting a line with `+`, `-`, or `*`
  + Sub-lists are made by indenting 2 spaces:
    - Marker character change forces new list start:
      * Ac tristique libero volutpat at
      + Facilisis in pretium nisl aliquet. This is a very long list item that will surely wrap onto the next line.
      - Nulla volutpat aliquam velit
  + Very easy!

  Ordered

  1. Lorem ipsum dolor sit amet
  2. Consectetur adipiscing elit. This is a very long list item that will surely wrap onto the next line.
  3. Integer molestie lorem at massa

  Start numbering with offset:

  57. foo
  58. bar


Code

  Inline \`code\`

  Indented code

      // Some comments
      line 1 of code
      line 2 of code
      line 3 of code


  Block code "fences"

  \`\`\`
  Sample text here...
  \`\`\`

  Syntax highlighting

  \`\`\` js
  var foo = function (bar) {
    return bar++;
  };

  console.log(foo(5));
  \`\`\`


Tables

  | Option | Description |
  | ------ | ----------- |
  | data   | path to data files to supply the data that will be passed into templates. |
  | engine | engine to be used for processing templates. Handlebars is the default. |
  | ext    | extension to be used for dest files. |

  Right aligned columns

  | Option | Description |
  | ------:| -----------:|
  | data   | path to data files to supply the data that will be passed into templates. |
  | engine | engine to be used for processing templates. Handlebars is the default. |
  | ext    | extension to be used for dest files. |


Links

  [link text](https://www.google.com)

  [link with title](https://www.google.com "title text!")

  Autoconverted link https://www.google.com (enable linkify to see)


Images

  ![Minion](https://octodex.github.com/images/minion.png)
  ![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")

  Like links, Images also have a footnote style syntax

  ![Alt text][id]

  With a reference later in the document defining the URL location:

  [id]: https://octodex.github.com/images/dojocat.jpg  "The Dojocat"


Typographic Replacements

  Enable typographer option to see result.

  (c) (C) (r) (R) (tm) (TM) (p) (P) +-

  test.. test... test..... test?..... test!....

  !!!!!! ???? ,,  -- ---

  "Smartypants, double quotes" and 'single quotes'

Rules and Styles

How to style stuff

Text styles are applied in a way that makes it much more convenient to manage changes to global styles while also allowing fine tuning of individual elements.

Think of the implementation like applying styles in CSS. changes to the body effect everything, but can be overwritten further down the style / component tree.

Be careful when styling 'text': the text rule is not applied to all rendered text, most notably list bullet points. If you want to, for instance, color all text, change the body style.

Example

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar} from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `
This is some text which is red because of the body style, which is also really small!

\`\`\`
//This is a code block woooo

const cool = () => {
  console.log('????');
};
\`\`\`

and some more small text

# This is a h1
## this is a h2
### this is a h3
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown
            style={{
              body: {color: 'red', fontSize: 10},
              heading1: {color: 'purple'},
              code_block: {color: 'black', fontSize: 14},
            }}>
            {copy}
          </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Styles

Styles are used to override how certain rules are styled. The existing implementation is here

NOTE: By default styles are merged with the existing implementation, to change this, see the mergeStyle prop

Example Implementation

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar, StyleSheet} from 'react-native';

import Markdown from 'react-native-markdown-display';

const styles = StyleSheet.create({
  heading1: {
    fontSize: 32,
    backgroundColor: '#000000',
    color: '#FFFFFF',
  },
  heading2: {
    fontSize: 24,
  },
  heading3: {
    fontSize: 18,
  },
  heading4: {
    fontSize: 16,
  },
  heading5: {
    fontSize: 13,
  },
  heading6: {
    fontSize: 11,
  },
});

const copy = `
# h1 Heading 8-)
## h2 Heading 8-)
### h3 Heading 8-)

| Option | Description |
| ------ | ----------- |
| data   | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext    | extension to be used for dest files. |
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown style={styles}>{copy}</Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Rules

Rules are used to specify how you want certain elements to be displayed. The existing implementation is here

Example Implementation

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar, Text} from 'react-native';

import Markdown from 'react-native-markdown-display';

const rules = {
  heading1: (node, children, parent, styles) => (
    <Text key={node.key} style={[styles.heading, styles.heading1]}>
      >> H1 TEXT HERE >> "{children}"
    </Text>
  ),
  heading2: (node, children, parent, styles) => (
    <Text key={node.key} style={[styles.heading, styles.heading2]}>
      >> H2 TEXT HERE >> "{children}"
    </Text>
  ),
  heading3: (node, children, parent, styles) => (
    <Text key={node.key} style={[styles.heading, styles.heading3]}>
      >> H3 TEXT HERE >> "{children}"
    </Text>
  ),
};

const copy = `
# h1 Heading 8-)
## h2 Heading 8-)
### h3 Heading 8-)

| Option | Description |
| ------ | ----------- |
| data   | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext    | extension to be used for dest files. |
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown rules={rules}>{copy}</Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

All rules and their associated styles:

Render RuleStyle(s)
bodybody
heading1heading1
heading2heading2
heading3heading3
heading4heading4
heading5heading5
heading6heading6
hrhr
strongstrong
emem
ss
blockquoteblockquote
bullet_listbullet_list
ordered_listordered_list
list_itemlist_item - This is a special case that contains a set of pseudo classes that don't align to the render rule: ordered_list_icon, ordered_list_content, bullet_list_icon, bullet_list_content
code_inlinecode_inline
code_blockcode_block
fencefence
tabletable
theadthead
tbodytbody
thth
trtr
tdtd
linklink
blocklinkblocklink
imageimage
texttext
textgrouptextgroup
paragraphparagraph
hardbreakhardbreak
softbreaksoftbreak
prepre
inlineinline
spanspan

Handling Links

Links, by default, will be handled with the import { Linking } from 'react-native'; import and Linking.openURL(url); call.

It is possible to overwrite this behaviour in one of two ways:

onLinkPress Callback

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar} from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `[This is a link!](https://github.com/iamacup/react-native-markdown-display/)`;

const onLinkPress = (url) => {
  if (url) {
    // some custom logic
    return false;
  }

  // return true to open with `Linking.openURL
  // return false to handle it yourself
  return true;
};

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown onLinkPress={onLinkPress}>{copy}</Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Using a Custom Rule

You will need to overwrite one or both of link and blocklink, the original defenitions can be found here

Something like this with yourCustomHandlerFunctionOrLogicHere:

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar, Text} from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `[This is a link!](https://github.com/iamacup/react-native-markdown-display/)`;

const rules = {
  link: (node, children, parent, styles) => {
    return (
      <Text
        key={node.key}
        style={styles.link}
        onPress={() =>
          yourCustomHandlerFunctionOrLogicHere(node.attributes.href)
        }>
        {children}
      </Text>
    );
  },
};

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown rules={rules}>{copy}</Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Disabling Specific Types of Markdown

You can dissable any type of markdown you want, which is very useful in a mobile environment, by passing the markdownit property like below. Note that for convenience we also export the MarkdownIt instance so you don't have to include it as a project dependency directly just to remove some types of markdown.

This example will stop images and links.

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar, Text} from 'react-native';

import Markdown, {MarkdownIt} from 'react-native-markdown-display';

const copy = `
# This heading will show with formatting

[but this link will just](be displayed as this text)
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown
            markdownit={MarkdownIt({typographer: true}).disable([
              'link',
              'image',
            ])}>
            {copy}
          </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

A full list of things you can turn off is here

Pre Processing

It is possible to need to pre-process the data outside of this library (related discussion here). As a result, you can pass an AST tree directly as the children like this:

import React from 'react';
import {SafeAreaView, ScrollView, StatusBar, Text} from 'react-native';

import Markdown, {
  MarkdownIt,
  tokensToAST,
  stringToTokens,
} from 'react-native-markdown-display';

const markdownItInstance = MarkdownIt({typographer: true});

const copy = `
# Hello this is a title

This is some text with **BOLD!**
`;

const ast = tokensToAST(stringToTokens(copy, markdownItInstance));

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}>
          <Markdown>{ast}</Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Other Notes

This is a fork of react-native-markdown-renderer, a library that unfortunately has not been updated for some time so i took all of the outstanding pull requests from that library and tested + merged as necessary.

版本与发布记录

@cosmicmedia/react-native-markdown-display 共发布 8 个版本,首次发布于 2023/07/02;过去 12 个月发布了 0 个版本。

版本发布日期距今
1.1.7latest2023/08/093 年前
1.1.62023/08/093 年前
1.1.52023/07/023 年前
1.1.42023/07/023 年前
1.1.32023/07/023 年前
1.1.22023/07/023 年前

关于 @cosmicmedia/react-native-markdown-display 的常见问题

@cosmicmedia/react-native-markdown-display 是什么?

Markdown renderer for react-native, with CommonMark spec support + adds syntax extensions & sugar (URL autolinking, typographer), originally created by Mient-jan Stelling as react-native-markdown-renderer

如何安装 @cosmicmedia/react-native-markdown-display?

在项目目录运行 npm install @cosmicmedia/react-native-markdown-display,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^16.2.0 || ^18.0.0)、react-native(>=0.50.4)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cosmicmedia/react-native-markdown-display 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cosmicmedia/react-native-markdown-display 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@cosmicmedia/react-native-markdown-display 可以商用吗?

@cosmicmedia/react-native-markdown-display 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cosmicmedia/react-native-markdown-display 的下载量有多少?

根据 npm 官方下载统计,@cosmicmedia/react-native-markdown-display 在 2026/10/11 – 2026/11/09 这 30 天内被下载 6,336 次,日均约 211 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cosmicmedia/react-native-markdown-display 还在维护吗?

最新版本 1.1.7 发布于 2023/08/09(3 年前);至今共发布 8 个版本,其中过去 12 个月发布了 0 个;首次发布于 2023/07/02。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。