# @bunli/tui 中文文档

规范地址：https://npmcn.com/package/%40bunli/tui/

版本：0\.6\.0
npm 元数据更新时间：2026-03-27T23:26:44.142Z
中文译文更新时间：2026-11-08T19:54:00.568Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40bunli/tui
原文对照：https://npmcn.com/package/%40bunli/tui/?lang=original

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：279 kB，161 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：7 个
- peer 依赖：@opentui/core ^0\.1\.90，react ^19\.2\.4
- 首次发布：2025-10-24T09:53:41.015Z
- 最新版本发布：2026-03-27T23:26:44.046Z
- 近 30 天下载量：3129（2026-10-09 至 2026-11-07，npm 官方下载统计）
- 已发布版本数：15（近 12 个月 14 个）

## 中文简介

Bunli CLI 框架的终端用户界面插件

## 安装

```sh
npm install @bunli/tui
```

也可以使用：`pnpm add @bunli/tui`、`yarn add @bunli/tui`、`bun add @bunli/tui`

## README

# @bunli/图伊

一个基于反应的终端用户界面库,用于Bunli CLI框架,由OpenTUI的React渲染器提供动力.

## 特征

-   **基于反应的组件**: 使用熟悉的反应模式和JSX构建 TUIs
-   **构成部分库**: 交替缓冲 TUI 的格式、布局、反馈、数据显示和图表组件
-   **OpenTUI 整合**: 完全访问 OpenTUI 的回放钩和组件
-   **类型安全**: 完整类型脚本支持,并有适当的类型推论
-   **动画支持**:平滑动画的内置时间系统
-   **键盘处理**: 方便键盘事件管理 `useKeyboard`
-   **第一级别 TUI 支持**: TUI 渲染是一个一等特性, 不是插件
-   **主题系统**: 预设主题并带有符号覆盖 `ThemeProvider`编号 :`createTheme`

## 安装

```bash
bun add @bunli/tui react
```

## 快速启动

```typescript
import { createCLI, defineCommand } from '@bunli/core'

const cli = await createCLI({
  name: 'my-app',
  version: '1.0.0'
})

// Define a command with TUI using the render property
const myCommand = defineCommand({
  name: 'deploy',
  description: 'Deploy application',
  render: () => (
    <box title="Deployment" style={{ border: true, padding: 2 }}>
      <text>Deploying...</text>
    </box>
  ),
  handler: async () => {
    // Non-TUI fallback when render is skipped
    console.log('Deploying application...')
  }
})

cli.command(myCommand)
await cli.run()
```

Bunli自动接通OpenTUI运行时间. 运行时间/文本 API 现在来自 `@bunli/runtime/app`,即时/会话API来自 `@bunli/runtime/prompt`,以及 `@bunli/tui` 专注于UI组件和钩.

### TUI 执行语义

-   带有 `render` 在交互式终端中运行.
-   非交互终端返回到 `handler` 当在现相.
-   明确配置全屏流量 `bufferMode: 'alternate'`。 。 。 .

### Render 寿命周期( 运行时退出)

使用的命令 `render` 最终必须呼叫 `useRuntime().exit()` (例如,在提交/取消/请求时),或命令不会退出.

```typescript
import { useRuntime } from '@bunli/runtime/app'
import { useKeyboard } from '@bunli/tui'

function DeployTUI() {
  const runtime = useRuntime()

  useKeyboard((key) => {
    if (key.name === 'q' || (key.ctrl && key.name === 'c')) {
      runtime.exit()
    }
  })

  return <text>Press q to quit</text>
}
```

## 缓冲模式( 替代对标准)

OpenTUI可以使用可替换的屏幕缓冲器(全屏TUI)或标准终端缓冲器(以回滚方式输出)来渲染.

配置此内容 `createCLI()` 配置 :

```typescript
const cli = await createCLI({
  name: 'my-app',
  version: '1.0.0',
  tui: {
    renderer: {
      bufferMode: 'alternate' // or 'standard'
    }
  }
})
```

注释:

-   `bufferMode: 'standard'` 默认值.
-   使用 `bufferMode: 'alternate'` 用于全屏/屏蔽体验.
-   鼠标跟踪默认已禁用( S)`useMouse: false`),以避免在标准缓冲工作流程中退出后泄露生鼠逃生序列. 需要时明确启用 .

