@lantos1618/better-ui 0.2.2 → 0.3.1

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 (59) hide show
  1. package/README.md +231 -148
  2. package/dist/index.d.mts +314 -0
  3. package/dist/index.d.ts +314 -0
  4. package/dist/index.js +522 -0
  5. package/dist/index.mjs +491 -0
  6. package/package.json +59 -20
  7. package/lib/aui/README.md +0 -136
  8. package/lib/aui/__tests__/aui-complete.test.ts +0 -251
  9. package/lib/aui/__tests__/aui-comprehensive.test.ts +0 -376
  10. package/lib/aui/__tests__/aui-concise.test.ts +0 -278
  11. package/lib/aui/__tests__/aui-integration.test.ts +0 -309
  12. package/lib/aui/__tests__/aui-simple.test.ts +0 -116
  13. package/lib/aui/__tests__/aui.test.ts +0 -269
  14. package/lib/aui/__tests__/concise-api.test.ts +0 -165
  15. package/lib/aui/__tests__/core.test.ts +0 -265
  16. package/lib/aui/__tests__/simple-api.test.ts +0 -200
  17. package/lib/aui/ai-assistant.ts +0 -408
  18. package/lib/aui/ai-control.ts +0 -353
  19. package/lib/aui/client/use-aui.ts +0 -55
  20. package/lib/aui/client-control.ts +0 -551
  21. package/lib/aui/client-executor.ts +0 -417
  22. package/lib/aui/components/ToolRenderer.tsx +0 -22
  23. package/lib/aui/core.ts +0 -137
  24. package/lib/aui/demo.tsx +0 -89
  25. package/lib/aui/examples/ai-complete-demo.tsx +0 -359
  26. package/lib/aui/examples/ai-control-demo.tsx +0 -356
  27. package/lib/aui/examples/ai-control-tools.ts +0 -308
  28. package/lib/aui/examples/concise-api.tsx +0 -153
  29. package/lib/aui/examples/index.tsx +0 -163
  30. package/lib/aui/examples/quick-demo.tsx +0 -91
  31. package/lib/aui/examples/simple-demo.tsx +0 -71
  32. package/lib/aui/examples/simple-tools.tsx +0 -160
  33. package/lib/aui/examples/user-api.tsx +0 -208
  34. package/lib/aui/examples/user-requested.tsx +0 -174
  35. package/lib/aui/examples/weather-search-tools.tsx +0 -119
  36. package/lib/aui/examples.tsx +0 -367
  37. package/lib/aui/hooks/useAUITool.ts +0 -142
  38. package/lib/aui/hooks/useAUIToolEnhanced.ts +0 -343
  39. package/lib/aui/hooks/useAUITools.ts +0 -195
  40. package/lib/aui/index.ts +0 -156
  41. package/lib/aui/provider.tsx +0 -45
  42. package/lib/aui/server-control.ts +0 -386
  43. package/lib/aui/server-executor.ts +0 -165
  44. package/lib/aui/server.ts +0 -167
  45. package/lib/aui/tool-registry.ts +0 -380
  46. package/lib/aui/tools/advanced-examples.tsx +0 -86
  47. package/lib/aui/tools/ai-complete.ts +0 -375
  48. package/lib/aui/tools/api-tools.tsx +0 -230
  49. package/lib/aui/tools/data-tools.tsx +0 -232
  50. package/lib/aui/tools/dom-tools.tsx +0 -202
  51. package/lib/aui/tools/examples.ts +0 -43
  52. package/lib/aui/tools/file-tools.tsx +0 -202
  53. package/lib/aui/tools/form-tools.tsx +0 -233
  54. package/lib/aui/tools/index.ts +0 -8
  55. package/lib/aui/tools/navigation-tools.tsx +0 -172
  56. package/lib/aui/tools/notification-tools.ts +0 -213
  57. package/lib/aui/tools/state-tools.tsx +0 -209
  58. package/lib/aui/types.ts +0 -47
  59. package/lib/aui/vercel-ai.ts +0 -100
@@ -1,233 +0,0 @@
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
- });
@@ -1,8 +0,0 @@
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';
@@ -1,172 +0,0 @@
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
- });
@@ -1,213 +0,0 @@
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
- });