npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@iyucode/md-editor

v4.11.2

Published

Markdown editor for react.

Downloads

1

Readme

🎄 md-editor-rt

English | 中文

Markdown editor for react, developed in jsx and typescript. This project is based on the md-editor-rt project and has been modified for secondary development.

  • Source documentation and demo:Go
  • Use it online:Go
  • The same series editor for vue3:md-editor-v3

⭐️ Features

  • Toolbar, screenfull or screenfull in web pages and so on.
  • Themes, Built-in default and dark themes.
  • Shortcut key for editor.
  • Beautify your content by prettier(only for markdown content, not the code and other text).
  • Multi-language, build-in Chinese and English(default: Chinese).
  • Upload picture, paste or clip the picture and upload it.
  • Render article directly(no editor, no event listener, only preview content).
  • Theme of preview, default, vuepress, github, cyanosis, mk-cute, smart-blue styles(not identical). It can be customized also(Refer to example page).
  • mermaid(>=1.3.0), katex mathematical formula(>=1.4.0).
  • Customize the toolbar as you like.
  • On-demand Import(>=4.0.0).

📦 Install

yarn add md-editor-rt

Use existing extension of language and theme, such as Japanese

yarn add @vavt/cm-extension

Use existing components of toolbar, such as exporting content as PDF

yarn add @vavt/v3-extension

For more ways to use or contribute, please refer to: md-editor-extension

💡 Usage

✍🏻 Display Editor

import React, { useState } from 'react';
import { MdEditor } from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';

export default () => {
  const [text, setText] = useState('# Hello Editor');
  return <MdEditor modelValue={text} onChange={setText} />;
};

^4.0.0, internal components can be imported on-demand.

If there are multiple editors on the page, please set different editorId for each editor!

📖 Preview Only

import React, { useState } from 'react';
import { MdPreview, MdCatalog } from 'md-editor-rt';
import 'md-editor-rt/lib/preview.css';

const scrollElement = document.documentElement;

export default () => {
  const [text] = useState('# Hello Editor');
  const [id] = useState('preview-only');

  return (
    <>
      <MdPreview editorId={id} modelValue={text} />
      <MdCatalog editorId={id} scrollElement={scrollElement} />
    </>
  );
};

🗺 Preview

| Default theme | Dark theme | Preview only | | --- | --- | --- | | | | |

Inputing prompt and mark, emoji extensions

🎁 Apis

🔖 MdPreivew Props

| name | type | default | description | | --- | --- | --- | --- | | modelValue | string | '' | Markdown content | | theme | 'light' \| 'dark' | 'light' | Editor theme | | className | string | '' | | | language | string | 'zh-CN' | Build-in language('zh-CN','en-US') | | editorId | string | 'md-editor-rt' | Editor id, it is used when there are more than two editors in the same page | | showCodeRowNumber | boolean | false | Show row number for code block or not | | previewTheme | 'default' \| 'github' \| 'vuepress' \| 'mk-cute' \| 'smart-blue' \| 'cyanosis' | 'default' | Preview theme, can be customized | | style | CSSProperties | {} | Editor inline style | | noMermaid | boolean | false | Use mermaid or not | | noKatex | boolean | false | Use katex or not | | codeTheme | 'atom' \| 'a11y' \| 'github' \| 'gradient' \| 'kimbie' \| 'paraiso' \| 'qtcreator' \| 'stackoverflow' | 'atom' | Highlight code style, can be customized also | | mdHeadingId | (text: string, level: number, index: number) => string | (text) => text | H1-H6 ID generator | | sanitize | (html: string) => string | (html) => html | Sanitize the html, prevent XSS. After 3.x, dangerous code has been processed by default. Please do not use this attribute unless there are special requirements | | noIconfont | boolean | false | Not append iconfont script, download different versions SVGFont Class and import it by yourself | | formatCopiedText | (text: string) => string | (text: string) => text | Format copied code | | codeStyleReverse | boolean | true | Code style will be reversed to dark while code block of the theme has a dark background | | codeStyleReverseList | Array<string> | ['default', 'mk-cute'] | Themes to be reversed | | noHighlight | boolean | false | Highlight code or not | | noImgZoomIn | boolean | false | Enable the function of enlarging images | | customIcon | CustomIcon | {} | Customized icons | | sanitizeMermaid | (h: string) => Promise<string> | (h: string) => Promise.resolve(h) | Convert the generated mermaid code |

