@c15t/dev-tools 2.0.0-rc.2 → 2.0.0-rc.4

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 (52) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/components/panel.d.ts +1 -0
  3. package/dist/components/panel.d.ts.map +1 -1
  4. package/dist/components/tabs.d.ts.map +1 -1
  5. package/dist/components/ui.d.ts +8 -0
  6. package/dist/components/ui.d.ts.map +1 -1
  7. package/dist/core/debug-bundle.d.ts +14 -0
  8. package/dist/core/debug-bundle.d.ts.map +1 -0
  9. package/dist/core/devtools.d.ts.map +1 -1
  10. package/dist/core/override-storage.d.ts +7 -0
  11. package/dist/core/override-storage.d.ts.map +1 -0
  12. package/dist/core/panel-renderer.d.ts +5 -0
  13. package/dist/core/panel-renderer.d.ts.map +1 -1
  14. package/dist/core/state-manager.d.ts +1 -1
  15. package/dist/core/state-manager.d.ts.map +1 -1
  16. package/dist/core/store-connector.d.ts +20 -0
  17. package/dist/core/store-connector.d.ts.map +1 -1
  18. package/dist/core/store-instrumentation.d.ts +13 -0
  19. package/dist/core/store-instrumentation.d.ts.map +1 -0
  20. package/dist/index.cjs +2469 -845
  21. package/dist/index.js +2472 -848
  22. package/dist/panels/actions.d.ts +1 -0
  23. package/dist/panels/actions.d.ts.map +1 -1
  24. package/dist/panels/consents.d.ts.map +1 -1
  25. package/dist/panels/dom-scanner.d.ts.map +1 -1
  26. package/dist/panels/events.d.ts.map +1 -1
  27. package/dist/panels/iab.d.ts +6 -0
  28. package/dist/panels/iab.d.ts.map +1 -1
  29. package/dist/panels/location.d.ts +9 -6
  30. package/dist/panels/location.d.ts.map +1 -1
  31. package/dist/panels/scripts.d.ts +2 -0
  32. package/dist/panels/scripts.d.ts.map +1 -1
  33. package/dist/react.cjs +2392 -752
  34. package/dist/react.js +2376 -736
  35. package/dist/tanstack.cjs +2197 -555
  36. package/dist/tanstack.js +2195 -553
  37. package/dist/utils/preference-trigger.d.ts +2 -2
  38. package/dist/utils/preference-trigger.d.ts.map +1 -1
  39. package/dist/version.d.ts +2 -0
  40. package/dist/version.d.ts.map +1 -0
  41. package/package.json +16 -14
  42. package/tsconfig.json +9 -1
  43. package/dist/__tests__/components/ui.test.d.ts +0 -2
  44. package/dist/__tests__/components/ui.test.d.ts.map +0 -1
  45. package/dist/__tests__/core/renderer.test.d.ts +0 -2
  46. package/dist/__tests__/core/renderer.test.d.ts.map +0 -1
  47. package/dist/__tests__/core/reset-consents.test.d.ts +0 -2
  48. package/dist/__tests__/core/reset-consents.test.d.ts.map +0 -1
  49. package/dist/__tests__/core/state-manager.test.d.ts +0 -2
  50. package/dist/__tests__/core/state-manager.test.d.ts.map +0 -1
  51. package/dist/__tests__/panels/dom-scanner.test.d.ts +0 -2
  52. package/dist/__tests__/panels/dom-scanner.test.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -260,21 +260,21 @@ var __webpack_modules__ = {
260
260
  module.id,
261
261
  `.toggle-bPZtik {
262
262
  border-radius: var(--c15t-radius-full, 9999px);
263
- background-color: var(--c15t-switch-track, #ccc);
263
+ background-color: var(--c15t-switch-track, #d9d9d9);
264
264
  cursor: pointer;
265
- width: 36px;
266
- height: 20px;
267
- transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
265
+ width: 2rem;
266
+ height: 1.25rem;
267
+ transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), box-shadow var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
268
268
  border: none;
269
269
  align-items: center;
270
- padding: 0;
270
+ padding: .125rem;
271
271
  display: inline-flex;
272
272
  position: relative;
273
273
  }
274
274
 
275
275
  .toggle-bPZtik:focus-visible {
276
- outline: 2px solid var(--c15t-primary, #335cff);
277
- outline-offset: 2px;
276
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
277
+ outline: none;
278
278
  }
279
279
 
280
280
  .toggleActive-Ldlasg {
@@ -284,16 +284,16 @@ var __webpack_modules__ = {
284
284
  .toggleThumb-hjGfoX {
285
285
  border-radius: var(--c15t-radius-full, 9999px);
286
286
  background-color: var(--c15t-switch-thumb, #fff);
287
- width: 16px;
288
- height: 16px;
289
- transition: transform var(--c15t-duration-fast, .1s) var(--c15t-easing-spring, cubic-bezier(.34, 1.56, .64, 1));
287
+ width: .75rem;
288
+ height: .75rem;
289
+ box-shadow: 0 0 0 1px var(--c15t-border, #e3e3e3);
290
+ transition: transform var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
290
291
  position: absolute;
291
292
  left: 2px;
292
- box-shadow: 0 1px 2px #0003;
293
293
  }
294
294
 
295
295
  .toggleActive-Ldlasg .toggleThumb-hjGfoX {
296
- transform: translateX(16px);
296
+ transform: translateX(1rem);
297
297
  }
298
298
 
299
299
  .toggle-bPZtik:disabled, .toggleDisabled-ZcD8nZ {
@@ -306,13 +306,14 @@ var __webpack_modules__ = {
306
306
  }
307
307
 
308
308
  .badge-yA0giZ {
309
- border-radius: var(--c15t-radius-sm, .25rem);
309
+ border-radius: var(--c15t-radius-full, 9999px);
310
310
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
311
311
  font-weight: var(--c15t-font-weight-medium, 500);
312
+ line-height: var(--c15t-line-height-tight, 1.25);
312
313
  white-space: nowrap;
314
+ justify-content: center;
313
315
  align-items: center;
314
- padding: 2px 6px;
315
- line-height: 1;
316
+ padding: .1875rem .4375rem;
316
317
  display: inline-flex;
317
318
  }
318
319
 
@@ -345,38 +346,49 @@ var __webpack_modules__ = {
345
346
  justify-content: center;
346
347
  align-items: center;
347
348
  gap: var(--c15t-space-xs, .25rem);
348
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
349
- border: 1px solid var(--c15t-border, #e3e3e3);
349
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
350
350
  border-radius: var(--c15t-radius-md, .5rem);
351
- background-color: var(--c15t-surface, #fff);
351
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
352
+ min-height: 2rem;
352
353
  color: var(--c15t-text, #171717);
353
- font-family: inherit;
354
- font-size: var(--c15t-devtools-font-size-xs, .75rem);
354
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
355
+ font-size: var(--c15t-font-size-sm, .875rem);
355
356
  font-weight: var(--c15t-font-weight-medium, 500);
357
+ line-height: var(--c15t-line-height-tight, 1.25);
358
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
356
359
  cursor: pointer;
357
- transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
360
+ transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), box-shadow var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
361
+ padding: .375rem .625rem;
358
362
  display: inline-flex;
359
363
  }
360
364
 
361
365
  .btn-evRVlh:hover {
362
- background-color: var(--c15t-surface-hover, #f7f7f7);
366
+ background-color: var(--c15t-devtools-surface-subtle, #f7f7f7);
363
367
  border-color: var(--c15t-border-hover, #c9c9c9);
368
+ box-shadow: var(--c15t-shadow-md, 0 4px 12px #00000014);
364
369
  }
365
370
 
366
371
  .btn-evRVlh:focus-visible {
367
- outline: 2px solid var(--c15t-primary, #335cff);
368
- outline-offset: 1px;
372
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d), 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
373
+ outline: none;
374
+ }
375
+
376
+ .btn-evRVlh:active {
377
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
378
+ transform: scale(.98);
369
379
  }
370
380
 
371
381
  .btn-evRVlh:disabled {
372
382
  opacity: .5;
373
383
  cursor: not-allowed;
384
+ box-shadow: none;
374
385
  }
375
386
 
376
387
  .btnPrimary-dA6nqY {
377
388
  background-color: var(--c15t-primary, #335cff);
378
389
  border-color: var(--c15t-primary, #335cff);
379
390
  color: var(--c15t-text-on-primary, #fff);
391
+ box-shadow: none;
380
392
  }
381
393
 
382
394
  .btnPrimary-dA6nqY:hover {
@@ -388,6 +400,7 @@ var __webpack_modules__ = {
388
400
  background-color: var(--c15t-devtools-badge-error, #ef4343);
389
401
  border-color: var(--c15t-devtools-badge-error, #ef4343);
390
402
  color: var(--c15t-text-on-primary, #fff);
403
+ box-shadow: none;
391
404
  }
392
405
 
393
406
  .btnDanger-eDnqOX:hover {
@@ -396,8 +409,10 @@ var __webpack_modules__ = {
396
409
  }
397
410
 
398
411
  .btnSmall-TjXoqZ {
399
- padding: 2px var(--c15t-space-xs, .25rem);
400
- font-size: 10px;
412
+ min-height: 1.75rem;
413
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
414
+ border-radius: var(--c15t-radius-sm, .375rem);
415
+ padding: .25rem .5rem;
401
416
  }
402
417
 
403
418
  .btnIcon-fiYQAh {
@@ -407,19 +422,22 @@ var __webpack_modules__ = {
407
422
  }
408
423
 
409
424
  .input-IeTcCs {
410
- width: 100%;
411
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
412
- border: 1px solid var(--c15t-border, #e3e3e3);
425
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
413
426
  border-radius: var(--c15t-radius-md, .5rem);
414
- background-color: var(--c15t-surface, #fff);
427
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
428
+ width: 100%;
429
+ min-height: 2rem;
415
430
  color: var(--c15t-text, #171717);
416
- font-family: inherit;
417
- font-size: var(--c15t-font-size-sm, .875rem);
418
- transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
431
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
432
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
433
+ line-height: var(--c15t-line-height-tight, 1.25);
434
+ transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), box-shadow var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
435
+ padding: .375rem .625rem;
419
436
  }
420
437
 
421
438
  .input-IeTcCs:focus {
422
- border-color: var(--c15t-primary, #335cff);
439
+ border-color: var(--c15t-devtools-focus-ring, #335cff);
440
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--c15t-devtools-focus-ring, #335cff) 25%, transparent);
423
441
  outline: none;
424
442
  }
425
443
 
@@ -428,30 +446,35 @@ var __webpack_modules__ = {
428
446
  }
429
447
 
430
448
  .inputSmall-pJyXcL {
431
- padding: 2px var(--c15t-space-xs, .25rem);
449
+ min-height: 1.625rem;
432
450
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
451
+ padding: .25rem .4375rem;
433
452
  }
434
453
 
435
454
  .select-byJ1WM {
436
- width: 100%;
437
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
438
- border: 1px solid var(--c15t-border, #e3e3e3);
455
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
439
456
  border-radius: var(--c15t-radius-md, .5rem);
440
- background-color: var(--c15t-surface, #fff);
457
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
458
+ width: 100%;
459
+ min-height: 2rem;
441
460
  color: var(--c15t-text, #171717);
442
- font-family: inherit;
461
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
443
462
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
463
+ line-height: var(--c15t-line-height-tight, 1.25);
444
464
  cursor: pointer;
465
+ transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), box-shadow var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
466
+ padding: .375rem .625rem;
445
467
  }
446
468
 
447
469
  .select-byJ1WM:focus {
448
- border-color: var(--c15t-primary, #335cff);
470
+ border-color: var(--c15t-devtools-focus-ring, #335cff);
471
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--c15t-devtools-focus-ring, #335cff) 25%, transparent);
449
472
  outline: none;
450
473
  }
451
474
 
452
475
  .grid-LlrmEz {
453
476
  gap: var(--c15t-space-sm, .5rem);
454
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
477
+ padding: var(--c15t-space-md, 1rem);
455
478
  display: grid;
456
479
  }
457
480
 
@@ -464,42 +487,51 @@ var __webpack_modules__ = {
464
487
  }
465
488
 
466
489
  .gridCard-Qm5xxI {
467
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, .75rem);
468
- border: 1px solid var(--c15t-border, #e3e3e3);
469
- border-radius: var(--c15t-radius-md, .5rem);
470
- background-color: var(--c15t-surface, #fff);
471
- transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
472
490
  justify-content: space-between;
473
491
  align-items: center;
492
+ gap: var(--c15t-space-sm, .5rem);
493
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
494
+ border-radius: var(--c15t-radius-md, .5rem);
495
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
496
+ min-height: 2.75rem;
497
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
498
+ transition: border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
499
+ padding: .5625rem .75rem;
474
500
  display: flex;
475
501
  }
476
502
 
477
503
  .gridCard-Qm5xxI:hover {
478
504
  border-color: var(--c15t-border-hover, #c9c9c9);
505
+ background-color: var(--c15t-devtools-surface-subtle, #fafafa);
479
506
  }
480
507
 
481
508
  .gridCardTitle-HjXETp {
482
509
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
483
510
  font-weight: var(--c15t-font-weight-medium, 500);
484
511
  color: var(--c15t-text, #171717);
512
+ line-height: var(--c15t-line-height-tight, 1.25);
485
513
  }
486
514
 
487
515
  .listItem-XUKGIo {
488
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-md, 1rem);
489
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
490
516
  justify-content: space-between;
491
517
  align-items: center;
518
+ gap: var(--c15t-space-sm, .5rem);
519
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
520
+ border-radius: var(--c15t-radius-md, .5rem);
521
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
522
+ margin-bottom: .375rem;
523
+ padding: .625rem .75rem;
492
524
  display: flex;
493
525
  }
494
526
 
495
527
  .listItem-XUKGIo:last-child {
496
- border-bottom: none;
528
+ margin-bottom: 0;
497
529
  }
498
530
 
499
531
  .listItemContent-WDBF1N {
500
532
  flex-direction: column;
501
533
  flex: 1;
502
- gap: 2px;
534
+ gap: .1875rem;
503
535
  min-width: 0;
504
536
  display: flex;
505
537
  }
@@ -513,6 +545,7 @@ var __webpack_modules__ = {
513
545
  .listItemDescription-E6JHyZ {
514
546
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
515
547
  color: var(--c15t-text-muted, #737373);
548
+ line-height: var(--c15t-line-height-tight, 1.25);
516
549
  text-overflow: ellipsis;
517
550
  white-space: nowrap;
518
551
  overflow: hidden;
@@ -526,8 +559,8 @@ var __webpack_modules__ = {
526
559
  }
527
560
 
528
561
  .section-a197cB {
529
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
530
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
562
+ border-bottom: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
563
+ padding: .75rem 1rem;
531
564
  }
532
565
 
533
566
  .section-a197cB:last-child {
@@ -535,9 +568,10 @@ var __webpack_modules__ = {
535
568
  }
536
569
 
537
570
  .sectionHeader-Xcljcw {
538
- margin-bottom: var(--c15t-space-sm, .5rem);
539
571
  justify-content: space-between;
540
572
  align-items: center;
573
+ gap: .5rem;
574
+ margin-bottom: .625rem;
541
575
  display: flex;
542
576
  }
543
577
 
@@ -546,13 +580,60 @@ var __webpack_modules__ = {
546
580
  font-weight: var(--c15t-font-weight-semibold, 600);
547
581
  color: var(--c15t-text-muted, #737373);
548
582
  text-transform: uppercase;
549
- letter-spacing: .5px;
583
+ letter-spacing: .04em;
584
+ }
585
+
586
+ .overrideField-keNdpJ {
587
+ flex-direction: column;
588
+ gap: .3125rem;
589
+ margin-bottom: 0;
590
+ display: flex;
591
+ }
592
+
593
+ .overrideLabel-ApMoTw {
594
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
595
+ font-weight: var(--c15t-font-weight-semibold, 600);
596
+ color: var(--c15t-text-muted, #737373);
597
+ line-height: var(--c15t-line-height-tight, 1.25);
598
+ }
599
+
600
+ .overrideHint-yCfwGt {
601
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
602
+ color: var(--c15t-text-muted, #737373);
603
+ line-height: var(--c15t-line-height-tight, 1.25);
604
+ margin-top: .5rem;
605
+ }
606
+
607
+ .overrideActions-imdcn7 {
608
+ border-top: 1px dashed var(--c15t-devtools-border-strong, #e3e3e3);
609
+ justify-content: space-between;
610
+ align-items: center;
611
+ gap: .5rem;
612
+ margin-top: .625rem;
613
+ padding-top: .625rem;
614
+ display: flex;
615
+ }
616
+
617
+ .overrideActionButtons-gYOx1e {
618
+ flex-wrap: wrap;
619
+ gap: .375rem;
620
+ display: flex;
621
+ }
622
+
623
+ .overrideStatus-sty_qS {
624
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
625
+ color: var(--c15t-text-muted, #737373);
626
+ }
627
+
628
+ .overrideStatusDirty-OUdDMw {
629
+ color: var(--c15t-devtools-badge-warning, #f59f0a);
550
630
  }
551
631
 
552
632
  .infoRow-RlB_0h {
553
- padding: var(--c15t-space-xs, .25rem) 0;
554
633
  justify-content: space-between;
555
634
  align-items: center;
635
+ gap: .5rem;
636
+ padding: .25rem 0;
556
637
  display: flex;
557
638
  }
558
639
 
@@ -565,6 +646,7 @@ var __webpack_modules__ = {
565
646
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
566
647
  font-weight: var(--c15t-font-weight-medium, 500);
567
648
  color: var(--c15t-text, #171717);
649
+ font-variant-numeric: tabular-nums;
568
650
  font-family: ui-monospace, Cascadia Code, Source Code Pro, Menlo, Consolas, DejaVu Sans Mono, monospace;
569
651
  }
570
652
 
@@ -575,18 +657,27 @@ var __webpack_modules__ = {
575
657
  flex-direction: column;
576
658
  justify-content: center;
577
659
  align-items: center;
660
+ gap: .375rem;
578
661
  display: flex;
579
662
  }
580
663
 
581
664
  .emptyStateIcon-WHFkX8 {
665
+ opacity: .55;
582
666
  width: 32px;
583
667
  height: 32px;
584
- margin-bottom: var(--c15t-space-sm, .5rem);
585
- opacity: .5;
586
668
  }
587
669
 
588
670
  .emptyStateText-TaLvAJ {
589
671
  font-size: var(--c15t-font-size-sm, .875rem);
672
+ line-height: var(--c15t-line-height-normal, 1.5);
673
+ }
674
+
675
+ .disconnectedState-dOtZBG {
676
+ padding: var(--c15t-space-xl, 2rem);
677
+ text-align: center;
678
+ font-size: var(--c15t-font-size-sm, .875rem);
679
+ color: var(--c15t-text-muted, #737373);
680
+ line-height: var(--c15t-line-height-normal, 1.5);
590
681
  }
591
682
 
592
683
  @media (prefers-reduced-motion: reduce) {
@@ -641,12 +732,20 @@ var __webpack_modules__ = {
641
732
  section: "section-a197cB",
642
733
  sectionHeader: "sectionHeader-Xcljcw",
643
734
  sectionTitle: "sectionTitle-RUiFld",
735
+ overrideField: "overrideField-keNdpJ",
736
+ overrideLabel: "overrideLabel-ApMoTw",
737
+ overrideHint: "overrideHint-yCfwGt",
738
+ overrideActions: "overrideActions-imdcn7",
739
+ overrideActionButtons: "overrideActionButtons-gYOx1e",
740
+ overrideStatus: "overrideStatus-sty_qS",
741
+ overrideStatusDirty: "overrideStatusDirty-OUdDMw",
644
742
  infoRow: "infoRow-RlB_0h",
645
743
  infoLabel: "infoLabel-_pbK33",
646
744
  infoValue: "infoValue-flMl_e",
647
745
  emptyState: "emptyState-QcmzTQ",
648
746
  emptyStateIcon: "emptyStateIcon-WHFkX8",
649
- emptyStateText: "emptyStateText-TaLvAJ"
747
+ emptyStateText: "emptyStateText-TaLvAJ",
748
+ disconnectedState: "disconnectedState-dOtZBG"
650
749
  };
651
750
  const __rspack_default_export = ___CSS_LOADER_EXPORT___;
652
751
  },
@@ -675,9 +774,9 @@ var __webpack_modules__ = {
675
774
  .floatingButton-Gw8MtJ {
676
775
  width: var(--c15t-devtools-button-size, 40px);
677
776
  height: var(--c15t-devtools-button-size, 40px);
678
- border: 1px solid var(--c15t-border, #e3e3e3);
777
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
679
778
  border-radius: var(--c15t-radius-full, 9999px);
680
- background-color: var(--c15t-surface, #fff);
779
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
681
780
  box-shadow: var(--c15t-shadow-lg, 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a);
682
781
  cursor: grab;
683
782
  z-index: var(--c15t-devtools-z-index, 99999);
@@ -705,13 +804,13 @@ var __webpack_modules__ = {
705
804
  }
706
805
 
707
806
  .floatingButton-Gw8MtJ:focus-visible {
708
- outline: 2px solid var(--c15t-primary, #335cff);
709
- outline-offset: 2px;
807
+ box-shadow: var(--c15t-shadow-lg, 0 8px 24px #0000001f), 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
808
+ outline: none;
710
809
  }
711
810
 
712
811
  .floatingButton-Gw8MtJ:active {
713
812
  cursor: grabbing;
714
- transform: scale(1.02);
813
+ transform: scale(.98);
715
814
  }
716
815
 
717
816
  .floatingButtonIcon-cHWefk {
@@ -752,6 +851,7 @@ var __webpack_modules__ = {
752
851
 
753
852
  .backdrop-LhVMB5 {
754
853
  background-color: var(--c15t-overlay, #00000080);
854
+ backdrop-filter: blur(1px);
755
855
  z-index: calc(var(--c15t-devtools-z-index, 99999) + 1);
756
856
  position: fixed;
757
857
  inset: 0;
@@ -760,10 +860,10 @@ var __webpack_modules__ = {
760
860
  .panel-jtWove {
761
861
  width: var(--c15t-devtools-panel-width, 480px);
762
862
  max-height: var(--c15t-devtools-panel-max-height, 560px);
763
- background-color: var(--c15t-surface, #fff);
764
- border: 1px solid var(--c15t-border, #e3e3e3);
863
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
864
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
765
865
  border-radius: var(--c15t-radius-lg, .75rem);
766
- box-shadow: var(--c15t-shadow-lg, 0 8px 24px #0000001f);
866
+ box-shadow: var(--c15t-shadow-lg, 0 10px 28px #00000029);
767
867
  z-index: calc(var(--c15t-devtools-z-index, 99999) + 2);
768
868
  flex-direction: column;
769
869
  display: flex;
@@ -796,11 +896,11 @@ var __webpack_modules__ = {
796
896
  }
797
897
 
798
898
  .header-xluoTr {
799
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
800
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
899
+ border-bottom: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
801
900
  background-color: var(--c15t-devtools-surface-muted, #f5f5f5);
802
901
  justify-content: space-between;
803
902
  align-items: center;
903
+ padding: .6875rem .875rem;
804
904
  display: flex;
805
905
  }
806
906
 
@@ -809,6 +909,7 @@ var __webpack_modules__ = {
809
909
  gap: var(--c15t-space-sm, .5rem);
810
910
  font-size: var(--c15t-font-size-sm, .875rem);
811
911
  font-weight: var(--c15t-font-weight-semibold, 600);
912
+ line-height: var(--c15t-line-height-tight, 1.25);
812
913
  color: var(--c15t-text, #171717);
813
914
  display: flex;
814
915
  }
@@ -820,9 +921,9 @@ var __webpack_modules__ = {
820
921
  }
821
922
 
822
923
  .closeButton-Yto0Nb {
823
- border-radius: var(--c15t-radius-sm, .25rem);
824
- width: 28px;
825
- height: 28px;
924
+ border-radius: var(--c15t-radius-md, .5rem);
925
+ width: 2rem;
926
+ height: 2rem;
826
927
  color: var(--c15t-text-muted, #737373);
827
928
  cursor: pointer;
828
929
  transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
@@ -835,13 +936,13 @@ var __webpack_modules__ = {
835
936
  }
836
937
 
837
938
  .closeButton-Yto0Nb:hover {
838
- background-color: var(--c15t-surface-hover, #f7f7f7);
939
+ background-color: var(--c15t-devtools-surface-subtle, #f7f7f7);
839
940
  color: var(--c15t-text, #171717);
840
941
  }
841
942
 
842
943
  .closeButton-Yto0Nb:focus-visible {
843
- outline: 2px solid var(--c15t-primary, #335cff);
844
- outline-offset: 1px;
944
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
945
+ outline: none;
845
946
  }
846
947
 
847
948
  .closeButtonIcon-fVlR1I {
@@ -849,33 +950,71 @@ var __webpack_modules__ = {
849
950
  height: 16px;
850
951
  }
851
952
 
953
+ .inlineActionButton-Ky8BmN {
954
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
955
+ border-radius: var(--c15t-radius-sm, .375rem);
956
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
957
+ min-height: 1.625rem;
958
+ color: var(--c15t-text, #171717);
959
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
960
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
961
+ font-weight: var(--c15t-font-weight-medium, 500);
962
+ line-height: var(--c15t-line-height-tight, 1.25);
963
+ cursor: pointer;
964
+ transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
965
+ justify-content: center;
966
+ align-items: center;
967
+ padding: .25rem .5rem;
968
+ display: inline-flex;
969
+ }
970
+
971
+ .inlineActionButton-Ky8BmN:hover {
972
+ background-color: var(--c15t-devtools-surface-subtle, #f7f7f7);
973
+ border-color: var(--c15t-border-hover, #c9c9c9);
974
+ }
975
+
976
+ .inlineActionButton-Ky8BmN:focus-visible {
977
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
978
+ outline: none;
979
+ }
980
+
852
981
  .content-yDMYfG {
982
+ scrollbar-gutter: stable;
853
983
  overscroll-behavior: contain;
854
984
  -webkit-overflow-scrolling: touch;
985
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
855
986
  flex: auto;
856
987
  min-height: 200px;
857
- overflow: hidden auto;
988
+ overflow: hidden scroll;
858
989
  }
859
990
 
860
991
  .footer-ESbmwQ {
861
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-md, 1rem);
862
- border-top: 1px solid var(--c15t-border, #e3e3e3);
992
+ border-top: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
863
993
  background-color: var(--c15t-devtools-surface-muted, #f5f5f5);
864
994
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
865
995
  color: var(--c15t-text-muted, #737373);
866
996
  justify-content: space-between;
867
997
  align-items: center;
998
+ gap: .5rem;
999
+ padding: .5rem .75rem;
868
1000
  display: flex;
869
1001
  }
870
1002
 
871
1003
  .footerStatus-rlb99A {
872
1004
  align-items: center;
873
- gap: var(--c15t-space-xs, .25rem);
1005
+ gap: .375rem;
1006
+ min-width: 0;
874
1007
  display: flex;
875
1008
  }
876
1009
 
1010
+ .footerMeta-Vdtxdk {
1011
+ opacity: .75;
1012
+ white-space: nowrap;
1013
+ }
1014
+
877
1015
  .statusDot-hYJoej {
878
1016
  border-radius: var(--c15t-radius-full, 9999px);
1017
+ flex-shrink: 0;
879
1018
  width: 6px;
880
1019
  height: 6px;
881
1020
  }
@@ -914,6 +1053,7 @@ var __webpack_modules__ = {
914
1053
  font-size: var(--c15t-font-size-sm, .875rem);
915
1054
  color: var(--c15t-text-muted, #737373);
916
1055
  max-width: 280px;
1056
+ line-height: var(--c15t-line-height-normal, 1.5);
917
1057
  }
918
1058
 
919
1059
  @media (prefers-reduced-motion: reduce) {
@@ -930,17 +1070,17 @@ var __webpack_modules__ = {
930
1070
  }
931
1071
 
932
1072
  .dropdownMenu-aKK18l {
933
- min-width: 200px;
934
- padding: var(--c15t-space-xs, .25rem);
935
- border: 1px solid var(--c15t-border, #e3e3e3);
1073
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
936
1074
  border-radius: var(--c15t-radius-lg, .75rem);
937
- background-color: var(--c15t-surface, #fff);
1075
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1076
+ min-width: 200px;
938
1077
  box-shadow: var(--c15t-shadow-lg, 0 8px 24px #0000001f);
939
1078
  z-index: calc(var(--c15t-devtools-z-index, 99999) + 1);
940
1079
  opacity: 0;
941
1080
  transform-origin: 0 100%;
942
1081
  pointer-events: none;
943
1082
  transition: opacity var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1)), transform var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1));
1083
+ padding: .375rem;
944
1084
  position: fixed;
945
1085
  transform: scale(.95)translateY(8px);
946
1086
  }
@@ -968,34 +1108,35 @@ var __webpack_modules__ = {
968
1108
  }
969
1109
 
970
1110
  .menuItem-kBbHRP {
971
- align-items: center;
972
- gap: var(--c15t-space-sm, .5rem);
973
- width: 100%;
974
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, .75rem);
975
1111
  border-radius: var(--c15t-radius-md, .5rem);
1112
+ width: 100%;
976
1113
  color: var(--c15t-text, #171717);
977
- font-size: var(--c15t-font-size-sm, .875rem);
1114
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
978
1115
  font-weight: var(--c15t-font-weight-medium, 500);
1116
+ line-height: var(--c15t-line-height-tight, 1.25);
979
1117
  text-align: left;
980
1118
  cursor: pointer;
981
1119
  transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
982
1120
  background: none;
983
1121
  border: none;
1122
+ align-items: center;
1123
+ gap: .625rem;
1124
+ padding: .5rem .625rem;
984
1125
  display: flex;
985
1126
  }
986
1127
 
987
1128
  .menuItem-kBbHRP:hover {
988
- background-color: var(--c15t-surface-hover, #f2f2f2);
1129
+ background-color: var(--c15t-devtools-surface-subtle, #f2f2f2);
989
1130
  }
990
1131
 
991
1132
  .menuItem-kBbHRP:focus-visible {
992
- outline: 2px solid var(--c15t-primary, #335cff);
993
- outline-offset: -2px;
1133
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1134
+ outline: none;
994
1135
  }
995
1136
 
996
1137
  .menuItemIcon-P3pP5K {
997
- width: 20px;
998
- height: 20px;
1138
+ width: 1rem;
1139
+ height: 1rem;
999
1140
  color: var(--c15t-text-muted, #737373);
1000
1141
  flex-shrink: 0;
1001
1142
  }
@@ -1008,6 +1149,7 @@ var __webpack_modules__ = {
1008
1149
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
1009
1150
  color: var(--c15t-text-muted, #737373);
1010
1151
  font-weight: var(--c15t-font-weight-normal, 400);
1152
+ margin-top: .125rem;
1011
1153
  }
1012
1154
 
1013
1155
  .menuItemContent-hBlruV {
@@ -1023,8 +1165,8 @@ var __webpack_modules__ = {
1023
1165
  .menuItemToggleTrack-gDp_f3 {
1024
1166
  background-color: var(--c15t-switch-track, #d9d9d9);
1025
1167
  border-radius: var(--c15t-radius-full, 9999px);
1026
- width: 36px;
1027
- height: 20px;
1168
+ width: 2rem;
1169
+ height: 1.25rem;
1028
1170
  transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1029
1171
  position: relative;
1030
1172
  }
@@ -1032,21 +1174,22 @@ var __webpack_modules__ = {
1032
1174
  .menuItemToggleThumb-ioqqyc {
1033
1175
  background-color: var(--c15t-switch-thumb, #fff);
1034
1176
  border-radius: var(--c15t-radius-full, 9999px);
1035
- width: 16px;
1036
- height: 16px;
1037
- box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000001a);
1177
+ width: .75rem;
1178
+ height: .75rem;
1179
+ box-shadow: 0 0 0 1px var(--c15t-border, #e3e3e3);
1038
1180
  transition: transform var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1039
1181
  position: absolute;
1040
- top: 2px;
1182
+ top: 50%;
1041
1183
  left: 2px;
1184
+ transform: translateY(-50%);
1042
1185
  }
1043
1186
 
1044
1187
  .menuItemToggleChecked-K3BPtk .menuItemToggleTrack-gDp_f3 {
1045
- background-color: var(--c15t-switch-track-checked, #335cff);
1188
+ background-color: var(--c15t-switch-track-active, #335cff);
1046
1189
  }
1047
1190
 
1048
1191
  .menuItemToggleChecked-K3BPtk .menuItemToggleThumb-ioqqyc {
1049
- transform: translateX(16px);
1192
+ transform: translate(1rem, -50%);
1050
1193
  }
1051
1194
 
1052
1195
  .menuDivider-JIBdhU {
@@ -1082,9 +1225,11 @@ var __webpack_modules__ = {
1082
1225
  headerLogo: "headerLogo-PxJ_w1",
1083
1226
  closeButton: "closeButton-Yto0Nb",
1084
1227
  closeButtonIcon: "closeButtonIcon-fVlR1I",
1228
+ inlineActionButton: "inlineActionButton-Ky8BmN",
1085
1229
  content: "content-yDMYfG",
1086
1230
  footer: "footer-ESbmwQ",
1087
1231
  footerStatus: "footerStatus-rlb99A",
1232
+ footerMeta: "footerMeta-Vdtxdk",
1088
1233
  statusDot: "statusDot-hYJoej",
1089
1234
  statusConnected: "statusConnected-hPSUgS",
1090
1235
  statusDisconnected: "statusDisconnected-HIpcee",
@@ -1123,55 +1268,63 @@ var __webpack_modules__ = {
1123
1268
  ___CSS_LOADER_EXPORT___.push([
1124
1269
  module.id,
1125
1270
  `.tabList-IyuiBE {
1126
- gap: var(--c15t-space-xs, .25rem);
1127
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
1128
- border-bottom: 1px solid var(--c15t-border, #e3e3e3);
1129
- background-color: var(--c15t-surface, #fff);
1130
- scrollbar-width: none;
1131
- -ms-overflow-style: none;
1271
+ border-bottom: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
1272
+ background-color: var(--c15t-devtools-surface-subtle, #fafafa);
1273
+ align-items: center;
1274
+ gap: .375rem;
1275
+ padding: .75rem;
1132
1276
  display: flex;
1133
- overflow-x: auto;
1134
1277
  }
1135
1278
 
1136
- .tabList-IyuiBE::-webkit-scrollbar {
1137
- display: none;
1279
+ .tabStrip-_KrWe4 {
1280
+ align-items: center;
1281
+ gap: var(--c15t-space-xs, .25rem);
1282
+ flex: auto;
1283
+ min-width: 0;
1284
+ display: flex;
1285
+ overflow: hidden;
1138
1286
  }
1139
1287
 
1140
1288
  .tab-yfDEqg {
1141
- align-items: center;
1142
- gap: var(--c15t-space-xs, .25rem);
1143
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
1144
1289
  border-radius: var(--c15t-radius-md, .5rem);
1290
+ min-height: 1.875rem;
1145
1291
  color: var(--c15t-text-muted, #737373);
1146
- font-family: inherit;
1292
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
1147
1293
  font-size: var(--c15t-devtools-font-size-xs, .75rem);
1148
1294
  font-weight: var(--c15t-font-weight-medium, 500);
1295
+ line-height: var(--c15t-line-height-tight, 1.25);
1149
1296
  cursor: pointer;
1150
1297
  white-space: nowrap;
1151
- transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1298
+ transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), box-shadow var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1152
1299
  background-color: #0000;
1153
- border: none;
1300
+ border: 1px solid #0000;
1301
+ flex-shrink: 0;
1302
+ align-items: center;
1303
+ gap: .375rem;
1304
+ padding: .25rem .625rem;
1154
1305
  display: flex;
1155
1306
  }
1156
1307
 
1157
1308
  .tab-yfDEqg:hover {
1158
- background-color: var(--c15t-surface-hover, #f7f7f7);
1309
+ background-color: var(--c15t-devtools-surface-muted, #f7f7f7);
1159
1310
  color: var(--c15t-text, #171717);
1160
1311
  }
1161
1312
 
1162
1313
  .tab-yfDEqg:focus-visible {
1163
- outline: 2px solid var(--c15t-primary, #335cff);
1164
- outline-offset: 1px;
1314
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1315
+ outline: none;
1165
1316
  }
1166
1317
 
1167
1318
  .tabActive-r4hing {
1168
- background-color: var(--c15t-primary, #335cff);
1169
- color: var(--c15t-text-on-primary, #fff);
1319
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1320
+ border-color: var(--c15t-devtools-border-strong, #e3e3e3);
1321
+ color: var(--c15t-text, #171717);
1322
+ box-shadow: var(--c15t-shadow-sm, 0 1px 2px #0000000d);
1170
1323
  }
1171
1324
 
1172
1325
  .tabActive-r4hing:hover {
1173
- background-color: var(--c15t-primary-hover, #03f);
1174
- color: var(--c15t-text-on-primary, #fff);
1326
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1327
+ color: var(--c15t-text, #171717);
1175
1328
  }
1176
1329
 
1177
1330
  .tabIcon-U9tnu0 {
@@ -1180,6 +1333,131 @@ var __webpack_modules__ = {
1180
1333
  height: 14px;
1181
1334
  }
1182
1335
 
1336
+ .tabHidden-HBXYSd {
1337
+ display: none;
1338
+ }
1339
+
1340
+ .overflowContainer-TTw9DO {
1341
+ flex-shrink: 0;
1342
+ position: relative;
1343
+ }
1344
+
1345
+ .overflowContainerHidden-sQa_XZ {
1346
+ display: none;
1347
+ }
1348
+
1349
+ .overflowButton-tKq4FF {
1350
+ border-radius: var(--c15t-radius-md, .5rem);
1351
+ width: 1.875rem;
1352
+ height: 1.875rem;
1353
+ color: var(--c15t-text-muted, #737373);
1354
+ cursor: pointer;
1355
+ transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), border-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1356
+ background-color: #0000;
1357
+ border: 1px solid #0000;
1358
+ justify-content: center;
1359
+ align-items: center;
1360
+ padding: 0;
1361
+ display: inline-flex;
1362
+ }
1363
+
1364
+ .overflowButton-tKq4FF:hover {
1365
+ background-color: var(--c15t-devtools-surface-muted, #f7f7f7);
1366
+ color: var(--c15t-text, #171717);
1367
+ }
1368
+
1369
+ .overflowButton-tKq4FF:focus-visible {
1370
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1371
+ outline: none;
1372
+ }
1373
+
1374
+ .overflowButtonIcon-FSurfC {
1375
+ justify-content: center;
1376
+ align-items: center;
1377
+ width: 14px;
1378
+ height: 14px;
1379
+ display: inline-flex;
1380
+ }
1381
+
1382
+ .overflowMenu-TST0eZ {
1383
+ border: 1px solid var(--c15t-devtools-border-strong, #e3e3e3);
1384
+ border-radius: var(--c15t-radius-md, .5rem);
1385
+ background-color: var(--c15t-devtools-surface-elevated, #fff);
1386
+ min-width: 10rem;
1387
+ box-shadow: var(--c15t-shadow-md, 0 4px 12px #00000014);
1388
+ opacity: 0;
1389
+ transform-origin: 100% 0;
1390
+ pointer-events: none;
1391
+ z-index: 10;
1392
+ transition: opacity var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1)), transform var(--c15t-duration-fast, .1s) var(--c15t-easing-out, cubic-bezier(.215, .61, .355, 1));
1393
+ flex-direction: column;
1394
+ gap: .125rem;
1395
+ padding: .3125rem;
1396
+ display: flex;
1397
+ position: absolute;
1398
+ top: calc(100% + .375rem);
1399
+ right: 0;
1400
+ transform: translateY(-4px)scale(.98);
1401
+ }
1402
+
1403
+ .overflowMenu-TST0eZ[data-state="open"] {
1404
+ opacity: 1;
1405
+ pointer-events: auto;
1406
+ transform: translateY(0)scale(1);
1407
+ }
1408
+
1409
+ .overflowItem-y5Pz7k {
1410
+ border-radius: var(--c15t-radius-sm, .375rem);
1411
+ min-height: 1.75rem;
1412
+ color: var(--c15t-text, #171717);
1413
+ font-family: var(--c15t-font-family, system-ui, -apple-system, sans-serif);
1414
+ font-size: var(--c15t-devtools-font-size-xs, .75rem);
1415
+ font-weight: var(--c15t-font-weight-medium, 500);
1416
+ line-height: var(--c15t-line-height-tight, 1.25);
1417
+ text-align: left;
1418
+ cursor: pointer;
1419
+ white-space: nowrap;
1420
+ transition: background-color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1)), color var(--c15t-duration-fast, .1s) var(--c15t-easing, cubic-bezier(.4, 0, .2, 1));
1421
+ background-color: #0000;
1422
+ border: none;
1423
+ align-items: center;
1424
+ gap: .5rem;
1425
+ padding: .3125rem .5rem;
1426
+ display: inline-flex;
1427
+ }
1428
+
1429
+ .overflowItem-y5Pz7k:hover {
1430
+ background-color: var(--c15t-devtools-surface-subtle, #fafafa);
1431
+ }
1432
+
1433
+ .overflowItem-y5Pz7k:focus-visible {
1434
+ box-shadow: 0 0 0 2px var(--c15t-devtools-focus-ring, #335cff);
1435
+ outline: none;
1436
+ }
1437
+
1438
+ .overflowItemActive-mzVG1T {
1439
+ background-color: var(--c15t-devtools-accent-soft, #ebefff);
1440
+ color: var(--c15t-text, #171717);
1441
+ }
1442
+
1443
+ .overflowItemDisabled-dcHX3K {
1444
+ opacity: .5;
1445
+ cursor: not-allowed;
1446
+ }
1447
+
1448
+ .overflowItemIcon-fz291V {
1449
+ flex-shrink: 0;
1450
+ justify-content: center;
1451
+ align-items: center;
1452
+ width: 14px;
1453
+ height: 14px;
1454
+ display: inline-flex;
1455
+ }
1456
+
1457
+ .overflowItemHidden-k4aawi {
1458
+ display: none;
1459
+ }
1460
+
1183
1461
  .tabDisabled-lDuv5l {
1184
1462
  opacity: .5;
1185
1463
  cursor: not-allowed;
@@ -1200,7 +1478,7 @@ var __webpack_modules__ = {
1200
1478
  }
1201
1479
 
1202
1480
  @media (prefers-reduced-motion: reduce) {
1203
- .tab-yfDEqg {
1481
+ .tab-yfDEqg, .overflowButton-tKq4FF, .overflowMenu-TST0eZ, .overflowItem-y5Pz7k {
1204
1482
  transition: none;
1205
1483
  }
1206
1484
  }
@@ -1216,9 +1494,21 @@ var __webpack_modules__ = {
1216
1494
  ]);
1217
1495
  ___CSS_LOADER_EXPORT___.locals = {
1218
1496
  tabList: "tabList-IyuiBE",
1497
+ tabStrip: "tabStrip-_KrWe4",
1219
1498
  tab: "tab-yfDEqg",
1220
1499
  tabActive: "tabActive-r4hing",
1221
1500
  tabIcon: "tabIcon-U9tnu0",
1501
+ tabHidden: "tabHidden-HBXYSd",
1502
+ overflowContainer: "overflowContainer-TTw9DO",
1503
+ overflowContainerHidden: "overflowContainerHidden-sQa_XZ",
1504
+ overflowButton: "overflowButton-tKq4FF",
1505
+ overflowButtonIcon: "overflowButtonIcon-FSurfC",
1506
+ overflowMenu: "overflowMenu-TST0eZ",
1507
+ overflowItem: "overflowItem-y5Pz7k",
1508
+ overflowItemActive: "overflowItemActive-mzVG1T",
1509
+ overflowItemDisabled: "overflowItemDisabled-dcHX3K",
1510
+ overflowItemIcon: "overflowItemIcon-fz291V",
1511
+ overflowItemHidden: "overflowItemHidden-k4aawi",
1222
1512
  tabDisabled: "tabDisabled-lDuv5l",
1223
1513
  tabPanel: "tabPanel-QKO8FX",
1224
1514
  tabPanelActive: "tabPanelActive-mrNlGE"
@@ -1242,6 +1532,15 @@ var __webpack_modules__ = {
1242
1532
  --c15t-devtools-button-size: 40px;
1243
1533
  --c15t-devtools-z-index: 99999;
1244
1534
  --c15t-devtools-surface-muted: var(--c15t-surface-hover, #f7f7f7);
1535
+ --c15t-devtools-surface-subtle: #fafafa;
1536
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #fff);
1537
+ --c15t-devtools-border-strong: var(--c15t-border, #e3e3e3);
1538
+ --c15t-devtools-code-surface: #f7f7f7;
1539
+ --c15t-devtools-accent-soft: #ebefff;
1540
+ --c15t-devtools-focus-ring: var(--c15t-primary, #335cff);
1541
+ --c15t-devtools-text-muted: var(--c15t-text-muted, #737373);
1542
+ --c15t-devtools-font-size-sm: var(--c15t-font-size-sm, .875rem);
1543
+ --c15t-surface-muted: var(--c15t-devtools-surface-muted, #f7f7f7);
1245
1544
  --c15t-devtools-font-size-xs: .75rem;
1246
1545
  --c15t-devtools-badge-success: #21c45d;
1247
1546
  --c15t-devtools-badge-success-bg: #e4fbed;
@@ -1255,8 +1554,37 @@ var __webpack_modules__ = {
1255
1554
  --c15t-devtools-badge-neutral-bg: #f0f0f0;
1256
1555
  }
1257
1556
 
1557
+ :is(:global(.c15t-light), :global(.light)) {
1558
+ --c15t-devtools-surface-muted: var(--c15t-surface-hover, #f7f7f7);
1559
+ --c15t-devtools-surface-subtle: #fafafa;
1560
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #fff);
1561
+ --c15t-devtools-border-strong: var(--c15t-border, #e3e3e3);
1562
+ --c15t-devtools-code-surface: #f7f7f7;
1563
+ --c15t-devtools-accent-soft: #ebefff;
1564
+ --c15t-devtools-badge-success-bg: #e4fbed;
1565
+ --c15t-devtools-badge-error-bg: #fde7e7;
1566
+ --c15t-devtools-badge-warning-bg: #fef7dc;
1567
+ --c15t-devtools-badge-info-bg: #dcebfe;
1568
+ --c15t-devtools-badge-neutral-bg: #f0f0f0;
1569
+ }
1570
+
1571
+ @supports (color: color-mix(in srgb, white, black)) {
1572
+ :root {
1573
+ --c15t-devtools-surface-muted: color-mix(in srgb, var(--c15t-surface-hover, #f7f7f7) 85%, var(--c15t-surface, #fff));
1574
+ --c15t-devtools-surface-subtle: color-mix(in srgb, var(--c15t-surface-hover, #f7f7f7) 55%, var(--c15t-surface, #fff));
1575
+ --c15t-devtools-border-strong: color-mix(in srgb, var(--c15t-border, #e3e3e3) 80%, var(--c15t-text-muted, #737373));
1576
+ --c15t-devtools-code-surface: color-mix(in srgb, var(--c15t-surface-hover, #f7f7f7) 70%, var(--c15t-surface, #fff));
1577
+ --c15t-devtools-accent-soft: color-mix(in srgb, var(--c15t-primary, #335cff) 12%, transparent);
1578
+ }
1579
+ }
1580
+
1258
1581
  :is(:global(.c15t-dark), :global(.dark)) {
1259
1582
  --c15t-devtools-surface-muted: var(--c15t-surface-hover, #292929);
1583
+ --c15t-devtools-surface-subtle: #242424;
1584
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #1a1a1a);
1585
+ --c15t-devtools-border-strong: var(--c15t-border, #3d3d3d);
1586
+ --c15t-devtools-code-surface: #212121;
1587
+ --c15t-devtools-accent-soft: #335cff33;
1260
1588
  --c15t-devtools-badge-success-bg: #21c45d33;
1261
1589
  --c15t-devtools-badge-error-bg: #ef434333;
1262
1590
  --c15t-devtools-badge-warning-bg: #f59f0a33;
@@ -1265,8 +1593,13 @@ var __webpack_modules__ = {
1265
1593
  }
1266
1594
 
1267
1595
  @media (prefers-color-scheme: dark) {
1268
- :root {
1596
+ :global(:root:not(.light):not(.c15t-light)) {
1269
1597
  --c15t-devtools-surface-muted: var(--c15t-surface-hover, #292929);
1598
+ --c15t-devtools-surface-subtle: #242424;
1599
+ --c15t-devtools-surface-elevated: var(--c15t-surface, #1a1a1a);
1600
+ --c15t-devtools-border-strong: var(--c15t-border, #3d3d3d);
1601
+ --c15t-devtools-code-surface: #212121;
1602
+ --c15t-devtools-accent-soft: #335cff33;
1270
1603
  --c15t-devtools-badge-success-bg: #21c45d33;
1271
1604
  --c15t-devtools-badge-error-bg: #ef434333;
1272
1605
  --c15t-devtools-badge-warning-bg: #f59f0a33;
@@ -1794,7 +2127,7 @@ var __webpack_exports__ = {};
1794
2127
  type: options.type ?? 'button'
1795
2128
  });
1796
2129
  }
1797
- function span(options = {}) {
2130
+ function renderer_span(options = {}) {
1798
2131
  return createElement({
1799
2132
  ...options,
1800
2133
  tag: 'span'
@@ -1873,7 +2206,8 @@ var __webpack_exports__ = {};
1873
2206
  panel_module_options.insertStyleElement = insertStyleElement_default();
1874
2207
  injectStylesIntoStyleTag_default()(panel_module.A, panel_module_options);
1875
2208
  const styles_panel_module = panel_module.A && panel_module.A.locals ? panel_module.A.locals : void 0;
1876
- const PREFERENCE_TRIGGER_SELECTORS = '[data-c15t-trigger], [aria-label*="privacy settings"], [aria-label*="preference"]';
2209
+ const PREFERENCE_TRIGGER_SELECTORS = '[data-c15t-trigger], [aria-label*="privacy settings" i], [aria-label*="preference" i]';
2210
+ const PREVIOUS_DISPLAY_ATTR = 'data-c15t-devtools-prev-display';
1877
2211
  function detectPreferenceTrigger() {
1878
2212
  const triggers = document.querySelectorAll(PREFERENCE_TRIGGER_SELECTORS);
1879
2213
  return triggers.length > 0;
@@ -1883,11 +2217,23 @@ var __webpack_exports__ = {};
1883
2217
  }
1884
2218
  function setPreferenceTriggerVisibility(visible) {
1885
2219
  const elements = getPreferenceTriggerElements();
1886
- for (const el of elements)el.style.display = visible ? '' : 'none';
2220
+ for (const el of elements){
2221
+ if (visible) {
2222
+ const previousDisplay = el.getAttribute(PREVIOUS_DISPLAY_ATTR);
2223
+ if (null === previousDisplay) el.style.removeProperty('display');
2224
+ else {
2225
+ el.style.display = previousDisplay;
2226
+ el.removeAttribute(PREVIOUS_DISPLAY_ATTR);
2227
+ }
2228
+ continue;
2229
+ }
2230
+ if (!el.hasAttribute(PREVIOUS_DISPLAY_ATTR)) el.setAttribute(PREVIOUS_DISPLAY_ATTR, el.style.display);
2231
+ el.style.display = 'none';
2232
+ }
1887
2233
  }
1888
- function getPreferenceCenterOpener() {
2234
+ function getPreferenceCenterOpener(namespace = 'c15tStore') {
1889
2235
  const win = window;
1890
- const store = win.c15tStore;
2236
+ const store = win[namespace];
1891
2237
  if (store && 'function' == typeof store.getState) {
1892
2238
  const state = store.getState();
1893
2239
  if ('function' == typeof state.setActiveUI) return ()=>{
@@ -1896,6 +2242,7 @@ var __webpack_exports__ = {};
1896
2242
  }
1897
2243
  return null;
1898
2244
  }
2245
+ const version = '2.0.0-rc.4';
1899
2246
  const DEVTOOLS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 446 445" aria-label="c15t">
1900
2247
  <path fill="currentColor" d="M223.178.313c39.064 0 70.732 31.668 70.732 70.732-.001 39.064-31.668 70.731-70.732 70.731-12.181 0-23.642-3.079-33.649-8.502l-55.689 55.689a70.267 70.267 0 0 1 5.574 13.441h167.531c8.695-29.217 35.762-50.523 67.804-50.523 39.064 0 70.731 31.668 70.731 70.732s-31.668 70.732-70.731 70.732c-32.042 0-59.108-21.306-67.803-50.523H139.413a70.417 70.417 0 0 1-7.888 17.396l54.046 54.046c10.893-6.851 23.786-10.815 37.605-10.815 39.064 0 70.732 31.669 70.732 70.733 0 39.064-31.668 70.731-70.732 70.731s-70.732-31.667-70.732-70.731c0-10.518 2.296-20.499 6.414-29.471l-57.78-57.78c-8.972 4.117-18.952 6.414-29.47 6.414-39.063 0-70.731-31.668-70.732-70.732 0-39.064 31.669-70.732 70.733-70.732 12.18 0 23.642 3.079 33.649 8.502l55.688-55.688c-5.423-10.007-8.502-21.469-8.502-33.65 0-39.064 31.668-70.733 70.732-70.733Zm0 343.555c-16.742 0-30.314 13.572-30.314 30.314 0 16.741 13.572 30.313 30.314 30.313s30.314-13.572 30.314-30.313c0-16.742-13.572-30.314-30.314-30.314ZM71.611 192.299c-16.742 0-30.315 13.572-30.315 30.314s13.573 30.314 30.315 30.314c16.741 0 30.313-13.572 30.313-30.314 0-16.741-13.572-30.314-30.313-30.314Zm303.138 0c-16.729 0-30.294 13.551-30.315 30.275l.001.039-.001.038c.021 16.725 13.586 30.276 30.315 30.276 16.741 0 30.313-13.572 30.313-30.314 0-16.741-13.572-30.314-30.313-30.314ZM223.178 40.73c-16.742 0-30.314 13.573-30.314 30.315s13.573 30.313 30.314 30.313c16.742 0 30.313-13.572 30.314-30.313 0-16.742-13.572-30.314-30.314-30.315Z"/>
1901
2248
  </svg>`;
@@ -1976,7 +2323,7 @@ var __webpack_exports__ = {};
1976
2323
  const labelContainer = renderer_div({
1977
2324
  className: styles_panel_module.menuItemContent ?? ''
1978
2325
  });
1979
- const label = span({
2326
+ const label = renderer_span({
1980
2327
  className: styles_panel_module.menuItemLabel ?? '',
1981
2328
  text: item.label
1982
2329
  });
@@ -2098,8 +2445,13 @@ var __webpack_exports__ = {};
2098
2445
  return styles_panel_module.positionTopLeft ?? '';
2099
2446
  }
2100
2447
  }
2448
+ function formatRetryDelay(delayMs) {
2449
+ if (null === delayMs) return 'n/a';
2450
+ if (delayMs < 1000) return `${delayMs}ms`;
2451
+ return `${(delayMs / 1000).toFixed(1)}s`;
2452
+ }
2101
2453
  function createPanel(options) {
2102
- const { stateManager, storeConnector, onRenderContent, enableUnifiedMode = true } = options;
2454
+ const { stateManager, storeConnector, onRenderContent, namespace = 'c15tStore', enableUnifiedMode = true } = options;
2103
2455
  let removePortal = null;
2104
2456
  let isAnimatingOut = false;
2105
2457
  let draggable = null;
@@ -2128,7 +2480,7 @@ var __webpack_exports__ = {};
2128
2480
  return;
2129
2481
  }
2130
2482
  hasPreferenceTrigger = detectPreferenceTrigger();
2131
- const preferenceCenterOpener = getPreferenceCenterOpener();
2483
+ const preferenceCenterOpener = getPreferenceCenterOpener(namespace);
2132
2484
  useUnifiedMode = hasPreferenceTrigger && null !== preferenceCenterOpener;
2133
2485
  if (useUnifiedMode && !dropdownMenu) {
2134
2486
  dropdownMenu = createDropdownMenu({
@@ -2148,7 +2500,7 @@ var __webpack_exports__ = {};
2148
2500
  description: 'Open privacy settings',
2149
2501
  icon: PREFERENCES_ICON,
2150
2502
  onClick: ()=>{
2151
- const opener = getPreferenceCenterOpener();
2503
+ const opener = getPreferenceCenterOpener(namespace);
2152
2504
  if (opener) opener();
2153
2505
  }
2154
2506
  },
@@ -2204,6 +2556,7 @@ var __webpack_exports__ = {};
2204
2556
  let panelElement = null;
2205
2557
  let backdropElement = null;
2206
2558
  let contentContainer = null;
2559
+ let footerElement = null;
2207
2560
  function createPanelElement() {
2208
2561
  const corner = draggable?.getCorner() ?? stateManager.getState().position;
2209
2562
  const positionClass = getPositionClass(corner);
@@ -2228,7 +2581,7 @@ var __webpack_exports__ = {};
2228
2581
  }));
2229
2582
  return logoWrapper;
2230
2583
  })(),
2231
- span({
2584
+ renderer_span({
2232
2585
  text: 'c15t DevTools'
2233
2586
  })
2234
2587
  ]
@@ -2255,37 +2608,60 @@ var __webpack_exports__ = {};
2255
2608
  contentContainer = renderer_div({
2256
2609
  className: styles_panel_module.content
2257
2610
  });
2258
- const isConnected = storeConnector.isConnected();
2259
- const footer = renderer_div({
2260
- className: styles_panel_module.footer,
2261
- children: [
2262
- renderer_div({
2263
- className: styles_panel_module.footerStatus,
2264
- children: [
2265
- span({
2266
- className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
2267
- }),
2268
- span({
2269
- text: isConnected ? 'Connected' : 'Disconnected'
2270
- })
2271
- ]
2272
- }),
2273
- span({
2274
- text: 'v1.8.3'
2275
- })
2276
- ]
2611
+ footerElement = renderer_div({
2612
+ className: styles_panel_module.footer
2277
2613
  });
2614
+ updateFooter();
2278
2615
  panel.appendChild(header);
2279
2616
  panel.appendChild(contentContainer);
2280
- panel.appendChild(footer);
2281
- if (isConnected) onRenderContent(contentContainer);
2617
+ panel.appendChild(footerElement);
2618
+ if (storeConnector.isConnected()) onRenderContent(contentContainer);
2282
2619
  else renderErrorState(contentContainer);
2283
2620
  return panel;
2284
2621
  }
2285
- function renderErrorState(container) {
2286
- clearElement(container);
2287
- const errorState = renderer_div({
2288
- className: styles_panel_module.errorState,
2622
+ function updateFooter() {
2623
+ if (!footerElement) return;
2624
+ clearElement(footerElement);
2625
+ const isConnected = storeConnector.isConnected();
2626
+ const storeState = storeConnector.getState();
2627
+ const isLoading = storeState?.isLoadingConsentInfo ?? false;
2628
+ const diagnostics = storeConnector.getDiagnostics();
2629
+ const statusChildren = [
2630
+ renderer_span({
2631
+ className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
2632
+ }),
2633
+ renderer_span({
2634
+ text: isConnected ? 'Connected' : 'Disconnected'
2635
+ })
2636
+ ];
2637
+ if (isLoading) statusChildren.push(renderer_span({
2638
+ className: styles_panel_module.footerMeta,
2639
+ text: '\u00b7 Fetching /init\u2026'
2640
+ }));
2641
+ else if (!isConnected) statusChildren.push(renderer_span({
2642
+ className: styles_panel_module.footerMeta,
2643
+ text: `· ${diagnostics.namespace} · retry ${diagnostics.reconnectAttempts} · next ${formatRetryDelay(diagnostics.nextRetryInMs)}`
2644
+ }));
2645
+ footerElement.appendChild(renderer_div({
2646
+ className: styles_panel_module.footerStatus,
2647
+ children: statusChildren
2648
+ }));
2649
+ if (!isConnected) footerElement.appendChild(renderer_button({
2650
+ className: styles_panel_module.inlineActionButton,
2651
+ text: 'Retry',
2652
+ onClick: ()=>{
2653
+ storeConnector.retryConnection();
2654
+ }
2655
+ }));
2656
+ footerElement.appendChild(renderer_span({
2657
+ text: `v${version}`
2658
+ }));
2659
+ }
2660
+ function renderErrorState(container) {
2661
+ clearElement(container);
2662
+ const diagnostics = storeConnector.getDiagnostics();
2663
+ const errorState = renderer_div({
2664
+ className: styles_panel_module.errorState,
2289
2665
  children: [
2290
2666
  (()=>{
2291
2667
  const iconWrap = renderer_div({
@@ -2304,6 +2680,30 @@ var __webpack_exports__ = {};
2304
2680
  renderer_div({
2305
2681
  className: styles_panel_module.errorMessage,
2306
2682
  text: 'c15t consent manager is not initialized. Make sure you have set up the ConsentManagerProvider in your app.'
2683
+ }),
2684
+ renderer_div({
2685
+ className: styles_panel_module.errorMessage,
2686
+ style: {
2687
+ marginTop: '4px',
2688
+ fontSize: 'var(--c15t-devtools-font-size-xs)'
2689
+ },
2690
+ text: `Namespace: ${diagnostics.namespace} · Retries: ${diagnostics.reconnectAttempts} · Next retry: ${formatRetryDelay(diagnostics.nextRetryInMs)}`
2691
+ }),
2692
+ diagnostics.lastError ? renderer_div({
2693
+ className: styles_panel_module.errorMessage,
2694
+ style: {
2695
+ marginTop: '4px',
2696
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
2697
+ color: 'var(--c15t-text-muted)'
2698
+ },
2699
+ text: `Last error: ${diagnostics.lastError}`
2700
+ }) : null,
2701
+ renderer_button({
2702
+ className: styles_panel_module.inlineActionButton,
2703
+ text: 'Retry Connection',
2704
+ onClick: ()=>{
2705
+ storeConnector.retryConnection();
2706
+ }
2307
2707
  })
2308
2708
  ]
2309
2709
  });
@@ -2339,6 +2739,7 @@ var __webpack_exports__ = {};
2339
2739
  panelElement = null;
2340
2740
  }
2341
2741
  contentContainer = null;
2742
+ footerElement = null;
2342
2743
  isAnimatingOut = false;
2343
2744
  floatingButton.style.display = '';
2344
2745
  stateManager.setOpen(false);
@@ -2357,9 +2758,14 @@ var __webpack_exports__ = {};
2357
2758
  update();
2358
2759
  });
2359
2760
  const unsubscribeStore = storeConnector.subscribe(()=>{
2761
+ updateFooter();
2360
2762
  if (contentContainer) if (storeConnector.isConnected()) onRenderContent(contentContainer);
2361
2763
  else renderErrorState(contentContainer);
2362
2764
  });
2765
+ const unsubscribeDiagnostics = storeConnector.subscribeDiagnostics(()=>{
2766
+ updateFooter();
2767
+ if (contentContainer && !storeConnector.isConnected()) renderErrorState(contentContainer);
2768
+ });
2363
2769
  container.appendChild(floatingButton);
2364
2770
  removePortal = createPortal(container);
2365
2771
  return {
@@ -2369,6 +2775,7 @@ var __webpack_exports__ = {};
2369
2775
  destroy: ()=>{
2370
2776
  unsubscribeState();
2371
2777
  unsubscribeStore();
2778
+ unsubscribeDiagnostics();
2372
2779
  if (dropdownMenu) {
2373
2780
  dropdownMenu.destroy();
2374
2781
  dropdownMenu = null;
@@ -2417,6 +2824,11 @@ var __webpack_exports__ = {};
2417
2824
  const EVENTS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2418
2825
  <path d="M12 20h9"></path>
2419
2826
  <path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"></path>
2827
+ </svg>`;
2828
+ const MORE_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
2829
+ <circle cx="12" cy="5" r="1.75"></circle>
2830
+ <circle cx="12" cy="12" r="1.75"></circle>
2831
+ <circle cx="12" cy="19" r="1.75"></circle>
2420
2832
  </svg>`;
2421
2833
  const TABS = [
2422
2834
  {
@@ -2453,12 +2865,56 @@ var __webpack_exports__ = {};
2453
2865
  function createTabs(options) {
2454
2866
  const { onTabChange, disabledTabs = [] } = options;
2455
2867
  let activeTab = options.activeTab;
2868
+ let isOverflowMenuOpen = false;
2869
+ let visibleTabIds = [];
2870
+ let hiddenTabIds = [];
2456
2871
  const tabButtons = new Map();
2872
+ const overflowButtons = new Map();
2457
2873
  const tabList = renderer_div({
2458
- className: styles_tabs_module.tabList,
2874
+ className: styles_tabs_module.tabList
2875
+ });
2876
+ const tabStrip = renderer_div({
2877
+ className: styles_tabs_module.tabStrip,
2459
2878
  role: 'tablist',
2460
2879
  ariaLabel: 'DevTools tabs'
2461
2880
  });
2881
+ tabList.appendChild(tabStrip);
2882
+ const overflowMenu = renderer_div({
2883
+ className: styles_tabs_module.overflowMenu,
2884
+ role: 'menu',
2885
+ ariaLabel: 'All tabs'
2886
+ });
2887
+ overflowMenu.dataset.state = 'closed';
2888
+ const overflowButton = renderer_button({
2889
+ className: styles_tabs_module.overflowButton,
2890
+ ariaLabel: 'More tabs',
2891
+ ariaExpanded: 'false',
2892
+ onClick: ()=>toggleOverflowMenu(),
2893
+ onKeyDown: (e)=>{
2894
+ if ('ArrowDown' === e.key || 'Enter' === e.key || ' ' === e.key) {
2895
+ e.preventDefault();
2896
+ openOverflowMenu();
2897
+ focusFirstEnabledOverflowItem();
2898
+ }
2899
+ }
2900
+ });
2901
+ overflowButton.setAttribute('aria-haspopup', 'menu');
2902
+ const overflowIcon = renderer_div({
2903
+ className: styles_tabs_module.overflowButtonIcon
2904
+ });
2905
+ overflowIcon.appendChild(createSvgElement(MORE_ICON, {
2906
+ width: 14,
2907
+ height: 14
2908
+ }));
2909
+ overflowButton.appendChild(overflowIcon);
2910
+ const overflowContainer = renderer_div({
2911
+ className: styles_tabs_module.overflowContainer,
2912
+ children: [
2913
+ overflowButton,
2914
+ overflowMenu
2915
+ ]
2916
+ });
2917
+ tabList.appendChild(overflowContainer);
2462
2918
  for (const tab of TABS){
2463
2919
  const isActive = tab.id === activeTab;
2464
2920
  const isDisabled = disabledTabs.includes(tab.id);
@@ -2472,6 +2928,7 @@ var __webpack_exports__ = {};
2472
2928
  disabled: isDisabled,
2473
2929
  onClick: ()=>{
2474
2930
  if (!isDisabled) {
2931
+ closeOverflowMenu();
2475
2932
  setActiveTab(tab.id);
2476
2933
  onTabChange(tab.id);
2477
2934
  }
@@ -2488,11 +2945,188 @@ var __webpack_exports__ = {};
2488
2945
  tabButton.appendChild(iconWrapper);
2489
2946
  tabButton.appendChild(document.createTextNode(tab.label));
2490
2947
  tabButtons.set(tab.id, tabButton);
2491
- tabList.appendChild(tabButton);
2948
+ tabStrip.appendChild(tabButton);
2949
+ const overflowItem = renderer_button({
2950
+ className: `${styles_tabs_module.overflowItem} ${isActive ? styles_tabs_module.overflowItemActive : ''} ${isDisabled ? styles_tabs_module.overflowItemDisabled : ''}`,
2951
+ role: 'menuitemradio',
2952
+ ariaChecked: isActive ? 'true' : 'false',
2953
+ disabled: isDisabled,
2954
+ onClick: ()=>{
2955
+ if (!isDisabled) {
2956
+ setActiveTab(tab.id);
2957
+ onTabChange(tab.id);
2958
+ closeOverflowMenu();
2959
+ tabButtons.get(tab.id)?.focus();
2960
+ }
2961
+ },
2962
+ onKeyDown: (e)=>handleOverflowKeyDown(e, tab.id)
2963
+ });
2964
+ const overflowItemIcon = renderer_div({
2965
+ className: styles_tabs_module.overflowItemIcon
2966
+ });
2967
+ overflowItemIcon.appendChild(createSvgElement(tab.icon, {
2968
+ width: 14,
2969
+ height: 14
2970
+ }));
2971
+ overflowItem.appendChild(overflowItemIcon);
2972
+ overflowItem.appendChild(document.createTextNode(tab.label));
2973
+ overflowButtons.set(tab.id, overflowItem);
2974
+ overflowMenu.appendChild(overflowItem);
2975
+ }
2976
+ function applyActiveState(tab) {
2977
+ for (const [tabId, tabButton] of tabButtons){
2978
+ const isActive = tabId === tab;
2979
+ if (styles_tabs_module.tabActive) tabButton.classList.toggle(styles_tabs_module.tabActive, isActive);
2980
+ tabButton.setAttribute('aria-selected', isActive ? 'true' : 'false');
2981
+ tabButton.tabIndex = isActive ? 0 : -1;
2982
+ }
2983
+ for (const [tabId, overflowItem] of overflowButtons){
2984
+ const isActive = tabId === tab;
2985
+ if (styles_tabs_module.overflowItemActive) overflowItem.classList.toggle(styles_tabs_module.overflowItemActive, isActive);
2986
+ overflowItem.setAttribute('aria-checked', isActive ? 'true' : 'false');
2987
+ }
2988
+ }
2989
+ function updateVisibleTabs() {
2990
+ const allTabIds = TABS.map((t)=>t.id);
2991
+ const iabEnabled = !disabledTabs.includes('iab');
2992
+ const preferredSecondTab = iabEnabled ? 'iab' : 'consents';
2993
+ const overflowSecondTab = iabEnabled ? 'consents' : 'iab';
2994
+ const showOverflowSecondTabInStrip = activeTab === overflowSecondTab;
2995
+ const stripSecondTab = showOverflowSecondTabInStrip ? overflowSecondTab : preferredSecondTab;
2996
+ const forcedOverflowTab = showOverflowSecondTabInStrip ? preferredSecondTab : overflowSecondTab;
2997
+ const layoutTabIds = [
2998
+ 'location',
2999
+ stripSecondTab,
3000
+ "scripts",
3001
+ 'actions',
3002
+ 'events',
3003
+ forcedOverflowTab
3004
+ ];
3005
+ const forcedOverflowTabIds = new Set();
3006
+ forcedOverflowTabIds.add(forcedOverflowTab);
3007
+ for (const [index, tabId] of layoutTabIds.entries()){
3008
+ const tabButton = tabButtons.get(tabId);
3009
+ if (tabButton) tabButton.style.order = String(index);
3010
+ const overflowItem = overflowButtons.get(tabId);
3011
+ if (overflowItem) overflowItem.style.order = String(index);
3012
+ }
3013
+ for (const tabId of allTabIds){
3014
+ const tabButton = tabButtons.get(tabId);
3015
+ if (tabButton && styles_tabs_module.tabHidden) tabButton.classList.remove(styles_tabs_module.tabHidden);
3016
+ }
3017
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.remove(styles_tabs_module.overflowContainerHidden);
3018
+ const stripGap = Number.parseFloat(getComputedStyle(tabStrip).gap || '0');
3019
+ const calculateVisibleTabs = (availableWidth)=>{
3020
+ if (availableWidth <= 0) return [];
3021
+ const nextVisible = [];
3022
+ let usedWidth = 0;
3023
+ for (const tabId of layoutTabIds){
3024
+ if (forcedOverflowTabIds.has(tabId)) continue;
3025
+ const tabButton = tabButtons.get(tabId);
3026
+ if (!tabButton) continue;
3027
+ const width = tabButton.getBoundingClientRect().width;
3028
+ const nextUsed = 0 === nextVisible.length ? width : usedWidth + stripGap + width;
3029
+ if (nextUsed <= availableWidth) {
3030
+ nextVisible.push(tabId);
3031
+ usedWidth = nextUsed;
3032
+ } else break;
3033
+ }
3034
+ return nextVisible;
3035
+ };
3036
+ const measureStripWidth = ()=>tabStrip.getBoundingClientRect().width;
3037
+ const showOverflowContainer = ()=>{
3038
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.remove(styles_tabs_module.overflowContainerHidden);
3039
+ };
3040
+ const hideOverflowContainer = ()=>{
3041
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.add(styles_tabs_module.overflowContainerHidden);
3042
+ };
3043
+ const measureVisibleWidth = (tabIds)=>{
3044
+ let width = 0;
3045
+ for (const [index, tabId] of tabIds.entries()){
3046
+ const tabButton = tabButtons.get(tabId);
3047
+ if (tabButton) {
3048
+ width += tabButton.getBoundingClientRect().width;
3049
+ if (index > 0) width += stripGap;
3050
+ }
3051
+ }
3052
+ return width;
3053
+ };
3054
+ if (0 === forcedOverflowTabIds.size) {
3055
+ hideOverflowContainer();
3056
+ const visibleWithoutOverflow = calculateVisibleTabs(measureStripWidth());
3057
+ if (visibleWithoutOverflow.length === layoutTabIds.length) visibleTabIds = visibleWithoutOverflow;
3058
+ else {
3059
+ showOverflowContainer();
3060
+ visibleTabIds = calculateVisibleTabs(measureStripWidth());
3061
+ }
3062
+ } else {
3063
+ showOverflowContainer();
3064
+ const withOverflow = calculateVisibleTabs(measureStripWidth());
3065
+ visibleTabIds = withOverflow.length > 0 ? withOverflow : [
3066
+ activeTab
3067
+ ];
3068
+ }
3069
+ if (!visibleTabIds.includes(activeTab) && !disabledTabs.includes(activeTab)) if (visibleTabIds.length > 0) visibleTabIds[visibleTabIds.length - 1] = activeTab;
3070
+ else visibleTabIds = [
3071
+ activeTab
3072
+ ];
3073
+ visibleTabIds = [
3074
+ ...new Set(visibleTabIds)
3075
+ ];
3076
+ const maxStripWidth = measureStripWidth();
3077
+ while(visibleTabIds.length > 1 && measureVisibleWidth(visibleTabIds) > maxStripWidth + 0.5){
3078
+ let removeIndex = visibleTabIds.length - 1;
3079
+ if (visibleTabIds[removeIndex] === activeTab) removeIndex = Math.max(0, removeIndex - 1);
3080
+ visibleTabIds.splice(removeIndex, 1);
3081
+ }
3082
+ hiddenTabIds = layoutTabIds.filter((tabId)=>!visibleTabIds.includes(tabId) || forcedOverflowTabIds.has(tabId) && tabId !== activeTab);
3083
+ for (const tabId of allTabIds){
3084
+ const tabButton = tabButtons.get(tabId);
3085
+ if (tabButton) {
3086
+ if (styles_tabs_module.tabHidden) tabButton.classList.toggle(styles_tabs_module.tabHidden, hiddenTabIds.includes(tabId));
3087
+ }
3088
+ }
3089
+ for (const tabId of allTabIds){
3090
+ const overflowItem = overflowButtons.get(tabId);
3091
+ if (overflowItem) {
3092
+ if (styles_tabs_module.overflowItemHidden) overflowItem.classList.toggle(styles_tabs_module.overflowItemHidden, !hiddenTabIds.includes(tabId));
3093
+ }
3094
+ }
3095
+ if (styles_tabs_module.overflowContainerHidden) overflowContainer.classList.toggle(styles_tabs_module.overflowContainerHidden, 0 === hiddenTabIds.length);
3096
+ if (0 === hiddenTabIds.length) closeOverflowMenu();
3097
+ }
3098
+ function focusFirstEnabledOverflowItem() {
3099
+ const firstEnabled = hiddenTabIds.find((tabId)=>!disabledTabs.includes(tabId));
3100
+ if (firstEnabled) overflowButtons.get(firstEnabled)?.focus();
3101
+ }
3102
+ function openOverflowMenu() {
3103
+ if (isOverflowMenuOpen || 0 === hiddenTabIds.length) return;
3104
+ isOverflowMenuOpen = true;
3105
+ overflowMenu.dataset.state = 'open';
3106
+ overflowButton.setAttribute('aria-expanded', 'true');
3107
+ document.addEventListener('click', handleOutsideClick);
3108
+ document.addEventListener('keydown', handleEscapeKey);
3109
+ }
3110
+ function closeOverflowMenu() {
3111
+ if (!isOverflowMenuOpen) return;
3112
+ isOverflowMenuOpen = false;
3113
+ overflowMenu.dataset.state = 'closed';
3114
+ overflowButton.setAttribute('aria-expanded', 'false');
3115
+ document.removeEventListener('click', handleOutsideClick);
3116
+ document.removeEventListener('keydown', handleEscapeKey);
3117
+ }
3118
+ function toggleOverflowMenu() {
3119
+ if (isOverflowMenuOpen) closeOverflowMenu();
3120
+ else openOverflowMenu();
3121
+ }
3122
+ function handleOutsideClick(e) {
3123
+ if (!overflowContainer.contains(e.target)) closeOverflowMenu();
3124
+ }
3125
+ function handleEscapeKey(e) {
3126
+ if ('Escape' === e.key) closeOverflowMenu();
2492
3127
  }
2493
3128
  function handleKeyDown(e, currentTab) {
2494
- const tabIds = TABS.map((t)=>t.id);
2495
- const enabledTabIds = tabIds.filter((id)=>!disabledTabs.includes(id));
3129
+ const enabledTabIds = visibleTabIds.filter((tabId)=>!disabledTabs.includes(tabId));
2496
3130
  const currentIndex = enabledTabIds.indexOf(currentTab);
2497
3131
  let newIndex = currentIndex;
2498
3132
  switch(e.key){
@@ -2519,23 +3153,152 @@ var __webpack_exports__ = {};
2519
3153
  tabButtons.get(newTab)?.focus();
2520
3154
  }
2521
3155
  }
3156
+ function handleOverflowKeyDown(e, currentTab) {
3157
+ const enabledTabIds = hiddenTabIds.filter((tabId)=>!disabledTabs.includes(tabId));
3158
+ const currentIndex = enabledTabIds.indexOf(currentTab);
3159
+ if ('Escape' === e.key) {
3160
+ e.preventDefault();
3161
+ closeOverflowMenu();
3162
+ overflowButton.focus();
3163
+ return;
3164
+ }
3165
+ let newIndex = currentIndex;
3166
+ switch(e.key){
3167
+ case 'ArrowDown':
3168
+ newIndex = (currentIndex + 1) % enabledTabIds.length;
3169
+ break;
3170
+ case 'ArrowUp':
3171
+ newIndex = currentIndex > 0 ? currentIndex - 1 : enabledTabIds.length - 1;
3172
+ break;
3173
+ default:
3174
+ return;
3175
+ }
3176
+ e.preventDefault();
3177
+ const newTab = enabledTabIds[newIndex];
3178
+ if (newTab) overflowButtons.get(newTab)?.focus();
3179
+ }
2522
3180
  function setActiveTab(tab) {
2523
3181
  activeTab = tab;
2524
- for (const [tabId, tabButton] of tabButtons){
2525
- const isActive = tabId === tab;
2526
- if (styles_tabs_module.tabActive) tabButton.classList.toggle(styles_tabs_module.tabActive, isActive);
2527
- tabButton.setAttribute('aria-selected', isActive ? 'true' : 'false');
2528
- tabButton.tabIndex = isActive ? 0 : -1;
2529
- }
3182
+ applyActiveState(tab);
3183
+ updateVisibleTabs();
2530
3184
  }
3185
+ const handleWindowResize = ()=>{
3186
+ updateVisibleTabs();
3187
+ };
3188
+ let resizeObserver = null;
3189
+ if ('undefined' != typeof ResizeObserver) {
3190
+ resizeObserver = new ResizeObserver(()=>{
3191
+ updateVisibleTabs();
3192
+ });
3193
+ resizeObserver.observe(tabList);
3194
+ } else window.addEventListener('resize', handleWindowResize);
3195
+ applyActiveState(activeTab);
3196
+ requestAnimationFrame(()=>{
3197
+ updateVisibleTabs();
3198
+ });
2531
3199
  return {
2532
3200
  element: tabList,
2533
3201
  setActiveTab,
2534
3202
  destroy: ()=>{
3203
+ closeOverflowMenu();
3204
+ if (resizeObserver) {
3205
+ resizeObserver.disconnect();
3206
+ resizeObserver = null;
3207
+ } else window.removeEventListener('resize', handleWindowResize);
2535
3208
  tabButtons.clear();
3209
+ overflowButtons.clear();
2536
3210
  }
2537
3211
  };
2538
3212
  }
3213
+ function createDebugBundle(payload) {
3214
+ const { namespace, devToolsState, connection, recentEvents, storeState } = payload;
3215
+ const bundle = {
3216
+ generatedAt: new Date().toISOString(),
3217
+ namespace,
3218
+ devToolsState,
3219
+ connection,
3220
+ recentEvents,
3221
+ storeState,
3222
+ overrides: storeState?.overrides ?? null,
3223
+ iab: storeState?.iab ? {
3224
+ tcString: (storeState?.iab).tcString ?? null,
3225
+ purposeCount: Object.keys((storeState?.iab).purposeConsents ?? {}).length,
3226
+ vendorCount: Object.keys((storeState?.iab).vendorConsents ?? {}).length
3227
+ } : null
3228
+ };
3229
+ return JSON.stringify(bundle, null, 2);
3230
+ }
3231
+ function sanitizeStoreState(state) {
3232
+ if (!state) return null;
3233
+ try {
3234
+ return JSON.parse(JSON.stringify(state, (_key, value)=>'function' == typeof value ? void 0 : value));
3235
+ } catch {
3236
+ return {
3237
+ error: 'Unable to serialize store state'
3238
+ };
3239
+ }
3240
+ }
3241
+ function downloadDebugBundle(content) {
3242
+ const blob = new Blob([
3243
+ content
3244
+ ], {
3245
+ type: 'application/json'
3246
+ });
3247
+ const url = URL.createObjectURL(blob);
3248
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
3249
+ const anchor = document.createElement('a');
3250
+ anchor.href = url;
3251
+ anchor.download = `c15t-debug-bundle-${timestamp}.json`;
3252
+ anchor.click();
3253
+ URL.revokeObjectURL(url);
3254
+ }
3255
+ const DEVTOOLS_OVERRIDES_STORAGE_KEY = 'c15t-devtools-overrides';
3256
+ function normalizeStringValue(value) {
3257
+ if ('string' != typeof value) return;
3258
+ const normalized = value.trim();
3259
+ return normalized.length > 0 ? normalized : void 0;
3260
+ }
3261
+ function normalizeBooleanValue(value) {
3262
+ return 'boolean' == typeof value ? value : void 0;
3263
+ }
3264
+ function normalizeOverrides(value) {
3265
+ if (!value || 'object' != typeof value) return null;
3266
+ const source = value;
3267
+ const overrides = {
3268
+ country: normalizeStringValue(source.country),
3269
+ region: normalizeStringValue(source.region),
3270
+ language: normalizeStringValue(source.language),
3271
+ gpc: normalizeBooleanValue(source.gpc)
3272
+ };
3273
+ return hasPersistedOverrides(overrides) ? overrides : null;
3274
+ }
3275
+ function hasPersistedOverrides(overrides) {
3276
+ return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
3277
+ }
3278
+ function loadPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
3279
+ if ('undefined' == typeof window) return null;
3280
+ try {
3281
+ const stored = localStorage.getItem(storageKey);
3282
+ if (!stored) return null;
3283
+ const parsed = JSON.parse(stored);
3284
+ return normalizeOverrides(parsed);
3285
+ } catch {
3286
+ return null;
3287
+ }
3288
+ }
3289
+ function persistOverrides(overrides, storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
3290
+ if ('undefined' == typeof window) return;
3291
+ try {
3292
+ if (!hasPersistedOverrides(overrides)) return void localStorage.removeItem(storageKey);
3293
+ localStorage.setItem(storageKey, JSON.stringify(overrides));
3294
+ } catch {}
3295
+ }
3296
+ function clearPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
3297
+ if ('undefined' == typeof window) return;
3298
+ try {
3299
+ localStorage.removeItem(storageKey);
3300
+ } catch {}
3301
+ }
2539
3302
  var components_module = __webpack_require__("../../node_modules/.bun/@rsbuild+core@1.6.12/node_modules/@rsbuild/core/compiled/css-loader/index.js??ruleSet[1].rules[1].use[1]!builtin:lightningcss-loader??ruleSet[1].rules[1].use[2]!./src/styles/components.module.css");
2540
3303
  var components_module_options = {};
2541
3304
  components_module_options.styleTagTransform = styleTagTransform_default();
@@ -2572,7 +3335,7 @@ var __webpack_exports__ = {};
2572
3335
  info: styles_components_module.badgeInfo,
2573
3336
  neutral: styles_components_module.badgeNeutral
2574
3337
  }[variant];
2575
- return span({
3338
+ return renderer_span({
2576
3339
  className: `${styles_components_module.badge} ${variantClass}`,
2577
3340
  text
2578
3341
  });
@@ -2603,31 +3366,19 @@ var __webpack_exports__ = {};
2603
3366
  btn.appendChild(document.createTextNode(text));
2604
3367
  return btn;
2605
3368
  }
2606
- function createListItem(options) {
2607
- const { title, description, actions = [] } = options;
2608
- const content = renderer_div({
2609
- className: styles_components_module.listItemContent,
2610
- children: [
2611
- span({
2612
- className: styles_components_module.listItemTitle,
2613
- text: title
2614
- }),
2615
- description ? span({
2616
- className: styles_components_module.listItemDescription,
2617
- text: description
2618
- }) : null
2619
- ]
2620
- });
2621
- const actionsContainer = renderer_div({
2622
- className: styles_components_module.listItemActions,
2623
- children: actions
2624
- });
2625
- return renderer_div({
2626
- className: styles_components_module.listItem,
2627
- children: [
2628
- content,
2629
- actionsContainer
2630
- ]
3369
+ function createInput(options) {
3370
+ const { value, placeholder, ariaLabel, small = false, onInput } = options;
3371
+ const sizeClass = small ? styles_components_module.inputSmall : '';
3372
+ return input({
3373
+ className: `${styles_components_module.input} ${sizeClass}`.trim(),
3374
+ type: 'text',
3375
+ value,
3376
+ placeholder,
3377
+ ariaLabel,
3378
+ onInput: (event)=>{
3379
+ const target = event.target;
3380
+ onInput?.(target?.value ?? '');
3381
+ }
2631
3382
  });
2632
3383
  }
2633
3384
  function createSection(options) {
@@ -2635,7 +3386,7 @@ var __webpack_exports__ = {};
2635
3386
  const header = renderer_div({
2636
3387
  className: styles_components_module.sectionHeader,
2637
3388
  children: [
2638
- span({
3389
+ renderer_span({
2639
3390
  className: styles_components_module.sectionTitle,
2640
3391
  text: title
2641
3392
  }),
@@ -2655,11 +3406,11 @@ var __webpack_exports__ = {};
2655
3406
  return renderer_div({
2656
3407
  className: styles_components_module.infoRow,
2657
3408
  children: [
2658
- span({
3409
+ renderer_span({
2659
3410
  className: styles_components_module.infoLabel,
2660
3411
  text: label
2661
3412
  }),
2662
- span({
3413
+ renderer_span({
2663
3414
  className: styles_components_module.infoValue,
2664
3415
  text: value
2665
3416
  })
@@ -2679,7 +3430,7 @@ var __webpack_exports__ = {};
2679
3430
  }));
2680
3431
  children.push(iconWrapper);
2681
3432
  }
2682
- children.push(span({
3433
+ children.push(renderer_span({
2683
3434
  className: styles_components_module.emptyStateText,
2684
3435
  text
2685
3436
  }));
@@ -2699,7 +3450,7 @@ var __webpack_exports__ = {};
2699
3450
  function createGridCard(options) {
2700
3451
  const { title, action } = options;
2701
3452
  const children = [
2702
- span({
3453
+ renderer_span({
2703
3454
  className: styles_components_module.gridCardTitle,
2704
3455
  text: title
2705
3456
  })
@@ -2710,6 +3461,18 @@ var __webpack_exports__ = {};
2710
3461
  children
2711
3462
  });
2712
3463
  }
3464
+ function createDisconnectedState(message = 'Store not connected') {
3465
+ return renderer_div({
3466
+ className: styles_components_module.disconnectedState,
3467
+ style: {
3468
+ padding: '24px',
3469
+ textAlign: 'center',
3470
+ color: 'var(--c15t-text-muted)',
3471
+ fontSize: 'var(--c15t-devtools-font-size-sm)'
3472
+ },
3473
+ text: message
3474
+ });
3475
+ }
2713
3476
  const REFRESH_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2714
3477
  <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path>
2715
3478
  <path d="M21 3v5h-5"></path>
@@ -2738,18 +3501,10 @@ var __webpack_exports__ = {};
2738
3501
  <line x1="12" y1="19" x2="20" y2="19"></line>
2739
3502
  </svg>`;
2740
3503
  function renderActionsPanel(container, options) {
2741
- const { getState, onResetConsents, onRefetchBanner, onShowBanner, onOpenPreferences, onCopyState } = options;
3504
+ const { getState, onResetConsents, onRefetchBanner, onShowBanner, onOpenPreferences, onCopyState, onExportDebugBundle } = options;
2742
3505
  clearElement(container);
2743
3506
  const state = getState();
2744
- if (!state) return void container.appendChild(renderer_div({
2745
- style: {
2746
- padding: '24px',
2747
- textAlign: 'center',
2748
- color: 'var(--c15t-text-muted)',
2749
- fontSize: 'var(--c15t-devtools-font-size-sm)'
2750
- },
2751
- text: 'Store not connected'
2752
- }));
3507
+ if (!state) return void container.appendChild(createDisconnectedState());
2753
3508
  const actionCards = [
2754
3509
  createActionCard({
2755
3510
  icon: actions_EYE_ICON,
@@ -2770,6 +3525,12 @@ var __webpack_exports__ = {};
2770
3525
  icon: COPY_ICON,
2771
3526
  label: 'Copy State',
2772
3527
  onClick: onCopyState
3528
+ }),
3529
+ createActionCard({
3530
+ icon: REFRESH_ICON,
3531
+ label: 'Export Debug',
3532
+ onClick: ()=>onExportDebugBundle?.(),
3533
+ disabled: !onExportDebugBundle
2773
3534
  })
2774
3535
  ];
2775
3536
  const grid = createGrid({
@@ -2807,7 +3568,7 @@ var __webpack_exports__ = {};
2807
3568
  },
2808
3569
  children: [
2809
3570
  createIconWrapper(TERMINAL_ICON, 14),
2810
- span({
3571
+ renderer_span({
2811
3572
  style: {
2812
3573
  fontSize: 'var(--c15t-devtools-font-size-xs)',
2813
3574
  fontWeight: '600',
@@ -2830,10 +3591,10 @@ var __webpack_exports__ = {};
2830
3591
  color: 'var(--c15t-text-muted)'
2831
3592
  },
2832
3593
  children: [
2833
- span({
3594
+ renderer_span({
2834
3595
  text: `window.${getNamespace(state)}.getState()`
2835
3596
  }),
2836
- span({
3597
+ renderer_span({
2837
3598
  text: 'window.__c15tDevTools.open()'
2838
3599
  })
2839
3600
  ]
@@ -2843,7 +3604,7 @@ var __webpack_exports__ = {};
2843
3604
  container.appendChild(consoleSection);
2844
3605
  }
2845
3606
  function createActionCard(options) {
2846
- const { icon, label, onClick } = options;
3607
+ const { icon, label, onClick, disabled = false } = options;
2847
3608
  const card = renderer_div({
2848
3609
  className: styles_components_module.gridCard ?? '',
2849
3610
  style: {
@@ -2854,11 +3615,12 @@ var __webpack_exports__ = {};
2854
3615
  gap: '6px',
2855
3616
  padding: '16px 8px',
2856
3617
  cursor: 'pointer',
2857
- transition: 'background-color var(--c15t-duration-fast) var(--c15t-easing)'
3618
+ transition: 'background-color var(--c15t-duration-fast) var(--c15t-easing)',
3619
+ opacity: disabled ? '0.55' : '1'
2858
3620
  },
2859
3621
  children: [
2860
3622
  createIconWrapper(icon, 20),
2861
- span({
3623
+ renderer_span({
2862
3624
  style: {
2863
3625
  fontSize: 'var(--c15t-devtools-font-size-xs)',
2864
3626
  fontWeight: '500',
@@ -2869,13 +3631,15 @@ var __webpack_exports__ = {};
2869
3631
  })
2870
3632
  ]
2871
3633
  });
2872
- card.addEventListener('click', onClick);
2873
- card.addEventListener('mouseenter', ()=>{
2874
- card.style.backgroundColor = 'var(--c15t-surface-hover)';
2875
- });
2876
- card.addEventListener('mouseleave', ()=>{
2877
- card.style.backgroundColor = '';
2878
- });
3634
+ if (!disabled) {
3635
+ card.addEventListener('click', onClick);
3636
+ card.addEventListener('mouseenter', ()=>{
3637
+ card.style.backgroundColor = 'var(--c15t-surface-hover)';
3638
+ });
3639
+ card.addEventListener('mouseleave', ()=>{
3640
+ card.style.backgroundColor = '';
3641
+ });
3642
+ }
2879
3643
  return card;
2880
3644
  }
2881
3645
  function createIconWrapper(icon, size) {
@@ -2896,19 +3660,12 @@ var __webpack_exports__ = {};
2896
3660
  function getNamespace(state) {
2897
3661
  return state.config?.meta?.namespace || 'c15tStore';
2898
3662
  }
3663
+ const consentSearchByContainer = new WeakMap();
2899
3664
  function renderConsentsPanel(container, options) {
2900
3665
  const { getState, onConsentChange, onSave, onAcceptAll, onRejectAll, onReset } = options;
2901
3666
  clearElement(container);
2902
3667
  const state = getState();
2903
- if (!state) return void container.appendChild(renderer_div({
2904
- style: {
2905
- padding: '24px',
2906
- textAlign: 'center',
2907
- color: 'var(--c15t-text-muted)',
2908
- fontSize: 'var(--c15t-devtools-font-size-sm)'
2909
- },
2910
- text: 'Store not connected'
2911
- }));
3668
+ if (!state) return void container.appendChild(createDisconnectedState());
2912
3669
  const isIabMode = 'iab' === state.model;
2913
3670
  const savedConsents = state.consents || {};
2914
3671
  const selectedConsents = state.selectedConsents || {};
@@ -2922,15 +3679,40 @@ var __webpack_exports__ = {};
2922
3679
  ct.name,
2923
3680
  ct
2924
3681
  ]));
3682
+ const searchQuery = consentSearchByContainer.get(container) ?? '';
2925
3683
  const consentEntries = Object.entries(displayConsents);
2926
- if (0 === consentEntries.length) container.appendChild(renderer_div({
3684
+ const filteredConsentEntries = consentEntries.filter(([name])=>{
3685
+ if (!searchQuery) return true;
3686
+ const consentType = consentTypeMap.get(name);
3687
+ const displayName = consentType?.name || name;
3688
+ return `${name} ${displayName}`.toLowerCase().includes(searchQuery);
3689
+ });
3690
+ const showSearchInput = consentEntries.length > 4;
3691
+ if (showSearchInput) container.appendChild(renderer_div({
3692
+ style: {
3693
+ padding: '8px 0 10px'
3694
+ },
3695
+ children: [
3696
+ createInput({
3697
+ value: searchQuery,
3698
+ placeholder: 'Filter consents…',
3699
+ ariaLabel: 'Filter consents',
3700
+ small: true,
3701
+ onInput: (value)=>{
3702
+ consentSearchByContainer.set(container, value.trim().toLowerCase());
3703
+ renderConsentsPanel(container, options);
3704
+ }
3705
+ })
3706
+ ]
3707
+ }));
3708
+ if (0 === filteredConsentEntries.length) container.appendChild(renderer_div({
2927
3709
  style: {
2928
3710
  padding: '24px',
2929
3711
  textAlign: 'center',
2930
3712
  color: 'var(--c15t-devtools-text-muted)',
2931
3713
  fontSize: 'var(--c15t-devtools-font-size-sm)'
2932
3714
  },
2933
- text: 'No consents configured'
3715
+ text: 0 === consentEntries.length ? 'No consents configured' : 'No matching consents'
2934
3716
  }));
2935
3717
  else {
2936
3718
  if (isIabMode) {
@@ -2948,7 +3730,7 @@ var __webpack_exports__ = {};
2948
3730
  container.appendChild(iabNotice);
2949
3731
  }
2950
3732
  const gridCards = [];
2951
- for (const [name, value] of consentEntries){
3733
+ for (const [name, value] of filteredConsentEntries){
2952
3734
  const consentType = consentTypeMap.get(name);
2953
3735
  const isNecessary = 'necessary' === name;
2954
3736
  const displayName = consentType?.name || name;
@@ -3012,13 +3794,13 @@ var __webpack_exports__ = {};
3012
3794
  },
3013
3795
  children: [
3014
3796
  createButton({
3015
- text: 'All',
3797
+ text: 'Accept',
3016
3798
  variant: 'primary',
3017
3799
  small: true,
3018
3800
  onClick: onAcceptAll
3019
3801
  }),
3020
3802
  createButton({
3021
- text: 'None',
3803
+ text: 'Reject',
3022
3804
  variant: 'default',
3023
3805
  small: true,
3024
3806
  onClick: onRejectAll
@@ -3038,7 +3820,7 @@ var __webpack_exports__ = {};
3038
3820
  gap: '8px'
3039
3821
  },
3040
3822
  children: [
3041
- span({
3823
+ renderer_span({
3042
3824
  style: {
3043
3825
  fontSize: 'var(--c15t-devtools-font-size-xs)',
3044
3826
  color: 'var(--c15t-devtools-badge-warning)'
@@ -3052,7 +3834,7 @@ var __webpack_exports__ = {};
3052
3834
  onClick: onSave
3053
3835
  })
3054
3836
  ]
3055
- }) : span({
3837
+ }) : renderer_span({
3056
3838
  style: {
3057
3839
  fontSize: 'var(--c15t-devtools-font-size-xs)',
3058
3840
  color: 'var(--c15t-text-muted)'
@@ -3066,19 +3848,36 @@ var __webpack_exports__ = {};
3066
3848
  function formatConsentName(name) {
3067
3849
  return name.replace(/_/g, ' ').replace(/\b\w/g, (l)=>l.toUpperCase());
3068
3850
  }
3851
+ const panelStateByContainer = new WeakMap();
3852
+ function getPanelState(container) {
3853
+ const existing = panelStateByContainer.get(container);
3854
+ if (existing) return existing;
3855
+ const initialState = {
3856
+ activeFilter: 'all',
3857
+ selectedEventId: null,
3858
+ searchQuery: ''
3859
+ };
3860
+ panelStateByContainer.set(container, initialState);
3861
+ return initialState;
3862
+ }
3069
3863
  function renderEventsPanel(container, options) {
3070
3864
  const { getEvents, onClear } = options;
3865
+ const panelState = getPanelState(container);
3071
3866
  clearElement(container);
3072
- const events = getEvents();
3867
+ const allEvents = getEvents();
3868
+ const events = allEvents.filter((event)=>matchesFilter(event, panelState.activeFilter)).filter((event)=>matchesSearch(event, panelState.searchQuery));
3869
+ if (!events.some((event)=>event.id === panelState.selectedEventId)) panelState.selectedEventId = events[0]?.id ?? null;
3870
+ const selectedEvent = events.find((event)=>event.id === panelState.selectedEventId) ?? null;
3073
3871
  const header = renderer_div({
3074
3872
  style: {
3075
3873
  display: 'flex',
3076
3874
  alignItems: 'center',
3077
3875
  justifyContent: 'space-between',
3078
- padding: '12px 16px 8px'
3876
+ padding: '12px 16px 8px',
3877
+ gap: '8px'
3079
3878
  },
3080
3879
  children: [
3081
- span({
3880
+ renderer_span({
3082
3881
  style: {
3083
3882
  fontSize: 'var(--c15t-devtools-font-size-xs)',
3084
3883
  fontWeight: '600',
@@ -3086,75 +3885,187 @@ var __webpack_exports__ = {};
3086
3885
  textTransform: 'uppercase',
3087
3886
  letterSpacing: '0.5px'
3088
3887
  },
3089
- text: `Events (${events.length})`
3888
+ text: `Events (${events.length}/${allEvents.length})`
3090
3889
  }),
3091
- createButton({
3092
- text: 'Clear',
3093
- small: true,
3094
- onClick: onClear
3890
+ renderer_div({
3891
+ style: {
3892
+ display: 'flex',
3893
+ gap: '6px'
3894
+ },
3895
+ children: [
3896
+ createButton({
3897
+ text: 'Export',
3898
+ small: true,
3899
+ onClick: ()=>exportEvents(allEvents)
3900
+ }),
3901
+ createButton({
3902
+ text: 'Clear',
3903
+ small: true,
3904
+ onClick: ()=>{
3905
+ onClear();
3906
+ panelState.selectedEventId = null;
3907
+ renderEventsPanel(container, options);
3908
+ }
3909
+ })
3910
+ ]
3095
3911
  })
3096
3912
  ]
3097
3913
  });
3098
3914
  container.appendChild(header);
3915
+ container.appendChild(renderer_div({
3916
+ style: {
3917
+ display: 'flex',
3918
+ flexWrap: 'wrap',
3919
+ gap: '6px',
3920
+ padding: '0 16px 8px'
3921
+ },
3922
+ children: EVENT_FILTERS.map((filter)=>createFilterButton(filter, filter === panelState.activeFilter, ()=>{
3923
+ panelState.activeFilter = filter;
3924
+ panelState.selectedEventId = null;
3925
+ renderEventsPanel(container, options);
3926
+ }))
3927
+ }));
3928
+ container.appendChild(renderer_div({
3929
+ style: {
3930
+ padding: '0 16px 8px'
3931
+ },
3932
+ children: [
3933
+ createInput({
3934
+ value: panelState.searchQuery,
3935
+ placeholder: 'Search events…',
3936
+ ariaLabel: 'Search events',
3937
+ small: true,
3938
+ onInput: (value)=>{
3939
+ panelState.searchQuery = value.trim().toLowerCase();
3940
+ panelState.selectedEventId = null;
3941
+ renderEventsPanel(container, options);
3942
+ }
3943
+ })
3944
+ ]
3945
+ }));
3099
3946
  const eventList = renderer_div({
3100
3947
  style: {
3101
3948
  display: 'flex',
3102
3949
  flexDirection: 'column',
3103
3950
  gap: '4px',
3104
3951
  padding: '0 12px 12px',
3105
- maxHeight: '400px',
3952
+ maxHeight: '300px',
3106
3953
  overflowY: 'auto'
3107
3954
  }
3108
3955
  });
3109
- if (0 === events.length) {
3110
- const emptyState = renderer_div({
3111
- style: {
3112
- padding: '32px 16px',
3113
- textAlign: 'center',
3114
- color: 'var(--c15t-text-muted)',
3115
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3116
- },
3117
- text: 'No events recorded yet'
3118
- });
3119
- eventList.appendChild(emptyState);
3120
- } else for (const event of events){
3121
- const eventItem = createEventItem(event);
3122
- eventList.appendChild(eventItem);
3123
- }
3956
+ if (0 === events.length) eventList.appendChild(renderer_div({
3957
+ style: {
3958
+ padding: '20px 16px',
3959
+ textAlign: 'center',
3960
+ color: 'var(--c15t-text-muted)',
3961
+ fontSize: 'var(--c15t-devtools-font-size-sm)'
3962
+ },
3963
+ text: 'No events match this filter'
3964
+ }));
3965
+ else for (const event of events)eventList.appendChild(createEventItem(event, event.id === panelState.selectedEventId, ()=>{
3966
+ panelState.selectedEventId = event.id;
3967
+ renderEventsPanel(container, options);
3968
+ }));
3124
3969
  container.appendChild(eventList);
3970
+ container.appendChild(createPayloadSection(selectedEvent));
3125
3971
  }
3126
- function createEventItem(event) {
3127
- const time = formatTime(event.timestamp);
3128
- const icon = getEventIcon(event.type);
3129
- const color = getEventColor(event.type);
3972
+ const EVENT_FILTERS = [
3973
+ 'all',
3974
+ 'error',
3975
+ 'consent',
3976
+ 'network',
3977
+ 'iab'
3978
+ ];
3979
+ function createFilterButton(filter, active, onClick) {
3980
+ return createButton({
3981
+ text: filter.toUpperCase(),
3982
+ small: true,
3983
+ variant: active ? 'primary' : 'default',
3984
+ onClick
3985
+ });
3986
+ }
3987
+ function matchesFilter(event, filter) {
3988
+ if ('all' === filter) return true;
3989
+ if ('error' === filter) return 'error' === event.type;
3990
+ if ('consent' === filter) return 'consent_set' === event.type || 'consent_save' === event.type || 'consent_reset' === event.type;
3991
+ if ('network' === filter) return 'network' === event.type;
3992
+ return 'iab' === event.type;
3993
+ }
3994
+ function matchesSearch(event, query) {
3995
+ if (!query) return true;
3996
+ const haystack = `${event.type} ${event.message} ${JSON.stringify(event.data ?? {})}`;
3997
+ return haystack.toLowerCase().includes(query);
3998
+ }
3999
+ function createPayloadSection(event) {
4000
+ const payload = event?.data ? JSON.stringify(event.data, null, 2) : null;
3130
4001
  return renderer_div({
3131
- className: styles_components_module.gridCard ?? '',
3132
4002
  style: {
3133
- display: 'flex',
3134
- alignItems: 'center',
3135
- gap: '8px',
3136
- padding: '6px 10px',
3137
- fontSize: 'var(--c15t-devtools-font-size-xs)'
4003
+ padding: '0 12px 12px'
3138
4004
  },
3139
4005
  children: [
3140
- span({
4006
+ renderer_div({
3141
4007
  style: {
3142
- color,
3143
- fontSize: '8px',
3144
- lineHeight: '1'
4008
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
4009
+ fontWeight: '600',
4010
+ color: 'var(--c15t-text-muted)',
4011
+ textTransform: 'uppercase',
4012
+ letterSpacing: '0.5px',
4013
+ marginBottom: '6px'
3145
4014
  },
3146
- text: icon
4015
+ text: 'Payload'
3147
4016
  }),
3148
- span({
4017
+ renderer_div({
4018
+ className: styles_components_module.gridCard ?? '',
3149
4019
  style: {
3150
- color: 'var(--c15t-text-muted)',
3151
- fontFamily: 'monospace',
4020
+ padding: '8px',
4021
+ fontFamily: 'ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace',
4022
+ fontSize: '11px',
4023
+ color: 'var(--c15t-text-muted)',
4024
+ maxHeight: '140px',
4025
+ overflowY: 'auto',
4026
+ whiteSpace: 'pre-wrap',
4027
+ wordBreak: 'break-word'
4028
+ },
4029
+ text: payload || 'Select an event with payload data'
4030
+ })
4031
+ ]
4032
+ });
4033
+ }
4034
+ function createEventItem(event, selected, onSelect) {
4035
+ const time = formatTime(event.timestamp);
4036
+ const icon = getEventIcon(event.type);
4037
+ const color = getEventColor(event.type);
4038
+ return renderer_div({
4039
+ className: styles_components_module.gridCard ?? '',
4040
+ style: {
4041
+ display: 'flex',
4042
+ alignItems: 'center',
4043
+ gap: '8px',
4044
+ padding: '6px 10px',
4045
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
4046
+ cursor: 'pointer',
4047
+ borderColor: selected ? 'var(--c15t-devtools-badge-info, #3b82f6)' : 'var(--c15t-border)'
4048
+ },
4049
+ onClick: onSelect,
4050
+ children: [
4051
+ renderer_span({
4052
+ style: {
4053
+ color,
4054
+ fontSize: '8px',
4055
+ lineHeight: '1'
4056
+ },
4057
+ text: icon
4058
+ }),
4059
+ renderer_span({
4060
+ style: {
4061
+ color: 'var(--c15t-text-muted)',
4062
+ fontFamily: 'monospace',
3152
4063
  fontSize: '10px',
3153
4064
  flexShrink: '0'
3154
4065
  },
3155
4066
  text: time
3156
4067
  }),
3157
- span({
4068
+ renderer_span({
3158
4069
  style: {
3159
4070
  color: 'var(--c15t-text)',
3160
4071
  flex: '1'
@@ -3164,6 +4075,21 @@ var __webpack_exports__ = {};
3164
4075
  ]
3165
4076
  });
3166
4077
  }
4078
+ function exportEvents(events) {
4079
+ const json = JSON.stringify(events, null, 2);
4080
+ const blob = new Blob([
4081
+ json
4082
+ ], {
4083
+ type: 'application/json'
4084
+ });
4085
+ const url = URL.createObjectURL(blob);
4086
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
4087
+ const a = document.createElement('a');
4088
+ a.href = url;
4089
+ a.download = `c15t-events-${timestamp}.json`;
4090
+ a.click();
4091
+ URL.revokeObjectURL(url);
4092
+ }
3167
4093
  function formatTime(timestamp) {
3168
4094
  const date = new Date(timestamp);
3169
4095
  return date.toLocaleTimeString('en-US', {
@@ -3182,7 +4108,10 @@ var __webpack_exports__ = {};
3182
4108
  return '○';
3183
4109
  case 'error':
3184
4110
  return '✕';
3185
- case 'info':
4111
+ case 'network':
4112
+ return '◉';
4113
+ case 'iab':
4114
+ return '◆';
3186
4115
  default:
3187
4116
  return '○';
3188
4117
  }
@@ -3196,43 +4125,23 @@ var __webpack_exports__ = {};
3196
4125
  return 'var(--c15t-devtools-badge-warning, #f59e0b)';
3197
4126
  case 'error':
3198
4127
  return 'var(--c15t-devtools-badge-error, #ef4444)';
3199
- case 'info':
4128
+ case 'network':
4129
+ return 'var(--c15t-devtools-badge-warning, #f59e0b)';
4130
+ case 'iab':
4131
+ return 'var(--c15t-devtools-badge-info, #3b82f6)';
3200
4132
  default:
3201
4133
  return 'var(--c15t-text-muted)';
3202
4134
  }
3203
4135
  }
4136
+ const iabSearchByContainer = new WeakMap();
3204
4137
  function renderIabPanel(container, options) {
3205
- const { getState, onReset } = options;
4138
+ const { getState, onSetPurposeConsent, onSetVendorConsent, onSetSpecialFeatureOptIn, onAcceptAll, onRejectAll, onSave, onReset } = options;
3206
4139
  clearElement(container);
3207
4140
  const state = getState();
3208
- if (!state) return void container.appendChild(renderer_div({
3209
- style: {
3210
- padding: '24px',
3211
- textAlign: 'center',
3212
- color: 'var(--c15t-text-muted)',
3213
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3214
- },
3215
- text: 'Store not connected'
3216
- }));
3217
- if ('iab' !== state.model) return void container.appendChild(renderer_div({
3218
- style: {
3219
- padding: '24px',
3220
- textAlign: 'center',
3221
- color: 'var(--c15t-text-muted)',
3222
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3223
- },
3224
- text: 'IAB TCF mode is not configured'
3225
- }));
4141
+ if (!state) return void container.appendChild(createDisconnectedState());
4142
+ if ('iab' !== state.model) return void container.appendChild(createDisconnectedState('IAB TCF mode is not configured'));
3226
4143
  const iabState = state.iab;
3227
- if (!iabState) return void container.appendChild(renderer_div({
3228
- style: {
3229
- padding: '24px',
3230
- textAlign: 'center',
3231
- color: 'var(--c15t-text-muted)',
3232
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3233
- },
3234
- text: 'IAB state not available'
3235
- }));
4144
+ if (!iabState) return void container.appendChild(createDisconnectedState('IAB state not available'));
3236
4145
  const tcString = iabState.tcString;
3237
4146
  const tcStringSection = createSection({
3238
4147
  title: 'TC String',
@@ -3264,9 +4173,30 @@ var __webpack_exports__ = {};
3264
4173
  });
3265
4174
  container.appendChild(tcStringSection);
3266
4175
  const gvl = iabState.gvl;
4176
+ const searchQuery = iabSearchByContainer.get(container) ?? '';
4177
+ container.appendChild(createSection({
4178
+ title: 'Filter',
4179
+ children: [
4180
+ createInput({
4181
+ value: searchQuery,
4182
+ placeholder: 'Filter purposes or vendors…',
4183
+ ariaLabel: 'Filter IAB purposes and vendors',
4184
+ small: true,
4185
+ onInput: (value)=>{
4186
+ iabSearchByContainer.set(container, value.trim().toLowerCase());
4187
+ renderIabPanel(container, options);
4188
+ }
4189
+ })
4190
+ ]
4191
+ }));
3267
4192
  const purposeConsents = iabState.purposeConsents || {};
3268
4193
  const purposes = gvl?.purposes || {};
3269
- const purposeEntries = Object.entries(purposeConsents);
4194
+ const purposeEntries = Object.entries(purposeConsents).filter(([purposeId])=>{
4195
+ if (!searchQuery) return true;
4196
+ const purposeInfo = purposes[purposeId];
4197
+ const purposeName = purposeInfo?.name || `Purpose ${purposeId}`;
4198
+ return `${purposeId} ${purposeName}`.toLowerCase().includes(searchQuery);
4199
+ });
3270
4200
  if (purposeEntries.length > 0) {
3271
4201
  const purposeList = renderer_div({
3272
4202
  style: {
@@ -3280,7 +4210,9 @@ var __webpack_exports__ = {};
3280
4210
  for (const [purposeId, consent] of purposeEntries){
3281
4211
  const purposeInfo = purposes[purposeId];
3282
4212
  const purposeName = purposeInfo?.name || `Purpose ${purposeId}`;
3283
- purposeList.appendChild(createPurposeRow(purposeId, purposeName, Boolean(consent)));
4213
+ purposeList.appendChild(createPurposeRow(purposeId, purposeName, Boolean(consent), (value)=>{
4214
+ onSetPurposeConsent(Number(purposeId), value);
4215
+ }));
3284
4216
  }
3285
4217
  const purposesSection = createSection({
3286
4218
  title: `Purposes (${purposeEntries.length})`,
@@ -3292,7 +4224,12 @@ var __webpack_exports__ = {};
3292
4224
  }
3293
4225
  const specialFeatureOptIns = iabState.specialFeatureOptIns || {};
3294
4226
  const specialFeatures = gvl?.specialFeatures || {};
3295
- const specialFeatureEntries = Object.entries(specialFeatureOptIns);
4227
+ const specialFeatureEntries = Object.entries(specialFeatureOptIns).filter(([featureId])=>{
4228
+ if (!searchQuery) return true;
4229
+ const featureInfo = specialFeatures[featureId];
4230
+ const featureName = featureInfo?.name || `Special Feature ${featureId}`;
4231
+ return `${featureId} ${featureName}`.toLowerCase().includes(searchQuery);
4232
+ });
3296
4233
  if (specialFeatureEntries.length > 0) {
3297
4234
  const specialFeatureList = renderer_div({
3298
4235
  style: {
@@ -3306,7 +4243,9 @@ var __webpack_exports__ = {};
3306
4243
  for (const [featureId, optIn] of specialFeatureEntries){
3307
4244
  const featureInfo = specialFeatures[featureId];
3308
4245
  const featureName = featureInfo?.name || `Special Feature ${featureId}`;
3309
- specialFeatureList.appendChild(createPurposeRow(featureId, featureName, Boolean(optIn)));
4246
+ specialFeatureList.appendChild(createPurposeRow(featureId, featureName, Boolean(optIn), (value)=>{
4247
+ onSetSpecialFeatureOptIn(Number(featureId), value);
4248
+ }, 'feature'));
3310
4249
  }
3311
4250
  const specialFeaturesSection = createSection({
3312
4251
  title: `Special Features (${specialFeatureEntries.length})`,
@@ -3318,7 +4257,12 @@ var __webpack_exports__ = {};
3318
4257
  }
3319
4258
  const vendorConsents = iabState.vendorConsents || {};
3320
4259
  const vendors = gvl?.vendors || {};
3321
- const vendorEntries = Object.entries(vendorConsents);
4260
+ const vendorEntries = Object.entries(vendorConsents).filter(([vendorId])=>{
4261
+ if (!searchQuery) return true;
4262
+ const vendorInfo = vendors[vendorId];
4263
+ const vendorName = vendorInfo?.name || `Vendor ${vendorId}`;
4264
+ return `${vendorId} ${vendorName}`.toLowerCase().includes(searchQuery);
4265
+ });
3322
4266
  const iabVendors = [];
3323
4267
  const customVendors = [];
3324
4268
  for (const [vendorId, consent] of vendorEntries){
@@ -3346,7 +4290,9 @@ var __webpack_exports__ = {};
3346
4290
  overflowY: 'auto'
3347
4291
  }
3348
4292
  });
3349
- for (const [vendorId, consent, vendorName] of iabVendors)vendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'iab'));
4293
+ for (const [vendorId, consent, vendorName] of iabVendors)vendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'iab', (value)=>{
4294
+ onSetVendorConsent(Number(vendorId), value);
4295
+ }));
3350
4296
  const vendorsSection = createSection({
3351
4297
  title: `IAB Vendors (${iabVendors.length})`,
3352
4298
  children: [
@@ -3365,7 +4311,9 @@ var __webpack_exports__ = {};
3365
4311
  overflowY: 'auto'
3366
4312
  }
3367
4313
  });
3368
- for (const [vendorId, consent, vendorName] of customVendors)customVendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'custom'));
4314
+ for (const [vendorId, consent, vendorName] of customVendors)customVendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'custom', (value)=>{
4315
+ onSetVendorConsent(vendorId, value);
4316
+ }));
3369
4317
  const customVendorsSection = createSection({
3370
4318
  title: `Custom Vendors (${customVendors.length})`,
3371
4319
  children: [
@@ -3387,15 +4335,40 @@ var __webpack_exports__ = {};
3387
4335
  style: {
3388
4336
  display: 'flex',
3389
4337
  alignItems: 'center',
3390
- justifyContent: 'flex-end',
4338
+ justifyContent: 'space-between',
3391
4339
  padding: '12px 16px',
3392
4340
  marginTop: 'auto',
3393
4341
  borderTop: '1px solid var(--c15t-border)',
3394
4342
  backgroundColor: 'var(--c15t-surface)'
3395
4343
  },
3396
4344
  children: [
4345
+ renderer_div({
4346
+ style: {
4347
+ display: 'flex',
4348
+ gap: '6px'
4349
+ },
4350
+ children: [
4351
+ createButton({
4352
+ text: 'Accept All',
4353
+ variant: 'primary',
4354
+ small: true,
4355
+ onClick: onAcceptAll
4356
+ }),
4357
+ createButton({
4358
+ text: 'Reject All',
4359
+ small: true,
4360
+ onClick: onRejectAll
4361
+ }),
4362
+ createButton({
4363
+ text: 'Save',
4364
+ variant: 'primary',
4365
+ small: true,
4366
+ onClick: onSave
4367
+ })
4368
+ ]
4369
+ }),
3397
4370
  createButton({
3398
- text: 'Reset All',
4371
+ text: 'Reset',
3399
4372
  variant: 'danger',
3400
4373
  small: true,
3401
4374
  onClick: onReset
@@ -3404,7 +4377,7 @@ var __webpack_exports__ = {};
3404
4377
  });
3405
4378
  container.appendChild(footer);
3406
4379
  }
3407
- function createPurposeRow(id, name, consent) {
4380
+ function createPurposeRow(id, name, consent, onChange, ariaKind = 'purpose') {
3408
4381
  return renderer_div({
3409
4382
  style: {
3410
4383
  display: 'flex',
@@ -3415,7 +4388,7 @@ var __webpack_exports__ = {};
3415
4388
  borderBottom: '1px solid var(--c15t-border)'
3416
4389
  },
3417
4390
  children: [
3418
- span({
4391
+ renderer_span({
3419
4392
  style: {
3420
4393
  color: 'var(--c15t-text)',
3421
4394
  overflow: 'hidden',
@@ -3427,14 +4400,28 @@ var __webpack_exports__ = {};
3427
4400
  text: `${id}. ${name}`,
3428
4401
  title: name
3429
4402
  }),
3430
- createBadge({
3431
- text: consent ? '✓' : '✕',
3432
- variant: consent ? 'success' : 'error'
4403
+ renderer_div({
4404
+ style: {
4405
+ display: 'flex',
4406
+ alignItems: 'center',
4407
+ gap: '6px'
4408
+ },
4409
+ children: [
4410
+ createBadge({
4411
+ text: consent ? '✓' : '✕',
4412
+ variant: consent ? 'success' : 'error'
4413
+ }),
4414
+ createToggle({
4415
+ checked: consent,
4416
+ onChange,
4417
+ ariaLabel: `Toggle ${ariaKind} ${id}`
4418
+ })
4419
+ ]
3433
4420
  })
3434
4421
  ]
3435
4422
  });
3436
4423
  }
3437
- function createVendorRow(id, name, consent, type) {
4424
+ function createVendorRow(id, name, consent, type, onChange) {
3438
4425
  return renderer_div({
3439
4426
  style: {
3440
4427
  display: 'flex',
@@ -3455,7 +4442,7 @@ var __webpack_exports__ = {};
3455
4442
  marginRight: '8px'
3456
4443
  },
3457
4444
  children: [
3458
- 'custom' === type ? span({
4445
+ 'custom' === type ? renderer_span({
3459
4446
  style: {
3460
4447
  fontSize: '9px',
3461
4448
  padding: '1px 4px',
@@ -3466,7 +4453,7 @@ var __webpack_exports__ = {};
3466
4453
  },
3467
4454
  text: 'CUSTOM'
3468
4455
  }) : null,
3469
- span({
4456
+ renderer_span({
3470
4457
  style: {
3471
4458
  color: 'var(--c15t-text)',
3472
4459
  overflow: 'hidden',
@@ -3481,27 +4468,24 @@ var __webpack_exports__ = {};
3481
4468
  createBadge({
3482
4469
  text: consent ? '✓' : '✕',
3483
4470
  variant: consent ? 'success' : 'error'
4471
+ }),
4472
+ createToggle({
4473
+ checked: consent,
4474
+ onChange,
4475
+ ariaLabel: `Toggle vendor ${id}`
3484
4476
  })
3485
4477
  ]
3486
4478
  });
3487
4479
  }
3488
4480
  function truncateText(text, maxLength) {
3489
4481
  if (text.length <= maxLength) return text;
3490
- return text.slice(0, maxLength - 3) + '...';
4482
+ return `${text.slice(0, maxLength - 3)}...`;
3491
4483
  }
3492
4484
  function renderLocationPanel(container, options) {
3493
- const { getState, onSetOverrides, onClearOverrides } = options;
4485
+ const { getState, onApplyOverrides, onClearOverrides } = options;
3494
4486
  clearElement(container);
3495
4487
  const state = getState();
3496
- if (!state) return void container.appendChild(renderer_div({
3497
- style: {
3498
- padding: '24px',
3499
- textAlign: 'center',
3500
- color: 'var(--c15t-text-muted)',
3501
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3502
- },
3503
- text: 'Store not connected'
3504
- }));
4488
+ if (!state) return void container.appendChild(createDisconnectedState());
3505
4489
  const locationInfo = state.locationInfo;
3506
4490
  const overrides = state.overrides;
3507
4491
  const translationConfig = state.translationConfig;
@@ -3511,145 +4495,230 @@ var __webpack_exports__ = {};
3511
4495
  createCompactInfoCard('Jurisdiction', locationInfo?.jurisdiction || '—'),
3512
4496
  createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—')
3513
4497
  ];
4498
+ gridItems.push(createCompactInfoCard('GPC', getEffectiveGpcLabel(overrides?.gpc)));
3514
4499
  if (state.model) gridItems.push(createCompactInfoCard('Model', getModelLabel(state.model)));
3515
4500
  const locationGrid = createGrid({
3516
- columns: 2,
4501
+ columns: 3,
3517
4502
  children: gridItems
3518
4503
  });
3519
4504
  container.appendChild(locationGrid);
4505
+ const initialDraft = getDraftFromOverrides(overrides);
4506
+ let appliedOverrides = normalizeOverrideDraft(initialDraft);
4507
+ let isSubmitting = false;
4508
+ const countryField = createOverrideSelect({
4509
+ label: 'Country',
4510
+ selectOptions: COUNTRY_OPTIONS,
4511
+ value: initialDraft.country
4512
+ });
4513
+ const regionField = createOverrideInput({
4514
+ label: 'Region',
4515
+ placeholder: 'e.g., CA, NY, BE',
4516
+ value: initialDraft.region
4517
+ });
4518
+ const languageField = createOverrideInput({
4519
+ label: 'Language',
4520
+ placeholder: 'e.g., de, fr, en-US',
4521
+ value: initialDraft.language
4522
+ });
4523
+ const gpcField = createOverrideSelect({
4524
+ label: 'GPC',
4525
+ selectOptions: GPC_OPTIONS,
4526
+ value: initialDraft.gpc
4527
+ });
4528
+ const formStatus = renderer_span({
4529
+ className: styles_components_module.overrideStatus,
4530
+ text: 'In sync'
4531
+ });
4532
+ const applyButton = createButton({
4533
+ text: 'Apply',
4534
+ variant: 'primary',
4535
+ small: true,
4536
+ disabled: true,
4537
+ onClick: ()=>{
4538
+ applyDraft();
4539
+ }
4540
+ });
4541
+ const revertButton = createButton({
4542
+ text: 'Revert',
4543
+ small: true,
4544
+ disabled: true,
4545
+ onClick: ()=>{
4546
+ setDraftValues(getDraftFromOverrides(appliedOverrides));
4547
+ updateFormState();
4548
+ }
4549
+ });
4550
+ const clearButton = createButton({
4551
+ text: 'Clear',
4552
+ small: true,
4553
+ onClick: ()=>{
4554
+ clearDraftAndOverrides();
4555
+ }
4556
+ });
4557
+ const overrideFieldsGrid = renderer_div({
4558
+ style: {
4559
+ display: 'grid',
4560
+ gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
4561
+ gap: '8px 10px'
4562
+ },
4563
+ children: [
4564
+ countryField.element,
4565
+ regionField.element,
4566
+ languageField.element,
4567
+ gpcField.element
4568
+ ]
4569
+ });
3520
4570
  const overrideSection = createSection({
3521
4571
  title: 'Override Settings',
3522
- actions: [
3523
- createButton({
3524
- text: 'Clear',
3525
- small: true,
3526
- onClick: onClearOverrides
3527
- })
3528
- ],
3529
4572
  children: [
3530
- createOverrideSelect({
3531
- label: 'Country',
3532
- selectOptions: COUNTRY_OPTIONS,
3533
- value: overrides?.country || '',
3534
- onChange: (value)=>onSetOverrides({
3535
- country: value || void 0
3536
- })
4573
+ overrideFieldsGrid,
4574
+ renderer_span({
4575
+ className: styles_components_module.overrideHint,
4576
+ text: 'GPC override only affects opt-out or unregulated jurisdictions.'
3537
4577
  }),
3538
- createOverrideInput({
3539
- label: 'Region',
3540
- placeholder: 'e.g., CA, NY, BE',
3541
- value: overrides?.region || '',
3542
- onChange: (value)=>onSetOverrides({
3543
- region: value || void 0
3544
- })
3545
- }),
3546
- createOverrideInput({
3547
- label: 'Language',
3548
- placeholder: 'e.g., de, fr, en',
3549
- value: overrides?.language || '',
3550
- onChange: (value)=>onSetOverrides({
3551
- language: value || void 0
3552
- })
4578
+ renderer_div({
4579
+ className: styles_components_module.overrideActions,
4580
+ children: [
4581
+ renderer_div({
4582
+ className: styles_components_module.overrideActionButtons,
4583
+ children: [
4584
+ revertButton,
4585
+ applyButton,
4586
+ clearButton
4587
+ ]
4588
+ }),
4589
+ formStatus
4590
+ ]
3553
4591
  })
3554
4592
  ]
3555
4593
  });
3556
4594
  container.appendChild(overrideSection);
3557
- const hasOverrides = overrides && (overrides.country || overrides.region || overrides.language);
3558
- if (hasOverrides) {
3559
- const overrideBanner = renderer_div({
3560
- style: {
3561
- padding: '8px 16px',
3562
- backgroundColor: 'var(--c15t-devtools-badge-info-bg)',
3563
- color: 'var(--c15t-devtools-badge-info)',
3564
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3565
- borderTop: '1px solid var(--c15t-devtools-border)'
3566
- },
3567
- text: 'Overrides are active. This may affect consent behavior.'
4595
+ countryField.control.addEventListener('change', updateFormState);
4596
+ regionField.control.addEventListener('input', updateFormState);
4597
+ languageField.control.addEventListener('input', updateFormState);
4598
+ gpcField.control.addEventListener('change', updateFormState);
4599
+ updateFormState();
4600
+ async function applyDraft() {
4601
+ if (isSubmitting) return;
4602
+ const draftOverrides = getDraftOverrides();
4603
+ if (overridesEqual(draftOverrides, appliedOverrides)) return;
4604
+ isSubmitting = true;
4605
+ updateFormState();
4606
+ try {
4607
+ await onApplyOverrides(draftOverrides);
4608
+ appliedOverrides = draftOverrides;
4609
+ } finally{
4610
+ isSubmitting = false;
4611
+ updateFormState();
4612
+ }
4613
+ }
4614
+ async function clearDraftAndOverrides() {
4615
+ if (isSubmitting) return;
4616
+ isSubmitting = true;
4617
+ updateFormState();
4618
+ try {
4619
+ await onClearOverrides();
4620
+ appliedOverrides = {};
4621
+ setDraftValues(getDraftFromOverrides(void 0));
4622
+ } finally{
4623
+ isSubmitting = false;
4624
+ updateFormState();
4625
+ }
4626
+ }
4627
+ function getDraftOverrides() {
4628
+ return normalizeOverrideDraft({
4629
+ country: countryField.control.value,
4630
+ region: regionField.control.value,
4631
+ language: languageField.control.value,
4632
+ gpc: gpcField.control.value
3568
4633
  });
3569
- container.appendChild(overrideBanner);
4634
+ }
4635
+ function setDraftValues(draft) {
4636
+ countryField.control.value = draft.country;
4637
+ regionField.control.value = draft.region;
4638
+ languageField.control.value = draft.language;
4639
+ gpcField.control.value = draft.gpc;
4640
+ }
4641
+ function updateFormState() {
4642
+ const draftOverrides = getDraftOverrides();
4643
+ const hasDraftChanges = !overridesEqual(draftOverrides, appliedOverrides);
4644
+ applyButton.disabled = !hasDraftChanges || isSubmitting;
4645
+ revertButton.disabled = !hasDraftChanges || isSubmitting;
4646
+ clearButton.disabled = isSubmitting;
4647
+ formStatus.textContent = isSubmitting ? 'Applying...' : hasDraftChanges ? 'Unsaved changes' : hasOverridesValue(appliedOverrides) ? 'Overrides active' : 'No overrides';
4648
+ if (styles_components_module.overrideStatusDirty) formStatus.classList.toggle(styles_components_module.overrideStatusDirty, !isSubmitting && hasDraftChanges);
3570
4649
  }
3571
4650
  }
3572
4651
  function createOverrideInput(options) {
3573
- const { label, placeholder, value, onChange } = options;
3574
- let debounceTimer = null;
4652
+ const { label, placeholder, value } = options;
3575
4653
  const inputField = input({
3576
4654
  className: `${styles_components_module.input ?? ''} ${styles_components_module.inputSmall ?? ''}`.trim(),
3577
4655
  placeholder,
3578
- value,
3579
- onInput: (e)=>{
3580
- const target = e.target;
3581
- if (debounceTimer) clearTimeout(debounceTimer);
3582
- debounceTimer = setTimeout(()=>{
3583
- onChange(target.value);
3584
- }, 500);
3585
- }
3586
- });
3587
- return renderer_div({
3588
- style: {
3589
- display: 'flex',
3590
- alignItems: 'center',
3591
- justifyContent: 'space-between',
3592
- gap: '8px',
3593
- marginBottom: '8px'
3594
- },
3595
- children: [
3596
- renderer_div({
3597
- style: {
3598
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3599
- color: 'var(--c15t-devtools-text-muted)',
3600
- minWidth: '60px'
3601
- },
3602
- text: label
3603
- }),
3604
- renderer_div({
3605
- style: {
3606
- flex: '1'
3607
- },
3608
- children: [
3609
- inputField
3610
- ]
3611
- })
3612
- ]
4656
+ value
3613
4657
  });
4658
+ return {
4659
+ element: renderer_div({
4660
+ className: styles_components_module.overrideField,
4661
+ children: [
4662
+ renderer_span({
4663
+ className: styles_components_module.overrideLabel,
4664
+ text: label
4665
+ }),
4666
+ inputField
4667
+ ]
4668
+ }),
4669
+ control: inputField
4670
+ };
3614
4671
  }
3615
4672
  function createOverrideSelect(options) {
3616
- const { label, selectOptions, value, onChange } = options;
4673
+ const { label, selectOptions, value } = options;
3617
4674
  const selectField = renderer_select({
3618
4675
  className: `${styles_components_module.input ?? ''} ${styles_components_module.inputSmall ?? ''}`.trim(),
3619
4676
  options: selectOptions,
3620
- selectedValue: value,
3621
- onChange: (e)=>{
3622
- const target = e.target;
3623
- onChange(target.value);
3624
- }
3625
- });
3626
- return renderer_div({
3627
- style: {
3628
- display: 'flex',
3629
- alignItems: 'center',
3630
- justifyContent: 'space-between',
3631
- gap: '8px',
3632
- marginBottom: '8px'
3633
- },
3634
- children: [
3635
- renderer_div({
3636
- style: {
3637
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3638
- color: 'var(--c15t-devtools-text-muted)',
3639
- minWidth: '60px'
3640
- },
3641
- text: label
3642
- }),
3643
- renderer_div({
3644
- style: {
3645
- flex: '1'
3646
- },
3647
- children: [
3648
- selectField
3649
- ]
3650
- })
3651
- ]
4677
+ selectedValue: value
3652
4678
  });
4679
+ return {
4680
+ element: renderer_div({
4681
+ className: styles_components_module.overrideField,
4682
+ children: [
4683
+ renderer_span({
4684
+ className: styles_components_module.overrideLabel,
4685
+ text: label
4686
+ }),
4687
+ selectField
4688
+ ]
4689
+ }),
4690
+ control: selectField
4691
+ };
4692
+ }
4693
+ function getDraftFromOverrides(overrides) {
4694
+ return {
4695
+ country: overrides?.country ?? '',
4696
+ region: overrides?.region ?? '',
4697
+ language: overrides?.language ?? '',
4698
+ gpc: overrides?.gpc === true ? 'true' : overrides?.gpc === false ? 'false' : ''
4699
+ };
4700
+ }
4701
+ function normalizeOverrideDraft(draft) {
4702
+ return {
4703
+ country: normalizeAlphaCode(draft.country),
4704
+ region: normalizeAlphaCode(draft.region),
4705
+ language: normalizeLanguageCode(draft.language),
4706
+ gpc: 'true' === draft.gpc ? true : 'false' === draft.gpc ? false : void 0
4707
+ };
4708
+ }
4709
+ function normalizeAlphaCode(value) {
4710
+ const normalized = value.trim().toUpperCase();
4711
+ return normalized || void 0;
4712
+ }
4713
+ function normalizeLanguageCode(value) {
4714
+ const normalized = value.trim();
4715
+ return normalized || void 0;
4716
+ }
4717
+ function overridesEqual(a, b) {
4718
+ return a.country === b.country && a.region === b.region && a.language === b.language && a.gpc === b.gpc;
4719
+ }
4720
+ function hasOverridesValue(overrides) {
4721
+ return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
3653
4722
  }
3654
4723
  const COUNTRY_OPTIONS = [
3655
4724
  {
@@ -3773,6 +4842,32 @@ var __webpack_exports__ = {};
3773
4842
  label: 'ZA - South Africa'
3774
4843
  }
3775
4844
  ];
4845
+ const GPC_OPTIONS = [
4846
+ {
4847
+ value: '',
4848
+ label: '-- Browser Default --'
4849
+ },
4850
+ {
4851
+ value: 'true',
4852
+ label: 'Force On (Simulated)'
4853
+ },
4854
+ {
4855
+ value: 'false',
4856
+ label: 'Force Off (Simulated)'
4857
+ }
4858
+ ];
4859
+ function getEffectiveGpcLabel(gpcOverride) {
4860
+ if (true === gpcOverride) return 'On (Override)';
4861
+ if (false === gpcOverride) return 'Off (Override)';
4862
+ if ('undefined' == typeof window || 'undefined' == typeof navigator) return 'Unknown';
4863
+ try {
4864
+ const nav = navigator;
4865
+ const value = nav.globalPrivacyControl;
4866
+ return true === value || '1' === value ? 'Active' : 'Inactive';
4867
+ } catch {
4868
+ return 'Unknown';
4869
+ }
4870
+ }
3776
4871
  function getModelLabel(model) {
3777
4872
  switch(model){
3778
4873
  case 'opt-in':
@@ -3789,19 +4884,21 @@ var __webpack_exports__ = {};
3789
4884
  return renderer_div({
3790
4885
  className: styles_components_module.gridCard ?? '',
3791
4886
  style: {
4887
+ padding: '6px 8px',
4888
+ minHeight: 'auto',
3792
4889
  flexDirection: 'column',
3793
4890
  alignItems: 'flex-start',
3794
- gap: '2px'
4891
+ gap: '1px'
3795
4892
  },
3796
4893
  children: [
3797
- span({
4894
+ renderer_span({
3798
4895
  style: {
3799
4896
  fontSize: 'var(--c15t-devtools-font-size-xs)',
3800
4897
  color: 'var(--c15t-text-muted)'
3801
4898
  },
3802
4899
  text: label
3803
4900
  }),
3804
- span({
4901
+ renderer_span({
3805
4902
  style: {
3806
4903
  fontSize: 'var(--c15t-font-size-sm)',
3807
4904
  fontWeight: '500',
@@ -3816,34 +4913,38 @@ var __webpack_exports__ = {};
3816
4913
  function scanDOM(state) {
3817
4914
  const results = [];
3818
4915
  const configuredScripts = state.scripts || [];
3819
- const managedDomains = new Map();
4916
+ const managedResources = [];
3820
4917
  for (const script of configuredScripts)if (script.src) try {
3821
4918
  const url = new URL(script.src, window.location.origin);
3822
- if (url.hostname !== window.location.hostname) managedDomains.set(url.hostname, script.id);
4919
+ if (url.hostname !== window.location.hostname) managedResources.push({
4920
+ scriptId: script.id,
4921
+ domain: url.hostname,
4922
+ pathPrefix: normalizePathname(url.pathname)
4923
+ });
3823
4924
  } catch {}
3824
4925
  const scriptElements = document.querySelectorAll("script[src]");
3825
4926
  for (const el of scriptElements){
3826
4927
  const src = el.getAttribute('src');
3827
4928
  if (!src) continue;
3828
- const resource = checkResource(src, "script", managedDomains);
4929
+ const resource = checkResource(src, "script", managedResources);
3829
4930
  if (resource) results.push(resource);
3830
4931
  }
3831
4932
  const iframeElements = document.querySelectorAll('iframe[src]');
3832
4933
  for (const el of iframeElements){
3833
4934
  const src = el.getAttribute('src');
3834
4935
  if (!src) continue;
3835
- const resource = checkResource(src, 'iframe', managedDomains);
4936
+ const resource = checkResource(src, 'iframe', managedResources);
3836
4937
  if (resource) results.push(resource);
3837
4938
  }
3838
4939
  return results;
3839
4940
  }
3840
- function checkResource(src, type, managedDomains) {
4941
+ function checkResource(src, type, managedResources) {
3841
4942
  try {
3842
4943
  const url = new URL(src, window.location.origin);
3843
4944
  const domain = url.hostname;
3844
4945
  if (domain === window.location.hostname) return null;
3845
4946
  if ('data:' === url.protocol || 'blob:' === url.protocol) return null;
3846
- const managedBy = managedDomains.get(domain);
4947
+ const managedBy = findManagedScriptId(url, managedResources);
3847
4948
  const isManaged = Boolean(managedBy);
3848
4949
  return {
3849
4950
  type,
@@ -3855,6 +4956,21 @@ var __webpack_exports__ = {};
3855
4956
  } catch {}
3856
4957
  return null;
3857
4958
  }
4959
+ function findManagedScriptId(url, managedResources) {
4960
+ const domain = url.hostname;
4961
+ const path = normalizePathname(url.pathname);
4962
+ let bestMatch = null;
4963
+ for (const matcher of managedResources)if (matcher.domain === domain) {
4964
+ if ('/' === matcher.pathPrefix || path.startsWith(matcher.pathPrefix)) {
4965
+ if (!bestMatch || matcher.pathPrefix.length > bestMatch.pathPrefix.length) bestMatch = matcher;
4966
+ }
4967
+ }
4968
+ return bestMatch?.scriptId;
4969
+ }
4970
+ function normalizePathname(pathname) {
4971
+ const trimmed = pathname.trim();
4972
+ return trimmed.length > 0 ? trimmed : '/';
4973
+ }
3858
4974
  function createDomScannerSection(state) {
3859
4975
  let resultsContainer = null;
3860
4976
  let lastScanResults = [];
@@ -3958,21 +5074,21 @@ var __webpack_exports__ = {};
3958
5074
  borderBottom: '1px solid var(--c15t-border)'
3959
5075
  },
3960
5076
  children: [
3961
- span({
5077
+ renderer_span({
3962
5078
  style: {
3963
5079
  color: iconColor,
3964
5080
  flexShrink: '0'
3965
5081
  },
3966
5082
  text: icon
3967
5083
  }),
3968
- span({
5084
+ renderer_span({
3969
5085
  style: {
3970
5086
  color: 'var(--c15t-text-muted)',
3971
5087
  flexShrink: '0'
3972
5088
  },
3973
5089
  text: `${resource.type}:`
3974
5090
  }),
3975
- span({
5091
+ renderer_span({
3976
5092
  style: {
3977
5093
  fontWeight: '500',
3978
5094
  color: 'var(--c15t-text)',
@@ -4018,22 +5134,37 @@ var __webpack_exports__ = {};
4018
5134
  <polyline points="16 18 22 12 16 6"></polyline>
4019
5135
  <polyline points="8 6 2 12 8 18"></polyline>
4020
5136
  </svg>`;
5137
+ const scriptsSearchByContainer = new WeakMap();
4021
5138
  function renderScriptsPanel(container, options) {
4022
- const { getState } = options;
5139
+ const { getState, getEvents } = options;
4023
5140
  clearElement(container);
4024
5141
  const state = getState();
4025
- if (!state) return void container.appendChild(renderer_div({
4026
- style: {
4027
- padding: '24px',
4028
- textAlign: 'center',
4029
- color: 'var(--c15t-text-muted)',
4030
- fontSize: 'var(--c15t-devtools-font-size-sm)'
4031
- },
4032
- text: 'Store not connected'
4033
- }));
5142
+ if (!state) return void container.appendChild(createDisconnectedState());
4034
5143
  const scripts = state.scripts || [];
4035
5144
  const loadedScripts = state.loadedScripts || {};
4036
5145
  const networkBlocker = state.networkBlocker;
5146
+ const events = getEvents?.() ?? [];
5147
+ const searchQuery = scriptsSearchByContainer.get(container) ?? '';
5148
+ const filteredScripts = scripts.filter((script)=>{
5149
+ if (!searchQuery) return true;
5150
+ const category = 'string' == typeof script.category ? script.category : JSON.stringify(script.category);
5151
+ return `${script.id} ${category}`.toLowerCase().includes(searchQuery);
5152
+ });
5153
+ if (scripts.length > 4) container.appendChild(createSection({
5154
+ title: 'Filter',
5155
+ children: [
5156
+ createInput({
5157
+ value: searchQuery,
5158
+ placeholder: "Filter scripts…",
5159
+ ariaLabel: "Filter scripts",
5160
+ small: true,
5161
+ onInput: (value)=>{
5162
+ scriptsSearchByContainer.set(container, value.trim().toLowerCase());
5163
+ renderScriptsPanel(container, options);
5164
+ }
5165
+ })
5166
+ ]
5167
+ }));
4037
5168
  if (0 === scripts.length) {
4038
5169
  const scriptsSection = createSection({
4039
5170
  title: 'Configured Scripts',
@@ -4050,10 +5181,19 @@ var __webpack_exports__ = {};
4050
5181
  style: {
4051
5182
  display: 'flex',
4052
5183
  flexDirection: 'column',
4053
- gap: '4px'
5184
+ borderTop: '1px solid var(--c15t-border)',
5185
+ borderBottom: '1px solid var(--c15t-border)'
4054
5186
  }
4055
5187
  });
4056
- for (const script of scripts){
5188
+ if (0 === filteredScripts.length) scriptsList.appendChild(renderer_div({
5189
+ style: {
5190
+ padding: '10px 0',
5191
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5192
+ color: 'var(--c15t-text-muted)'
5193
+ },
5194
+ text: "No matching scripts"
5195
+ }));
5196
+ for (const script of filteredScripts){
4057
5197
  const scriptId = script.id;
4058
5198
  const isLoaded = true === loadedScripts[scriptId];
4059
5199
  const category = script.category;
@@ -4077,17 +5217,64 @@ var __webpack_exports__ = {};
4077
5217
  text: status.charAt(0).toUpperCase() + status.slice(1),
4078
5218
  variant: statusVariant
4079
5219
  });
4080
- const item = createListItem({
4081
- title: scriptId,
4082
- description: `Category: ${categoryDisplay}`,
4083
- actions: [
4084
- badge
5220
+ const row = renderer_div({
5221
+ style: {
5222
+ display: 'flex',
5223
+ alignItems: 'center',
5224
+ justifyContent: 'space-between',
5225
+ gap: '8px',
5226
+ padding: '8px 0',
5227
+ borderBottom: '1px solid var(--c15t-border)'
5228
+ },
5229
+ children: [
5230
+ renderer_div({
5231
+ style: {
5232
+ display: 'flex',
5233
+ flexDirection: 'column',
5234
+ gap: '2px',
5235
+ minWidth: '0',
5236
+ flex: '1'
5237
+ },
5238
+ children: [
5239
+ renderer_div({
5240
+ style: {
5241
+ fontSize: 'var(--c15t-font-size-sm)',
5242
+ fontWeight: '500',
5243
+ color: 'var(--c15t-text)',
5244
+ overflow: 'hidden',
5245
+ textOverflow: 'ellipsis',
5246
+ whiteSpace: 'nowrap'
5247
+ },
5248
+ text: scriptId
5249
+ }),
5250
+ renderer_div({
5251
+ style: {
5252
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5253
+ color: 'var(--c15t-text-muted)',
5254
+ overflow: 'hidden',
5255
+ textOverflow: 'ellipsis',
5256
+ whiteSpace: 'nowrap'
5257
+ },
5258
+ text: `Category: ${categoryDisplay}`
5259
+ })
5260
+ ]
5261
+ }),
5262
+ renderer_div({
5263
+ style: {
5264
+ flexShrink: '0'
5265
+ },
5266
+ children: [
5267
+ badge
5268
+ ]
5269
+ })
4085
5270
  ]
4086
5271
  });
4087
- scriptsList.appendChild(item);
5272
+ scriptsList.appendChild(row);
4088
5273
  }
5274
+ const lastRow = scriptsList.lastElementChild;
5275
+ if (lastRow) lastRow.style.borderBottom = 'none';
4089
5276
  const scriptsSection = createSection({
4090
- title: `Configured Scripts (${scripts.length})`,
5277
+ title: `Configured Scripts (${filteredScripts.length}/${scripts.length})`,
4091
5278
  children: [
4092
5279
  scriptsList
4093
5280
  ]
@@ -4116,6 +5303,20 @@ var __webpack_exports__ = {};
4116
5303
  ]
4117
5304
  });
4118
5305
  container.appendChild(networkSection);
5306
+ const blockedRequestEvents = events.filter((event)=>'network' === event.type);
5307
+ const networkEventsSection = createSection({
5308
+ title: `Blocked Requests (${blockedRequestEvents.length})`,
5309
+ children: 0 === blockedRequestEvents.length ? [
5310
+ renderer_div({
5311
+ style: {
5312
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
5313
+ color: 'var(--c15t-devtools-text-muted)'
5314
+ },
5315
+ text: 'No blocked network requests recorded in this session'
5316
+ })
5317
+ ] : createBlockedRequestContent(blockedRequestEvents)
5318
+ });
5319
+ container.appendChild(networkEventsSection);
4119
5320
  const loadedCount = Object.values(loadedScripts).filter(Boolean).length;
4120
5321
  const totalCount = scripts.length;
4121
5322
  const summarySection = createSection({
@@ -4141,12 +5342,80 @@ var __webpack_exports__ = {};
4141
5342
  }
4142
5343
  function checkScriptConsent(state, category) {
4143
5344
  if (!category) return true;
5345
+ if ('function' == typeof state.has) try {
5346
+ return state.has(category);
5347
+ } catch {}
4144
5348
  if ('string' == typeof category) {
4145
5349
  const consents = state.consents || {};
4146
5350
  return true === consents[category];
4147
5351
  }
4148
5352
  return false;
4149
5353
  }
5354
+ function createBlockedRequestContent(events) {
5355
+ const stats = new Map();
5356
+ for (const event of events){
5357
+ const ruleId = getEventRuleId(event) ?? 'unknown';
5358
+ stats.set(ruleId, (stats.get(ruleId) ?? 0) + 1);
5359
+ }
5360
+ const statsList = renderer_div({
5361
+ style: {
5362
+ display: 'flex',
5363
+ flexDirection: 'column',
5364
+ gap: '4px',
5365
+ marginBottom: '8px'
5366
+ },
5367
+ children: [
5368
+ ...stats.entries()
5369
+ ].sort((a, b)=>b[1] - a[1]).map(([ruleId, count])=>createInfoRow({
5370
+ label: 'unknown' === ruleId ? 'Unknown Rule' : `Rule: ${ruleId}`,
5371
+ value: `${count}`
5372
+ }))
5373
+ });
5374
+ const latestEvents = events.slice(0, 5);
5375
+ const latestList = renderer_div({
5376
+ style: {
5377
+ display: 'flex',
5378
+ flexDirection: 'column',
5379
+ gap: '4px'
5380
+ },
5381
+ children: latestEvents.map((event)=>createInfoRow({
5382
+ label: `${formatEventTime(event.timestamp)} ${getEventMethod(event)}`,
5383
+ value: scripts_truncateText(getEventUrl(event), 38)
5384
+ }))
5385
+ });
5386
+ return [
5387
+ statsList,
5388
+ latestList
5389
+ ];
5390
+ }
5391
+ function getEventRuleId(event) {
5392
+ const data = event.data;
5393
+ const rule = data?.rule;
5394
+ const ruleId = rule?.id ?? data?.ruleId;
5395
+ return 'string' == typeof ruleId || 'number' == typeof ruleId ? String(ruleId) : void 0;
5396
+ }
5397
+ function getEventMethod(event) {
5398
+ const data = event.data;
5399
+ const method = data?.method;
5400
+ return 'string' == typeof method ? method.toUpperCase() : 'REQ';
5401
+ }
5402
+ function getEventUrl(event) {
5403
+ const data = event.data;
5404
+ const url = data?.url;
5405
+ return 'string' == typeof url ? url : event.message;
5406
+ }
5407
+ function formatEventTime(timestamp) {
5408
+ return new Date(timestamp).toLocaleTimeString('en-US', {
5409
+ hour12: false,
5410
+ hour: '2-digit',
5411
+ minute: '2-digit',
5412
+ second: '2-digit'
5413
+ });
5414
+ }
5415
+ function scripts_truncateText(text, maxLength) {
5416
+ if (text.length <= maxLength) return text;
5417
+ return `${text.slice(0, maxLength - 3)}...`;
5418
+ }
4150
5419
  const STORAGE_KEYS = {
4151
5420
  C15T: 'c15t',
4152
5421
  PENDING_SYNC: 'c15t:pending-consent-sync',
@@ -4183,7 +5452,222 @@ var __webpack_exports__ = {};
4183
5452
  message: 'All consents reset (storage cleared)'
4184
5453
  });
4185
5454
  }
5455
+ function createPanelRenderer(config) {
5456
+ const { storeConnector, stateManager, enableEventLogging = true, onPersistOverrides, onClearPersistedOverrides, onCopyState, onExportDebugBundle } = config;
5457
+ const getStoreState = ()=>storeConnector.getState();
5458
+ const logEvent = (type, message, data)=>{
5459
+ if (enableEventLogging) stateManager.addEvent({
5460
+ type,
5461
+ message,
5462
+ data
5463
+ });
5464
+ };
5465
+ const resetConsents = async ()=>{
5466
+ const store = storeConnector.getStore();
5467
+ if (store) await resetAllConsents(store, enableEventLogging ? stateManager : void 0);
5468
+ };
5469
+ const renderPanel = (container, tab)=>{
5470
+ switch(tab){
5471
+ case 'consents':
5472
+ renderConsentsPanel(container, {
5473
+ getState: getStoreState,
5474
+ onConsentChange: (name, value)=>{
5475
+ const store = storeConnector.getStore();
5476
+ if (store) {
5477
+ const consentName = String(name);
5478
+ store.getState().setSelectedConsent(consentName, value);
5479
+ logEvent('info', `${consentName} toggled to ${value} (not saved)`, {
5480
+ name: consentName,
5481
+ value
5482
+ });
5483
+ }
5484
+ },
5485
+ onSave: ()=>{
5486
+ const store = storeConnector.getStore();
5487
+ if (store) {
5488
+ store.getState().saveConsents('custom');
5489
+ logEvent('consent_save', 'Saved consent preferences');
5490
+ }
5491
+ },
5492
+ onAcceptAll: ()=>{
5493
+ const store = storeConnector.getStore();
5494
+ if (store) {
5495
+ store.getState().saveConsents('all');
5496
+ logEvent('consent_save', 'Accepted all consents');
5497
+ }
5498
+ },
5499
+ onRejectAll: ()=>{
5500
+ const store = storeConnector.getStore();
5501
+ if (store) {
5502
+ store.getState().saveConsents('necessary');
5503
+ logEvent('consent_save', 'Rejected all optional consents');
5504
+ }
5505
+ },
5506
+ onReset: resetConsents
5507
+ });
5508
+ break;
5509
+ case 'location':
5510
+ renderLocationPanel(container, {
5511
+ getState: getStoreState,
5512
+ onApplyOverrides: async (overrides)=>{
5513
+ const store = storeConnector.getStore();
5514
+ if (store) {
5515
+ await store.getState().setOverrides({
5516
+ country: overrides.country,
5517
+ region: overrides.region,
5518
+ language: overrides.language,
5519
+ gpc: overrides.gpc
5520
+ });
5521
+ logEvent('info', 'Overrides updated', {
5522
+ country: overrides.country,
5523
+ region: overrides.region,
5524
+ language: overrides.language,
5525
+ gpc: overrides.gpc
5526
+ });
5527
+ onPersistOverrides?.({
5528
+ country: overrides.country,
5529
+ region: overrides.region,
5530
+ language: overrides.language,
5531
+ gpc: overrides.gpc
5532
+ });
5533
+ }
5534
+ },
5535
+ onClearOverrides: async ()=>{
5536
+ const store = storeConnector.getStore();
5537
+ if (store) {
5538
+ await store.getState().setOverrides({
5539
+ country: void 0,
5540
+ region: void 0,
5541
+ language: void 0,
5542
+ gpc: void 0
5543
+ });
5544
+ logEvent('info', 'Overrides cleared');
5545
+ onClearPersistedOverrides?.();
5546
+ }
5547
+ }
5548
+ });
5549
+ break;
5550
+ case "scripts":
5551
+ renderScriptsPanel(container, {
5552
+ getState: getStoreState,
5553
+ getEvents: ()=>stateManager.getState().eventLog
5554
+ });
5555
+ break;
5556
+ case 'iab':
5557
+ renderIabPanel(container, {
5558
+ getState: getStoreState,
5559
+ onSetPurposeConsent: (purposeId, value)=>{
5560
+ const iab = storeConnector.getStore()?.getState().iab;
5561
+ if (!iab) return;
5562
+ iab.setPurposeConsent(purposeId, value);
5563
+ logEvent('iab', `IAB purpose ${purposeId} set to ${value}`);
5564
+ },
5565
+ onSetVendorConsent: (vendorId, value)=>{
5566
+ const iab = storeConnector.getStore()?.getState().iab;
5567
+ if (!iab) return;
5568
+ iab.setVendorConsent(vendorId, value);
5569
+ logEvent('iab', `IAB vendor ${vendorId} set to ${value}`);
5570
+ },
5571
+ onSetSpecialFeatureOptIn: (featureId, value)=>{
5572
+ const iab = storeConnector.getStore()?.getState().iab;
5573
+ if (!iab) return;
5574
+ iab.setSpecialFeatureOptIn(featureId, value);
5575
+ logEvent('iab', `IAB feature ${featureId} set to ${value}`);
5576
+ },
5577
+ onAcceptAll: ()=>{
5578
+ const iab = storeConnector.getStore()?.getState().iab;
5579
+ if (!iab) return;
5580
+ iab.acceptAll();
5581
+ logEvent('iab', 'IAB accept all selected');
5582
+ },
5583
+ onRejectAll: ()=>{
5584
+ const iab = storeConnector.getStore()?.getState().iab;
5585
+ if (!iab) return;
5586
+ iab.rejectAll();
5587
+ logEvent('iab', 'IAB reject all selected');
5588
+ },
5589
+ onSave: ()=>{
5590
+ const iab = storeConnector.getStore()?.getState().iab;
5591
+ if (!iab) return;
5592
+ iab.save().then(()=>logEvent('iab', 'IAB preferences saved')).catch((error)=>{
5593
+ logEvent('error', `Failed to save IAB preferences: ${String(error)}`);
5594
+ });
5595
+ },
5596
+ onReset: resetConsents
5597
+ });
5598
+ break;
5599
+ case 'events':
5600
+ renderEventsPanel(container, {
5601
+ getEvents: ()=>stateManager.getState().eventLog,
5602
+ onClear: ()=>{
5603
+ stateManager.clearEventLog();
5604
+ logEvent('info', 'Event log cleared');
5605
+ }
5606
+ });
5607
+ break;
5608
+ case 'actions':
5609
+ renderActionsPanel(container, {
5610
+ getState: getStoreState,
5611
+ onResetConsents: resetConsents,
5612
+ onRefetchBanner: async ()=>{
5613
+ const store = storeConnector.getStore();
5614
+ if (store) {
5615
+ await store.getState().initConsentManager();
5616
+ logEvent('info', 'Banner data refetched');
5617
+ }
5618
+ },
5619
+ onShowBanner: ()=>{
5620
+ const store = storeConnector.getStore();
5621
+ if (store) {
5622
+ store.getState().setActiveUI('banner', {
5623
+ force: true
5624
+ });
5625
+ logEvent('info', 'Banner shown');
5626
+ }
5627
+ },
5628
+ onOpenPreferences: ()=>{
5629
+ const store = storeConnector.getStore();
5630
+ if (store) {
5631
+ store.getState().setActiveUI('dialog');
5632
+ logEvent('info', 'Preferences dialog opened');
5633
+ }
5634
+ },
5635
+ onCopyState: ()=>{
5636
+ const state = getStoreState();
5637
+ if (state) if (onCopyState) {
5638
+ const result = onCopyState(state);
5639
+ if (result instanceof Promise) result.then((ok)=>{
5640
+ logEvent(ok ? 'info' : 'error', ok ? 'State copied to clipboard' : 'Failed to copy state');
5641
+ }).catch(()=>{
5642
+ logEvent('error', 'Failed to copy state');
5643
+ });
5644
+ else logEvent(result ? 'info' : 'error', result ? 'State copied to clipboard' : 'Failed to copy state');
5645
+ } else navigator.clipboard.writeText(JSON.stringify(state, null, 2)).then(()=>{
5646
+ logEvent('info', 'State copied to clipboard');
5647
+ }).catch(()=>{
5648
+ logEvent('error', 'Failed to copy state');
5649
+ });
5650
+ },
5651
+ onExportDebugBundle: onExportDebugBundle ? ()=>{
5652
+ try {
5653
+ onExportDebugBundle();
5654
+ logEvent('info', 'Debug bundle exported');
5655
+ } catch {
5656
+ logEvent('error', 'Failed to export debug bundle');
5657
+ }
5658
+ } : void 0
5659
+ });
5660
+ break;
5661
+ }
5662
+ };
5663
+ return {
5664
+ renderPanel,
5665
+ getStoreState,
5666
+ resetConsents
5667
+ };
5668
+ }
4186
5669
  const STORAGE_KEY = 'c15t-devtools-events';
5670
+ const ACTIVE_TAB_STORAGE_KEY = 'c15t-devtools-active-tab';
4187
5671
  function loadPersistedEvents() {
4188
5672
  if ('undefined' == typeof window) return [];
4189
5673
  try {
@@ -4198,11 +5682,29 @@ var __webpack_exports__ = {};
4198
5682
  sessionStorage.setItem(STORAGE_KEY, JSON.stringify(events));
4199
5683
  } catch {}
4200
5684
  }
5685
+ function isDevToolsTab(value) {
5686
+ return 'consents' === value || 'location' === value || "scripts" === value || 'iab' === value || 'events' === value || 'actions' === value;
5687
+ }
5688
+ function loadPersistedActiveTab() {
5689
+ if ('undefined' == typeof window) return null;
5690
+ try {
5691
+ const stored = localStorage.getItem(ACTIVE_TAB_STORAGE_KEY);
5692
+ if (isDevToolsTab(stored)) return stored;
5693
+ } catch {}
5694
+ return null;
5695
+ }
5696
+ function persistActiveTab(tab) {
5697
+ if ('undefined' == typeof window) return;
5698
+ try {
5699
+ localStorage.setItem(ACTIVE_TAB_STORAGE_KEY, tab);
5700
+ } catch {}
5701
+ }
4201
5702
  function createStateManager(initialState = {}) {
4202
5703
  const persistedEvents = loadPersistedEvents();
5704
+ const persistedActiveTab = loadPersistedActiveTab();
4203
5705
  let state = {
4204
5706
  isOpen: false,
4205
- activeTab: 'location',
5707
+ activeTab: persistedActiveTab ?? 'location',
4206
5708
  position: 'bottom-right',
4207
5709
  isConnected: false,
4208
5710
  eventLog: persistedEvents,
@@ -4243,6 +5745,7 @@ var __webpack_exports__ = {};
4243
5745
  setState({
4244
5746
  activeTab: tab
4245
5747
  });
5748
+ persistActiveTab(tab);
4246
5749
  },
4247
5750
  setPosition: (position)=>{
4248
5751
  setState({
@@ -4284,12 +5787,67 @@ var __webpack_exports__ = {};
4284
5787
  const { namespace = 'c15tStore', onConnect, onStateChange, onDisconnect } = options;
4285
5788
  let store = null;
4286
5789
  let unsubscribe = null;
4287
- let pollInterval = null;
5790
+ let reconnectTimeout = null;
5791
+ let reconnectAttempts = 0;
5792
+ let hasNotifiedDisconnect = false;
4288
5793
  const listeners = new Set();
5794
+ const diagnosticsListeners = new Set();
5795
+ let diagnostics = {
5796
+ namespace,
5797
+ reconnectAttempts: 0,
5798
+ nextRetryInMs: null,
5799
+ lastError: null,
5800
+ isPolling: false,
5801
+ disconnectNotified: false
5802
+ };
5803
+ const INITIAL_RETRY_DELAY_MS = 100;
5804
+ const MAX_RETRY_DELAY_MS = 2000;
5805
+ const DISCONNECT_NOTIFY_ATTEMPTS = 5;
5806
+ function updateDiagnostics(partial, notify = true) {
5807
+ diagnostics = {
5808
+ ...diagnostics,
5809
+ ...partial
5810
+ };
5811
+ if (!notify) return;
5812
+ for (const listener of diagnosticsListeners)listener(diagnostics);
5813
+ }
5814
+ function clearReconnectTimer() {
5815
+ if (reconnectTimeout) {
5816
+ clearTimeout(reconnectTimeout);
5817
+ reconnectTimeout = null;
5818
+ updateDiagnostics({
5819
+ isPolling: false,
5820
+ nextRetryInMs: null
5821
+ });
5822
+ }
5823
+ }
5824
+ function resetReconnectState() {
5825
+ reconnectAttempts = 0;
5826
+ hasNotifiedDisconnect = false;
5827
+ updateDiagnostics({
5828
+ reconnectAttempts: 0,
5829
+ nextRetryInMs: null,
5830
+ lastError: null,
5831
+ disconnectNotified: false
5832
+ });
5833
+ }
5834
+ function notifyDisconnectedOnce() {
5835
+ if (hasNotifiedDisconnect) return;
5836
+ hasNotifiedDisconnect = true;
5837
+ updateDiagnostics({
5838
+ disconnectNotified: true
5839
+ });
5840
+ onDisconnect?.();
5841
+ }
4289
5842
  function tryConnect() {
4290
5843
  if ('undefined' == typeof window) return false;
4291
5844
  const storeInstance = window[namespace];
4292
5845
  if (storeInstance && 'function' == typeof storeInstance.getState) {
5846
+ if (store === storeInstance && unsubscribe) return true;
5847
+ if (unsubscribe) {
5848
+ unsubscribe();
5849
+ unsubscribe = null;
5850
+ }
4293
5851
  store = storeInstance;
4294
5852
  unsubscribe = store.subscribe((state)=>{
4295
5853
  onStateChange?.(state);
@@ -4297,30 +5855,41 @@ var __webpack_exports__ = {};
4297
5855
  });
4298
5856
  const currentState = store.getState();
4299
5857
  onConnect?.(currentState, store);
4300
- if (pollInterval) {
4301
- clearInterval(pollInterval);
4302
- pollInterval = null;
4303
- }
5858
+ clearReconnectTimer();
5859
+ resetReconnectState();
5860
+ updateDiagnostics({
5861
+ lastError: null
5862
+ });
4304
5863
  return true;
4305
5864
  }
5865
+ updateDiagnostics({
5866
+ lastError: `Store "${namespace}" not found on window`
5867
+ });
4306
5868
  return false;
4307
5869
  }
5870
+ function scheduleReconnect(immediate = false) {
5871
+ if (store || reconnectTimeout) return;
5872
+ const delay = immediate ? 0 : Math.min(INITIAL_RETRY_DELAY_MS * 2 ** Math.min(reconnectAttempts, 5), MAX_RETRY_DELAY_MS);
5873
+ updateDiagnostics({
5874
+ isPolling: true,
5875
+ nextRetryInMs: delay,
5876
+ reconnectAttempts
5877
+ });
5878
+ reconnectTimeout = setTimeout(()=>{
5879
+ reconnectTimeout = null;
5880
+ reconnectAttempts++;
5881
+ updateDiagnostics({
5882
+ reconnectAttempts,
5883
+ nextRetryInMs: null
5884
+ });
5885
+ if (tryConnect()) return;
5886
+ if (reconnectAttempts >= DISCONNECT_NOTIFY_ATTEMPTS) notifyDisconnectedOnce();
5887
+ scheduleReconnect();
5888
+ }, delay);
5889
+ }
4308
5890
  function startPolling() {
4309
- if (pollInterval) return;
4310
5891
  if (tryConnect()) return;
4311
- let attempts = 0;
4312
- const maxAttempts = 50;
4313
- pollInterval = setInterval(()=>{
4314
- attempts++;
4315
- if (tryConnect()) return;
4316
- if (attempts >= maxAttempts) {
4317
- if (pollInterval) {
4318
- clearInterval(pollInterval);
4319
- pollInterval = null;
4320
- }
4321
- onDisconnect?.();
4322
- }
4323
- }, 100);
5892
+ scheduleReconnect(true);
4324
5893
  }
4325
5894
  startPolling();
4326
5895
  return {
@@ -4334,17 +5903,28 @@ var __webpack_exports__ = {};
4334
5903
  listeners.delete(listener);
4335
5904
  };
4336
5905
  },
5906
+ getDiagnostics: ()=>diagnostics,
5907
+ subscribeDiagnostics: (listener)=>{
5908
+ diagnosticsListeners.add(listener);
5909
+ listener(diagnostics);
5910
+ return ()=>{
5911
+ diagnosticsListeners.delete(listener);
5912
+ };
5913
+ },
5914
+ retryConnection: ()=>{
5915
+ if (store) return;
5916
+ resetReconnectState();
5917
+ scheduleReconnect(true);
5918
+ },
4337
5919
  destroy: ()=>{
4338
- if (pollInterval) {
4339
- clearInterval(pollInterval);
4340
- pollInterval = null;
4341
- }
5920
+ clearReconnectTimer();
4342
5921
  if (unsubscribe) {
4343
5922
  unsubscribe();
4344
5923
  unsubscribe = null;
4345
5924
  }
4346
5925
  store = null;
4347
5926
  listeners.clear();
5927
+ diagnosticsListeners.clear();
4348
5928
  }
4349
5929
  };
4350
5930
  }
@@ -4357,6 +5937,133 @@ var __webpack_exports__ = {};
4357
5937
  function isC15tStoreAvailable(namespace = 'c15tStore') {
4358
5938
  return null !== getC15tStore(namespace);
4359
5939
  }
5940
+ const REGISTRY_KEY = '__c15tDevToolsInstrumentationRegistry';
5941
+ let fallbackRegistry = null;
5942
+ function getRegistry() {
5943
+ if ('undefined' == typeof window) {
5944
+ if (!fallbackRegistry) fallbackRegistry = new Map();
5945
+ return fallbackRegistry;
5946
+ }
5947
+ const host = window;
5948
+ const existing = host[REGISTRY_KEY];
5949
+ if (existing) return existing;
5950
+ const registry = new Map();
5951
+ host[REGISTRY_KEY] = registry;
5952
+ return registry;
5953
+ }
5954
+ function getBlockedRequestMessage(payload) {
5955
+ const data = payload;
5956
+ const method = 'string' == typeof data?.method ? data.method.toUpperCase() : 'REQUEST';
5957
+ const url = 'string' == typeof data?.url ? data.url : 'unknown-url';
5958
+ return `Network blocked: ${method} ${url}`;
5959
+ }
5960
+ function emitEvent(entry, event) {
5961
+ for (const listener of entry.listeners)listener(event);
5962
+ }
5963
+ function ensureNetworkBlockerWrapped(entry) {
5964
+ const blocker = entry.store.getState().networkBlocker;
5965
+ if (!blocker) return;
5966
+ if (blocker.onRequestBlocked === entry.wrappedNetworkBlockedCallback) return;
5967
+ entry.originalNetworkBlockedCallback = blocker.onRequestBlocked;
5968
+ entry.wrappedNetworkBlockedCallback = (payload)=>{
5969
+ emitEvent(entry, {
5970
+ type: 'network',
5971
+ message: getBlockedRequestMessage(payload),
5972
+ data: payload
5973
+ });
5974
+ if ('function' == typeof entry.originalNetworkBlockedCallback) entry.originalNetworkBlockedCallback(payload);
5975
+ };
5976
+ entry.store.getState().setNetworkBlocker({
5977
+ ...blocker,
5978
+ onRequestBlocked: entry.wrappedNetworkBlockedCallback
5979
+ });
5980
+ }
5981
+ function restoreInstrumentation(entry) {
5982
+ entry.stopWatchingStore?.();
5983
+ entry.stopWatchingStore = null;
5984
+ const state = entry.store.getState();
5985
+ state.setCallback('onBannerFetched', entry.originalCallbacks.onBannerFetched);
5986
+ state.setCallback('onConsentSet', entry.originalCallbacks.onConsentSet);
5987
+ state.setCallback('onError', entry.originalCallbacks.onError);
5988
+ state.setCallback('onBeforeConsentRevocationReload', entry.originalCallbacks.onBeforeConsentRevocationReload);
5989
+ const blocker = state.networkBlocker;
5990
+ if (blocker && blocker.onRequestBlocked === entry.wrappedNetworkBlockedCallback) state.setNetworkBlocker({
5991
+ ...blocker,
5992
+ onRequestBlocked: entry.originalNetworkBlockedCallback
5993
+ });
5994
+ entry.wrappedNetworkBlockedCallback = null;
5995
+ }
5996
+ function createInstrumentationEntry(store) {
5997
+ const entry = {
5998
+ store,
5999
+ listeners: new Set(),
6000
+ originalCallbacks: {
6001
+ ...store.getState().callbacks
6002
+ },
6003
+ originalNetworkBlockedCallback: store.getState().networkBlocker?.onRequestBlocked,
6004
+ wrappedNetworkBlockedCallback: null,
6005
+ stopWatchingStore: null
6006
+ };
6007
+ store.getState().setCallback('onBannerFetched', (payload)=>{
6008
+ const jurisdiction = payload.jurisdiction;
6009
+ emitEvent(entry, {
6010
+ type: 'info',
6011
+ message: `Banner fetched: ${String(jurisdiction)}`,
6012
+ data: payload
6013
+ });
6014
+ if ('function' == typeof entry.originalCallbacks.onBannerFetched) entry.originalCallbacks.onBannerFetched(payload);
6015
+ });
6016
+ store.getState().setCallback('onConsentSet', (payload)=>{
6017
+ emitEvent(entry, {
6018
+ type: 'consent_set',
6019
+ message: 'Consent preferences updated',
6020
+ data: payload
6021
+ });
6022
+ if ('function' == typeof entry.originalCallbacks.onConsentSet) entry.originalCallbacks.onConsentSet(payload);
6023
+ });
6024
+ store.getState().setCallback('onError', (payload)=>{
6025
+ const errorMessage = payload.error;
6026
+ emitEvent(entry, {
6027
+ type: 'error',
6028
+ message: `Error: ${String(errorMessage)}`,
6029
+ data: payload
6030
+ });
6031
+ if ('function' == typeof entry.originalCallbacks.onError) entry.originalCallbacks.onError(payload);
6032
+ });
6033
+ store.getState().setCallback('onBeforeConsentRevocationReload', (payload)=>{
6034
+ emitEvent(entry, {
6035
+ type: 'info',
6036
+ message: 'Consent revocation - page will reload',
6037
+ data: payload
6038
+ });
6039
+ if ('function' == typeof entry.originalCallbacks.onBeforeConsentRevocationReload) entry.originalCallbacks.onBeforeConsentRevocationReload(payload);
6040
+ });
6041
+ ensureNetworkBlockerWrapped(entry);
6042
+ entry.stopWatchingStore = store.subscribe(()=>{
6043
+ ensureNetworkBlockerWrapped(entry);
6044
+ });
6045
+ return entry;
6046
+ }
6047
+ function registerStoreInstrumentation(options) {
6048
+ const { namespace, store, onEvent } = options;
6049
+ const registry = getRegistry();
6050
+ let entry = registry.get(namespace);
6051
+ if (!entry || entry.store !== store) {
6052
+ if (entry) restoreInstrumentation(entry);
6053
+ entry = createInstrumentationEntry(store);
6054
+ registry.set(namespace, entry);
6055
+ }
6056
+ entry.listeners.add(onEvent);
6057
+ return ()=>{
6058
+ const current = registry.get(namespace);
6059
+ if (!current) return;
6060
+ current.listeners.delete(onEvent);
6061
+ if (0 === current.listeners.size) {
6062
+ restoreInstrumentation(current);
6063
+ registry.delete(namespace);
6064
+ }
6065
+ };
6066
+ }
4360
6067
  var tokens = __webpack_require__("../../node_modules/.bun/@rsbuild+core@1.6.12/node_modules/@rsbuild/core/compiled/css-loader/index.js??ruleSet[1].rules[1].use[1]!builtin:lightningcss-loader??ruleSet[1].rules[1].use[2]!./src/styles/tokens.css");
4361
6068
  var tokens_options = {};
4362
6069
  tokens_options.styleTagTransform = styleTagTransform_default();
@@ -4366,59 +6073,148 @@ var __webpack_exports__ = {};
4366
6073
  tokens_options.insertStyleElement = insertStyleElement_default();
4367
6074
  injectStylesIntoStyleTag_default()(tokens.A, tokens_options);
4368
6075
  tokens.A && tokens.A.locals && tokens.A.locals;
6076
+ const PANEL_HEIGHT_TRANSITION = 'height var(--c15t-duration-normal, 200ms) var(--c15t-easing, cubic-bezier(0.4, 0, 0.2, 1))';
6077
+ const PANEL_HEIGHT_TRANSITION_MS = 200;
6078
+ const PANEL_HEIGHT_TRANSITION_BUFFER_MS = 80;
6079
+ function normalizeOverridesForPersistence(overrides) {
6080
+ return {
6081
+ country: overrides?.country?.trim() || void 0,
6082
+ region: overrides?.region?.trim() || void 0,
6083
+ language: overrides?.language?.trim() || void 0,
6084
+ gpc: overrides?.gpc
6085
+ };
6086
+ }
6087
+ function persistedOverridesEqual(a, b) {
6088
+ return a.country === b.country && a.region === b.region && a.language === b.language && a.gpc === b.gpc;
6089
+ }
6090
+ function prefersReducedMotion() {
6091
+ return 'undefined' != typeof window && 'function' == typeof window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
6092
+ }
6093
+ function createPanelHeightAnimator() {
6094
+ let activePanel = null;
6095
+ let frameId = null;
6096
+ let timeoutId = null;
6097
+ let removeTransitionListener = null;
6098
+ function clearAnimationState() {
6099
+ if (null !== frameId) {
6100
+ window.cancelAnimationFrame(frameId);
6101
+ frameId = null;
6102
+ }
6103
+ if (null !== timeoutId) {
6104
+ clearTimeout(timeoutId);
6105
+ timeoutId = null;
6106
+ }
6107
+ if (removeTransitionListener) {
6108
+ removeTransitionListener();
6109
+ removeTransitionListener = null;
6110
+ }
6111
+ if (activePanel) {
6112
+ activePanel.style.height = '';
6113
+ activePanel.style.transition = '';
6114
+ activePanel.style.willChange = '';
6115
+ activePanel = null;
6116
+ }
6117
+ }
6118
+ function animate(panel, previousHeight) {
6119
+ if (!Number.isFinite(previousHeight) || prefersReducedMotion()) return;
6120
+ const nextHeight = panel.getBoundingClientRect().height;
6121
+ if (!Number.isFinite(nextHeight) || Math.abs(nextHeight - previousHeight) < 1) return;
6122
+ clearAnimationState();
6123
+ activePanel = panel;
6124
+ panel.style.height = `${previousHeight}px`;
6125
+ panel.style.willChange = 'height';
6126
+ panel.getBoundingClientRect();
6127
+ const handleTransitionEnd = (event)=>{
6128
+ const transitionEvent = event;
6129
+ if ('string' == typeof transitionEvent.propertyName && transitionEvent.propertyName && 'height' !== transitionEvent.propertyName) return;
6130
+ clearAnimationState();
6131
+ };
6132
+ panel.addEventListener('transitionend', handleTransitionEnd);
6133
+ removeTransitionListener = ()=>{
6134
+ panel.removeEventListener('transitionend', handleTransitionEnd);
6135
+ };
6136
+ frameId = window.requestAnimationFrame(()=>{
6137
+ frameId = null;
6138
+ panel.style.transition = PANEL_HEIGHT_TRANSITION;
6139
+ panel.style.height = `${nextHeight}px`;
6140
+ });
6141
+ timeoutId = setTimeout(()=>{
6142
+ clearAnimationState();
6143
+ }, PANEL_HEIGHT_TRANSITION_MS + PANEL_HEIGHT_TRANSITION_BUFFER_MS);
6144
+ }
6145
+ return {
6146
+ animate,
6147
+ destroy: clearAnimationState
6148
+ };
6149
+ }
6150
+ function createStateCopy(state) {
6151
+ return {
6152
+ consents: state.consents,
6153
+ selectedConsents: state.selectedConsents,
6154
+ consentInfo: state.consentInfo,
6155
+ locationInfo: state.locationInfo,
6156
+ model: state.model,
6157
+ overrides: state.overrides,
6158
+ scripts: state.scripts?.map((script)=>({
6159
+ id: script.id
6160
+ })),
6161
+ loadedScripts: state.loadedScripts
6162
+ };
6163
+ }
4369
6164
  function createDevTools(options = {}) {
4370
6165
  const { namespace = 'c15tStore', position = 'bottom-right', defaultOpen = false } = options;
4371
6166
  const stateManager = createStateManager({
4372
6167
  position,
4373
6168
  isOpen: defaultOpen
4374
6169
  });
4375
- let originalCallbacks = {};
6170
+ let detachInstrumentation = null;
4376
6171
  const storeConnector = createStoreConnector({
4377
6172
  namespace,
4378
- onConnect: (state, store)=>{
6173
+ onConnect: (_state, store)=>{
6174
+ detachInstrumentation?.();
6175
+ detachInstrumentation = registerStoreInstrumentation({
6176
+ namespace,
6177
+ store,
6178
+ onEvent: (event)=>{
6179
+ stateManager.addEvent(event);
6180
+ }
6181
+ });
4379
6182
  stateManager.setConnected(true);
4380
6183
  stateManager.addEvent({
4381
6184
  type: 'info',
4382
6185
  message: 'Connected to c15tStore'
4383
6186
  });
4384
- originalCallbacks = {
4385
- ...state.callbacks
4386
- };
4387
- store.getState().setCallback('onBannerFetched', (payload)=>{
4388
- stateManager.addEvent({
4389
- type: 'info',
4390
- message: `Banner fetched: ${String(payload.jurisdiction)}`,
4391
- data: payload
4392
- });
4393
- if ('function' == typeof originalCallbacks.onBannerFetched) originalCallbacks.onBannerFetched(payload);
4394
- });
4395
- store.getState().setCallback('onConsentSet', (payload)=>{
4396
- stateManager.addEvent({
4397
- type: 'consent_set',
4398
- message: 'Consent preferences updated',
4399
- data: payload
4400
- });
4401
- if ('function' == typeof originalCallbacks.onConsentSet) originalCallbacks.onConsentSet(payload);
4402
- });
4403
- store.getState().setCallback('onError', (payload)=>{
4404
- stateManager.addEvent({
4405
- type: 'error',
4406
- message: `Error: ${payload.error}`,
4407
- data: payload
4408
- });
4409
- if ('function' == typeof originalCallbacks.onError) originalCallbacks.onError(payload);
4410
- });
4411
- store.getState().setCallback('onBeforeConsentRevocationReload', (payload)=>{
4412
- stateManager.addEvent({
4413
- type: 'info',
4414
- message: 'Consent revocation - page will reload',
4415
- data: payload
6187
+ const persistedOverrides = loadPersistedOverrides();
6188
+ if (persistedOverrides) {
6189
+ const currentOverrides = normalizeOverridesForPersistence(store.getState().overrides);
6190
+ if (!persistedOverridesEqual(persistedOverrides, currentOverrides)) store.getState().setOverrides({
6191
+ country: persistedOverrides.country,
6192
+ region: persistedOverrides.region,
6193
+ language: persistedOverrides.language,
6194
+ gpc: persistedOverrides.gpc
6195
+ }).then(()=>{
6196
+ stateManager.addEvent({
6197
+ type: 'info',
6198
+ message: 'Applied persisted devtools overrides',
6199
+ data: {
6200
+ country: persistedOverrides.country,
6201
+ region: persistedOverrides.region,
6202
+ language: persistedOverrides.language,
6203
+ gpc: persistedOverrides.gpc
6204
+ }
6205
+ });
6206
+ }).catch(()=>{
6207
+ stateManager.addEvent({
6208
+ type: 'error',
6209
+ message: 'Failed to apply persisted devtools overrides'
6210
+ });
4416
6211
  });
4417
- if ('function' == typeof originalCallbacks.onBeforeConsentRevocationReload) originalCallbacks.onBeforeConsentRevocationReload(payload);
4418
- });
6212
+ }
4419
6213
  },
4420
6214
  onDisconnect: ()=>{
4421
6215
  stateManager.setConnected(false);
6216
+ detachInstrumentation?.();
6217
+ detachInstrumentation = null;
4422
6218
  stateManager.addEvent({
4423
6219
  type: 'error',
4424
6220
  message: 'Disconnected from c15tStore'
@@ -4426,22 +6222,56 @@ var __webpack_exports__ = {};
4426
6222
  },
4427
6223
  onStateChange: ()=>{}
4428
6224
  });
6225
+ const panelRenderer = createPanelRenderer({
6226
+ storeConnector,
6227
+ stateManager,
6228
+ enableEventLogging: true,
6229
+ onPersistOverrides: persistOverrides,
6230
+ onClearPersistedOverrides: clearPersistedOverrides,
6231
+ onCopyState: async (state)=>{
6232
+ try {
6233
+ await navigator.clipboard.writeText(JSON.stringify(createStateCopy(state), null, 2));
6234
+ return true;
6235
+ } catch {
6236
+ return false;
6237
+ }
6238
+ },
6239
+ onExportDebugBundle: ()=>{
6240
+ const bundle = createDebugBundle({
6241
+ namespace,
6242
+ devToolsState: stateManager.getState(),
6243
+ connection: storeConnector.getDiagnostics(),
6244
+ recentEvents: stateManager.getState().eventLog.slice(0, 100),
6245
+ storeState: sanitizeStoreState(storeConnector.getState())
6246
+ });
6247
+ downloadDebugBundle(bundle);
6248
+ }
6249
+ });
4429
6250
  let tabsInstance = null;
6251
+ const panelHeightAnimator = createPanelHeightAnimator();
4430
6252
  const panelInstance = createPanel({
4431
6253
  stateManager,
4432
6254
  storeConnector,
6255
+ namespace,
4433
6256
  onRenderContent: (container)=>{
4434
- renderContent(container, stateManager, storeConnector);
6257
+ renderContent(container);
4435
6258
  }
4436
6259
  });
4437
- function renderContent(container, stateManager, storeConnector) {
6260
+ function renderContent(container) {
6261
+ const panel = container.parentElement;
6262
+ const previousPanelHeight = panel?.getBoundingClientRect().height ?? 0;
4438
6263
  clearElement(container);
4439
6264
  const storeState = storeConnector.getState();
4440
6265
  const disabledTabs = [];
4441
6266
  if (!storeState || 'iab' !== storeState.model) disabledTabs.push('iab');
6267
+ let currentActiveTab = stateManager.getState().activeTab;
6268
+ if (disabledTabs.includes(currentActiveTab)) {
6269
+ stateManager.setActiveTab('consents');
6270
+ currentActiveTab = 'consents';
6271
+ }
4442
6272
  if (tabsInstance) tabsInstance.destroy();
4443
6273
  tabsInstance = createTabs({
4444
- activeTab: stateManager.getState().activeTab,
6274
+ activeTab: currentActiveTab,
4445
6275
  onTabChange: (tab)=>{
4446
6276
  stateManager.setActiveTab(tab);
4447
6277
  },
@@ -4456,202 +6286,9 @@ var __webpack_exports__ = {};
4456
6286
  }
4457
6287
  });
4458
6288
  container.appendChild(panelContent);
4459
- const state = stateManager.getState();
4460
- const getStoreState = ()=>storeConnector.getState();
4461
- switch(state.activeTab){
4462
- case 'consents':
4463
- renderConsentsPanel(panelContent, {
4464
- getState: getStoreState,
4465
- onConsentChange: (name, value)=>{
4466
- const store = storeConnector.getStore();
4467
- if (store) {
4468
- const consentName = String(name);
4469
- store.getState().setSelectedConsent(consentName, value);
4470
- stateManager.addEvent({
4471
- type: 'info',
4472
- message: `${consentName} toggled to ${value} (not saved)`,
4473
- data: {
4474
- name: consentName,
4475
- value
4476
- }
4477
- });
4478
- }
4479
- },
4480
- onSave: ()=>{
4481
- const store = storeConnector.getStore();
4482
- if (store) {
4483
- store.getState().saveConsents('custom');
4484
- stateManager.addEvent({
4485
- type: 'consent_save',
4486
- message: 'Saved consent preferences'
4487
- });
4488
- }
4489
- },
4490
- onAcceptAll: ()=>{
4491
- const store = storeConnector.getStore();
4492
- if (store) {
4493
- store.getState().saveConsents('all');
4494
- stateManager.addEvent({
4495
- type: 'consent_save',
4496
- message: 'Accepted all consents'
4497
- });
4498
- }
4499
- },
4500
- onRejectAll: ()=>{
4501
- const store = storeConnector.getStore();
4502
- if (store) {
4503
- store.getState().saveConsents('necessary');
4504
- stateManager.addEvent({
4505
- type: 'consent_save',
4506
- message: 'Rejected all optional consents'
4507
- });
4508
- }
4509
- },
4510
- onReset: async ()=>{
4511
- const store = storeConnector.getStore();
4512
- if (store) await resetAllConsents(store, stateManager);
4513
- }
4514
- });
4515
- break;
4516
- case 'location':
4517
- renderLocationPanel(panelContent, {
4518
- getState: getStoreState,
4519
- onSetOverrides: async (overrides)=>{
4520
- const store = storeConnector.getStore();
4521
- if (store) {
4522
- const currentOverrides = store.getState().overrides || {};
4523
- await store.getState().setOverrides({
4524
- ...currentOverrides,
4525
- ...overrides
4526
- });
4527
- stateManager.addEvent({
4528
- type: 'info',
4529
- message: 'Overrides updated',
4530
- data: overrides
4531
- });
4532
- await store.getState().initConsentManager();
4533
- stateManager.addEvent({
4534
- type: 'info',
4535
- message: 'Consent manager re-initialized with new overrides'
4536
- });
4537
- }
4538
- },
4539
- onClearOverrides: async ()=>{
4540
- const store = storeConnector.getStore();
4541
- if (store) {
4542
- await store.getState().setOverrides(void 0);
4543
- stateManager.addEvent({
4544
- type: 'info',
4545
- message: 'Overrides cleared'
4546
- });
4547
- await store.getState().initConsentManager();
4548
- stateManager.addEvent({
4549
- type: 'info',
4550
- message: 'Consent manager re-initialized'
4551
- });
4552
- }
4553
- }
4554
- });
4555
- break;
4556
- case "scripts":
4557
- renderScriptsPanel(panelContent, {
4558
- getState: getStoreState
4559
- });
4560
- break;
4561
- case 'iab':
4562
- renderIabPanel(panelContent, {
4563
- getState: getStoreState,
4564
- onReset: async ()=>{
4565
- const store = storeConnector.getStore();
4566
- if (store) await resetAllConsents(store, stateManager);
4567
- }
4568
- });
4569
- break;
4570
- case 'events':
4571
- renderEventsPanel(panelContent, {
4572
- getEvents: ()=>stateManager.getState().eventLog,
4573
- onClear: ()=>{
4574
- stateManager.clearEventLog();
4575
- stateManager.addEvent({
4576
- type: 'info',
4577
- message: 'Event log cleared'
4578
- });
4579
- }
4580
- });
4581
- break;
4582
- case 'actions':
4583
- renderActionsPanel(panelContent, {
4584
- getState: getStoreState,
4585
- onResetConsents: async ()=>{
4586
- const store = storeConnector.getStore();
4587
- if (store) await resetAllConsents(store, stateManager);
4588
- },
4589
- onRefetchBanner: async ()=>{
4590
- const store = storeConnector.getStore();
4591
- if (store) {
4592
- await store.getState().initConsentManager();
4593
- stateManager.addEvent({
4594
- type: 'info',
4595
- message: 'Banner data refetched'
4596
- });
4597
- }
4598
- },
4599
- onShowBanner: ()=>{
4600
- const store = storeConnector.getStore();
4601
- if (store) {
4602
- store.getState().setActiveUI('banner', {
4603
- force: true
4604
- });
4605
- stateManager.addEvent({
4606
- type: 'info',
4607
- message: 'Banner shown'
4608
- });
4609
- }
4610
- },
4611
- onOpenPreferences: ()=>{
4612
- const store = storeConnector.getStore();
4613
- if (store) {
4614
- store.getState().setActiveUI('dialog');
4615
- stateManager.addEvent({
4616
- type: 'info',
4617
- message: 'Preference center opened'
4618
- });
4619
- }
4620
- },
4621
- onCopyState: ()=>{
4622
- const state = storeConnector.getState();
4623
- if (state) {
4624
- const stateCopy = {
4625
- consents: state.consents,
4626
- consentInfo: state.consentInfo,
4627
- locationInfo: state.locationInfo,
4628
- model: state.model,
4629
- overrides: state.overrides,
4630
- scripts: state.scripts?.map((s)=>({
4631
- id: s.id
4632
- })),
4633
- loadedScripts: state.loadedScripts
4634
- };
4635
- navigator.clipboard.writeText(JSON.stringify(stateCopy, null, 2)).then(()=>{
4636
- stateManager.addEvent({
4637
- type: 'info',
4638
- message: 'State copied to clipboard'
4639
- });
4640
- }).catch(()=>{
4641
- stateManager.addEvent({
4642
- type: 'error',
4643
- message: 'Failed to copy state'
4644
- });
4645
- });
4646
- }
4647
- }
4648
- });
4649
- break;
4650
- }
6289
+ panelRenderer.renderPanel(panelContent, currentActiveTab);
6290
+ if (panel) panelHeightAnimator.animate(panel, previousPanelHeight);
4651
6291
  }
4652
- storeConnector.subscribe(()=>{
4653
- panelInstance.update();
4654
- });
4655
6292
  const instance = {
4656
6293
  open: ()=>stateManager.setOpen(true),
4657
6294
  close: ()=>stateManager.setOpen(false),
@@ -4665,6 +6302,9 @@ var __webpack_exports__ = {};
4665
6302
  };
4666
6303
  },
4667
6304
  destroy: ()=>{
6305
+ detachInstrumentation?.();
6306
+ detachInstrumentation = null;
6307
+ panelHeightAnimator.destroy();
4668
6308
  tabsInstance?.destroy();
4669
6309
  panelInstance.destroy();
4670
6310
  storeConnector.destroy();
@@ -4677,13 +6317,61 @@ var __webpack_exports__ = {};
4677
6317
  }
4678
6318
  function createDevToolsPanel(options) {
4679
6319
  const { namespace = 'c15tStore' } = options;
6320
+ let detachInstrumentation = null;
4680
6321
  const stateManager = createStateManager({
4681
6322
  isOpen: true
4682
6323
  });
4683
6324
  const storeConnector = createStoreConnector({
4684
6325
  namespace,
4685
- onConnect: ()=>stateManager.setConnected(true),
4686
- onDisconnect: ()=>stateManager.setConnected(false)
6326
+ onConnect: (state, store)=>{
6327
+ detachInstrumentation?.();
6328
+ detachInstrumentation = registerStoreInstrumentation({
6329
+ namespace,
6330
+ store,
6331
+ onEvent: (event)=>stateManager.addEvent(event)
6332
+ });
6333
+ stateManager.setConnected(true);
6334
+ const persistedOverrides = loadPersistedOverrides();
6335
+ if (persistedOverrides) {
6336
+ const currentOverrides = normalizeOverridesForPersistence(state.overrides);
6337
+ if (!persistedOverridesEqual(persistedOverrides, currentOverrides)) store.getState().setOverrides({
6338
+ country: persistedOverrides.country,
6339
+ region: persistedOverrides.region,
6340
+ language: persistedOverrides.language,
6341
+ gpc: persistedOverrides.gpc
6342
+ });
6343
+ }
6344
+ },
6345
+ onDisconnect: ()=>{
6346
+ stateManager.setConnected(false);
6347
+ detachInstrumentation?.();
6348
+ detachInstrumentation = null;
6349
+ }
6350
+ });
6351
+ const panelRenderer = createPanelRenderer({
6352
+ storeConnector,
6353
+ stateManager,
6354
+ enableEventLogging: false,
6355
+ onPersistOverrides: persistOverrides,
6356
+ onClearPersistedOverrides: clearPersistedOverrides,
6357
+ onCopyState: async (state)=>{
6358
+ try {
6359
+ await navigator.clipboard.writeText(JSON.stringify(createStateCopy(state), null, 2));
6360
+ return true;
6361
+ } catch {
6362
+ return false;
6363
+ }
6364
+ },
6365
+ onExportDebugBundle: ()=>{
6366
+ const bundle = createDebugBundle({
6367
+ namespace,
6368
+ devToolsState: stateManager.getState(),
6369
+ connection: storeConnector.getDiagnostics(),
6370
+ recentEvents: stateManager.getState().eventLog.slice(0, 100),
6371
+ storeState: sanitizeStoreState(storeConnector.getState())
6372
+ });
6373
+ downloadDebugBundle(bundle);
6374
+ }
4687
6375
  });
4688
6376
  const container = renderer_div({
4689
6377
  style: {
@@ -4704,108 +6392,42 @@ var __webpack_exports__ = {};
4704
6392
  }
4705
6393
  });
4706
6394
  function renderActivePanel() {
4707
- const state = stateManager.getState();
4708
- const getStoreState = ()=>storeConnector.getState();
4709
- switch(state.activeTab){
4710
- case 'consents':
4711
- renderConsentsPanel(contentArea, {
4712
- getState: getStoreState,
4713
- onConsentChange: (name, value)=>{
4714
- storeConnector.getStore()?.getState().setSelectedConsent(name, value);
4715
- },
4716
- onSave: ()=>{
4717
- storeConnector.getStore()?.getState().saveConsents('custom');
4718
- },
4719
- onAcceptAll: ()=>{
4720
- storeConnector.getStore()?.getState().saveConsents('all');
4721
- },
4722
- onRejectAll: ()=>{
4723
- storeConnector.getStore()?.getState().saveConsents('necessary');
4724
- },
4725
- onReset: async ()=>{
4726
- const store = storeConnector.getStore();
4727
- if (store) await resetAllConsents(store);
4728
- }
4729
- });
4730
- break;
4731
- case 'location':
4732
- renderLocationPanel(contentArea, {
4733
- getState: getStoreState,
4734
- onSetOverrides: async (overrides)=>{
4735
- const store = storeConnector.getStore();
4736
- if (store) {
4737
- const current = store.getState().overrides || {};
4738
- await store.getState().setOverrides({
4739
- ...current,
4740
- ...overrides
4741
- });
4742
- }
4743
- },
4744
- onClearOverrides: async ()=>{
4745
- await storeConnector.getStore()?.getState().setOverrides(void 0);
4746
- }
4747
- });
4748
- break;
4749
- case "scripts":
4750
- renderScriptsPanel(contentArea, {
4751
- getState: getStoreState
4752
- });
4753
- break;
4754
- case 'iab':
4755
- renderIabPanel(contentArea, {
4756
- getState: getStoreState,
4757
- onReset: async ()=>{
4758
- const store = storeConnector.getStore();
4759
- if (store) await resetAllConsents(store);
4760
- }
4761
- });
4762
- break;
4763
- case 'events':
4764
- renderEventsPanel(contentArea, {
4765
- getEvents: ()=>stateManager.getState().eventLog,
4766
- onClear: ()=>{
4767
- stateManager.clearEventLog();
4768
- }
4769
- });
4770
- break;
4771
- case 'actions':
4772
- renderActionsPanel(contentArea, {
4773
- getState: getStoreState,
4774
- onResetConsents: async ()=>{
4775
- const store = storeConnector.getStore();
4776
- if (store) await resetAllConsents(store);
4777
- },
4778
- onRefetchBanner: async ()=>{
4779
- await storeConnector.getStore()?.getState().initConsentManager();
4780
- },
4781
- onShowBanner: ()=>{
4782
- storeConnector.getStore()?.getState().setActiveUI('banner', {
4783
- force: true
4784
- });
4785
- },
4786
- onOpenPreferences: ()=>{
4787
- storeConnector.getStore()?.getState().setActiveUI('dialog');
4788
- },
4789
- onCopyState: ()=>{
4790
- const state = storeConnector.getState();
4791
- if (state) navigator.clipboard.writeText(JSON.stringify(state, null, 2));
4792
- }
4793
- });
4794
- break;
6395
+ const activeTab = syncTabs();
6396
+ panelRenderer.renderPanel(contentArea, activeTab);
6397
+ }
6398
+ let tabsInstance = null;
6399
+ let iabDisabled = true;
6400
+ function getDisabledTabs() {
6401
+ const disabledTabs = [];
6402
+ const storeState = storeConnector.getState();
6403
+ if (!storeState || 'iab' !== storeState.model) disabledTabs.push('iab');
6404
+ return disabledTabs;
6405
+ }
6406
+ function syncTabs() {
6407
+ const disabledTabs = getDisabledTabs();
6408
+ const nextIabDisabled = disabledTabs.includes('iab');
6409
+ let activeTab = stateManager.getState().activeTab;
6410
+ if (disabledTabs.includes(activeTab)) {
6411
+ activeTab = 'consents';
6412
+ stateManager.setActiveTab(activeTab);
4795
6413
  }
6414
+ if (tabsInstance && iabDisabled === nextIabDisabled) tabsInstance.setActiveTab(activeTab);
6415
+ else {
6416
+ tabsInstance?.destroy();
6417
+ tabsInstance = createTabs({
6418
+ activeTab,
6419
+ onTabChange: (tab)=>{
6420
+ stateManager.setActiveTab(tab);
6421
+ renderActivePanel();
6422
+ },
6423
+ disabledTabs
6424
+ });
6425
+ iabDisabled = nextIabDisabled;
6426
+ if (!tabsInstance.element.parentElement) container.appendChild(tabsInstance.element);
6427
+ }
6428
+ return activeTab;
4796
6429
  }
4797
- const storeState = storeConnector.getState();
4798
- const disabledTabs = [];
4799
- if (!storeState || 'iab' !== storeState.model) disabledTabs.push('iab');
4800
- const tabsInstance = createTabs({
4801
- activeTab: stateManager.getState().activeTab,
4802
- onTabChange: (tab)=>{
4803
- stateManager.setActiveTab(tab);
4804
- renderActivePanel();
4805
- },
4806
- disabledTabs
4807
- });
4808
- container.appendChild(tabsInstance.element);
6430
+ syncTabs();
4809
6431
  container.appendChild(contentArea);
4810
6432
  renderActivePanel();
4811
6433
  const unsubscribe = storeConnector.subscribe(()=>{
@@ -4814,8 +6436,10 @@ var __webpack_exports__ = {};
4814
6436
  return {
4815
6437
  element: container,
4816
6438
  destroy: ()=>{
6439
+ detachInstrumentation?.();
6440
+ detachInstrumentation = null;
4817
6441
  unsubscribe();
4818
- tabsInstance.destroy();
6442
+ tabsInstance?.destroy();
4819
6443
  storeConnector.destroy();
4820
6444
  stateManager.destroy();
4821
6445
  }