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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +823 -0
  3. package/dist/ai-progress-controls.es.js +7191 -0
  4. package/dist/ai-progress-controls.es.js.map +1 -0
  5. package/dist/ai-progress-controls.umd.js +2 -0
  6. package/dist/ai-progress-controls.umd.js.map +1 -0
  7. package/dist/index.d.ts +2212 -0
  8. package/package.json +105 -0
  9. package/src/__tests__/setup.ts +93 -0
  10. package/src/core/base/AIControl.ts +230 -0
  11. package/src/core/base/index.ts +3 -0
  12. package/src/core/base/types.ts +77 -0
  13. package/src/core/base/utils.ts +168 -0
  14. package/src/core/batch-progress/BatchProgress.test.ts +458 -0
  15. package/src/core/batch-progress/BatchProgress.ts +760 -0
  16. package/src/core/batch-progress/index.ts +14 -0
  17. package/src/core/batch-progress/styles.ts +480 -0
  18. package/src/core/batch-progress/types.ts +169 -0
  19. package/src/core/model-loader/ModelLoader.test.ts +311 -0
  20. package/src/core/model-loader/ModelLoader.ts +673 -0
  21. package/src/core/model-loader/index.ts +2 -0
  22. package/src/core/model-loader/styles.ts +496 -0
  23. package/src/core/model-loader/types.ts +127 -0
  24. package/src/core/parameter-panel/ParameterPanel.test.ts +856 -0
  25. package/src/core/parameter-panel/ParameterPanel.ts +877 -0
  26. package/src/core/parameter-panel/index.ts +14 -0
  27. package/src/core/parameter-panel/styles.ts +323 -0
  28. package/src/core/parameter-panel/types.ts +278 -0
  29. package/src/core/parameter-slider/ParameterSlider.test.ts +299 -0
  30. package/src/core/parameter-slider/ParameterSlider.ts +653 -0
  31. package/src/core/parameter-slider/index.ts +8 -0
  32. package/src/core/parameter-slider/styles.ts +493 -0
  33. package/src/core/parameter-slider/types.ts +107 -0
  34. package/src/core/queue-progress/QueueProgress.test.ts +344 -0
  35. package/src/core/queue-progress/QueueProgress.ts +563 -0
  36. package/src/core/queue-progress/index.ts +5 -0
  37. package/src/core/queue-progress/styles.ts +469 -0
  38. package/src/core/queue-progress/types.ts +130 -0
  39. package/src/core/retry-progress/RetryProgress.test.ts +397 -0
  40. package/src/core/retry-progress/RetryProgress.ts +957 -0
  41. package/src/core/retry-progress/index.ts +6 -0
  42. package/src/core/retry-progress/styles.ts +530 -0
  43. package/src/core/retry-progress/types.ts +176 -0
  44. package/src/core/stream-progress/StreamProgress.test.ts +531 -0
  45. package/src/core/stream-progress/StreamProgress.ts +517 -0
  46. package/src/core/stream-progress/index.ts +2 -0
  47. package/src/core/stream-progress/styles.ts +349 -0
  48. package/src/core/stream-progress/types.ts +82 -0
  49. package/src/index.ts +19 -0
@@ -0,0 +1,496 @@
1
+ export const styles = `
2
+ <style>
3
+ :host {
4
+ /* CSS variables inherit from document root with fallback defaults */
5
+ display: block;
6
+ font-family: var(--ai-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
7
+ font-size: var(--ai-font-size, 14px);
8
+ }
9
+
10
+ :host([style*="cursor: progress"]) .model-loader {
11
+ cursor: progress;
12
+ }
13
+
14
+ :host([style*="cursor: not-allowed"]) .model-loader {
15
+ cursor: not-allowed;
16
+ }
17
+
18
+ :host([style*="cursor: default"]) .model-loader {
19
+ cursor: default;
20
+ }
21
+
22
+ .model-loader {
23
+ background: var(--ai-background-color, #ffffff);
24
+ border: 1px solid var(--ai-border-color, #e5e7eb);
25
+ border-radius: var(--ai-border-radius, 8px);
26
+ padding: var(--ai-spacing, 12px);
27
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
28
+ }
29
+
30
+ .model-loader.loading {
31
+ border-color: var(--ai-primary-color, #3b82f6);
32
+ }
33
+
34
+ .model-loader.error {
35
+ border-color: #ef4444;
36
+ }
37
+
38
+ .model-loader.completed {
39
+ border-color: var(--ai-secondary-color, #10b981);
40
+ }
41
+
42
+ .header {
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: space-between;
46
+ margin-bottom: var(--ai-spacing, 12px);
47
+ }
48
+
49
+ .model-name {
50
+ font-size: 15px;
51
+ font-weight: 600;
52
+ color: var(--ai-text-color, #1f2937);
53
+ }
54
+
55
+ .status-badge {
56
+ padding: 4px 10px;
57
+ border-radius: 12px;
58
+ font-size: 11px;
59
+ font-weight: 600;
60
+ text-transform: uppercase;
61
+ letter-spacing: 0.5px;
62
+ }
63
+
64
+ .status-badge.loading {
65
+ background: #dbeafe;
66
+ color: #1e40af;
67
+ }
68
+
69
+ .status-badge.completed {
70
+ background: #d1fae5;
71
+ color: #065f46;
72
+ }
73
+
74
+ .status-badge.error {
75
+ background: #fee2e2;
76
+ color: #991b1b;
77
+ }
78
+
79
+ .stages {
80
+ display: flex;
81
+ flex-direction: column;
82
+ gap: var(--ai-spacing, 12px);
83
+ margin-bottom: var(--ai-spacing, 12px);
84
+ }
85
+
86
+ .stage {
87
+ display: flex;
88
+ flex-direction: column;
89
+ gap: 6px;
90
+ }
91
+
92
+ .stage-header {
93
+ display: flex;
94
+ align-items: center;
95
+ justify-content: space-between;
96
+ }
97
+
98
+ .stage-info {
99
+ display: flex;
100
+ align-items: center;
101
+ gap: 8px;
102
+ }
103
+
104
+ .stage-icon {
105
+ width: 24px;
106
+ height: 24px;
107
+ border-radius: 50%;
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ font-size: 12px;
112
+ font-weight: bold;
113
+ flex-shrink: 0;
114
+ }
115
+
116
+ .stage-icon.pending {
117
+ background: #f3f4f6;
118
+ color: #9ca3af;
119
+ }
120
+
121
+ .stage-icon.in-progress {
122
+ background: #dbeafe;
123
+ color: #1e40af;
124
+ animation: pulse 2s ease-in-out infinite;
125
+ }
126
+
127
+ .stage-icon.completed {
128
+ background: #d1fae5;
129
+ color: #065f46;
130
+ }
131
+
132
+ .stage-icon.error {
133
+ background: #fee2e2;
134
+ color: #991b1b;
135
+ }
136
+
137
+ @keyframes pulse {
138
+ 0%, 100% {
139
+ opacity: 1;
140
+ }
141
+ 50% {
142
+ opacity: 0.7;
143
+ }
144
+ }
145
+
146
+ .stage-name {
147
+ font-size: 13px;
148
+ font-weight: 600;
149
+ color: var(--ai-text-color, #1f2937);
150
+ text-transform: capitalize;
151
+ }
152
+
153
+ .stage-progress-text {
154
+ font-size: 12px;
155
+ color: #6b7280;
156
+ font-weight: 600;
157
+ font-variant-numeric: tabular-nums;
158
+ }
159
+
160
+ .stage-message {
161
+ font-size: 12px;
162
+ color: #6b7280;
163
+ padding-left: 32px;
164
+ }
165
+
166
+ .progress-bar {
167
+ width: 100%;
168
+ height: 6px;
169
+ background: #f3f4f6;
170
+ border-radius: 3px;
171
+ overflow: hidden;
172
+ margin-left: 32px;
173
+ width: calc(100% - 32px);
174
+ }
175
+
176
+ .progress-fill {
177
+ height: 100%;
178
+ background: linear-gradient(90deg, var(--ai-primary-color, #3b82f6), var(--ai-secondary-color, #10b981));
179
+ transition: width 0.3s ease;
180
+ border-radius: 3px;
181
+ }
182
+
183
+ .progress-fill.error {
184
+ background: #ef4444;
185
+ }
186
+
187
+ .stage.in-progress .progress-fill {
188
+ animation: shimmer 2s ease-in-out infinite;
189
+ }
190
+
191
+ @keyframes shimmer {
192
+ 0% {
193
+ opacity: 1;
194
+ }
195
+ 50% {
196
+ opacity: 0.7;
197
+ }
198
+ 100% {
199
+ opacity: 1;
200
+ }
201
+ }
202
+
203
+ /* Override default animation when animation attribute is set */
204
+ :host([animation]) .stage.in-progress .progress-fill {
205
+ animation: none !important;
206
+ }
207
+
208
+ .stats {
209
+ display: grid;
210
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
211
+ gap: var(--ai-spacing, 12px);
212
+ padding-top: var(--ai-spacing, 12px);
213
+ border-top: 1px solid var(--ai-border-color, #e5e7eb);
214
+ margin-top: var(--ai-spacing, 12px);
215
+ }
216
+
217
+ .stat-item {
218
+ display: flex;
219
+ flex-direction: column;
220
+ gap: 4px;
221
+ }
222
+
223
+ .stat-label {
224
+ font-size: 11px;
225
+ color: #6b7280;
226
+ text-transform: uppercase;
227
+ letter-spacing: 0.5px;
228
+ font-weight: 600;
229
+ }
230
+
231
+ .stat-value {
232
+ font-size: 15px;
233
+ color: var(--ai-text-color, #1f2937);
234
+ font-weight: 600;
235
+ font-variant-numeric: tabular-nums;
236
+ }
237
+
238
+ .error-message {
239
+ background: #fef2f2;
240
+ border: 1px solid #fecaca;
241
+ border-radius: 6px;
242
+ padding: 12px;
243
+ margin-top: var(--ai-spacing, 12px);
244
+ display: flex;
245
+ align-items: flex-start;
246
+ gap: 8px;
247
+ }
248
+
249
+ .error-icon {
250
+ color: #dc2626;
251
+ font-size: 18px;
252
+ flex-shrink: 0;
253
+ margin-top: 2px;
254
+ }
255
+
256
+ .error-text {
257
+ color: #991b1b;
258
+ font-size: 13px;
259
+ line-height: 1.5;
260
+ }
261
+
262
+ .retry-button {
263
+ width: 100%;
264
+ padding: 10px 16px;
265
+ background: var(--ai-primary-color, #3b82f6);
266
+ color: white;
267
+ border: none;
268
+ border-radius: calc(var(--ai-border-radius, 8px) * 0.75);
269
+ font-size: 13px;
270
+ font-weight: 600;
271
+ cursor: pointer;
272
+ transition: background 0.2s ease;
273
+ font-family: inherit;
274
+ margin-top: var(--ai-spacing, 12px);
275
+ }
276
+
277
+ .retry-button:hover {
278
+ background: #2563eb;
279
+ }
280
+
281
+ .retry-button:active {
282
+ transform: translateY(1px);
283
+ }
284
+
285
+ .retry-button:focus-visible {
286
+ outline: 2px solid var(--ai-primary-color, #3b82f6);
287
+ outline-offset: 2px;
288
+ }
289
+
290
+ /* Visual Variants */
291
+
292
+ /* Minimal variant - clean, no shadows */
293
+ :host([variant="minimal"]) .model-loader {
294
+ box-shadow: none;
295
+ border: 1px solid var(--ai-border-color, #e5e7eb);
296
+ }
297
+
298
+ :host([variant="minimal"]) .progress-bar {
299
+ background: transparent;
300
+ border: 1px solid var(--ai-border-color, #e5e7eb);
301
+ }
302
+
303
+ /* Gradient variant - colorful gradients */
304
+ :host([variant="gradient"]) .progress-fill {
305
+ background: linear-gradient(
306
+ 90deg,
307
+ var(--ai-primary-color, #3b82f6),
308
+ var(--ai-secondary-color, #10b981),
309
+ var(--ai-primary-color, #3b82f6)
310
+ );
311
+ background-size: 200% 100%;
312
+ animation: gradient-shift 3s ease-in-out infinite;
313
+ }
314
+
315
+ @keyframes gradient-shift {
316
+ 0%, 100% { background-position: 0% 50%; }
317
+ 50% { background-position: 100% 50%; }
318
+ }
319
+
320
+ /* Override default animation when animation attribute is set */
321
+ :host([animation][variant="gradient"]) .progress-fill {
322
+ animation: none !important;
323
+ }
324
+
325
+ /* Glassmorphic variant - frosted glass effect */
326
+ :host([variant="glassmorphic"]) .model-loader {
327
+ background: rgba(255, 255, 255, 0.1);
328
+ backdrop-filter: blur(10px);
329
+ -webkit-backdrop-filter: blur(10px);
330
+ border: 1px solid rgba(255, 255, 255, 0.2);
331
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
332
+ }
333
+
334
+ :host([variant="glassmorphic"]) .progress-bar {
335
+ background: rgba(0, 0, 0, 0.1);
336
+ }
337
+
338
+ :host([variant="glassmorphic"]) .progress-fill {
339
+ background: linear-gradient(
340
+ 90deg,
341
+ rgba(59, 130, 246, 0.8),
342
+ rgba(16, 185, 129, 0.8)
343
+ );
344
+ }
345
+
346
+ /* Animation Effects */
347
+
348
+ /* Striped animation */
349
+ :host([animation="striped"]) .progress-fill {
350
+ background-image:
351
+ linear-gradient(
352
+ 45deg,
353
+ rgba(255, 255, 255, 0.2) 25%,
354
+ transparent 25%,
355
+ transparent 50%,
356
+ rgba(255, 255, 255, 0.2) 50%,
357
+ rgba(255, 255, 255, 0.2) 75%,
358
+ transparent 75%,
359
+ transparent
360
+ ),
361
+ linear-gradient(to right, var(--ai-primary-color, #3b82f6), var(--ai-primary-color, #3b82f6)) !important;
362
+ background-size: 2rem 2rem, 100% 100% !important;
363
+ animation: progress-stripes 3s linear infinite !important;
364
+ }
365
+
366
+ @keyframes progress-stripes {
367
+ 0% { background-position: 0 0, 0 0; }
368
+ 100% { background-position: 2rem 0, 0 0; }
369
+ }
370
+
371
+ /* Pulse animation */
372
+ :host([animation="pulse"]) .progress-fill {
373
+ animation: progress-pulse 4s ease-in-out infinite !important;
374
+ }
375
+
376
+ @keyframes progress-pulse {
377
+ 0%, 100% { opacity: 1; }
378
+ 50% { opacity: 0.3; }
379
+ }
380
+
381
+ /* Glow animation */
382
+ :host([animation="glow"]) .progress-fill {
383
+ animation: progress-glow 4s ease-in-out infinite !important;
384
+ }
385
+
386
+ @keyframes progress-glow {
387
+ 0%, 100% {
388
+ box-shadow: 0 0 5px var(--ai-primary-color, #3b82f6),
389
+ 0 0 10px var(--ai-primary-color, #3b82f6);
390
+ }
391
+ 50% {
392
+ box-shadow: 0 0 20px var(--ai-primary-color, #3b82f6),
393
+ 0 0 35px var(--ai-primary-color, #3b82f6),
394
+ 0 0 50px var(--ai-primary-color, #3b82f6);
395
+ }
396
+ }
397
+
398
+ /* Dark mode support - variables can be overridden at document level */
399
+ @media (prefers-color-scheme: dark) {
400
+ .progress-bar {
401
+ background: #374151;
402
+ }
403
+
404
+ .stat-label,
405
+ .stage-message,
406
+ .stage-progress-text {
407
+ color: #9ca3af;
408
+ }
409
+
410
+ .error-message {
411
+ background: #450a0a;
412
+ border-color: #7f1d1d;
413
+ }
414
+ }
415
+
416
+ /* Reduced motion support */
417
+ @media (prefers-reduced-motion: reduce) {
418
+ .progress-fill,
419
+ .stage-icon.in-progress,
420
+ .stage.in-progress .progress-fill {
421
+ animation: none;
422
+ transition: none;
423
+ }
424
+
425
+ .retry-button {
426
+ transition: none;
427
+ }
428
+ }
429
+
430
+ /* Size variants */
431
+ :host([size="compact"]) .model-loader {
432
+ padding: 8px;
433
+ font-size: 12px;
434
+ }
435
+
436
+ :host([size="compact"]) .progress-bar {
437
+ height: 6px;
438
+ }
439
+
440
+ :host([size="compact"]) .model-name {
441
+ font-size: 13px;
442
+ }
443
+
444
+ :host([size="compact"]) .status-badge {
445
+ padding: 3px 8px;
446
+ font-size: 10px;
447
+ }
448
+
449
+ :host([size="compact"]) .stage-name {
450
+ font-size: 11px;
451
+ }
452
+
453
+ :host([size="compact"]) .stat-value {
454
+ font-size: 14px;
455
+ }
456
+
457
+ :host([size="large"]) .model-loader {
458
+ padding: 16px;
459
+ font-size: 16px;
460
+ }
461
+
462
+ :host([size="large"]) .progress-bar {
463
+ height: 10px;
464
+ }
465
+
466
+ :host([size="large"]) .model-name {
467
+ font-size: 17px;
468
+ }
469
+
470
+ :host([size="large"]) .status-badge {
471
+ padding: 5px 12px;
472
+ font-size: 12px;
473
+ }
474
+
475
+ :host([size="large"]) .stage-name {
476
+ font-size: 15px;
477
+ }
478
+
479
+ :host([size="large"]) .stat-value {
480
+ font-size: 18px;
481
+ }
482
+
483
+ /* Responsive design */
484
+ @media (max-width: 640px) {
485
+ .stats {
486
+ grid-template-columns: 1fr;
487
+ }
488
+ }
489
+
490
+ /* Disabled state */
491
+ :host([disabled]) .model-loader {
492
+ opacity: 0.5;
493
+ pointer-events: none;
494
+ }
495
+ </style>
496
+ `;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Loading stages for model initialization
3
+ */
4
+ export type ModelStage = 'download' | 'load' | 'initialize' | 'ready';
5
+
6
+ /**
7
+ * Status of each stage
8
+ */
9
+ export type StageStatus = 'pending' | 'in-progress' | 'completed' | 'error';
10
+
11
+ /**
12
+ * Configuration for ModelLoader component
13
+ */
14
+ export interface ModelLoaderConfig {
15
+ /** Stages to show (default: all) */
16
+ stages?: ModelStage[];
17
+
18
+ /** Model name to display */
19
+ modelName?: string;
20
+
21
+ /** Show bytes downloaded/total */
22
+ showBytes?: boolean;
23
+
24
+ /** Show memory usage */
25
+ showMemoryUsage?: boolean;
26
+
27
+ /** Show estimated time remaining */
28
+ showETA?: boolean;
29
+
30
+ /** Show retry button on error */
31
+ showRetryButton?: boolean;
32
+
33
+ /** Enable smooth progress animation */
34
+ smoothProgress?: boolean;
35
+
36
+ /** Update throttle in milliseconds */
37
+ updateThrottle?: number;
38
+
39
+ /** Custom retry button label */
40
+ retryLabel?: string;
41
+
42
+ /** Enable automatic cursor state changes based on component state */
43
+ cursorFeedback?: boolean;
44
+
45
+ /** Component size variant */
46
+ size?: 'compact' | 'default' | 'large';
47
+
48
+ /** Visual style variant */
49
+ variant?: 'default' | 'minimal' | 'gradient' | 'glassmorphic';
50
+
51
+ /** Animation style */
52
+ animation?: 'none' | 'striped' | 'pulse' | 'glow';
53
+
54
+ /** Debug mode */
55
+ debug?: boolean;
56
+
57
+ /** Custom CSS class */
58
+ className?: string;
59
+
60
+ /** Aria label */
61
+ ariaLabel?: string;
62
+ }
63
+
64
+ /**
65
+ * State for each stage
66
+ */
67
+ export interface StageState {
68
+ status: StageStatus;
69
+ progress: number; // 0-100
70
+ message?: string;
71
+ bytesLoaded?: number;
72
+ totalBytes?: number;
73
+ startTime?: number;
74
+ endTime?: number;
75
+ }
76
+
77
+ /**
78
+ * Overall ModelLoader state
79
+ */
80
+ export interface ModelLoaderState {
81
+ currentStage: ModelStage;
82
+ stages: Record<ModelStage, StageState>;
83
+ isLoading: boolean;
84
+ hasError: boolean;
85
+ errorMessage?: string;
86
+ memoryUsage?: number; // in MB
87
+ startTime: number;
88
+ }
89
+
90
+ /**
91
+ * Update data for a stage
92
+ */
93
+ export interface StageUpdate {
94
+ stage: ModelStage;
95
+ progress?: number; // 0-100
96
+ bytesLoaded?: number;
97
+ totalBytes?: number;
98
+ message?: string;
99
+ memoryUsage?: number;
100
+ }
101
+
102
+ /**
103
+ * Event data for stage change
104
+ */
105
+ export interface StageChangeEvent {
106
+ previousStage: ModelStage;
107
+ currentStage: ModelStage;
108
+ timestamp: number;
109
+ }
110
+
111
+ /**
112
+ * Event data for completion
113
+ */
114
+ export interface LoadCompleteEvent {
115
+ duration: number;
116
+ memoryUsage?: number;
117
+ stages: Record<ModelStage, StageState>;
118
+ }
119
+
120
+ /**
121
+ * Event data for error
122
+ */
123
+ export interface LoadErrorEvent {
124
+ stage: ModelStage;
125
+ message: string;
126
+ timestamp: number;
127
+ }