@lantos1618/better-ui 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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -0
  3. package/lib/aui/README.md +136 -0
  4. package/lib/aui/__tests__/aui-complete.test.ts +251 -0
  5. package/lib/aui/__tests__/aui-comprehensive.test.ts +376 -0
  6. package/lib/aui/__tests__/aui-concise.test.ts +278 -0
  7. package/lib/aui/__tests__/aui-integration.test.ts +309 -0
  8. package/lib/aui/__tests__/aui-simple.test.ts +116 -0
  9. package/lib/aui/__tests__/aui.test.ts +269 -0
  10. package/lib/aui/__tests__/concise-api.test.ts +165 -0
  11. package/lib/aui/__tests__/core.test.ts +265 -0
  12. package/lib/aui/__tests__/simple-api.test.ts +200 -0
  13. package/lib/aui/ai-assistant.ts +408 -0
  14. package/lib/aui/ai-control.ts +353 -0
  15. package/lib/aui/client/use-aui.ts +55 -0
  16. package/lib/aui/client-control.ts +551 -0
  17. package/lib/aui/client-executor.ts +417 -0
  18. package/lib/aui/components/ToolRenderer.tsx +22 -0
  19. package/lib/aui/core.ts +137 -0
  20. package/lib/aui/demo.tsx +89 -0
  21. package/lib/aui/examples/ai-complete-demo.tsx +359 -0
  22. package/lib/aui/examples/ai-control-demo.tsx +356 -0
  23. package/lib/aui/examples/ai-control-tools.ts +308 -0
  24. package/lib/aui/examples/concise-api.tsx +153 -0
  25. package/lib/aui/examples/index.tsx +163 -0
  26. package/lib/aui/examples/quick-demo.tsx +91 -0
  27. package/lib/aui/examples/simple-demo.tsx +71 -0
  28. package/lib/aui/examples/simple-tools.tsx +160 -0
  29. package/lib/aui/examples/user-api.tsx +208 -0
  30. package/lib/aui/examples/user-requested.tsx +174 -0
  31. package/lib/aui/examples/weather-search-tools.tsx +119 -0
  32. package/lib/aui/examples.tsx +367 -0
  33. package/lib/aui/hooks/useAUITool.ts +142 -0
  34. package/lib/aui/hooks/useAUIToolEnhanced.ts +343 -0
  35. package/lib/aui/hooks/useAUITools.ts +195 -0
  36. package/lib/aui/index.ts +156 -0
  37. package/lib/aui/provider.tsx +45 -0
  38. package/lib/aui/server-control.ts +386 -0
  39. package/lib/aui/server-executor.ts +165 -0
  40. package/lib/aui/server.ts +167 -0
  41. package/lib/aui/tool-registry.ts +380 -0
  42. package/lib/aui/tools/advanced-examples.tsx +86 -0
  43. package/lib/aui/tools/ai-complete.ts +375 -0
  44. package/lib/aui/tools/api-tools.tsx +230 -0
  45. package/lib/aui/tools/data-tools.tsx +232 -0
  46. package/lib/aui/tools/dom-tools.tsx +202 -0
  47. package/lib/aui/tools/examples.ts +43 -0
  48. package/lib/aui/tools/file-tools.tsx +202 -0
  49. package/lib/aui/tools/form-tools.tsx +233 -0
  50. package/lib/aui/tools/index.ts +8 -0
  51. package/lib/aui/tools/navigation-tools.tsx +172 -0
  52. package/lib/aui/tools/notification-tools.ts +213 -0
  53. package/lib/aui/tools/state-tools.tsx +209 -0
  54. package/lib/aui/types.ts +47 -0
  55. package/lib/aui/vercel-ai.ts +100 -0
  56. package/package.json +51 -0
@@ -0,0 +1,233 @@
1
+ import { z } from 'zod';
2
+ import { createAITool } from '../ai-control';
3
+
4
+ export const formSubmit = createAITool('form.submit')
5
+ .describe('Submit a form')
6
+ .tag('form', 'submission', 'client')
7
+ .input(z.object({
8
+ selector: z.string(),
9
+ preventDefault: z.boolean().optional().default(true)
10
+ }))
11
+ .clientExecute(async ({ input }) => {
12
+ const form = document.querySelector(input.selector) as HTMLFormElement;
13
+ if (!form) throw new Error(`Form not found: ${input.selector}`);
14
+
15
+ if (!input.preventDefault) {
16
+ form.submit();
17
+ } else {
18
+ const event = new Event('submit', { bubbles: true, cancelable: true });
19
+ form.dispatchEvent(event);
20
+ }
21
+
22
+ return { submitted: true, selector: input.selector };
23
+ });
24
+
25
+ export const formReset = createAITool('form.reset')
26
+ .describe('Reset a form to its default values')
27
+ .tag('form', 'reset', 'client')
28
+ .input(z.object({
29
+ selector: z.string()
30
+ }))
31
+ .clientExecute(async ({ input }) => {
32
+ const form = document.querySelector(input.selector) as HTMLFormElement;
33
+ if (!form) throw new Error(`Form not found: ${input.selector}`);
34
+
35
+ form.reset();
36
+ return { reset: true, selector: input.selector };
37
+ });
38
+
39
+ export const formFill = createAITool('form.fill')
40
+ .describe('Fill multiple form fields at once')
41
+ .tag('form', 'input', 'client')
42
+ .input(z.object({
43
+ formSelector: z.string(),
44
+ values: z.record(z.any()),
45
+ submit: z.boolean().optional()
46
+ }))
47
+ .clientExecute(async ({ input }) => {
48
+ const form = document.querySelector(input.formSelector) as HTMLFormElement;
49
+ if (!form) throw new Error(`Form not found: ${input.formSelector}`);
50
+
51
+ const filled: Record<string, any> = {};
52
+
53
+ Object.entries(input.values).forEach(([name, value]) => {
54
+ const field = form.elements.namedItem(name) as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
55
+
56
+ if (field) {
57
+ if (field instanceof HTMLInputElement) {
58
+ if (field.type === 'checkbox') {
59
+ field.checked = Boolean(value);
60
+ } else if (field.type === 'radio') {
61
+ const radios = form.querySelectorAll(`input[name="${name}"]`) as NodeListOf<HTMLInputElement>;
62
+ radios.forEach(radio => {
63
+ radio.checked = radio.value === value;
64
+ });
65
+ } else {
66
+ field.value = String(value);
67
+ }
68
+ } else {
69
+ field.value = String(value);
70
+ }
71
+
72
+ field.dispatchEvent(new Event('input', { bubbles: true }));
73
+ field.dispatchEvent(new Event('change', { bubbles: true }));
74
+ filled[name] = value;
75
+ }
76
+ });
77
+
78
+ if (input.submit) {
79
+ form.submit();
80
+ }
81
+
82
+ return { filled, submitted: input.submit };
83
+ });
84
+
85
+ export const formValidate = createAITool('form.validate')
86
+ .describe('Validate a form using HTML5 validation')
87
+ .tag('form', 'validation', 'client')
88
+ .input(z.object({
89
+ selector: z.string(),
90
+ showErrors: z.boolean().optional()
91
+ }))
92
+ .clientExecute(async ({ input }) => {
93
+ const form = document.querySelector(input.selector) as HTMLFormElement;
94
+ if (!form) throw new Error(`Form not found: ${input.selector}`);
95
+
96
+ const isValid = form.checkValidity();
97
+ const errors: Array<{ field: string; message: string }> = [];
98
+
99
+ if (!isValid && input.showErrors) {
100
+ const fields = form.querySelectorAll('input, select, textarea') as NodeListOf<HTMLInputElement>;
101
+ fields.forEach(field => {
102
+ if (!field.validity.valid) {
103
+ errors.push({
104
+ field: field.name || field.id,
105
+ message: field.validationMessage
106
+ });
107
+ field.reportValidity();
108
+ }
109
+ });
110
+ }
111
+
112
+ return { valid: isValid, errors };
113
+ });
114
+
115
+ export const formGetData = createAITool('form.getData')
116
+ .describe('Get all form data as an object')
117
+ .tag('form', 'read', 'client')
118
+ .input(z.object({
119
+ selector: z.string(),
120
+ includeDisabled: z.boolean().optional()
121
+ }))
122
+ .clientExecute(async ({ input }) => {
123
+ const form = document.querySelector(input.selector) as HTMLFormElement;
124
+ if (!form) throw new Error(`Form not found: ${input.selector}`);
125
+
126
+ const formData = new FormData(form);
127
+ const data: Record<string, any> = {};
128
+
129
+ formData.forEach((value, key) => {
130
+ if (data[key]) {
131
+ if (!Array.isArray(data[key])) {
132
+ data[key] = [data[key]];
133
+ }
134
+ data[key].push(value);
135
+ } else {
136
+ data[key] = value;
137
+ }
138
+ });
139
+
140
+ if (input.includeDisabled) {
141
+ const disabledFields = form.querySelectorAll('[disabled]') as NodeListOf<HTMLInputElement>;
142
+ disabledFields.forEach(field => {
143
+ if (field.name && !(field.name in data)) {
144
+ data[field.name] = field.value;
145
+ }
146
+ });
147
+ }
148
+
149
+ return { data };
150
+ });
151
+
152
+ export const formSetError = createAITool('form.setError')
153
+ .describe('Set custom validation error on a form field')
154
+ .tag('form', 'validation', 'client')
155
+ .input(z.object({
156
+ selector: z.string(),
157
+ message: z.string(),
158
+ show: z.boolean().optional()
159
+ }))
160
+ .clientExecute(async ({ input }) => {
161
+ const field = document.querySelector(input.selector) as HTMLInputElement;
162
+ if (!field) throw new Error(`Field not found: ${input.selector}`);
163
+
164
+ field.setCustomValidity(input.message);
165
+
166
+ if (input.show) {
167
+ field.reportValidity();
168
+ }
169
+
170
+ return { field: input.selector, message: input.message };
171
+ });
172
+
173
+ export const formClearErrors = createAITool('form.clearErrors')
174
+ .describe('Clear validation errors from form fields')
175
+ .tag('form', 'validation', 'client')
176
+ .input(z.object({
177
+ selector: z.string()
178
+ }))
179
+ .clientExecute(async ({ input }) => {
180
+ const form = document.querySelector(input.selector) as HTMLFormElement;
181
+ if (!form) throw new Error(`Form not found: ${input.selector}`);
182
+
183
+ const fields = form.querySelectorAll('input, select, textarea') as NodeListOf<HTMLInputElement>;
184
+ fields.forEach(field => {
185
+ field.setCustomValidity('');
186
+ });
187
+
188
+ return { cleared: true, fields: fields.length };
189
+ });
190
+
191
+ export const formWatch = createAITool('form.watch')
192
+ .describe('Watch form changes')
193
+ .tag('form', 'reactive', 'client')
194
+ .input(z.object({
195
+ selector: z.string(),
196
+ fields: z.array(z.string()).optional()
197
+ }))
198
+ .clientExecute(async ({ input }) => {
199
+ const form = document.querySelector(input.selector) as HTMLFormElement;
200
+ if (!form) throw new Error(`Form not found: ${input.selector}`);
201
+
202
+ const watchId = Math.random().toString(36).substring(7);
203
+
204
+ return {
205
+ watchId,
206
+ onChange: (callback: (data: Record<string, any>) => void) => {
207
+ const handler = () => {
208
+ const formData = new FormData(form);
209
+ const data: Record<string, any> = {};
210
+
211
+ if (input.fields) {
212
+ input.fields.forEach(field => {
213
+ data[field] = formData.get(field);
214
+ });
215
+ } else {
216
+ formData.forEach((value, key) => {
217
+ data[key] = value;
218
+ });
219
+ }
220
+
221
+ callback(data);
222
+ };
223
+
224
+ form.addEventListener('input', handler);
225
+ form.addEventListener('change', handler);
226
+
227
+ return () => {
228
+ form.removeEventListener('input', handler);
229
+ form.removeEventListener('change', handler);
230
+ };
231
+ }
232
+ };
233
+ });
@@ -0,0 +1,8 @@
1
+ export * from './dom-tools';
2
+ export * from './api-tools';
3
+ export * from './state-tools';
4
+ export * from './navigation-tools';
5
+ export * from './form-tools';
6
+ export * from './data-tools';
7
+ export * from './notification-tools';
8
+ export * from './file-tools';
@@ -0,0 +1,172 @@
1
+ import { z } from 'zod';
2
+ import { createAITool } from '../ai-control';
3
+
4
+ export const navigate = createAITool('navigate')
5
+ .describe('Navigate to a different page or URL')
6
+ .tag('navigation', 'routing', 'client')
7
+ .input(z.object({
8
+ url: z.string(),
9
+ newTab: z.boolean().optional(),
10
+ replace: z.boolean().optional()
11
+ }))
12
+ .clientExecute(async ({ input }) => {
13
+ if (input.newTab) {
14
+ window.open(input.url, '_blank');
15
+ } else if (input.replace) {
16
+ window.location.replace(input.url);
17
+ } else {
18
+ window.location.href = input.url;
19
+ }
20
+ return { navigated: true, url: input.url };
21
+ });
22
+
23
+ export const back = createAITool('navigate.back')
24
+ .describe('Go back in browser history')
25
+ .tag('navigation', 'history', 'client')
26
+ .input(z.object({
27
+ steps: z.number().optional().default(1)
28
+ }))
29
+ .clientExecute(async ({ input }) => {
30
+ const steps = input.steps || 1;
31
+ window.history.go(-steps);
32
+ return { back: steps };
33
+ });
34
+
35
+ export const forward = createAITool('navigate.forward')
36
+ .describe('Go forward in browser history')
37
+ .tag('navigation', 'history', 'client')
38
+ .input(z.object({
39
+ steps: z.number().optional().default(1)
40
+ }))
41
+ .clientExecute(async ({ input }) => {
42
+ const steps = input.steps || 1;
43
+ window.history.go(steps);
44
+ return { forward: steps };
45
+ });
46
+
47
+ export const reload = createAITool('navigate.reload')
48
+ .describe('Reload the current page')
49
+ .tag('navigation', 'page', 'client')
50
+ .input(z.object({
51
+ force: z.boolean().optional()
52
+ }))
53
+ .clientExecute(async ({ input }) => {
54
+ window.location.reload();
55
+ return { reloading: true };
56
+ });
57
+
58
+ export const pushState = createAITool('navigate.pushState')
59
+ .describe('Push a new state to browser history')
60
+ .tag('navigation', 'history', 'client')
61
+ .input(z.object({
62
+ url: z.string(),
63
+ state: z.any().optional(),
64
+ title: z.string().optional()
65
+ }))
66
+ .clientExecute(async ({ input }) => {
67
+ window.history.pushState(input.state, input.title || '', input.url);
68
+ return { pushed: true, url: input.url };
69
+ });
70
+
71
+ export const replaceState = createAITool('navigate.replaceState')
72
+ .describe('Replace current state in browser history')
73
+ .tag('navigation', 'history', 'client')
74
+ .input(z.object({
75
+ url: z.string(),
76
+ state: z.any().optional(),
77
+ title: z.string().optional()
78
+ }))
79
+ .clientExecute(async ({ input }) => {
80
+ window.history.replaceState(input.state, input.title || '', input.url);
81
+ return { replaced: true, url: input.url };
82
+ });
83
+
84
+ export const getLocation = createAITool('navigate.getLocation')
85
+ .describe('Get current location information')
86
+ .tag('navigation', 'location', 'client')
87
+ .input(z.object({}))
88
+ .clientExecute(async () => {
89
+ return {
90
+ href: window.location.href,
91
+ protocol: window.location.protocol,
92
+ host: window.location.host,
93
+ hostname: window.location.hostname,
94
+ port: window.location.port,
95
+ pathname: window.location.pathname,
96
+ search: window.location.search,
97
+ hash: window.location.hash,
98
+ origin: window.location.origin
99
+ };
100
+ });
101
+
102
+ export const getParams = createAITool('navigate.getParams')
103
+ .describe('Get URL search parameters')
104
+ .tag('navigation', 'params', 'client')
105
+ .input(z.object({
106
+ key: z.string().optional()
107
+ }))
108
+ .clientExecute(async ({ input }) => {
109
+ const params = new URLSearchParams(window.location.search);
110
+
111
+ if (input.key) {
112
+ return {
113
+ key: input.key,
114
+ value: params.get(input.key),
115
+ found: params.has(input.key)
116
+ };
117
+ }
118
+
119
+ const allParams: Record<string, string> = {};
120
+ params.forEach((value, key) => {
121
+ allParams[key] = value;
122
+ });
123
+
124
+ return { params: allParams };
125
+ });
126
+
127
+ export const setParams = createAITool('navigate.setParams')
128
+ .describe('Set URL search parameters')
129
+ .tag('navigation', 'params', 'client')
130
+ .input(z.object({
131
+ params: z.record(z.string()),
132
+ replace: z.boolean().optional()
133
+ }))
134
+ .clientExecute(async ({ input }) => {
135
+ const url = new URL(window.location.href);
136
+
137
+ Object.entries(input.params).forEach(([key, value]) => {
138
+ if (value === null || value === undefined) {
139
+ url.searchParams.delete(key);
140
+ } else {
141
+ url.searchParams.set(key, value);
142
+ }
143
+ });
144
+
145
+ if (input.replace) {
146
+ window.history.replaceState(null, '', url.toString());
147
+ } else {
148
+ window.history.pushState(null, '', url.toString());
149
+ }
150
+
151
+ return { params: input.params, url: url.toString() };
152
+ });
153
+
154
+ export const setHash = createAITool('navigate.setHash')
155
+ .describe('Set URL hash')
156
+ .tag('navigation', 'hash', 'client')
157
+ .input(z.object({
158
+ hash: z.string(),
159
+ scroll: z.boolean().optional()
160
+ }))
161
+ .clientExecute(async ({ input }) => {
162
+ window.location.hash = input.hash;
163
+
164
+ if (input.scroll && input.hash) {
165
+ const element = document.querySelector(input.hash);
166
+ if (element) {
167
+ element.scrollIntoView({ behavior: 'smooth' });
168
+ }
169
+ }
170
+
171
+ return { hash: input.hash };
172
+ });
@@ -0,0 +1,213 @@
1
+ import React from 'react';
2
+ import { z } from 'zod';
3
+ import { createAITool } from '../ai-control';
4
+
5
+ export const notifyToast = createAITool('notify.toast')
6
+ .describe('Show a toast notification')
7
+ .tag('notification', 'ui', 'client')
8
+ .input(z.object({
9
+ message: z.string(),
10
+ type: z.enum(['success', 'error', 'warning', 'info']).optional(),
11
+ duration: z.number().optional().default(3000),
12
+ position: z.enum(['top', 'bottom', 'top-left', 'top-right', 'bottom-left', 'bottom-right']).optional()
13
+ }))
14
+ .clientExecute(async ({ input }) => {
15
+ const toast = document.createElement('div');
16
+ toast.className = `aui-toast aui-toast-${input.type || 'info'}`;
17
+ toast.textContent = input.message;
18
+
19
+ const styles: any = {
20
+ position: 'fixed',
21
+ padding: '12px 24px',
22
+ borderRadius: '4px',
23
+ zIndex: '9999',
24
+ transition: 'opacity 0.3s',
25
+ fontSize: '14px',
26
+ fontFamily: 'system-ui, -apple-system, sans-serif'
27
+ };
28
+
29
+ const typeStyles: any = {
30
+ success: { backgroundColor: '#10b981', color: 'white' },
31
+ error: { backgroundColor: '#ef4444', color: 'white' },
32
+ warning: { backgroundColor: '#f59e0b', color: 'white' },
33
+ info: { backgroundColor: '#3b82f6', color: 'white' }
34
+ };
35
+
36
+ const positionStyles: any = {
37
+ top: { top: '20px', left: '50%', transform: 'translateX(-50%)' },
38
+ bottom: { bottom: '20px', left: '50%', transform: 'translateX(-50%)' },
39
+ 'top-left': { top: '20px', left: '20px' },
40
+ 'top-right': { top: '20px', right: '20px' },
41
+ 'bottom-left': { bottom: '20px', left: '20px' },
42
+ 'bottom-right': { bottom: '20px', right: '20px' }
43
+ };
44
+
45
+ Object.assign(toast.style, styles, typeStyles[input.type || 'info'], positionStyles[input.position || 'top']);
46
+
47
+ document.body.appendChild(toast);
48
+
49
+ setTimeout(() => {
50
+ toast.style.opacity = '0';
51
+ setTimeout(() => document.body.removeChild(toast), 300);
52
+ }, input.duration);
53
+
54
+ return { shown: true, message: input.message };
55
+ });
56
+
57
+ export const notifyAlert = createAITool('notify.alert')
58
+ .describe('Show a browser alert dialog')
59
+ .tag('notification', 'dialog', 'client')
60
+ .input(z.object({
61
+ message: z.string(),
62
+ title: z.string().optional()
63
+ }))
64
+ .clientExecute(async ({ input }) => {
65
+ window.alert(input.message);
66
+ return { shown: true };
67
+ });
68
+
69
+ export const notifyConfirm = createAITool('notify.confirm')
70
+ .describe('Show a confirmation dialog')
71
+ .tag('notification', 'dialog', 'client')
72
+ .input(z.object({
73
+ message: z.string(),
74
+ title: z.string().optional()
75
+ }))
76
+ .clientExecute(async ({ input }) => {
77
+ const confirmed = window.confirm(input.message);
78
+ return { confirmed };
79
+ });
80
+
81
+ export const notifyPrompt = createAITool('notify.prompt')
82
+ .describe('Show a prompt dialog for user input')
83
+ .tag('notification', 'dialog', 'client')
84
+ .input(z.object({
85
+ message: z.string(),
86
+ defaultValue: z.string().optional()
87
+ }))
88
+ .clientExecute(async ({ input }) => {
89
+ const value = window.prompt(input.message, input.defaultValue);
90
+ return { value, cancelled: value === null };
91
+ });
92
+
93
+ export const notifyBadge = createAITool('notify.badge')
94
+ .describe('Update badge count on an element')
95
+ .tag('notification', 'ui', 'client')
96
+ .input(z.object({
97
+ selector: z.string(),
98
+ count: z.number(),
99
+ show: z.boolean().optional()
100
+ }))
101
+ .clientExecute(async ({ input }) => {
102
+ const element = document.querySelector(input.selector);
103
+ if (!element) throw new Error(`Element not found: ${input.selector}`);
104
+
105
+ let badge = element.querySelector('.aui-badge') as HTMLElement;
106
+
107
+ if (!badge) {
108
+ badge = document.createElement('span');
109
+ badge.className = 'aui-badge';
110
+ badge.style.cssText = `
111
+ position: absolute;
112
+ top: -8px;
113
+ right: -8px;
114
+ background: #ef4444;
115
+ color: white;
116
+ border-radius: 10px;
117
+ padding: 2px 6px;
118
+ font-size: 12px;
119
+ font-weight: bold;
120
+ min-width: 20px;
121
+ text-align: center;
122
+ `;
123
+ (element as HTMLElement).style.position = 'relative';
124
+ element.appendChild(badge);
125
+ }
126
+
127
+ if (input.show === false || input.count === 0) {
128
+ badge.style.display = 'none';
129
+ } else {
130
+ badge.style.display = 'block';
131
+ badge.textContent = String(input.count);
132
+ }
133
+
134
+ return { selector: input.selector, count: input.count };
135
+ });
136
+
137
+ export const notifyProgress = createAITool('notify.progress')
138
+ .describe('Show or update a progress indicator')
139
+ .tag('notification', 'ui', 'client')
140
+ .input(z.object({
141
+ id: z.string(),
142
+ value: z.number().min(0).max(100),
143
+ message: z.string().optional(),
144
+ show: z.boolean().optional()
145
+ }))
146
+ .clientExecute(async ({ input }) => {
147
+ let progress = document.getElementById(`aui-progress-${input.id}`) as HTMLElement;
148
+
149
+ if (!progress) {
150
+ progress = document.createElement('div');
151
+ progress.id = `aui-progress-${input.id}`;
152
+ progress.style.cssText = `
153
+ position: fixed;
154
+ top: 50%;
155
+ left: 50%;
156
+ transform: translate(-50%, -50%);
157
+ background: white;
158
+ padding: 20px;
159
+ border-radius: 8px;
160
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
161
+ z-index: 9999;
162
+ min-width: 300px;
163
+ `;
164
+
165
+ const bar = document.createElement('div');
166
+ bar.className = 'aui-progress-bar';
167
+ bar.style.cssText = `
168
+ width: 100%;
169
+ height: 20px;
170
+ background: #e5e7eb;
171
+ border-radius: 10px;
172
+ overflow: hidden;
173
+ margin-top: 10px;
174
+ `;
175
+
176
+ const fill = document.createElement('div');
177
+ fill.className = 'aui-progress-fill';
178
+ fill.style.cssText = `
179
+ height: 100%;
180
+ background: #3b82f6;
181
+ transition: width 0.3s;
182
+ border-radius: 10px;
183
+ `;
184
+
185
+ const label = document.createElement('div');
186
+ label.className = 'aui-progress-label';
187
+ label.style.cssText = 'margin-bottom: 10px; font-family: system-ui;';
188
+
189
+ bar.appendChild(fill);
190
+ progress.appendChild(label);
191
+ progress.appendChild(bar);
192
+ document.body.appendChild(progress);
193
+ }
194
+
195
+ if (input.show === false) {
196
+ progress.style.display = 'none';
197
+ } else {
198
+ progress.style.display = 'block';
199
+ const fill = progress.querySelector('.aui-progress-fill') as HTMLElement;
200
+ const label = progress.querySelector('.aui-progress-label') as HTMLElement;
201
+
202
+ fill.style.width = `${input.value}%`;
203
+ label.textContent = input.message || `${input.value}%`;
204
+
205
+ if (input.value >= 100) {
206
+ setTimeout(() => {
207
+ progress.style.display = 'none';
208
+ }, 1000);
209
+ }
210
+ }
211
+
212
+ return { id: input.id, value: input.value };
213
+ });