🔩 MdEditor Props

Except for the same as MdPreview:

| name | type | default | description | | --- | --- | --- | --- | | pageFullscreen | boolean | false | Screenfull in web page | | preview | boolean | true | Preview content in editor | | htmlPreview | boolean | false | Preview html in editor(If true, preview must be false) | | toolbars | Array<ToolbarNames \| number> | [toolbars] | Show contents of toolbar, all keyssee toolbars below | | toolbarsExclude | Array<ToolbarNames \| number> | [] | Don't show contents of toolbar, all keystoolbars | | noPrettier | boolean | false | Use prettier to beautify content or not | | tabWidth | number | 2 | One tab eq some spaces | | tableShape | [number, number] | [6, 4] | Preset the size of the table, [columns, rows] | | placeholder | string | '' | | | defToolbars | Array<DropdownToolbar \| NormalToolbar \| ModalToolbar> | [] | Custom toolbar in DropdownToolbar, NormalToolbar or ModalToolbar | | footers | Array<'markdownTotal' \| '=' \| 'scrollSwitch' \| number> | ['markdownTotal', '=', 'scrollSwitch'] | Show contents of footer, they are divided by '='. Set it to [] to hidden footer | | scrollAuto | boolean | true | Scroll default setting | | defFooters | Array<string \| ReactElement> | [] | Custom footer | | noUploadImg | boolean | false | Not show the entrance to upload pictures | | autoFocus | boolean | false | same as autofocus in native textarea | | disabled | boolean | false | same as disabled in native textarea | | readOnly | boolean | false | same as readonly in native textarea | | maxLength | number | | same as maxlength in native textarea | | autoDetectCode | boolean | false | auto detect the type of pasted code, only support that copied from vscode | | completions | Array<CompletionSource> | [] | @codemirror/autocomplete List of function to match keywords | | showToolbarName | boolean | false | Show toolbar name or not | | inputBoxWitdh | string | '50%' | Default width of input box | | disableResizing | boolean | false | When opening preview mode or HTML preview mode, disable resizing of the editor area |

[
  'bold',
  'underline',
  'italic',
  '-',
  'strikeThrough',
  'title',
  'sub',
  'sup',
  'quote',
  'unorderedList',
  'orderedList',
  'task', // ^2.4.0
  '-',
  'codeRow',
  'code',
  'link',
  'image',
  'table',
  'mermaid',
  'katex',
  '-',
  'revoke',
  'next',
  'save',
  '=',
  'pageFullscreen',
  'fullscreen',
  'preview',
  'htmlPreview',
  'catalog',
  'github'
];

You can sort the toolbar as you like, split tools by '-', the left and right toolbars are divided by '='!

Expand language, you need to replace all the content here:

export interface ToolbarTips {
  bold?: string;
  underline?: string;
  italic?: string;
  strikeThrough?: string;
  title?: string;
  sub?: string;
  sup?: string;
  quote?: string;
  unorderedList?: string;
  orderedList?: string;
  task?: string; // ^2.4.0
  codeRow?: string;
  code?: string;
  link?: string;
  image?: string;
  table?: string;
  mermaid?: string;
  katex?: string;
  revoke?: string;
  next?: string;
  save?: string;
  prettier?: string;
  pageFullscreen?: string;
  fullscreen?: string;
  catalog?: string;
  preview?: string;
  htmlPreview?: string;
  github?: string;
  '-'?: string;
  '='?: string;
}

export interface StaticTextDefaultValue {
  // Toolbar hover tips(html title)
  toolbarTips?: ToolbarTips;
  // h1-h6 dropdown menu item
  titleItem?: {
    h1?: string;
    h2?: string;
    h3?: string;
    h4?: string;
    h5?: string;
    h6?: string;
  };
  // v1.6.0
  imgTitleItem?: {
    link: string;
    upload: string;
    clip2upload: string;
  };
  // The modal tips of add link or upload picture
  linkModalTips?: {
    linkTitle?: string;
    imageTitle?: string;
    descLabel?: string;
    descLabelPlaceHolder?: string;
    urlLabel?: string;
    urlLabelPlaceHolder?: string;
    buttonOK?: string;
  };
  // The modal tips of clip the picture, v1.2.0
  clipModalTips?: {
    title?: string;
    buttonUpload?: string;
  };
  // Copy code tips, v1.1.4
  copyCode?: {
    text?: string;
    successTips?: string;
    failTips?: string;
  };
  // 1.8.0
  mermaid?: {
    flow?: string;
    sequence?: string;
    gantt?: string;
    class?: string;
    state?: string;
    pie?: string;
    relationship?: string;
    journey?: string;
  };
  // 1.9.0
  katex?: {
    // formula inline
    inline: string;
    // formula block
    block: string;
  };
  footer?: {
    markdownTotal: string;
    scrollAuto: string;
  };
}

🧵 MdPreview Events

| name | type | description | | --- | --- | --- | | onHtmlChanged | html: string | Compile markdown successful event, you can use it to get the html code | | onGetCatalog | list: Array<HeadList> | Get catalog of article |

🪢 MdEditor Events

Except for the same as MdPreview:

| name | type | description | | --- | --- | --- | | onChange | value: string | Content changed(bind to oninput of textarea) | | onSave | value: string, html: Promise<string> | Saving content, ctrl+s and clicking button will trigger it | | onUploadImg | files: Array<File>, callback: (urls: Array<string>) => void | Uploading picture, when picture is uploading the modal will not close, please provide right urls to the callback function | | onError | err: { name: 'Cropper' \| 'fullscreen' \| 'prettier' \| 'overlength'; message: string } | Catch run-time error, Cropper, fullscreen and prettier are used when they are not loaded. And content exceeds the length limit error | | onBlur | event: FocusEvent<HTMLTextAreaElement, Element> | Textarea has lost focus | | onFocus | event: FocusEvent<HTMLTextAreaElement, Element> | Textarea has received focus | | onInput | event: Event | Element gets input | | onDrop | event: DragEvent | Selection is being dragged | | onInputBoxWitdhChange | (width: string) => void | Width of input box has been changed |

🤱🏼 Expose

After 2.5.0, Editor exposes several methods on the instance, used to get or change the internal status of the editor.

import React, { useState, useEffect, useRef } from 'react';
import { MdEditor, ExposeParam } from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';

export default () => {
  const [text, setText] = useState('#Hello Editor');

  const editorRef = useRef<ExposeParam>();

  useEffect(() => {
    editorRef.current?.on('catalog', console.log);
  }, []);

  return <MdEditor ref={editorRef} modelValue={text} onChange={setText} />;
};

Switched to the opposite status, if toggle without input parameter.

👂🏼 on

Get the internal state of the editor, including pageFullscreen, fullscreen, preview, htmlPreview, catalog, etc.

  • pageFullscreen

    editorRef.current?.on('pageFullscreen', (status) => console.log(status));
  • fullscreen

    editorRef.current?.on('fullscreen', (status) => console.log(status));
  • preview

    editorRef.current?.on('preview', (status) => console.log(status));
  • htmlPreview

    editorRef.current?.on('htmlPreview', (status) => console.log(status));
  • catalog

    editorRef.current?.on('catalog', (status) => console.log(status));

💻 togglePageFullscreen

Toggle status of fullscreen within the page.

editorRef.current?.togglePageFullscreen(true);

