Initial commit: MetonaEditor v0.1.0

This commit is contained in:
2026-07-23 16:23:07 +08:00
commit 22e867eda8
32 changed files with 17621 additions and 0 deletions
+194
View File
@@ -0,0 +1,194 @@
/**
* MetonaEditor Constants - 常量定义
* @module constants
* @version 0.1.0
* @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'];