@simon_he/vue-tui 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,526 +1,201 @@
1
- # Vue Terminal
1
+ # @simon_he/vue-tui
2
2
 
3
- 用 Vue 组件语法绘制和交互的终端渲染框架。目标是让 “终端” 具备:
3
+ Vue TUI is a Vue 3 terminal UI toolkit for building terminal-style interfaces that can render in a browser or in a real CLI. It gives you Vue components, terminal cell rendering, event dispatch, markdown rendering, and high-throughput primitives for lists, logs, and streaming transcripts.
4
4
 
5
- - 类终端的写入/删除/更新/尺寸调整能力
6
- - ANSI 样式渲染(颜色、加粗、下划线等)
7
- - 事件机制(点击、移动、滚动、拖拽)
8
- - Vue 组件 + 响应式数据驱动终端界面更新
5
+ Use it when you want:
9
6
 
10
- ## 快速开始
7
+ - Browser-hosted terminal interfaces, dashboards, demos, and playgrounds.
8
+ - CLI apps that use Vue component composition instead of imperative stdout drawing.
9
+ - Shared UI code that can run against a DOM renderer, a stdout renderer, or headless tests.
10
+ - Large terminal surfaces such as virtual lists, append-only logs, markdown transcripts, and agent console UIs.
11
11
 
12
- ### 浏览器渲染
13
-
14
- ```vue
15
- <script setup lang="ts">
16
- import { computed, ref } from 'vue'
17
- import {
18
- TerminalProvider,
19
- TBox,
20
- TInput,
21
- TText,
22
- useLayout,
23
- } from '@simon_he/vue-tui'
24
-
25
- const layout = useLayout()
26
- const cols = computed(() => layout.clipRect?.w ?? 80)
27
- const rows = computed(() => layout.clipRect?.h ?? 24)
28
- const input = ref('')
29
- </script>
30
-
31
- <template>
32
- <TerminalProvider
33
- :cols="80"
34
- :rows="24"
35
- :default-style="{ fg: 'whiteBright' }"
36
- >
37
- <TBox
38
- :x="0"
39
- :y="0"
40
- :w="80"
41
- :h="24"
42
- border
43
- title="Demo"
44
- :padding="1"
45
- :style="{ fg: 'blueBright' }"
46
- >
47
- <TText :x="0" :y="0" :w="78" :value="`cols=${cols} rows=${rows}`" />
48
- <TInput :x="0" :y="20" :w="78" v-model="input" placeholder="Type..." />
49
- </TBox>
50
- </TerminalProvider>
51
- </template>
52
- ```
53
-
54
- ## 组件文档与验收标准
55
-
56
- - VitePress 文档站点(本地):`bun run --filter '@simon_he/vue-tui' docs:dev`(入口 `docs/index.md`)
57
- - 组件使用文档:`docs/components.md`
58
- - 组件 Props/Events(自动生成):`docs/generated/components-api.md`(脚本:`scripts/generate-component-api-docs.ts`)
59
- - 组件验收标准(可信赖组件定义 + 测试范围):`docs/components-acceptance.md`
60
- - Terminal 兼容性与颜色一致性:`docs/terminal-compatibility.md`
61
- - 性能关注点与回归策略:`docs/performance.md`
62
-
63
- ### 终端(真实 CLI)渲染
64
-
65
- 内置 `vue-terminal run`,直接在真实终端中跑 UI(stdout renderer + stdin driver):
66
-
67
- ```bash
68
- pnpm build
69
- node cli.mjs --app basic
70
- ```
71
-
72
- ## GoatChain(示例应用)
73
-
74
- GoatChain 风格的示例应用放在 `examples/goatchain`(支持 browser + terminal 构建)。
75
-
76
- ## 示例工程
12
+ ## Install
77
13
 
78
14
  ```bash
79
- # 浏览器示例(交互测试)
80
- pnpm -C examples/basic dev
81
- pnpm -C examples/goatchain dev
82
-
83
- # 打包 browser
84
- pnpm build:examples
85
-
86
- # 打包成 terminal 产物并运行
87
- pnpm build:examples:terminal
88
- pnpm run:basic:terminal
89
- pnpm run:goatchain:terminal
15
+ pnpm add @simon_he/vue-tui vue
90
16
  ```
