@jboltai/tokui 0.1.0
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/CHANGELOG.md +35 -0
- package/LICENSE +21 -0
- package/README.md +423 -0
- package/README_EN.md +438 -0
- package/dist/tokui.cjs +11 -0
- package/dist/tokui.cjs.map +1 -0
- package/dist/tokui.css +2 -0
- package/dist/tokui.mjs +8792 -0
- package/dist/tokui.mjs.map +1 -0
- package/dist/tokui.umd.js +11 -0
- package/dist/tokui.umd.js.map +1 -0
- package/package.json +100 -0
- package/src/index.d.ts +116 -0
- package/src/server/tokui-builder.d.ts +89 -0
- package/src/server/tokui-builder.js +678 -0
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jboltai/tokui",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TokUI — Zero-dependency streaming UI description & rendering framework for AI chat. Describe UI with a tiny DSL, stream over SSE, render to real DOM incrementally.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"tokui",
|
|
7
|
+
"streaming-ui",
|
|
8
|
+
"dsl",
|
|
9
|
+
"ui-framework",
|
|
10
|
+
"ai",
|
|
11
|
+
"sse",
|
|
12
|
+
"server-sent-events",
|
|
13
|
+
"component",
|
|
14
|
+
"render",
|
|
15
|
+
"framework-agnostic",
|
|
16
|
+
"react",
|
|
17
|
+
"vue",
|
|
18
|
+
"svelte",
|
|
19
|
+
"web-components"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "sdxiaomu (https://jboltai.com)",
|
|
23
|
+
"contributors": [
|
|
24
|
+
"sdxiaomu <mumengmeng@vecspc.com>"
|
|
25
|
+
],
|
|
26
|
+
"homepage": "https://github.com/jboltai/tokui",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/jboltai/tokui.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/jboltai/tokui/issues"
|
|
33
|
+
},
|
|
34
|
+
"main": "dist/tokui.cjs",
|
|
35
|
+
"module": "dist/tokui.mjs",
|
|
36
|
+
"types": "src/index.d.ts",
|
|
37
|
+
"browser": "dist/tokui.umd.js",
|
|
38
|
+
"unpkg": "dist/tokui.umd.js",
|
|
39
|
+
"jsdelivr": "dist/tokui.umd.js",
|
|
40
|
+
"style": "dist/tokui.css",
|
|
41
|
+
"exports": {
|
|
42
|
+
".": {
|
|
43
|
+
"types": "./src/index.d.ts",
|
|
44
|
+
"import": "./dist/tokui.mjs",
|
|
45
|
+
"require": "./dist/tokui.cjs",
|
|
46
|
+
"browser": "./dist/tokui.umd.js",
|
|
47
|
+
"default": "./dist/tokui.mjs"
|
|
48
|
+
},
|
|
49
|
+
"./css": "./dist/tokui.css",
|
|
50
|
+
"./builder": {
|
|
51
|
+
"types": "./src/server/tokui-builder.d.ts",
|
|
52
|
+
"node": "./src/server/tokui-builder.js",
|
|
53
|
+
"require": "./src/server/tokui-builder.js",
|
|
54
|
+
"default": "./src/server/tokui-builder.js"
|
|
55
|
+
},
|
|
56
|
+
"./package.json": "./package.json"
|
|
57
|
+
},
|
|
58
|
+
"files": [
|
|
59
|
+
"dist",
|
|
60
|
+
"src/index.d.ts",
|
|
61
|
+
"src/server/tokui-builder.js",
|
|
62
|
+
"src/server/tokui-builder.d.ts",
|
|
63
|
+
"README.md",
|
|
64
|
+
"README_EN.md",
|
|
65
|
+
"CHANGELOG.md",
|
|
66
|
+
"LICENSE"
|
|
67
|
+
],
|
|
68
|
+
"engines": {
|
|
69
|
+
"node": ">=18"
|
|
70
|
+
},
|
|
71
|
+
"publishConfig": {
|
|
72
|
+
"access": "public",
|
|
73
|
+
"provenance": true
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"c8": "^10.1.3",
|
|
77
|
+
"typescript": "^6.0.3",
|
|
78
|
+
"vite": "^8.0.16",
|
|
79
|
+
"vitepress": "^1.6.4"
|
|
80
|
+
},
|
|
81
|
+
"scripts": {
|
|
82
|
+
"test": "npm run test:all",
|
|
83
|
+
"test:all": "for f in tests/test-*.js; do node \"$f\" || exit 1; done",
|
|
84
|
+
"test:core": "node tests/test-event-bus.js && node tests/test-theme.js && node tests/test-renderer.js",
|
|
85
|
+
"test:parser": "node tests/test-parser.js",
|
|
86
|
+
"test:builder": "node tests/test-builder.js",
|
|
87
|
+
"test:layout": "node tests/test-layout.js",
|
|
88
|
+
"test:table": "node tests/test-table.js",
|
|
89
|
+
"typecheck": "tsc",
|
|
90
|
+
"coverage": "c8 --include='src/**/*.js' --exclude='src/server/**' npm run test:all",
|
|
91
|
+
"server": "node src/server/sse-server.js",
|
|
92
|
+
"dev": "vite",
|
|
93
|
+
"build": "vite build --mode lib",
|
|
94
|
+
"build:lib": "vite build --mode lib",
|
|
95
|
+
"dev:lib": "vite build --mode lib --watch",
|
|
96
|
+
"docs:dev": "vitepress dev docs",
|
|
97
|
+
"docs:build": "npm run build && vitepress build docs",
|
|
98
|
+
"docs:preview": "vitepress preview docs"
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Type definitions for TokUI
|
|
2
|
+
// 零依赖流式 UI 描述与渲染框架 / Zero-dependency streaming UI description & rendering framework
|
|
3
|
+
// Public API mirrors src/lib.js
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 事件处理器函数签名
|
|
7
|
+
* @param data - DSL 中 clk/sub 属性携带的数据(任意结构)
|
|
8
|
+
* @param event - 原生 DOM 事件对象
|
|
9
|
+
* @param element - 触发事件的 DOM 元素
|
|
10
|
+
*/
|
|
11
|
+
export type TokUIHandlerFn = (data: any, event: Event, element: HTMLElement) => void;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* onEvent 回调签名
|
|
15
|
+
* @param eventName - 事件名,如 'streamEnd'
|
|
16
|
+
* @param data - 事件数据
|
|
17
|
+
*/
|
|
18
|
+
export type TokUIEventCallback = (eventName: string, data: any) => void;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* TokUI 构造选项
|
|
22
|
+
*/
|
|
23
|
+
export interface TokUIOptions {
|
|
24
|
+
/** 渲染目标容器(CSS 选择器或 DOM 元素) */
|
|
25
|
+
container?: string | HTMLElement | null;
|
|
26
|
+
/** 主题名称,如 'default' / 'dark',默认 'default' */
|
|
27
|
+
theme?: string;
|
|
28
|
+
/** 是否启用流式渲染模式,默认 true */
|
|
29
|
+
streaming?: boolean;
|
|
30
|
+
/** 事件回调,如接收到 ('streamEnd', {}) */
|
|
31
|
+
onEvent?: TokUIEventCallback | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* TokUI 核心类
|
|
36
|
+
*
|
|
37
|
+
* 三种用法:
|
|
38
|
+
* render(dsl) — 一次性渲染
|
|
39
|
+
* startStream() + feed(chk) — 手动流式喂入
|
|
40
|
+
* connect(url, body) — SSE 自动连接并流式渲染
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const ui = new TokUI({ container: '#app', theme: 'dark' });
|
|
44
|
+
* ui.connect('/api/chat/stream', { prompt: 'hi' });
|
|
45
|
+
*/
|
|
46
|
+
export class TokUI {
|
|
47
|
+
/** 合并后的运行时选项 */
|
|
48
|
+
options: Required<Pick<TokUIOptions, 'theme' | 'streaming'>> & TokUIOptions;
|
|
49
|
+
|
|
50
|
+
/** 主容器 DOM */
|
|
51
|
+
container: HTMLElement | null;
|
|
52
|
+
|
|
53
|
+
/** 流式目标容器 */
|
|
54
|
+
streamingContainer: HTMLElement | null;
|
|
55
|
+
|
|
56
|
+
constructor(options?: TokUIOptions);
|
|
57
|
+
|
|
58
|
+
/** 一次性渲染完整 DSL 文本到容器 */
|
|
59
|
+
render(tokuiString: string, targetContainer?: HTMLElement): void;
|
|
60
|
+
|
|
61
|
+
/** 开始流式渲染(初始化流式解析器) */
|
|
62
|
+
startStream(targetContainer?: HTMLElement): void;
|
|
63
|
+
|
|
64
|
+
/** 向流式解析器喂入一段 DSL 文本片段 */
|
|
65
|
+
feed(chunk: string): void;
|
|
66
|
+
|
|
67
|
+
/** 结束流式渲染(刷新缓冲区并重置插槽栈) */
|
|
68
|
+
endStream(): void;
|
|
69
|
+
|
|
70
|
+
/** 断开 SSE 连接并清理流式容器 */
|
|
71
|
+
disconnect(): void;
|
|
72
|
+
|
|
73
|
+
/** 通过 SSE 连接服务端并流式渲染,返回 fetch Promise */
|
|
74
|
+
connect(url: string, body?: Record<string, any>): Promise<void>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 注册事件处理函数(与 DSL 中 clk:/sub: 绑定对应)
|
|
79
|
+
* @param name - 处理函数名称
|
|
80
|
+
* @param fn - 处理函数
|
|
81
|
+
*/
|
|
82
|
+
export declare function registerHandler(name: string, fn: TokUIHandlerFn): void;
|
|
83
|
+
|
|
84
|
+
/** 移除已注册的事件处理函数 */
|
|
85
|
+
export declare function removeHandler(name: string): void;
|
|
86
|
+
|
|
87
|
+
/** 设置当前主题(更新容器 data-tokui-theme 属性) */
|
|
88
|
+
export declare function setTheme(themeName: string): void;
|
|
89
|
+
|
|
90
|
+
/** 获取当前主题名称 */
|
|
91
|
+
export declare function getTheme(): string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* DOM 创建快捷方法
|
|
95
|
+
* @param tag - 标签名
|
|
96
|
+
* @param attrs - 属性键值表(on* / formaction 会被过滤防 XSS)
|
|
97
|
+
* @param textContent - 文本内容
|
|
98
|
+
*/
|
|
99
|
+
export declare function el(
|
|
100
|
+
tag: string,
|
|
101
|
+
attrs?: Record<string, unknown>,
|
|
102
|
+
textContent?: string
|
|
103
|
+
): HTMLElement;
|
|
104
|
+
|
|
105
|
+
/** 公共命名空间对象(ESM default 导出) */
|
|
106
|
+
export interface TokUINamespace {
|
|
107
|
+
TokUI: typeof TokUI;
|
|
108
|
+
registerHandler: typeof registerHandler;
|
|
109
|
+
removeHandler: typeof removeHandler;
|
|
110
|
+
setTheme: typeof setTheme;
|
|
111
|
+
getTheme: typeof getTheme;
|
|
112
|
+
el: typeof el;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
declare const TokUINamespace: TokUINamespace;
|
|
116
|
+
export default TokUINamespace;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Type definitions for TokUIBuilder
|
|
2
|
+
// 链式 DSL 生成器 / Chainable DSL builder (server-side)
|
|
3
|
+
// Public API mirrors src/server/tokui-builder.js
|
|
4
|
+
//
|
|
5
|
+
// 注:builder 有 ~170 个对应 DSL 组件的链式方法,本声明覆盖核心原语
|
|
6
|
+
// (_open / _selfClosing)与常用组件。**未列出**的组件方法可用这两个
|
|
7
|
+
// 原语等价表达,或临时 `as any`:
|
|
8
|
+
// b._selfClosing('gantt', null, { data: [...] }) // 自闭合组件
|
|
9
|
+
// b._open('drawer', { tt: '抽屉' }) ... b.end() // 容器组件
|
|
10
|
+
|
|
11
|
+
/** 组件属性键值表(DSL 属性,值任意) */
|
|
12
|
+
export type BuilderAttrs = Record<string, any>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* TokUI 构建器 —— 链式生成 TokUI DSL 字符串
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const b = new TokUIBuilder();
|
|
19
|
+
* b.card({ tt: '标题' }).h2('内容').p('描述').end();
|
|
20
|
+
* const dsl = b.toString(); // '[card tt:标题][h2 内容][p 描述][/card]'
|
|
21
|
+
*/
|
|
22
|
+
export declare class TokUIBuilder {
|
|
23
|
+
constructor();
|
|
24
|
+
|
|
25
|
+
// —— 终端方法(输出)——
|
|
26
|
+
/** 输出完整 DSL 字符串(自动补全未关闭容器) */
|
|
27
|
+
toString(): string;
|
|
28
|
+
/** 输出 DSL 片段数组(自动补全未关闭容器) */
|
|
29
|
+
toChunks(): string[];
|
|
30
|
+
|
|
31
|
+
// —— 容器栈控制 ——
|
|
32
|
+
/** 关闭最近一个未关闭容器 */
|
|
33
|
+
end(): this;
|
|
34
|
+
/** 关闭全部未关闭容器 */
|
|
35
|
+
endAll(): this;
|
|
36
|
+
/** 清空构建器状态 */
|
|
37
|
+
reset(): this;
|
|
38
|
+
|
|
39
|
+
// —— 底层原语(任意组件的强类型逃逸口)——
|
|
40
|
+
/** 容器组件开标签 */
|
|
41
|
+
_open(type: string, attrs?: BuilderAttrs): this;
|
|
42
|
+
/** 自闭合组件 */
|
|
43
|
+
_selfClosing(type: string, content?: string | null, attrs?: BuilderAttrs): this;
|
|
44
|
+
/** 补全未关闭容器并返回片段数组 */
|
|
45
|
+
_finalizeChunks(): string[];
|
|
46
|
+
|
|
47
|
+
// —— 标题 / 文本(content-first)——
|
|
48
|
+
h1(content?: string, attrs?: BuilderAttrs): this;
|
|
49
|
+
h2(content?: string, attrs?: BuilderAttrs): this;
|
|
50
|
+
h3(content?: string, attrs?: BuilderAttrs): this;
|
|
51
|
+
h4(content?: string, attrs?: BuilderAttrs): this;
|
|
52
|
+
h5(content?: string, attrs?: BuilderAttrs): this;
|
|
53
|
+
h6(content?: string, attrs?: BuilderAttrs): this;
|
|
54
|
+
p(content?: string, attrs?: BuilderAttrs): this;
|
|
55
|
+
tag(content?: string, attrs?: BuilderAttrs): this;
|
|
56
|
+
|
|
57
|
+
// —— 自闭合叶子(attrs-only)——
|
|
58
|
+
dv(attrs?: BuilderAttrs): this;
|
|
59
|
+
a(attrs?: BuilderAttrs): this;
|
|
60
|
+
img(attrs?: BuilderAttrs): this;
|
|
61
|
+
input(attrs?: BuilderAttrs): this;
|
|
62
|
+
pwd(attrs?: BuilderAttrs): this;
|
|
63
|
+
btn(attrs?: BuilderAttrs): this;
|
|
64
|
+
checkbox(attrs?: BuilderAttrs): this;
|
|
65
|
+
toggle(attrs?: BuilderAttrs): this;
|
|
66
|
+
col(attrs?: BuilderAttrs): this;
|
|
67
|
+
tcol(attrs?: BuilderAttrs): this;
|
|
68
|
+
opt(attrs?: BuilderAttrs): this;
|
|
69
|
+
|
|
70
|
+
// —— 容器(attrs-only,需 end() 闭合)——
|
|
71
|
+
card(attrs?: BuilderAttrs): this;
|
|
72
|
+
ft(attrs?: BuilderAttrs): this;
|
|
73
|
+
form(attrs?: BuilderAttrs): this;
|
|
74
|
+
table(attrs?: BuilderAttrs): this;
|
|
75
|
+
tbody(attrs?: BuilderAttrs): this;
|
|
76
|
+
select(attrs?: BuilderAttrs): this;
|
|
77
|
+
radio(attrs?: BuilderAttrs): this;
|
|
78
|
+
btngroup(attrs?: BuilderAttrs): this;
|
|
79
|
+
picker(attrs?: BuilderAttrs): this;
|
|
80
|
+
toggleGroup(attrs?: BuilderAttrs): this;
|
|
81
|
+
|
|
82
|
+
// —— 表格辅助 ——
|
|
83
|
+
thead(attrs?: BuilderAttrs): this;
|
|
84
|
+
theadCols(cols: any[]): this;
|
|
85
|
+
tr(cells: any[], attrs?: BuilderAttrs): this;
|
|
86
|
+
|
|
87
|
+
// —— 代码块(容器)——
|
|
88
|
+
code(attrs?: BuilderAttrs): this;
|
|
89
|
+
}
|