## 使用量

### 模块分割

根据模式使用子路径导出 :

-   `@bunli/tui/interactive`: 交替缓冲交互组件.
-   `@bunli/tui/charts`:终端-本土图原始.
-   `@bunli/tui`: root 导出后再出口共享组件/套接字.
-   `@bunli/runtime/app`:运行时间生命周期/文本 API.
-   `@bunli/runtime/prompt`: 即时/会话API.

### Clack 迁移快速地图

用 Bunli- native API 替换 clack 智能模型时使用此功能 :

```typescript
// clack
// import { intro, outro, confirm, select, multiselect, log } from '@clack/prompts'

// bunli
// prompt is provided via handler args by Bunli

prompt.intro('Setup')
const confirmed = await prompt.confirm('Continue?', { default: true })
const env = await prompt.select('Environment', {
  options: [
    { label: 'Development', value: 'dev' },
    { label: 'Production', value: 'prod' }
  ]
})
const features = await prompt.multiselect('Features', {
  options: [
    { label: 'Testing', value: 'testing' },
    { label: 'Docker', value: 'docker' }
  ],
  initialValues: ['testing']
})
prompt.log.success(`Selected ${env}`)
prompt.outro('Done')
```

### 基本TUI组件

```typescript
import { defineCommand } from '@bunli/core'

function MyTUI() {
  return (
    <box title="My App" style={{ border: true, padding: 2 }}>
      <text>Hello from My App!</text>
    </box>
  )
}

export const myCommand = defineCommand({
  name: 'my-command',
  description: 'My command with TUI',
  render: () => <MyTUI />,
  handler: async () => {
    console.log('Running my-command in CLI mode')
  }
})
```

### 使用窗体组件

```typescript
import { defineCommand } from '@bunli/core'
import { useRuntime } from '@bunli/runtime/app'
import { SchemaForm } from '@bunli/tui'
import { z } from 'zod'

const configSchema = z.object({
  apiUrl: z.string().url('Enter a valid URL'),
  region: z.enum(['us-east', 'us-west'])
})

function ConfigTUI() {
  const runtime = useRuntime()
  const regions = [
    { label: 'US East', value: 'us-east', hint: 'US East region' },
    { label: 'US West', value: 'us-west', hint: 'US West region' }
  ]

  return (
    <SchemaForm
      title="Configure Settings"
      schema={configSchema}
      fields={[
        {
          kind: 'text',
          name: 'apiUrl',
          label: 'API URL',
          placeholder: 'https://api.example.com',
          required: true
        },
        {
          kind: 'select',
          name: 'region',
          label: 'Region',
          options: regions
        }
      ]}
      onSubmit={(values) => {
        console.log('Validated form values:', values)
      }}
      onCancel={() => runtime.exit()}
    />
  )
}

export const configureCommand = defineCommand({
  name: 'configure',
  description: 'Configure application settings',
  render: () => <ConfigTUI />
})
```

### 使用 OpenTUI 钩

```typescript
import { useRuntime } from '@bunli/runtime/app'
import { useKeyboard, useTimeline, useTerminalDimensions } from '@bunli/tui'

function InteractiveTUI({ command }) {
  const [count, setCount] = useState(0)
  const { width, height } = useTerminalDimensions()
  const runtime = useRuntime()
  
  const timeline = useTimeline({ duration: 2000 })
  
  useKeyboard((key) => {
    if (key.name === 'q') {
      runtime.exit()
    }
    if (key.name === 'space') {
      setCount(prev => prev + 1)
    }
  })
  
  useEffect(() => {
    timeline.add({ count: 0 }, {
      count: 100,
      duration: 2000,
      onUpdate: (anim) => setCount(anim.targets[0].count)
    })
  }, [])
  
  return (
    <box title="Interactive Demo" style={{ border: true, padding: 2 }}>
      <text>Count: {count}</text>
      <text>Terminal: {width}x{height}</text>
      <text>Press SPACE to increment, Q to quit</text>
    </box>
  )
}
```

## 构成部分库

交互式组件可从 `@bunli/tui/interactive` 和根出口.

包含原始人 :

