├── docs ├── index.md ├── .vitepress │ ├── theme │ │ ├── custom.css │ │ └── index.js │ └── config.js └── package.json ├── packages ├── bytemd │ ├── .gitignore │ ├── src │ │ ├── locales │ │ ├── env.d.ts │ │ ├── index.ts │ │ ├── status.svelte │ │ ├── utils.ts │ │ ├── help.svelte │ │ ├── toc.svelte │ │ ├── viewer.svelte │ │ └── types.ts │ ├── README.md │ ├── tsconfig.json │ ├── locales │ │ ├── zgh.json │ │ ├── zh_Hant.json │ │ ├── zh_Hans.json │ │ ├── ja.json │ │ ├── ko.json │ │ ├── ar.json │ │ ├── en.json │ │ ├── id.json │ │ ├── tr.json │ │ ├── fr.json │ │ ├── pl.json │ │ ├── nb_NO.json │ │ ├── de.json │ │ ├── pt.json │ │ ├── pt_BR.json │ │ ├── es.json │ │ ├── ru.json │ │ └── ca.json │ ├── tsconfig.svelte.json │ ├── test │ │ ├── setup.ts │ │ ├── viewer.test.ts │ │ └── editor.test.ts │ └── package.json ├── plugin-gfm │ ├── src │ │ ├── locales │ │ ├── icons.ts │ │ └── index.ts │ ├── locales │ │ ├── zh_Hans.json │ │ ├── zh_Hant.json │ │ ├── ar.json │ │ ├── en.json │ │ ├── es.json │ │ ├── fr.json │ │ ├── id.json │ │ ├── pl.json │ │ ├── ru.json │ │ ├── tr.json │ │ ├── ca.json │ │ ├── nb_NO.json │ │ ├── de.json │ │ └── pt_BR.json │ ├── tsconfig.json │ ├── README.md │ └── package.json ├── plugin-math │ ├── src │ │ ├── locales │ │ ├── utils │ │ │ ├── icons.ts │ │ │ └── index.ts │ │ └── index.ts │ ├── locales │ │ ├── ja.json │ │ ├── zh_Hans.json │ │ ├── zh_Hant.json │ │ ├── ar.json │ │ ├── id.json │ │ ├── en.json │ │ ├── fr.json │ │ ├── tr.json │ │ ├── ca.json │ │ ├── es.json │ │ ├── nb_NO.json │ │ ├── pt_BR.json │ │ ├── ru.json │ │ └── pl.json │ ├── tsconfig.json │ ├── README.md │ └── package.json ├── plugin-math-ssr │ ├── src │ │ ├── locales │ │ ├── utils │ │ └── index.ts │ ├── locales │ ├── tsconfig.json │ ├── README.md │ └── package.json ├── plugin-mermaid │ ├── src │ │ ├── locales │ │ ├── icons.ts │ │ └── index.ts │ ├── tsconfig.json │ ├── locales │ │ ├── zh_Hans.json │ │ ├── ar.json │ │ ├── nb_NO.json │ │ ├── id.json │ │ ├── pl.json │ │ ├── de.json │ │ ├── tr.json │ │ ├── pt_BR.json │ │ ├── ca.json │ │ ├── es.json │ │ ├── ru.json │ │ ├── fr.json │ │ └── en.json │ ├── README.md │ └── package.json ├── vue │ ├── src │ │ ├── editor.vue.ts │ │ ├── viewer.vue.ts │ │ ├── index.ts │ │ ├── editor.vue │ │ └── viewer.vue │ ├── plugin.mjs │ ├── README.md │ ├── tsconfig.json │ └── package.json ├── react │ ├── README.md │ ├── src │ │ ├── index.ts │ │ ├── editor.tsx │ │ └── viewer.tsx │ ├── tsconfig.json │ └── package.json ├── vue-next │ ├── README.md │ ├── src │ │ ├── editor.vue.ts │ │ ├── viewer.vue.ts │ │ ├── index.ts │ │ ├── editor.vue │ │ └── viewer.vue │ ├── plugin.mjs │ ├── tsconfig.json │ └── package.json ├── plugin-breaks │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ ├── README.md │ └── package.json ├── plugin-gemoji │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ ├── README.md │ └── package.json ├── plugin-frontmatter │ ├── tsconfig.json │ ├── README.md │ ├── src │ │ └── index.ts │ └── package.json ├── plugin-highlight │ ├── tsconfig.json │ ├── README.md │ ├── src │ │ └── index.ts │ └── package.json ├── plugin-medium-zoom │ ├── tsconfig.json │ ├── README.md │ ├── src │ │ └── index.ts │ └── package.json └── plugin-highlight-ssr │ ├── tsconfig.json │ ├── src │ └── index.ts │ ├── README.md │ └── package.json ├── examples ├── svelte │ ├── .npmrc │ ├── static │ │ └── favicon.png │ ├── .gitignore │ ├── tsconfig.json │ ├── src │ │ ├── app.html │ │ ├── app.d.ts │ │ └── routes │ │ │ └── index.svelte │ ├── svelte.config.js │ ├── package.json │ └── README.md ├── vue3 │ ├── env.d.ts │ ├── public │ │ └── favicon.ico │ ├── src │ │ ├── main.ts │ │ └── App.vue │ ├── tsconfig.vite-config.json │ ├── tsconfig.json │ ├── vite.config.ts │ ├── index.html │ ├── .gitignore │ ├── package.json │ └── README.md ├── vue │ ├── .browserslistrc │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ ├── src │ │ ├── shims-vue.d.ts │ │ ├── main.ts │ │ ├── shims-tsx.d.ts │ │ └── App.vue │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── tsconfig.json ├── react │ ├── src │ │ ├── react-app-env.d.ts │ │ ├── App.css │ │ ├── setupTests.ts │ │ ├── App.test.tsx │ │ ├── index.css │ │ ├── reportWebVitals.ts │ │ ├── index.tsx │ │ └── App.tsx │ ├── public │ │ ├── robots.txt │ │ ├── favicon.ico │ │ ├── logo192.png │ │ ├── logo512.png │ │ ├── manifest.json │ │ └── index.html │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── react-nextjs │ ├── .eslintrc.json │ ├── public │ │ ├── favicon.ico │ │ └── vercel.svg │ ├── next.config.js │ ├── next-env.d.ts │ ├── pages │ │ ├── _app.tsx │ │ ├── api │ │ │ └── hello.ts │ │ └── index.tsx │ ├── styles │ │ ├── globals.css │ │ └── Home.module.css │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── nuxt3 │ ├── .gitignore │ ├── tsconfig.json │ ├── nuxt.config.ts │ ├── app.vue │ ├── package.json │ └── README.md ├── vue-nuxtjs │ ├── static │ │ └── favicon.ico │ ├── .editorconfig │ ├── store │ │ └── README.md │ ├── tsconfig.json │ ├── pages │ │ └── index.vue │ ├── package.json │ ├── nuxt.config.js │ ├── .gitignore │ └── README.md ├── vanilla-js │ └── index.html └── legacy-browser │ └── index.html ├── playground ├── src │ ├── env.d.ts │ ├── index.ts │ ├── text.md │ └── app.svelte ├── vite.config.mjs ├── tsconfig.json ├── index.html └── package.json ├── .prettierignore ├── pnpm-workspace.yaml ├── .gitignore ├── lerna.json ├── .github └── workflows │ ├── test.yml │ ├── style.yml │ ├── release.yml │ └── bundlewatch.yml ├── netlify.toml ├── scripts ├── deploy.sh ├── plugin-template.md ├── utils.mjs ├── icon.mjs ├── postinstall.mjs └── build.mjs ├── tsconfig-base.json ├── vitest.config.mjs ├── tsconfig.json ├── LICENSE └── package.json /docs/index.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /packages/bytemd/.gitignore: -------------------------------------------------------------------------------- 1 | /svelte 2 | -------------------------------------------------------------------------------- /packages/bytemd/src/locales: -------------------------------------------------------------------------------- 1 | ../locales -------------------------------------------------------------------------------- /packages/plugin-gfm/src/locales: -------------------------------------------------------------------------------- 1 | ../locales -------------------------------------------------------------------------------- /packages/plugin-math/src/locales: -------------------------------------------------------------------------------- 1 | ../locales -------------------------------------------------------------------------------- /examples/svelte/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /packages/plugin-math-ssr/src/locales: -------------------------------------------------------------------------------- 1 | ../locales -------------------------------------------------------------------------------- /packages/plugin-mermaid/src/locales: -------------------------------------------------------------------------------- 1 | ../locales -------------------------------------------------------------------------------- /packages/plugin-math-ssr/locales: -------------------------------------------------------------------------------- 1 | ../plugin-math/locales -------------------------------------------------------------------------------- /packages/plugin-math-ssr/src/utils: -------------------------------------------------------------------------------- 1 | ../../plugin-math/src/utils -------------------------------------------------------------------------------- /examples/vue3/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/vue/src/editor.vue.ts: -------------------------------------------------------------------------------- 1 | export { default } from 'vue' 2 | -------------------------------------------------------------------------------- /packages/vue/src/viewer.vue.ts: -------------------------------------------------------------------------------- 1 | export { default } from 'vue' 2 | -------------------------------------------------------------------------------- /playground/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | scripts/*.md 2 | CHANGELOG.md 3 | svelte 4 | dist 5 | -------------------------------------------------------------------------------- /examples/vue/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/** 3 | - playground 4 | -------------------------------------------------------------------------------- /packages/vue/plugin.mjs: -------------------------------------------------------------------------------- 1 | export { createVuePlugin } from 'vite-plugin-vue2' 2 | -------------------------------------------------------------------------------- /examples/react/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/bytemd/README.md: -------------------------------------------------------------------------------- 1 | # ByteMD 2 | 3 | https://github.com/bytedance/bytemd 4 | -------------------------------------------------------------------------------- /packages/bytemd/src/env.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svelte' // to fix `tsc --build` 2 | -------------------------------------------------------------------------------- /packages/react/README.md: -------------------------------------------------------------------------------- 1 | # ByteMD 2 | 3 | https://github.com/bytedance/bytemd 4 | -------------------------------------------------------------------------------- /packages/vue/README.md: -------------------------------------------------------------------------------- 1 | # ByteMD 2 | 3 | https://github.com/bytedance/bytemd 4 | -------------------------------------------------------------------------------- /examples/react-nextjs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /packages/vue-next/README.md: -------------------------------------------------------------------------------- 1 | # ByteMD 2 | 3 | https://github.com/bytedance/bytemd 4 | -------------------------------------------------------------------------------- /packages/vue-next/src/editor.vue.ts: -------------------------------------------------------------------------------- 1 | export { DefineComponent as default } from 'vue' 2 | -------------------------------------------------------------------------------- /packages/vue-next/src/viewer.vue.ts: -------------------------------------------------------------------------------- 1 | export { DefineComponent as default } from 'vue' 2 | -------------------------------------------------------------------------------- /examples/react/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | max-width: 1200px; 3 | margin: 0 auto; 4 | } 5 | -------------------------------------------------------------------------------- /packages/vue-next/plugin.mjs: -------------------------------------------------------------------------------- 1 | export { default as createVue3Plugin } from '@vitejs/plugin-vue' 2 | -------------------------------------------------------------------------------- /examples/react/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/nuxt3/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | dist 9 | -------------------------------------------------------------------------------- /examples/vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/vue/public/favicon.ico -------------------------------------------------------------------------------- /examples/vue3/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/vue3/public/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | dist 5 | tsconfig.tsbuildinfo 6 | coverage 7 | packages/*/LICENSE 8 | -------------------------------------------------------------------------------- /examples/react/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/react/public/favicon.ico -------------------------------------------------------------------------------- /examples/react/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/react/public/logo192.png -------------------------------------------------------------------------------- /examples/react/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/react/public/logo512.png -------------------------------------------------------------------------------- /examples/svelte/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/svelte/static/favicon.png -------------------------------------------------------------------------------- /examples/vue/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /examples/nuxt3/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://v3.nuxtjs.org/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/vue-nuxtjs/static/favicon.ico -------------------------------------------------------------------------------- /examples/vue3/src/main.ts: -------------------------------------------------------------------------------- 1 | import App from './App.vue' 2 | import { createApp } from 'vue' 3 | 4 | createApp(App).mount('#app') 5 | -------------------------------------------------------------------------------- /packages/vue/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Editor } from './editor.vue' 2 | export { default as Viewer } from './viewer.vue' 3 | -------------------------------------------------------------------------------- /examples/react-nextjs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natanfelles/bytemd/main/examples/react-nextjs/public/favicon.ico -------------------------------------------------------------------------------- /examples/svelte/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | -------------------------------------------------------------------------------- /packages/vue-next/src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Editor } from './editor.vue' 2 | export { default as Viewer } from './viewer.vue' 3 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "ブロック 公式", 3 | "blockText": "公式", 4 | "inline": "インライン公式", 5 | "inlineText": "公式" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/zh_Hans.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "块级公式", 3 | "blockText": "公式", 4 | "inline": "行内公式", 5 | "inlineText": "公式" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/zh_Hant.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "塊級公式", 3 | "blockText": "公式", 4 | "inline": "內聯公式", 5 | "inlineText": "公式" 6 | } 7 | -------------------------------------------------------------------------------- /playground/src/index.ts: -------------------------------------------------------------------------------- 1 | import App from './app.svelte' 2 | 3 | const app = new App({ 4 | target: document.body, 5 | }) 6 | 7 | export default app 8 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "صيغة الكتلة", 3 | "blockText": "صيغة", 4 | "inline": "صيغة مضمنة", 5 | "inlineText": "صيغة" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Blok rumus", 3 | "blockText": "rumus", 4 | "inline": "Rumus sebaris", 5 | "inlineText": "rumus" 6 | } 7 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- 1 | /* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css */ 2 | :root { 3 | --c-brand: #0969da; 4 | } 5 | -------------------------------------------------------------------------------- /examples/react-nextjs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Block formula", 3 | "blockText": "formula", 4 | "inline": "Inline formula", 5 | "inlineText": "formula" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Formule en bloc", 3 | "blockText": "formule", 4 | "inline": "Formule en ligne", 5 | "inlineText": "formule" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Blok formülü", 3 | "blockText": "formül", 4 | "inline": "Satır içi formülü", 5 | "inlineText": "formül" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/ca.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Fórmula en bloc", 3 | "blockText": "fórmula", 4 | "inline": "Fórmula en el cos", 5 | "inlineText": "fórmula" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Fórmula en bloque", 3 | "blockText": "fórmula", 4 | "inline": "Fórmula en renglón", 5 | "inlineText": "fórmula" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/nb_NO.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Blokkformel", 3 | "blockText": "formel", 4 | "inline": "Formel på samme linje", 5 | "inlineText": "formel" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/pt_BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Bloco de Fórmula", 3 | "blockText": "fórmula", 4 | "inline": "Fórmula em linha", 5 | "inlineText": "fórmula" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Блочная формула", 3 | "blockText": "формула", 4 | "inline": "Встроенная формула", 5 | "inlineText": "формула" 6 | } 7 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "useWorkspaces": true, 4 | "version": "1.22.0", 5 | "registry": "https://registry.npmjs.org" 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/locales/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "block": "Wzór eksponowany", 3 | "blockText": "wzór eksponowany", 4 | "inline": "Wzór w tekście", 5 | "inlineText": "wzór w tekście" 6 | } 7 | -------------------------------------------------------------------------------- /examples/vue/src/main.ts: -------------------------------------------------------------------------------- 1 | import App from './App.vue' 2 | import Vue from 'vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: (h) => h(App), 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /packages/bytemd/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" } 5 | } 6 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/zh_Hans.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "删除线", 3 | "strikeText": "文本", 4 | "table": "表格", 5 | "tableHeading": "标题", 6 | "task": "任务列表", 7 | "taskText": "待办事项" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/zh_Hant.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "刪除線", 3 | "strikeText": "文本", 4 | "table": "表格", 5 | "tableHeading": "標題", 6 | "task": "任務列表", 7 | "taskText": "待辦事項" 8 | } 9 | -------------------------------------------------------------------------------- /packages/react/src/index.ts: -------------------------------------------------------------------------------- 1 | export { Editor } from './editor' 2 | export type { EditorProps } from './editor' 3 | export { Viewer } from './viewer' 4 | export type { ViewerProps } from './viewer' 5 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "توسيط خط", 3 | "strikeText": "نص", 4 | "table": "جدول", 5 | "tableHeading": "عنوان", 6 | "task": "قائمة المهام", 7 | "taskText": "مهام" 8 | } 9 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.js: -------------------------------------------------------------------------------- 1 | // https://vitepress.vuejs.org/guide/theming.html#customizing-css 2 | 3 | import DefaultTheme from 'vitepress/theme' 4 | import './custom.css' 5 | 6 | export default DefaultTheme 7 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Strikethrough", 3 | "strikeText": "text", 4 | "table": "Table", 5 | "tableHeading": "Heading", 6 | "task": "Task list", 7 | "taskText": "todo" 8 | } 9 | -------------------------------------------------------------------------------- /examples/nuxt3/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import { defineNuxtConfig } from 'nuxt' 2 | 3 | // https://v3.nuxtjs.org/api/configuration/nuxt.config 4 | export default defineNuxtConfig({ 5 | css: ['bytemd/dist/index.css'], 6 | }) 7 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Tachado", 3 | "strikeText": "texto", 4 | "table": "Tabla", 5 | "tableHeading": "Título", 6 | "task": "Lista de tareas", 7 | "taskText": "pendientes" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Barré", 3 | "strikeText": "texte", 4 | "table": "Tableau", 5 | "tableHeading": "Titre", 6 | "task": "Liste de tâches", 7 | "taskText": "à-faire" 8 | } 9 | -------------------------------------------------------------------------------- /examples/vue3/tsconfig.vite-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.node.json", 3 | "include": ["vite.config.*"], 4 | "compilerOptions": { 5 | "composite": true, 6 | "types": ["node"] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Coret Kata", 3 | "strikeText": "teks", 4 | "table": "Tabel", 5 | "tableHeading": "Tajuk", 6 | "task": "Daftar tugas", 7 | "taskText": "untuk-dilakukan" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "przekreślenie", 3 | "strikeText": "tekst", 4 | "table": "tabela", 5 | "tableHeading": "nagłówek", 6 | "task": "lista zadań", 7 | "taskText": "zadanie" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Зачеркнутый", 3 | "strikeText": "текст", 4 | "table": "Таблица", 5 | "tableHeading": "Заголовок", 6 | "task": "Список задач", 7 | "taskText": "задача" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Üstü çizili", 3 | "strikeText": "metin", 4 | "table": "Tablo", 5 | "tableHeading": "Başlık", 6 | "task": "Görev listesi", 7 | "taskText": "yapılacak" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/ca.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Ratllat", 3 | "strikeText": "text", 4 | "table": "Taula", 5 | "tableHeading": "Encapçalament", 6 | "task": "Llista de tasques", 7 | "taskText": "pendents" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/nb_NO.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Gjennomstrek", 3 | "strikeText": "tekst", 4 | "table": "Tabell", 5 | "tableHeading": "Overskrift", 6 | "task": "Gjøremålsliste", 7 | "taskText": "gjøremål" 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Durchstreichen", 3 | "strikeText": "Text", 4 | "table": "Tabelle", 5 | "tableHeading": "Überschrift", 6 | "task": "Aufgabenliste", 7 | "taskText": "Noch zu tun" 8 | } 9 | -------------------------------------------------------------------------------- /packages/bytemd/src/index.ts: -------------------------------------------------------------------------------- 1 | import './index.scss' 2 | 3 | export * from './types' 4 | export { default as Editor } from './editor.svelte' 5 | export { default as Viewer } from './viewer.svelte' 6 | export { getProcessor } from './utils' 7 | -------------------------------------------------------------------------------- /packages/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-gfm/locales/pt_BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "strike": "Riscado", 3 | "strikeText": "texto riscado", 4 | "table": "Tabela", 5 | "tableHeading": "Cabeçalho da tabela", 6 | "task": "Tarefa", 7 | "taskText": "texto da tarefa" 8 | } 9 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/vue-next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-breaks/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-gemoji/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-gfm/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /examples/react-nextjs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /packages/plugin-frontmatter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-highlight/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-math-ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-medium-zoom/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-highlight-ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [{ "path": "../bytemd" }] 6 | } 7 | -------------------------------------------------------------------------------- /packages/plugin-breaks/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { BytemdPlugin } from 'bytemd' 2 | import remarkBreaks from 'remark-breaks' 3 | 4 | export default function breaks(): BytemdPlugin { 5 | return { 6 | remark: (processor) => processor.use(remarkBreaks), 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/plugin-gemoji/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { BytemdPlugin } from 'bytemd' 2 | import remarkGemoji from 'remark-gemoji' 3 | 4 | export default function gemoji(): BytemdPlugin { 5 | return { 6 | remark: (processor) => processor.use(remarkGemoji), 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /examples/react/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom' 6 | -------------------------------------------------------------------------------- /examples/react-nextjs/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '../styles/globals.css' 2 | import 'bytemd/dist/index.css' 3 | import type { AppProps } from 'next/app' 4 | 5 | function MyApp({ Component, pageProps }: AppProps) { 6 | return 7 | } 8 | 9 | export default MyApp 10 | -------------------------------------------------------------------------------- /packages/bytemd/locales/zgh.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "ⴰⵎⵉⵔⵉⵡ", 3 | "boldText": "ⴰⴹⵕⵉⵚ ⵉⵔⵉⵡⵏ", 4 | "closeHelp": "ⵇⵇⵏ ⵜⵉⵡⵉⵙⵉ", 5 | "closeToc": "ⵇⵇⵏ ⵜⴰⵍⴳⴰⵎⵜ ⵏ ⵓⴽⵜⵜⵓⵔ", 6 | "code": "ⵉⵏⵉⴳⵍ", 7 | "codeBlock": "ⴰⴱⵍⵓⴽ ⵏ ⵉⵏⵉⴳⵍ", 8 | "codeLang": "ⵜⵓⵜⵍⴰⵢⵜ", 9 | "codeText": "ⵉⵏⵉⴳⵍ" 10 | } 11 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /examples/vue/src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue' 2 | 3 | declare global { 4 | namespace JSX { 5 | interface Element extends VNode {} 6 | interface ElementClass extends Vue {} 7 | interface IntrinsicElements { 8 | [elem: string]: any 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/bytemd/tsconfig.svelte.json: -------------------------------------------------------------------------------- 1 | // for svelte entry 2 | { 3 | "extends": "../../tsconfig-base.json", 4 | "include": ["src"], 5 | "compilerOptions": { 6 | "rootDir": "src", 7 | "outDir": "svelte", 8 | "composite": false, 9 | "emitDeclarationOnly": false 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "private": true, 4 | "scripts": { 5 | "build": "vitepress build .", 6 | "dev": "vitepress dev .", 7 | "serve": "vitepress serve ." 8 | }, 9 | "dependencies": { 10 | "vitepress": "1.0.0-alpha.1", 11 | "vue": "^3.2.37" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/zh_Hans.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "类图", 3 | "er": "关系图", 4 | "flowchart": "流程图", 5 | "gantt": "甘特图", 6 | "mermaid": "Mermaid图表", 7 | "mindmap": "思维导图", 8 | "pie": "饼状图", 9 | "sequence": "时序图", 10 | "state": "状态图", 11 | "timeline": "时间轴", 12 | "uj": "旅程图" 13 | } 14 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: 3 | push: 4 | pull_request: 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: actions/setup-node@v3 11 | - run: corepack enable 12 | - run: pnpm install 13 | - run: pnpm test 14 | -------------------------------------------------------------------------------- /.github/workflows/style.yml: -------------------------------------------------------------------------------- 1 | name: style 2 | on: 3 | push: 4 | pull_request: 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v3 10 | - uses: actions/setup-node@v3 11 | - run: corepack enable 12 | - run: pnpm install 13 | - run: pnpm style 14 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | # https://docs.netlify.com/configure-builds/file-based-configuration/#configuration-details 2 | # https://answers.netlify.com/t/using-pnpm-and-pnpm-workspaces/2759 3 | [build.environment] 4 | NPM_FLAGS="--prefix=/dev/null" 5 | 6 | [build] 7 | publish = "docs/.vitepress/dist" 8 | command = "bash scripts/deploy.sh" 9 | -------------------------------------------------------------------------------- /examples/react/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import App from './App' 2 | import { render, screen } from '@testing-library/react' 3 | import React from 'react' 4 | 5 | test('renders learn react link', () => { 6 | render() 7 | const linkElement = screen.getByText(/learn react/i) 8 | expect(linkElement).toBeInTheDocument() 9 | }) 10 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "مخططات الفئات", 3 | "er": "مخطط علاقات العناصر", 4 | "flowchart": "خارطة سير المعلومات", 5 | "gantt": "خارطة جانت", 6 | "mermaid": "مخطط ميرميد", 7 | "pie": "مخطط دائري", 8 | "sequence": "مخطط متسلسل", 9 | "state": "مخطط حالة الآلة", 10 | "uj": "مخطط رحلة المستخدم" 11 | } 12 | -------------------------------------------------------------------------------- /examples/svelte/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/svelte/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/nb_NO.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Klassediagram", 3 | "er": "Enhetsrelaskonsdiagram", 4 | "flowchart": "Flytskjema", 5 | "gantt": "Gantt-skjema", 6 | "mermaid": "Mermaid-diagrammer", 7 | "pie": "Kakediagram", 8 | "sequence": "Sekvensdiagram", 9 | "state": "Tilstandsdiagram", 10 | "uj": "Brukerreisediagram" 11 | } 12 | -------------------------------------------------------------------------------- /examples/svelte/src/app.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // See https://kit.svelte.dev/docs/types#app 4 | // for information about these interfaces 5 | // and what to do when importing types 6 | declare namespace App { 7 | // interface Locals {} 8 | // interface Platform {} 9 | // interface Session {} 10 | // interface Stuff {} 11 | } 12 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Diagram kelas", 3 | "er": "Diagram hubungan entitas", 4 | "flowchart": "Bagan alur", 5 | "gantt": "Bagan Gantt", 6 | "mermaid": "Diagram Mermaid", 7 | "pie": "Bagan pai", 8 | "sequence": "Diagram urutan", 9 | "state": "Diagram kondisi", 10 | "uj": "Diagram penjelajahan pengguna" 11 | } 12 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | npm i -g pnpm 4 | pnpm install 5 | 6 | # packages 7 | pnpm build 8 | 9 | # docs 10 | cd docs 11 | npm install # not in workspace because of Vue 2/3 version 12 | pnpm build 13 | 14 | # playground 15 | cd .. 16 | pnpm --filter playground build 17 | 18 | # move assets 19 | mv playground/dist docs/.vitepress/dist/playground 20 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Diagram klas", 3 | "er": "Diagram relacji encji", 4 | "flowchart": "Schemat blokowy", 5 | "gantt": "Wykres Gantta", 6 | "mermaid": "Diagramy syren", 7 | "pie": "Wykres kołowy", 8 | "sequence": "Diagram interakcji", 9 | "state": "Diagram stanu", 10 | "uj": "Diagram podróży użytkownika" 11 | } 12 | -------------------------------------------------------------------------------- /examples/vue3/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.web.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | } 9 | }, 10 | 11 | "references": [ 12 | { 13 | "path": "./tsconfig.vite-config.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Klassendiagramm", 3 | "er": "Entity-Relationship-Diagramm", 4 | "flowchart": "Flussdiagramm", 5 | "gantt": "Gantt-Diagramm", 6 | "mermaid": "Mermaid-Diagramme", 7 | "pie": "Kreisdiagramm", 8 | "sequence": "Sequenzdiagramm", 9 | "state": "Zustandsdiagramm", 10 | "uj": "User Journey-Diagramm" 11 | } 12 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Sınıf diyagramı", 3 | "er": "Varlık ilişki diyagramı", 4 | "flowchart": "Akış diyagramı", 5 | "gantt": "Gantt şeması", 6 | "mermaid": "Mermaid diyagramları", 7 | "pie": "Pasta grafiği", 8 | "sequence": "Sıra diyagramı", 9 | "state": "Durum diyagramı", 10 | "uj": "Kullanıcı yolculuk diyagramı" 11 | } 12 | -------------------------------------------------------------------------------- /examples/vue3/vite.config.ts: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue' 2 | import { fileURLToPath, URL } from 'url' 3 | import { defineConfig } from 'vite' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue()], 8 | resolve: { 9 | alias: { 10 | '@': fileURLToPath(new URL('./src', import.meta.url)), 11 | }, 12 | }, 13 | }) 14 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/pt_BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Diagrama de classes", 3 | "er": "Entidade Relacionada", 4 | "flowchart": "Fluxograma", 5 | "gantt": "Gráfico Gantt", 6 | "mermaid": "Diagrama Mermaid", 7 | "pie": "Gráfico de Pizza", 8 | "sequence": "Diagrama de sequência", 9 | "state": "Gráfico de fluxo de estado", 10 | "uj": "Diagrama de casos de uso" 11 | } 12 | -------------------------------------------------------------------------------- /playground/vite.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { svelte } from '@sveltejs/vite-plugin-svelte' 3 | import sveltePreprocess from 'svelte-preprocess' 4 | import { defineConfig } from 'vite' 5 | 6 | export default defineConfig({ 7 | base: '/playground/', 8 | plugins: [ 9 | svelte({ 10 | preprocess: [sveltePreprocess({ typescript: true })], 11 | }), 12 | ], 13 | }) 14 | -------------------------------------------------------------------------------- /examples/react-nextjs/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /examples/vue/README.md: -------------------------------------------------------------------------------- 1 | # example-vue 2 | 3 | ## Project setup 4 | 5 | ``` 6 | yarn install 7 | ``` 8 | 9 | ### Compiles and hot-reloads for development 10 | 11 | ``` 12 | yarn serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | 17 | ``` 18 | yarn build 19 | ``` 20 | 21 | ### Customize configuration 22 | 23 | See [Configuration Reference](https://cli.vuejs.org/config/). 24 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | fetch-depth: 0 13 | - uses: actions/setup-node@v3 14 | - run: npx changelogithub 15 | env: 16 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 17 | -------------------------------------------------------------------------------- /tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "skipLibCheck": true, 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | "jsx": "react", 7 | "strict": true, 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "resolveJsonModule": true, 11 | "composite": true, 12 | "emitDeclarationOnly": true 13 | }, 14 | "exclude": ["**/__tests__"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/plugin-highlight-ssr/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { BytemdPlugin } from 'bytemd' 2 | import rehypeHighlight, { Options } from 'rehype-highlight' 3 | 4 | export default function highlightSsr({ 5 | ignoreMissing = true, 6 | ...rest 7 | }: Options = {}): BytemdPlugin { 8 | return { 9 | rehype: (processor) => 10 | processor.use(rehypeHighlight, { ignoreMissing, ...rest }), 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/ca.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Diagrama de classes", 3 | "er": "Diagrama entitat-relació", 4 | "flowchart": "Diagrama de flux", 5 | "gantt": "Diagrama de Gantt", 6 | "mermaid": "Diagrames del Mermaid", 7 | "pie": "Diagrama sectorial", 8 | "sequence": "Diagrama de seqüències", 9 | "state": "Diagrama d’estats", 10 | "uj": "Diagrama de recorregut d’usuari" 11 | } 12 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Diagrama de clases", 3 | "er": "Diagrama de entidad-relación", 4 | "flowchart": "Diagrama de flujo", 5 | "gantt": "Diagrama de Gantt", 6 | "mermaid": "Diagramas de Mermaid", 7 | "pie": "Gráfico sectorial", 8 | "sequence": "Diagrama de secuencia", 9 | "state": "Diagrama de estado", 10 | "uj": "Diagrama de trayecto de usuario" 11 | } 12 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Диаграмма классов", 3 | "er": "Диаграмма отношений сущностей", 4 | "flowchart": "Блок-схема", 5 | "gantt": "Диаграмма Ганта", 6 | "mermaid": "Диаграммы Mermaid", 7 | "pie": "Круговая диаграмма", 8 | "sequence": "Диаграмма последовательностей", 9 | "state": "Диаграмма состояния", 10 | "uj": "Диаграмма пользовательского опыта" 11 | } 12 | -------------------------------------------------------------------------------- /examples/vue3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Diagramme de classes", 3 | "er": "Diagramme de relation entre entités", 4 | "flowchart": "Organigramme", 5 | "gantt": "Diagramme de Gantt", 6 | "mermaid": "Diagrammes Mermaid", 7 | "pie": "Graphique circulaire", 8 | "sequence": "Diagramme de séquences", 9 | "state": "Diagramme d'état", 10 | "uj": "Diagramme de parcours utilisateur" 11 | } 12 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "class": "Class diagram", 3 | "er": "Entity relationship diagram", 4 | "flowchart": "Flow chart", 5 | "gantt": "Gantt chart", 6 | "mermaid": "Mermaid diagrams", 7 | "mindmap": "Mindmaps", 8 | "pie": "Pie chart", 9 | "sequence": "Sequence diagram", 10 | "state": "State diagram", 11 | "timeline": "Timeline", 12 | "uj": "User journey diagram" 13 | } 14 | -------------------------------------------------------------------------------- /examples/react-nextjs/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | max-width: 1200px; 8 | margin: 0 auto; 9 | } 10 | 11 | a { 12 | color: inherit; 13 | text-decoration: none; 14 | } 15 | 16 | * { 17 | box-sizing: border-box; 18 | } 19 | -------------------------------------------------------------------------------- /examples/react/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/svelte/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import preprocess from 'svelte-preprocess'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | 10 | kit: { 11 | adapter: adapter() 12 | } 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /examples/nuxt3/app.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /examples/nuxt3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/example-nuxt3", 3 | "scripts": { 4 | "build": "nuxt build", 5 | "dev": "nuxt dev", 6 | "generate": "nuxt generate", 7 | "preview": "nuxt preview" 8 | }, 9 | "devDependencies": { 10 | "nuxt": "3.0.0-rc.4" 11 | }, 12 | "dependencies": { 13 | "@bytemd/plugin-gfm": "latest", 14 | "@bytemd/vue-next": "latest", 15 | "bytemd": "latest" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/react/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /examples/vue3/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Vuex Store files. Vuex Store option is implemented in the Nuxt.js framework. 6 | 7 | Creating a file in this directory automatically activates the option in the framework. 8 | 9 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). 10 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/src/icons.ts: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT, generated by scripts/icon.ts 2 | export const icons = { 3 | ChartGraph: 4 | '', 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/bundlewatch.yml: -------------------------------------------------------------------------------- 1 | name: bundlewatch 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: actions/setup-node@v3 13 | - run: corepack enable 14 | - run: pnpm install 15 | - run: pnpm build 16 | - run: npx bundlewatch 17 | env: 18 | BUNDLEWATCH_GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' 19 | -------------------------------------------------------------------------------- /docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { defineConfig } from 'vitepress' 3 | 4 | export default defineConfig({ 5 | title: 'ByteMD', 6 | description: 'Hackable Markdown Editor and Viewer', 7 | themeConfig: { 8 | nav: [ 9 | { 10 | text: 'Playground', 11 | link: 'https://bytemd.js.org/playground/', 12 | }, 13 | { 14 | text: 'GitHub', 15 | link: 'https://github.com/bytedance/bytemd', 16 | }, 17 | ], 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /examples/react/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals' 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry) 7 | getFID(onPerfEntry) 8 | getFCP(onPerfEntry) 9 | getLCP(onPerfEntry) 10 | getTTFB(onPerfEntry) 11 | }) 12 | } 13 | } 14 | 15 | export default reportWebVitals 16 | -------------------------------------------------------------------------------- /examples/svelte/src/routes/index.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | { 14 | value = e.detail.value 15 | }} 16 | {plugins} 17 | /> 18 |
19 | 20 | 26 | -------------------------------------------------------------------------------- /vitest.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { sveltePreprocessor } from './scripts/utils.mjs' 3 | import { svelte } from '@sveltejs/vite-plugin-svelte' 4 | import { defineConfig } from 'vitest/config' 5 | 6 | export default defineConfig({ 7 | test: { 8 | include: ['packages/bytemd/**/*.test.ts'], 9 | globals: true, 10 | environment: 'jsdom', 11 | setupFiles: 'packages/bytemd/test/setup.ts', 12 | }, 13 | plugins: [ 14 | svelte({ 15 | preprocess: [sveltePreprocessor], 16 | }), 17 | ], 18 | }) 19 | -------------------------------------------------------------------------------- /packages/plugin-breaks/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-breaks 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-breaks.svg)](https://npm.im/@bytemd/plugin-breaks) 4 | 5 | ByteMD plugin to support breaks 6 | 7 | ## Usage 8 | 9 | ```js 10 | import breaks from '@bytemd/plugin-breaks' 11 | import { Editor } from 'bytemd' 12 | 13 | new Editor({ 14 | target: document.body, 15 | props: { 16 | plugins: [ 17 | breaks(), 18 | // ... other plugins 19 | ], 20 | }, 21 | }) 22 | ``` 23 | 24 | ## License 25 | 26 | MIT 27 | -------------------------------------------------------------------------------- /packages/plugin-gemoji/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-gemoji 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-gemoji.svg)](https://npm.im/@bytemd/plugin-gemoji) 4 | 5 | ByteMD plugin to support Gemoji shortcodes 6 | 7 | ## Usage 8 | 9 | ```js 10 | import gemoji from '@bytemd/plugin-gemoji' 11 | import { Editor } from 'bytemd' 12 | 13 | new Editor({ 14 | target: document.body, 15 | props: { 16 | plugins: [ 17 | gemoji(), 18 | // ... other plugins 19 | ], 20 | }, 21 | }) 22 | ``` 23 | 24 | ## License 25 | 26 | MIT 27 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-mermaid 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-mermaid.svg)](https://npm.im/@bytemd/plugin-mermaid) 4 | 5 | ByteMD plugin to support Mermaid diagram 6 | 7 | ## Usage 8 | 9 | ```js 10 | import mermaid from '@bytemd/plugin-mermaid' 11 | import { Editor } from 'bytemd' 12 | 13 | new Editor({ 14 | target: document.body, 15 | props: { 16 | plugins: [ 17 | mermaid(), 18 | // ... other plugins 19 | ], 20 | }, 21 | }) 22 | ``` 23 | 24 | ## License 25 | 26 | MIT 27 | -------------------------------------------------------------------------------- /examples/react-nextjs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /packages/plugin-math/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-math 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-math.svg)](https://npm.im/@bytemd/plugin-math) 4 | 5 | ByteMD plugin to support math formula 6 | 7 | ## Usage 8 | 9 | ```js 10 | import math from '@bytemd/plugin-math' 11 | import { Editor } from 'bytemd' 12 | import 'katex/dist/katex.css' 13 | 14 | new Editor({ 15 | target: document.body, 16 | props: { 17 | plugins: [ 18 | math(), 19 | // ... other plugins 20 | ], 21 | }, 22 | }) 23 | ``` 24 | 25 | ## License 26 | 27 | MIT 28 | -------------------------------------------------------------------------------- /packages/plugin-gfm/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-gfm 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-gfm.svg)](https://npm.im/@bytemd/plugin-gfm) 4 | 5 | ByteMD plugin to support GFM (autolink literals, strikethrough, tables, tasklists) 6 | 7 | ## Usage 8 | 9 | ```js 10 | import gfm from '@bytemd/plugin-gfm' 11 | import { Editor } from 'bytemd' 12 | 13 | new Editor({ 14 | target: document.body, 15 | props: { 16 | plugins: [ 17 | gfm(), 18 | // ... other plugins 19 | ], 20 | }, 21 | }) 22 | ``` 23 | 24 | ## License 25 | 26 | MIT 27 | -------------------------------------------------------------------------------- /packages/plugin-frontmatter/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-frontmatter 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-frontmatter.svg)](https://npm.im/@bytemd/plugin-frontmatter) 4 | 5 | ByteMD plugin to parse frontmatter 6 | 7 | ## Usage 8 | 9 | ```js 10 | import frontmatter from '@bytemd/plugin-frontmatter' 11 | import { Editor } from 'bytemd' 12 | 13 | new Editor({ 14 | target: document.body, 15 | props: { 16 | plugins: [ 17 | frontmatter(), 18 | // ... other plugins 19 | ], 20 | }, 21 | }) 22 | ``` 23 | 24 | ## License 25 | 26 | MIT 27 | -------------------------------------------------------------------------------- /packages/plugin-medium-zoom/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-medium-zoom 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-medium-zoom.svg)](https://npm.im/@bytemd/plugin-medium-zoom) 4 | 5 | ByteMD plugin to zoom images like Medium 6 | 7 | ## Usage 8 | 9 | ```js 10 | import mediumZoom from '@bytemd/plugin-medium-zoom' 11 | import { Editor } from 'bytemd' 12 | 13 | new Editor({ 14 | target: document.body, 15 | props: { 16 | plugins: [ 17 | mediumZoom(), 18 | // ... other plugins 19 | ], 20 | }, 21 | }) 22 | ``` 23 | 24 | ## License 25 | 26 | MIT 27 | -------------------------------------------------------------------------------- /examples/react/src/index.tsx: -------------------------------------------------------------------------------- 1 | import App from './App' 2 | import './index.css' 3 | import reportWebVitals from './reportWebVitals' 4 | import React from 'react' 5 | import ReactDOM from 'react-dom' 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ) 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals() 18 | -------------------------------------------------------------------------------- /examples/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/example-vue", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "vue-cli-service build", 7 | "serve": "vue-cli-service serve" 8 | }, 9 | "dependencies": { 10 | "@bytemd/plugin-gfm": "latest", 11 | "@bytemd/vue": "latest", 12 | "bytemd": "latest", 13 | "vue": "^2.6.14" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-typescript": "~5.0.0", 17 | "@vue/cli-service": "~5.0.0", 18 | "typescript": "~4.5.5", 19 | "vue-template-compiler": "^2.6.14" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-math-ssr/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-math-ssr 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-math-ssr.svg)](https://npm.im/@bytemd/plugin-math-ssr) 4 | 5 | ByteMD plugin to support math formula (SSR compatible) 6 | 7 | ## Usage 8 | 9 | ```js 10 | import math from '@bytemd/plugin-math-ssr' 11 | import { Editor } from 'bytemd' 12 | import 'katex/dist/katex.css' 13 | 14 | new Editor({ 15 | target: document.body, 16 | props: { 17 | plugins: [ 18 | math(), 19 | // ... other plugins 20 | ], 21 | }, 22 | }) 23 | ``` 24 | 25 | ## License 26 | 27 | MIT 28 | -------------------------------------------------------------------------------- /examples/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "lib": ["ESNext", "ESNext.AsyncIterable", "DOM"], 7 | "esModuleInterop": true, 8 | "allowJs": true, 9 | "sourceMap": true, 10 | "strict": true, 11 | "noEmit": true, 12 | "experimentalDecorators": true, 13 | "baseUrl": ".", 14 | "paths": { 15 | "~/*": ["./*"], 16 | "@/*": ["./*"] 17 | }, 18 | "types": ["@nuxt/types", "@types/node"] 19 | }, 20 | "exclude": ["node_modules", ".nuxt", "dist"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/plugin-highlight/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-highlight 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-highlight.svg)](https://npm.im/@bytemd/plugin-highlight) 4 | 5 | ByteMD plugin to highlight code blocks 6 | 7 | ## Usage 8 | 9 | ```js 10 | import highlight from '@bytemd/plugin-highlight' 11 | import { Editor } from 'bytemd' 12 | import 'highlight.js/styles/default.css' 13 | 14 | new Editor({ 15 | target: document.body, 16 | props: { 17 | plugins: [ 18 | highlight(), 19 | // ... other plugins 20 | ], 21 | }, 22 | }) 23 | ``` 24 | 25 | ## License 26 | 27 | MIT 28 | -------------------------------------------------------------------------------- /examples/react-nextjs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /examples/react/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/pages/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 25 | 26 | 32 | -------------------------------------------------------------------------------- /packages/plugin-highlight-ssr/README.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-highlight-ssr 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-highlight-ssr.svg)](https://npm.im/@bytemd/plugin-highlight-ssr) 4 | 5 | ByteMD plugin to highlight code blocks (SSR compatible) 6 | 7 | ## Usage 8 | 9 | ```js 10 | import highlight from '@bytemd/plugin-highlight-ssr' 11 | import { Editor } from 'bytemd' 12 | import 'highlight.js/styles/default.css' 13 | 14 | new Editor({ 15 | target: document.body, 16 | props: { 17 | plugins: [ 18 | highlight(), 19 | // ... other plugins 20 | ], 21 | }, 22 | }) 23 | ``` 24 | 25 | ## License 26 | 27 | MIT 28 | -------------------------------------------------------------------------------- /examples/vue3/src/App.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | 22 | 30 | -------------------------------------------------------------------------------- /examples/vue3/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/example-vue3", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "build": "vue-tsc --noEmit && vite build", 6 | "dev": "vite", 7 | "preview": "vite preview --port 5050", 8 | "typecheck": "vue-tsc --noEmit" 9 | }, 10 | "dependencies": { 11 | "@bytemd/plugin-gfm": "latest", 12 | "@bytemd/vue-next": "latest", 13 | "bytemd": "latest", 14 | "vue": "^3.2.31" 15 | }, 16 | "devDependencies": { 17 | "@types/node": "^16.11.25", 18 | "@vitejs/plugin-vue": "^2.2.2", 19 | "@vue/tsconfig": "^0.1.3", 20 | "typescript": "~4.5.5", 21 | "vite": "^2.8.4", 22 | "vue-tsc": "^0.31.4" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/plugin-template.md: -------------------------------------------------------------------------------- 1 | # @bytemd/plugin-{{name}} 2 | 3 | [![npm](https://img.shields.io/npm/v/@bytemd/plugin-{{name}}.svg)](https://npm.im/@bytemd/plugin-{{name}}) 4 | 5 | {{{desc}}} 6 | 7 | ## Usage 8 | 9 | ```js 10 | {{{header}}} 11 | import { Editor } from 'bytemd' 12 | import {{importedName}} from '@bytemd/plugin-{{name}}' 13 | 14 | new Editor({ 15 | target: document.body, 16 | props: { 17 | plugins: [ 18 | {{importedName}}(), 19 | // ... other plugins 20 | ], 21 | }, 22 | }) 23 | ``` 24 | 25 | {{#options}}### Options 26 | 27 | {{{options}}} 28 | {{/options}} 29 | {{#example}}## Example 30 | 31 | {{{example}}} 32 | {{/example}} 33 | ## License 34 | 35 | MIT 36 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "packages/bytemd" }, 5 | { "path": "packages/plugin-breaks" }, 6 | { "path": "packages/plugin-frontmatter" }, 7 | { "path": "packages/plugin-gemoji" }, 8 | { "path": "packages/plugin-gfm" }, 9 | { "path": "packages/plugin-highlight" }, 10 | { "path": "packages/plugin-highlight-ssr" }, 11 | { "path": "packages/plugin-math" }, 12 | { "path": "packages/plugin-math-ssr" }, 13 | { "path": "packages/plugin-medium-zoom" }, 14 | { "path": "packages/plugin-mermaid" }, 15 | { "path": "packages/react" }, 16 | { "path": "packages/vue" }, 17 | { "path": "packages/vue-next" } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/example-vue-nuxtjs", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "nuxt build", 7 | "dev": "nuxt", 8 | "generate": "nuxt generate", 9 | "start": "nuxt start" 10 | }, 11 | "dependencies": { 12 | "@bytemd/plugin-gfm": "latest", 13 | "@bytemd/vue": "latest", 14 | "bytemd": "latest", 15 | "core-js": "^3.19.3", 16 | "nuxt": "^2.15.8", 17 | "vue": "^2.6.14", 18 | "vue-server-renderer": "^2.6.14", 19 | "vue-template-compiler": "^2.6.14", 20 | "webpack": "^4.46.0" 21 | }, 22 | "devDependencies": { 23 | "@nuxt/types": "^2.15.8", 24 | "@nuxt/typescript-build": "^2.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/react-nextjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/example-react-nextjs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "next build", 7 | "dev": "next dev", 8 | "lint": "next lint", 9 | "start": "next start" 10 | }, 11 | "dependencies": { 12 | "@bytemd/plugin-gfm": "latest", 13 | "@bytemd/react": "latest", 14 | "bytemd": "latest", 15 | "next": "12.1.1", 16 | "react": "17.0.2", 17 | "react-dom": "17.0.2" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "17.0.23", 21 | "@types/react": "17.0.43", 22 | "@types/react-dom": "17.0.14", 23 | "eslint": "8.12.0", 24 | "eslint-config-next": "12.1.1", 25 | "typescript": "4.6.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /playground/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "include": ["src", "src/locales/*.json"], 4 | "compilerOptions": { "rootDir": "src", "outDir": "dist" }, 5 | "references": [ 6 | { "path": "../packages/bytemd" }, 7 | { "path": "../packages/plugin-breaks" }, 8 | { "path": "../packages/plugin-frontmatter" }, 9 | { "path": "../packages/plugin-gemoji" }, 10 | { "path": "../packages/plugin-gfm" }, 11 | { "path": "../packages/plugin-highlight" }, 12 | { "path": "../packages/plugin-highlight-ssr" }, 13 | { "path": "../packages/plugin-math" }, 14 | { "path": "../packages/plugin-math-ssr" }, 15 | { "path": "../packages/plugin-medium-zoom" }, 16 | { "path": "../packages/plugin-mermaid" } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /playground/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ByteMD Playground 8 | 12 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/svelte/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/example-svelte", 3 | "version": "0.0.1", 4 | "scripts": { 5 | "dev": "svelte-kit dev", 6 | "build": "svelte-kit build", 7 | "package": "svelte-kit package", 8 | "preview": "svelte-kit preview", 9 | "prepare": "svelte-kit sync", 10 | "check": "svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch" 12 | }, 13 | "devDependencies": { 14 | "@bytemd/plugin-gfm": "latest", 15 | "@sveltejs/adapter-auto": "next", 16 | "@sveltejs/kit": "next", 17 | "bytemd": "latest", 18 | "svelte": "^3.44.0", 19 | "svelte-check": "^2.7.1", 20 | "svelte-preprocess": "^4.10.6", 21 | "tslib": "^2.3.1", 22 | "typescript": "^4.7.2" 23 | }, 24 | "type": "module" 25 | } 26 | -------------------------------------------------------------------------------- /examples/nuxt3/README.md: -------------------------------------------------------------------------------- 1 | # Nuxt 3 Minimal Starter 2 | 3 | Look at the [nuxt 3 documentation](https://v3.nuxtjs.org) to learn more. 4 | 5 | ## Setup 6 | 7 | Make sure to install the dependencies: 8 | 9 | ```bash 10 | # yarn 11 | yarn install 12 | 13 | # npm 14 | npm install 15 | 16 | # pnpm 17 | pnpm install --shamefully-hoist 18 | ``` 19 | 20 | ## Development Server 21 | 22 | Start the development server on http://localhost:3000 23 | 24 | ```bash 25 | npm run dev 26 | ``` 27 | 28 | ## Production 29 | 30 | Build the application for production: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | Locally preview production build: 37 | 38 | ```bash 39 | npm run preview 40 | ``` 41 | 42 | Checkout the [deployment documentation](https://v3.nuxtjs.org/guide/deploy/presets) for more information. 43 | -------------------------------------------------------------------------------- /packages/plugin-math-ssr/src/index.ts: -------------------------------------------------------------------------------- 1 | import en from './locales/en.json' 2 | import { MathLocale, getMathActions } from './utils' 3 | import type { BytemdPlugin } from 'bytemd' 4 | import rehypeKatex, { Options } from 'rehype-katex' 5 | import remarkMath from 'remark-math' 6 | 7 | export interface BytemdPluginMathSsrOptions { 8 | locale?: Partial 9 | katexOptions?: Omit 10 | } 11 | 12 | export default function mathSsr({ 13 | locale: _locale, 14 | katexOptions, 15 | }: BytemdPluginMathSsrOptions = {}): BytemdPlugin { 16 | const locale = { ...en, ..._locale } 17 | return { 18 | remark: (processor) => processor.use(remarkMath), 19 | rehype: (processor) => processor.use(rehypeKatex, katexOptions), 20 | actions: getMathActions(locale), 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 27 | 28 | 38 | -------------------------------------------------------------------------------- /examples/vue/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "useDefineForClassFields": true, 14 | "sourceMap": true, 15 | "baseUrl": ".", 16 | "types": ["webpack-env"], 17 | "paths": { 18 | "@/*": ["src/*"] 19 | }, 20 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 21 | }, 22 | "include": [ 23 | "src/**/*.ts", 24 | "src/**/*.tsx", 25 | "src/**/*.vue", 26 | "tests/**/*.ts", 27 | "tests/**/*.tsx" 28 | ], 29 | "exclude": ["node_modules"] 30 | } 31 | -------------------------------------------------------------------------------- /packages/plugin-medium-zoom/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { BytemdPlugin } from 'bytemd' 2 | import type * as M from 'medium-zoom' 3 | 4 | export interface BytemdPluginMediumZoomOptions extends M.ZoomOptions { 5 | filter?: (img: HTMLDivElement) => boolean 6 | } 7 | 8 | export default function mediumZoom( 9 | options?: BytemdPluginMediumZoomOptions 10 | ): BytemdPlugin { 11 | let m: typeof M 12 | 13 | return { 14 | viewerEffect({ markdownBody }) { 15 | const imgs = [...markdownBody.querySelectorAll('img')].filter((e) => { 16 | return (options?.filter?.(e) ?? true) && !e.closest('a') 17 | }) 18 | if (imgs.length === 0) return 19 | ;(async () => { 20 | if (!m) { 21 | m = await import('medium-zoom') 22 | } 23 | m.default(imgs, options) 24 | })() 25 | }, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import './App.css' 2 | import pluginGfm from '@bytemd/plugin-gfm' 3 | import { Editor } from '@bytemd/react' 4 | import 'bytemd/dist/index.css' 5 | import React, { useMemo, useState } from 'react' 6 | 7 | function App() { 8 | const [value, setValue] = useState('') 9 | const plugins = useMemo(() => [pluginGfm()], []) 10 | 11 | return ( 12 |
13 | { 17 | // upload images here 18 | return [ 19 | { 20 | url: 'https://picsum.photos/200/300', 21 | }, 22 | ] 23 | }} 24 | onChange={(v) => { 25 | setValue(v) 26 | }} 27 | /> 28 |
29 | ) 30 | } 31 | 32 | export default App 33 | -------------------------------------------------------------------------------- /packages/bytemd/test/setup.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // https://github.com/jsdom/jsdom/issues/3002#issuecomment-655752934 4 | document.createRange = () => { 5 | const range = new Range() 6 | 7 | range.getBoundingClientRect = vi.fn() 8 | 9 | range.getClientRects = () => { 10 | return { 11 | item: () => null, 12 | length: 0, 13 | [Symbol.iterator]: vi.fn(), 14 | } 15 | } 16 | 17 | return range 18 | } 19 | 20 | // https://github.com/facebook/jest/issues/9983#issuecomment-626489847 21 | if (typeof TextEncoder === 'undefined') { 22 | global.TextEncoder = require('util').TextEncoder 23 | } 24 | 25 | // https://stackoverflow.com/a/65095454 26 | ;(global as any).ResizeObserver = class ResizeObserver { 27 | observe() { 28 | // do nothing 29 | } 30 | unobserve() { 31 | // do nothing 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/plugin-highlight/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { BytemdPlugin } from 'bytemd' 2 | import type H from 'highlight.js' 3 | 4 | export interface BytemdPluginHighlightOptions { 5 | init?(hljs: typeof H): void | Promise 6 | } 7 | 8 | export default function highlight({ 9 | init, 10 | }: BytemdPluginHighlightOptions = {}): BytemdPlugin { 11 | let hljs: typeof H 12 | return { 13 | viewerEffect({ markdownBody }) { 14 | ;(async () => { 15 | const els = markdownBody.querySelectorAll('pre>code') 16 | if (els.length === 0) return 17 | 18 | if (!hljs) { 19 | hljs = await import('highlight.js').then((m) => m.default) 20 | if (init) await init(hljs) 21 | } 22 | 23 | els.forEach((el) => { 24 | hljs.highlightElement(el) 25 | }) 26 | })() 27 | }, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/utils.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import fs from 'fs-extra' 3 | import path from 'path' 4 | import sveltePreprocess from 'svelte-preprocess' 5 | import { fileURLToPath } from 'url' 6 | 7 | // https://stackoverflow.com/a/50052194 8 | const __dirname = path.dirname(fileURLToPath(import.meta.url)) 9 | 10 | export const rootDir = path.resolve(__dirname, '..') 11 | 12 | export const packagesDir = path.join(rootDir, 'packages') 13 | export const packages = fs.readdirSync(packagesDir) 14 | 15 | export const sveltePreprocessor = sveltePreprocess({ 16 | typescript: true, 17 | // https://github.com/sveltejs/svelte/issues/189#issuecomment-586142198 18 | replace: [ 19 | [/(>)[\s]*([<{])/g, '$1$2'], 20 | [/({[/:][a-z]+})[\s]*([<{])/g, '$1$2'], 21 | [/({[#:][a-z]+ .+?})[\s]*([<{])/g, '$1$2'], 22 | [/([>}])[\s]+(<|{[/#:][a-z][^}]*})/g, '$1$2'], 23 | ], 24 | }) 25 | -------------------------------------------------------------------------------- /packages/plugin-math/src/utils/icons.ts: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT, generated by scripts/icon.ts 2 | export const icons = { 3 | Formula: 4 | '', 5 | Inline: 6 | '', 7 | Block: 8 | '', 9 | } 10 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground", 3 | "private": true, 4 | "dependencies": { 5 | "@bytemd/plugin-breaks": "workspace:*", 6 | "@bytemd/plugin-frontmatter": "workspace:*", 7 | "@bytemd/plugin-gemoji": "workspace:*", 8 | "@bytemd/plugin-gfm": "workspace:*", 9 | "@bytemd/plugin-highlight": "workspace:*", 10 | "@bytemd/plugin-highlight-ssr": "workspace:*", 11 | "@bytemd/plugin-math": "workspace:*", 12 | "@bytemd/plugin-math-ssr": "workspace:*", 13 | "@bytemd/plugin-medium-zoom": "workspace:*", 14 | "@bytemd/plugin-mermaid": "workspace:*", 15 | "@sveltejs/vite-plugin-svelte": "2.0.4", 16 | "bytemd": "workspace:*", 17 | "github-markdown-css": "^5.2.0", 18 | "highlight.js": "^11.7.0", 19 | "katex": "^0.16.4", 20 | "svelte-preprocess": "^5.0.3", 21 | "vite": "^4.2.1" 22 | }, 23 | "scripts": { 24 | "dev": "vite", 25 | "build": "vite build", 26 | "preview": "vite preview" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /packages/plugin-frontmatter/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { BytemdPlugin } from 'bytemd' 2 | import { load } from 'js-yaml' 3 | import remarkFrontmatter from 'remark-frontmatter' 4 | 5 | export interface BytemdPluginFrontmatterOptions { 6 | onError?(err: any): void 7 | } 8 | 9 | declare module 'vfile' { 10 | interface VFile { 11 | frontmatter: ReturnType 12 | } 13 | } 14 | 15 | export default function frontmatter({ 16 | onError, 17 | }: BytemdPluginFrontmatterOptions = {}): BytemdPlugin { 18 | return { 19 | remark: (processor) => 20 | // @ts-ignore 21 | processor.use(remarkFrontmatter).use(() => (tree, file) => { 22 | // TODO: arg types 23 | // console.log(tree); 24 | const fisrtNode = tree.children[0] 25 | if (fisrtNode?.type !== 'yaml') return 26 | 27 | try { 28 | file.frontmatter = load(fisrtNode.value) 29 | } catch (err) { 30 | onError?.(err) 31 | } 32 | }), 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/plugin-breaks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-breaks", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to support breaks", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-breaks" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "remark-breaks": "^3.0.2" 32 | }, 33 | "devDependencies": { 34 | "bytemd": "workspace:*" 35 | }, 36 | "peerDependencies": { 37 | "bytemd": "^1.5.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/react", 3 | "version": "1.22.0", 4 | "description": "Hackable Markdown Editor and Viewer", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/react" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "bytemd": "workspace:*" 32 | }, 33 | "devDependencies": { 34 | "@types/react": "^18.0.31", 35 | "react": "^18.2.0" 36 | }, 37 | "peerDependencies": { 38 | "react": "*" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-mermaid", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to support Mermaid diagram", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-mermaid" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "mermaid": "^10.0.2" 32 | }, 33 | "devDependencies": { 34 | "bytemd": "workspace:*" 35 | }, 36 | "peerDependencies": { 37 | "bytemd": "^1.5.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/plugin-gemoji/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-gemoji", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to support Gemoji shortcodes", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-gemoji" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "remark-gemoji": "^7.0.1" 32 | }, 33 | "devDependencies": { 34 | "bytemd": "workspace:*" 35 | }, 36 | "peerDependencies": { 37 | "bytemd": "^1.5.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/plugin-highlight/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-highlight", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to highlight code blocks", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-highlight" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "highlight.js": "^11.7.0" 32 | }, 33 | "devDependencies": { 34 | "bytemd": "workspace:*" 35 | }, 36 | "peerDependencies": { 37 | "bytemd": "^1.5.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/vue-next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/vue-next", 3 | "version": "1.22.0", 4 | "description": "Hackable Markdown Editor and Viewer", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/vue-next" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "bytemd": "workspace:*" 32 | }, 33 | "devDependencies": { 34 | "@vitejs/plugin-vue": "^4.1.0", 35 | "vue": "^3.2.47" 36 | }, 37 | "peerDependencies": { 38 | "vue": "^3.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/svelte/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm init svelte 12 | 13 | # create a new project in my-app 14 | npm init svelte my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /packages/plugin-medium-zoom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-medium-zoom", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to zoom images like Medium", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-medium-zoom" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "medium-zoom": "^1.0.8" 32 | }, 33 | "devDependencies": { 34 | "bytemd": "workspace:*" 35 | }, 36 | "peerDependencies": { 37 | "bytemd": "^1.5.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/react/src/editor.tsx: -------------------------------------------------------------------------------- 1 | import * as bytemd from 'bytemd' 2 | import React, { useEffect, useRef } from 'react' 3 | 4 | export interface EditorProps extends bytemd.EditorProps { 5 | onChange?(value: string): void 6 | } 7 | 8 | export const Editor: React.FC = ({ onChange, ...props }) => { 9 | const ed = useRef() 10 | const el = useRef(null) 11 | const onChangeRef = useRef() 12 | 13 | useEffect(() => { 14 | if (!el.current) return 15 | 16 | const editor = new bytemd.Editor({ 17 | target: el.current, 18 | props, 19 | }) 20 | editor.$on('change', (e: CustomEvent<{ value: string }>) => { 21 | onChangeRef.current?.(e.detail.value) 22 | }) 23 | ed.current = editor 24 | 25 | return () => { 26 | editor.$destroy() 27 | } 28 | }, []) 29 | 30 | useEffect(() => { 31 | onChangeRef.current = onChange 32 | }, [onChange]) 33 | 34 | useEffect(() => { 35 | // TODO: performance 36 | ed.current?.$set(props) 37 | }, [props]) 38 | 39 | return
40 | } 41 | -------------------------------------------------------------------------------- /examples/react-nextjs/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /packages/plugin-gfm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-gfm", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to support GFM (autolink literals, strikethrough, tables, tasklists)", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-gfm" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "remark-gfm": "^3.0.1" 32 | }, 33 | "devDependencies": { 34 | "bytemd": "workspace:*" 35 | }, 36 | "peerDependencies": { 37 | "bytemd": "^1.5.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/plugin-highlight-ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-highlight-ssr", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to highlight code blocks (SSR compatible)", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-highlight-ssr" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "rehype-highlight": "^6.0.0" 32 | }, 33 | "devDependencies": { 34 | "bytemd": "workspace:*" 35 | }, 36 | "peerDependencies": { 37 | "bytemd": "^1.5.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/vue", 3 | "version": "1.22.0", 4 | "description": "Hackable Markdown Editor and Viewer", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/vue" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "bytemd": "workspace:*" 32 | }, 33 | "devDependencies": { 34 | "vite-plugin-vue2": "^2.0.3", 35 | "vue": "^2.7.14", 36 | "vue-template-compiler": "^2.7.14" 37 | }, 38 | "peerDependencies": { 39 | "vue": "^2.0.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/vanilla-js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ByteMD example 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 |
19 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /packages/plugin-math-ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-math-ssr", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to support math formula (SSR compatible)", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-math-ssr" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "rehype-katex": "^6.0.2", 32 | "remark-math": "^5.1.1" 33 | }, 34 | "devDependencies": { 35 | "bytemd": "workspace:*" 36 | }, 37 | "peerDependencies": { 38 | "bytemd": "^1.5.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/plugin-math/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-math", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to support math formula", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-math" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "@types/katex": "^0.16.0", 32 | "katex": "^0.16.4", 33 | "remark-math": "^5.1.1" 34 | }, 35 | "devDependencies": { 36 | "bytemd": "workspace:*" 37 | }, 38 | "peerDependencies": { 39 | "bytemd": "^1.5.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/vue/src/editor.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rongjian Zhang 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 | -------------------------------------------------------------------------------- /packages/bytemd/locales/zh_Hant.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "粗體", 3 | "boldText": "粗體字", 4 | "cheatsheet": "Markdown 語法", 5 | "closeHelp": "關閉幫助", 6 | "closeToc": "關閉目錄", 7 | "code": "代碼", 8 | "codeBlock": "代碼塊", 9 | "codeLang": "編程語言", 10 | "codeText": "代碼", 11 | "exitFullscreen": "退出全屏", 12 | "exitPreviewOnly": "恢復默認", 13 | "exitWriteOnly": "恢復默認", 14 | "fullscreen": "全屏", 15 | "h1": "一級標題", 16 | "h2": "二級標題", 17 | "h3": "三級標題", 18 | "h4": "四級標題", 19 | "h5": "五級標題", 20 | "h6": "六級標題", 21 | "headingText": "標題", 22 | "help": "幫助", 23 | "hr": "分割線", 24 | "image": "圖像", 25 | "imageAlt": "alt", 26 | "imageTitle": "圖像描述", 27 | "italic": "斜體", 28 | "italicText": "斜體字", 29 | "limited": "已達最大字符數限制", 30 | "lines": "行數", 31 | "link": "連結", 32 | "linkText": "連結描述", 33 | "ol": "定義列表", 34 | "olItem": "項目", 35 | "preview": "預覽", 36 | "previewOnly": "僅預覽區", 37 | "quote": "引用", 38 | "quotedText": "引用文本", 39 | "shortcuts": "快捷鍵", 40 | "source": "源碼", 41 | "sync": "同步滾動", 42 | "toc": "目錄", 43 | "top": "回到頂部", 44 | "ul": "無序列表", 45 | "ulItem": "項目", 46 | "words": "字數", 47 | "write": "編輯", 48 | "writeOnly": "僅編輯區" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/zh_Hans.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "粗体", 3 | "boldText": "粗体文本", 4 | "cheatsheet": "Markdown 语法", 5 | "closeHelp": "关闭帮助", 6 | "closeToc": "关闭目录", 7 | "code": "代码", 8 | "codeBlock": "代码块", 9 | "codeLang": "编程语言", 10 | "codeText": "代码", 11 | "exitFullscreen": "退出全屏", 12 | "exitPreviewOnly": "恢复默认", 13 | "exitWriteOnly": "恢复默认", 14 | "fullscreen": "全屏", 15 | "h1": "一级标题", 16 | "h2": "二级标题", 17 | "h3": "三级标题", 18 | "h4": "四级标题", 19 | "h5": "五级标题", 20 | "h6": "六级标题", 21 | "headingText": "标题", 22 | "help": "帮助", 23 | "hr": "分割线", 24 | "image": "图片", 25 | "imageAlt": "alt", 26 | "imageTitle": "图片描述", 27 | "italic": "斜体", 28 | "italicText": "斜体文本", 29 | "limited": "已达最大字符数限制", 30 | "lines": "行数", 31 | "link": "链接", 32 | "linkText": "链接描述", 33 | "ol": "有序列表", 34 | "olItem": "项目", 35 | "preview": "预览", 36 | "previewOnly": "仅预览区", 37 | "quote": "引用", 38 | "quotedText": "引用文本", 39 | "shortcuts": "快捷键", 40 | "source": "源代码", 41 | "sync": "同步滚动", 42 | "toc": "目录", 43 | "top": "回到顶部", 44 | "ul": "无序列表", 45 | "ulItem": "项目", 46 | "words": "字数", 47 | "write": "编辑", 48 | "writeOnly": "仅编辑区" 49 | } 50 | -------------------------------------------------------------------------------- /packages/plugin-frontmatter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/plugin-frontmatter", 3 | "version": "1.22.0", 4 | "description": "ByteMD plugin to parse frontmatter", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/bytedance/bytemd.git", 8 | "directory": "packages/plugin-frontmatter" 9 | }, 10 | "license": "MIT", 11 | "author": "Rongjian Zhang", 12 | "exports": { 13 | ".": { 14 | "types": "./dist/index.d.ts", 15 | "import": "./dist/index.mjs", 16 | "require": "./dist/index.js" 17 | }, 18 | "./locales/*": "./locales/*", 19 | "./lib/locales/*": "./locales/*" 20 | }, 21 | "main": "./dist/index.js", 22 | "jsdelivr": "./dist/index.umd.js", 23 | "unpkg": "./dist/index.umd.js", 24 | "module": "./dist/index.mjs", 25 | "types": "./dist/index.d.ts", 26 | "files": [ 27 | "dist", 28 | "locales" 29 | ], 30 | "dependencies": { 31 | "@types/js-yaml": "^4.0.5", 32 | "js-yaml": "^4.1.0", 33 | "remark-frontmatter": "^4.0.1", 34 | "vfile": "^5.3.7" 35 | }, 36 | "devDependencies": { 37 | "bytemd": "workspace:*" 38 | }, 39 | "peerDependencies": { 40 | "bytemd": "^1.5.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/react-nextjs/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from '../styles/Home.module.css' 2 | import pluginGfm from '@bytemd/plugin-gfm' 3 | import { Editor } from '@bytemd/react' 4 | import type { NextPage } from 'next' 5 | import Head from 'next/head' 6 | import { useMemo, useState } from 'react' 7 | 8 | const Home: NextPage = () => { 9 | const [value, setValue] = useState('') 10 | const plugins = useMemo(() => [pluginGfm()], []) 11 | 12 | return ( 13 |
14 | 15 | Create Next App 16 | 17 | 18 | 19 | {/* */} 20 | 21 | { 25 | // upload images here 26 | return [ 27 | { 28 | url: 'https://picsum.photos/200/300', 29 | }, 30 | ] 31 | }} 32 | onChange={(v) => { 33 | setValue(v) 34 | }} 35 | /> 36 |
37 | ) 38 | } 39 | 40 | export default Home 41 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/nuxt.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // Global page headers: https://go.nuxtjs.dev/config-head 3 | head: { 4 | title: 'vue-nuxtjs', 5 | htmlAttrs: { 6 | lang: 'en', 7 | }, 8 | meta: [ 9 | { charset: 'utf-8' }, 10 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 11 | { hid: 'description', name: 'description', content: '' }, 12 | { name: 'format-detection', content: 'telephone=no' }, 13 | ], 14 | link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }], 15 | }, 16 | 17 | // Global CSS: https://go.nuxtjs.dev/config-css 18 | css: [], 19 | 20 | // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins 21 | plugins: [], 22 | 23 | // Auto import components: https://go.nuxtjs.dev/config-components 24 | components: true, 25 | 26 | // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules 27 | buildModules: [ 28 | // https://go.nuxtjs.dev/typescript 29 | '@nuxt/typescript-build', 30 | ], 31 | 32 | // Modules: https://go.nuxtjs.dev/config-modules 33 | modules: [], 34 | 35 | // Build Configuration: https://go.nuxtjs.dev/config-build 36 | build: {}, 37 | } 38 | -------------------------------------------------------------------------------- /packages/bytemd/locales/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "太字", 3 | "boldText": "ボールドテキスト", 4 | "cheatsheet": "マークダウン カンニングペーパー", 5 | "closeHelp": "ヘルプビューアを閉じます", 6 | "closeToc": "目次を閉じます", 7 | "code": "コード", 8 | "codeBlock": "コードブロック", 9 | "codeLang": "lang", 10 | "codeText": "コード", 11 | "exitFullscreen": "全画面を閉じます", 12 | "exitPreviewOnly": "プレビューのみを終了", 13 | "exitWriteOnly": "Exit 書き込み専用", 14 | "fullscreen": "全画面", 15 | "h1": "見出し1", 16 | "h2": "見出し2", 17 | "h3": "見出し3", 18 | "h4": "見出し4", 19 | "h5": "見出し5", 20 | "h6": "見出し6", 21 | "headingText": "見出し", 22 | "help": "ヘルプビューア", 23 | "hr": "区切り線", 24 | "image": "イメージ", 25 | "imageAlt": "alt", 26 | "imageTitle": "タイトル", 27 | "italic": "イタリック", 28 | "italicText": "斜体のテキスト", 29 | "lines": "線", 30 | "link": "リンク", 31 | "linkText": "リンクテキスト", 32 | "ol": "番号付きリスト", 33 | "olItem": "アイテム", 34 | "preview": "プレビュー", 35 | "previewOnly": "試写専用", 36 | "quote": "見積もり", 37 | "quotedText": "引用テキスト", 38 | "shortcuts": "ショートカット", 39 | "source": "原始コード", 40 | "sync": "スクロール同期", 41 | "toc": "目次", 42 | "top": "トップにスクロールします", 43 | "ul": "順序なしリスト", 44 | "ulItem": "アイテム", 45 | "words": "言葉", 46 | "write": "書く", 47 | "writeOnly": "書き込み専用" 48 | } 49 | -------------------------------------------------------------------------------- /packages/bytemd/locales/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "굵게", 3 | "boldText": "굵은 글자", 4 | "cheatsheet": "참고용 마크다운", 5 | "closeHelp": "도움말 닫기", 6 | "closeToc": "목차 닫기", 7 | "code": "코드", 8 | "codeBlock": "코드 블록", 9 | "codeLang": "언어", 10 | "codeText": "코드", 11 | "exitFullscreen": "꽉 찬 화면 종료", 12 | "exitPreviewOnly": "미리보기 전용 종료", 13 | "exitWriteOnly": "쓰기 전용 종료", 14 | "fullscreen": "꽉 찬 화면", 15 | "h1": "제목 1", 16 | "h2": "제목 2", 17 | "h3": "제목 3", 18 | "h4": "제목 4", 19 | "h5": "제목 5", 20 | "h6": "제목 6", 21 | "headingText": "제목", 22 | "help": "도움말", 23 | "hr": "구분선", 24 | "image": "이미지", 25 | "imageAlt": "대체 텍스트", 26 | "imageTitle": "타이틀", 27 | "italic": "이탤릭", 28 | "italicText": "이탤릭 글자", 29 | "limited": "최대 글자수 한도에 도달했습니다", 30 | "lines": "줄", 31 | "link": "링크", 32 | "linkText": "링크 글자", 33 | "ol": "순서 있는 목록", 34 | "olItem": "아이템", 35 | "preview": "미리보기", 36 | "previewOnly": "미리보기 전용", 37 | "quote": "인용", 38 | "quotedText": "인용된 텍스트", 39 | "shortcuts": "바로가기", 40 | "source": "소스 코드", 41 | "sync": "스크롤 동기화", 42 | "toc": "목차", 43 | "top": "맨 위로 스크롤", 44 | "ul": "순서 없는 목록", 45 | "ulItem": "아이템", 46 | "words": "글자", 47 | "write": "작성", 48 | "writeOnly": "쓰기 전용" 49 | } 50 | -------------------------------------------------------------------------------- /examples/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/example-react", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "react-scripts build", 7 | "eject": "react-scripts eject", 8 | "start": "react-scripts start", 9 | "test": "react-scripts test" 10 | }, 11 | "browserslist": { 12 | "production": [ 13 | ">0.2%", 14 | "not dead", 15 | "not op_mini all" 16 | ], 17 | "development": [ 18 | "last 1 chrome version", 19 | "last 1 firefox version", 20 | "last 1 safari version" 21 | ] 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "dependencies": { 30 | "@bytemd/plugin-gfm": "latest", 31 | "@bytemd/react": "latest", 32 | "@testing-library/jest-dom": "^5.16.3", 33 | "@testing-library/react": "^12.1.4", 34 | "@testing-library/user-event": "^13.5.0", 35 | "@types/jest": "^27.4.1", 36 | "@types/node": "^16.11.26", 37 | "@types/react": "^17.0.43", 38 | "@types/react-dom": "^17.0.14", 39 | "bytemd": "latest", 40 | "react": "^17.0.2", 41 | "react-dom": "^17.0.2", 42 | "react-scripts": "5.0.0", 43 | "typescript": "^4.6.3", 44 | "web-vitals": "^2.1.4" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/bytemd/test/viewer.test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Viewer } from '../src' 3 | import '@testing-library/jest-dom' 4 | import { render, act } from '@testing-library/svelte' 5 | 6 | function stripComment(str: string) { 7 | return str.replace(/<\!--.*?-->/g, '') 8 | } 9 | 10 | test('value', async () => { 11 | const $ = render(Viewer, { value: '# title' }) 12 | expect( 13 | stripComment($.container.querySelector('.markdown-body')?.innerHTML) 14 | ).toEqual('

