feat: add runtime theme context

- add runtime-level theme ownership and change notification

- inject shared theme into mounted and dynamically added components

- cover theme injection and switching with regression tests
This commit is contained in:
chuan
2026-06-04 03:27:07 +08:00
Unverified
parent a0d9d6c323
commit d877612354
10 changed files with 266 additions and 14 deletions
+22 -1
View File
@@ -386,10 +386,31 @@ TinyTUI 现在已经具备最小可运行的 C# TUI 框架骨架:终端输入
- `CancellableLoader` 暴露标准 `CancellationToken`,比只暴露回调更容易接入 C# async 工作流
- `TruncatedText` 直接复用 `ITextMeasurer`,能继承第 5 项已经补过的 ANSI、OSC 和 grapheme 宽度处理
本次 Runtime 级主题上下文推进:
- 新增 `IThemeComponent`,让组件可以显式接收 Runtime 级共享 `ITuiTheme`
- `TuiRuntime` 现在持有 `Theme`,构造函数支持传入初始主题,默认仍使用 `TuiTheme.Default`
- `ITuiRuntime` 增加 `ThemeChanged``SetTheme(ITuiTheme theme)`,主题切换时会更新已挂载根组件和 overlay 组件并请求重渲染
- `MountRuntimeComponentTree` 复用现有 Runtime 挂载上下文,在根组件、overlay、动态 `Container.Add` 和内置 `Box.Child` 路径同时注入共享主题和共享 keybinding
- `Input``SelectList``Image``CancellableLoader``Editor` 接入主题注入,其中 `Editor` 会把主题转发给内部 `AutocompleteList`
- 新增 xUnit 回归测试,覆盖根组件主题注入、overlay 主题注入、动态容器子组件主题注入、`SetTheme` 刷新已挂载组件且不破坏 keybinding 注入
本次为什么这样做:
- 对比 `tmp/tui/src/tui.ts`,参考实现的关键生命周期是 `TUI.invalidate()` 会递归根组件和 overlayC# 侧已有 Runtime 挂载计数,因此把主题注入接到同一条生命周期能避免维护两套递归逻辑
- 主题切换只负责更新共享主题、触发组件失效和重渲染,不扩展控件样式细节,避免把本轮任务扩大成完整主题系统
- `IThemeComponent``IKeybindingComponent` 对称,第三方组件可以选择接入并自行向内部子组件转发,Runtime 不需要用反射猜测组件结构
本次当前更好的点:
- C# 侧主题是 Runtime 实例级状态,不是模块级全局对象,多 Runtime 和测试场景可以隔离不同主题
- 已挂载 overlay 和动态添加的容器子树会收到同一个主题对象,避免浮层和后续加入组件继续使用默认主题
- 主题切换路径不会重建 keybinding registry,测试覆盖了切换主题后共享快捷键仍然生效
后续仍需补齐:
- `SettingsList` 还没有移植,参考实现里的搜索、描述换行、值循环、submenu 委托和主题分区仍需单独推进
- `ITuiTheme` 当前是轻量样式接口,还没有 runtime 级主题持有、主题切换事件和组件缓存 theme version
- `ITuiTheme` 当前是轻量样式接口,还没有 theme version、分区主题、Markdown 完整主题或控件级样式覆盖策略
- `Input` 目前仍是尾部输入模型,还没有参考实现里的水平滚动、按 grapheme 移动、kill ring 和 undo;这些应在输入/编辑能力后续增量中处理
- 组件缓存规范还只具备 invalidate 入口,没有统一的 width/content/theme cache key,也没有 Markdown AST 或复杂布局缓存基类
- 焦点恢复策略仍比 `tmp/tui/src/tui.ts` 简化,overlay 被临时隐藏、非 overlay 组件短暂抢焦点和多层 submenu 的 blocked restore 还需要继续补强