Bug Fixes: - fix(core): insert() replace param was non-functional due to identical ternary branches - fix(types): correct project URL typo (MetonaToast → MetonaEditor) Improvements: - feat(core): scope CSS theme variables to .me-wrapper per-instance, preventing global style pollution - feat(themes): add optional target parameter to setThemeVariables() for element-scoped theming - perf(parser): improve bold/strikethrough regex to support inline delimiter chars (e.g. **a*b**, ~~a~b~~) - fix(parser): prevent *** cross-tag nesting by requiring first content char ≠ delimiter - docs(animations): clarify module purpose as future-use animation metadata registry Tests: - test(core): add 2 cases for insert() replace:true / replace:false behavior - All 409 tests passing (+2 new) Chores: - bump version 0.1.0 → 0.1.1 across all source files, package.json, README, and demo
195 lines
6.1 KiB
JavaScript
195 lines
6.1 KiB
JavaScript
/**
|
|
* MetonaEditor Constants - 常量定义
|
|
* @module constants
|
|
* @version 0.1.1
|
|
* @description 默认配置、主题、动画、工具栏等常量
|
|
*/
|
|
|
|
import { ICONS } from './icons.js';
|
|
import { LOCALES } from './locales.js';
|
|
|
|
/**
|
|
* 默认工具栏按钮序列
|
|
* '|' 表示分组分隔符
|
|
*/
|
|
export const DEFAULT_TOOLBAR = [
|
|
'bold', 'italic', 'strikethrough', 'code', '|',
|
|
'h1', 'h2', 'h3', '|',
|
|
'quote', 'ul', 'ol', '|',
|
|
'link', 'image', 'table', 'hr', '|',
|
|
'undo', 'redo', '|',
|
|
'edit', 'split', 'preview', 'fullscreen',
|
|
];
|
|
|
|
/**
|
|
* 默认配置
|
|
*/
|
|
export const DEFAULTS = Object.freeze({
|
|
// 内容
|
|
value: '',
|
|
placeholder: '',
|
|
// 视图模式:edit / split / preview
|
|
mode: 'split',
|
|
// 高度:数字为 px,字符串原样使用
|
|
height: 400,
|
|
// 工具栏:数组或 false(隐藏)
|
|
toolbar: DEFAULT_TOOLBAR,
|
|
// 字数统计状态栏
|
|
wordCount: true,
|
|
// 自动聚焦
|
|
autofocus: false,
|
|
// 拼写检查
|
|
spellcheck: false,
|
|
// 历史栈上限
|
|
historyLimit: 100,
|
|
// 同步滚动(分屏模式)
|
|
syncScroll: true,
|
|
// 制表符插入的空格数(0 表示插入 \t)
|
|
tabSize: 2,
|
|
// 主题:light / dark / auto / warm / 自定义
|
|
theme: 'auto',
|
|
// 国际化
|
|
locale: 'zh-CN',
|
|
// 自定义 Markdown 渲染函数 (md, env) => html,覆盖内置解析器
|
|
render: null,
|
|
// 自定义代码高亮函数 (code, lang) => html
|
|
highlight: null,
|
|
// 自定义渲染前的 HTML 净化函数(接收渲染后的 HTML,返回安全 HTML)
|
|
sanitize: null,
|
|
// 外观
|
|
className: '',
|
|
style: {},
|
|
// 插件
|
|
plugins: [],
|
|
// 生命周期回调
|
|
onChange: null,
|
|
onInput: null,
|
|
onFocus: null,
|
|
onBlur: null,
|
|
onSave: null,
|
|
onModeChange: null,
|
|
onFullscreen: null,
|
|
onCreate: null,
|
|
onDestroy: null,
|
|
});
|
|
|
|
// Icons - 从 icons.js 导入并重新导出(保持单一来源)
|
|
export { ICONS };
|
|
|
|
/**
|
|
* 类型颜色配置(保留用于状态提示与按钮强调)
|
|
*/
|
|
export const TYPE_COLORS = {
|
|
success: { fg: '#10b981', bg: 'rgba(16, 185, 129, 0.1)' },
|
|
error: { fg: '#ef4444', bg: 'rgba(239, 68, 68, 0.1)' },
|
|
warning: { fg: '#f59e0b', bg: 'rgba(245, 158, 11, 0.1)' },
|
|
info: { fg: '#3b82f6', bg: 'rgba(59, 130, 246, 0.1)' },
|
|
loading: { fg: '#6366f1', bg: 'rgba(99, 102, 241, 0.1)' },
|
|
default: { fg: '#6b7280', bg: 'rgba(107, 114, 128, 0.1)' },
|
|
};
|
|
|
|
/**
|
|
* 主题配置
|
|
*/
|
|
export const THEMES = {
|
|
light: {
|
|
bg: 'rgba(255, 255, 255, 0.96)',
|
|
text: '#1f2937',
|
|
border: 'rgba(0, 0, 0, 0.08)',
|
|
shadow: '0 10px 36px -10px rgba(0, 0, 0, 0.18), 0 4px 14px -4px rgba(0, 0, 0, 0.08)',
|
|
hoverShadow: '0 14px 48px -10px rgba(0, 0, 0, 0.22), 0 6px 18px -4px rgba(0, 0, 0, 0.10)',
|
|
// 编辑器专属
|
|
toolbarBg: 'rgba(248, 249, 250, 0.92)',
|
|
textareaBg: '#ffffff',
|
|
previewBg: '#ffffff',
|
|
codeBg: 'rgba(243, 244, 246, 1)',
|
|
codeText: '#1f2937',
|
|
accent: '#3b82f6',
|
|
muted: '#6b7280',
|
|
},
|
|
dark: {
|
|
bg: 'rgba(28, 32, 40, 0.94)',
|
|
text: '#e6e8eb',
|
|
border: 'rgba(255, 255, 255, 0.1)',
|
|
shadow: '0 10px 36px -10px rgba(0, 0, 0, 0.6), 0 4px 14px -4px rgba(0, 0, 0, 0.4)',
|
|
hoverShadow: '0 14px 48px -8px rgba(0, 0, 0, 0.6), 0 6px 18px -4px rgba(0, 0, 0, 0.4)',
|
|
toolbarBg: 'rgba(22, 26, 33, 0.92)',
|
|
textareaBg: '#1c2028',
|
|
previewBg: '#1c2028',
|
|
codeBg: 'rgba(15, 18, 24, 1)',
|
|
codeText: '#e6e8eb',
|
|
accent: '#60a5fa',
|
|
muted: '#9ca3af',
|
|
},
|
|
auto: 'auto',
|
|
warm: {
|
|
bg: 'rgba(255, 251, 235, 0.96)',
|
|
text: '#78350f',
|
|
border: 'rgba(245, 158, 11, 0.2)',
|
|
shadow: '0 10px 36px -10px rgba(245, 158, 11, 0.18), 0 4px 14px -4px rgba(245, 158, 11, 0.08)',
|
|
hoverShadow: '0 14px 48px -10px rgba(245, 158, 11, 0.22), 0 6px 18px -4px rgba(245, 158, 11, 0.10)',
|
|
toolbarBg: 'rgba(254, 243, 199, 0.92)',
|
|
textareaBg: '#fffbeb',
|
|
previewBg: '#fffbeb',
|
|
codeBg: 'rgba(254, 215, 170, 0.6)',
|
|
codeText: '#78350f',
|
|
accent: '#d97706',
|
|
muted: '#a16207',
|
|
},
|
|
};
|
|
|
|
/**
|
|
* 位置配置(保留,预览面板提示等场景可用)
|
|
*/
|
|
export const POSITIONS = [
|
|
'top-left', 'top-center', 'top-right',
|
|
'bottom-left', 'bottom-center', 'bottom-right',
|
|
];
|
|
|
|
/**
|
|
* 动画配置(保留,DOM 过渡与未来扩展使用)
|
|
*/
|
|
export const ANIMATIONS = {
|
|
slide: { enter: { transform: 'translateX(80px)', opacity: 0 }, leave: { transform: 'translateX(120%)', opacity: 0 }, duration: 400, easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' },
|
|
fade: { enter: { opacity: 0, filter: 'blur(3px)' }, leave: { opacity: 0, filter: 'blur(3px)' }, duration: 500, easing: 'ease' },
|
|
scale: { enter: { transform: 'scale(0.55)', opacity: 0 }, leave: { transform: 'scale(0.55)', opacity: 0 }, duration: 450, easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' },
|
|
bounce: { enter: { transform: 'translateY(-80px)', opacity: 0 }, leave: { transform: 'translateY(20px)', opacity: 0 }, duration: 650, easing: 'ease' },
|
|
flip: { enter: { transform: 'perspective(500px) rotateX(-90deg)', opacity: 0 }, leave: { transform: 'perspective(500px) rotateX(90deg)', opacity: 0 }, duration: 500, easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' },
|
|
rotate: { enter: { transform: 'rotate(-25deg) scale(0.6)', opacity: 0 }, leave: { transform: 'rotate(25deg) scale(0.6)', opacity: 0 }, duration: 500, easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' },
|
|
zoom: { enter: { transform: 'scale(0.1)', opacity: 0 }, leave: { transform: 'scale(0.1)', opacity: 0 }, duration: 500, easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' },
|
|
};
|
|
|
|
/**
|
|
* 主题类型
|
|
*/
|
|
export const THEME_TYPES = ['light', 'dark', 'auto'];
|
|
|
|
/**
|
|
* 动画类型
|
|
*/
|
|
export const ANIMATION_TYPES = ['slide', 'fade', 'scale', 'bounce', 'flip', 'rotate', 'zoom'];
|
|
|
|
/**
|
|
* 编辑器视图模式
|
|
*/
|
|
export const EDIT_MODES = ['edit', 'split', 'preview'];
|
|
|
|
/**
|
|
* 内置工具栏动作清单
|
|
*/
|
|
export const TOOLBAR_ACTIONS = [
|
|
'bold', 'italic', 'strikethrough', 'underline', 'code',
|
|
'h1', 'h2', 'h3', 'quote', 'ul', 'ol', 'indent', 'outdent', 'hr',
|
|
'link', 'image', 'table',
|
|
'undo', 'redo',
|
|
'edit', 'split', 'preview', 'fullscreen',
|
|
];
|
|
|
|
// Locales - 从 locales.js 导入并重新导出
|
|
export { LOCALES };
|
|
|
|
/**
|
|
* 进度条方向(保留兼容)
|
|
*/
|
|
export const PROGRESS_DIRECTIONS = ['horizontal', 'vertical'];
|