xfy 9bc8b5c2ee refactor(libs): 抽取 @yggdrasil/shared 消除跨 IIFE 库的类型/常量重复
新增 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 侧的对称改动。
2026-07-14 15:39:41 +08:00

62 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { THEME_CHANGE_EVENT } from '@yggdrasil/shared';
import { TerminalInstance, XtermOptions } from './terminal';
import type { ThemeName } from './themes';
/**
* 主题切换事件由 @yggdrasil/shared 统一定义。
*
* yggdrasil-core 在 VT 回调内(NEW 快照捕获前)同步 dispatch 此事件,
* 让 xterm 同步 setTheme——否则圆形展开扫过终端区域时 OLD/NEW 快照同色
* (背景由 .xterm-scrollable-element 的 inline background-color 注入,不随
* .dark 翻转),看不到变化,动画结束后才瞬切。
*/
/**
* 模块入口:暴露对象字面量 { create } 作为默认导出。
* IIFE 产物挂在 window.XtermTerminal 上,由 Rust 侧用 Reflect::get 取
* (对象字面量,不能用 wasm-bindgen 的 extern fn——那会被编成函数调用而失败
*/
const XtermTerminal = {
_instances: new Map<string, TerminalInstance>(),
create(containerId: string, options: XtermOptions = new XtermOptions()): TerminalInstance | 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 TerminalInstance(container, options);
this._instances.set(containerId, instance);
return instance;
},
};
/**
* 订阅主题切换事件:VT 回调内同步 dispatch 时,遍历所有存活实例调 setTheme。
*
* 必须在模块加载时注册一次(IIFE 顶层),确保任何时刻 dispatch 都能命中。
* 单实例异常用 try/catch 隔离,避免一个实例失败中断其他实例换肤。
* 与 Dioxus use_effect 驱动的 set_theme 幂等共存(setTheme 相同主题是 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';
XtermTerminal._instances.forEach((instance) => {
try {
instance.setTheme(theme);
} catch (e) {
console.error('[XtermTerminal] setTheme failed during theme change:', e);
}
});
});
}
export default XtermTerminal;