@simon_he/vue-tui 0.0.6 → 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 +145 -470
- package/dist/experimental.cjs +8847 -0
- package/dist/experimental.d.ts +825 -0
- package/dist/experimental.js +7475 -0
- package/dist/index.cjs +7695 -4695
- package/dist/index.d.ts +396 -164
- package/dist/index.js +6086 -4232
- package/dist/markdown.cjs +20560 -0
- package/dist/markdown.d.ts +112 -0
- package/dist/markdown.js +1581 -0
- package/dist/path-suggest-BeV6n7m-.js +3 -0
- package/dist/sgr-Tko2EQ0U.js +484 -0
- package/dist/theme-Bsm65g8k.d.ts +32 -0
- package/dist/types-ClIV2h1o.d.ts +103 -0
- package/dist/wheel-scroll-CiNsasLf.js +825 -0
- package/package.json +83 -45
- package/dist/path-suggest-DIMby3r0.js +0 -3
- /package/dist/{path-suggest-CZQYJIIg.js → path-suggest-DmrmeueH.js} +0 -0
package/README.md
CHANGED
|
@@ -1,526 +1,201 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @simon_he/vue-tui
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
## LLM 集成(对接指南)
|
|
18
|
+
Vue is a peer dependency. The current package supports Vue `>=3.3.0 <4`.
|
|
95
19
|
|
|
96
|
-
|
|
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
|
-
|
|
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
|
-
|
|
30
|
+
## Browser Usage
|
|
105
31
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
- `
|
|
178
|
-
- `
|
|
179
|
-
-
|
|
180
|
-
- `
|
|
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
|
-
##
|
|
102
|
+
## Components
|
|
183
103
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
218
|
-
- DOM 事件转换为 cell 坐标 (cellX/cellY)
|
|
219
|
-
- hit test 查找当前坐标命中的节点 (支持 zIndex)
|
|
127
|
+
Run the docs locally:
|
|
220
128
|
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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
|
-
|
|
147
|
+
The smoke commands are deterministic and avoid real LLM APIs, real TTY dependencies, and timing-only pass/fail gates.
|
|
321
148
|
|
|
322
|
-
|
|
323
|
-
- `compositionstart/update/end` 与浏览器一致,结束后触发一次 `input`
|
|
324
|
-
- `v-model` 绑定:`input` 时更新 `modelValue`,`change` 作为提交确认
|
|
149
|
+
## Performance Notes
|
|
325
150
|
|
|
326
|
-
|
|
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
|
-
|
|
329
|
-
- `focus` 由点击或 `v-focus` 触发,`blur` 由切换焦点或卸载触发
|
|
330
|
-
- `focusin/focusout` 可选支持,用于冒泡式焦点事件
|
|
157
|
+
Useful checks:
|
|
331
158
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
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
|
-
```
|
|
391
|
-
|
|
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
|
-
-
|
|
522
|
-
-
|
|
523
|
-
-
|
|
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
|
|