Metadata-Version: 2.4
Name: tuikinter
Version: 0.2.0
Summary: A reactive, declarative TUI library for Python — indentation is your layout, state changes re-render for you. Powered by Textual.
Project-URL: Homepage, https://github.com/JoshuaMaoJH/tuikinter
Project-URL: Repository, https://github.com/JoshuaMaoJH/tuikinter
Project-URL: Issues, https://github.com/JoshuaMaoJH/tuikinter/issues
Project-URL: Changelog, https://github.com/JoshuaMaoJH/tuikinter/blob/main/CHANGELOG.md
Author: Joshua Mao
License-Expression: MIT
License-File: LICENSE
Keywords: cli,console,declarative,reactive,terminal,textual,tui,ui,widgets
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: User Interfaces
Requires-Python: >=3.9
Requires-Dist: textual>=0.40
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# tuikinter

**响应式、声明式的现代终端 UI 库。** 底层是 [Textual](https://github.com/Textualize/textual)，上层是一套极简的 API：用 `with` 块的**缩进表达布局**，用 `state` 让**界面随数据自动刷新**。

> A reactive, declarative TUI library for Python. Indentation is your layout; state changes re-render the UI for you.

```python
import tuikinter as ui

count = ui.state(0)

with ui.App("我的应用") as app:
    with app.col(pady=1):
        ui.label(lambda: f"  计数: {count}")        # 读了 count，count 一变它自动刷新
        with app.row():
            ui.button("-1", on=lambda: count.set(count - 1), variant="error")
            ui.button("+1", on=lambda: count.set(count + 1), variant="success")
    ui.button("退出", on=app.quit)

app.run()
```

没有一句 `.config(text=...)`，没有手动刷新。`count` 变了，那个 `label` 自己就变了。

---

## 安装

```bash
pip install tuikinter
```

需要 Python 3.9+。依赖 `textual>=0.40`。

## 为什么是它

tuikinter 不是又一个 tkinter 克隆。它拿了两个现代 UI 框架的好思想，放进终端：

- **缩进即布局。** `with app.col():` / `with app.row():` 的嵌套就是界面的层级。代码长什么样，界面就长什么样——像 Flutter / SwiftUI 那样。
- **状态驱动。** `ui.state(x)` 是一个响应式値。渲染函数读了哪些 state，就自动订阅哪些；state 一变，只重渲染用到它的那几个控件——像 Vue / MobX 的自动依赖追踪。

## 核心概念

### `state` —— 响应式状态

```python
count = ui.state(0)

count.get()                 # 读
count.set(5)                # 写
count.value = 5            # 同上
count.update(lambda v: v+1) # 基于旧値算新値

# state 能直接参与运算和格式化，省掉 .get()
count - 1                   # = count.get() - 1
f"计数: {count}"            # 自动取値
```

把一个**函数**传给 `ui.label(...)` 或 `ui.progress(...)`，它就成了响应式的——函数里读到的 state 一变，控件自动重渲染：

```python
ui.label(lambda: f"你好, {name}！")        # name 变 -> 文本变
ui.progress(lambda: count.get() * 10)     # count 变 -> 进度变
```

### `with` 块 —— 布局

```python
with ui.App("标题") as app:
    with app.col():      # 竖排 (column)
        ui.label("上")
        ui.label("下")
    with app.row():      # 横排 (row)
        ui.label("左")
        ui.label("右")
app.run()
```

`col` / `row` 接受 `padx` / `pady` 调间距。控件创建时自动认领当前 `with` 块作为父容器，不需要手动传 parent。

## 控件

| 工厂函数 | 说明 |
|---|---|
| `ui.label(text)` | 文本。`text` 可是字符串，也可是返回字符串的函数(响应式) |
| `ui.button(text, on=fn)` | 按钮。`on=` 是点击回调；`variant=` 可选 `default/primary/success/error/warning` |
| `ui.entry(state=s)` | 单行输入。`state=` 双向绑定；`placeholder=` / `password=True` |
| `ui.checkbox(text, state=s)` | 勾选框。`state=` 双向绑定到布尔 state；`on=` 变化回调 |
| `ui.progress(value)` | 进度条。`value` 可是数字或函数(响应式)；`total=` 默认 100 |

## 一个完整例子

```python
import tuikinter as ui

count = ui.state(0)
name = ui.state("Joshua")

with ui.App("演示") as app:
    with app.col(pady=1):
        ui.label(lambda: f"  计数: {count}")
        with app.row():
            ui.button("-1", on=lambda: count.set(count - 1), variant="error")
            ui.button("+1", on=lambda: count.set(count + 1), variant="success")

    with app.row(pady=1):
        ui.label("名字:")
        ui.entry(state=name, placeholder="输入...")
    ui.label(lambda: f"  你好, {name}！")

    ui.progress(lambda: max(0, min(100, count.get() * 10)))
    ui.button("退出", on=app.quit)

app.run()
```

运行 `python examples/demo.py` 看实际效果。

## 许可

MIT License。详见 [LICENSE](LICENSE)。
