ai-chat-ui-kit 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.
Files changed (95) hide show
  1. package/.eslintrc.cjs +74 -0
  2. package/.github/actions/screenshot/action.yml +35 -0
  3. package/.github/workflows/pages.yml +46 -0
  4. package/README.md +285 -0
  5. package/docs/README.md +176 -0
  6. package/docs/api/components.md +344 -0
  7. package/docs/api/core.md +349 -0
  8. package/docs/chat-style-1-minimal.html +78 -0
  9. package/docs/chat-style-2-neon.html +74 -0
  10. package/docs/chat-style-3-glass.html +73 -0
  11. package/docs/chat-style-4-terminal.html +84 -0
  12. package/docs/chat-style-5-gradient.html +69 -0
  13. package/docs/chat-style-6-corporate.html +116 -0
  14. package/docs/examples/basic-chat.md +291 -0
  15. package/docs/examples/custom-plugins.md +431 -0
  16. package/docs/examples/multi-model.md +466 -0
  17. package/docs/guide/api-adapters.md +431 -0
  18. package/docs/guide/getting-started.md +244 -0
  19. package/docs/guide/headless-mode.md +508 -0
  20. package/docs/guide/plugins.md +416 -0
  21. package/docs/guide/themes.md +327 -0
  22. package/docs/index.html +256 -0
  23. package/docs/theme-preview-1-minimal.html +74 -0
  24. package/docs/theme-preview-2-neon.html +73 -0
  25. package/docs/theme-preview-3-glass.html +77 -0
  26. package/docs/theme-preview-4-terminal.html +86 -0
  27. package/docs/theme-preview-5-gradient.html +79 -0
  28. package/docs/theme-preview-6-corporate.html +71 -0
  29. package/examples/index.html +414 -0
  30. package/examples/react-app/App.tsx +131 -0
  31. package/examples/react-app/index.html +12 -0
  32. package/examples/react-app/main.tsx +15 -0
  33. package/examples/react-app/package.json +24 -0
  34. package/examples/vue-app/index.html +12 -0
  35. package/examples/vue-app/package.json +22 -0
  36. package/examples/vue-app/src/App.vue +145 -0
  37. package/examples/vue-app/src/main.ts +9 -0
  38. package/package.json +44 -0
  39. package/packages/components/package.json +25 -0
  40. package/packages/components/src/chat/chat.css +80 -0
  41. package/packages/components/src/chat/chat.ts +236 -0
  42. package/packages/components/src/index.ts +36 -0
  43. package/packages/components/src/input/input.css +52 -0
  44. package/packages/components/src/input/input.ts +116 -0
  45. package/packages/components/src/markdown/markdown.css +118 -0
  46. package/packages/components/src/markdown/markdown.ts +229 -0
  47. package/packages/components/src/message/message.css +56 -0
  48. package/packages/components/src/message/message.ts +72 -0
  49. package/packages/components/src/styles/global.css +43 -0
  50. package/packages/components/src/tool-call/tool-call.css +98 -0
  51. package/packages/components/src/tool-call/tool-call.ts +171 -0
  52. package/packages/components/src/types.ts +55 -0
  53. package/packages/components/src/utils/helpers.ts +128 -0
  54. package/packages/components/tsconfig.json +25 -0
  55. package/packages/components/tsup.config.ts +18 -0
  56. package/packages/core/package.json +47 -0
  57. package/packages/core/pnpm-lock.yaml +2032 -0
  58. package/packages/core/pnpm-workspace.yaml +2 -0
  59. package/packages/core/src/api/adapters.ts +717 -0
  60. package/packages/core/src/api/base.ts +210 -0
  61. package/packages/core/src/api/index.ts +54 -0
  62. package/packages/core/src/index.ts +93 -0
  63. package/packages/core/src/parser/latex.ts +274 -0
  64. package/packages/core/src/parser/markdown.test.ts +58 -0
  65. package/packages/core/src/parser/markdown.ts +206 -0
  66. package/packages/core/src/parser/mermaid.ts +276 -0
  67. package/packages/core/src/plugins/PluginManager.ts +232 -0
  68. package/packages/core/src/plugins/builtin.ts +406 -0
  69. package/packages/core/src/store/ChatStore.ts +163 -0
  70. package/packages/core/src/store/ModelConfigStore.ts +136 -0
  71. package/packages/core/src/store/ToolCallStore.ts +164 -0
  72. package/packages/core/src/store/base.ts +75 -0
  73. package/packages/core/src/types/index.ts +133 -0
  74. package/packages/core/tsup.config.ts +18 -0
  75. package/packages/themes/package.json +33 -0
  76. package/packages/themes/src/corporate/index.ts +52 -0
  77. package/packages/themes/src/corporate/theme.css +228 -0
  78. package/packages/themes/src/glass/index.ts +52 -0
  79. package/packages/themes/src/glass/theme.css +237 -0
  80. package/packages/themes/src/gradient/index.ts +53 -0
  81. package/packages/themes/src/gradient/theme.css +218 -0
  82. package/packages/themes/src/index.ts +13 -0
  83. package/packages/themes/src/minimal/index.ts +52 -0
  84. package/packages/themes/src/minimal/theme.css +198 -0
  85. package/packages/themes/src/neon/index.ts +52 -0
  86. package/packages/themes/src/neon/theme.css +233 -0
  87. package/packages/themes/src/terminal/index.ts +52 -0
  88. package/packages/themes/src/terminal/theme.css +235 -0
  89. package/packages/themes/src/types.ts +10 -0
  90. package/packages/themes/src/vite-env.d.ts +9 -0
  91. package/packages/themes/tsup.config.ts +21 -0
  92. package/pnpm-workspace.yaml +4 -0
  93. package/tsconfig.json +27 -0
  94. package/vite.config.ts +25 -0
  95. package/vitest.config.ts +28 -0
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @generated-by AI: edenxpzhang
3
+ * @generated-date 2026-05-13
4
+ */
5
+ :host {
6
+ display: block;
7
+ }
8
+
9
+ .tool-call {
10
+ border: 1px solid var(--ai-border, #e8e8e8);
11
+ border-radius: var(--ai-border-radius, 8px);
12
+ overflow: hidden;
13
+ font-size: 12px;
14
+ }
15
+
16
+ .tool-call-header {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: 8px;
20
+ padding: 8px 12px;
21
+ background-color: var(--ai-bg-secondary, #f5f5f5);
22
+ cursor: pointer;
23
+ user-select: none;
24
+ }
25
+
26
+ .tool-call-header:hover {
27
+ background-color: var(--ai-border, #e8e8e8);
28
+ }
29
+
30
+ .tool-call-status {
31
+ width: 8px;
32
+ height: 8px;
33
+ border-radius: 50%;
34
+ }
35
+
36
+ .tool-call-status-pending {
37
+ background-color: #faad14;
38
+ }
39
+
40
+ .tool-call-status-running {
41
+ background-color: #1677ff;
42
+ animation: pulse 1.5s infinite;
43
+ }
44
+
45
+ .tool-call-status-completed {
46
+ background-color: #52c41a;
47
+ }
48
+
49
+ .tool-call-status-failed {
50
+ background-color: #ff4d4f;
51
+ }
52
+
53
+ @keyframes pulse {
54
+ 0%, 100% { opacity: 1; }
55
+ 50% { opacity: 0.5; }
56
+ }
57
+
58
+ .tool-call-name {
59
+ flex: 1;
60
+ font-weight: 500;
61
+ color: var(--ai-text, #333333);
62
+ }
63
+
64
+ .tool-call-toggle {
65
+ color: var(--ai-text-secondary, #666666);
66
+ font-size: 10px;
67
+ }
68
+
69
+ .tool-call-details {
70
+ padding: 12px;
71
+ border-top: 1px solid var(--ai-border, #e8e8e8);
72
+ background-color: var(--ai-bg, #ffffff);
73
+ }
74
+
75
+ .tool-call-section {
76
+ margin-bottom: 8px;
77
+ }
78
+
79
+ .tool-call-section:last-child {
80
+ margin-bottom: 0;
81
+ }
82
+
83
+ .tool-call-label {
84
+ font-weight: 500;
85
+ color: var(--ai-text-secondary, #666666);
86
+ margin-bottom: 4px;
87
+ }
88
+
89
+ .tool-call-content {
90
+ background-color: var(--ai-bg-secondary, #f5f5f5);
91
+ padding: 8px;
92
+ border-radius: 4px;
93
+ overflow-x: auto;
94
+ font-family: 'Courier New', monospace;
95
+ font-size: 11px;
96
+ white-space: pre-wrap;
97
+ word-break: break-all;
98
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * @generated-by AI: edenxpzhang
3
+ * @generated-date 2026-05-13
4
+ */
5
+
6
+ import { LitElement, html, css } from 'lit';
7
+ import { customElement, property, state } from 'lit/decorators.js';
8
+ import './tool-call.css';
9
+
10
+ // 导入共享类型
11
+ import { ToolCall } from '../types.js';
12
+
13
+ @customElement('ai-tool-call')
14
+ export class AiToolCall extends LitElement {
15
+ static styles = css`
16
+ :host {
17
+ display: block;
18
+ }
19
+
20
+ .tool-call {
21
+ border: 1px solid var(--ai-border, #e8e8e8);
22
+ border-radius: var(--ai-border-radius, 8px);
23
+ overflow: hidden;
24
+ font-size: 12px;
25
+ }
26
+
27
+ .tool-call-header {
28
+ display: flex;
29
+ align-items: center;
30
+ gap: 8px;
31
+ padding: 8px 12px;
32
+ background-color: var(--ai-bg-secondary, #f5f5f5);
33
+ cursor: pointer;
34
+ user-select: none;
35
+ }
36
+
37
+ .tool-call-header:hover {
38
+ background-color: var(--ai-border, #e8e8e8);
39
+ }
40
+
41
+ .tool-call-status {
42
+ width: 8px;
43
+ height: 8px;
44
+ border-radius: 50%;
45
+ }
46
+
47
+ .tool-call-status-pending {
48
+ background-color: #faad14;
49
+ }
50
+
51
+ .tool-call-status-running {
52
+ background-color: #1677ff;
53
+ animation: pulse 1.5s infinite;
54
+ }
55
+
56
+ .tool-call-status-completed {
57
+ background-color: #52c41a;
58
+ }
59
+
60
+ .tool-call-status-failed {
61
+ background-color: #ff4d4f;
62
+ }
63
+
64
+ @keyframes pulse {
65
+ 0%, 100% { opacity: 1; }
66
+ 50% { opacity: 0.5; }
67
+ }
68
+
69
+ .tool-call-name {
70
+ flex: 1;
71
+ font-weight: 500;
72
+ color: var(--ai-text, #333333);
73
+ }
74
+
75
+ .tool-call-toggle {
76
+ color: var(--ai-text-secondary, #666666);
77
+ font-size: 10px;
78
+ }
79
+
80
+ .tool-call-details {
81
+ padding: 12px;
82
+ border-top: 1px solid var(--ai-border, #e8e8e8);
83
+ background-color: var(--ai-bg, #ffffff);
84
+ }
85
+
86
+ .tool-call-section {
87
+ margin-bottom: 8px;
88
+ }
89
+
90
+ .tool-call-section:last-child {
91
+ margin-bottom: 0;
92
+ }
93
+
94
+ .tool-call-label {
95
+ font-weight: 500;
96
+ color: var(--ai-text-secondary, #666666);
97
+ margin-bottom: 4px;
98
+ }
99
+
100
+ .tool-call-content {
101
+ background-color: var(--ai-bg-secondary, #f5f5f5);
102
+ padding: 8px;
103
+ border-radius: 4px;
104
+ overflow-x: auto;
105
+ font-family: 'Courier New', monospace;
106
+ font-size: 11px;
107
+ white-space: pre-wrap;
108
+ word-break: break-all;
109
+ }
110
+ `;
111
+
112
+ @property({ type: Object })
113
+ toolCall?: ToolCall;
114
+
115
+ @state()
116
+ private expanded = false;
117
+
118
+ render() {
119
+ if (!this.toolCall) {
120
+ return html``;
121
+ }
122
+
123
+ const statusClass = `tool-call-status-${this.toolCall.status}`;
124
+
125
+ return html`
126
+ <div class="tool-call">
127
+ <div class="tool-call-header" @click=${this.toggleExpand}>
128
+ <div class="tool-call-status ${statusClass}"></div>
129
+ <div class="tool-call-name">${this.toolCall.name}</div>
130
+ <div class="tool-call-toggle">
131
+ ${this.expanded ? '▼' : '▶'}
132
+ </div>
133
+ </div>
134
+ ${this.expanded
135
+ ? html`
136
+ <div class="tool-call-details">
137
+ <div class="tool-call-section">
138
+ <div class="tool-call-label">参数</div>
139
+ <div class="tool-call-content">
140
+ ${JSON.stringify(this.toolCall.parameters, null, 2)}
141
+ </div>
142
+ </div>
143
+ ${this.toolCall.result
144
+ ? html`
145
+ <div class="tool-call-section">
146
+ <div class="tool-call-label">结果</div>
147
+ <div class="tool-call-content">
148
+ ${typeof this.toolCall.result === 'string'
149
+ ? this.toolCall.result
150
+ : JSON.stringify(this.toolCall.result, null, 2)}
151
+ </div>
152
+ </div>
153
+ `
154
+ : ''}
155
+ </div>
156
+ `
157
+ : ''}
158
+ </div>
159
+ `;
160
+ }
161
+
162
+ private toggleExpand() {
163
+ this.expanded = !this.expanded;
164
+ }
165
+ }
166
+
167
+ declare global {
168
+ interface HTMLElementTagNameMap {
169
+ 'ai-tool-call': AiToolCall;
170
+ }
171
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @generated-by AI: edenxpzhang
3
+ * @generated-date 2026-05-13
4
+ */
5
+
6
+ /**
7
+ * 消息角色
8
+ */
9
+ export type MessageRole = 'user' | 'assistant' | 'system';
10
+
11
+ /**
12
+ * 消息对象
13
+ */
14
+ export interface Message {
15
+ id: string;
16
+ role: MessageRole;
17
+ content: string;
18
+ timestamp: number;
19
+ toolCalls?: ToolCall[];
20
+ }
21
+
22
+ /**
23
+ * 工具调用状态
24
+ */
25
+ export type ToolCallStatus = 'pending' | 'running' | 'completed' | 'failed';
26
+
27
+ /**
28
+ * 工具调用对象
29
+ */
30
+ export interface ToolCall {
31
+ id: string;
32
+ name: string;
33
+ parameters: Record<string, any>;
34
+ status: ToolCallStatus;
35
+ result?: any;
36
+ }
37
+
38
+ /**
39
+ * 模型配置
40
+ */
41
+ export interface ModelConfig {
42
+ model: string;
43
+ temperature?: number;
44
+ maxTokens?: number;
45
+ topP?: number;
46
+ }
47
+
48
+ /**
49
+ * 会话数据(用于导入/导出)
50
+ */
51
+ export interface SessionData {
52
+ messages: Message[];
53
+ config?: ModelConfig;
54
+ exportDate: string;
55
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @generated-by AI: edenxpzhang
3
+ * @generated-date 2026-05-13
4
+ */
5
+
6
+ /**
7
+ * 创建 HTML 元素
8
+ * @param tag 标签名
9
+ * @param attrs 属性对象
10
+ * @returns HTMLElement
11
+ */
12
+ export function createElement(tag: string, attrs?: Record<string, any>): HTMLElement {
13
+ const element = document.createElement(tag);
14
+
15
+ if (attrs) {
16
+ Object.entries(attrs).forEach(([key, value]) => {
17
+ if (key === 'className') {
18
+ element.className = value;
19
+ } else if (key === 'textContent') {
20
+ element.textContent = value;
21
+ } else if (key.startsWith('on')) {
22
+ const event = key.slice(2).toLowerCase();
23
+ element.addEventListener(event, value);
24
+ } else {
25
+ element.setAttribute(key, value);
26
+ }
27
+ });
28
+ }
29
+
30
+ return element;
31
+ }
32
+
33
+ /**
34
+ * 防抖函数
35
+ * @param fn 要防抖的函数
36
+ * @param delay 延迟时间(毫秒)
37
+ * @returns 防抖后的函数
38
+ */
39
+ export function debounce<T extends (...args: any[]) => any>(
40
+ fn: T,
41
+ delay: number
42
+ ): (...args: Parameters<T>) => void {
43
+ let timer: ReturnType<typeof setTimeout>;
44
+
45
+ return function (this: any, ...args: Parameters<T>) {
46
+ clearTimeout(timer);
47
+ timer = setTimeout(() => {
48
+ fn.apply(this, args);
49
+ }, delay);
50
+ };
51
+ }
52
+
53
+ /**
54
+ * 节流函数
55
+ * @param fn 要节流的函数
56
+ * @param limit 时间限制(毫秒)
57
+ * @returns 节流后的函数
58
+ */
59
+ export function throttle<T extends (...args: any[]) => any>(
60
+ fn: T,
61
+ limit: number
62
+ ): (...args: Parameters<T>) => void {
63
+ let inThrottle = false;
64
+
65
+ return function (this: any, ...args: Parameters<T>) {
66
+ if (!inThrottle) {
67
+ fn.apply(this, args);
68
+ inThrottle = true;
69
+ setTimeout(() => {
70
+ inThrottle = false;
71
+ }, limit);
72
+ }
73
+ };
74
+ }
75
+
76
+ /**
77
+ * 深拷贝对象
78
+ * @param obj 要拷贝的对象
79
+ * @returns 拷贝后的对象
80
+ */
81
+ export function deepClone<T>(obj: T): T {
82
+ if (obj === null || typeof obj !== 'object') {
83
+ return obj;
84
+ }
85
+
86
+ if (Array.isArray(obj)) {
87
+ return obj.map(item => deepClone(item)) as T;
88
+ }
89
+
90
+ const cloned = {} as T;
91
+ Object.keys(obj as object).forEach(key => {
92
+ (cloned as any)[key] = deepClone((obj as any)[key]);
93
+ });
94
+
95
+ return cloned;
96
+ }
97
+
98
+ /**
99
+ * 生成 UUID v4
100
+ * @returns UUID 字符串
101
+ */
102
+ export function generateUUID(): string {
103
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
104
+ const r = Math.random() * 16 | 0;
105
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
106
+ return v.toString(16);
107
+ });
108
+ }
109
+
110
+ /**
111
+ * 防抖装饰器(用于类方法)
112
+ * @param delay 延迟时间(毫秒)
113
+ */
114
+ export function Debounce(delay: number) {
115
+ return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
116
+ const originalMethod = descriptor.value;
117
+ let timer: ReturnType<typeof setTimeout>;
118
+
119
+ descriptor.value = function (...args: any[]) {
120
+ clearTimeout(timer);
121
+ timer = setTimeout(() => {
122
+ originalMethod.apply(this, args);
123
+ }, delay);
124
+ };
125
+
126
+ return descriptor;
127
+ };
128
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
6
+ "moduleResolution": "node",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "useDefineForClassFields": true,
12
+ "experimentalDecorators": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true,
16
+ "outDir": "./dist",
17
+ "rootDir": "./src",
18
+ "baseUrl": ".",
19
+ "paths": {
20
+ "@ai-chat/core": ["../core/src"]
21
+ }
22
+ },
23
+ "include": ["src/**/*"],
24
+ "exclude": ["node_modules", "dist"]
25
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @generated-by AI: edenxpzhang
3
+ * @generated-date 2026-05-13
4
+ */
5
+ import { defineConfig } from 'tsup';
6
+
7
+ export default defineConfig({
8
+ entry: ['src/**/*.ts'],
9
+ outDir: 'dist',
10
+ format: ['esm', 'cjs'],
11
+ target: 'esnext',
12
+ splitting: true,
13
+ clean: true,
14
+ dts: true,
15
+ sourcemap: true,
16
+ treeshake: true,
17
+ external: ['lit', '@lit/reactive-element', 'lit-html', 'lit-element'],
18
+ });
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@ai-chat/core",
3
+ "version": "0.1.0",
4
+ "description": "Core logic layer for AI Chat UI Kit (Headless)",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ },
15
+ "./package.json": "./package.json"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "dev": "tsup --watch",
22
+ "build": "tsup",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "clean": "rimraf dist",
26
+ "type-check": "tsc --noEmit"
27
+ },
28
+ "keywords": [
29
+ "ai",
30
+ "chat",
31
+ "headless",
32
+ "store"
33
+ ],
34
+ "author": "edenxpzhang",
35
+ "license": "MIT",
36
+ "dependencies": {
37
+ "marked": "^12.0.0",
38
+ "marked-highlight": "^2.0.0",
39
+ "highlight.js": "^11.9.0",
40
+ "mermaid": "^10.9.0",
41
+ "katex": "^0.16.0"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^7.0.0",
45
+ "typescript": "^5.0.0"
46
+ }
47
+ }