-   表单 : `Form`, (中文(简体) ), `SchemaForm`, (中文(简体) ), `FormField`, (中文(简体) ), `SelectField`
-   表单 v2: `NumberField`, (中文(简体) ), `PasswordField`, (中文(简体) ), `TextareaField`, (中文(简体) ), `CheckboxField`, (中文(简体) ), `MultiSelectField`
-   布局 : `Container`, (中文(简体) ), `Stack`, (中文(简体) ), `Grid`, (中文(简体) ), `Panel`, (中文(简体) ), `Card`, (中文(简体) ), `Divider`, (中文(简体) ), `SectionHeader`
-   导航/流程 : `Tabs`, (中文(简体) ), `Menu`, (中文(简体) ), `CommandPalette`, (中文(简体) ), `Modal`
-   反馈 : `Alert`, (中文(简体) ), `Badge`, (中文(简体) ), `Toast`, (中文(简体) ), `ProgressBar`, (中文(简体) ), `EmptyState`
-   数据显示 : `List`, (中文(简体) ), `Table`, (中文(简体) ), `DataTable`, (中文(简体) ), `KeyValueList`, (中文(简体) ), `Stat`, (中文(简体) ), `Markdown`, (中文(简体) ), `Diff`
-   图: `BarChart`, (中文(简体) ), `LineChart`, (中文(简体) ), `Sparkline` 从 `@bunli/tui/charts`
-   运行时管弦乐/吼: 从 `@bunli/runtime/app` (单位:千美元)`DialogProvider`, (中文(简体) ), `useDialogManager`, (中文(简体) ), `FocusScopeProvider`, (中文(简体) ), `useScopedKeyboard`页:1

### 键盘合同

交互式原始文件的默认键盘绑定 :

-   `Modal`数字 : `Esc` 编号 : `Ctrl+C` 关上, `Tab`编号 :`Shift+Tab` 焦点陷阱
-   `Dialog confirm`数字 : `Left`编号 :`h`编号 :`y` - > 确认, `Right`编号 :`l`编号 :`n` - > 取消选择, `Tab` 切换, `Enter` 提交
-   `Dialog choose`数字 : `Up`编号 :`k` 先前, `Down`编号 :`j` 接下来, `Enter` 提交。 为选择/导航而跳过已禁用的选项 .
-   `Menu`数字 : `Up`编号 :`k`, (中文(简体) ), `Down`编号 :`j`, (中文(简体) ), `Enter`
-   `Tabs`数字 : `Left`编号 :`h` 上一个标签, `Right`编号 :`l` 下一个标签
-   `CommandPalette`数字 : `Up`编号 :`k`, (中文(简体) ), `Down`编号 :`j`, (中文(简体) ), `Enter`
-   `DataTable`数字 : `Left`编号 :`h` 上一个排序列, `Right`编号 :`l` 下一个排序列, `Up`编号 :`k` 上一行,请, `Down`编号 :`j` 下一个行, `Enter` 选择行
-   `Form`数字 : `Tab`编号 :`Shift+Tab` 实地导航, `Ctrl+S` 提交, `Ctrl+R` 重设, `F8`编号 :`Shift+F8` 跳转出错字段, `Esc` 取消( e)

### 对话框管理器

使用对话框管理器来堆放确认/选择流 , 具有一致的优先处理和解职语义 .

```typescript
import { useDialogManager, DialogDismissedError } from '@bunli/runtime/app'

function Screen() {
  const dialogs = useDialogManager()

  async function deploy() {
    try {
      const confirmed = await dialogs.confirm({
        title: 'Deploy',
        message: 'Ship this release now?'
      })
      if (!confirmed) return

      const target = await dialogs.choose({
        title: 'Target',
        options: [
          { label: 'Staging', value: 'staging', section: 'General' },
          { label: 'Production', value: 'production', section: 'Protected', disabled: true }
        ]
      })

      console.log('Deploying to', target)
    } catch (error) {
      if (error instanceof DialogDismissedError) {
        console.log('Dialog dismissed')
      }
    }
  }

  return <box />
}
```

### 表单

用于受控交互式形式的由计划驱动的容器.

```typescript
const runtime = useRuntime()

<Form 
  title="My Form"
  schema={schema}
  onSubmit={(values) => console.log(values)}
  onCancel={() => runtime.exit()}
>
  {/* Form fields */}
</Form>
```