🖥 toggleFullscreen

Toggle status of fullscreen widthin browser.

editorRef.current?.toggleFullscreen(true);

📖 togglePreview

Toggle status of preview.

editorRef.current?.togglePreview(true);

📼 toggleHtmlPreview

Toggle status of htmlPreview.

editorRef.current?.toggleHtmlPreview(true);

🧬 toggleCatalog

Toggle status of catalog.

editorRef.current?.toggleCatalog(true);

💾 triggerSave

editorRef.current?.triggerSave();

💉 insert

Manually insert content into textarea.

/**
 * @params selectedText
 */
editorRef.current?.insert((selectedText) => {
  /**
   * @return targetValue    Content to be inserted
   * @return select         Automatically select content, default: true
   * @return deviationStart Start position of the selected content, default: 0
   * @return deviationEnd   End position of the selected content, default: 0
   */
  return {
    targetValue: `${selectedText}`,
    select: true,
    deviationStart: 0,
    deviationEnd: 0
  };
});

For more examples, refer to source code of extension component

🎯 focus

Focus on textarea.

import type { FocusOption } from 'md-editor-rt';

const option: FocusOption | undefined = 'start';

// Cursor position when focusing on textarea, default: position when it last lost focus
editorRef.current?.focus(option);

✒️ rerender

Re render the content.

editorRef.current?.rerender();

🔍 getSelectedText

Get the currently selected text.

console.log(editorRef.current?.getSelectedText());

🗑 resetHistory

Clear current history.

💴 Config Editor

Use config(option: ConfigOption) to reconfigure markdown-it and so on.

codeMirrorExtensions

Customize new extensions based on theme and default extensions f codeMirror.

Example: Editor does not render the line number of textarea by default, this extension needs to be manually added

import { config } from 'md-editor-rt';
import { lineNumbers } from '@codemirror/view';

config({
  codeMirrorExtensions(_theme, extensions) {
    return [...extensions, lineNumbers()];
  }
});

markdownItConfig

Customize extensions, attributes of markdown-it, etc.

type MarkdownItConfig = (
  md: markdownit,
  options: {
    editorId: string;
  }
) => void;

Example: Use markdown-it-anchor to render a hyperlink symbol to the right of the title

import { config } from 'md-editor-rt';
import ancher from 'markdown-it-anchor';

config({
  markdownItConfig(mdit) {
    mdit.use(ancher, {
      permalink: true
    });
  }
});

markdownItPlugins

Select and add built-in plugins to markdown-it.

type MarkdownItPlugins = (
  plugins: Array<MarkdownItConfigPlugin>,
  options: {
    editorId: string;
  }
) => Array<MarkdownItConfigPlugin>;

Example: Modify the class name of the image.

import { config } from 'md-editor-rt';

config({
  markdownItPlugins(plugins) {
    return plugins.map((p) => {
      if (p.type === 'image') {
        return {
          ...p,
          options: {
            ...p.options,
            classes: 'my-class'
          }
        };
      }

      return p;
    });
  }
});

editorConfig

Add more languages, reset mermaid template or delay rendering time:

import { config } from 'md-editor-rt';

config({
  editorConfig: {
    languageUserDefined: { lang: StaticTextDefaultValue },
    mermaidTemplate: {
      flow: `flow tempalte`,
      ...more
    },
    // Default 500ms. It is set to 0ms when preview only and not set.
    renderDelay: 500
  }
});

editorExtensions

Config some dependency libraries, like highlight..

import { config } from 'md-editor-rt';

config({
  editorExtensions: { iconfont: 'https://xxx.cc' }
});
export interface EditorExtensions {
  highlight?: {
    instance?: any;
    js?: string;
    css?: {
      [key: string]: {
        light: string;
        dark: string;
      };
    };
  };
  prettier?: {
    standaloneJs?: string;
    parserMarkdownJs?: string;
  };
  cropper?: {
    instance?: any;
    js?: string;
    css?: string;
  };
  iconfont?: string;
  screenfull?: {
    instance?: any;
    js?: string;
  };
  mermaid?: {
    instance?: any;
    js?: string;
  };
  katex?: {
    instance?: any;
    js?: string;
    css?: string;
  };
}

