From 1cd5b63174898a4a1318a8856d9a4c5295db65d7 Mon Sep 17 00:00:00 2001 From: thzxx <1440196015@qq.com> Date: Sat, 25 Jul 2026 08:53:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20v0.2.1=20=E2=80=94=20reference=20links,?= =?UTF-8?q?=20context=20menu,=20RTL,=20ja/ko,=20regex=20search,=20hooks,?= =?UTF-8?q?=20copy=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Added - Reference link/image resolution: [text][ref] + ![alt][ref] with [ref]: url definitions - Right-click context menu: undo/redo/cut/copy/paste/selectAll + custom items - RTL CSS layout support for Arabic, Hebrew, Persian etc. - Japanese (ja) and Korean (ko) locales with 60+ keys each - Divider position localStorage persistence - Regex search toggle in search/replace panel - Export HTML with embedded CSS styles - beforeChange / afterChange lifecycle hooks (instance + global) - copyAsMarkdown() / copyAsHTML() clipboard APIs - CHANGELOG.md, CONTRIBUTING.md, CI workflow (.github/workflows/ci.yml) - 2 new test suites: index.test.ts, styles.test.ts (684 total tests, +74) ## Changed - autoSave plugin: closure-based state per instance instead of this context - Plugin install() now receives options as second argument - RTL locale detection: now uses language prefix (ar-SA → RTL) - Rollup dev mode: only builds UMD format - prepublishOnly now includes typecheck + test - Version bumped to 0.2.1 ## Fixed - [text][ref] now correctly renders as link (was raw text) - ![alt][ref] no longer produces empty src - autoSave plugin state isolation across multiple editor instances - Footnote definitions no longer consumed by refDef handler --- .github/workflows/ci.yml | 46 +++++++++ CHANGELOG.md | 150 +++++++++++++++++++++++++++ CONTRIBUTING.md | 147 ++++++++++++++++++++++++++ README.md | 26 ++++- package.json | 4 +- rollup.config.js | 109 ++++++++++---------- site/demo.html | 14 +-- site/docs.html | 4 +- site/index.html | 12 +-- src/constants.ts | 1 + src/core.ts | 137 +++++++++++++++++++++++- src/i18n.ts | 7 +- src/index.ts | 4 +- src/locales.ts | 50 +++++++++ src/parser.ts | 53 ++++++++-- src/plugins.ts | 160 +++++++++++++++++++++++----- src/styles.ts | 20 +++- tests/core.test.ts | 218 ++++++++++++++++++++++++++++++++++++++- tests/index.test.ts | 181 ++++++++++++++++++++++++++++++++ tests/parser.test.ts | 107 +++++++++++++++++++ tests/plugins.test.ts | 5 +- tests/styles.test.ts | 109 ++++++++++++++++++++ 22 files changed, 1448 insertions(+), 116 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 tests/index.test.ts create mode 100644 tests/styles.test.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cc7fcc8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + test: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x, 18.x, 20.x] + + steps: + - uses: actions/checkout@v4 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Type check + run: npm run typecheck + + - name: Lint + run: npm run lint + + - name: Run tests + run: npm test + + - name: Build + run: npm run build + + - name: Upload coverage + uses: actions/upload-artifact@v4 + if: always() + with: + name: coverage-${{ matrix.node-version }} + path: coverage/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8ca1743 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,150 @@ +# Changelog + +All notable changes to MetonaEditor will be documented in this file. + +## [0.2.1] - 2026-07-25 + +### Added +- **Reference link/image resolution**: Full support for `[text][ref]` and `![alt][ref]` syntax with `[ref]: url` definitions. +- **Right-click context menu**: Built-in undo/redo/cut/copy/paste/selectAll with custom item support. +- **RTL (Right-to-Left) CSS support**: Full RTL layout for Arabic, Hebrew, Persian and other RTL languages. +- **Japanese (ja) and Korean (ko) locales**: Complete translations for all 60+ UI keys. +- **Divider position persistence**: Split-view divider ratio saved to localStorage and restored on reload. +- **Regex search support**: Toggle regex mode in search panel with `.*` button. +- **Export HTML with embedded CSS**: `exportHTML` now includes minimal CSS styles for standalone viewing. +- **`beforeChange` / `afterChange` lifecycle hooks**: Instance and global hooks that fire around content changes. +- **`copyAsMarkdown()` / `copyAsHTML()` APIs**: Copy editor content to clipboard as Markdown or rich HTML. +- **New test suites**: `tests/index.test.ts` (global API) and `tests/styles.test.ts` (CSS injection). +- **684 tests** (up from 610), 9 test suites (up from 7). + +### Changed +- **autoSave plugin refactored**: Uses closure-based state per instance instead of `this` context, preventing state conflicts when the same plugin object is shared across multiple editors. +- **Plugin `install()` now receives `options` as second argument** for cleaner API. +- **RTL locale detection improved**: Now detects RTL by language prefix (e.g., `ar-SA` → RTL). + +### Fixed +- Reference link syntax `[text][ref]` now correctly resolves to links instead of raw text. +- Reference image syntax `![alt][ref]` no longer produces empty `src=""`. +- autoSave plugin state isolation when used across multiple editor instances. +- Footnote definitions no longer incorrectly consumed by reference definition parser. + +--- + +## [0.2.0] - 2026-07-23 + +### Added +- **TypeScript full rewrite**: All 12 source modules in TypeScript strict mode with complete type exports. +- **Parser 99% line coverage**: Self-built Markdown parser with 14 block-level handlers. +- **parseTokens / renderTokens API**: Separate tokenization and rendering for transform pipelines. +- **registerBlockHandler**: Extensible block syntax via handler registration. +- **610 tests**: Comprehensive test coverage across 7 suites. +- **Triple emphasis `***text***`**: Bold+italic combined formatting. +- **Link text inline formatting**: Bold, italic, and code within link text. +- **Backslash escape**: `\*`, `\_`, `\\` for literal punctuation. +- **Tab-indented code blocks**: Tab or 4-space indented code. + +### Changed +- **Plugin system v2**: Topological sort dependency management, 6 preset plugins. +- **Theme system overhaul**: CSS variable-based, instance isolation, external theme following. +- **i18n overhaul**: Instance-level locale isolation, plural rules, remote loading. + +--- + +## [0.1.15] - 2026-07-21 + +### Added +- Parser short and medium-term improvements. +- Triple emphasis syntax `***bold italic***`. +- Link text inline formatting support. +- Backslash escape sequences. +- `parseTokens` / `renderTokens` separation API. + +--- + +## [0.1.14] - 2026-07-20 + +### Added +- Syntax highlighting feature (reverted in 0.1.15). +- Mermaid.js CDN support in demo page. + +--- + +## [0.1.7] - 2026-07-19 + +### Added +- Line number gutter with active line highlighting. +- Smart Enter (list/quote continuation). +- Bracket auto-close with selection wrapping. +- Outline panel. + +--- + +## [0.1.6] - 2026-07-18 + +### Added +- `topologicalSort` for plugin dependency resolution. +- `validateConfig` for plugin configuration validation. +- `editor.unuse()` to uninstall plugins. +- `editor.registerShortcut()` / `unregisterShortcut()`. +- `editor.toast()` notification API. + +--- + +## [0.1.5] - 2026-07-17 + +### Added +- Instance-level theme context (`createInstanceTheme`). +- `followExternalTheme` / `adoptFromParent` for external theme following. +- `exportCSSVars` / `getCSSVariable` for theme inspection. +- `applyThemeToElement` for scoped theme application. + +--- + +## [0.1.4] - 2026-07-16 + +### Added +- Setext headings (underlined H1/H2). +- Nested lists (3+ levels). +- Indented code blocks (4 spaces / tab). +- HTML comment passthrough. +- Entity reference protection. +- Hard line breaks (2 trailing spaces). +- Link titles with single quotes. +- LaTeX math formulas (`$inline$` / `$$block$$`). +- Footnotes `[^id]`. +- Definition lists (`Term\n: definition`). +- Backtick exact matching (`` ` ``). +- Enhanced emoji set (150+). + +--- + +## [0.1.3] - 2026-07-15 + +### Fixed +- `exec` custom action support via `_customActions`. +- `refresh()` method for forced re-render. +- Focus/blur event parameter fixes. + +--- + +## [0.1.2] - 2026-07-14 + +### Added +- Highlight marker `==text==`. +- Superscript `x^2^` and subscript `H~2~O`. +- Emoji shortcodes `:smile:` (100+ emojis). +- Table column alignment (`:---:`, `---:`). +- Read-only mode with `readOnly` config and `setReadOnly()`. + +--- + +## [0.1.0] - 2026-07-10 + +### Added +- Initial release. +- Markdown editor with edit/split/preview modes. +- Self-built parser (CommonMark + GFM). +- Plugin system with autoSave, exportTool, searchReplace. +- Theme system (light/dark/auto). +- i18n (zh-CN/en-US). +- Toolbar, shortcuts, history stack. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..7f5f087 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,147 @@ +# Contributing to MetonaEditor + +Thanks for your interest in contributing! This document outlines the development workflow and conventions. + +## Prerequisites + +- Node.js >= 16.0.0 +- npm >= 8.0.0 + +## Setup + +```bash +git clone https://git.metona.cn/MetonaTeam/MetonaEditor.git +cd MetonaEditor +npm install +``` + +## Development + +```bash +# Start dev server with hot reload (port 3001) +npm run dev + +# Run tests in watch mode +npm run test:watch + +# Type check +npm run typecheck + +# Lint +npm run lint +npm run lint:fix + +# Format +npm run format +``` + +## Project Structure + +``` +src/ +├── index.ts # Entry point, global API +├── core.ts # MarkdownEditor class +├── parser.ts # Markdown parser (tokenizer + renderer) +├── plugins.ts # Plugin system & 6 presets +├── themes.ts # Theme system +├── i18n.ts # Internationalization +├── styles.ts # CSS-in-JS injection +├── constants.ts # Types, defaults, configs +├── utils.ts # Utility functions +├── animations.ts # Animation metadata +├── icons.ts # Toolbar SVG icons +└── locales.ts # Translation data + +tests/ +├── parser.test.ts +├── core.test.ts +├── plugins.test.ts +├── themes.test.ts +├── i18n.test.ts +├── utils.test.ts +├── animations.test.ts +├── index.test.ts +└── styles.test.ts + +site/ +├── index.html # Landing page +├── demo.html # Full-featured demo +└── docs.html # API documentation +``` + +## Code Conventions + +### TypeScript +- **Strict mode** is enabled — all code must pass `tsc --noEmit`. +- Export types explicitly. Avoid `any` where possible. +- Use `interface` for object shapes, `type` for unions/primitives. + +### Style +- Run `npm run format` before committing (uses Prettier). +- Follow existing comment patterns: JSDoc `/** */` for public APIs, `//` for inline notes. +- Keep functions focused and under ~60 lines where practical. + +### Testing +- **Every new feature must include tests.** +- Test files mirror source structure: `src/foo.ts` → `tests/foo.test.ts`. +- Use descriptive test names: `('does X when Y')`. +- Run the full suite before submitting: `npm test`. + +### Commits +- Use conventional commit messages: + - `feat: add reference link resolution` + - `fix: autoSave plugin state conflict` + - `docs: update API reference` + - `test: add index.ts global API tests` + - `chore: optimize rollup dev build` + +## Building + +```bash +# Production build (all formats) +npm run build + +# Output in dist/ +# ├── metona-editor.js UMD +# ├── metona-editor.min.js UMD minified +# ├── metona-editor.esm.js ES Module +# ├── metona-editor.cjs.js CommonJS +# └── metona-editor.d.ts TypeScript declarations +``` + +## Plugin Development + +Plugins follow a simple convention: + +```typescript +const myPlugin = { + name: 'myPlugin', + version: '1.0.0', + description: 'Description of my plugin', + depends: [], // optional: plugin names this depends on + priority: 50, // optional: for topological sort ordering + + install(editor, options?) { + // Called when plugin is installed + // Use editor.on() to subscribe to events + // Return a Promise for async initialization + }, + + destroy(editor) { + // Called when plugin is uninstalled + // Clean up event listeners, timers, DOM nodes + }, +}; +``` + +## Releasing + +1. Update version in `package.json` and `src/index.ts` (`VERSION` constant). +2. Update `CHANGELOG.md`. +3. Run full test suite: `npm test`. +4. Build: `npm run build`. +5. Publish: `npm publish`. + +## Questions? + +Open an issue at [git.metona.cn/MetonaTeam/MetonaEditor/issues](https://git.metona.cn/MetonaTeam/MetonaEditor/issues). diff --git a/README.md b/README.md index c6fcaa2..ffc08a0 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ > TypeScript 重构 · 零运行时依赖 · 轻量级桌面端 Markdown Editor 库 -[![version](https://img.shields.io/badge/version-0.2.0-blue)](https://git.metona.cn/MetonaTeam/-/packages/npm/@metona-team%2Fmetona-editor) +[![version](https://img.shields.io/badge/version-0.2.1-blue)](https://git.metona.cn/MetonaTeam/-/packages/npm/@metona-team%2Fmetona-editor) [![license](https://img.shields.io/badge/license-MIT-green)](./LICENSE) -[![tests](https://img.shields.io/badge/tests-610%20passed-brightgreen)](./tests) +[![tests](https://img.shields.io/badge/tests-684%20passed-brightgreen)](./tests) [![coverage](https://img.shields.io/badge/coverage-parser%2099%25-brightgreen)](./tests) [![types](https://img.shields.io/badge/types-TypeScript%20strict-blue)](./tsconfig.json) @@ -16,10 +16,14 @@ - **插件系统 v2** — 拓扑排序依赖管理,6 个预设插件开箱即用,安装 / 卸载生命周期 - **三模式视图** — edit / split / preview,拖拽分隔条调整比例,双向滚动同步 - **主题系统** — light / dark / warm / auto,CSS 变量可定制,实例级隔离,主题继承,外部跟随 -- **国际化** — zh-CN / en-US 完整翻译,实例级语言隔离,远程加载翻译包 -- **编辑体验** — 行号装订线、智能 Enter、括号自动闭合、拖放文件、大纲面板、Zen 专注模式 +- **国际化** — zh-CN / en-US / ja / ko 完整翻译,实例级语言隔离,远程加载翻译包 +- **编辑体验** — 行号装订线、智能 Enter、括号自动闭合、拖放文件、大纲面板、Zen 专注模式、右键上下文菜单 - **安全** — HTML 转义,XSS 协议过滤(javascript / vbscript / file / data),sanitize 钩子 - **桌面端优先** — 纯电脑端设计,无移动端冗余代码 +- **引用链接** — 支持 `[text][ref]` / `![alt][ref]` 引用式链接和图片,含 title 属性 +- **RTL 支持** — 完整的从右到左布局适配(阿拉伯语、希伯来语等) +- **正则搜索** — 查找替换面板支持正则表达式模式 +- **分隔条记忆** — 分屏比例自动保存到 localStorage --- @@ -287,6 +291,13 @@ editor.toast(message: string, opts?: { }): this ``` +### Copy API + +```typescript +editor.copyAsMarkdown(): this // 复制 Markdown 源码到剪贴板 +editor.copyAsHTML(): this // 复制渲染后的 HTML 到剪贴板 +``` + ### 销毁 ```typescript @@ -352,6 +363,9 @@ import { parseMarkdown, parseTokens, renderTokens, safeUrl, slugify, registerBlo | `linkClick` | 预览区链接点击 | `({ href, text })` | | `fileOpened` | fileSystem 打开文件 | `({ name, handle })` | | `fileSaved` | fileSystem 保存文件 | `({ handle })` | +| `beforeChange` | 内容变更前 | `(oldValue, newValue, editor)` | +| `afterChange` | 内容变更后 | `(newValue, editor)` | +| `copy` | 复制到剪贴板 | `({ type })` | ### 全局钩子 @@ -363,6 +377,8 @@ import { parseMarkdown, parseTokens, renderTokens, safeUrl, slugify, registerBlo | `afterRender` | 每次渲染后(全局) | | `beforeDestroy` | destroy 前 | | `afterDestroy` | destroy 后 | +| `beforeChange` | 内容变更前(全局) | +| `afterChange` | 内容变更后(全局) | --- @@ -393,6 +409,8 @@ import { parseMarkdown, parseTokens, renderTokens, safeUrl, slugify, registerBlo | 表格 | `\| a \| b \|` | `` + 列对齐 | | 链接 | `[text](url 'title')` | `` | | 图片 | `![alt](url)` | `` | +| 引用链接 | `[text][ref]` + `[ref]: url` | `` | +| 引用图片 | `![alt][ref]` + `[ref]: url` | `` | | 自动链接 | `` | `` | | 数学公式 | `$E=mc^2$` `$$\int$$` | `` / `
` | | 脚注 | `text[^1]` | `` + 底部定义 | diff --git a/package.json b/package.json index e4064eb..5dc903d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@metona-team/metona-editor", - "version": "0.2.0", + "version": "0.2.1", "description": "Type-safe, lightweight, zero-dependency Markdown Editor. Desktop-first. React-free. Single-file bundle.", "type": "module", "main": "dist/metona-editor.js", @@ -30,7 +30,7 @@ "lint:fix": "eslint src/ --fix", "format": "prettier --write src/", "typecheck": "tsc --noEmit", - "prepublishOnly": "npm run build" + "prepublishOnly": "npm run typecheck && npm test && npm run build" }, "repository": { "type": "git", diff --git a/rollup.config.js b/rollup.config.js index a93879c..a25ba0c 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -55,61 +55,64 @@ export default [ }, plugins: [...basePlugins, ...devPlugins], }, - // ES Module - { - input: 'src/index.ts', - output: { - file: 'dist/metona-editor.esm.js', - format: 'es', - exports: 'named', - sourcemap: true, + // Only build all formats in production + ...(isDev ? [] : [ + // ES Module + { + input: 'src/index.ts', + output: { + file: 'dist/metona-editor.esm.js', + format: 'es', + exports: 'named', + sourcemap: true, + }, + plugins: basePlugins, }, - plugins: basePlugins, - }, - // CommonJS - { - input: 'src/index.ts', - output: { - file: 'dist/metona-editor.cjs.js', - format: 'cjs', - exports: 'named', - sourcemap: true, + // CommonJS + { + input: 'src/index.ts', + output: { + file: 'dist/metona-editor.cjs.js', + format: 'cjs', + exports: 'named', + sourcemap: true, + }, + plugins: basePlugins, }, - plugins: basePlugins, - }, - // UMD minified - { - input: 'src/index.ts', - output: { - file: 'dist/metona-editor.min.js', - format: 'umd', - name: 'MeEditor', - exports: 'named', - sourcemap: false, + // UMD minified + { + input: 'src/index.ts', + output: { + file: 'dist/metona-editor.min.js', + format: 'umd', + name: 'MeEditor', + exports: 'named', + sourcemap: false, + }, + plugins: [ + ...basePlugins, + terser({ + compress: { + drop_console: true, + drop_debugger: true, + pure_funcs: ['console.log', 'console.warn'], + passes: 2, + }, + format: { comments: false }, + mangle: { toplevel: true }, + }), + ], }, - plugins: [ - ...basePlugins, - terser({ - compress: { - drop_console: true, - drop_debugger: true, - pure_funcs: ['console.log', 'console.warn'], - passes: 2, - }, - format: { comments: false }, - mangle: { toplevel: true }, - }), - ], - }, - // TypeScript declarations bundle - { - input: 'src/index.ts', - output: { - file: 'dist/metona-editor.d.ts', - format: 'es', + // TypeScript declarations bundle + { + input: 'src/index.ts', + output: { + file: 'dist/metona-editor.d.ts', + format: 'es', + }, + plugins: [ + dts(), + ], }, - plugins: [ - dts(), - ], - }, + ]), ]; diff --git a/site/demo.html b/site/demo.html index 22f8aeb..990f049 100644 --- a/site/demo.html +++ b/site/demo.html @@ -45,11 +45,11 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
-

MetonaEditor v0.2.0

+

MetonaEditor v0.2.1

TypeScript 零运行时依赖 - 610 tests + 684 tests 6 个插件 桌面端优先
@@ -60,7 +60,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr - + @@ -90,7 +90,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
@@ -98,12 +98,12 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr