ai-progress-controls 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/LICENSE +21 -0
- package/README.md +823 -0
- package/dist/ai-progress-controls.es.js +7191 -0
- package/dist/ai-progress-controls.es.js.map +1 -0
- package/dist/ai-progress-controls.umd.js +2 -0
- package/dist/ai-progress-controls.umd.js.map +1 -0
- package/dist/index.d.ts +2212 -0
- package/package.json +105 -0
- package/src/__tests__/setup.ts +93 -0
- package/src/core/base/AIControl.ts +230 -0
- package/src/core/base/index.ts +3 -0
- package/src/core/base/types.ts +77 -0
- package/src/core/base/utils.ts +168 -0
- package/src/core/batch-progress/BatchProgress.test.ts +458 -0
- package/src/core/batch-progress/BatchProgress.ts +760 -0
- package/src/core/batch-progress/index.ts +14 -0
- package/src/core/batch-progress/styles.ts +480 -0
- package/src/core/batch-progress/types.ts +169 -0
- package/src/core/model-loader/ModelLoader.test.ts +311 -0
- package/src/core/model-loader/ModelLoader.ts +673 -0
- package/src/core/model-loader/index.ts +2 -0
- package/src/core/model-loader/styles.ts +496 -0
- package/src/core/model-loader/types.ts +127 -0
- package/src/core/parameter-panel/ParameterPanel.test.ts +856 -0
- package/src/core/parameter-panel/ParameterPanel.ts +877 -0
- package/src/core/parameter-panel/index.ts +14 -0
- package/src/core/parameter-panel/styles.ts +323 -0
- package/src/core/parameter-panel/types.ts +278 -0
- package/src/core/parameter-slider/ParameterSlider.test.ts +299 -0
- package/src/core/parameter-slider/ParameterSlider.ts +653 -0
- package/src/core/parameter-slider/index.ts +8 -0
- package/src/core/parameter-slider/styles.ts +493 -0
- package/src/core/parameter-slider/types.ts +107 -0
- package/src/core/queue-progress/QueueProgress.test.ts +344 -0
- package/src/core/queue-progress/QueueProgress.ts +563 -0
- package/src/core/queue-progress/index.ts +5 -0
- package/src/core/queue-progress/styles.ts +469 -0
- package/src/core/queue-progress/types.ts +130 -0
- package/src/core/retry-progress/RetryProgress.test.ts +397 -0
- package/src/core/retry-progress/RetryProgress.ts +957 -0
- package/src/core/retry-progress/index.ts +6 -0
- package/src/core/retry-progress/styles.ts +530 -0
- package/src/core/retry-progress/types.ts +176 -0
- package/src/core/stream-progress/StreamProgress.test.ts +531 -0
- package/src/core/stream-progress/StreamProgress.ts +517 -0
- package/src/core/stream-progress/index.ts +2 -0
- package/src/core/stream-progress/styles.ts +349 -0
- package/src/core/stream-progress/types.ts +82 -0
- package/src/index.ts +19 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { QueueProgress } from './QueueProgress';
|
|
3
|
+
import { waitForElement, waitForNextTick } from '../../__tests__/setup';
|
|
4
|
+
|
|
5
|
+
describe('QueueProgress Component', () => {
|
|
6
|
+
let progress: QueueProgress;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
progress = new QueueProgress();
|
|
10
|
+
document.body.appendChild(progress);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
if (progress.parentNode) {
|
|
15
|
+
progress.remove();
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('Constructor & Configuration', () => {
|
|
20
|
+
it('should create instance with default config', () => {
|
|
21
|
+
expect(progress).toBeInstanceOf(QueueProgress);
|
|
22
|
+
expect(progress.tagName.toLowerCase()).toBe('queue-progress');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should accept custom configuration', () => {
|
|
26
|
+
const customProgress = new QueueProgress({
|
|
27
|
+
position: 100,
|
|
28
|
+
queueSize: 200,
|
|
29
|
+
showPosition: true,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
expect(customProgress['config'].position).toBe(100);
|
|
33
|
+
expect(customProgress['config'].queueSize).toBe(200);
|
|
34
|
+
customProgress.remove();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should have shadow root', async () => {
|
|
38
|
+
await waitForElement(progress);
|
|
39
|
+
expect(progress.shadowRoot).toBeTruthy();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
describe('State Management', () => {
|
|
44
|
+
it('should initialize with waiting status', () => {
|
|
45
|
+
const status = progress.getStatus();
|
|
46
|
+
expect(status).toBe('waiting');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should track position', () => {
|
|
50
|
+
const customProgress = new QueueProgress({ position: 5 });
|
|
51
|
+
document.body.appendChild(customProgress);
|
|
52
|
+
customProgress.start();
|
|
53
|
+
expect(customProgress.getPosition()).toBe(5);
|
|
54
|
+
customProgress.remove();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('Methods', () => {
|
|
59
|
+
describe('start()', () => {
|
|
60
|
+
it('should start queue tracking', () => {
|
|
61
|
+
const customProgress = new QueueProgress({ position: 3, queueSize: 10 });
|
|
62
|
+
document.body.appendChild(customProgress);
|
|
63
|
+
customProgress.start('Waiting in queue...');
|
|
64
|
+
|
|
65
|
+
expect(customProgress.getStatus()).toBe('waiting');
|
|
66
|
+
expect(customProgress.getPosition()).toBe(3);
|
|
67
|
+
customProgress.remove();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should emit queuestart event', async () => {
|
|
71
|
+
const spy = vi.fn();
|
|
72
|
+
progress.addEventListener('queuestart', spy);
|
|
73
|
+
|
|
74
|
+
progress.start();
|
|
75
|
+
await waitForNextTick();
|
|
76
|
+
|
|
77
|
+
expect(spy).toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('update()', () => {
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
progress['config'].position = 5;
|
|
84
|
+
progress['state'].position = 5;
|
|
85
|
+
progress.start();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should update queue position', () => {
|
|
89
|
+
progress.update({ position: 3 });
|
|
90
|
+
expect(progress.getPosition()).toBe(3);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should emit positionchange event', async () => {
|
|
94
|
+
const spy = vi.fn();
|
|
95
|
+
progress.addEventListener('positionchange', spy);
|
|
96
|
+
|
|
97
|
+
progress.update({ position: 2 });
|
|
98
|
+
await waitForNextTick();
|
|
99
|
+
|
|
100
|
+
expect(spy).toHaveBeenCalled();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should handle position decrease', () => {
|
|
104
|
+
progress['config'].position = 3;
|
|
105
|
+
progress['state'].position = 3;
|
|
106
|
+
progress.start();
|
|
107
|
+
|
|
108
|
+
progress.update({ position: 1 });
|
|
109
|
+
expect(progress.getPosition()).toBe(1);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('complete()', () => {
|
|
114
|
+
beforeEach(() => {
|
|
115
|
+
progress['config'].position = 1;
|
|
116
|
+
progress['state'].position = 1;
|
|
117
|
+
progress.start();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should complete queue', () => {
|
|
121
|
+
progress.complete();
|
|
122
|
+
expect(progress.getStatus()).toBe('completed');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should emit queuecomplete event', async () => {
|
|
126
|
+
const spy = vi.fn();
|
|
127
|
+
progress.addEventListener('queuecomplete', spy);
|
|
128
|
+
|
|
129
|
+
progress.complete();
|
|
130
|
+
await waitForNextTick();
|
|
131
|
+
|
|
132
|
+
expect(spy).toHaveBeenCalled();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
describe('cancel()', () => {
|
|
137
|
+
beforeEach(() => {
|
|
138
|
+
progress['config'].position = 5;
|
|
139
|
+
progress['state'].position = 5;
|
|
140
|
+
progress.start();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should cancel queue', () => {
|
|
144
|
+
progress.cancel();
|
|
145
|
+
expect(progress.getStatus()).toBe('cancelled');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should update status on cancel', async () => {
|
|
149
|
+
progress.cancel('User cancelled');
|
|
150
|
+
await waitForNextTick();
|
|
151
|
+
|
|
152
|
+
expect(progress.getStatus()).toBe('cancelled');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('error()', () => {
|
|
157
|
+
beforeEach(() => {
|
|
158
|
+
progress['config'].position = 2;
|
|
159
|
+
progress['state'].position = 2;
|
|
160
|
+
progress.start();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should handle error', () => {
|
|
164
|
+
progress.error('Queue error');
|
|
165
|
+
expect(progress.getStatus()).toBe('error');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('should emit queueerror event', async () => {
|
|
169
|
+
const spy = vi.fn();
|
|
170
|
+
progress.addEventListener('queueerror', spy);
|
|
171
|
+
|
|
172
|
+
progress.error('Test error');
|
|
173
|
+
await waitForNextTick();
|
|
174
|
+
|
|
175
|
+
expect(spy).toHaveBeenCalled();
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe('reset()', () => {
|
|
180
|
+
it('should reset to initial state', () => {
|
|
181
|
+
progress.start({ position: 5, total: 10 });
|
|
182
|
+
progress.update({ position: 3 });
|
|
183
|
+
progress.reset();
|
|
184
|
+
|
|
185
|
+
expect(progress.getStatus()).toBe('waiting');
|
|
186
|
+
expect(progress.getPosition()).toBe(0);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('Properties', () => {
|
|
192
|
+
it('should get/set disabled state', () => {
|
|
193
|
+
expect(progress.disabled).toBe(false);
|
|
194
|
+
|
|
195
|
+
progress.disabled = true;
|
|
196
|
+
expect(progress.disabled).toBe(true);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('Rendering', () => {
|
|
201
|
+
it('should render in shadow DOM', async () => {
|
|
202
|
+
await waitForElement(progress);
|
|
203
|
+
expect(progress.shadowRoot?.querySelector('.queue-container')).toBeTruthy();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should update display on position change', async () => {
|
|
207
|
+
progress.start({ position: 5, total: 10 });
|
|
208
|
+
await waitForElement(progress);
|
|
209
|
+
|
|
210
|
+
progress.update({ position: 3 });
|
|
211
|
+
await waitForNextTick();
|
|
212
|
+
|
|
213
|
+
const container = progress.shadowRoot?.querySelector('.queue-container');
|
|
214
|
+
expect(container).toBeTruthy();
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
describe('Accessibility', () => {
|
|
219
|
+
it('should have proper ARIA role', async () => {
|
|
220
|
+
await waitForElement(progress);
|
|
221
|
+
const role = progress.getAttribute('role');
|
|
222
|
+
expect(role).toBe('status');
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe('Edge Cases', () => {
|
|
227
|
+
it('should handle position 0', () => {
|
|
228
|
+
progress.start({ position: 0, total: 10 });
|
|
229
|
+
expect(progress.getPosition()).toBe(0);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should handle position at total', () => {
|
|
233
|
+
const customProgress = new QueueProgress({ position: 10, queueSize: 10 });
|
|
234
|
+
document.body.appendChild(customProgress);
|
|
235
|
+
customProgress.start();
|
|
236
|
+
expect(customProgress.getPosition()).toBe(10);
|
|
237
|
+
customProgress.remove();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should handle rapid position updates', async () => {
|
|
241
|
+
progress['config'].position = 10;
|
|
242
|
+
progress['state'].position = 10;
|
|
243
|
+
progress.start();
|
|
244
|
+
|
|
245
|
+
for (let i = 9; i >= 0; i--) {
|
|
246
|
+
progress.update({ position: i });
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Wait for throttled updates to complete (100ms throttle + buffer)
|
|
250
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
251
|
+
|
|
252
|
+
// Throttling means not all updates will be processed, but position should be lower
|
|
253
|
+
expect(progress.getPosition()).toBeLessThanOrEqual(10);
|
|
254
|
+
expect(progress.getPosition()).toBeGreaterThanOrEqual(0);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
describe('Size Variants', () => {
|
|
259
|
+
it('should default to default size', () => {
|
|
260
|
+
expect(progress['config'].size).toBe('default');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should accept size in constructor', () => {
|
|
264
|
+
const compact = new QueueProgress({ size: 'compact' });
|
|
265
|
+
expect(compact['config'].size).toBe('compact');
|
|
266
|
+
compact.remove();
|
|
267
|
+
|
|
268
|
+
const large = new QueueProgress({ size: 'large' });
|
|
269
|
+
expect(large['config'].size).toBe('large');
|
|
270
|
+
large.remove();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should update size via attribute', async () => {
|
|
274
|
+
await waitForElement(progress);
|
|
275
|
+
|
|
276
|
+
progress.setAttribute('size', 'compact');
|
|
277
|
+
await waitForNextTick();
|
|
278
|
+
expect(progress['config'].size).toBe('compact');
|
|
279
|
+
expect(progress.getAttribute('size')).toBe('compact');
|
|
280
|
+
|
|
281
|
+
progress.setAttribute('size', 'large');
|
|
282
|
+
await waitForNextTick();
|
|
283
|
+
expect(progress['config'].size).toBe('large');
|
|
284
|
+
expect(progress.getAttribute('size')).toBe('large');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should apply size attribute to host element', async () => {
|
|
288
|
+
await waitForElement(progress);
|
|
289
|
+
|
|
290
|
+
progress.setAttribute('size', 'compact');
|
|
291
|
+
await waitForNextTick();
|
|
292
|
+
expect(progress.hasAttribute('size')).toBe(true);
|
|
293
|
+
expect(progress.getAttribute('size')).toBe('compact');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
describe('Visual Variants', () => {
|
|
298
|
+
it('should apply default variant by default', () => {
|
|
299
|
+
expect(progress['config'].variant).toBe('default');
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('should apply minimal variant', () => {
|
|
303
|
+
const minimal = new QueueProgress({ variant: 'minimal' });
|
|
304
|
+
expect(minimal['config'].variant).toBe('minimal');
|
|
305
|
+
minimal.remove();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('should apply gradient variant', () => {
|
|
309
|
+
const gradient = new QueueProgress({ variant: 'gradient' });
|
|
310
|
+
expect(gradient['config'].variant).toBe('gradient');
|
|
311
|
+
gradient.remove();
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('should apply glassmorphic variant', () => {
|
|
315
|
+
const glassmorphic = new QueueProgress({ variant: 'glassmorphic' });
|
|
316
|
+
expect(glassmorphic['config'].variant).toBe('glassmorphic');
|
|
317
|
+
glassmorphic.remove();
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
describe('Animation Effects', () => {
|
|
322
|
+
it('should apply none animation by default', () => {
|
|
323
|
+
expect(progress['config'].animation).toBe('none');
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('should apply striped animation', () => {
|
|
327
|
+
const striped = new QueueProgress({ animation: 'striped' });
|
|
328
|
+
expect(striped['config'].animation).toBe('striped');
|
|
329
|
+
striped.remove();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should apply pulse animation', () => {
|
|
333
|
+
const pulse = new QueueProgress({ animation: 'pulse' });
|
|
334
|
+
expect(pulse['config'].animation).toBe('pulse');
|
|
335
|
+
pulse.remove();
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('should apply glow animation', () => {
|
|
339
|
+
const glow = new QueueProgress({ animation: 'glow' });
|
|
340
|
+
expect(glow['config'].animation).toBe('glow');
|
|
341
|
+
glow.remove();
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|