🫨 iconfontType

Set the way to display icons:

  • svg: with symbol
  • class: with font-class

If the icon is customized through the attribute customIcon, the customized icon will be used first.

🎨 mermaidConfig

Configure mermaid, Details

import { config } from 'md-editor-v3';
config({
  mermaidConfig(base: any) {
    return {
      ...base,
      logLevel: 'error'
    };
  }
});

🪡 Shortcut Key

Pay attention: shortcut keys are only available when the textarea has received focus!

| key | function | description | | --- | --- | --- | | TAB | insert space | Insert space, the length eq tabWidth, default: 2, support multiline | | SHIFT + TAB | delete space, setting is the same as Tab | | | CTRL + C | copy | When selected, copy the selected content. When not selected, copy the content of the current line | | CTRL + X | shear | When selected, cut the selected content. When not selected, cut the current line | | CTRL + D | delete | When selected, delete the selected content. When not selected, delete the current line | | CTRL + S | save | Trigger onSave event | | CTRL + B | bold text | **bold** | | CTRL + U | underline | <u>underline</u> | | CTRL + I | italic | *italic* | | CTRL + 1-6 | h1-h6 | # title | | CTRL + ↑ | superscript | <sup>superscript</sup> | | CTRL + ↓ | subscript | <sub>subscript</sub> | | CTRL + O | ordered list | 1. ordered list | | CTRL + L | link | [link](https://github.com/imzbf/md-editor-rt) | | CTRL + Z | withdraw | Withdraw history in editor, not the function of system | | CTRL + SHIFT + S | line-through | ~line-through~ | | CTRL + SHIFT + U | unordered list | - unordered list | | CTRL + SHIFT + C | code block | | | CTRL + SHIFT + I | picture | ![picture](https://imzbf.github.io/md-editor-rt/imgs/preview-light.png) | | CTRL + SHIFT + Z | forward | Forward history in editor, not the function of system | | CTRL + SHIFT + F | Beautify | | | CTRL + ALT + C | code row | | | CTRL + SHIFT + ALT + T | table | \|table\| |

🪤 Internal Components

import { NormalToolbar } from 'md-editor-rt';

For more examples, refer to document.

🐣 NormalToolbar

NormalToolbar

  • props

    • title: string, not necessary, title of toolbar.
    • trigger: ReactNode, necessary, it is usually an icon, which is displayed on the toolbar.
  • events

    • onClick: (e: MouseEvent) => void, necessary.

🐼 DropdownToolbar

DropdownToolbar

  • props

    • title: string, not necessary, title of toolbar.
    • visible: boolean, necessary.
    • trigger: ReactNode, necessary, it is usually an icon, which is displayed on the toolbar.
    • overlay: ReactNode, necessary, content of dropdown box.
  • events

    • onChange: (visible: boolean) => void, necessary.

🦉 ModalToolbar

ModalToolbar

  • props

    • title: string, not necessary, title of toolbar.
    • modalTitle: ReactNode, not necessary, title of the Modal.
    • visible: boolean, necessary, visibility of Modal.
    • width: string, not necessary, width of Modal, default auto.
    • height: string, same as width.
    • showAdjust: boolean, not necessary, visibility of fullscreen button.
    • isFullscreen: boolean, necessary when showAdjust = true, status of fullscreen.
    • trigger: ReactNode, necessary, it is usually an icon, which is displayed on the toolbar.
    • children: ReactNode, necessary, content of Modal.
  • events

    • onClick: () => void, necessary.
    • onClose: () => void, necessary, closed event.
    • onAdjust: (val: boolean) => void, fullscreen button was clicked.

🐻 MdCatalog