**道具 :**

-   `title: string` - 表格标题
-   `schema: StandardSchemaV1` - 验证计划(支持Zod和其他标准Schema适配器)
-   `onSubmit: (values) => void | Promise<void>` - 提交具有计划验证值的处理器
-   `onCancel?: () => void` - 取消处理器(可选)
-   `onValidationError?: (errors: Record<string, string>) => void` - 验证错误召回
-   `initialValues?: Partial<InferOutput<schema>>` - 初始控制值
-   `validateOnChange?: boolean` - 输入/选择时验证(默认) `true`(中文(简体) )
-   `submitHint?: string` - 页脚提示覆盖
-   `onReset?: () => void` - 重置回调
-   `onDirtyChange?: (isDirty, dirtyFields) => void` - 肮脏的状态召回
-   `onSubmitStateChange?: ({ isSubmitting, isValidating }) => void` - 自动调用状态
-   `scopeId?: string` - 嵌入式交互式流动的键盘范围边界 id

### 形状

更高层次的造型建构器,使字段来自描述符.

```typescript
<SchemaForm
  title="Deploy"
  schema={schema}
  fields={[
    { kind: 'text', name: 'service', label: 'Service' },
    { kind: 'select', name: 'env', label: 'Environment', options: envOptions },
    { kind: 'checkbox', name: 'telemetry', label: 'Enable telemetry' },
    {
      kind: 'textarea',
      name: 'notes',
      label: 'Release notes',
      visibleWhen: (values) => values.env === 'production'
    }
  ]}
  onSubmit={(values) => console.log(values)}
/>
```

支助 `SchemaForm` 字段类型 :

-   `text`
-   `select`
-   `multiselect`
-   `number`
-   `password`
-   `textarea`
-   `checkbox`

场级行为 :

-   `visibleWhen(values) => boolean` 用于有条件渲染.
-   `deriveDefault(values) => unknown` 用于依赖性默认初始化.

### 表单字段

受控文本字段必须形成上下文 .

```typescript
<FormField
  label="Username"
  name="username"
  placeholder="Enter username"
  required
  defaultValue=""
/>
```

**道具 :**

-   `label: string` - 实地标签
-   `name: string` - 字段名称
-   `placeholder?: string` - 占位符文本
-   `required?: boolean` - 是否需要字段
-   `description?: string` - 帮助文本
-   `defaultValue?: string` - 形式状态初始值
-   `onChange?: (value: string) => void` - 更改处理器
-   `onSubmit?: (value: string) => void` - 提交处理器

### 选择字段

受控的选定字段将形成上下文 .

```typescript
<SelectField
  label="Environment"
  name="env"
  options={[
    { label: 'Development', value: 'dev', hint: 'Development environment' },
    { label: 'Production', value: 'prod', hint: 'Production environment' }
  ]}
  defaultValue="dev"
  onChange={setEnvironment}
/>
```

**道具 :**

-   `label: string` - 实地标签
-   `name: string` - 字段名称
-   `options: SelectOption[]` - 可用的选项
-   `required?: boolean` - 是否需要字段
-   `description?: string` - 帮助文本
-   `defaultValue?: SelectOption['value']` - 初始选定值
-   `onChange?: (value: SelectOption['value']) => void` - 更改处理器

### 进度栏

显示完成状态的进度栏组件 .

```typescript
<ProgressBar 
  value={75} 
  label="Upload Progress" 
  color="#00ff00" 
/>
```

**道具 :**

-   `value: number` - 进度值(0-100)
-   `label?: string` - 进度标签
-   `color?: string` - 进步栏颜色

### 图表初级

`@bunli/tui/charts` 支持负和稀有值,轴标签,以及多序列调色板.

```typescript
import { BarChart, LineChart } from '@bunli/tui/charts'

<BarChart
  series={[
    { name: 'build', points: [{ label: 'Mon', value: -2 }, { label: 'Tue', value: 6 }] },
    { name: 'test', points: [{ label: 'Mon', value: null }, { label: 'Tue', value: 4 }] }
  ]}
  axis={{ yLabel: 'Jobs', xLabel: 'Day', showRange: true }}
/>

<LineChart
  series={{ name: 'latency', points: [{ value: 120 }, { value: 98 }, { value: null }, { value: 104 }] }}
  axis={{ yLabel: 'ms' }}
/>
```

