@smartnet360/svelte-components 0.0.122 → 0.0.124

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 (28) hide show
  1. package/dist/apps/antenna-tools/band-config.d.ts +3 -2
  2. package/dist/apps/antenna-tools/band-config.js +6 -4
  3. package/dist/apps/antenna-tools/components/AntennaControls.svelte +71 -9
  4. package/dist/apps/antenna-tools/components/AntennaControls.svelte.d.ts +2 -0
  5. package/dist/apps/antenna-tools/components/AntennaSettingsModal.svelte +5 -2
  6. package/dist/apps/antenna-tools/components/AntennaSettingsModal.svelte.d.ts +3 -0
  7. package/dist/apps/antenna-tools/components/AntennaTools.svelte +55 -85
  8. package/dist/apps/antenna-tools/components/AntennaTools.svelte.d.ts +5 -3
  9. package/dist/apps/antenna-tools/components/DatabaseViewer.svelte +3 -6
  10. package/dist/apps/antenna-tools/components/MSIConverter.svelte +123 -15
  11. package/dist/apps/antenna-tools/components/MSIConverter.svelte.d.ts +3 -0
  12. package/dist/apps/antenna-tools/types.d.ts +8 -3
  13. package/dist/apps/antenna-tools/types.js +14 -8
  14. package/dist/apps/antenna-tools/utils/db-utils.d.ts +3 -2
  15. package/dist/apps/antenna-tools/utils/db-utils.js +3 -2
  16. package/dist/apps/antenna-tools/utils/msi-parser.d.ts +50 -2
  17. package/dist/apps/antenna-tools/utils/msi-parser.js +110 -27
  18. package/dist/apps/index.d.ts +2 -0
  19. package/dist/apps/index.js +1 -0
  20. package/dist/core/Benchmark/Benchmark.svelte +662 -0
  21. package/dist/core/Benchmark/Benchmark.svelte.d.ts +3 -0
  22. package/dist/core/Benchmark/benchmark-utils.d.ts +48 -0
  23. package/dist/core/Benchmark/benchmark-utils.js +80 -0
  24. package/dist/core/Benchmark/index.d.ts +2 -0
  25. package/dist/core/Benchmark/index.js +3 -0
  26. package/dist/core/index.d.ts +1 -0
  27. package/dist/core/index.js +2 -0
  28. package/package.json +1 -1