title

') 15 | $.component.$destroy() 16 | }) 17 | 18 | test('plugin', async () => { 19 | const $ = render(Viewer) 20 | const off = vi.fn() 21 | const viewerEffect = vi.fn(() => off) 22 | 23 | $.component.$set({ plugins: [{ viewerEffect }] }) 24 | await act() 25 | expect(viewerEffect).toBeCalled() 26 | expect(viewerEffect).toBeCalledTimes(1) 27 | 28 | // FIXME: 29 | // expect(viewerEffect).toBeCalledWith( 30 | // expect.objectContaining({ 31 | // markdownBody: $.container.querySelector('.markdown-body'), 32 | // file: expect.objectContaining({ 33 | // contents: '', 34 | // data: {}, 35 | // }), 36 | // }) 37 | // ) 38 | 39 | $.component.$set({ plugins: [{ viewerEffect }] }) 40 | await act() 41 | expect(off).toBeCalled() 42 | expect(off).toBeCalledTimes(1) 43 | }) 44 | -------------------------------------------------------------------------------- /packages/plugin-gfm/src/icons.ts: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT, generated by scripts/icon.ts 2 | export const icons = { 3 | Strikethrough: 4 | '', 5 | CheckCorrect: 6 | '', 7 | InsertTable: 8 | '', 9 | } 10 | -------------------------------------------------------------------------------- /examples/legacy-browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IE9 Example 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /packages/vue-next/src/editor.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 56 | -------------------------------------------------------------------------------- /packages/bytemd/src/status.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 |
21 | 22 | {locale.words}: {words} 23 | 24 | 25 | {locale.lines}: {lines} 26 | 27 | {#if islimited} 28 | {locale.limited} 29 | {/if} 30 |
31 | 32 |
33 | {#if showSync} 34 | 42 | {/if} 43 | dispatch('top')} 45 | on:keydown|self={(e) => 46 | ['Enter', 'Space'].includes(e.code) && dispatch('top')} 47 | >{locale.top} 49 |
50 |
51 | -------------------------------------------------------------------------------- /packages/plugin-math/src/index.ts: -------------------------------------------------------------------------------- 1 | import en from './locales/en.json' 2 | import { MathLocale, getMathActions } from './utils' 3 | import type { BytemdPlugin } from 'bytemd' 4 | import type { default as K, KatexOptions } from 'katex' 5 | import remarkMath from 'remark-math' 6 | 7 | export interface BytemdPluginMathOptions { 8 | locale?: Partial 9 | katexOptions?: Omit 10 | } 11 | 12 | export default function math({ 13 | locale: _locale, 14 | katexOptions, 15 | }: BytemdPluginMathOptions = {}): BytemdPlugin { 16 | const locale = { ...en, ..._locale } 17 | let katex: typeof K 18 | 19 | return { 20 | remark: (processor) => processor.use(remarkMath), 21 | viewerEffect({ markdownBody }) { 22 | const renderMath = async (selector: string, displayMode: boolean) => { 23 | const els = markdownBody.querySelectorAll(selector) 24 | if (els.length === 0) return 25 | 26 | if (!katex) { 27 | katex = await import('katex').then((m) => m.default) 28 | } 29 | 30 | els.forEach((el) => { 31 | katex.render(el.innerText, el, { 32 | ...katexOptions, 33 | throwOnError: false, 34 | displayMode, 35 | }) 36 | }) 37 | } 38 | 39 | renderMath('.math.math-inline', false) 40 | renderMath('.math.math-display', true) 41 | }, 42 | actions: getMathActions(locale), 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/bytemd/locales/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "سميك", 3 | "boldText": "نص سميك", 4 | "cheatsheet": "مرجع للغة التوصيف", 5 | "closeHelp": "أغلق المساعدة", 6 | "closeToc": "أغلق قائمة المحتوى", 7 | "code": "نص برمجي", 8 | "codeBlock": "مربع برمجة", 9 | "codeLang": "اللغة", 10 | "codeText": "نص برمجي", 11 | "exitFullscreen": "الخروج من ملء الشاشة", 12 | "exitPreviewOnly": "الخروج من وضع معاينة فقط", 13 | "exitWriteOnly": "الخروج من وضع التعديل فقط", 14 | "fullscreen": "ملء الشاشة", 15 | "h1": "عنوان 1", 16 | "h2": "عنوان 2", 17 | "h3": "عنوان 3", 18 | "h4": "عنوان 4", 19 | "h5": "عنوان 5", 20 | "h6": "عنوان 6", 21 | "headingText": "عنوان", 22 | "help": "مساعدة", 23 | "hr": "فاصل عرضي", 24 | "image": "صورة", 25 | "imageAlt": "وصف الصورة", 26 | "imageTitle": "العنوان", 27 | "italic": "مائل", 28 | "italicText": "نص مائل", 29 | "limited": "تم الوصول لحد الكتابة الأقصى", 30 | "lines": "الأسطر", 31 | "link": "رابط", 32 | "linkText": "نص الرابط", 33 | "ol": "قائمة مرتبة", 34 | "olItem": "عنصر", 35 | "preview": "معاينة", 36 | "previewOnly": "معاينة فقط", 37 | "quote": "اقتباس", 38 | "quotedText": "النص المقتبس", 39 | "shortcuts": "اختصارات", 40 | "source": "المصدر البرمجي", 41 | "sync": "ربط الحركة", 42 | "toc": "الفهرس", 43 | "top": "الذهاب الى البداية", 44 | "ul": "قائمة منقطة", 45 | "ulItem": "عنصر", 46 | "words": "كلمات", 47 | "write": "أكتب", 48 | "writeOnly": "الكتابة فقط" 49 | } 50 | -------------------------------------------------------------------------------- /scripts/icon.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import * as icons from '@icon-park/svg' 3 | import { execSync } from 'child_process' 4 | import fs from 'fs-extra' 5 | import svgo from 'svgo' 6 | 7 | /** @type {Record} */ 8 | const meta = { 9 | 'bytemd/src': [ 10 | 'Close', 11 | 12 | 'H', 13 | 'H1', 14 | 'H2', 15 | 'H3', 16 | 'LevelFourTitle', 17 | 'LevelFiveTitle', 18 | 'LevelSixTitle', 19 | 'TextBold', 20 | 'TextItalic', 21 | 'Quote', 22 | 'LinkOne', 23 | 'Pic', 24 | 'Code', 25 | 'CodeBrackets', 26 | 'ListTwo', 27 | 'OrderedList', 28 | 'DividingLine', 29 | 30 | 'AlignTextLeftOne', 31 | 'Helpcenter', 32 | 'LeftExpand', 33 | 'RightExpand', 34 | 'OffScreen', 35 | 'FullScreen', 36 | 'GithubOne', 37 | ], 38 | 'plugin-gfm/src': ['Strikethrough', 'CheckCorrect', 'InsertTable'], 39 | 'plugin-math/src/utils': ['Formula', 'Inline', 'Block'], 40 | 'plugin-mermaid/src': ['ChartGraph'], 41 | } 42 | 43 | for (let [p, keys] of Object.entries(meta)) { 44 | let obj = {} 45 | for (let key of keys) { 46 | const svg = svgo.optimize(icons[key]({})) 47 | obj[key] = svg.data 48 | } 49 | 50 | fs.writeFileSync( 51 | `./packages/${p}/icons.ts`, 52 | `// DO NOT EDIT, generated by scripts/icon.ts 53 | export const icons=${JSON.stringify(obj)}` 54 | ) 55 | } 56 | 57 | execSync('npx prettier --write packages/**/*.ts') 58 | -------------------------------------------------------------------------------- /packages/bytemd/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Bold", 3 | "boldText": "bold text", 4 | "cheatsheet": "Markdown Cheatsheet", 5 | "closeHelp": "Close help", 6 | "closeToc": "Close table of contents", 7 | "code": "Code", 8 | "codeBlock": "Code block", 9 | "codeLang": "lang", 10 | "codeText": "code", 11 | "exitFullscreen": "Exit fullscreen", 12 | "exitPreviewOnly": "Exit preview only", 13 | "exitWriteOnly": "Exit write only", 14 | "fullscreen": "Fullscreen", 15 | "h1": "Heading 1", 16 | "h2": "Heading 2", 17 | "h3": "Heading 3", 18 | "h4": "Heading 4", 19 | "h5": "Heading 5", 20 | "h6": "Heading 6", 21 | "headingText": "heading", 22 | "help": "Help", 23 | "hr": "Horizontal rule", 24 | "image": "Image", 25 | "imageAlt": "alt", 26 | "imageTitle": "title", 27 | "italic": "Italic", 28 | "italicText": "italic text", 29 | "limited": "The maximum character limit has been reached", 30 | "lines": "Lines", 31 | "link": "Link", 32 | "linkText": "link text", 33 | "ol": "Ordered list", 34 | "olItem": "item", 35 | "preview": "Preview", 36 | "previewOnly": "Preview only", 37 | "quote": "Quote", 38 | "quotedText": "quoted text", 39 | "shortcuts": "Shortcuts", 40 | "source": "Source code", 41 | "sync": "Scroll sync", 42 | "toc": "Table of contents", 43 | "top": "Scroll to top", 44 | "ul": "Unordered list", 45 | "ulItem": "item", 46 | "words": "Words", 47 | "write": "Write", 48 | "writeOnly": "Write only" 49 | } 50 | -------------------------------------------------------------------------------- /packages/plugin-math/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { icons } from './icons' 2 | import type { BytemdAction } from 'bytemd' 3 | 4 | export type MathLocale = { 5 | inline: string 6 | inlineText: string 7 | block: string 8 | blockText: string 9 | } 10 | 11 | export function getMathActions(locale: MathLocale): BytemdAction[] { 12 | return [ 13 | { 14 | icon: icons.Formula, 15 | handler: { 16 | type: 'dropdown', 17 | actions: [ 18 | { 19 | title: locale.inline, 20 | icon: icons.Inline, 21 | cheatsheet: `$${locale.inlineText}$`, 22 | handler: { 23 | type: 'action', 24 | click({ wrapText, editor }) { 25 | wrapText('$') 26 | editor.focus() 27 | }, 28 | }, 29 | }, 30 | { 31 | title: locale.block, 32 | icon: icons.Block, 33 | cheatsheet: `$$↵${locale.blockText}↵$$`, 34 | handler: { 35 | type: 'action', 36 | click({ appendBlock, editor, codemirror }) { 37 | const { line } = appendBlock('$$\n\\TeX\n$$') 38 | editor.setSelection( 39 | codemirror.Pos(line + 1, 0), 40 | codemirror.Pos(line + 1, 4) 41 | ) 42 | editor.focus() 43 | }, 44 | }, 45 | }, 46 | ], 47 | }, 48 | }, 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /packages/bytemd/locales/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Tebal", 3 | "boldText": "teks tebal", 4 | "cheatsheet": "Contekan Markdown", 5 | "closeHelp": "Tutup bantuan", 6 | "closeToc": "Tutup daftar isi", 7 | "code": "Kode", 8 | "codeBlock": "Blok kode", 9 | "codeLang": "bahasa", 10 | "codeText": "kode", 11 | "exitFullscreen": "Keluar layar penuh", 12 | "exitPreviewOnly": "Keluar hanya-pratinjau", 13 | "exitWriteOnly": "Keluar hanya menulis", 14 | "fullscreen": "Layar penuh", 15 | "h1": "Tajuk 1", 16 | "h2": "Tajuk 2", 17 | "h3": "Tajuk 3", 18 | "h4": "Tajuk 4", 19 | "h5": "Tajuk 5", 20 | "h6": "Tajuk 6", 21 | "headingText": "tajuk", 22 | "help": "Bantuan", 23 | "hr": "Kaidah horizontal", 24 | "image": "Gambar", 25 | "imageAlt": "alternatif", 26 | "imageTitle": "judul", 27 | "italic": "Miring", 28 | "italicText": "teks miring", 29 | "limited": "Batas maksimum karakter telah tercapai", 30 | "lines": "Baris", 31 | "link": "Tautan", 32 | "linkText": "teks tautan", 33 | "ol": "Daftar terurut", 34 | "olItem": "item", 35 | "preview": "Pratinjau", 36 | "previewOnly": "Hanya-pratinjau", 37 | "quote": "Kutip", 38 | "quotedText": "teks kutipan", 39 | "shortcuts": "Pintasan", 40 | "source": "Kode sumber", 41 | "sync": "Sinkronisasi pengguliran", 42 | "toc": "Daftar isi", 43 | "top": "Ke permulaan", 44 | "ul": "Daftar tak berurutan", 45 | "ulItem": "item", 46 | "words": "Kata", 47 | "write": "Tulis", 48 | "writeOnly": "Hanya menulis" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { ViewerProps } from './types' 2 | import { defaultSchema } from 'hast-util-sanitize' 3 | import type { Schema } from 'hast-util-sanitize' 4 | import rehypeRaw from 'rehype-raw' 5 | import rehypeSanitize from 'rehype-sanitize' 6 | import rehypeStringify from 'rehype-stringify' 7 | import remarkParse from 'remark-parse' 8 | import remarkRehype from 'remark-rehype' 9 | import { unified } from 'unified' 10 | import type { Processor } from 'unified' 11 | 12 | const schemaStr = JSON.stringify(defaultSchema) 13 | 14 | /** 15 | * Get unified processor with ByteMD plugins 16 | */ 17 | export function getProcessor({ 18 | sanitize, 19 | plugins, 20 | remarkRehype: remarkRehypeOptions = {}, 21 | }: Omit) { 22 | let processor: Processor = unified().use(remarkParse) 23 | 24 | plugins?.forEach(({ remark }) => { 25 | if (remark) processor = remark(processor) 26 | }) 27 | processor = processor 28 | .use(remarkRehype, { allowDangerousHtml: true, ...remarkRehypeOptions }) 29 | .use(rehypeRaw) 30 | 31 | let schema = JSON.parse(schemaStr) as Schema 32 | schema.attributes!['*'].push('className') // Allow class names by default 33 | 34 | if (typeof sanitize === 'function') { 35 | schema = sanitize(schema) 36 | } 37 | 38 | processor = processor.use(rehypeSanitize, schema) 39 | 40 | plugins?.forEach(({ rehype }) => { 41 | if (rehype) processor = rehype(processor) 42 | }) 43 | 44 | return processor.use(rehypeStringify) 45 | } 46 | -------------------------------------------------------------------------------- /packages/bytemd/locales/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Kalın", 3 | "boldText": "kalın metin", 4 | "cheatsheet": "Markdown Kısayol Tuşları", 5 | "closeHelp": "Yardımı Kapat", 6 | "closeToc": "İçindekileri Kapat", 7 | "code": "Kod", 8 | "codeBlock": "Kod bloğu", 9 | "codeLang": "dil", 10 | "codeText": "kod", 11 | "exitFullscreen": "Tam ekrandan çık", 12 | "exitPreviewOnly": "Sadece ön izlemeyi kapat", 13 | "exitWriteOnly": "Sadece editörü kapat", 14 | "fullscreen": "Tam ekran", 15 | "h1": "Başlık 1", 16 | "h2": "Başlık 2", 17 | "h3": "Başlık 3", 18 | "h4": "Başlık 4", 19 | "h5": "Başlık 5", 20 | "h6": "Başlık 6", 21 | "headingText": "başlık", 22 | "help": "Yardım", 23 | "hr": "Yatay Çizgi", 24 | "image": "Resim", 25 | "imageAlt": "alternatif metin", 26 | "imageTitle": "başlık", 27 | "italic": "italik", 28 | "italicText": "italik metin", 29 | "limited": "Maksimum karakter sınırına ulaşıldı", 30 | "lines": "Satırlar", 31 | "link": "Bağlantı", 32 | "linkText": "bağlantı metni", 33 | "ol": "Sıralı liste", 34 | "olItem": "madde", 35 | "preview": "Ön izleme", 36 | "previewOnly": "Sadece ön izleme", 37 | "quote": "Alıntı", 38 | "quotedText": "alıntılanmış metin", 39 | "shortcuts": "Kısayollar", 40 | "source": "Kaynak kodu", 41 | "sync": "Kaydırma senkronizasyonu", 42 | "toc": "İçindekiler", 43 | "top": "En başa git", 44 | "ul": "Sırasız liste", 45 | "ulItem": "madde", 46 | "words": "Kelimeler", 47 | "write": "Yaz", 48 | "writeOnly": "Sadece yazı modu" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Gras", 3 | "boldText": "texte en gras", 4 | "cheatsheet": "Aide-mémoire Markdown", 5 | "closeHelp": "Fermer l'aide", 6 | "closeToc": "Ferme le sommaire", 7 | "code": "Code", 8 | "codeBlock": "Bloc de code", 9 | "codeLang": "langue", 10 | "codeText": "code", 11 | "exitFullscreen": "Quitter le plein écran", 12 | "exitPreviewOnly": "Quitter l'aperçu seul", 13 | "exitWriteOnly": "Quitter l'écriture seule", 14 | "fullscreen": "Plein écran", 15 | "h1": "Titre 1", 16 | "h2": "Titre 2", 17 | "h3": "Titre 3", 18 | "h4": "Titre 4", 19 | "h5": "Titre 5", 20 | "h6": "Titre 6", 21 | "headingText": "titre", 22 | "help": "Aide", 23 | "hr": "Règle horizontale", 24 | "image": "Image", 25 | "imageAlt": "alt", 26 | "imageTitle": "titre", 27 | "italic": "Italique", 28 | "italicText": "texte en italique", 29 | "limited": "La limite maximale de caractères a été atteinte", 30 | "lines": "Lignes", 31 | "link": "Lien", 32 | "linkText": "texte du texte", 33 | "ol": "Liste ordonnée", 34 | "olItem": "élément", 35 | "preview": "Aperçu", 36 | "previewOnly": "Aperçu seul", 37 | "quote": "Citation", 38 | "quotedText": "texte cité", 39 | "shortcuts": "Raccourcis", 40 | "source": "Code source", 41 | "sync": "Défilement synchro", 42 | "toc": "Sommaire", 43 | "top": "Défiler vers le haut", 44 | "ul": "Liste non ordonnée", 45 | "ulItem": "élément", 46 | "words": "Mots", 47 | "write": "Écrire", 48 | "writeOnly": "Écriture seule" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Pogrubienie", 3 | "boldText": "pogrubienie", 4 | "cheatsheet": "Ściągawka markdowna", 5 | "closeHelp": "Zamknij pomoc", 6 | "closeToc": "Zamknij spis treści", 7 | "code": "Kod", 8 | "codeBlock": "Blok kodu", 9 | "codeLang": "język", 10 | "codeText": "kod", 11 | "exitFullscreen": "Zamknij pełny ekran", 12 | "exitPreviewOnly": "Zamknij widok podglądu", 13 | "exitWriteOnly": "Zamknij widok edytora", 14 | "fullscreen": "Pełny ekran", 15 | "h1": "Nagłówek 1", 16 | "h2": "Nagłówek 2", 17 | "h3": "Nagłówek 3", 18 | "h4": "Nagłówek 4", 19 | "h5": "Nagłówek 5", 20 | "h6": "Nagłówek 6", 21 | "headingText": "nagłówek", 22 | "help": "Pomoc", 23 | "hr": "Pozioma linia", 24 | "image": "Obraz", 25 | "imageAlt": "tekst alternatywny", 26 | "imageTitle": "tytuł", 27 | "italic": "Kursywa", 28 | "italicText": "kursywa", 29 | "limited": "Osiągnięto limit liczby znaków", 30 | "lines": "Linie", 31 | "link": "Hiperłącze", 32 | "linkText": "hiperłącze", 33 | "ol": "Lista numerowana", 34 | "olItem": "element listy", 35 | "preview": "Podgląd", 36 | "previewOnly": "Tylko podgląd", 37 | "quote": "Cytat", 38 | "quotedText": "cytat", 39 | "shortcuts": "Skróty", 40 | "source": "Kod źródłowy", 41 | "sync": "Synchronizuj przewijanie", 42 | "toc": "Spis treści", 43 | "top": "Przewiń do góry", 44 | "ul": "Lista nienumerowana", 45 | "ulItem": "element listy", 46 | "words": "Słowa", 47 | "write": "Edytor", 48 | "writeOnly": "Tylko edytor" 49 | } 50 | -------------------------------------------------------------------------------- /packages/react/src/viewer.tsx: -------------------------------------------------------------------------------- 1 | import * as bytemd from 'bytemd' 2 | import React, { useMemo, useEffect, useRef, FC } from 'react' 3 | 4 | export interface ViewerProps extends bytemd.ViewerProps {} 5 | 6 | export const Viewer: FC = ({ 7 | value, 8 | sanitize, 9 | plugins, 10 | remarkRehype, 11 | }) => { 12 | const elRef = useRef(null) 13 | const file = useMemo(() => { 14 | try { 15 | return bytemd 16 | .getProcessor({ sanitize, plugins, remarkRehype }) 17 | .processSync(value) 18 | } catch (err) { 19 | console.error(err) 20 | } 21 | }, [value, sanitize, plugins, remarkRehype]) 22 | 23 | useEffect(() => { 24 | const markdownBody = elRef.current 25 | if (!markdownBody || !file) return 26 | 27 | const cbs = plugins?.map(({ viewerEffect }) => 28 | viewerEffect?.({ markdownBody, file }) 29 | ) 30 | return () => { 31 | cbs?.forEach((cb) => cb && cb()) 32 | } 33 | }, [file, plugins]) 34 | 35 | return ( 36 |
{ 38 | const $ = e.target as HTMLElement 39 | if ($.tagName !== 'A') return 40 | 41 | const href = $.getAttribute('href') 42 | if (!href?.startsWith('#')) return 43 | 44 | elRef.current 45 | ?.querySelector('#user-content-' + href.slice(1)) 46 | ?.scrollIntoView() 47 | }} 48 | ref={elRef} 49 | className="markdown-body" 50 | dangerouslySetInnerHTML={{ __html: file?.toString() ?? '' }} 51 | >
52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /packages/bytemd/locales/nb_NO.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Fet", 3 | "boldText": "fet tekst", 4 | "cheatsheet": "Markdown-jukseark", 5 | "closeHelp": "Lukk hjelp", 6 | "closeToc": "Lukk innholdsfortegnelse", 7 | "code": "Kode", 8 | "codeBlock": "Kodeblokk", 9 | "codeLang": "språk", 10 | "codeText": "kode", 11 | "exitFullscreen": "Avslutt fullskjermsvisning", 12 | "exitPreviewOnly": "Avslutt kun forhåndsvisning", 13 | "exitWriteOnly": "Avslutt kun skriving", 14 | "fullscreen": "Fullskjermsvisning", 15 | "h1": "Overskrift 1", 16 | "h2": "Overskrift 2", 17 | "h3": "Overskrift 3", 18 | "h4": "Overskrift 4", 19 | "h5": "Overskrift 5", 20 | "h6": "Overskrift 6", 21 | "headingText": "overskrift", 22 | "help": "Hjelp", 23 | "hr": "Vannrett linje", 24 | "image": "Bilde", 25 | "imageAlt": "alt. tekst", 26 | "imageTitle": "tittel", 27 | "italic": "Kursiv", 28 | "italicText": "skråskriftstekst", 29 | "limited": "Maksimalt antall tegn oppbrukt", 30 | "lines": "Linjer", 31 | "link": "Lenke", 32 | "linkText": "lenketekst", 33 | "ol": "Nummerert liste", 34 | "olItem": "element", 35 | "preview": "Forhåndsvis", 36 | "previewOnly": "Kun forhåndsvisning", 37 | "quote": "Sitat", 38 | "quotedText": "Sitert tekst", 39 | "shortcuts": "Snarveier", 40 | "source": "Kildekode", 41 | "sync": "Rullingssynkronisering", 42 | "toc": "Innholdsfortegnelse", 43 | "top": "Rull til toppen", 44 | "ul": "Liste", 45 | "ulItem": "element", 46 | "words": "Ord", 47 | "write": "Skriv", 48 | "writeOnly": "Kun skriving" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Fett", 3 | "boldText": "Fetter Text", 4 | "cheatsheet": "Markdown-Spickzettel", 5 | "closeHelp": "Hilfe schließen", 6 | "closeToc": "Inhaltsverzeichnis schließen", 7 | "code": "Code", 8 | "codeBlock": "Codeblock", 9 | "codeLang": "Sprache", 10 | "codeText": "Code", 11 | "exitFullscreen": "Vollbildmodus beenden", 12 | "exitPreviewOnly": "Nur Vorschau schließen", 13 | "exitWriteOnly": "Nur Schreiben schließen", 14 | "fullscreen": "Vollbild", 15 | "h1": "Überschrift 1", 16 | "h2": "Überschrift 2", 17 | "h3": "Überschrift 3", 18 | "h4": "Überschrift 4", 19 | "h5": "Überschrift 5", 20 | "h6": "Überschrift 6", 21 | "headingText": "Überschrift", 22 | "help": "Hilfe", 23 | "hr": "Horizontale Linie", 24 | "image": "Bild", 25 | "imageAlt": "Alternativtext", 26 | "imageTitle": "Titel", 27 | "italic": "Kursiv", 28 | "italicText": "Kursiver Text", 29 | "limited": "Die maximale Zeichengrenze ist erreicht", 30 | "lines": "Zeilen", 31 | "link": "Link", 32 | "linkText": "Linktext", 33 | "ol": "Geordnete Liste", 34 | "olItem": "Artikel", 35 | "preview": "Vorschau", 36 | "previewOnly": "Nur Vorschau", 37 | "quote": "Zitat", 38 | "quotedText": "Zitattext", 39 | "shortcuts": "Verknüpfungen", 40 | "source": "Quellcode", 41 | "sync": "Synchronisiertes Scrollen", 42 | "toc": "Inhaltsverzeichnis", 43 | "top": "Nach oben scrollen", 44 | "ul": "Ungeordnete Liste", 45 | "ulItem": "Artikel", 46 | "words": "Wörter", 47 | "write": "Schreiben", 48 | "writeOnly": "Nur Schreiben" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/pt.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Negrito", 3 | "boldText": "texto em negrito", 4 | "cheatsheet": "Referência de Markdown", 5 | "closeHelp": "Fechar ajuda", 6 | "closeToc": "Fechar índice", 7 | "code": "Código", 8 | "codeBlock": "Bloco de código", 9 | "codeLang": "linguagem", 10 | "codeText": "código", 11 | "exitFullscreen": "Sair do ecrã inteiro", 12 | "exitPreviewOnly": "Sair apenas do modo Visualizar", 13 | "exitWriteOnly": "Sair apenas do modo Escrever", 14 | "fullscreen": "Tela Cheia", 15 | "h1": "Cabeçalho 1", 16 | "h2": "Cabeçalho 2", 17 | "h3": "Cabeçalho 3", 18 | "h4": "Cabeçalho 4", 19 | "h5": "Cabeçalho 5", 20 | "h6": "Cabeçalho 6", 21 | "headingText": "cabeçalho", 22 | "help": "ajuda", 23 | "hr": "Linha horizontal", 24 | "image": "Imagem", 25 | "imageAlt": "alt", 26 | "imageTitle": "titulo", 27 | "italic": "Italico", 28 | "italicText": "texto em italico", 29 | "limited": "O máximo de caracteres foi atingido", 30 | "lines": "Linhas", 31 | "link": "Link", 32 | "linkText": "texto do link", 33 | "ol": "Lista Ordenada", 34 | "olItem": "item", 35 | "preview": "Visualizar", 36 | "previewOnly": "Somente visualização", 37 | "quote": "Citar", 38 | "quotedText": "texto citado", 39 | "shortcuts": "Atalhos", 40 | "source": "Código-fonte", 41 | "sync": "Sincronizar a barra de rolagem", 42 | "toc": "Índice", 43 | "top": "Rolar para cima", 44 | "ul": "Lista não ordenada", 45 | "ulItem": "item", 46 | "words": "Palavras", 47 | "write": "Escrever", 48 | "writeOnly": "Apenas escrever" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/pt_BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Negrito", 3 | "boldText": "texto em negrito", 4 | "cheatsheet": "Referência de Markdown", 5 | "closeHelp": "Fechar ajuda", 6 | "closeToc": "Fechar índice", 7 | "code": "Código", 8 | "codeBlock": "Bloco de código", 9 | "codeLang": "linguagem", 10 | "codeText": "código", 11 | "exitFullscreen": "Sair da tela cheia", 12 | "exitPreviewOnly": "Sair apenas do modo Visualizar", 13 | "exitWriteOnly": "Sair apenas do modo Escrever", 14 | "fullscreen": "Tela cheia", 15 | "h1": "Cabeçalho 1", 16 | "h2": "Cabeçalho 2", 17 | "h3": "Cabeçalho 3", 18 | "h4": "Cabeçalho 4", 19 | "h5": "Cabeçalho 5", 20 | "h6": "Cabeçalho 6", 21 | "headingText": "cabeçalho", 22 | "help": "Ajuda", 23 | "hr": "Linha horizontal", 24 | "image": "Imagem", 25 | "imageAlt": "texto", 26 | "imageTitle": "título", 27 | "italic": "Itálico", 28 | "italicText": "texto itálico", 29 | "limited": "O limite máximo de caracteres foi atingido", 30 | "lines": "Linhas", 31 | "link": "Link", 32 | "linkText": "texto do link", 33 | "ol": "Lista ordenada", 34 | "olItem": "item", 35 | "preview": "Visualizar", 36 | "previewOnly": "Visualizar apenas", 37 | "quote": "Citar", 38 | "quotedText": "texto citado", 39 | "shortcuts": "Atalhos", 40 | "source": "Código fonte", 41 | "sync": "Sincronizar a barra de rolagem", 42 | "toc": "Índice", 43 | "top": "Rolar para cima", 44 | "ul": "Lista não ordenada", 45 | "ulItem": "item", 46 | "words": "Palavras", 47 | "write": "Escrever", 48 | "writeOnly": "Escrever apenas" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Negrita", 3 | "boldText": "texto en negritas", 4 | "cheatsheet": "Referencia rápida de Markdown", 5 | "closeHelp": "Cerrar ayuda", 6 | "closeToc": "Cerrar sumario", 7 | "code": "Código", 8 | "codeBlock": "Bloque de código", 9 | "codeLang": "lenguaje", 10 | "codeText": "código", 11 | "exitFullscreen": "Salir de pantalla completa", 12 | "exitPreviewOnly": "Salir de Solo previsualización", 13 | "exitWriteOnly": "Salir de Solo escritura", 14 | "fullscreen": "Pantalla completa", 15 | "h1": "Título 1", 16 | "h2": "Título 2", 17 | "h3": "Título 3", 18 | "h4": "Título 4", 19 | "h5": "Título 5", 20 | "h6": "Título 6", 21 | "headingText": "título", 22 | "help": "Ayuda", 23 | "hr": "Línea horizontal", 24 | "image": "Imagen", 25 | "imageAlt": "texto alt.", 26 | "imageTitle": "título", 27 | "italic": "Itálica", 28 | "italicText": "texto en itálicas", 29 | "limited": "S'ha arribat al límit màxim de caràcters", 30 | "lines": "Renglones", 31 | "link": "Enlace", 32 | "linkText": "texto de enlace", 33 | "ol": "Lista numerada", 34 | "olItem": "elemento", 35 | "preview": "Previsualizar", 36 | "previewOnly": "Solo previsualización", 37 | "quote": "Cita", 38 | "quotedText": "texto citado", 39 | "shortcuts": "Atajos", 40 | "source": "Código fuente", 41 | "sync": "Desplazamiento síncrono", 42 | "toc": "Sumario", 43 | "top": "Desplazarse hasta arriba", 44 | "ul": "Lista con bolos", 45 | "ulItem": "elemento", 46 | "words": "Palabras", 47 | "write": "Escribir", 48 | "writeOnly": "Solo escritura" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Жирный", 3 | "boldText": "жирный текст", 4 | "cheatsheet": "Шпаргалка по Markdown", 5 | "closeHelp": "Закрыть справку", 6 | "closeToc": "Закрыть оглавление", 7 | "code": "Код", 8 | "codeBlock": "Блок кода", 9 | "codeLang": "язык", 10 | "codeText": "код", 11 | "exitFullscreen": "Выйти из полноэкранного режима", 12 | "exitPreviewOnly": "Выйти из режима предпросмотра", 13 | "exitWriteOnly": "Выйти из режима редактирования", 14 | "fullscreen": "Полноэкранный режим", 15 | "h1": "Заголовок 1", 16 | "h2": "Заголовок 2", 17 | "h3": "Заголовок 3", 18 | "h4": "Заголовок 4", 19 | "h5": "Заголовок 5", 20 | "h6": "Заголовок 6", 21 | "headingText": "заголовок", 22 | "help": "Справка", 23 | "hr": "Горизонтальная линия", 24 | "image": "Изображение", 25 | "imageAlt": "alt", 26 | "imageTitle": "название", 27 | "italic": "Курсив", 28 | "italicText": "курсивный текст", 29 | "limited": "Достигнуто максимальное количество символов", 30 | "lines": "Строки", 31 | "link": "Ссылка", 32 | "linkText": "текст ссылки", 33 | "ol": "Нумерованный список", 34 | "olItem": "элемент", 35 | "preview": "Предпросмотр", 36 | "previewOnly": "Только предпросмотр", 37 | "quote": "Цитата", 38 | "quotedText": "цитируемый текст", 39 | "shortcuts": "Горячие клавиши", 40 | "source": "Исходный код", 41 | "sync": "Синхронизация прокрутки", 42 | "toc": "Оглавление", 43 | "top": "Пролистать наверх", 44 | "ul": "Маркированный список", 45 | "ulItem": "элемент", 46 | "words": "Слова", 47 | "write": "Редактор", 48 | "writeOnly": "Только редактор" 49 | } 50 | -------------------------------------------------------------------------------- /packages/bytemd/locales/ca.json: -------------------------------------------------------------------------------- 1 | { 2 | "bold": "Negreta", 3 | "boldText": "text en negreta", 4 | "cheatsheet": "Referència ràpida del Markdown", 5 | "closeHelp": "Tanca l’ajuda", 6 | "closeToc": "Tanca la taula de contingut", 7 | "code": "Codi", 8 | "codeBlock": "Bloc de codi", 9 | "codeLang": "llenguatge", 10 | "codeText": "codi", 11 | "exitFullscreen": "Surt de la pantalla completa", 12 | "exitPreviewOnly": "Surt de «Només previsualització»", 13 | "exitWriteOnly": "Surt de «Només escriptura»", 14 | "fullscreen": "Pantalla completa", 15 | "h1": "Encapçalament 1", 16 | "h2": "Encapçalament 2", 17 | "h3": "Encapçalament 3", 18 | "h4": "Encapçalament 4", 19 | "h5": "Encapçalament 5", 20 | "h6": "Encapçalament 6", 21 | "headingText": "encapçalament", 22 | "help": "Ajuda", 23 | "hr": "Línia horitzontal", 24 | "image": "Imatge", 25 | "imageAlt": "text alt.", 26 | "imageTitle": "títol", 27 | "italic": "Cursiva", 28 | "italicText": "text en cursiva", 29 | "limited": "S'ha arribat al límit màxim de caràcters", 30 | "lines": "Línies", 31 | "link": "Enllaç", 32 | "linkText": "text de l’enllaç", 33 | "ol": "Llista ordenada", 34 | "olItem": "element", 35 | "preview": "Previsualització", 36 | "previewOnly": "Només previsualització", 37 | "quote": "Cita", 38 | "quotedText": "text citat", 39 | "shortcuts": "Dreceres", 40 | "source": "Codi font", 41 | "sync": "Desplaçament síncron", 42 | "toc": "Taula de contingut", 43 | "top": "Desplaça’t fins al capdamunt", 44 | "ul": "Llista sense ordenar", 45 | "ulItem": "element", 46 | "words": "Mots", 47 | "write": "Escriptura", 48 | "writeOnly": "Només escriptura" 49 | } 50 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | /logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless 79 | 80 | # IDE / Editor 81 | .idea 82 | 83 | # Service worker 84 | sw.* 85 | 86 | # macOS 87 | .DS_Store 88 | 89 | # Vim swap files 90 | *.swp 91 | -------------------------------------------------------------------------------- /packages/vue/src/viewer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 67 | -------------------------------------------------------------------------------- /examples/react-nextjs/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /packages/bytemd/src/help.svelte: -------------------------------------------------------------------------------- 1 | 26 | 27 |
28 |

{locale.cheatsheet}

29 |
    30 | {#each items as action} 31 | {#if action.cheatsheet} 32 |
  • 33 |
    {@html action.icon}
    34 |
    {action.title}
    35 |
    36 | {action.cheatsheet} 37 |
    38 |
  • 39 | {/if} 40 | {/each} 41 |
42 |

{locale.shortcuts}

43 |
    44 | {#each items as action} 45 | {#if action.handler && action.handler.type === 'action' && action.handler.shortcut} 46 |
  • 47 |
    {@html action.icon}
    48 |
    {action.title}
    49 |
    50 | {action.handler.shortcut} 51 |
    52 |
  • 53 | {/if} 54 | {/each} 55 |
56 |
57 | -------------------------------------------------------------------------------- /examples/vue3/README.md: -------------------------------------------------------------------------------- 1 | # vue-next 2 | 3 | This template should help get you started developing with Vue 3 in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.vscode-typescript-vue-plugin). 8 | 9 | ## Type Support for `.vue` Imports in TS 10 | 11 | TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types. 12 | 13 | If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps: 14 | 15 | 1. Disable the built-in TypeScript Extension 16 | 1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette 17 | 2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)` 18 | 2. Reload the VSCode window by running `Developer: Reload Window` from the command palette. 19 | 20 | ## Customize configuration 21 | 22 | See [Vite Configuration Reference](https://vitejs.dev/config/). 23 | 24 | ## Project Setup 25 | 26 | ```sh 27 | npm install 28 | ``` 29 | 30 | ### Compile and Hot-Reload for Development 31 | 32 | ```sh 33 | npm run dev 34 | ``` 35 | 36 | ### Type-Check, Compile and Minify for Production 37 | 38 | ```sh 39 | npm run build 40 | ``` 41 | -------------------------------------------------------------------------------- /packages/bytemd/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bytemd", 3 | "version": "1.22.0", 4 | "description": "Hackable Markdown Editor and Viewer", 5 | "keywords": [ 6 | "markdown", 7 | "editor", 8 | "viewer" 9 | ], 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/bytedance/bytemd.git", 13 | "directory": "packages/bytemd" 14 | }, 15 | "license": "MIT", 16 | "author": "Rongjian Zhang", 17 | "exports": { 18 | ".": { 19 | "types": "./dist/index.d.ts", 20 | "svelte": "./svelte/index.js", 21 | "import": "./dist/index.mjs", 22 | "require": "./dist/index.js" 23 | }, 24 | "./locales/*": "./locales/*", 25 | "./lib/locales/*": "./locales/*", 26 | "./dist/index.css": "./dist/index.css", 27 | "./dist/index.min.css": "./dist/index.min.css" 28 | }, 29 | "main": "./dist/index.js", 30 | "svelte": "./svelte/index.js", 31 | "jsdelivr": "./dist/index.umd.js", 32 | "unpkg": "./dist/index.umd.js", 33 | "module": "./dist/index.mjs", 34 | "types": "./dist/index.d.ts", 35 | "files": [ 36 | "dist", 37 | "locales", 38 | "svelte" 39 | ], 40 | "dependencies": { 41 | "@popperjs/core": "^2.11.7", 42 | "@types/codemirror": "^5.60.7", 43 | "@types/hast": "^2.3.4", 44 | "@types/lodash-es": "^4.17.7", 45 | "@types/mdast": "^3.0.11", 46 | "codemirror-ssr": "^0.65.0", 47 | "hast-util-sanitize": "^4.1.0", 48 | "lodash-es": "^4.17.21", 49 | "rehype-raw": "^6.1.1", 50 | "rehype-sanitize": "^5.0.1", 51 | "rehype-stringify": "^9.0.3", 52 | "remark-parse": "^10.0.1", 53 | "remark-rehype": "^10.1.0", 54 | "select-files": "^1.0.1", 55 | "tippy.js": "^6.3.7", 56 | "unified": "^10.1.2", 57 | "unist-util-visit": "^4.1.2", 58 | "vfile": "^5.3.7", 59 | "word-count": "^0.2.2" 60 | }, 61 | "devDependencies": { 62 | "@primer/css": "^15.2.0" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /examples/react/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /packages/plugin-gfm/src/index.ts: -------------------------------------------------------------------------------- 1 | import { icons } from './icons' 2 | import en from './locales/en.json' 3 | import type { BytemdPlugin } from 'bytemd' 4 | import remarkGfm, { Options } from 'remark-gfm' 5 | 6 | type Locale = { 7 | strike: string 8 | strikeText: string 9 | task: string 10 | taskText: string 11 | table: string 12 | tableHeading: string 13 | } 14 | 15 | export interface BytemdPluginGfmOptions extends Options { 16 | locale?: Partial 17 | } 18 | 19 | export default function gfm({ 20 | locale: _locale, 21 | ...remarkGfmOptions 22 | }: BytemdPluginGfmOptions = {}): BytemdPlugin { 23 | const locale = { ...en, ..._locale } as Locale 24 | 25 | return { 26 | remark: (processor) => processor.use(remarkGfm, remarkGfmOptions), 27 | actions: [ 28 | { 29 | title: locale.strike, 30 | icon: icons.Strikethrough, 31 | cheatsheet: `~~${locale.strikeText}~~`, 32 | handler: { 33 | type: 'action', 34 | click({ wrapText, editor }) { 35 | wrapText('~~') 36 | editor.focus() 37 | }, 38 | }, 39 | }, 40 | { 41 | title: locale.task, 42 | icon: icons.CheckCorrect, 43 | cheatsheet: `- [ ] ${locale.taskText}`, 44 | handler: { 45 | type: 'action', 46 | click({ replaceLines, editor }) { 47 | replaceLines((line) => '- [ ] ' + line) 48 | editor.focus() 49 | }, 50 | }, 51 | }, 52 | { 53 | title: locale.table, 54 | icon: icons.InsertTable, 55 | handler: { 56 | type: 'action', 57 | click({ editor, appendBlock, codemirror }) { 58 | const { line } = appendBlock( 59 | `| ${locale.tableHeading} | |\n| --- | --- |\n| | |\n` 60 | ) 61 | editor.setSelection( 62 | codemirror.Pos(line, 2), 63 | codemirror.Pos(line, 2 + locale.tableHeading.length) 64 | ) 65 | editor.focus() 66 | }, 67 | }, 68 | }, 69 | ], 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/vue-next/src/viewer.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 88 | -------------------------------------------------------------------------------- /playground/src/text.md: -------------------------------------------------------------------------------- 1 | --- 2 | # frontmatter: https://jekyllrb.com/docs/front-matter/ 3 | layout: post 4 | title: Blogging Like a Hacker 5 | --- 6 | 7 | ## Markdown Basic Syntax 8 | 9 | I just love **bold text**. Italicized text is the _cat's meow_. At the command prompt, type `nano`. 10 | 11 | My favorite markdown editor is [ByteMD](https://github.com/bytedance/bytemd). 12 | 13 | 1. First item 14 | 2. Second item 15 | 3. Third item 16 | 17 | > Dorothy followed her through many of the beautiful rooms in her castle. 18 | 19 | ```js 20 | import gfm from '@bytemd/plugin-gfm' 21 | import { Editor, Viewer } from 'bytemd' 22 | 23 | const plugins = [ 24 | gfm(), 25 | // Add more plugins here 26 | ] 27 | 28 | const editor = new Editor({ 29 | target: document.body, // DOM to render 30 | props: { 31 | value: '', 32 | plugins, 33 | }, 34 | }) 35 | 36 | editor.on('change', (e) => { 37 | editor.$set({ value: e.detail.value }) 38 | }) 39 | ``` 40 | 41 | ## GFM Extended Syntax 42 | 43 | Automatic URL Linking: https://github.com/bytedance/bytemd 44 | 45 | ~~The world is flat.~~ We now know that the world is round. 46 | 47 | - [x] Write the press release 48 | - [ ] Update the website 49 | - [ ] Contact the media 50 | 51 | | Syntax | Description | 52 | | --------- | ----------- | 53 | | Header | Title | 54 | | Paragraph | Text | 55 | 56 | ## Footnotes 57 | 58 | Here's a simple footnote,[^1] and here's a longer one.[^bignote] 59 | 60 | [^1]: This is the first footnote. 61 | [^bignote]: Here's one with multiple paragraphs and code. 62 | 63 | Indent paragraphs to include them in the footnote. 64 | 65 | `{ my code }` 66 | 67 | Add as many paragraphs as you like. 68 | 69 | ## Gemoji 70 | 71 | Thumbs up: :+1:, thumbs down: :-1:. 72 | 73 | Families: :family_man_man_boy_boy: 74 | 75 | Long flags: :wales:, :scotland:, :england:. 76 | 77 | ## Math Equation 78 | 79 | Inline math equation: $a+b$ 80 | 81 | $$ 82 | \displaystyle \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) 83 | $$ 84 | 85 | ## Mermaid Diagrams 86 | 87 | ```mermaid 88 | graph TD; 89 | A-->B; 90 | A-->C; 91 | B-->D; 92 | C-->D; 93 | ``` 94 | -------------------------------------------------------------------------------- /examples/react/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | -------------------------------------------------------------------------------- /packages/bytemd/src/toc.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 53 | 54 |
55 |

{locale.toc}

56 |
    57 | {#each items as item, index} 58 |
  • { 64 | dispatch('click', index) 65 | }} 66 | on:keydown|self={(e) => { 67 | if (['Enter', 'Space'].includes(e.code)) { 68 | dispatch('click', index) 69 | } 70 | }} 71 | > 72 | {item.text} 73 |
  • 74 | {/each} 75 |
76 |
77 | -------------------------------------------------------------------------------- /examples/react-nextjs/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bytemd/monorepo", 3 | "private": true, 4 | "workspaces": [ 5 | "packages/*" 6 | ], 7 | "scripts": { 8 | "build": "pnpm clean && node scripts/build.mjs && tsc --build", 9 | "clean": "rm -rf packages/*/tsconfig.tsbuildinfo && rm -rf packages/*/dist", 10 | "dev": "pnpm --filter playground dev", 11 | "format": "prettier --write '**/*.{ts,tsx,json,md,svelte}' && sort-package-json package.json 'packages/*/package.json'", 12 | "postinstall": "node scripts/postinstall.mjs && pnpm format && sort-json packages/*/locales/*.json", 13 | "pub": "pnpm build && lerna publish", 14 | "style": "prettier --check '**/*.{ts,tsx,json,md,svelte}'", 15 | "test": "vitest" 16 | }, 17 | "prettier": { 18 | "pluginSearchDirs": [ 19 | "." 20 | ], 21 | "proseWrap": "never", 22 | "semi": false, 23 | "singleQuote": true 24 | }, 25 | "devDependencies": { 26 | "@icon-park/svg": "^1.4.2", 27 | "@sveltejs/vite-plugin-svelte": "2.0.4", 28 | "@testing-library/jest-dom": "^5.16.5", 29 | "@testing-library/svelte": "^3.2.2", 30 | "@trivago/prettier-plugin-sort-imports": "^4.1.1", 31 | "@types/fs-extra": "^11.0.1", 32 | "@types/lodash-es": "^4.17.7", 33 | "@types/resolve": "^1.20.2", 34 | "conventional-changelog-cli": "^2.2.2", 35 | "decode-named-character-reference": "^1.0.2", 36 | "execa": "^7.1.1", 37 | "fast-glob": "^3.2.12", 38 | "fs-extra": "^11.1.1", 39 | "jsdom": "^21.1.1", 40 | "lerna": "^6.6.1", 41 | "lodash-es": "^4.17.21", 42 | "mustache": "^4.2.0", 43 | "prettier": "^2.8.7", 44 | "prettier-plugin-svelte": "^2.10.0", 45 | "resolve": "^1.22.1", 46 | "sass": "^1.60.0", 47 | "sort-json": "^2.0.1", 48 | "sort-package-json": "^2.4.1", 49 | "svelte": "^3.57.0", 50 | "svelte-preprocess": "^5.0.3", 51 | "svelte2tsx": "^0.6.10", 52 | "svgo": "^3.0.2", 53 | "typescript": "^5.0.2", 54 | "vite": "^4.2.1", 55 | "vitest": "^0.29.8" 56 | }, 57 | "packageManager": "pnpm@8.15.9+sha512.499434c9d8fdd1a2794ebf4552b3b25c0a633abcee5bb15e7b5de90f32f47b513aca98cd5cfd001c31f0db454bc3804edccd578501e4ca293a6816166bbd9f81", 58 | "bundlewatch": { 59 | "files": [ 60 | { 61 | "path": "packages/*/dist/index.umd.js" 62 | } 63 | ], 64 | "ci": { 65 | "repoBranchBase": "main", 66 | "trackBranches": [ 67 | "main" 68 | ] 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/bytemd/src/viewer.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | 93 | 94 |
95 | {@html html} 96 |
97 | -------------------------------------------------------------------------------- /examples/vue-nuxtjs/README.md: -------------------------------------------------------------------------------- 1 | # vue-nuxtjs 2 | 3 | ## Build Setup 4 | 5 | ```bash 6 | # install dependencies 7 | $ yarn install 8 | 9 | # serve with hot reload at localhost:3000 10 | $ yarn dev 11 | 12 | # build for production and launch server 13 | $ yarn build 14 | $ yarn start 15 | 16 | # generate static project 17 | $ yarn generate 18 | ``` 19 | 20 | For detailed explanation on how things work, check out the [documentation](https://nuxtjs.org). 21 | 22 | ## Special Directories 23 | 24 | You can create the following extra directories, some of which have special behaviors. Only `pages` is required; you can delete them if you don't want to use their functionality. 25 | 26 | ### `assets` 27 | 28 | The assets directory contains your uncompiled assets such as Stylus or Sass files, images, or fonts. 29 | 30 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/assets). 31 | 32 | ### `components` 33 | 34 | The components directory contains your Vue.js components. Components make up the different parts of your page and can be reused and imported into your pages, layouts and even other components. 35 | 36 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/components). 37 | 38 | ### `layouts` 39 | 40 | Layouts are a great help when you want to change the look and feel of your Nuxt app, whether you want to include a sidebar or have distinct layouts for mobile and desktop. 41 | 42 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/layouts). 43 | 44 | ### `pages` 45 | 46 | This directory contains your application views and routes. Nuxt will read all the `*.vue` files inside this directory and setup Vue Router automatically. 47 | 48 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/get-started/routing). 49 | 50 | ### `plugins` 51 | 52 | The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use `Vue.use()`, you should create a file in `plugins/` and add its path to plugins in `nuxt.config.js`. 53 | 54 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/plugins). 55 | 56 | ### `static` 57 | 58 | This directory contains your static files. Each file inside this directory is mapped to `/`. 59 | 60 | Example: `/static/robots.txt` is mapped as `/robots.txt`. 61 | 62 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/static). 63 | 64 | ### `store` 65 | 66 | This directory contains your Vuex store files. Creating a file in this directory automatically activates Vuex. 67 | 68 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/store). 69 | -------------------------------------------------------------------------------- /packages/bytemd/test/editor.test.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { Editor } from '../src' 3 | import '@testing-library/jest-dom' 4 | import { 5 | render, 6 | cleanup, 7 | fireEvent, 8 | act, 9 | RenderResult, 10 | } from '@testing-library/svelte' 11 | 12 | function sleep(ms: number = 0) { 13 | return new Promise((r) => setTimeout(r, ms)) 14 | } 15 | 16 | function getCodeMirror($: RenderResult) { 17 | const dom = $.container.querySelector('.CodeMirror') as any 18 | return dom.CodeMirror as CodeMirror.Editor 19 | } 20 | 21 | function stripComment(str: string) { 22 | return str.replace(/<\!--.*?-->/g, '') 23 | } 24 | 25 | const heading = '# title' 26 | const headingHtml = '

title

' 27 | const paragraph = 'abc' 28 | const paragraphHtml = '

abc

' 29 | 30 | beforeEach(() => { 31 | cleanup() 32 | }) 33 | 34 | test('value', async () => { 35 | const $ = render(Editor, { value: heading }) 36 | const onChange = vi.fn() 37 | $.component.$on('change', onChange) 38 | await act() 39 | expect(getCodeMirror($).getValue()).toEqual(heading) 40 | 41 | // // change from UI 42 | // getCodeMirror($).setValue(paragraph); 43 | // await act(); 44 | // expect(getCodeMirror($).getValue()).toEqual(paragraph); 45 | // expect(onChange).toBeCalled(); 46 | // expect(onChange).toBeCalledTimes(1); 47 | // // expect(onChange).toBeCalledWith() 48 | 49 | // change from props 50 | $.component.$set({ value: heading }) 51 | expect(getCodeMirror($).getValue()).toEqual(heading) 52 | expect(onChange).not.toBeCalled() 53 | }) 54 | 55 | test('preview debounce', async () => { 56 | const $ = render(Editor, {}) 57 | $.component.$set({ value: paragraph }) 58 | expect( 59 | stripComment($.container.querySelector('.markdown-body').innerHTML) 60 | ).toEqual('') 61 | await sleep(400) 62 | expect( 63 | stripComment($.container.querySelector('.markdown-body').innerHTML) 64 | ).toEqual(paragraphHtml) 65 | }) 66 | 67 | describe('mode', () => { 68 | test('split', async () => { 69 | const $ = render(Editor, { mode: 'split' }) 70 | await act() 71 | expect($.container.querySelector('.bytemd-editor')).toBeVisible() 72 | expect($.container.querySelector('.bytemd-preview')).toBeVisible() 73 | }) 74 | 75 | test('tab', async () => { 76 | const $ = render(Editor, { mode: 'tab' }) 77 | const write = $.getByText('Write') 78 | const preview = $.getByText('Preview') 79 | 80 | expect($.container.querySelector('.bytemd-editor')).toBeVisible() 81 | expect(write).toHaveClass('bytemd-toolbar-tab-active') 82 | // expect($.container.querySelector('.bytemd-preview')).toHaveStyle('width:0'); 83 | expect(preview).not.toHaveClass('bytemd-toolbar-tab-active') 84 | 85 | await fireEvent.click(preview) 86 | // expect($.container.querySelector('.bytemd-editor')).toHaveStyle('width:0'); 87 | expect(write).not.toHaveClass('bytemd-toolbar-tab-active') 88 | expect($.container.querySelector('.bytemd-preview')).toBeVisible() 89 | expect(preview).toHaveClass('bytemd-toolbar-tab-active') 90 | }) 91 | }) 92 | 93 | describe('plugin', () => { 94 | test('editor effect', async () => { 95 | const $ = render(Editor, {}) 96 | const editorOff = vi.fn() 97 | const editorEffect = vi.fn(() => editorOff) 98 | 99 | $.component.$set({ plugins: [{ editorEffect }] }) 100 | await act() 101 | expect(editorEffect).toBeCalled() 102 | expect(editorEffect).toBeCalledTimes(1) 103 | expect(editorEffect).toBeCalledWith( 104 | expect.objectContaining({ 105 | // $el: $.container.querySelector('.bytemd'), 106 | editor: getCodeMirror($), 107 | }) 108 | ) 109 | 110 | $.component.$set({ plugins: [{ editorEffect }] }) 111 | await act() 112 | expect(editorOff).toBeCalled() 113 | expect(editorOff).toBeCalledTimes(1) 114 | }) 115 | }) 116 | -------------------------------------------------------------------------------- /scripts/postinstall.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { packages, packagesDir, rootDir } from './utils.mjs' 3 | import fs from 'fs-extra' 4 | import _ from 'lodash-es' 5 | import mustache from 'mustache' 6 | import path from 'path' 7 | 8 | function readFileSyncSafe(p) { 9 | try { 10 | return fs.readFileSync(p, 'utf8') 11 | } catch (err) { 12 | return '' 13 | } 14 | } 15 | 16 | const plugins = packages.filter((x) => x.startsWith('plugin-')) 17 | 18 | packages.forEach((p) => { 19 | const tsconfig = path.join(packagesDir, p, 'tsconfig.json') 20 | const c = fs.readJsonSync(tsconfig) 21 | c.include = ['src', 'src/locales/*.json'] // https://github.com/microsoft/TypeScript/issues/25636#issuecomment-627111031 22 | c.compilerOptions = { 23 | rootDir: 'src', 24 | outDir: 'dist', 25 | } 26 | 27 | // tsconfig 28 | fs.writeJsonSync(tsconfig, c) 29 | }) 30 | 31 | fs.writeJsonSync('tsconfig.json', { 32 | files: [], 33 | references: packages.map((p) => ({ path: path.join('packages', p) })), 34 | }) 35 | 36 | packages.forEach((p) => { 37 | // license 38 | fs.copyFileSync( 39 | path.join(rootDir, 'LICENSE'), 40 | path.join(packagesDir, p, 'LICENSE') 41 | ) 42 | 43 | // package.json 44 | const pkgPath = path.join(packagesDir, p, 'package.json') 45 | const pkg = fs.readJsonSync(pkgPath) 46 | pkg.repository = { 47 | type: 'git', 48 | url: 'https://github.com/bytedance/bytemd.git', 49 | directory: `packages/${p}`, 50 | } 51 | 52 | pkg.types = './dist/index.d.ts' 53 | pkg.module = './dist/index.mjs' 54 | pkg.main = './dist/index.js' 55 | pkg.unpkg = './dist/index.umd.js' 56 | pkg.jsdelivr = './dist/index.umd.js' 57 | 58 | pkg.exports = { 59 | '.': { 60 | types: './dist/index.d.ts', 61 | ...(pkg.name === 'bytemd' 62 | ? { 63 | svelte: './svelte/index.js', 64 | } 65 | : {}), 66 | import: './dist/index.mjs', 67 | require: './dist/index.js', 68 | }, 69 | './locales/*': './locales/*', 70 | 71 | // for compatible with old version 72 | './lib/locales/*': './locales/*', 73 | } 74 | pkg.files = ['dist', 'locales'] 75 | 76 | if (pkg.name === 'bytemd') { 77 | pkg.exports['./dist/index.css'] = './dist/index.css' 78 | pkg.exports['./dist/index.min.css'] = './dist/index.min.css' 79 | pkg.files.push('svelte') 80 | } 81 | fs.writeJsonSync(pkgPath, pkg) 82 | }) 83 | 84 | // plugins readme 85 | plugins.forEach((p) => { 86 | const name = p.split('-').slice(1).join('-') 87 | const result = mustache.render( 88 | readFileSyncSafe(path.join(rootDir, 'scripts/plugin-template.md')), 89 | { 90 | name, 91 | importedName: _.camelCase(name.replace('-ssr', '')), 92 | header: p.startsWith('plugin-math') 93 | ? 'import "katex/dist/katex.css"' 94 | : p.startsWith('plugin-highlight') 95 | ? 'import "highlight.js/styles/default.css"' 96 | : '', 97 | desc: fs.readJsonSync(path.join(packagesDir, p, 'package.json')) 98 | .description, 99 | } 100 | ) 101 | fs.writeFileSync(path.join(packagesDir, p, 'README.md'), result) 102 | }) 103 | 104 | // bytemd readme 105 | const readme = readFileSyncSafe(path.join(rootDir, 'README.md')).replace( 106 | /### Official Plugins\s+([\w\W])*?\s+##/, 107 | (match, p1, offset, string) => { 108 | const content = plugins 109 | .map((p) => { 110 | const pkg = fs.readJsonSync(path.join(packagesDir, p, 'package.json')) 111 | if (pkg.private) return 112 | 113 | const name = p.split('-').slice(1).join('-') 114 | const badge = `[![npm](https://img.shields.io/npm/v/@bytemd/plugin-${name}.svg?label=)](https://npm.im/@bytemd/plugin-${name})` 115 | const desc = _.upperFirst( 116 | pkg.description.replace('ByteMD plugin to ', '') 117 | ) 118 | return `| [@bytemd/plugin-${name}](https://github.com/bytedance/bytemd/tree/main/packages/plugin-${name}) | ${badge} | ${desc} |` 119 | }) 120 | .filter((x) => x) 121 | .join('\n') 122 | 123 | return `### Official Plugins 124 | 125 | | Package | Status | Description | 126 | | --- | --- | --- | 127 | ${content} 128 | 129 | ##` 130 | } 131 | ) 132 | 133 | fs.writeFileSync(path.join(rootDir, 'README.md'), readme) 134 | -------------------------------------------------------------------------------- /playground/src/app.svelte: -------------------------------------------------------------------------------- 1 | 82 | 83 |
84 |
85 | Mode: 86 | {#each ['auto', 'split', 'tab'] as m} 87 | 88 | {/each} 89 | , Locale: 90 | 95 | , Max length: 96 | 97 |
98 |
99 | Plugins: 100 | {#each Object.keys(enabled) as p} 101 | {' '} 102 | 103 | {/each} 104 |
105 | 106 | { 114 | return Promise.all( 115 | files.map((file) => { 116 | // TODO: 117 | return { 118 | url: 'https://picsum.photos/300', 119 | } 120 | }) 121 | ) 122 | }} 123 | on:change={(e) => { 124 | value = e.detail.value 125 | }} 126 | /> 127 |
128 | 129 | 154 | -------------------------------------------------------------------------------- /packages/plugin-mermaid/src/index.ts: -------------------------------------------------------------------------------- 1 | import { icons } from './icons' 2 | import en from './locales/en.json' 3 | import type { BytemdPlugin } from 'bytemd' 4 | import type { default as Mermaid, MermaidConfig } from 'mermaid' 5 | 6 | type Locale = { 7 | mermaid: string 8 | flowchart: string 9 | sequence: string 10 | class: string 11 | state: string 12 | er: string 13 | uj: string 14 | gantt: string 15 | pie: string 16 | mindmap: string 17 | timeline: string 18 | } 19 | 20 | export interface BytemdPluginMermaidOptions extends MermaidConfig { 21 | locale?: Partial 22 | } 23 | 24 | export default function mermaid({ 25 | locale: _locale, 26 | ...mermaidConfig 27 | }: BytemdPluginMermaidOptions = {}): BytemdPlugin { 28 | const locale = { ...en, ..._locale } as Locale 29 | let m: typeof Mermaid 30 | 31 | const actionItems = [ 32 | { 33 | title: locale.flowchart, 34 | code: `graph TD 35 | Start --> Stop`, 36 | }, 37 | { 38 | title: locale.sequence, 39 | code: `sequenceDiagram 40 | Alice->>John: Hello John, how are you? 41 | John-->>Alice: Great! 42 | Alice-)John: See you later!`, 43 | }, 44 | { 45 | title: locale.class, 46 | code: `classDiagram 47 | Animal <|-- Duck 48 | Animal <|-- Fish 49 | Animal <|-- Zebra 50 | Animal : +int age 51 | Animal : +String gender 52 | Animal: +isMammal() 53 | Animal: +mate() 54 | class Duck{ 55 | +String beakColor 56 | +swim() 57 | +quack() 58 | } 59 | class Fish{ 60 | -int sizeInFeet 61 | -canEat() 62 | } 63 | class Zebra{ 64 | +bool is_wild 65 | +run() 66 | }`, 67 | }, 68 | { 69 | title: locale.state, 70 | code: `stateDiagram-v2 71 | [*] --> Still 72 | Still --> [*] 73 | 74 | Still --> Moving 75 | Moving --> Still 76 | Moving --> Crash 77 | Crash --> [*]`, 78 | }, 79 | { 80 | title: locale.er, 81 | code: `erDiagram 82 | CUSTOMER ||--o{ ORDER : places 83 | ORDER ||--|{ LINE-ITEM : contains 84 | CUSTOMER }|..|{ DELIVERY-ADDRESS : uses`, 85 | }, 86 | { 87 | title: locale.uj, 88 | code: `journey 89 | title My working day 90 | section Go to work 91 | Make tea: 5: Me 92 | Go upstairs: 3: Me 93 | Do work: 1: Me, Cat 94 | section Go home 95 | Go downstairs: 5: Me 96 | Sit down: 5: Me`, 97 | }, 98 | { 99 | title: locale.gantt, 100 | code: `gantt 101 | title A Gantt Diagram 102 | dateFormat YYYY-MM-DD 103 | section Section 104 | A task :a1, 2014-01-01, 30d 105 | Another task :after a1 , 20d 106 | section Another 107 | Task in sec :2014-01-12 , 12d 108 | another task : 24d`, 109 | }, 110 | { 111 | title: locale.pie, 112 | code: `pie title Pets adopted by volunteers 113 | "Dogs" : 386 114 | "Cats" : 85 115 | "Rats" : 15`, 116 | }, 117 | { 118 | title: locale.mindmap, 119 | code: `mindmap 120 | Root 121 | A 122 | B 123 | C 124 | `, 125 | }, 126 | { 127 | title: locale.timeline, 128 | code: `timeline 129 | title History of Social Media Platform 130 | 2002 : LinkedIn 131 | 2004 : Facebook 132 | : Google 133 | 2005 : Youtube 134 | 2006 : Twitter 135 | `, 136 | }, 137 | ] 138 | 139 | return { 140 | viewerEffect({ markdownBody }) { 141 | ;(async () => { 142 | const els = markdownBody.querySelectorAll( 143 | 'pre>code.language-mermaid' 144 | ) 145 | if (els.length === 0) return 146 | 147 | if (!m) { 148 | m = await import('mermaid').then((c) => c.default) 149 | if (mermaidConfig) { 150 | m.initialize(mermaidConfig) 151 | } 152 | } 153 | 154 | els.forEach((el, i) => { 155 | const pre = el.parentElement! 156 | const source = el.innerText 157 | 158 | const container = document.createElement('div') 159 | container.classList.add('bytemd-mermaid') 160 | container.style.lineHeight = 'initial' // reset line-height 161 | pre.replaceWith(container) 162 | 163 | m.render( 164 | `bytemd-mermaid-${Date.now()}-${i}`, 165 | source, 166 | // @ts-ignore 167 | container 168 | ) 169 | .then((svgCode) => { 170 | // @ts-ignore 171 | container.innerHTML = svgCode.svg 172 | }) 173 | .catch((err) => { 174 | // console.error(err); 175 | }) 176 | }) 177 | })() 178 | }, 179 | actions: [ 180 | { 181 | title: locale.mermaid, 182 | icon: icons.ChartGraph, 183 | cheatsheet: '```mermaid', 184 | handler: { 185 | type: 'dropdown', 186 | actions: actionItems.map(({ title, code }) => ({ 187 | title, 188 | handler: { 189 | type: 'action', 190 | click({ editor, appendBlock, codemirror }) { 191 | const { line } = appendBlock('```mermaid\n' + code + '\n```') 192 | editor.setSelection( 193 | codemirror.Pos(line + 1, 0), 194 | codemirror.Pos(line + code.split('\n').length) 195 | ) 196 | editor.focus() 197 | }, 198 | }, 199 | })), 200 | ...locale, 201 | }, 202 | }, 203 | ], 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /scripts/build.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import { createVue3Plugin } from '../packages/vue-next/plugin.mjs' 3 | import { createVuePlugin } from '../packages/vue/plugin.mjs' 4 | import { packages, packagesDir, sveltePreprocessor } from './utils.mjs' 5 | import { svelte } from '@sveltejs/vite-plugin-svelte' 6 | import { execaCommand } from 'execa' 7 | import glob from 'fast-glob' 8 | import fs from 'fs-extra' 9 | import { camelCase } from 'lodash-es' 10 | import path from 'path' 11 | import resolve from 'resolve' 12 | import { emitDts } from 'svelte2tsx' 13 | import { preprocess } from 'svelte/compiler' 14 | import { build } from 'vite' 15 | 16 | ;(async () => { 17 | for (let name of packages) { 18 | console.log('[building]', name) 19 | 20 | const root = path.resolve(packagesDir, name) 21 | process.chdir(root) 22 | 23 | if (name === 'bytemd') { 24 | // some parts are from here https://github.com/sveltejs/kit/blob/master/packages/kit/src/packaging/typescript.js 25 | await emitDts({ 26 | svelteShimsPath: 'node_modules/svelte2tsx/svelte-shims.d.ts', 27 | declarationDir: './dist', 28 | }) 29 | glob.sync('./dist/src/*.svelte.d.ts').forEach((file) => { 30 | // console.log(file) 31 | fs.moveSync(file, file.replace('/src', '')) 32 | }) 33 | fs.removeSync('./dist/src') 34 | } 35 | 36 | // build js 37 | const pkg = await fs.readJson(path.resolve(root, 'package.json')) 38 | 39 | for (let format of ['es', 'cjs', 'umd']) { 40 | const legacy = format === 'umd' || format === 'iife' 41 | const externalDeps = [] 42 | 43 | if (legacy) { 44 | externalDeps.push(...Object.keys({ ...pkg.peerDependencies })) 45 | } else if (format === 'es') { 46 | externalDeps.push( 47 | ...Object.keys({ 48 | ...pkg.peerDependencies, 49 | ...pkg.dependencies, 50 | }) 51 | ) 52 | } else if (format === 'cjs') { 53 | const deps = Object.keys({ ...pkg.dependencies }) 54 | // exclude esm packages, bundle them to make it work for cjs 55 | .filter((dep) => { 56 | const pkgPath = path.resolve( 57 | root, 58 | 'node_modules', 59 | dep, 60 | 'package.json' 61 | ) 62 | 63 | if (!fs.existsSync(pkgPath)) { 64 | throw new Error(`${dep} not exists, please install it`) 65 | } 66 | 67 | const { type: pkgType } = fs.readJsonSync(pkgPath) 68 | return pkgType !== 'module' 69 | }) 70 | 71 | externalDeps.push(...Object.keys({ ...pkg.peerDependencies }), ...deps) 72 | } 73 | 74 | const alias = { 75 | // https://github.com/rollup/plugins/issues/1159 76 | // for plugin-highlight-ssr 77 | lowlight: 'lowlight/lib/common', 78 | } 79 | 80 | if (format === 'cjs') { 81 | const pkgName = 'decode-named-character-reference' 82 | 83 | // do not resolve `browser` field to make CJS bundle work at SSR 84 | // https://github.com/vitejs/vite/issues/4405 85 | // for bytemd and plugin-gfm 86 | alias[pkgName] = resolve.sync(pkgName) 87 | } 88 | 89 | await build({ 90 | root, 91 | build: { 92 | emptyOutDir: false, 93 | minify: legacy, 94 | target: 'es2019', // nullish coalescing in es2020 95 | lib: { 96 | entry: 'src/index.ts', 97 | name: camelCase(pkg.name), 98 | formats: [format], 99 | fileName: 'index', 100 | }, 101 | rollupOptions: { 102 | external: [ 103 | ...externalDeps, 104 | ...externalDeps.map((dep) => new RegExp(`^${dep}\/`)), 105 | ], 106 | }, 107 | }, 108 | resolve: { alias }, 109 | plugins: [ 110 | name === 'bytemd' && 111 | svelte({ 112 | preprocess: [sveltePreprocessor], 113 | }), 114 | name === 'vue' && createVuePlugin(), 115 | name === 'vue-next' && createVue3Plugin(), 116 | ], 117 | }) 118 | } 119 | 120 | if (name === 'bytemd') { 121 | await fs.emptyDir('svelte') 122 | 123 | console.log('build svelte files...') 124 | const files = await glob('src/*.svelte') 125 | for (let file of files) { 126 | const dest = file.replace('src/', 'svelte/') 127 | await fs.ensureDir(path.dirname(dest)) 128 | 129 | if (fs.statSync(file).isDirectory()) return 130 | 131 | if (file.endsWith('.svelte')) { 132 | const source = await fs.readFile(file, 'utf8') 133 | const item = await preprocess(source, sveltePreprocessor, { 134 | filename: file, 135 | }) 136 | await fs.writeFile( 137 | dest, 138 | item.code.replace('