新增 libs/shared 内部包,作为跨 IIFE 库的单一真相源: - ThemeName 类型(原 codemirror/themes.ts + xterm/themes.ts 各一份) - THEME_CHANGE_EVENT 常量(原 yggdrasil-core 导出 + codemirror/xterm 各硬编码同名 string literal,靠注释维系一致) - prefersReducedMotion 函数(原 lightbox + yggdrasil-core 各一份) codemirror-editor / xterm-terminal / lightbox / yggdrasil-core 四个库 改为 workspace 依赖 @yggdrasil/shared,Vite 构建时 inline 进各自 IIFE, 不破坏 IIFE 隔离。消除「改一处忘改另一处导致静默失效」的风险。 附:image_reader_limits 已在上一提交共享;本提交是 libs 侧的对称改动。
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import { THEME_CHANGE_EVENT } from '@yggdrasil/shared';
|
||
import { CodeMirrorInstance, EditorOptions } from './editor';
|
||
import type { ThemeName } from './themes';
|
||
|
||
/**
|
||
* 主题切换事件由 @yggdrasil/shared 统一定义。
|
||
*
|
||
* yggdrasil-core 在 VT 回调内(NEW 快照捕获前)同步 dispatch 此事件,
|
||
* 让 CodeMirror 同步 reconfigure 主题——否则圆形展开扫过编辑器区域时
|
||
* OLD/NEW 快照同色(背景由 catppuccin Extension 注入,不随 .dark 翻转),
|
||
* 看不到变化,动画结束后才瞬切。
|
||
*/
|
||
|
||
/**
|
||
* 模块入口:暴露对象字面量 { create } 作为默认导出。
|
||
* IIFE 产物挂在 window.CodeMirrorEditor 上,由 Rust 侧用 Reflect::get 取
|
||
* (对象字面量,不能用 wasm-bindgen 的 extern fn——那会被编成函数调用而失败)。
|
||
*/
|
||
const CodeMirrorEditor = {
|
||
_instances: new Map<string, CodeMirrorInstance>(),
|
||
|
||
create(
|
||
containerId: string,
|
||
options: EditorOptions = new EditorOptions(),
|
||
): CodeMirrorInstance | null {
|
||
const container = document.getElementById(containerId);
|
||
if (!container) return null;
|
||
|
||
// 销毁同 id 的旧实例
|
||
const existing = this._instances.get(containerId);
|
||
if (existing) {
|
||
existing.destroy();
|
||
this._instances.delete(containerId);
|
||
}
|
||
|
||
const instance = new CodeMirrorInstance(container, options);
|
||
this._instances.set(containerId, instance);
|
||
return instance;
|
||
},
|
||
};
|
||
|
||
/**
|
||
* 订阅主题切换事件:VT 回调内同步 dispatch 时,遍历所有存活实例调 setTheme。
|
||
*
|
||
* 必须在模块加载时注册一次(IIFE 顶层),确保任何时刻 dispatch 都能命中。
|
||
* 单实例异常用 try/catch 隔离,避免一个实例失败中断其他实例换肤。
|
||
* 与 Dioxus use_effect 驱动的 set_theme 幂等共存(reconfigure 相同主题是 no-op)。
|
||
*/
|
||
if (typeof window !== 'undefined') {
|
||
window.addEventListener(THEME_CHANGE_EVENT, (event) => {
|
||
const detail = (event as CustomEvent).detail as { isDark: boolean } | undefined;
|
||
if (!detail) return;
|
||
const theme: ThemeName = detail.isDark ? 'dark' : 'light';
|
||
CodeMirrorEditor._instances.forEach((instance) => {
|
||
try {
|
||
instance.setTheme(theme);
|
||
} catch (e) {
|
||
console.error('[CodeMirrorEditor] setTheme failed during theme change:', e);
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
export default CodeMirrorEditor;
|