91
17
 
92
- terminal 构建产物会生成 `dist-terminal/terminal.js`,可以直接作为 `bin` 入口使用。
93
-
94
- ## LLM 集成(对接指南)
18
+ Vue is a peer dependency. The current package supports Vue `>=3.3.0 <4`.
95
19
 
96
- GoatChain 示例应用目前用的是 mock LLM,但你可以很快替换成任意 LLM SDK(OpenAI/Anthropic/本地模型)。
20
+ ## Entry Points
97
21
 
98
- 建议做法:
22
+ | Import | Stability | Use it for |
23
+ | -------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------- |
24
+ | `@simon_he/vue-tui` | Core | Terminal runtime, root Vue components, DOM/stdout renderers, events, layout, inputs, router, and runtime helpers |
25
+ | `@simon_he/vue-tui/markdown` | Focused | `TMarkdownText`, `TVirtualMarkdown`, markdown parser and layout helpers, streaming markdown block sources |
26
+ | `@simon_he/vue-tui/experimental` | Experimental | `TVirtualList`, `TLogView`, TLog search/link/minimap companions, append-only log store, and TLog plugins |
99
27
 
100
- 1. 用 ACP 风格的流式协议驱动 UI(支持 `text_delta` / `tool_call_delta` / `tool_call_end` / `tool_result` / `done`)。
101
- 2. tool_call 的执行可以交给 agent 侧(推荐,和 GoatChain CLI 一致),UI 只负责渲染与“暂停→继续”的用户输入。
102
- 3. 在 UI 侧维护 token 统计与 context window(真实 tokenizer 或近似估算均可)。
28
+ High-throughput log and virtualization APIs stay under `/experimental` until their public surface settles. Keep those imports isolated in application code.
103
29
 
104
- GoatChain 的核心协议定义在:
30
+ ## Browser Usage
105
31
 
106
- - `apps/goatchain/src/core/acp.ts`
107
- - `apps/goatchain/src/core/model.ts`
108
- - `apps/goatchain/src/core/store.ts`
109
- - `apps/goatchain/src/tools-mock.ts`
110
-
111
- 你只需要实现一个 `GoatChainAgent`(`receiveMessage(messages, metadata)` → `AsyncGenerator<ACPMessage>`),并传给 `GoatChainShell/GoatChainProvider`,其余 UI 与交互可以复用。
112
-
113
- ## 核心概念
114
-
115
- - Buffer: 以 Cell 网格存储字符与样式,负责最小化更新
116
- - Renderer: 将 Buffer diff 渲染为 DOM(后续可扩展 canvas)
117
- - EventManager: DOM 事件 -> cell 坐标 -> 命中测试 -> 派发给组件
118
- - Vue Layer: 提供 `TerminalProvider` 与内置组件 (TText/TBox/TView)
119
- - UI Layer: 通用组件与指令(`select`, `v-if`, `v-show` 等)
120
- - Vue3 对齐: 事件名称/修饰符/行为尽量与浏览器 Vue3 保持一致
32
+ ```vue
33
+ <script setup lang="ts">
34
+ import { ref } from "vue";
35
+ import { TerminalProvider, TBox, TInput, TText } from "@simon_he/vue-tui";
121
36
 
122
- ## 模块分层(建议结构)
37
+ const input = ref("");
38
+ </script>
123
39
 
124
- ```
125
- src/
126
- core/
127
- buffer/ # Cell 网格、dirty 标记、宽字符
128
- terminal/ # Terminal API(write/clear/resize/batch/commit)
129
- ansi/ # ANSI 解析 -> Style
130
- renderer/
131
- dom/ # 行/Span 渲染、diff 更新
132
- events/
133
- manager/ # 坐标映射、hit test、事件派发
134
- vue/
135
- components/ # TerminalProvider, TText, TBox, TView
136
- composables/ # useTerminal, useTerminalNode
137
- directives/ # v-if, v-show, v-model, v-focus 等
138
- runtime/ # 动态插入、组件工厂、命令式渲染
40
+ <template>
41
+ <TerminalProvider :cols="80" :rows="24" :default-style="{ fg: 'whiteBright' }">
42
+ <TBox :x="0" :y="0" :w="80" :h="24" border title="Demo" :padding="1">
43
+ <TText :x="0" :y="0" :w="78" value="Vue TUI is running" />
44
+ <TInput :x="0" :y="20" :w="78" v-model="input" placeholder="Type..." />
45
+ </TBox>
46
+ </TerminalProvider>
47
+ </template>
139
48
  ```
140
49
 
141
- ## 数据流
50
+ `TerminalProvider` wires the terminal buffer, DOM renderer, event manager, scheduler, runtime, layout context, and input plugins for browser Vue apps.
142
51
 
143
- ```
144
- Vue 组件 -> Terminal API -> Buffer -> Diff -> Renderer -> DOM
145
- DOM 事件 -> EventManager -> HitTest -> Vue 组件事件回调
146
- ```
52
+ ## CLI Usage
147
53
 
148
- ## 核心数据结构(设计草案)
54
+ For a real terminal, mount a headless Vue app and attach stdout/stdin:
149
55
 
150
56
  ```ts
151
- type Style = {
152
- fg?: string
153
- bg?: string
154
- bold?: boolean
155
- dim?: boolean
156
- italic?: boolean
157
- underline?: boolean
158
- inverse?: boolean
159
- }
160
-
161
- type Cell = {
162
- ch: string
163
- style: Style
164
- width: 1 | 2 // 宽字符支持
165
- }
166
-
167
- type Buffer = {
168
- rows: Cell[][]
169
- cols: number
170
- rowsCount: number
171
- dirtyRows: boolean[]
172
- }
57
+ import { createStdinDriver, createStdoutRenderer, createTerminalApp } from "@simon_he/vue-tui";
58
+ import App from "./App.vue";
59
+
60
+ const app = createTerminalApp({
61
+ cols: process.stdout.columns || 80,
62
+ rows: process.stdout.rows || 24,
63
+ component: App as any,
64
+ defaultStyle: { fg: "whiteBright" },
65
+ });
66
+
67
+ app.mount();
68
+
69
+ const renderer = createStdoutRenderer(app.terminal, {
70
+ output: process.stdout,
71
+ hideCursor: true,
72
+ colorMode: "auto",
73
+ });
74
+
75
+ app.scheduler.flush();
76
+
77
+ const driver = createStdinDriver({
78
+ dispatch(event) {
79
+ const prevented = app.events.dispatch(event);
80
+ app.scheduler.flush();
81
+ return prevented;
82
+ },
83
+ enableMouse: true,
84
+ onExit() {
85
+ driver.dispose();
86
+ renderer.dispose();
87
+ app.dispose();
88
+ process.exit(0);
89
+ },
90
+ });
173
91
  ```
174
92
 
175
- ## 终端语义范围(初版约束)
93
+ ## Core Concepts
176
94
 
177
- - `write()` 默认不解析 ANSI,仅做“就地写入”,越界裁剪
178
- - `writeAnsi()` 解析 ANSI 样式与基础控制序列
179
- - 光标与换行:`write()` 未提供 `x/y` 时使用内部 cursor,带 `x/y` 不更新全局 cursor
180
- - `scroll()` 仅滚动可视区域(是否保留 scrollback 由实现决定)
95
+ - `createTerminal({ cols, rows })` owns the cell buffer, cursor, planes, scrollback, and commit events.
96
+ - `createDomRenderer(terminal, container)` renders terminal cells to DOM with row caching and fast paths for plain and styled rows.
97
+ - `createStdoutRenderer(terminal, options)` emits ANSI output for real terminal UIs.
98
+ - `TerminalProvider` is the browser-facing Vue runtime provider.
99
+ - `createTerminalApp()` is the headless runtime for CLI apps and deterministic tests.
100
+ - `TRenderPlane` separates transcript, chrome, input, and overlay surfaces so small updates do not repaint large panes.
181
101
 
182
- ## Viewport 与 Scrollback(建议)
102
+ ## Components
183
103
 
184
- - Buffer 区分 viewport(可视区域)与 scrollback(历史区域)
185
- - cursor 驱动写入在底部时超出触发滚动
186
- - `scroll(lines)` 只移动 viewport,不影响 buffer 内容
187
- - 支持 `scrollTo()` 与 scrollback 上限(内存可控)
104
+ | Area | Components |
105
+ | ------------- | ---------------------------------------------------------------------------------------------- |
106
+ | Layout | `TBox`, `TView`, `TAnchor`, `TFlow`, `TRenderPlane`, `TRenderLayer` |
107
+ | Text | `TText`, `TTransition`, `TMarkdownText`, `TVirtualMarkdown` |
108
+ | Input | `TInput`, `TInputBox`, `TSelect`, `TPathPicker`, `TJsonEditor` |
109
+ | Overlay | `TDialog`, `TMultilineModal`, `TDebugOverlay` |
110
+ | Experimental | `TVirtualList`, `TLogView`, `TLogSearchBar`, `TLogLinksPanel`, `TLogScrollbar`, `TLogMinimap` |
111
+ | Runtime tools | `createTerminal`, `createDomRenderer`, `createStdoutRenderer`, `createTerminalApp`, event APIs |
188
112
 
189
- ## Terminal API(设计草案)
113
+ See [docs/components.md](./docs/components.md) and [docs/generated/components-api.md](./docs/generated/components-api.md) for props and events.
190
114
 
191
- ```ts
192
- interface Terminal {
193
- resize(cols: number, rows: number): void
194
- clear(x?: number, y?: number, w?: number, h?: number): void
195
- write(text: string, opts?: { x?: number; y?: number; style?: Style }): void
196
- writeAnsi(text: string, opts?: { x?: number; y?: number }): void
197
- put(x: number, y: number, ch: string, style?: Style): void
198
- fill(
199
- x: number,
200
- y: number,
201
- w: number,
202
- h: number,
203
- ch?: string,
204
- style?: Style,
205
- ): void
206
- scroll(lines: number): void
207
- setCursor(x: number, y: number, visible?: boolean): void
208
- batch(fn: () => void): void
209
- commit(): void
210
- on(event: TerminalEvent, cb: (e: TerminalEventPayload) => void): () => void
211
- dispose(): void
212
- }
213
- ```
115
+ ## Documentation
214
116
 
215
- ## 事件模型(设计草案)
117
+ | Page | Purpose |
118
+ | ---------------------------------------------------------------- | -------------------------------------------------------------------- |
119
+ | [Docs home](./docs/index.md) | Product overview and reading path |
120
+ | [Examples index](./docs/examples.md) | Browser, terminal, and smoke example commands |
121
+ | [Core API](./docs/api.md) | Terminal, renderer, events, runtime, planes, and scheduler contracts |
122
+ | [Performance](./docs/performance.md) | Practical performance guidance |
123
+ | [High-throughput rendering](./docs/high-throughput-rendering.md) | Scheduler, dirty rows, mailbox, log, and renderer architecture |
124
+ | [Agent Console](./docs/agent-console.md) | Streaming transcript example stack |
125
+ | [Release candidate](./docs/release-candidate.md) | 0.x validation, package export checks, and migration notes |
216
126
 
217
- - 事件名称与 Vue3 DOM 事件对齐(`@click`, `@keydown`, `@input` 等)
218
- - DOM 事件转换为 cell 坐标 (cellX/cellY)
219
- - hit test 查找当前坐标命中的节点 (支持 zIndex)
127
+ Run the docs locally:
220
128
 
221
- ```ts
222
- type TerminalEvent =
223
- | 'click'
224
- | 'dblclick'
225
- | 'contextmenu'
226
- | 'pointerdown'
227
- | 'pointerup'
228
- | 'pointermove'
229
- | 'pointerenter'
230
- | 'pointerleave'
231
- | 'mousedown'
232
- | 'mouseup'
233
- | 'mousemove'
234
- | 'mouseenter'
235
- | 'mouseleave'
236
- | 'wheel'
237
- | 'keydown'
238
- | 'keyup'
239
- | 'input'
240
- | 'change'
241
- | 'compositionstart'
242
- | 'compositionupdate'
243
- | 'compositionend'
244
- | 'focus'
245
- | 'blur'
246
- | 'drag'
247
-
248
- type TerminalBaseEvent = {
249
- type: TerminalEvent
250
- target: TerminalNode | null
251
- currentTarget: TerminalNode | null
252
- bubbles: boolean
253
- cancelable: boolean
254
- defaultPrevented: boolean
255
- timeStamp: number
256
- stopPropagation(): void
257
- preventDefault(): void
258
- nativeEvent?: Event
259
- }
260
-
261
- type TerminalPointerEvent = TerminalBaseEvent & {
262
- clientX: number
263
- clientY: number
264
- cellX: number
265
- cellY: number
266
- button?: number
267
- buttons?: number
268
- ctrlKey?: boolean
269
- shiftKey?: boolean
270
- altKey?: boolean
271
- metaKey?: boolean
272
- deltaY?: number
273
- }
274
-
275
- type TerminalKeyboardEvent = TerminalBaseEvent & {
276
- key: string
277
- code: string
278
- ctrlKey?: boolean
279
- shiftKey?: boolean
280
- altKey?: boolean
281
- metaKey?: boolean
282
- repeat?: boolean
283
- }
129
+ ```bash
130
+ pnpm run docs:dev
131
+ pnpm run docs:build
284
132
  ```
285
133
 
286
- ## 事件派发与冒泡(建议)
287
-
288
- - 默认冒泡,支持 `stopPropagation()`/`preventDefault()`,语义与 DOM 一致
289
- - 支持捕获阶段(可选),用于全局拦截(与 `.capture` 对齐)
290
- - 拖拽使用 pointer capture,保证按下后持续命中
291
- - 支持 `contextmenu` 事件(右键菜单)
292
-
293
- ## 事件桥接(建议)
294
-
295
- - Terminal 事件与 Vue 组件事件做统一归一化
296
- - 事件路径包含命中节点链,便于冒泡与拦截
297
- - `pointer` 事件优先于 `mouse`,便于兼容触控
298
-
299
- ## Vue3 浏览器事件对齐(约定)
300
-
301
- - 事件名称:与浏览器 DOM 事件一致(`click`, `keydown`, `input`, `focus` 等)
302
- - 事件修饰符:支持 `.stop` `.prevent` `.capture` `.once` `.passive` `.self` `.exact`
303
- - 键盘修饰符:`.ctrl` `.shift` `.alt` `.meta` `.enter` `.esc` 等与 Vue3 行为一致
304
- - 指针/鼠标:`pointer*` 优先,`mouse*` 兼容;`clientX/clientY` 保留
305
- - 事件对象:保留原生字段,并额外提供 `cellX/cellY` 与 `nativeEvent`
306
- - `v-model`:保持 `modelValue` + `update:modelValue` 的 Vue3 约定
307
-
308
- ## 事件映射表(核心字段)
134
+ ## Examples
309
135
 
310
- ```
311
- DOM Mouse/Pointer Event -> TerminalPointerEvent
312
- - clientX/clientY 保留,额外提供 cellX/cellY
313
- - button/buttons/ctrlKey/shiftKey/altKey/metaKey 保留
314
- DOM Keyboard Event -> TerminalKeyboardEvent
315
- - key/code/repeat/ctrlKey/shiftKey/altKey/metaKey 保留
316
- DOM Input/Composition Event -> TerminalBaseEvent
317
- - inputType/data 通过 nativeEvent 获取
136
+ ```bash
137
+ pnpm -C examples/basic dev
138
+ pnpm run build:examples
139
+ pnpm run build:examples:terminal
140
+ pnpm run run:basic:terminal
141
+ pnpm run example:tlog-view-lab
142
+ pnpm run example:agent-console
143
+ pnpm run example:agent-console:smoke
144
+ pnpm run example:agent-console:terminal:smoke
318
145
  ```
319
146
 
320
- ## `@input` / `@change` 触发规则(建议)
147
+ The smoke commands are deterministic and avoid real LLM APIs, real TTY dependencies, and timing-only pass/fail gates.
321
148
 
322
- - `TInput` 输入过程中触发 `input`,提交时触发 `change`
323
- - `compositionstart/update/end` 与浏览器一致,结束后触发一次 `input`
324
- - `v-model` 绑定:`input` 时更新 `modelValue`,`change` 作为提交确认
149
+ ## Performance Notes
325
150
 
326
- ## Pointer Capture / Focus / Blur 规则(建议)
151
+ - Use `TVirtualList` instead of rendering thousands of row components.
152
+ - Use `TLogView` with `createAppendOnlyLogStore({ maxLines })` for retained streaming logs.
153
+ - Provide stable line keys for custom `TLogView` sources; mutable rows should change keys or call the explicit invalidation APIs.
154
+ - Split high-volume content and frequently changing chrome into different `TRenderPlane`s.
155
+ - Reuse style objects on hot paths instead of creating new object literals every frame.
327
156
 
328
- - `pointerdown` 后启用捕获,直到 `pointerup` 释放
329
- - `focus` 由点击或 `v-focus` 触发,`blur` 由切换焦点或卸载触发
330
- - `focusin/focusout` 可选支持,用于冒泡式焦点事件
157
+ Useful checks:
331
158
 
332
- ## Vue 组件层(设计草案)
333
-
334
- ```vue
335
- <TerminalProvider :cols="80" :rows="24">
336
- <TView :x="2" :y="2" :w="20" :h="5" @click="onClick">
337
- <TText :value="title" :style="{ fg: 'green' }" />
338
- <TBox border />
339
- </TView>
340
- </TerminalProvider>
159
+ ```bash
160
+ pnpm run bench:dom-renderer
161
+ pnpm run bench:scroll-mailbox
162
+ pnpm run bench:phase2
341
163
  ```
342
164
 
343
- - `TerminalProvider`: 创建 terminal、绑定 renderer 和 event manager
344
- - `TView`: 提供局部坐标系、事件区域、zIndex
345
- - `TText`: 响应式写入文字
346
- - `TBox`: 绘制边框、标题
165
+ ## Issues And Feedback
347
166
 
348
- ## 通用组件与指令
167
+ - Report bugs: [new bug report](https://github.com/Simon-He95/vue-tui/issues/new?template=bug_report.yml)
168
+ - Request features: [new feature request](https://github.com/Simon-He95/vue-tui/issues/new?template=feature_request.yml)
169
+ - Report documentation issues: [new docs issue](https://github.com/Simon-He95/vue-tui/issues/new?template=docs.yml)
170
+ - Browse existing issues: [GitHub issues](https://github.com/Simon-He95/vue-tui/issues)
349
171
 
350
- - 通用组件:`TSelect`, `TInput`, `TList`, `TTable`, `TDialog`
351
- - 指令:
352
- - `v-if`: 条件渲染/卸载组件,释放 buffer 区域
353
- - `v-show`: 仅隐藏展示,保持节点存在以保留事件与状态
354
- - `v-model`: 绑定 `TInput` 文本与光标状态
355
- - `v-focus`: 让组件获得焦点(键盘输入)
172
+ For renderer, scheduler, or terminal behavior bugs, include the renderer target (`DOM`, `stdout`, or headless), the relevant command, and a minimal reproduction when possible.
356
173
 
357
- ## 动态插入组件(命令式)
174
+ ## Development
358
175
 
359
- 支持在事件回调中插入组件,例如监听 `input` 后插入 `TSelect`。
360
- 通过 `useTerminalRuntime()` 或 `createPortal()` 提供命令式入口。
361
-
362
- ```ts
363
- const { mount } = useTerminalRuntime()
364
-
365
- function onInputCommit(value: string) {
366
- if (value.startsWith('/')) {
367
- mount(TSelect, {
368
- x: 2,
369
- y: 10,
370
- w: 20,
371
- h: 6,
372
- options: ['a', 'b', 'c'],
373
- onSelect: (v) => console.log(v),
374
- })
375
- }
376
- }
176
+ ```bash
177
+ pnpm install
178
+ pnpm run format:check
179
+ pnpm run lint
180
+ pnpm run typecheck
181
+ pnpm run test
182
+ pnpm run build
377
183
  ```
378
184
 
379
- 约束:
380
-
381
- - 动态插入的组件必须显式提供布局 (x/y/w/h) 或依赖父容器布局
382
- - 插入/卸载会触发局部重绘,不影响其它区域
383
-
384
- ## 命令式渲染协议(建议)
385
-
386
- - `mount()` 返回 handle,包含 `update()` / `unmount()` / `move()` 等操作
387
- - 允许传入 `key` 复用实例,避免频繁销毁
388
- - `TerminalProvider` 卸载时自动清理所有命令式节点
185
+ Release validation:
389
186
 
390
- ```ts
391
- type TerminalHandle = {
392
- update: (props: Record<string, unknown>) => void
393
- move: (x: number, y: number) => void
394
- unmount: () => void
395
- }
187
+ ```bash
188
+ pnpm run release:dry-run
396
189
  ```
397
190
 
398
- ## 组件生命周期与资源管理(建议)
399
-
400
- - 挂载:注册事件节点、占用 buffer 区域、写入初始内容
401
- - 更新:清理旧区域 + 写入新内容,保持最小 dirty 范围
402
- - 卸载:释放事件节点、清理 buffer 区域、移除焦点/输入绑定
403
-
404
- 对 `v-if`/`v-show` 的行为约定:
405
-
406
- - `v-if`: 触发卸载与资源释放(清 buffer、解绑事件)
407
- - `v-show`: 仅隐藏渲染,保留节点与状态(不解绑事件)
408
-
409
- ## 焦点与输入协议(建议)
410
-
411
- - 引入 focus manager,维护当前焦点组件
412
- - `v-focus`/`focus()` 触发焦点切换,自动更新光标样式
413
- - 键盘事件仅派发给焦点组件
414
- - `TInput` 需要处理:
415
- - 文本插入、删除、移动光标
416
- - 组合输入(IME)阶段的暂存显示
417
- - Enter/Escape 行为(提交/取消)
418
-
419
- ## 键盘与快捷键(建议)
420
-
421
- - 统一规范化键名(如 `Enter`/`Esc`/`ArrowUp`)
422
- - 仅焦点组件接收输入,支持全局快捷键注册
423
- - 支持组合键与平台差异(macOS/Windows/Linux)
424
-
425
- ## 常见组件交互约定(示例)
426
-
427
- - `TSelect`:
428
- - 上下键切换选项,Enter 确认,Esc 取消
429
- - `onOpen`/`onClose` 用于显示/隐藏下拉
430
- - `TList`:
431
- - 支持滚动、虚拟化(列表过长时)
432
- - `TDialog`:
433
- - 居中布局、遮罩区域、阻止底层事件
434
-
435
- ## 响应式与尺寸变化(建议)
436
-
437
- - `TerminalProvider` 监听容器尺寸变化,触发 `resize(cols, rows)` 并广播 `resize` 事件
438
- - 组件接收 `onResize` 或 `useTerminalSize()` 响应尺寸变化
439
- - 布局建议:
440
- - `TView` 支持 `w/h` 为百分比或 `auto`(依赖父容器)
441
- - resize 时触发局部重排,避免全量重绘
442
-
443
- ## 布局与坐标系统(建议)
444
-
445
- - 坐标系基于 cell 网格,所有位置/尺寸以整数为主
446
- - 布局模式:
447
- - `absolute`: `x/y/w/h` 明确指定
448
- - `flow`: 垂直/水平流布局(简化版)
449
- - `anchor`: 支持 `left/right/top/bottom` 锚定
450
- - 约束:`minW/maxW/minH/maxH`,超出时裁剪
451
- - 容器提供 `padding` 与 `clip`,子组件默认裁剪到内容区域
452
-
453
- ## 布局计算(简版规则)
454
-
455
- - 先计算父容器 contentRect,再计算子组件布局
456
- - `absolute` 优先:有明确 `x/y/w/h` 时直接裁剪
457
- - `anchor` 次之:根据边距计算剩余空间
458
- - `flow` 最后:按方向累积尺寸,支持 `gap` 与 `wrap`
459
- - `auto` 尺寸:基于内容测量(文本/子组件)得到
460
-
461
- ## 带边框 Box 的内容保护
462
-
463
- 当 `TBox` 带边框时,需要保护内容区域不被破坏:
464
-
465
- - 外框占 1 cell 边距,内容区域为 `(x+1, y+1, w-2, h-2)`
466
- - 内容写入必须裁剪到内容区域,避免覆盖边框
467
- - 当内容超出时,支持 `overflow: clip | scroll`
468
- - 建议 `TBox` 内部提供 `padding` 与 `contentRect`,子组件写入基于 `contentRect`
469
-
470
- ## 渲染策略(初版)
471
-
472
- - 以行 (row) 为单位进行 dirty 标记
473
- - 每行合并相同样式为 span,减少 DOM 节点数
474
- - `batch()` + `commit()` 合并更新
475
-
476
- ## 渲染调度(建议)
477
-
478
- - 所有写入走调度器聚合到下一帧(`requestAnimationFrame`)
479
- - `batch()` 在同一帧内合并多个写入,减少 diff 次数
480
- - 支持 `flush()` 立即渲染(用于调试或关键交互)
481
-
482
- ## 字体度量与像素映射(建议)
483
-
484
- - 统一使用等宽字体,测量 `cellWidth`/`cellHeight`
485
- - 设备像素比变化时重新测量并触发重排
486
- - 支持固定 `cellSize` 覆盖测量结果(用于稳定布局)
487
-
488
- ## ANSI 支持
489
-
490
- - `writeAnsi()` 接受 ANSI 字符串,解析后写入 Buffer
491
- - 可先实现轻量解析器,后续切换到更完整的 ANSI 样式库(如 `ansis`)
492
-
493
- ## 文本分段与宽字符策略(建议)
494
-
495
- - 使用 grapheme 分段,避免组合字符被拆分
496
- - 宽字符占用 2 cell,后续 cell 标记为 continuation
497
- - 无法渲染的字符使用占位符(如 `?`)并记录告警
498
-
499
- ## 主题与样式系统(建议)
500
-
501
- - 提供 `Theme` 对象(默认 fg/bg、16/256 色板、字体设置)
502
- - ANSI 颜色映射依赖主题,可热更新
503
- - 允许组件局部覆盖主题(如 `TDialog`)
504
-
505
- ## 光标、选择与剪贴板(建议)
506
-
507
- - 光标形态:`block`/`underline`/`bar`,支持闪烁
508
- - 选择:鼠标拖拽选区,支持跨行
509
- - 剪贴板:复制/粘贴基于 Buffer 内容而非 DOM 文本
510
-
511
- ## 设计注意事项
512
-
513
- - 文本宽度:需支持 grapheme + wcwidth,避免 emoji/组合字符错位
514
- - 组合模型:建议引入容器裁剪与 zIndex,避免组件相互覆盖
515
- - 调度机制:统一 batch/commit,避免组件更新引发频繁重绘
516
- - 事件映射:需基于字体度量映射 cell 坐标,resize 时重算
517
- - 滚动与 resize:需要明确 scrollback 与重排策略
191
+ `release:dry-run` runs checks, tests, docs build, benchmarks, examples smoke, and packed package install smoke.
518
192
 
519
- ## 后续计划(草案)
193
+ ## Package Notes
520
194
 
521
- - 基础组件库完善 (TList/TInput/TTable)
522
- - Canvas 渲染器
523
- - 虚拟滚动和大 buffer 支持
195
+ - The published package ships `dist` only.
196
+ - Root, markdown, and experimental entrypoints are available as ESM, CJS, and type declarations after build.
197
+ - The root browser/core API does not require a Node runtime, but CLI usage expects a Node-like stdout/stdin environment.
198
+ - Terminal emoji and East Asian width behavior still depends on the user terminal and font.
524
199
 
525
200
  ## License
526
201