@@ -0,0 +1,662 @@
1
+ <svelte:options runes={true} />
2
+
3
+ <script lang="ts">
4
+ import { tick } from 'svelte';
5
+ import {
6
+ generateTestData,
7
+ runBenchmark,
8
+ formatDuration,
9
+ type BenchmarkResult,
10
+ type TestItem
11
+ } from './benchmark-utils';
12
+
13
+ // Test configuration
14
+ const DATA_SIZES = [100, 1000, 5000, 10000];
15
+
16
+ // Reactive state
17
+ let selectedSize = $state(1000);
18
+ let items = $state<TestItem[]>([]);
19
+ let results = $state<BenchmarkResult[]>([]);
20
+ let isRunning = $state(false);
21
+ let currentTest = $state('');
22
+ let filterValue = $state(500);
23
+
24
+ // Derived state - this is what we want to benchmark
25
+ let filteredItems = $derived(items.filter(item => item.value > filterValue));
26
+ let activeItems = $derived(items.filter(item => item.active));
27
+ let totalValue = $derived(items.reduce((sum, item) => sum + item.value, 0));
28
+ let groupedByCategory = $derived(() => {
29
+ const groups = new Map<string, TestItem[]>();
30
+ for (const item of items) {
31
+ const existing = groups.get(item.category) || [];
32
+ existing.push(item);
33
+ groups.set(item.category, existing);
34
+ }
35
+ return groups;
36
+ });
37
+
38
+ function log(message: string, data?: any) {
39
+ const timestamp = new Date().toISOString().split('T')[1].slice(0, -1);
40
+ if (data !== undefined) {
41
+ console.log(`%c[${timestamp}] ${message}`, 'color: #2196F3;', data);
42
+ } else {
43
+ console.log(`%c[${timestamp}] ${message}`, 'color: #2196F3;');
44
+ }
45
+ }
46
+
47
+ /** Wait for Svelte to finish updating the DOM */
48
+ async function waitForRender(): Promise<void> {
49
+ await tick(); // Wait for Svelte's microtask queue
50
+ return new Promise(resolve => {
51
+ requestAnimationFrame(() => {
52
+ requestAnimationFrame(() => {
53
+ resolve(); // Double rAF ensures paint is complete
54
+ });
55
+ });
56
+ });
57
+ }
58
+
59
+ /** Measure REAL time including DOM updates */
60
+ async function measureReal<T>(name: string, fn: () => T, itemCount: number): Promise<BenchmarkResult> {
61
+ const start = performance.now();
62
+
63
+ log(`[REAL] Starting: ${name}`);
64
+
65
+ // Execute the function
66
+ const result = fn();
67
+ const jsTime = performance.now() - start;
68
+
69
+ log(`[REAL] JS execution: ${formatDuration(jsTime)}`);
70
+
71
+ // Wait for Svelte + DOM + Paint
72
+ await waitForRender();
73
+
74
+ const totalTime = performance.now() - start;
75
+
76
+ log(`[REAL] Total time (including render): ${formatDuration(totalTime)}`);
77
+ log(`[REAL] Render overhead: ${formatDuration(totalTime - jsTime)}`);
78
+
79
+ return {
80
+ name: `${name} (REAL)`,
81
+ duration: totalTime,
82
+ itemCount,
83
+ opsPerSecond: (itemCount / totalTime) * 1000,
84
+ timestamp: new Date()
85
+ };
86
+ }
87
+
88
+ function clearResults() {
89
+ results = [];
90
+ items = [];
91
+ log('Results cleared');
92
+ }
93
+
94
+ // Test 1: Initial data generation
95
+ function testDataGeneration() {
96
+ currentTest = 'Data Generation';
97
+ log(`Starting: ${currentTest} with ${selectedSize} items`);
98
+
99
+ const result = runBenchmark(
100
+ `Generate ${selectedSize} items`,
101
+ () => {
102
+ items = generateTestData(selectedSize);
103
+ },
104
+ selectedSize
105
+ );
106
+
107
+ results = [...results, result];
108
+ log(`Completed: ${currentTest}`, { itemCount: items.length });
109
+ }
110
+
111
+ // Test 2: Filter operation (triggers $derived)
112
+ function testFilterOperation() {
113
+ if (items.length === 0) {
114
+ log('ERROR: No items loaded. Run data generation first.');
115
+ return;
116
+ }
117
+
118
+ currentTest = 'Filter Operation';
119
+ log(`Starting: ${currentTest}`);
120
+
121
+ const start = performance.now();
122
+
123
+ // Change filter value to trigger $derived recalculation
124
+ filterValue = Math.random() * 1000;
125
+
126
+ // Access the derived value to force computation
127
+ const count = filteredItems.length;
128
+
129
+ const duration = performance.now() - start;
130
+
131
+ const result: BenchmarkResult = {
132
+ name: `Filter items (threshold: ${filterValue.toFixed(0)})`,
133
+ duration,
134
+ itemCount: items.length,
135
+ opsPerSecond: (items.length / duration) * 1000,
136
+ timestamp: new Date()
137
+ };
138
+
139
+ results = [...results, result];
140
+ log(`Completed: ${currentTest}`, { filtered: count, total: items.length });
141
+ }
142
+
143
+ // Test 3: Update single item
144
+ function testSingleUpdate() {
145
+ if (items.length === 0) {
146
+ log('ERROR: No items loaded. Run data generation first.');
147
+ return;
148
+ }
149
+
150
+ currentTest = 'Single Item Update';
151
+ log(`Starting: ${currentTest}`);
152
+
153
+ const result = runBenchmark(
154
+ 'Update single item',
155
+ () => {
156
+ const index = Math.floor(Math.random() * items.length);
157
+ items[index] = { ...items[index], value: Math.random() * 1000 };
158
+ },
159
+ 1
160
+ );
161
+
162
+ results = [...results, result];
163
+ log(`Completed: ${currentTest}`);
164
+ }
165
+
166
+ // Test 4: Bulk update (update all items)
167
+ function testBulkUpdate() {
168
+ if (items.length === 0) {
169
+ log('ERROR: No items loaded. Run data generation first.');
170
+ return;
171
+ }
172
+
173
+ currentTest = 'Bulk Update';
174
+ log(`Starting: ${currentTest} for ${items.length} items`);
175
+
176
+ const result = runBenchmark(
177
+ `Bulk update ${items.length} items`,
178
+ () => {
179
+ items = items.map(item => ({
180
+ ...item,
181
+ value: item.value * 1.1,
182
+ active: !item.active
183
+ }));
184
+ },
185
+ items.length
186
+ );
187
+
188
+ results = [...results, result];
189
+ log(`Completed: ${currentTest}`);
190
+ }
191
+
192
+ // Test 5: Array push operations
193
+ function testArrayPush() {
194
+ currentTest = 'Array Push';
195
+ log(`Starting: ${currentTest}`);
196
+
197
+ const pushCount = 1000;
198
+ const result = runBenchmark(
199
+ `Push ${pushCount} items`,
200
+ () => {
201
+ for (let i = 0; i < pushCount; i++) {
202
+ items = [...items, {
203
+ id: items.length,
204
+ name: `New Item ${items.length}`,
205
+ value: Math.random() * 1000,
206
+ category: 'NEW',
207
+ active: true,
208
+ data: [1, 2, 3]
209
+ }];
210
+ }
211
+ },
212
+ pushCount
213
+ );
214
+
215
+ results = [...results, result];
216
+ log(`Completed: ${currentTest}`, { totalItems: items.length });
217
+ }
218
+
219
+ // Test 6: Derived with grouping (heavy operation)
220
+ function testGroupingDerived() {
221
+ if (items.length === 0) {
222
+ log('ERROR: No items loaded. Run data generation first.');
223
+ return;
224
+ }
225
+
226
+ currentTest = 'Grouping Derived';
227
+ log(`Starting: ${currentTest}`);
228
+
229
+ const start = performance.now();
230
+
231
+ // Access the grouped derived to force computation
232
+ const groups = groupedByCategory();
233
+ const groupCount = groups.size;
234
+
235
+ const duration = performance.now() - start;
236
+
237
+ const result: BenchmarkResult = {
238
+ name: `Group ${items.length} items into categories`,
239
+ duration,
240
+ itemCount: items.length,
241
+ opsPerSecond: (items.length / duration) * 1000,
242
+ timestamp: new Date()
243
+ };
244
+
245
+ results = [...results, result];
246
+ log(`Completed: ${currentTest}`, { groups: groupCount });
247
+ }
248
+
249
+ // Test 7: Multiple derived access (simulates real component)
250
+ function testMultipleDerivedAccess() {
251
+ if (items.length === 0) {
252
+ log('ERROR: No items loaded. Run data generation first.');
253
+ return;
254
+ }
255
+
256
+ currentTest = 'Multiple Derived Access';
257
+ log(`Starting: ${currentTest}`);
258
+
259
+ const iterations = 100;
260
+ const start = performance.now();
261
+
262
+ for (let i = 0; i < iterations; i++) {
263
+ // Access multiple derived values (like a component would during render)
264
+ const _f = filteredItems.length;
265
+ const _a = activeItems.length;
266
+ const _t = totalValue;
267
+ const _g = groupedByCategory().size;
268
+ }
269
+
270
+ const duration = performance.now() - start;
271
+
272
+ const result: BenchmarkResult = {
273
+ name: `Access 4 derived values ${iterations}x`,
274
+ duration,
275
+ itemCount: iterations * 4,
276
+ opsPerSecond: ((iterations * 4) / duration) * 1000,
277
+ timestamp: new Date()
278
+ };
279
+
280
+ results = [...results, result];
281
+ log(`Completed: ${currentTest}`);
282
+ }
283
+
284
+ // ============================================
285
+ // REAL TIME TESTS (including DOM updates)
286
+ // ============================================
287
+
288
+ // Test R1: Generate data and wait for render
289
+ async function testRealDataGeneration() {
290
+ currentTest = 'REAL: Data Generation + Render';
291
+ const result = await measureReal(
292
+ `Generate ${selectedSize} items + render`,
293
+ () => {
294
+ items = generateTestData(selectedSize);
295
+ },
296
+ selectedSize
297
+ );
298
+ results = [...results, result];
299
+ }
300
+
301
+ // Test R2: Bulk update and wait for render
302
+ async function testRealBulkUpdate() {
303
+ if (items.length === 0) {
304
+ log('ERROR: No items loaded.');
305
+ return;
306
+ }
307
+ currentTest = 'REAL: Bulk Update + Render';
308
+ const result = await measureReal(
309
+ `Bulk update ${items.length} items + render`,
310
+ () => {
311
+ items = items.map(item => ({
312
+ ...item,
313
+ value: item.value * 1.1,
314
+ active: !item.active
315
+ }));
316
+ },
317
+ items.length
318
+ );
319
+ results = [...results, result];
320
+ }
321
+
322
+ // Test R3: Filter change and wait for render
323
+ async function testRealFilterChange() {
324
+ if (items.length === 0) {
325
+ log('ERROR: No items loaded.');
326
+ return;
327
+ }
328
+ currentTest = 'REAL: Filter Change + Render';
329
+ const result = await measureReal(
330
+ 'Filter change + render',
331
+ () => {
332
+ filterValue = Math.random() * 1000;
333
+ // Force access to trigger derived
334
+ const _ = filteredItems.length;
335
+ },
336
+ items.length
337
+ );
338
+ results = [...results, result];
339
+ }
340
+
341
+ // Test R4: Array push (1000 individual reactive updates) - THE SLOW ONE
342
+ async function testRealArrayPush() {
343
+ currentTest = 'REAL: Array Push (1000 individual updates)';
344
+ const pushCount = 1000;
345
+
346
+ const result = await measureReal(
347
+ `Push ${pushCount} items individually + render`,
348
+ () => {
349
+ for (let i = 0; i < pushCount; i++) {
350
+ items = [...items, {
351
+ id: items.length,
352
+ name: `New Item ${items.length}`,
353
+ value: Math.random() * 1000,
354
+ category: 'NEW',
355
+ active: true,
356
+ data: [1, 2, 3]
357
+ }];
358
+ }
359
+ },
360
+ pushCount
361
+ );
362
+ results = [...results, result];
363
+ }
364
+
365
+ // Run all tests
366
+ async function runAllTests() {
367
+ isRunning = true;
368
+ results = [];
369
+ items = [];
370
+
371
+ log('=== STARTING FULL BENCHMARK SUITE ===');
372
+ log(`Data size: ${selectedSize} items`);
373
+ log(`Environment: ${import.meta.env.DEV ? 'DEVELOPMENT' : 'PRODUCTION'}`);
374
+ log(`User Agent: ${navigator.userAgent}`);
375
+
376
+ // Sync tests (JS only)
377
+ const syncTests = [
378
+ testDataGeneration,
379
+ testFilterOperation,
380
+ testSingleUpdate,
381
+ testBulkUpdate,
382
+ testGroupingDerived,
383
+ testMultipleDerivedAccess,
384
+ testArrayPush,
385
+ ];
386
+
387
+ log('--- Running JS-only tests ---');
388
+ for (const test of syncTests) {
389
+ await new Promise(resolve => setTimeout(resolve, 100));
390
+ test();
391
+ }
392
+
393
+ // Reset for real tests
394
+ items = [];
395
+ await waitForRender();
396
+
397
+ log('--- Running REAL tests (including render) ---');
398
+
399
+ // Async tests (including render)
400
+ await new Promise(resolve => setTimeout(resolve, 200));
401
+ await testRealDataGeneration();
402
+
403
+ await new Promise(resolve => setTimeout(resolve, 200));
404
+ await testRealBulkUpdate();
405
+
406
+ await new Promise(resolve => setTimeout(resolve, 200));
407
+ await testRealFilterChange();
408
+
409
+ log('=== BENCHMARK SUITE COMPLETED ===');
410
+ logSummary();
411
+
412
+ isRunning = false;
413
+ currentTest = '';
414
+ }
415
+
416
+ // Run only REAL tests (including the slow array push)
417
+ async function runRealTests() {
418
+ isRunning = true;
419
+ results = [];
420
+ items = [];
421
+
422
+ log('=== STARTING REAL-TIME BENCHMARK ===');
423
+ log(`Data size: ${selectedSize} items`);
424
+ log(`Environment: ${import.meta.env.DEV ? 'DEVELOPMENT' : 'PRODUCTION'}`);
425
+
426
+ await testRealDataGeneration();
427
+ await new Promise(resolve => setTimeout(resolve, 300));
428
+
429
+ await testRealBulkUpdate();
430
+ await new Promise(resolve => setTimeout(resolve, 300));
431
+
432
+ await testRealFilterChange();
433
+ await new Promise(resolve => setTimeout(resolve, 300));
434
+
435
+ // Reset and test array push
436
+ items = [];
437
+ await waitForRender();
438
+ await new Promise(resolve => setTimeout(resolve, 300));
439
+
440
+ await testRealArrayPush();
441
+
442
+ log('=== REAL-TIME BENCHMARK COMPLETED ===');
443
+ logSummary();
444
+
445
+ isRunning = false;
446
+ currentTest = '';
447
+ }
448
+
449
+ function logSummary() {
450
+ console.log('%c\n=== BENCHMARK SUMMARY ===', 'color: #4CAF50; font-weight: bold; font-size: 14px;');
451
+
452
+ const totalDuration = results.reduce((sum, r) => sum + r.duration, 0);
453
+
454
+ console.table(results.map(r => ({
455
+ Test: r.name,
456
+ Duration: formatDuration(r.duration),
457
+ Items: r.itemCount,
458
+ 'Ops/sec': r.opsPerSecond > 1000
459
+ ? `${(r.opsPerSecond / 1000).toFixed(1)}K`
460
+ : r.opsPerSecond.toFixed(1)
461
+ })));
462
+
463
+ console.log(`%cTotal time: ${formatDuration(totalDuration)}`, 'color: #FF9800; font-weight: bold;');
464
+ }
465
+ </script>
466
+
467
+ <div class="benchmark-container p-4">
468
+ <div class="card">
469
+ <div class="card-header bg-primary text-white">
470
+ <h5 class="mb-0">
471
+ <i class="bi bi-speedometer2 me-2"></i>
472
+ Svelte Reactivity Benchmark
473
+ </h5>
474
+ </div>
475
+
476
+ <div class="card-body">
477
+ <!-- Configuration -->
478
+ <div class="row mb-4">
479
+ <div class="col-md-6">
480
+ <label class="form-label fw-bold">Data Size</label>
481
+ <div class="btn-group w-100" role="group">
482
+ {#each DATA_SIZES as size}
483
+ <button
484
+ type="button"
485
+ class="btn {selectedSize === size ? 'btn-primary' : 'btn-outline-primary'}"
486
+ onclick={() => selectedSize = size}
487
+ disabled={isRunning}
488
+ >
489
+ {size.toLocaleString()}
490
+ </button>
491
+ {/each}
492
+ </div>
493
+ </div>
494
+ <div class="col-md-6">
495
+ <label class="form-label fw-bold">Environment</label>
496
+ <div class="alert alert-info py-2 mb-0">
497
+ <strong>{import.meta.env.DEV ? '🔧 DEVELOPMENT' : '🚀 PRODUCTION'}</strong>
498
+ <br>
499
+ <small class="text-muted">Items loaded: {items.length.toLocaleString()}</small>
500
+ </div>
501
+ </div>
502
+ </div>
503
+
504
+ <!-- Test Buttons -->
505
+ <div class="row g-2 mb-4">
506
+ <div class="col-12">
507
+ <label class="form-label fw-bold">Individual Tests</label>
508
+ </div>
509
+ <div class="col-auto">
510
+ <button class="btn btn-outline-secondary" onclick={testDataGeneration} disabled={isRunning}>
511
+ 1. Generate Data
512
+ </button>
513
+ </div>
514
+ <div class="col-auto">
515
+ <button class="btn btn-outline-secondary" onclick={testFilterOperation} disabled={isRunning || items.length === 0}>
516
+ 2. Filter
517
+ </button>
518
+ </div>
519
+ <div class="col-auto">
520
+ <button class="btn btn-outline-secondary" onclick={testSingleUpdate} disabled={isRunning || items.length === 0}>
521
+ 3. Single Update
522
+ </button>
523
+ </div>
524
+ <div class="col-auto">
525
+ <button class="btn btn-outline-secondary" onclick={testBulkUpdate} disabled={isRunning || items.length === 0}>
526
+ 4. Bulk Update
527
+ </button>
528
+ </div>
529
+ <div class="col-auto">
530
+ <button class="btn btn-outline-secondary" onclick={testGroupingDerived} disabled={isRunning || items.length === 0}>
531
+ 5. Grouping
532
+ </button>
533
+ </div>
534
+ <div class="col-auto">
535
+ <button class="btn btn-outline-secondary" onclick={testMultipleDerivedAccess} disabled={isRunning || items.length === 0}>
536
+ 6. Multi-Derived
537
+ </button>
538
+ </div>
539
+ <div class="col-auto">
540
+ <button class="btn btn-outline-secondary" onclick={testArrayPush} disabled={isRunning}>
541
+ 7. Array Push
542
+ </button>
543
+ </div>
544
+ </div>
545
+
546
+ <!-- Run All -->
547
+ <div class="d-flex gap-2 mb-4">
548
+ <button
549
+ class="btn btn-success btn-lg flex-grow-1"
550
+ onclick={runAllTests}
551
+ disabled={isRunning}
552
+ >
553
+ {#if isRunning}
554
+ <span class="spinner-border spinner-border-sm me-2" role="status"></span>
555
+ Running: {currentTest}...
556
+ {:else}
557
+ <i class="bi bi-play-fill me-2"></i>
558
+ Run All Tests
559
+ {/if}
560
+ </button>
561
+ <button
562
+ class="btn btn-warning btn-lg flex-grow-1"
563
+ onclick={runRealTests}
564
+ disabled={isRunning}
565
+ >
566
+ <i class="bi bi-stopwatch me-2"></i>
567
+ Run REAL Tests
568
+ </button>
569
+ <button class="btn btn-outline-danger" onclick={clearResults} disabled={isRunning}>
570
+ <i class="bi bi-trash"></i>
571
+ </button>
572
+ </div>
573
+
574
+ <!-- Results -->
575
+ {#if results.length > 0}
576
+ <div class="table-responsive">
577
+ <table class="table table-sm table-striped">
578
+ <thead class="table-dark">
579
+ <tr>
580
+ <th>#</th>
581
+ <th>Test</th>
582
+ <th class="text-end">Duration</th>
583
+ <th class="text-end">Items</th>
584
+ <th class="text-end">Ops/sec</th>
585
+ </tr>
586
+ </thead>
587
+ <tbody>
588
+ {#each results as result, i}
589
+ <tr class={result.duration > 1000 ? 'table-danger' : result.duration > 100 ? 'table-warning' : ''}>
590
+ <td>{i + 1}</td>
591
+ <td>{result.name}</td>
592
+ <td class="text-end font-monospace">
593
+ {formatDuration(result.duration)}
594
+ </td>
595
+ <td class="text-end">{result.itemCount.toLocaleString()}</td>
596
+ <td class="text-end font-monospace">
597
+ {result.opsPerSecond > 1000
598
+ ? `${(result.opsPerSecond / 1000).toFixed(1)}K`
599
+ : result.opsPerSecond.toFixed(1)}
600
+ </td>
601
+ </tr>
602
+ {/each}
603
+ </tbody>
604
+ <tfoot class="table-light">
605
+ <tr class="fw-bold">
606
+ <td colspan="2">Total</td>
607
+ <td class="text-end font-monospace">
608
+ {formatDuration(results.reduce((sum, r) => sum + r.duration, 0))}
609
+ </td>
610
+ <td colspan="2"></td>
611
+ </tr>
612
+ </tfoot>
613
+ </table>
614
+ </div>
615
+ {:else}
616
+ <div class="text-center text-muted py-4">
617
+ <i class="bi bi-bar-chart" style="font-size: 3rem;"></i>
618
+ <p class="mt-2">Run tests to see results</p>
619
+ <p class="small">Check browser console (F12) for detailed logs</p>
620
+ </div>
621
+ {/if}
622
+
623
+ <!-- Current State Display -->
624
+ {#if items.length > 0}
625
+ <div class="mt-4 p-3 bg-light rounded">
626
+ <h6 class="mb-2">Current Derived State:</h6>
627
+ <div class="row text-center">
628
+ <div class="col">
629
+ <div class="fw-bold">{filteredItems.length}</div>
630
+ <small class="text-muted">Filtered</small>
631
+ </div>
632
+ <div class="col">
633
+ <div class="fw-bold">{activeItems.length}</div>
634
+ <small class="text-muted">Active</small>
635
+ </div>
636
+ <div class="col">
637
+ <div class="fw-bold">{totalValue.toFixed(0)}</div>
638
+ <small class="text-muted">Total Value</small>
639
+ </div>
640
+ <div class="col">
641
+ <div class="fw-bold">{groupedByCategory().size}</div>
642
+ <small class="text-muted">Groups</small>
643
+ </div>
644
+ </div>
645
+ </div>
646
+ {/if}
647
+ </div>
648
+
649
+ <div class="card-footer text-muted small">
650
+ <i class="bi bi-info-circle me-1"></i>
651
+ Open browser console (F12) for detailed benchmark logs.
652
+ Red rows = &gt;1s, Yellow rows = &gt;100ms
653
+ </div>
654
+ </div>
655
+ </div>
656
+
657
+ <style>
658
+ .benchmark-container {
659
+ max-width: 900px;
660
+ margin: 0 auto;
661
+ }
662
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const Benchmark: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Benchmark = ReturnType<typeof Benchmark>;
3
+ export default Benchmark;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Benchmark utilities for measuring Svelte reactivity performance
3
+ */
4
+ export interface BenchmarkResult {
5
+ name: string;
6
+ duration: number;
7
+ itemCount: number;
8
+ opsPerSecond: number;
9
+ timestamp: Date;
10
+ }
11
+ export interface TestItem {
12
+ id: number;
13
+ name: string;
14
+ value: number;
15
+ category: string;
16
+ active: boolean;
17
+ data: number[];
18
+ }
19
+ /**
20
+ * Generate test data array
21
+ */
22
+ export declare function generateTestData(count: number): TestItem[];
23
+ /**
24
+ * Measure execution time of a function
25
+ */
26
+ export declare function measure<T>(fn: () => T): {
27
+ result: T;
28
+ duration: number;
29
+ };
30
+ /**
31
+ * Measure async execution time
32
+ */
33
+ export declare function measureAsync<T>(fn: () => Promise<T>): Promise<{
34
+ result: T;
35
+ duration: number;
36
+ }>;
37
+ /**
38
+ * Format duration for display
39
+ */
40
+ export declare function formatDuration(ms: number): string;
41
+ /**
42
+ * Create a detailed log entry
43
+ */
44
+ export declare function logBenchmark(result: BenchmarkResult): void;
45
+ /**
46
+ * Run a benchmark and return result
47
+ */
48
+ export declare function runBenchmark(name: string, fn: () => void, itemCount: number): BenchmarkResult;