feat: v0.2.4 — 搜索面板全面重设计 + 完整安装文档
### Changed - 搜索面板:暗色玻璃拟态设计,SVG 图标,流畅动画,改进间距和焦点状态 - README / site:补全 npm / CDN / ESM / CJS / 浏览器五种安装方式 ### Fixed - CI 卡死:移除 setInterval,改用纯事件驱动 - 浮动工具栏定位修正 - 浮动工具栏开关按钮修复
This commit is contained in:
@@ -2,6 +2,19 @@
|
||||
|
||||
All notable changes to MetonaEditor will be documented in this file.
|
||||
|
||||
## [0.2.4] - 2026-07-25
|
||||
|
||||
### Changed
|
||||
- **Search panel redesigned**: Dark-themed glass-morphism design with SVG icons, smooth animation, improved spacing and focus states.
|
||||
- **README & site install instructions**: Complete npm/CDN/ESM/CJS/Browser import examples added.
|
||||
|
||||
### Fixed
|
||||
- **CI hang**: Removed `setInterval` polling in floating toolbar; now uses pure event-driven selection detection.
|
||||
- **Floating toolbar positioning**: Corrected coordinate system (viewport→pane-local) for accurate placement near selected text.
|
||||
- **Floating toolbar toggle button**: Now properly disables/enables via `toggleFloatingToolbar()` API.
|
||||
|
||||
---
|
||||
|
||||
## [0.2.3] - 2026-07-25
|
||||
|
||||
### Added
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
> TypeScript 重构 · 零运行时依赖 · 轻量级桌面端 Markdown Editor 库
|
||||
|
||||
[](https://git.metona.cn/MetonaTeam/-/packages/npm/@metona-team%2Fmetona-editor)
|
||||
[](https://git.metona.cn/MetonaTeam/-/packages/npm/@metona-team%2Fmetona-editor)
|
||||
[](./LICENSE)
|
||||
[](./tests)
|
||||
[](./tests)
|
||||
[](./tests)
|
||||
[](./tsconfig.json)
|
||||
|
||||
@@ -46,32 +46,71 @@
|
||||
|
||||
## 快速开始
|
||||
|
||||
### npm 安装
|
||||
### 方式一:npm 安装(推荐)
|
||||
|
||||
```bash
|
||||
npm install @metona-team/metona-editor
|
||||
```
|
||||
|
||||
```typescript
|
||||
// ES Module / TypeScript
|
||||
import MeEditor from '@metona-team/metona-editor';
|
||||
|
||||
const editor = MeEditor.create('#editor', {
|
||||
value: '# Hello World',
|
||||
mode: 'split',
|
||||
theme: 'auto',
|
||||
plugins: ['autoSave', 'searchReplace'],
|
||||
});
|
||||
```
|
||||
|
||||
### CDN 引入
|
||||
```javascript
|
||||
// CommonJS
|
||||
const MeEditor = require('@metona-team/metona-editor');
|
||||
|
||||
const editor = MeEditor.create('#editor', { mode: 'split' });
|
||||
```
|
||||
|
||||
### 方式二:CDN 引入
|
||||
|
||||
```html
|
||||
<div id="editor"></div>
|
||||
<!-- jsDelivr CDN (推荐) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/@metona-team/metona-editor@0.2.4/dist/metona-editor.min.js"></script>
|
||||
|
||||
<!-- unpkg CDN -->
|
||||
<script src="https://unpkg.com/@metona-team/metona-editor@0.2.4/dist/metona-editor.min.js"></script>
|
||||
|
||||
<!-- Gitea 源 -->
|
||||
<script src="https://git.metona.cn/MetonaTeam/MetonaEditor/raw/branch/master/dist/metona-editor.js"></script>
|
||||
|
||||
<div id="editor"></div>
|
||||
<script>
|
||||
const editor = MeEditor.create('#editor', { mode: 'split' });
|
||||
</script>
|
||||
```
|
||||
|
||||
### 方式三:本地文件
|
||||
|
||||
```bash
|
||||
# 下载产物文件到项目中
|
||||
# dist/metona-editor.js → UMD (浏览器)
|
||||
# dist/metona-editor.min.js → UMD 压缩
|
||||
# dist/metona-editor.esm.js → ES Module
|
||||
# dist/metona-editor.cjs.js → CommonJS
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- 浏览器直接引入本地文件 -->
|
||||
<script src="./dist/metona-editor.min.js"></script>
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Node.js ESM
|
||||
import MeEditor from './dist/metona-editor.esm.js';
|
||||
// Node.js CJS
|
||||
const MeEditor = require('./dist/metona-editor.cjs.js');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置项
|
||||
|
||||
Vendored
+4
-4
@@ -1824,7 +1824,7 @@ const searchReplacePlugin = {
|
||||
if (!document.getElementById('me-search-style')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'me-search-style';
|
||||
style.textContent = `.me-search{position:absolute;top:8px;right:12px;z-index:20;display:flex;flex-direction:column;gap:6px;padding:8px;background:var(--md-toolbar-bg,#f8f9fa);border:1px solid var(--md-border,rgba(0,0,0,0.1));border-radius:8px;box-shadow:0 8px 24px -8px rgba(0,0,0,0.2);font-size:13px;min-width:280px}.me-search-row{display:flex;gap:4px;align-items:center}.me-search input{flex:1;min-width:0;padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));border-radius:4px;background:var(--md-textarea-bg,#fff);color:var(--md-text,#1f2937);font-size:13px}.me-search input:focus{outline:none;border-color:var(--md-accent,#3b82f6)}.me-search button{padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));background:var(--md-bg,#fff);color:var(--md-text,#1f2937);border-radius:4px;cursor:pointer;font-size:12px;line-height:1}.me-search button:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-count{color:var(--md-muted,#6b7280);font-size:12px;min-width:60px;text-align:center}.me-search .me-search-close{padding:2px 6px}`;
|
||||
style.textContent = `.me-search{position:absolute;top:10px;right:16px;z-index:20;display:flex;flex-direction:column;gap:8px;padding:12px;background:var(--md-bg,#1c2029);border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:10px;box-shadow:0 12px 40px -8px rgba(0,0,0,0.4),0 0 0 1px rgba(255,255,255,0.05);font-size:13px;min-width:300px;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);animation:meSearchIn .18s ease-out}@keyframes meSearchIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.me-search-row{display:flex;gap:6px;align-items:center}.me-search-row+.me-search-row{margin-top:2px}.me-search input{flex:1;min-width:0;padding:7px 10px;border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:6px;background:var(--md-textarea-bg,rgba(255,255,255,0.04));color:var(--md-text,#e6e8eb);font-size:13px;outline:none;transition:border-color .15s,box-shadow .15s}.me-search input::placeholder{color:var(--md-muted,#6b7280)}.me-search input:focus{border-color:var(--md-accent,#3b82f6);box-shadow:0 0 0 3px rgba(59,130,246,0.15)}.me-search .me-search-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid rgba(255,255,255,0.08);border-radius:5px;background:rgba(255,255,255,0.04);color:var(--md-muted,#9ca3af);cursor:pointer;transition:all .12s;flex-shrink:0}.me-search .me-search-btn:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn:active{transform:scale(.92)}.me-search .me-search-btn.me-active{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn svg{width:14px;height:14px}.me-search .me-search-count{color:var(--md-muted,#9ca3af);font-size:11.5px;min-width:28px;text-align:center;font-variant-numeric:tabular-nums}.me-search .me-search-close{margin-left:2px;font-size:16px;line-height:1}.me-search .me-search-close:hover{background:#ef4444;border-color:#ef4444}.me-search .me-search-replace-one,.me-search .me-search-replace-all{width:auto;padding:5px 10px;font-size:12px;font-weight:500;letter-spacing:.01em}.me-search .me-search-replace-all{background:rgba(59,130,246,0.12);border-color:rgba(59,130,246,0.3);color:var(--md-accent,#60a5fa)}.me-search .me-search-replace-all:hover{background:var(--md-accent,#3b82f6);color:#fff}`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
const state = {
|
||||
@@ -1864,7 +1864,7 @@ const searchReplacePlugin = {
|
||||
const panel = document.createElement('div');
|
||||
panel.className = 'me-search';
|
||||
panel.dataset.replace = showReplace ? '1' : '0';
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder') || 'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-prev">↑</button><button class="me-search-next">↓</button><span class="me-search-count"></span><button class="me-search-regex" title="Regex">.*</button><button class="me-search-close">×</button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder') || 'Replace'}"/><button class="me-search-replace-one">${t('replace') || 'Replace'}</button><button class="me-search-replace-all">${t('replaceAll') || 'All'}</button></div>`;
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder') || 'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-btn me-search-prev" title="${t('findPrev') || 'Previous'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></button><button class="me-search-btn me-search-next" title="${t('findNext') || 'Next'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button><span class="me-search-count"></span><button class="me-search-btn me-search-regex" title="Regex">.*</button><button class="me-search-btn me-search-close" title="${t('close') || 'Close'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder') || 'Replace'}"/><button class="me-search-btn me-search-replace-one">${t('replace') || 'Replace'}</button><button class="me-search-btn me-search-replace-all">${t('replaceAll') || 'All'}</button></div>`;
|
||||
editor.el.appendChild(panel);
|
||||
state._panel = panel;
|
||||
_updateReplaceVisible();
|
||||
@@ -4392,9 +4392,9 @@ const animationUtils = {
|
||||
/**
|
||||
* MetonaEditor — Type-safe, lightweight Markdown Editor
|
||||
* @module metona-editor
|
||||
* @version 0.2.3
|
||||
* @version 0.2.4
|
||||
*/
|
||||
const VERSION = '0.2.3';
|
||||
const VERSION = '0.2.4';
|
||||
const globalPlugins = [];
|
||||
MarkdownEditor.on('beforeCreate', (editor) => {
|
||||
if (!editor || editor.isDestroyed())
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -507,7 +507,7 @@ declare const animationUtils: {
|
||||
destroy(): void;
|
||||
};
|
||||
|
||||
declare const VERSION = "0.2.3";
|
||||
declare const VERSION = "0.2.4";
|
||||
declare function create(container: string | HTMLElement, options?: EditorOptions): MarkdownEditor;
|
||||
declare function use(plugin: string | any, options?: any): typeof api;
|
||||
declare function on(name: string, fn: (editor: MarkdownEditor) => void): () => void;
|
||||
|
||||
Vendored
+4
-4
@@ -1820,7 +1820,7 @@ const searchReplacePlugin = {
|
||||
if (!document.getElementById('me-search-style')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'me-search-style';
|
||||
style.textContent = `.me-search{position:absolute;top:8px;right:12px;z-index:20;display:flex;flex-direction:column;gap:6px;padding:8px;background:var(--md-toolbar-bg,#f8f9fa);border:1px solid var(--md-border,rgba(0,0,0,0.1));border-radius:8px;box-shadow:0 8px 24px -8px rgba(0,0,0,0.2);font-size:13px;min-width:280px}.me-search-row{display:flex;gap:4px;align-items:center}.me-search input{flex:1;min-width:0;padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));border-radius:4px;background:var(--md-textarea-bg,#fff);color:var(--md-text,#1f2937);font-size:13px}.me-search input:focus{outline:none;border-color:var(--md-accent,#3b82f6)}.me-search button{padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));background:var(--md-bg,#fff);color:var(--md-text,#1f2937);border-radius:4px;cursor:pointer;font-size:12px;line-height:1}.me-search button:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-count{color:var(--md-muted,#6b7280);font-size:12px;min-width:60px;text-align:center}.me-search .me-search-close{padding:2px 6px}`;
|
||||
style.textContent = `.me-search{position:absolute;top:10px;right:16px;z-index:20;display:flex;flex-direction:column;gap:8px;padding:12px;background:var(--md-bg,#1c2029);border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:10px;box-shadow:0 12px 40px -8px rgba(0,0,0,0.4),0 0 0 1px rgba(255,255,255,0.05);font-size:13px;min-width:300px;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);animation:meSearchIn .18s ease-out}@keyframes meSearchIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.me-search-row{display:flex;gap:6px;align-items:center}.me-search-row+.me-search-row{margin-top:2px}.me-search input{flex:1;min-width:0;padding:7px 10px;border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:6px;background:var(--md-textarea-bg,rgba(255,255,255,0.04));color:var(--md-text,#e6e8eb);font-size:13px;outline:none;transition:border-color .15s,box-shadow .15s}.me-search input::placeholder{color:var(--md-muted,#6b7280)}.me-search input:focus{border-color:var(--md-accent,#3b82f6);box-shadow:0 0 0 3px rgba(59,130,246,0.15)}.me-search .me-search-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid rgba(255,255,255,0.08);border-radius:5px;background:rgba(255,255,255,0.04);color:var(--md-muted,#9ca3af);cursor:pointer;transition:all .12s;flex-shrink:0}.me-search .me-search-btn:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn:active{transform:scale(.92)}.me-search .me-search-btn.me-active{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn svg{width:14px;height:14px}.me-search .me-search-count{color:var(--md-muted,#9ca3af);font-size:11.5px;min-width:28px;text-align:center;font-variant-numeric:tabular-nums}.me-search .me-search-close{margin-left:2px;font-size:16px;line-height:1}.me-search .me-search-close:hover{background:#ef4444;border-color:#ef4444}.me-search .me-search-replace-one,.me-search .me-search-replace-all{width:auto;padding:5px 10px;font-size:12px;font-weight:500;letter-spacing:.01em}.me-search .me-search-replace-all{background:rgba(59,130,246,0.12);border-color:rgba(59,130,246,0.3);color:var(--md-accent,#60a5fa)}.me-search .me-search-replace-all:hover{background:var(--md-accent,#3b82f6);color:#fff}`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
const state = {
|
||||
@@ -1860,7 +1860,7 @@ const searchReplacePlugin = {
|
||||
const panel = document.createElement('div');
|
||||
panel.className = 'me-search';
|
||||
panel.dataset.replace = showReplace ? '1' : '0';
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder') || 'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-prev">↑</button><button class="me-search-next">↓</button><span class="me-search-count"></span><button class="me-search-regex" title="Regex">.*</button><button class="me-search-close">×</button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder') || 'Replace'}"/><button class="me-search-replace-one">${t('replace') || 'Replace'}</button><button class="me-search-replace-all">${t('replaceAll') || 'All'}</button></div>`;
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder') || 'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-btn me-search-prev" title="${t('findPrev') || 'Previous'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></button><button class="me-search-btn me-search-next" title="${t('findNext') || 'Next'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button><span class="me-search-count"></span><button class="me-search-btn me-search-regex" title="Regex">.*</button><button class="me-search-btn me-search-close" title="${t('close') || 'Close'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder') || 'Replace'}"/><button class="me-search-btn me-search-replace-one">${t('replace') || 'Replace'}</button><button class="me-search-btn me-search-replace-all">${t('replaceAll') || 'All'}</button></div>`;
|
||||
editor.el.appendChild(panel);
|
||||
state._panel = panel;
|
||||
_updateReplaceVisible();
|
||||
@@ -4388,9 +4388,9 @@ const animationUtils = {
|
||||
/**
|
||||
* MetonaEditor — Type-safe, lightweight Markdown Editor
|
||||
* @module metona-editor
|
||||
* @version 0.2.3
|
||||
* @version 0.2.4
|
||||
*/
|
||||
const VERSION = '0.2.3';
|
||||
const VERSION = '0.2.4';
|
||||
const globalPlugins = [];
|
||||
MarkdownEditor.on('beforeCreate', (editor) => {
|
||||
if (!editor || editor.isDestroyed())
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+4
-4
@@ -1826,7 +1826,7 @@ dl{margin:.8em 0}dt{font-weight:650;margin:.6em 0 .2em}dd{margin:0 0 .3em 1.6em;
|
||||
if (!document.getElementById('me-search-style')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'me-search-style';
|
||||
style.textContent = `.me-search{position:absolute;top:8px;right:12px;z-index:20;display:flex;flex-direction:column;gap:6px;padding:8px;background:var(--md-toolbar-bg,#f8f9fa);border:1px solid var(--md-border,rgba(0,0,0,0.1));border-radius:8px;box-shadow:0 8px 24px -8px rgba(0,0,0,0.2);font-size:13px;min-width:280px}.me-search-row{display:flex;gap:4px;align-items:center}.me-search input{flex:1;min-width:0;padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));border-radius:4px;background:var(--md-textarea-bg,#fff);color:var(--md-text,#1f2937);font-size:13px}.me-search input:focus{outline:none;border-color:var(--md-accent,#3b82f6)}.me-search button{padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));background:var(--md-bg,#fff);color:var(--md-text,#1f2937);border-radius:4px;cursor:pointer;font-size:12px;line-height:1}.me-search button:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-count{color:var(--md-muted,#6b7280);font-size:12px;min-width:60px;text-align:center}.me-search .me-search-close{padding:2px 6px}`;
|
||||
style.textContent = `.me-search{position:absolute;top:10px;right:16px;z-index:20;display:flex;flex-direction:column;gap:8px;padding:12px;background:var(--md-bg,#1c2029);border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:10px;box-shadow:0 12px 40px -8px rgba(0,0,0,0.4),0 0 0 1px rgba(255,255,255,0.05);font-size:13px;min-width:300px;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);animation:meSearchIn .18s ease-out}@keyframes meSearchIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.me-search-row{display:flex;gap:6px;align-items:center}.me-search-row+.me-search-row{margin-top:2px}.me-search input{flex:1;min-width:0;padding:7px 10px;border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:6px;background:var(--md-textarea-bg,rgba(255,255,255,0.04));color:var(--md-text,#e6e8eb);font-size:13px;outline:none;transition:border-color .15s,box-shadow .15s}.me-search input::placeholder{color:var(--md-muted,#6b7280)}.me-search input:focus{border-color:var(--md-accent,#3b82f6);box-shadow:0 0 0 3px rgba(59,130,246,0.15)}.me-search .me-search-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid rgba(255,255,255,0.08);border-radius:5px;background:rgba(255,255,255,0.04);color:var(--md-muted,#9ca3af);cursor:pointer;transition:all .12s;flex-shrink:0}.me-search .me-search-btn:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn:active{transform:scale(.92)}.me-search .me-search-btn.me-active{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn svg{width:14px;height:14px}.me-search .me-search-count{color:var(--md-muted,#9ca3af);font-size:11.5px;min-width:28px;text-align:center;font-variant-numeric:tabular-nums}.me-search .me-search-close{margin-left:2px;font-size:16px;line-height:1}.me-search .me-search-close:hover{background:#ef4444;border-color:#ef4444}.me-search .me-search-replace-one,.me-search .me-search-replace-all{width:auto;padding:5px 10px;font-size:12px;font-weight:500;letter-spacing:.01em}.me-search .me-search-replace-all{background:rgba(59,130,246,0.12);border-color:rgba(59,130,246,0.3);color:var(--md-accent,#60a5fa)}.me-search .me-search-replace-all:hover{background:var(--md-accent,#3b82f6);color:#fff}`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
const state = {
|
||||
@@ -1866,7 +1866,7 @@ dl{margin:.8em 0}dt{font-weight:650;margin:.6em 0 .2em}dd{margin:0 0 .3em 1.6em;
|
||||
const panel = document.createElement('div');
|
||||
panel.className = 'me-search';
|
||||
panel.dataset.replace = showReplace ? '1' : '0';
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder') || 'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-prev">↑</button><button class="me-search-next">↓</button><span class="me-search-count"></span><button class="me-search-regex" title="Regex">.*</button><button class="me-search-close">×</button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder') || 'Replace'}"/><button class="me-search-replace-one">${t('replace') || 'Replace'}</button><button class="me-search-replace-all">${t('replaceAll') || 'All'}</button></div>`;
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder') || 'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-btn me-search-prev" title="${t('findPrev') || 'Previous'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></button><button class="me-search-btn me-search-next" title="${t('findNext') || 'Next'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button><span class="me-search-count"></span><button class="me-search-btn me-search-regex" title="Regex">.*</button><button class="me-search-btn me-search-close" title="${t('close') || 'Close'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder') || 'Replace'}"/><button class="me-search-btn me-search-replace-one">${t('replace') || 'Replace'}</button><button class="me-search-btn me-search-replace-all">${t('replaceAll') || 'All'}</button></div>`;
|
||||
editor.el.appendChild(panel);
|
||||
state._panel = panel;
|
||||
_updateReplaceVisible();
|
||||
@@ -4394,9 +4394,9 @@ dl{margin:.8em 0}dt{font-weight:650;margin:.6em 0 .2em}dd{margin:0 0 .3em 1.6em;
|
||||
/**
|
||||
* MetonaEditor — Type-safe, lightweight Markdown Editor
|
||||
* @module metona-editor
|
||||
* @version 0.2.3
|
||||
* @version 0.2.4
|
||||
*/
|
||||
const VERSION = '0.2.3';
|
||||
const VERSION = '0.2.4';
|
||||
const globalPlugins = [];
|
||||
MarkdownEditor.on('beforeCreate', (editor) => {
|
||||
if (!editor || editor.isDestroyed())
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@metona-team/metona-editor",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.4",
|
||||
"description": "Type-safe, lightweight, zero-dependency Markdown Editor. Desktop-first. React-free. Single-file bundle.",
|
||||
"type": "module",
|
||||
"main": "dist/metona-editor.js",
|
||||
|
||||
+6
-6
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📝</text></svg>"/>
|
||||
<title>MetonaEditor v0.2.3 — 全功能演示</title>
|
||||
<title>MetonaEditor v0.2.4 — 全功能演示</title>
|
||||
<style>
|
||||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||||
:root{--app-bg:#f5f6f8;--app-text:#1a1a2e;--app-card:#fff;--app-border:#e5e7eb;--app-accent:#3b82f6;--app-accent2:#8b5cf6;--header-bg:linear-gradient(135deg,#1e293b 0%,#0f172a 100%);--header-text:#f1f5f9;--badge-bg:rgba(255,255,255,.12);--badge-text:#e2e8f0}
|
||||
@@ -45,7 +45,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
|
||||
<body>
|
||||
|
||||
<header class="header">
|
||||
<h1><span class="grad">Metona</span>Editor v0.2.3</h1>
|
||||
<h1><span class="grad">Metona</span>Editor v0.2.4</h1>
|
||||
<div class="badges">
|
||||
<span class="badge">TypeScript</span>
|
||||
<span class="badge">零运行时依赖</span>
|
||||
@@ -91,7 +91,7 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
|
||||
</div>
|
||||
|
||||
<footer class="footer">
|
||||
MetonaEditor v0.2.3 · TypeScript · <a href="index.html">首页</a> · <a href="docs.html">API 文档</a> · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT
|
||||
MetonaEditor v0.2.4 · TypeScript · <a href="index.html">首页</a> · <a href="docs.html">API 文档</a> · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
||||
@@ -99,12 +99,12 @@ body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Micr
|
||||
<script>
|
||||
(function(){
|
||||
var demoMd=[
|
||||
'# 🚀 MetonaEditor v0.2.3 全功能演示',
|
||||
'# 🚀 MetonaEditor v0.2.4 全功能演示',
|
||||
'',
|
||||
'> TypeScript 重构 · 零运行时依赖 · **桌面端** Markdown Editor 库。',
|
||||
'> 全模块 TypeScript 严格模式,12 个源文件,684 个测试全部通过。',
|
||||
'',
|
||||
'## ✨ v0.2.3 新特性',
|
||||
'## ✨ v0.2.4 新特性',
|
||||
'',
|
||||
'- 浮动格式工具栏:选中文本自动弹出 bold/italic/code/link',
|
||||
'- 新增 `getSelectedText()` `getCursorPosition()` 等 10+ API',
|
||||
@@ -139,7 +139,7 @@ var demoMd=[
|
||||
'',
|
||||
'| 版本 | 日期 | 测试 | 主题 |',
|
||||
'| :--- | :---: | ---: | --- |',
|
||||
'| v0.2.3 | 2026-07 | 725 | 浮动工具栏+新API |',
|
||||
'| v0.2.4 | 2026-07 | 725 | 浮动工具栏+新API |',
|
||||
'| v0.2.2 | 2026-07 | 694 | 法语+表格格式化 |',
|
||||
'| v0.2.1 | 2026-07 | 684 | 引用链接+右键菜单 |',
|
||||
'| v0.2.0 | 2026-07 | 610 | TypeScript 重构 |',
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📖</text></svg>"/>
|
||||
<title>MetonaEditor v0.2.3 · 文档</title>
|
||||
<title>MetonaEditor v0.2.4 · 文档</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
:root{--bg:#0f1117;--bg-soft:#161922;--card:#1c2029;--card-hover:#232834;--text:#e6e8eb;--muted:#9ca3af;--accent:#3b82f6;--accent-2:#8b5cf6;--accent-soft:rgba(59,130,246,.12);--border:rgba(255,255,255,.08);--gradient:linear-gradient(135deg,#3b82f6 0%,#8b5cf6 50%,#ec4899 100%)}
|
||||
@@ -65,7 +65,7 @@ footer a{color:var(--accent);text-decoration:none}
|
||||
|
||||
<header class="docs-header">
|
||||
<h1><span class="grad">API 文档</span></h1>
|
||||
<p class="sub">MetonaEditor v0.2.3 · TypeScript · 完整配置、API 与使用指南</p>
|
||||
<p class="sub">MetonaEditor v0.2.4 · TypeScript · 完整配置、API 与使用指南</p>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
@@ -433,7 +433,7 @@ i18nUtils<span class="c-punc">.</span><span class="c-fn">formatDate</span><span
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
MetonaEditor v0.2.3 · TypeScript · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT License
|
||||
MetonaEditor v0.2.4 · TypeScript · <a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a> · MIT License
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
||||
+19
-6
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🚀</text></svg>"/>
|
||||
<title>MetonaEditor v0.2.3 · TypeScript · 桌面端 Markdown 编辑器</title>
|
||||
<title>MetonaEditor v0.2.4 · TypeScript · 桌面端 Markdown 编辑器</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
:root{--bg:#0f1117;--bg-soft:#161922;--card:#1c2029;--card-hover:#232834;--text:#e6e8eb;--muted:#9ca3af;--accent:#3b82f6;--accent-2:#8b5cf6;--accent-3:#ec4899;--accent-soft:rgba(59,130,246,.12);--border:rgba(255,255,255,.08);--gradient:linear-gradient(135deg,#3b82f6 0%,#8b5cf6 50%,#ec4899 100%);--shadow:0 20px 50px -20px rgba(0,0,0,.5)}
|
||||
@@ -106,7 +106,7 @@ footer a:hover{text-decoration:underline}
|
||||
<h1>TypeScript 重构 · 零依赖<br/><span class="grad">桌面端 Markdown 编辑器</span></h1>
|
||||
<p class="tagline">全模块 TypeScript 严格模式,内置自研解析器(99% 行覆盖率),6 个预设插件,中文优先。为桌面端现代 Web 应用而生。</p>
|
||||
<div class="badges">
|
||||
<span class="badge accent">v0.2.3</span>
|
||||
<span class="badge accent">v0.2.4</span>
|
||||
<span class="badge">TypeScript</span>
|
||||
<span class="badge">零运行时依赖</span>
|
||||
<span class="badge">725 tests</span>
|
||||
@@ -154,10 +154,23 @@ footer a:hover{text-decoration:underline}
|
||||
<div class="container">
|
||||
<span class="section-eyebrow">Quick Start</span>
|
||||
<h2 class="section-title">三行代码即可使用</h2>
|
||||
<p class="section-sub">TypeScript / npm / CDN 三种引入方式,都只需极少代码。</p>
|
||||
<div class="code-block"><span class="c-com">// npm 安装</span>
|
||||
<p class="section-sub">npm / CDN / 本地文件 三种方式,TypeScript / ESM / CJS 全面支持。</p>
|
||||
<div class="code-block"><span class="c-com">// 方式一:npm 安装(推荐)</span>
|
||||
<span class="c-kw">npm</span> install @metona-team/metona-editor
|
||||
|
||||
<span class="c-com">// ES Module / TypeScript</span>
|
||||
<span class="c-kw">import</span> MeEditor <span class="c-kw">from</span> <span class="c-str">'@metona-team/metona-editor'</span><span class="c-punc">;</span>
|
||||
|
||||
<span class="c-com">// CommonJS</span>
|
||||
<span class="c-kw">const</span> MeEditor <span class="c-punc">=</span> <span class="c-fn">require</span><span class="c-punc">(</span><span class="c-str">'@metona-team/metona-editor'</span><span class="c-punc">);</span>
|
||||
|
||||
<span class="c-com">// 方式二:CDN 引入</span>
|
||||
<span class="c-com"><script src="https://cdn.jsdelivr.net/npm/@metona-team/metona-editor@0.2.4/dist/metona-editor.min.js"></script></span>
|
||||
|
||||
<span class="c-com">// 方式三:本地文件</span>
|
||||
<span class="c-com"><script src="./dist/metona-editor.min.js"></script></span>
|
||||
|
||||
<span class="c-com">// 创建实例</span>
|
||||
<span class="c-kw">const</span> editor <span class="c-punc">=</span> MeEditor<span class="c-punc">.</span><span class="c-fn">create</span><span class="c-punc">(</span><span class="c-str">'#editor'</span><span class="c-punc">,</span> <span class="c-punc">{</span>
|
||||
<span class="c-fn">value</span><span class="c-punc">:</span> <span class="c-str">'# 你好,世界'</span><span class="c-punc">,</span>
|
||||
<span class="c-fn">mode</span><span class="c-punc">:</span> <span class="c-str">'split'</span><span class="c-punc">,</span>
|
||||
@@ -214,7 +227,7 @@ editor<span class="c-punc">.</span><span class="c-fn">exec</span><span class="c-
|
||||
<a href="https://git.metona.cn/MetonaTeam/MetonaEditor" target="_blank" rel="noopener">源码仓库</a>
|
||||
<a href="https://git.metona.cn/MetonaTeam/MetonaEditor/issues" target="_blank" rel="noopener">问题反馈</a>
|
||||
</div>
|
||||
<div>MetonaEditor v0.2.3 · TypeScript · MIT License · MetonaTeam</div>
|
||||
<div>MetonaEditor v0.2.4 · TypeScript · MIT License · MetonaTeam</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -224,7 +237,7 @@ MeEditor.themes.switchTheme('dark');
|
||||
MeEditor.create('#editor', {
|
||||
mode: 'split', height: 480, theme: 'dark',
|
||||
value: [
|
||||
'# 欢迎使用 MetonaEditor v0.2.3',
|
||||
'# 欢迎使用 MetonaEditor v0.2.4',
|
||||
'',
|
||||
'一个 **TypeScript 重构 · 零运行时依赖** 的桌面端 Markdown 编辑器。',
|
||||
'',
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* MetonaEditor — Type-safe, lightweight Markdown Editor
|
||||
* @module metona-editor
|
||||
* @version 0.2.3
|
||||
* @version 0.2.4
|
||||
*/
|
||||
|
||||
import { MarkdownEditor } from './core';
|
||||
@@ -13,7 +13,7 @@ import { animationUtils } from './animations';
|
||||
import { DEFAULTS, ICONS, THEMES, EDIT_MODES, DEFAULT_TOOLBAR, TOOLBAR_ACTIONS } from './constants';
|
||||
import type { EditMode, ThemeName, ToolbarItem, EditorOptions } from './constants';
|
||||
|
||||
const VERSION = '0.2.3';
|
||||
const VERSION = '0.2.4';
|
||||
|
||||
const globalPlugins: any[] = [];
|
||||
|
||||
|
||||
+2
-2
@@ -213,7 +213,7 @@ const searchReplacePlugin: Plugin = {
|
||||
// Inject style once globally
|
||||
if (!document.getElementById('me-search-style')) {
|
||||
const style = document.createElement('style'); style.id = 'me-search-style';
|
||||
style.textContent = `.me-search{position:absolute;top:8px;right:12px;z-index:20;display:flex;flex-direction:column;gap:6px;padding:8px;background:var(--md-toolbar-bg,#f8f9fa);border:1px solid var(--md-border,rgba(0,0,0,0.1));border-radius:8px;box-shadow:0 8px 24px -8px rgba(0,0,0,0.2);font-size:13px;min-width:280px}.me-search-row{display:flex;gap:4px;align-items:center}.me-search input{flex:1;min-width:0;padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));border-radius:4px;background:var(--md-textarea-bg,#fff);color:var(--md-text,#1f2937);font-size:13px}.me-search input:focus{outline:none;border-color:var(--md-accent,#3b82f6)}.me-search button{padding:4px 8px;border:1px solid var(--md-border,rgba(0,0,0,0.15));background:var(--md-bg,#fff);color:var(--md-text,#1f2937);border-radius:4px;cursor:pointer;font-size:12px;line-height:1}.me-search button:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-count{color:var(--md-muted,#6b7280);font-size:12px;min-width:60px;text-align:center}.me-search .me-search-close{padding:2px 6px}`;
|
||||
style.textContent = `.me-search{position:absolute;top:10px;right:16px;z-index:20;display:flex;flex-direction:column;gap:8px;padding:12px;background:var(--md-bg,#1c2029);border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:10px;box-shadow:0 12px 40px -8px rgba(0,0,0,0.4),0 0 0 1px rgba(255,255,255,0.05);font-size:13px;min-width:300px;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);animation:meSearchIn .18s ease-out}@keyframes meSearchIn{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.me-search-row{display:flex;gap:6px;align-items:center}.me-search-row+.me-search-row{margin-top:2px}.me-search input{flex:1;min-width:0;padding:7px 10px;border:1px solid var(--md-border,rgba(255,255,255,0.12));border-radius:6px;background:var(--md-textarea-bg,rgba(255,255,255,0.04));color:var(--md-text,#e6e8eb);font-size:13px;outline:none;transition:border-color .15s,box-shadow .15s}.me-search input::placeholder{color:var(--md-muted,#6b7280)}.me-search input:focus{border-color:var(--md-accent,#3b82f6);box-shadow:0 0 0 3px rgba(59,130,246,0.15)}.me-search .me-search-btn{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid rgba(255,255,255,0.08);border-radius:5px;background:rgba(255,255,255,0.04);color:var(--md-muted,#9ca3af);cursor:pointer;transition:all .12s;flex-shrink:0}.me-search .me-search-btn:hover{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn:active{transform:scale(.92)}.me-search .me-search-btn.me-active{background:var(--md-accent,#3b82f6);color:#fff;border-color:var(--md-accent,#3b82f6)}.me-search .me-search-btn svg{width:14px;height:14px}.me-search .me-search-count{color:var(--md-muted,#9ca3af);font-size:11.5px;min-width:28px;text-align:center;font-variant-numeric:tabular-nums}.me-search .me-search-close{margin-left:2px;font-size:16px;line-height:1}.me-search .me-search-close:hover{background:#ef4444;border-color:#ef4444}.me-search .me-search-replace-one,.me-search .me-search-replace-all{width:auto;padding:5px 10px;font-size:12px;font-weight:500;letter-spacing:.01em}.me-search .me-search-replace-all{background:rgba(59,130,246,0.12);border-color:rgba(59,130,246,0.3);color:var(--md-accent,#60a5fa)}.me-search .me-search-replace-all:hover{background:var(--md-accent,#3b82f6);color:#fff}`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ const searchReplacePlugin: Plugin = {
|
||||
const selected = editor.textarea.value.substring(editor.textarea.selectionStart, editor.textarea.selectionEnd);
|
||||
const panel = document.createElement('div'); panel.className = 'me-search';
|
||||
panel.dataset.replace = showReplace ? '1' : '0';
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder')||'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-prev">↑</button><button class="me-search-next">↓</button><span class="me-search-count"></span><button class="me-search-regex" title="Regex">.*</button><button class="me-search-close">×</button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder')||'Replace'}"/><button class="me-search-replace-one">${t('replace')||'Replace'}</button><button class="me-search-replace-all">${t('replaceAll')||'All'}</button></div>`;
|
||||
panel.innerHTML = `<div class="me-search-row"><input type="text" class="me-search-find" placeholder="${t('searchPlaceholder')||'Find'}" value="${escapeAttr(selected)}"/><button class="me-search-btn me-search-prev" title="${t('findPrev')||'Previous'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"/></svg></button><button class="me-search-btn me-search-next" title="${t('findNext')||'Next'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></button><span class="me-search-count"></span><button class="me-search-btn me-search-regex" title="Regex">.*</button><button class="me-search-btn me-search-close" title="${t('close')||'Close'}"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button></div><div class="me-search-row me-search-replace-row"><input type="text" class="me-search-replace" placeholder="${t('replacePlaceholder')||'Replace'}"/><button class="me-search-btn me-search-replace-one">${t('replace')||'Replace'}</button><button class="me-search-btn me-search-replace-all">${t('replaceAll')||'All'}</button></div>`;
|
||||
editor.el.appendChild(panel); state._panel = panel;
|
||||
_updateReplaceVisible();
|
||||
state._regexMode = false;
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ describe('index.ts - 全局 API', () => {
|
||||
|
||||
test('VERSION 是字符串', () => {
|
||||
expect(typeof VERSION).toBe('string');
|
||||
expect(VERSION).toBe('0.2.3');
|
||||
expect(VERSION).toBe('0.2.4');
|
||||
});
|
||||
|
||||
test('api.default 是 api 本身', () => {
|
||||
|
||||
Reference in New Issue
Block a user