### 主题提供和托肯斯

使用 `ThemeProvider` 以应用内置主题预设或符号覆盖.

```typescript
import { ThemeProvider, createTheme } from '@bunli/tui/interactive'

const customTheme = createTheme({
  preset: 'dark',
  tokens: {
    accent: '#3ec7ff',
    textSuccess: '#3cd89b'
  }
})

function App() {
  return (
    <ThemeProvider theme={customTheme}>
      <Panel title="Deploy status">
        <Alert tone="success" message="Ready to ship" />
      </Panel>
    </ThemeProvider>
  )
}
```

## OpenTUI 钩

套件再导出有用的 OpenTUI React hooks :

### 使用键盘

处理键盘事件.

```typescript
import { useRuntime } from '@bunli/runtime/app'
import { useKeyboard } from '@bunli/tui'

const runtime = useRuntime()

useKeyboard((key) => {
  if (key.name === 'escape') {
    runtime.exit()
  }
})
```

### 使用渲染器

访问 OpenTUI 渲染器实例 .

```typescript
import { useRenderer } from '@bunli/tui'

const renderer = useRenderer()
renderer.console.show()
```

使用 `useRenderer()` 仅限高级出纳器检查/控制。 使用 `useRuntime().exit()` 用于完成正常命令.

### 使用终端数字

获取当前终端维度 .

```typescript
import { useTerminalDimensions } from '@bunli/tui'

const { width, height } = useTerminalDimensions()
```

### 使用时间线

创建和管理动画.

```typescript
import { useTimeline } from '@bunli/tui'

const timeline = useTimeline({ duration: 2000 })

timeline.add({ x: 0 }, {
  x: 100,
  duration: 2000,
  onUpdate: (anim) => setX(anim.targets[0].x)
})
```

### 仅使用回复

处理终端调整事件大小 .

```typescript
import { useOnResize } from '@bunli/tui'

useOnResize((width, height) => {
  console.log(`Terminal resized to ${width}x${height}`)
})
```

## 渲染器配置

通过 `createCLI({ tui: { renderer } })` 和可选命令级别覆盖 `command.tui.renderer`。 。 。 .

## OpenTUI 组件

您可以直接使用任何 OpenTUI 反应组件 :

```typescript
import { render } from '@opentui/react'

function MyComponent() {
  return (
    <box style={{ border: true, padding: 2 }}>
      <text>Hello World</text>
      <input placeholder="Type here..." />
      <select options={options} />
    </box>
  )
}
```

可用组件 :

-   `<box>` - 有边界和布局的集装箱
-   `<text>` - 有样式的文本显示
-   `<input>` - 文本输入字段
-   `<select>` - 下拉选择
-   `<scrollbox>` - 可滚动容器
-   `<ascii-font>` - ASCII 艺术文本
-   `<tab-select>` - 基于标签的选择

## 实例

见 `examples/tui-demo` 完整示例目录 :

-   **部署指挥**: 有时间表的动画进度栏
-   **配置命令**: 带有输入和选择字段的窗体

## 类型脚本支持

软件包提供了完整的TypeScript支持:

```typescript
import type { TuiComponent, TuiComponentProps } from '@bunli/tui'

const MyTUI: TuiComponent = ({ command, args, store }) => {
  // Fully typed props
  return <box>{command.name}</box>
}
```

## 许可证

麻省理工学院

## 常见问题

### @bunli/tui 是什么？

Bunli CLI 框架的终端用户界面插件

### 如何安装 @bunli/tui？

在项目目录运行 npm install @bunli/tui，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：@opentui/core（^0\.1\.90）、react（^19\.2\.4）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @bunli/tui 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @bunli/tui 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @bunli/tui 可以商用吗？

@bunli/tui 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @bunli/tui 的下载量有多少？

根据 npm 官方下载统计，@bunli/tui 在 2026/10/09 – 2026/11/07 这 30 天内被下载 3,129 次，日均约 104 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @bunli/tui 还在维护吗？

最新版本 0\.6\.0 发布于 2026/03/28（7 个月前）；至今共发布 15 个版本，其中过去 12 个月发布了 14 个；首次发布于 2025/10/24。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