MdCatalog

  • props

    • editorId: string, necessary, same as editor's editorId, used to register listening events.
    • class: string, not necessary.
    • mdHeadingId: MdHeadingId, not necessary, same as editor.
    • scrollElement: string | HTMLElement, not necessary, it is an element selector when its type is string. When previewOnly eq true, it is usually set to document.documentElement.
    • theme: 'light' | 'dark', not necessary, provide it when you want to change theme online, it is the same as Editor theme.
    • offsetTop: number, not necessary, highlight current item of catalogs when title is offsetTop pixels from the top, default 20.
    • scrollElementOffsetTop: number, not necessary, offsetTop of the scroll container,default 0.
  • events

    • onClick: (e: MouseEvent, t: TocItem) => void, not necessary, heading was clicked.
    • onActive: (heading: HeadList | undefined) => void, not necessary, heading was highlighted.

🛸 MdModal

MdModal

  • props

    • title: ReactNode, not necessary, title of Modal.
    • visible: boolean, necessary, visibility of Modal.
    • width: string, not necessary, width of Modal, default auto.
    • height: string, same as width.
    • showAdjust: boolean, not necessary, visibility of fullscreen button.
    • isFullscreen: boolean, necessary when showAdjust = true, status of fullscreen.
    • children: ReactNode, necessary, content of Modal.
    • className: string, not necessary.
    • style: CSSProperties, not necessary.
  • events

    • onClose: () => void, necessary, closed event.
    • onAdjust: (val: boolean) => void, fullscreen button was clicked.

🪤 Internal Configuration

import {
  iconfontClassUrl,
  iconfontSvgUrl,
  allToolbar,
  allFooter,
  zh_CN,
  en_US
} from 'md-editor-rt';

console.log(iconfontClassUrl, iconfontSvgUrl, allToolbar, allFooter, zh_CN, en_US);

🗂 Examples

🥹 Upload Picture

Tips: When you paste and upload GIF, it will upload a static picture. So you should upload it by file system!

import React, { useState } from 'react';
import { MdEditor } from 'md-editor-rt';
import 'md-editor-rt/lib/style.css';

export default () => {
  const [text, setText] = useState('# Hello Editor');

  const onUploadImg = async (files, callback) => {
    const res = await Promise.all(
      files.map((file) => {
        return new Promise((rev, rej) => {
          const form = new FormData();
          form.append('file', file);

          axios
            .post('/api/img/upload', form, {
              headers: {
                'Content-Type': 'multipart/form-data'
              }
            })
            .then((res) => rev(res))
            .catch((error) => rej(error));
        });
      })
    );

    callback(res.map((item) => item.data.url));
  };

  return <MdEditor modelValue={text} onChange={setText} onUploadImg={onUploadImg} />;
};

🧙‍♂️ Change Styles

.css-vars(@isDark) {
  --md-color: if(@isDark, #999, #222);
  --md-hover-color: if(@isDark, #bbb, #000);
  --md-bk-color: if(@isDark, #000, #fff);
  --md-bk-color-outstand: if(@isDark, #111, #f6f6f6);
  --md-bk-hover-color: if(@isDark, #1b1a1a, #f5f7fa);
  --md-border-color: if(@isDark, #2d2d2d, #e6e6e6);
  --md-border-hover-color: if(@isDark, #636262, #b9b9b9);
  --md-border-active-color: if(@isDark, #777, #999);
  --md-modal-mask: #00000073;
  --md-scrollbar-bg-color: if(@isDark, #0f0f0f, #e2e2e2);
  --md-scrollbar-thumb-color: if(@isDark, #2d2d2d, #0000004d);
  --md-scrollbar-thumb-hover-color: if(@isDark, #3a3a3a, #00000059);
  --md-scrollbar-thumb-active-color: if(@isDark, #3a3a3a, #00000061);
}

.md-editor {
  .css-vars(false);
}

.md-editor-dark {
  .css-vars(true);
}

Change background color in dark mode:

.md-editor-dark {
  --md-bk-color: #333 !important;
}