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

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 (42) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/__tests__/core/override-storage.test.d.ts +2 -0
  3. package/dist/__tests__/core/override-storage.test.d.ts.map +1 -0
  4. package/dist/__tests__/core/store-connector.test.d.ts +2 -0
  5. package/dist/__tests__/core/store-connector.test.d.ts.map +1 -0
  6. package/dist/__tests__/panels/events.test.d.ts +2 -0
  7. package/dist/__tests__/panels/events.test.d.ts.map +1 -0
  8. package/dist/__tests__/panels/iab.test.d.ts +2 -0
  9. package/dist/__tests__/panels/iab.test.d.ts.map +1 -0
  10. package/dist/__tests__/panels/scripts.test.d.ts +2 -0
  11. package/dist/__tests__/panels/scripts.test.d.ts.map +1 -0
  12. package/dist/__tests__/utils/preference-trigger.test.d.ts +2 -0
  13. package/dist/__tests__/utils/preference-trigger.test.d.ts.map +1 -0
  14. package/dist/components/panel.d.ts +1 -0
  15. package/dist/components/panel.d.ts.map +1 -1
  16. package/dist/core/devtools.d.ts.map +1 -1
  17. package/dist/core/override-storage.d.ts +7 -0
  18. package/dist/core/override-storage.d.ts.map +1 -0
  19. package/dist/core/panel-renderer.d.ts.map +1 -1
  20. package/dist/core/state-manager.d.ts +1 -1
  21. package/dist/core/state-manager.d.ts.map +1 -1
  22. package/dist/core/store-connector.d.ts +4 -0
  23. package/dist/core/store-connector.d.ts.map +1 -1
  24. package/dist/index.cjs +1092 -244
  25. package/dist/index.js +1092 -244
  26. package/dist/panels/dom-scanner.d.ts.map +1 -1
  27. package/dist/panels/events.d.ts.map +1 -1
  28. package/dist/panels/iab.d.ts +6 -0
  29. package/dist/panels/iab.d.ts.map +1 -1
  30. package/dist/panels/location.d.ts +9 -6
  31. package/dist/panels/location.d.ts.map +1 -1
  32. package/dist/panels/scripts.d.ts +2 -0
  33. package/dist/panels/scripts.d.ts.map +1 -1
  34. package/dist/react.cjs +1015 -237
  35. package/dist/react.js +1015 -237
  36. package/dist/tanstack.cjs +810 -201
  37. package/dist/tanstack.js +810 -201
  38. package/dist/utils/preference-trigger.d.ts +2 -2
  39. package/dist/utils/preference-trigger.d.ts.map +1 -1
  40. package/dist/version.d.ts +2 -0
  41. package/dist/version.d.ts.map +1 -0
  42. package/package.json +10 -8
package/dist/react.cjs CHANGED
@@ -346,22 +346,26 @@ var __webpack_modules__ = {
346
346
  justify-content: center;
347
347
  align-items: center;
348
348
  gap: var(--c15t-space-xs, .25rem);
349
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
350
349
  border: 1px solid var(--c15t-border, #e3e3e3);
351
350
  border-radius: var(--c15t-radius-md, .5rem);
352
351
  background-color: var(--c15t-surface, #fff);
352
+ min-height: 30px;
353
353
  color: var(--c15t-text, #171717);
354
354
  font-family: inherit;
355
- font-size: var(--c15t-devtools-font-size-xs, .75rem);
355
+ font-size: 12px;
356
356
  font-weight: var(--c15t-font-weight-medium, 500);
357
357
  cursor: pointer;
358
- 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));
358
+ 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));
359
+ padding: 5px 10px;
360
+ line-height: 1;
359
361
  display: inline-flex;
362
+ box-shadow: 0 1px 1px #0000000a;
360
363
  }
361
364
 
362
365
  .btn-evRVlh:hover {
363
366
  background-color: var(--c15t-surface-hover, #f7f7f7);
364
367
  border-color: var(--c15t-border-hover, #c9c9c9);
368
+ box-shadow: 0 2px 6px #00000014;
365
369
  }
366
370
 
367
371
  .btn-evRVlh:focus-visible {
@@ -369,9 +373,14 @@ var __webpack_modules__ = {
369
373
  outline-offset: 1px;
370
374
  }
371
375
 
376
+ .btn-evRVlh:active {
377
+ box-shadow: 0 1px 2px #00000014;
378
+ }
379
+
372
380
  .btn-evRVlh:disabled {
373
381
  opacity: .5;
374
382
  cursor: not-allowed;
383
+ box-shadow: none;
375
384
  }
376
385
 
377
386
  .btnPrimary-dA6nqY {
@@ -397,8 +406,10 @@ var __webpack_modules__ = {
397
406
  }
398
407
 
399
408
  .btnSmall-TjXoqZ {
400
- padding: 2px var(--c15t-space-xs, .25rem);
401
- font-size: 10px;
409
+ border-radius: var(--c15t-radius-sm, .375rem);
410
+ min-height: 26px;
411
+ padding: 3px 8px;
412
+ font-size: 11px;
402
413
  }
403
414
 
404
415
  .btnIcon-fiYQAh {
@@ -550,6 +561,50 @@ var __webpack_modules__ = {
550
561
  letter-spacing: .5px;
551
562
  }
552
563
 
564
+ .overrideField-keNdpJ {
565
+ flex-direction: column;
566
+ gap: 3px;
567
+ margin-bottom: 0;
568
+ display: flex;
569
+ }
570
+
571
+ .overrideLabel-ApMoTw {
572
+ color: var(--c15t-text-muted, #737373);
573
+ font-size: 11px;
574
+ font-weight: 600;
575
+ }
576
+
577
+ .overrideHint-yCfwGt {
578
+ color: var(--c15t-devtools-text-muted, #737373);
579
+ margin-top: 6px;
580
+ font-size: 11px;
581
+ }
582
+
583
+ .overrideActions-imdcn7 {
584
+ border-top: 1px dashed var(--c15t-border, #e3e3e3);
585
+ justify-content: space-between;
586
+ align-items: center;
587
+ gap: 8px;
588
+ margin-top: 8px;
589
+ padding-top: 8px;
590
+ display: flex;
591
+ }
592
+
593
+ .overrideActionButtons-gYOx1e {
594
+ flex-wrap: wrap;
595
+ gap: 6px;
596
+ display: flex;
597
+ }
598
+
599
+ .overrideStatus-sty_qS {
600
+ color: var(--c15t-text-muted, #737373);
601
+ font-size: 11px;
602
+ }
603
+
604
+ .overrideStatusDirty-OUdDMw {
605
+ color: var(--c15t-devtools-badge-warning, #f59f0a);
606
+ }
607
+
553
608
  .infoRow-RlB_0h {
554
609
  padding: var(--c15t-space-xs, .25rem) 0;
555
610
  justify-content: space-between;
@@ -642,6 +697,13 @@ var __webpack_modules__ = {
642
697
  section: "section-a197cB",
643
698
  sectionHeader: "sectionHeader-Xcljcw",
644
699
  sectionTitle: "sectionTitle-RUiFld",
700
+ overrideField: "overrideField-keNdpJ",
701
+ overrideLabel: "overrideLabel-ApMoTw",
702
+ overrideHint: "overrideHint-yCfwGt",
703
+ overrideActions: "overrideActions-imdcn7",
704
+ overrideActionButtons: "overrideActionButtons-gYOx1e",
705
+ overrideStatus: "overrideStatus-sty_qS",
706
+ overrideStatusDirty: "overrideStatusDirty-OUdDMw",
645
707
  infoRow: "infoRow-RlB_0h",
646
708
  infoLabel: "infoLabel-_pbK33",
647
709
  infoValue: "infoValue-flMl_e",
@@ -1124,16 +1186,23 @@ var __webpack_modules__ = {
1124
1186
  ___CSS_LOADER_EXPORT___.push([
1125
1187
  module.id,
1126
1188
  `.tabList-IyuiBE {
1189
+ align-items: center;
1127
1190
  gap: var(--c15t-space-xs, .25rem);
1128
- padding: var(--c15t-space-sm, .5rem) var(--c15t-space-md, 1rem);
1191
+ padding: var(--c15t-space-sm, .5rem) var(--c15t-space-sm, .5rem);
1129
1192
  border-bottom: 1px solid var(--c15t-border, #e3e3e3);
1130
1193
  background-color: var(--c15t-surface, #fff);
1131
1194
  scrollbar-width: none;
1132
1195
  -ms-overflow-style: none;
1196
+ scroll-padding-inline-end: var(--c15t-space-sm, .5rem);
1133
1197
  display: flex;
1134
1198
  overflow-x: auto;
1135
1199
  }
1136
1200
 
1201
+ .tabList-IyuiBE:after {
1202
+ content: "";
1203
+ flex: 0 0 var(--c15t-space-sm, .5rem);
1204
+ }
1205
+
1137
1206
  .tabList-IyuiBE::-webkit-scrollbar {
1138
1207
  display: none;
1139
1208
  }
@@ -1141,17 +1210,17 @@ var __webpack_modules__ = {
1141
1210
  .tab-yfDEqg {
1142
1211
  align-items: center;
1143
1212
  gap: var(--c15t-space-xs, .25rem);
1144
- padding: var(--c15t-space-xs, .25rem) var(--c15t-space-sm, .5rem);
1145
1213
  border-radius: var(--c15t-radius-md, .5rem);
1146
1214
  color: var(--c15t-text-muted, #737373);
1147
1215
  font-family: inherit;
1148
- font-size: var(--c15t-devtools-font-size-xs, .75rem);
1216
+ font-size: 11px;
1149
1217
  font-weight: var(--c15t-font-weight-medium, 500);
1150
1218
  cursor: pointer;
1151
1219
  white-space: nowrap;
1152
1220
  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));
1153
1221
  background-color: #0000;
1154
1222
  border: none;
1223
+ padding: 3px 7px;
1155
1224
  display: flex;
1156
1225
  }
1157
1226
 
@@ -1884,9 +1953,9 @@ var __webpack_exports__ = {};
1884
1953
  const elements = getPreferenceTriggerElements();
1885
1954
  for (const el of elements)el.style.display = visible ? '' : 'none';
1886
1955
  }
1887
- function getPreferenceCenterOpener() {
1956
+ function getPreferenceCenterOpener(namespace = 'c15tStore') {
1888
1957
  const win = window;
1889
- const store = win.c15tStore;
1958
+ const store = win[namespace];
1890
1959
  if (store && 'function' == typeof store.getState) {
1891
1960
  const state = store.getState();
1892
1961
  if ('function' == typeof state.setActiveUI) return ()=>{
@@ -1895,6 +1964,7 @@ var __webpack_exports__ = {};
1895
1964
  }
1896
1965
  return null;
1897
1966
  }
1967
+ const version = '2.0.0-rc.3';
1898
1968
  const DEVTOOLS_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 446 445" aria-label="c15t">
1899
1969
  <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"/>
1900
1970
  </svg>`;
@@ -2098,7 +2168,7 @@ var __webpack_exports__ = {};
2098
2168
  }
2099
2169
  }
2100
2170
  function createPanel(options) {
2101
- const { stateManager, storeConnector, onRenderContent, enableUnifiedMode = true } = options;
2171
+ const { stateManager, storeConnector, onRenderContent, namespace = 'c15tStore', enableUnifiedMode = true } = options;
2102
2172
  let removePortal = null;
2103
2173
  let isAnimatingOut = false;
2104
2174
  let draggable = null;
@@ -2127,7 +2197,7 @@ var __webpack_exports__ = {};
2127
2197
  return;
2128
2198
  }
2129
2199
  hasPreferenceTrigger = detectPreferenceTrigger();
2130
- const preferenceCenterOpener = getPreferenceCenterOpener();
2200
+ const preferenceCenterOpener = getPreferenceCenterOpener(namespace);
2131
2201
  useUnifiedMode = hasPreferenceTrigger && null !== preferenceCenterOpener;
2132
2202
  if (useUnifiedMode && !dropdownMenu) {
2133
2203
  dropdownMenu = createDropdownMenu({
@@ -2147,7 +2217,7 @@ var __webpack_exports__ = {};
2147
2217
  description: 'Open privacy settings',
2148
2218
  icon: PREFERENCES_ICON,
2149
2219
  onClick: ()=>{
2150
- const opener = getPreferenceCenterOpener();
2220
+ const opener = getPreferenceCenterOpener(namespace);
2151
2221
  if (opener) opener();
2152
2222
  }
2153
2223
  },
@@ -2203,6 +2273,7 @@ var __webpack_exports__ = {};
2203
2273
  let panelElement = null;
2204
2274
  let backdropElement = null;
2205
2275
  let contentContainer = null;
2276
+ let footerElement = null;
2206
2277
  function createPanelElement() {
2207
2278
  const corner = draggable?.getCorner() ?? stateManager.getState().position;
2208
2279
  const positionClass = getPositionClass(corner);
@@ -2254,33 +2325,53 @@ var __webpack_exports__ = {};
2254
2325
  contentContainer = renderer_div({
2255
2326
  className: styles_panel_module.content
2256
2327
  });
2257
- const isConnected = storeConnector.isConnected();
2258
- const footer = renderer_div({
2259
- className: styles_panel_module.footer,
2260
- children: [
2261
- renderer_div({
2262
- className: styles_panel_module.footerStatus,
2263
- children: [
2264
- span({
2265
- className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
2266
- }),
2267
- span({
2268
- text: isConnected ? 'Connected' : 'Disconnected'
2269
- })
2270
- ]
2271
- }),
2272
- span({
2273
- text: 'v1.8.3'
2274
- })
2275
- ]
2328
+ footerElement = renderer_div({
2329
+ className: styles_panel_module.footer
2276
2330
  });
2331
+ updateFooter();
2277
2332
  panel.appendChild(header);
2278
2333
  panel.appendChild(contentContainer);
2279
- panel.appendChild(footer);
2280
- if (isConnected) onRenderContent(contentContainer);
2334
+ panel.appendChild(footerElement);
2335
+ if (storeConnector.isConnected()) onRenderContent(contentContainer);
2281
2336
  else renderErrorState(contentContainer);
2282
2337
  return panel;
2283
2338
  }
2339
+ function updateFooter() {
2340
+ if (!footerElement) return;
2341
+ clearElement(footerElement);
2342
+ const isConnected = storeConnector.isConnected();
2343
+ const storeState = storeConnector.getState();
2344
+ const isLoading = storeState?.isLoadingConsentInfo ?? false;
2345
+ const statusChildren = [
2346
+ span({
2347
+ className: `${styles_panel_module.statusDot} ${isConnected ? styles_panel_module.statusConnected : styles_panel_module.statusDisconnected}`
2348
+ }),
2349
+ span({
2350
+ text: isConnected ? 'Connected' : 'Disconnected'
2351
+ })
2352
+ ];
2353
+ if (isLoading) statusChildren.push(span({
2354
+ style: {
2355
+ marginLeft: '4px',
2356
+ opacity: '0.7'
2357
+ },
2358
+ text: '\u00b7 Fetching /init\u2026'
2359
+ }));
2360
+ footerElement.appendChild(renderer_div({
2361
+ className: styles_panel_module.footerStatus,
2362
+ children: statusChildren
2363
+ }));
2364
+ if (!isConnected) footerElement.appendChild(renderer_button({
2365
+ className: styles_panel_module.closeButton,
2366
+ text: 'Retry',
2367
+ onClick: ()=>{
2368
+ storeConnector.retryConnection();
2369
+ }
2370
+ }));
2371
+ footerElement.appendChild(span({
2372
+ text: `v${version}`
2373
+ }));
2374
+ }
2284
2375
  function renderErrorState(container) {
2285
2376
  clearElement(container);
2286
2377
  const errorState = renderer_div({
@@ -2303,6 +2394,13 @@ var __webpack_exports__ = {};
2303
2394
  renderer_div({
2304
2395
  className: styles_panel_module.errorMessage,
2305
2396
  text: 'c15t consent manager is not initialized. Make sure you have set up the ConsentManagerProvider in your app.'
2397
+ }),
2398
+ renderer_button({
2399
+ className: styles_panel_module.closeButton,
2400
+ text: 'Retry Connection',
2401
+ onClick: ()=>{
2402
+ storeConnector.retryConnection();
2403
+ }
2306
2404
  })
2307
2405
  ]
2308
2406
  });
@@ -2338,6 +2436,7 @@ var __webpack_exports__ = {};
2338
2436
  panelElement = null;
2339
2437
  }
2340
2438
  contentContainer = null;
2439
+ footerElement = null;
2341
2440
  isAnimatingOut = false;
2342
2441
  floatingButton.style.display = '';
2343
2442
  stateManager.setOpen(false);
@@ -2356,6 +2455,7 @@ var __webpack_exports__ = {};
2356
2455
  update();
2357
2456
  });
2358
2457
  const unsubscribeStore = storeConnector.subscribe(()=>{
2458
+ updateFooter();
2359
2459
  if (contentContainer) if (storeConnector.isConnected()) onRenderContent(contentContainer);
2360
2460
  else renderErrorState(contentContainer);
2361
2461
  });
@@ -3011,13 +3111,13 @@ var __webpack_exports__ = {};
3011
3111
  },
3012
3112
  children: [
3013
3113
  createButton({
3014
- text: 'All',
3114
+ text: 'Accept',
3015
3115
  variant: 'primary',
3016
3116
  small: true,
3017
3117
  onClick: onAcceptAll
3018
3118
  }),
3019
3119
  createButton({
3020
- text: 'None',
3120
+ text: 'Reject',
3021
3121
  variant: 'default',
3022
3122
  small: true,
3023
3123
  onClick: onRejectAll
@@ -3065,16 +3165,22 @@ var __webpack_exports__ = {};
3065
3165
  function formatConsentName(name) {
3066
3166
  return name.replace(/_/g, ' ').replace(/\b\w/g, (l)=>l.toUpperCase());
3067
3167
  }
3168
+ let activeFilter = 'all';
3169
+ let selectedEventId = null;
3068
3170
  function events_renderEventsPanel(container, options) {
3069
3171
  const { getEvents, onClear } = options;
3070
3172
  clearElement(container);
3071
- const events = getEvents();
3173
+ const allEvents = getEvents();
3174
+ const events = allEvents.filter((event)=>matchesFilter(event, activeFilter));
3175
+ if (!events.some((event)=>event.id === selectedEventId)) selectedEventId = events[0]?.id ?? null;
3176
+ const selectedEvent = events.find((event)=>event.id === selectedEventId) ?? null;
3072
3177
  const header = renderer_div({
3073
3178
  style: {
3074
3179
  display: 'flex',
3075
3180
  alignItems: 'center',
3076
3181
  justifyContent: 'space-between',
3077
- padding: '12px 16px 8px'
3182
+ padding: '12px 16px 8px',
3183
+ gap: '8px'
3078
3184
  },
3079
3185
  children: [
3080
3186
  span({
@@ -3085,44 +3191,130 @@ var __webpack_exports__ = {};
3085
3191
  textTransform: 'uppercase',
3086
3192
  letterSpacing: '0.5px'
3087
3193
  },
3088
- text: `Events (${events.length})`
3194
+ text: `Events (${events.length}/${allEvents.length})`
3089
3195
  }),
3090
- createButton({
3091
- text: 'Clear',
3092
- small: true,
3093
- onClick: onClear
3196
+ renderer_div({
3197
+ style: {
3198
+ display: 'flex',
3199
+ gap: '6px'
3200
+ },
3201
+ children: [
3202
+ createButton({
3203
+ text: 'Export',
3204
+ small: true,
3205
+ onClick: ()=>exportEvents(allEvents)
3206
+ }),
3207
+ createButton({
3208
+ text: 'Clear',
3209
+ small: true,
3210
+ onClick: ()=>{
3211
+ onClear();
3212
+ selectedEventId = null;
3213
+ events_renderEventsPanel(container, options);
3214
+ }
3215
+ })
3216
+ ]
3094
3217
  })
3095
3218
  ]
3096
3219
  });
3097
3220
  container.appendChild(header);
3221
+ container.appendChild(renderer_div({
3222
+ style: {
3223
+ display: 'flex',
3224
+ flexWrap: 'wrap',
3225
+ gap: '6px',
3226
+ padding: '0 16px 8px'
3227
+ },
3228
+ children: EVENT_FILTERS.map((filter)=>createFilterButton(filter, filter === activeFilter, ()=>{
3229
+ activeFilter = filter;
3230
+ selectedEventId = null;
3231
+ events_renderEventsPanel(container, options);
3232
+ }))
3233
+ }));
3098
3234
  const eventList = renderer_div({
3099
3235
  style: {
3100
3236
  display: 'flex',
3101
3237
  flexDirection: 'column',
3102
3238
  gap: '4px',
3103
3239
  padding: '0 12px 12px',
3104
- maxHeight: '400px',
3240
+ maxHeight: '300px',
3105
3241
  overflowY: 'auto'
3106
3242
  }
3107
3243
  });
3108
- if (0 === events.length) {
3109
- const emptyState = renderer_div({
3110
- style: {
3111
- padding: '32px 16px',
3112
- textAlign: 'center',
3113
- color: 'var(--c15t-text-muted)',
3114
- fontSize: 'var(--c15t-devtools-font-size-sm)'
3115
- },
3116
- text: 'No events recorded yet'
3117
- });
3118
- eventList.appendChild(emptyState);
3119
- } else for (const event of events){
3120
- const eventItem = createEventItem(event);
3121
- eventList.appendChild(eventItem);
3122
- }
3244
+ if (0 === events.length) eventList.appendChild(renderer_div({
3245
+ style: {
3246
+ padding: '20px 16px',
3247
+ textAlign: 'center',
3248
+ color: 'var(--c15t-text-muted)',
3249
+ fontSize: 'var(--c15t-devtools-font-size-sm)'
3250
+ },
3251
+ text: 'No events match this filter'
3252
+ }));
3253
+ else for (const event of events)eventList.appendChild(createEventItem(event, event.id === selectedEventId, ()=>{
3254
+ selectedEventId = event.id;
3255
+ events_renderEventsPanel(container, options);
3256
+ }));
3123
3257
  container.appendChild(eventList);
3258
+ container.appendChild(createPayloadSection(selectedEvent));
3259
+ }
3260
+ const EVENT_FILTERS = [
3261
+ 'all',
3262
+ 'error',
3263
+ 'consent',
3264
+ 'network',
3265
+ 'iab'
3266
+ ];
3267
+ function createFilterButton(filter, active, onClick) {
3268
+ return createButton({
3269
+ text: filter.toUpperCase(),
3270
+ small: true,
3271
+ variant: active ? 'primary' : 'default',
3272
+ onClick
3273
+ });
3274
+ }
3275
+ function matchesFilter(event, filter) {
3276
+ if ('all' === filter) return true;
3277
+ if ('error' === filter) return 'error' === event.type;
3278
+ if ('consent' === filter) return 'consent_set' === event.type || 'consent_save' === event.type || 'consent_reset' === event.type;
3279
+ if ('network' === filter) return 'network' === event.type;
3280
+ return 'iab' === event.type;
3281
+ }
3282
+ function createPayloadSection(event) {
3283
+ const payload = event?.data ? JSON.stringify(event.data, null, 2) : null;
3284
+ return renderer_div({
3285
+ style: {
3286
+ padding: '0 12px 12px'
3287
+ },
3288
+ children: [
3289
+ renderer_div({
3290
+ style: {
3291
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
3292
+ fontWeight: '600',
3293
+ color: 'var(--c15t-text-muted)',
3294
+ textTransform: 'uppercase',
3295
+ letterSpacing: '0.5px',
3296
+ marginBottom: '6px'
3297
+ },
3298
+ text: 'Payload'
3299
+ }),
3300
+ renderer_div({
3301
+ className: styles_components_module.gridCard ?? '',
3302
+ style: {
3303
+ padding: '8px',
3304
+ fontFamily: 'ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace',
3305
+ fontSize: '11px',
3306
+ color: 'var(--c15t-text-muted)',
3307
+ maxHeight: '140px',
3308
+ overflowY: 'auto',
3309
+ whiteSpace: 'pre-wrap',
3310
+ wordBreak: 'break-word'
3311
+ },
3312
+ text: payload || 'Select an event with payload data'
3313
+ })
3314
+ ]
3315
+ });
3124
3316
  }
3125
- function createEventItem(event) {
3317
+ function createEventItem(event, selected, onSelect) {
3126
3318
  const time = formatTime(event.timestamp);
3127
3319
  const icon = getEventIcon(event.type);
3128
3320
  const color = getEventColor(event.type);
@@ -3133,8 +3325,11 @@ var __webpack_exports__ = {};
3133
3325
  alignItems: 'center',
3134
3326
  gap: '8px',
3135
3327
  padding: '6px 10px',
3136
- fontSize: 'var(--c15t-devtools-font-size-xs)'
3328
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
3329
+ cursor: 'pointer',
3330
+ borderColor: selected ? 'var(--c15t-devtools-badge-info, #3b82f6)' : 'var(--c15t-border)'
3137
3331
  },
3332
+ onClick: onSelect,
3138
3333
  children: [
3139
3334
  span({
3140
3335
  style: {
@@ -3163,6 +3358,21 @@ var __webpack_exports__ = {};
3163
3358
  ]
3164
3359
  });
3165
3360
  }
3361
+ function exportEvents(events) {
3362
+ const json = JSON.stringify(events, null, 2);
3363
+ const blob = new Blob([
3364
+ json
3365
+ ], {
3366
+ type: 'application/json'
3367
+ });
3368
+ const url = URL.createObjectURL(blob);
3369
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
3370
+ const a = document.createElement('a');
3371
+ a.href = url;
3372
+ a.download = `c15t-events-${timestamp}.json`;
3373
+ a.click();
3374
+ URL.revokeObjectURL(url);
3375
+ }
3166
3376
  function formatTime(timestamp) {
3167
3377
  const date = new Date(timestamp);
3168
3378
  return date.toLocaleTimeString('en-US', {
@@ -3181,7 +3391,10 @@ var __webpack_exports__ = {};
3181
3391
  return '○';
3182
3392
  case 'error':
3183
3393
  return '✕';
3184
- case 'info':
3394
+ case 'network':
3395
+ return '◉';
3396
+ case 'iab':
3397
+ return '◆';
3185
3398
  default:
3186
3399
  return '○';
3187
3400
  }
@@ -3195,13 +3408,16 @@ var __webpack_exports__ = {};
3195
3408
  return 'var(--c15t-devtools-badge-warning, #f59e0b)';
3196
3409
  case 'error':
3197
3410
  return 'var(--c15t-devtools-badge-error, #ef4444)';
3198
- case 'info':
3411
+ case 'network':
3412
+ return 'var(--c15t-devtools-badge-warning, #f59e0b)';
3413
+ case 'iab':
3414
+ return 'var(--c15t-devtools-badge-info, #3b82f6)';
3199
3415
  default:
3200
3416
  return 'var(--c15t-text-muted)';
3201
3417
  }
3202
3418
  }
3203
3419
  function iab_renderIabPanel(container, options) {
3204
- const { getState, onReset } = options;
3420
+ const { getState, onSetPurposeConsent, onSetVendorConsent, onSetSpecialFeatureOptIn, onAcceptAll, onRejectAll, onSave, onReset } = options;
3205
3421
  clearElement(container);
3206
3422
  const state = getState();
3207
3423
  if (!state) return void container.appendChild(renderer_div({
@@ -3279,7 +3495,9 @@ var __webpack_exports__ = {};
3279
3495
  for (const [purposeId, consent] of purposeEntries){
3280
3496
  const purposeInfo = purposes[purposeId];
3281
3497
  const purposeName = purposeInfo?.name || `Purpose ${purposeId}`;
3282
- purposeList.appendChild(createPurposeRow(purposeId, purposeName, Boolean(consent)));
3498
+ purposeList.appendChild(createPurposeRow(purposeId, purposeName, Boolean(consent), (value)=>{
3499
+ onSetPurposeConsent(Number(purposeId), value);
3500
+ }));
3283
3501
  }
3284
3502
  const purposesSection = createSection({
3285
3503
  title: `Purposes (${purposeEntries.length})`,
@@ -3305,7 +3523,9 @@ var __webpack_exports__ = {};
3305
3523
  for (const [featureId, optIn] of specialFeatureEntries){
3306
3524
  const featureInfo = specialFeatures[featureId];
3307
3525
  const featureName = featureInfo?.name || `Special Feature ${featureId}`;
3308
- specialFeatureList.appendChild(createPurposeRow(featureId, featureName, Boolean(optIn)));
3526
+ specialFeatureList.appendChild(createPurposeRow(featureId, featureName, Boolean(optIn), (value)=>{
3527
+ onSetSpecialFeatureOptIn(Number(featureId), value);
3528
+ }, 'feature'));
3309
3529
  }
3310
3530
  const specialFeaturesSection = createSection({
3311
3531
  title: `Special Features (${specialFeatureEntries.length})`,
@@ -3345,7 +3565,9 @@ var __webpack_exports__ = {};
3345
3565
  overflowY: 'auto'
3346
3566
  }
3347
3567
  });
3348
- for (const [vendorId, consent, vendorName] of iabVendors)vendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'iab'));
3568
+ for (const [vendorId, consent, vendorName] of iabVendors)vendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'iab', (value)=>{
3569
+ onSetVendorConsent(Number(vendorId), value);
3570
+ }));
3349
3571
  const vendorsSection = createSection({
3350
3572
  title: `IAB Vendors (${iabVendors.length})`,
3351
3573
  children: [
@@ -3364,7 +3586,9 @@ var __webpack_exports__ = {};
3364
3586
  overflowY: 'auto'
3365
3587
  }
3366
3588
  });
3367
- for (const [vendorId, consent, vendorName] of customVendors)customVendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'custom'));
3589
+ for (const [vendorId, consent, vendorName] of customVendors)customVendorList.appendChild(createVendorRow(vendorId, vendorName, consent, 'custom', (value)=>{
3590
+ onSetVendorConsent(vendorId, value);
3591
+ }));
3368
3592
  const customVendorsSection = createSection({
3369
3593
  title: `Custom Vendors (${customVendors.length})`,
3370
3594
  children: [
@@ -3386,15 +3610,40 @@ var __webpack_exports__ = {};
3386
3610
  style: {
3387
3611
  display: 'flex',
3388
3612
  alignItems: 'center',
3389
- justifyContent: 'flex-end',
3613
+ justifyContent: 'space-between',
3390
3614
  padding: '12px 16px',
3391
3615
  marginTop: 'auto',
3392
3616
  borderTop: '1px solid var(--c15t-border)',
3393
3617
  backgroundColor: 'var(--c15t-surface)'
3394
3618
  },
3395
3619
  children: [
3620
+ renderer_div({
3621
+ style: {
3622
+ display: 'flex',
3623
+ gap: '6px'
3624
+ },
3625
+ children: [
3626
+ createButton({
3627
+ text: 'Accept All',
3628
+ variant: 'primary',
3629
+ small: true,
3630
+ onClick: onAcceptAll
3631
+ }),
3632
+ createButton({
3633
+ text: 'Reject All',
3634
+ small: true,
3635
+ onClick: onRejectAll
3636
+ }),
3637
+ createButton({
3638
+ text: 'Save',
3639
+ variant: 'primary',
3640
+ small: true,
3641
+ onClick: onSave
3642
+ })
3643
+ ]
3644
+ }),
3396
3645
  createButton({
3397
- text: 'Reset All',
3646
+ text: 'Reset',
3398
3647
  variant: 'danger',
3399
3648
  small: true,
3400
3649
  onClick: onReset
@@ -3403,7 +3652,7 @@ var __webpack_exports__ = {};
3403
3652
  });
3404
3653
  container.appendChild(footer);
3405
3654
  }
3406
- function createPurposeRow(id, name, consent) {
3655
+ function createPurposeRow(id, name, consent, onChange, ariaKind = 'purpose') {
3407
3656
  return renderer_div({
3408
3657
  style: {
3409
3658
  display: 'flex',
@@ -3426,14 +3675,28 @@ var __webpack_exports__ = {};
3426
3675
  text: `${id}. ${name}`,
3427
3676
  title: name
3428
3677
  }),
3429
- createBadge({
3430
- text: consent ? '✓' : '✕',
3431
- variant: consent ? 'success' : 'error'
3678
+ renderer_div({
3679
+ style: {
3680
+ display: 'flex',
3681
+ alignItems: 'center',
3682
+ gap: '6px'
3683
+ },
3684
+ children: [
3685
+ createBadge({
3686
+ text: consent ? '✓' : '✕',
3687
+ variant: consent ? 'success' : 'error'
3688
+ }),
3689
+ createToggle({
3690
+ checked: consent,
3691
+ onChange,
3692
+ ariaLabel: `Toggle ${ariaKind} ${id}`
3693
+ })
3694
+ ]
3432
3695
  })
3433
3696
  ]
3434
3697
  });
3435
3698
  }
3436
- function createVendorRow(id, name, consent, type) {
3699
+ function createVendorRow(id, name, consent, type, onChange) {
3437
3700
  return renderer_div({
3438
3701
  style: {
3439
3702
  display: 'flex',
@@ -3480,16 +3743,21 @@ var __webpack_exports__ = {};
3480
3743
  createBadge({
3481
3744
  text: consent ? '✓' : '✕',
3482
3745
  variant: consent ? 'success' : 'error'
3746
+ }),
3747
+ createToggle({
3748
+ checked: consent,
3749
+ onChange,
3750
+ ariaLabel: `Toggle vendor ${id}`
3483
3751
  })
3484
3752
  ]
3485
3753
  });
3486
3754
  }
3487
3755
  function truncateText(text, maxLength) {
3488
3756
  if (text.length <= maxLength) return text;
3489
- return text.slice(0, maxLength - 3) + '...';
3757
+ return `${text.slice(0, maxLength - 3)}...`;
3490
3758
  }
3491
3759
  function location_renderLocationPanel(container, options) {
3492
- const { getState, onSetOverrides, onClearOverrides } = options;
3760
+ const { getState, onApplyOverrides, onClearOverrides } = options;
3493
3761
  clearElement(container);
3494
3762
  const state = getState();
3495
3763
  if (!state) return void container.appendChild(renderer_div({
@@ -3510,145 +3778,230 @@ var __webpack_exports__ = {};
3510
3778
  createCompactInfoCard('Jurisdiction', locationInfo?.jurisdiction || '—'),
3511
3779
  createCompactInfoCard('Language', translationConfig?.defaultLanguage || '—')
3512
3780
  ];
3781
+ gridItems.push(createCompactInfoCard('GPC', getEffectiveGpcLabel(overrides?.gpc)));
3513
3782
  if (state.model) gridItems.push(createCompactInfoCard('Model', getModelLabel(state.model)));
3514
3783
  const locationGrid = createGrid({
3515
- columns: 2,
3784
+ columns: 3,
3516
3785
  children: gridItems
3517
3786
  });
3518
3787
  container.appendChild(locationGrid);
3788
+ const initialDraft = getDraftFromOverrides(overrides);
3789
+ let appliedOverrides = normalizeOverrideDraft(initialDraft);
3790
+ let isSubmitting = false;
3791
+ const countryField = createOverrideSelect({
3792
+ label: 'Country',
3793
+ selectOptions: COUNTRY_OPTIONS,
3794
+ value: initialDraft.country
3795
+ });
3796
+ const regionField = createOverrideInput({
3797
+ label: 'Region',
3798
+ placeholder: 'e.g., CA, NY, BE',
3799
+ value: initialDraft.region
3800
+ });
3801
+ const languageField = createOverrideInput({
3802
+ label: 'Language',
3803
+ placeholder: 'e.g., de, fr, en-US',
3804
+ value: initialDraft.language
3805
+ });
3806
+ const gpcField = createOverrideSelect({
3807
+ label: 'GPC',
3808
+ selectOptions: GPC_OPTIONS,
3809
+ value: initialDraft.gpc
3810
+ });
3811
+ const formStatus = span({
3812
+ className: styles_components_module.overrideStatus,
3813
+ text: 'In sync'
3814
+ });
3815
+ const applyButton = createButton({
3816
+ text: 'Apply',
3817
+ variant: 'primary',
3818
+ small: true,
3819
+ disabled: true,
3820
+ onClick: ()=>{
3821
+ applyDraft();
3822
+ }
3823
+ });
3824
+ const revertButton = createButton({
3825
+ text: 'Revert',
3826
+ small: true,
3827
+ disabled: true,
3828
+ onClick: ()=>{
3829
+ setDraftValues(getDraftFromOverrides(appliedOverrides));
3830
+ updateFormState();
3831
+ }
3832
+ });
3833
+ const clearButton = createButton({
3834
+ text: 'Clear',
3835
+ small: true,
3836
+ onClick: ()=>{
3837
+ clearDraftAndOverrides();
3838
+ }
3839
+ });
3840
+ const overrideFieldsGrid = renderer_div({
3841
+ style: {
3842
+ display: 'grid',
3843
+ gridTemplateColumns: 'repeat(2, minmax(0, 1fr))',
3844
+ gap: '8px 10px'
3845
+ },
3846
+ children: [
3847
+ countryField.element,
3848
+ regionField.element,
3849
+ languageField.element,
3850
+ gpcField.element
3851
+ ]
3852
+ });
3519
3853
  const overrideSection = createSection({
3520
3854
  title: 'Override Settings',
3521
- actions: [
3522
- createButton({
3523
- text: 'Clear',
3524
- small: true,
3525
- onClick: onClearOverrides
3526
- })
3527
- ],
3528
3855
  children: [
3529
- createOverrideSelect({
3530
- label: 'Country',
3531
- selectOptions: COUNTRY_OPTIONS,
3532
- value: overrides?.country || '',
3533
- onChange: (value)=>onSetOverrides({
3534
- country: value || void 0
3535
- })
3536
- }),
3537
- createOverrideInput({
3538
- label: 'Region',
3539
- placeholder: 'e.g., CA, NY, BE',
3540
- value: overrides?.region || '',
3541
- onChange: (value)=>onSetOverrides({
3542
- region: value || void 0
3543
- })
3856
+ overrideFieldsGrid,
3857
+ span({
3858
+ className: styles_components_module.overrideHint,
3859
+ text: 'GPC override only affects opt-out or unregulated jurisdictions.'
3544
3860
  }),
3545
- createOverrideInput({
3546
- label: 'Language',
3547
- placeholder: 'e.g., de, fr, en',
3548
- value: overrides?.language || '',
3549
- onChange: (value)=>onSetOverrides({
3550
- language: value || void 0
3551
- })
3861
+ renderer_div({
3862
+ className: styles_components_module.overrideActions,
3863
+ children: [
3864
+ renderer_div({
3865
+ className: styles_components_module.overrideActionButtons,
3866
+ children: [
3867
+ revertButton,
3868
+ applyButton,
3869
+ clearButton
3870
+ ]
3871
+ }),
3872
+ formStatus
3873
+ ]
3552
3874
  })
3553
3875
  ]
3554
3876
  });
3555
3877
  container.appendChild(overrideSection);
3556
- const hasOverrides = overrides && (overrides.country || overrides.region || overrides.language);
3557
- if (hasOverrides) {
3558
- const overrideBanner = renderer_div({
3559
- style: {
3560
- padding: '8px 16px',
3561
- backgroundColor: 'var(--c15t-devtools-badge-info-bg)',
3562
- color: 'var(--c15t-devtools-badge-info)',
3563
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3564
- borderTop: '1px solid var(--c15t-devtools-border)'
3565
- },
3566
- text: 'Overrides are active. This may affect consent behavior.'
3878
+ countryField.control.addEventListener('change', updateFormState);
3879
+ regionField.control.addEventListener('input', updateFormState);
3880
+ languageField.control.addEventListener('input', updateFormState);
3881
+ gpcField.control.addEventListener('change', updateFormState);
3882
+ updateFormState();
3883
+ async function applyDraft() {
3884
+ if (isSubmitting) return;
3885
+ const draftOverrides = getDraftOverrides();
3886
+ if (overridesEqual(draftOverrides, appliedOverrides)) return;
3887
+ isSubmitting = true;
3888
+ updateFormState();
3889
+ try {
3890
+ await onApplyOverrides(draftOverrides);
3891
+ appliedOverrides = draftOverrides;
3892
+ } finally{
3893
+ isSubmitting = false;
3894
+ updateFormState();
3895
+ }
3896
+ }
3897
+ async function clearDraftAndOverrides() {
3898
+ if (isSubmitting) return;
3899
+ isSubmitting = true;
3900
+ updateFormState();
3901
+ try {
3902
+ await onClearOverrides();
3903
+ appliedOverrides = {};
3904
+ setDraftValues(getDraftFromOverrides(void 0));
3905
+ } finally{
3906
+ isSubmitting = false;
3907
+ updateFormState();
3908
+ }
3909
+ }
3910
+ function getDraftOverrides() {
3911
+ return normalizeOverrideDraft({
3912
+ country: countryField.control.value,
3913
+ region: regionField.control.value,
3914
+ language: languageField.control.value,
3915
+ gpc: gpcField.control.value
3567
3916
  });
3568
- container.appendChild(overrideBanner);
3917
+ }
3918
+ function setDraftValues(draft) {
3919
+ countryField.control.value = draft.country;
3920
+ regionField.control.value = draft.region;
3921
+ languageField.control.value = draft.language;
3922
+ gpcField.control.value = draft.gpc;
3923
+ }
3924
+ function updateFormState() {
3925
+ const draftOverrides = getDraftOverrides();
3926
+ const hasDraftChanges = !overridesEqual(draftOverrides, appliedOverrides);
3927
+ applyButton.disabled = !hasDraftChanges || isSubmitting;
3928
+ revertButton.disabled = !hasDraftChanges || isSubmitting;
3929
+ clearButton.disabled = isSubmitting;
3930
+ formStatus.textContent = isSubmitting ? 'Applying...' : hasDraftChanges ? 'Unsaved changes' : hasOverridesValue(appliedOverrides) ? 'Overrides active' : 'No overrides';
3931
+ if (styles_components_module.overrideStatusDirty) formStatus.classList.toggle(styles_components_module.overrideStatusDirty, !isSubmitting && hasDraftChanges);
3569
3932
  }
3570
3933
  }
3571
3934
  function createOverrideInput(options) {
3572
- const { label, placeholder, value, onChange } = options;
3573
- let debounceTimer = null;
3935
+ const { label, placeholder, value } = options;
3574
3936
  const inputField = input({
3575
3937
  className: `${styles_components_module.input ?? ''} ${styles_components_module.inputSmall ?? ''}`.trim(),
3576
3938
  placeholder,
3577
- value,
3578
- onInput: (e)=>{
3579
- const target = e.target;
3580
- if (debounceTimer) clearTimeout(debounceTimer);
3581
- debounceTimer = setTimeout(()=>{
3582
- onChange(target.value);
3583
- }, 500);
3584
- }
3585
- });
3586
- return renderer_div({
3587
- style: {
3588
- display: 'flex',
3589
- alignItems: 'center',
3590
- justifyContent: 'space-between',
3591
- gap: '8px',
3592
- marginBottom: '8px'
3593
- },
3594
- children: [
3595
- renderer_div({
3596
- style: {
3597
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3598
- color: 'var(--c15t-devtools-text-muted)',
3599
- minWidth: '60px'
3600
- },
3601
- text: label
3602
- }),
3603
- renderer_div({
3604
- style: {
3605
- flex: '1'
3606
- },
3607
- children: [
3608
- inputField
3609
- ]
3610
- })
3611
- ]
3939
+ value
3612
3940
  });
3941
+ return {
3942
+ element: renderer_div({
3943
+ className: styles_components_module.overrideField,
3944
+ children: [
3945
+ span({
3946
+ className: styles_components_module.overrideLabel,
3947
+ text: label
3948
+ }),
3949
+ inputField
3950
+ ]
3951
+ }),
3952
+ control: inputField
3953
+ };
3613
3954
  }
3614
3955
  function createOverrideSelect(options) {
3615
- const { label, selectOptions, value, onChange } = options;
3956
+ const { label, selectOptions, value } = options;
3616
3957
  const selectField = renderer_select({
3617
3958
  className: `${styles_components_module.input ?? ''} ${styles_components_module.inputSmall ?? ''}`.trim(),
3618
3959
  options: selectOptions,
3619
- selectedValue: value,
3620
- onChange: (e)=>{
3621
- const target = e.target;
3622
- onChange(target.value);
3623
- }
3624
- });
3625
- return renderer_div({
3626
- style: {
3627
- display: 'flex',
3628
- alignItems: 'center',
3629
- justifyContent: 'space-between',
3630
- gap: '8px',
3631
- marginBottom: '8px'
3632
- },
3633
- children: [
3634
- renderer_div({
3635
- style: {
3636
- fontSize: 'var(--c15t-devtools-font-size-xs)',
3637
- color: 'var(--c15t-devtools-text-muted)',
3638
- minWidth: '60px'
3639
- },
3640
- text: label
3641
- }),
3642
- renderer_div({
3643
- style: {
3644
- flex: '1'
3645
- },
3646
- children: [
3647
- selectField
3648
- ]
3649
- })
3650
- ]
3960
+ selectedValue: value
3651
3961
  });
3962
+ return {
3963
+ element: renderer_div({
3964
+ className: styles_components_module.overrideField,
3965
+ children: [
3966
+ span({
3967
+ className: styles_components_module.overrideLabel,
3968
+ text: label
3969
+ }),
3970
+ selectField
3971
+ ]
3972
+ }),
3973
+ control: selectField
3974
+ };
3975
+ }
3976
+ function getDraftFromOverrides(overrides) {
3977
+ return {
3978
+ country: overrides?.country ?? '',
3979
+ region: overrides?.region ?? '',
3980
+ language: overrides?.language ?? '',
3981
+ gpc: overrides?.gpc === true ? 'true' : overrides?.gpc === false ? 'false' : ''
3982
+ };
3983
+ }
3984
+ function normalizeOverrideDraft(draft) {
3985
+ return {
3986
+ country: normalizeAlphaCode(draft.country),
3987
+ region: normalizeAlphaCode(draft.region),
3988
+ language: normalizeLanguageCode(draft.language),
3989
+ gpc: 'true' === draft.gpc ? true : 'false' === draft.gpc ? false : void 0
3990
+ };
3991
+ }
3992
+ function normalizeAlphaCode(value) {
3993
+ const normalized = value.trim().toUpperCase();
3994
+ return normalized || void 0;
3995
+ }
3996
+ function normalizeLanguageCode(value) {
3997
+ const normalized = value.trim();
3998
+ return normalized || void 0;
3999
+ }
4000
+ function overridesEqual(a, b) {
4001
+ return a.country === b.country && a.region === b.region && a.language === b.language && a.gpc === b.gpc;
4002
+ }
4003
+ function hasOverridesValue(overrides) {
4004
+ return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
3652
4005
  }
3653
4006
  const COUNTRY_OPTIONS = [
3654
4007
  {
@@ -3772,6 +4125,32 @@ var __webpack_exports__ = {};
3772
4125
  label: 'ZA - South Africa'
3773
4126
  }
3774
4127
  ];
4128
+ const GPC_OPTIONS = [
4129
+ {
4130
+ value: '',
4131
+ label: '-- Browser Default --'
4132
+ },
4133
+ {
4134
+ value: 'true',
4135
+ label: 'Force On (Simulated)'
4136
+ },
4137
+ {
4138
+ value: 'false',
4139
+ label: 'Force Off (Simulated)'
4140
+ }
4141
+ ];
4142
+ function getEffectiveGpcLabel(gpcOverride) {
4143
+ if (true === gpcOverride) return 'On (Override)';
4144
+ if (false === gpcOverride) return 'Off (Override)';
4145
+ if ('undefined' == typeof window || 'undefined' == typeof navigator) return 'Unknown';
4146
+ try {
4147
+ const nav = navigator;
4148
+ const value = nav.globalPrivacyControl;
4149
+ return true === value || '1' === value ? 'Active' : 'Inactive';
4150
+ } catch {
4151
+ return 'Unknown';
4152
+ }
4153
+ }
3775
4154
  function getModelLabel(model) {
3776
4155
  switch(model){
3777
4156
  case 'opt-in':
@@ -3788,9 +4167,11 @@ var __webpack_exports__ = {};
3788
4167
  return renderer_div({
3789
4168
  className: styles_components_module.gridCard ?? '',
3790
4169
  style: {
4170
+ padding: '6px 8px',
4171
+ minHeight: 'auto',
3791
4172
  flexDirection: 'column',
3792
4173
  alignItems: 'flex-start',
3793
- gap: '2px'
4174
+ gap: '1px'
3794
4175
  },
3795
4176
  children: [
3796
4177
  span({
@@ -3815,34 +4196,38 @@ var __webpack_exports__ = {};
3815
4196
  function scanDOM(state) {
3816
4197
  const results = [];
3817
4198
  const configuredScripts = state.scripts || [];
3818
- const managedDomains = new Map();
4199
+ const managedResources = [];
3819
4200
  for (const script of configuredScripts)if (script.src) try {
3820
4201
  const url = new URL(script.src, window.location.origin);
3821
- if (url.hostname !== window.location.hostname) managedDomains.set(url.hostname, script.id);
4202
+ if (url.hostname !== window.location.hostname) managedResources.push({
4203
+ scriptId: script.id,
4204
+ domain: url.hostname,
4205
+ pathPrefix: normalizePathname(url.pathname)
4206
+ });
3822
4207
  } catch {}
3823
4208
  const scriptElements = document.querySelectorAll("script[src]");
3824
4209
  for (const el of scriptElements){
3825
4210
  const src = el.getAttribute('src');
3826
4211
  if (!src) continue;
3827
- const resource = checkResource(src, "script", managedDomains);
4212
+ const resource = checkResource(src, "script", managedResources);
3828
4213
  if (resource) results.push(resource);
3829
4214
  }
3830
4215
  const iframeElements = document.querySelectorAll('iframe[src]');
3831
4216
  for (const el of iframeElements){
3832
4217
  const src = el.getAttribute('src');
3833
4218
  if (!src) continue;
3834
- const resource = checkResource(src, 'iframe', managedDomains);
4219
+ const resource = checkResource(src, 'iframe', managedResources);
3835
4220
  if (resource) results.push(resource);
3836
4221
  }
3837
4222
  return results;
3838
4223
  }
3839
- function checkResource(src, type, managedDomains) {
4224
+ function checkResource(src, type, managedResources) {
3840
4225
  try {
3841
4226
  const url = new URL(src, window.location.origin);
3842
4227
  const domain = url.hostname;
3843
4228
  if (domain === window.location.hostname) return null;
3844
4229
  if ('data:' === url.protocol || 'blob:' === url.protocol) return null;
3845
- const managedBy = managedDomains.get(domain);
4230
+ const managedBy = findManagedScriptId(url, managedResources);
3846
4231
  const isManaged = Boolean(managedBy);
3847
4232
  return {
3848
4233
  type,
@@ -3854,6 +4239,21 @@ var __webpack_exports__ = {};
3854
4239
  } catch {}
3855
4240
  return null;
3856
4241
  }
4242
+ function findManagedScriptId(url, managedResources) {
4243
+ const domain = url.hostname;
4244
+ const path = normalizePathname(url.pathname);
4245
+ let bestMatch = null;
4246
+ for (const matcher of managedResources)if (matcher.domain === domain) {
4247
+ if ('/' === matcher.pathPrefix || path.startsWith(matcher.pathPrefix)) {
4248
+ if (!bestMatch || matcher.pathPrefix.length > bestMatch.pathPrefix.length) bestMatch = matcher;
4249
+ }
4250
+ }
4251
+ return bestMatch?.scriptId;
4252
+ }
4253
+ function normalizePathname(pathname) {
4254
+ const trimmed = pathname.trim();
4255
+ return trimmed.length > 0 ? trimmed : '/';
4256
+ }
3857
4257
  function createDomScannerSection(state) {
3858
4258
  let resultsContainer = null;
3859
4259
  let lastScanResults = [];
@@ -4018,7 +4418,7 @@ var __webpack_exports__ = {};
4018
4418
  <polyline points="8 6 2 12 8 18"></polyline>
4019
4419
  </svg>`;
4020
4420
  function scripts_renderScriptsPanel(container, options) {
4021
- const { getState } = options;
4421
+ const { getState, getEvents } = options;
4022
4422
  clearElement(container);
4023
4423
  const state = getState();
4024
4424
  if (!state) return void container.appendChild(renderer_div({
@@ -4033,6 +4433,7 @@ var __webpack_exports__ = {};
4033
4433
  const scripts = state.scripts || [];
4034
4434
  const loadedScripts = state.loadedScripts || {};
4035
4435
  const networkBlocker = state.networkBlocker;
4436
+ const events = getEvents?.() ?? [];
4036
4437
  if (0 === scripts.length) {
4037
4438
  const scriptsSection = createSection({
4038
4439
  title: 'Configured Scripts',
@@ -4115,6 +4516,20 @@ var __webpack_exports__ = {};
4115
4516
  ]
4116
4517
  });
4117
4518
  container.appendChild(networkSection);
4519
+ const blockedRequestEvents = events.filter((event)=>'network' === event.type);
4520
+ const networkEventsSection = createSection({
4521
+ title: `Blocked Requests (${blockedRequestEvents.length})`,
4522
+ children: 0 === blockedRequestEvents.length ? [
4523
+ renderer_div({
4524
+ style: {
4525
+ fontSize: 'var(--c15t-devtools-font-size-xs)',
4526
+ color: 'var(--c15t-devtools-text-muted)'
4527
+ },
4528
+ text: 'No blocked network requests recorded in this session'
4529
+ })
4530
+ ] : createBlockedRequestContent(blockedRequestEvents)
4531
+ });
4532
+ container.appendChild(networkEventsSection);
4118
4533
  const loadedCount = Object.values(loadedScripts).filter(Boolean).length;
4119
4534
  const totalCount = scripts.length;
4120
4535
  const summarySection = createSection({
@@ -4140,12 +4555,127 @@ var __webpack_exports__ = {};
4140
4555
  }
4141
4556
  function checkScriptConsent(state, category) {
4142
4557
  if (!category) return true;
4558
+ if ('function' == typeof state.has) try {
4559
+ return state.has(category);
4560
+ } catch {}
4143
4561
  if ('string' == typeof category) {
4144
4562
  const consents = state.consents || {};
4145
4563
  return true === consents[category];
4146
4564
  }
4147
4565
  return false;
4148
4566
  }
4567
+ function createBlockedRequestContent(events) {
4568
+ const stats = new Map();
4569
+ for (const event of events){
4570
+ const ruleId = getEventRuleId(event) ?? 'unknown';
4571
+ stats.set(ruleId, (stats.get(ruleId) ?? 0) + 1);
4572
+ }
4573
+ const statsList = renderer_div({
4574
+ style: {
4575
+ display: 'flex',
4576
+ flexDirection: 'column',
4577
+ gap: '4px',
4578
+ marginBottom: '8px'
4579
+ },
4580
+ children: [
4581
+ ...stats.entries()
4582
+ ].sort((a, b)=>b[1] - a[1]).map(([ruleId, count])=>createInfoRow({
4583
+ label: 'unknown' === ruleId ? 'Unknown Rule' : `Rule: ${ruleId}`,
4584
+ value: `${count}`
4585
+ }))
4586
+ });
4587
+ const latestEvents = events.slice(0, 5);
4588
+ const latestList = renderer_div({
4589
+ style: {
4590
+ display: 'flex',
4591
+ flexDirection: 'column',
4592
+ gap: '4px'
4593
+ },
4594
+ children: latestEvents.map((event)=>createInfoRow({
4595
+ label: `${formatEventTime(event.timestamp)} ${getEventMethod(event)}`,
4596
+ value: scripts_truncateText(getEventUrl(event), 38)
4597
+ }))
4598
+ });
4599
+ return [
4600
+ statsList,
4601
+ latestList
4602
+ ];
4603
+ }
4604
+ function getEventRuleId(event) {
4605
+ const data = event.data;
4606
+ const rule = data?.rule;
4607
+ const ruleId = rule?.id ?? data?.ruleId;
4608
+ return 'string' == typeof ruleId || 'number' == typeof ruleId ? String(ruleId) : void 0;
4609
+ }
4610
+ function getEventMethod(event) {
4611
+ const data = event.data;
4612
+ const method = data?.method;
4613
+ return 'string' == typeof method ? method.toUpperCase() : 'REQ';
4614
+ }
4615
+ function getEventUrl(event) {
4616
+ const data = event.data;
4617
+ const url = data?.url;
4618
+ return 'string' == typeof url ? url : event.message;
4619
+ }
4620
+ function formatEventTime(timestamp) {
4621
+ return new Date(timestamp).toLocaleTimeString('en-US', {
4622
+ hour12: false,
4623
+ hour: '2-digit',
4624
+ minute: '2-digit',
4625
+ second: '2-digit'
4626
+ });
4627
+ }
4628
+ function scripts_truncateText(text, maxLength) {
4629
+ if (text.length <= maxLength) return text;
4630
+ return `${text.slice(0, maxLength - 3)}...`;
4631
+ }
4632
+ const DEVTOOLS_OVERRIDES_STORAGE_KEY = 'c15t-devtools-overrides';
4633
+ function normalizeStringValue(value) {
4634
+ if ('string' != typeof value) return;
4635
+ const normalized = value.trim();
4636
+ return normalized.length > 0 ? normalized : void 0;
4637
+ }
4638
+ function normalizeBooleanValue(value) {
4639
+ return 'boolean' == typeof value ? value : void 0;
4640
+ }
4641
+ function normalizeOverrides(value) {
4642
+ if (!value || 'object' != typeof value) return null;
4643
+ const source = value;
4644
+ const overrides = {
4645
+ country: normalizeStringValue(source.country),
4646
+ region: normalizeStringValue(source.region),
4647
+ language: normalizeStringValue(source.language),
4648
+ gpc: normalizeBooleanValue(source.gpc)
4649
+ };
4650
+ return hasPersistedOverrides(overrides) ? overrides : null;
4651
+ }
4652
+ function hasPersistedOverrides(overrides) {
4653
+ return Boolean(overrides.country || overrides.region || overrides.language || void 0 !== overrides.gpc);
4654
+ }
4655
+ function override_storage_loadPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4656
+ if ('undefined' == typeof window) return null;
4657
+ try {
4658
+ const stored = localStorage.getItem(storageKey);
4659
+ if (!stored) return null;
4660
+ const parsed = JSON.parse(stored);
4661
+ return normalizeOverrides(parsed);
4662
+ } catch {
4663
+ return null;
4664
+ }
4665
+ }
4666
+ function override_storage_persistOverrides(overrides, storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4667
+ if ('undefined' == typeof window) return;
4668
+ try {
4669
+ if (!hasPersistedOverrides(overrides)) return void localStorage.removeItem(storageKey);
4670
+ localStorage.setItem(storageKey, JSON.stringify(overrides));
4671
+ } catch {}
4672
+ }
4673
+ function override_storage_clearPersistedOverrides(storageKey = DEVTOOLS_OVERRIDES_STORAGE_KEY) {
4674
+ if ('undefined' == typeof window) return;
4675
+ try {
4676
+ localStorage.removeItem(storageKey);
4677
+ } catch {}
4678
+ }
4149
4679
  const STORAGE_KEYS = {
4150
4680
  C15T: 'c15t',
4151
4681
  PENDING_SYNC: 'c15t:pending-consent-sync',
@@ -4283,12 +4813,37 @@ var __webpack_exports__ = {};
4283
4813
  const { namespace = 'c15tStore', onConnect, onStateChange, onDisconnect } = options;
4284
4814
  let store = null;
4285
4815
  let unsubscribe = null;
4286
- let pollInterval = null;
4816
+ let reconnectTimeout = null;
4817
+ let reconnectAttempts = 0;
4818
+ let hasNotifiedDisconnect = false;
4287
4819
  const listeners = new Set();
4820
+ const INITIAL_RETRY_DELAY_MS = 100;
4821
+ const MAX_RETRY_DELAY_MS = 2000;
4822
+ const DISCONNECT_NOTIFY_ATTEMPTS = 5;
4823
+ function clearReconnectTimer() {
4824
+ if (reconnectTimeout) {
4825
+ clearTimeout(reconnectTimeout);
4826
+ reconnectTimeout = null;
4827
+ }
4828
+ }
4829
+ function resetReconnectState() {
4830
+ reconnectAttempts = 0;
4831
+ hasNotifiedDisconnect = false;
4832
+ }
4833
+ function notifyDisconnectedOnce() {
4834
+ if (hasNotifiedDisconnect) return;
4835
+ hasNotifiedDisconnect = true;
4836
+ onDisconnect?.();
4837
+ }
4288
4838
  function tryConnect() {
4289
4839
  if ('undefined' == typeof window) return false;
4290
4840
  const storeInstance = window[namespace];
4291
4841
  if (storeInstance && 'function' == typeof storeInstance.getState) {
4842
+ if (store === storeInstance && unsubscribe) return true;
4843
+ if (unsubscribe) {
4844
+ unsubscribe();
4845
+ unsubscribe = null;
4846
+ }
4292
4847
  store = storeInstance;
4293
4848
  unsubscribe = store.subscribe((state)=>{
4294
4849
  onStateChange?.(state);
@@ -4296,30 +4851,26 @@ var __webpack_exports__ = {};
4296
4851
  });
4297
4852
  const currentState = store.getState();
4298
4853
  onConnect?.(currentState, store);
4299
- if (pollInterval) {
4300
- clearInterval(pollInterval);
4301
- pollInterval = null;
4302
- }
4854
+ clearReconnectTimer();
4855
+ resetReconnectState();
4303
4856
  return true;
4304
4857
  }
4305
4858
  return false;
4306
4859
  }
4860
+ function scheduleReconnect(immediate = false) {
4861
+ if (store || reconnectTimeout) return;
4862
+ const delay = immediate ? 0 : Math.min(INITIAL_RETRY_DELAY_MS * 2 ** Math.min(reconnectAttempts, 5), MAX_RETRY_DELAY_MS);
4863
+ reconnectTimeout = setTimeout(()=>{
4864
+ reconnectTimeout = null;
4865
+ reconnectAttempts++;
4866
+ if (tryConnect()) return;
4867
+ if (reconnectAttempts >= DISCONNECT_NOTIFY_ATTEMPTS) notifyDisconnectedOnce();
4868
+ scheduleReconnect();
4869
+ }, delay);
4870
+ }
4307
4871
  function startPolling() {
4308
- if (pollInterval) return;
4309
4872
  if (tryConnect()) return;
4310
- let attempts = 0;
4311
- const maxAttempts = 50;
4312
- pollInterval = setInterval(()=>{
4313
- attempts++;
4314
- if (tryConnect()) return;
4315
- if (attempts >= maxAttempts) {
4316
- if (pollInterval) {
4317
- clearInterval(pollInterval);
4318
- pollInterval = null;
4319
- }
4320
- onDisconnect?.();
4321
- }
4322
- }, 100);
4873
+ scheduleReconnect(true);
4323
4874
  }
4324
4875
  startPolling();
4325
4876
  return {
@@ -4333,11 +4884,13 @@ var __webpack_exports__ = {};
4333
4884
  listeners.delete(listener);
4334
4885
  };
4335
4886
  },
4887
+ retryConnection: ()=>{
4888
+ if (store) return;
4889
+ resetReconnectState();
4890
+ scheduleReconnect(true);
4891
+ },
4336
4892
  destroy: ()=>{
4337
- if (pollInterval) {
4338
- clearInterval(pollInterval);
4339
- pollInterval = null;
4340
- }
4893
+ clearReconnectTimer();
4341
4894
  if (unsubscribe) {
4342
4895
  unsubscribe();
4343
4896
  unsubscribe = null;
@@ -4356,6 +4909,86 @@ var __webpack_exports__ = {};
4356
4909
  tokens_options.insertStyleElement = insertStyleElement_default();
4357
4910
  injectStylesIntoStyleTag_default()(tokens.A, tokens_options);
4358
4911
  tokens.A && tokens.A.locals && tokens.A.locals;
4912
+ const PANEL_HEIGHT_TRANSITION = 'height var(--c15t-duration-normal, 200ms) var(--c15t-easing, cubic-bezier(0.4, 0, 0.2, 1))';
4913
+ const PANEL_HEIGHT_TRANSITION_MS = 200;
4914
+ const PANEL_HEIGHT_TRANSITION_BUFFER_MS = 80;
4915
+ function normalizeOverridesForPersistence(overrides) {
4916
+ return {
4917
+ country: overrides?.country?.trim() || void 0,
4918
+ region: overrides?.region?.trim() || void 0,
4919
+ language: overrides?.language?.trim() || void 0,
4920
+ gpc: overrides?.gpc
4921
+ };
4922
+ }
4923
+ function persistedOverridesEqual(a, b) {
4924
+ return a.country === b.country && a.region === b.region && a.language === b.language && a.gpc === b.gpc;
4925
+ }
4926
+ function getBlockedRequestMessage(payload) {
4927
+ const data = payload;
4928
+ const method = 'string' == typeof data?.method ? data.method.toUpperCase() : 'REQUEST';
4929
+ const url = 'string' == typeof data?.url ? data.url : 'unknown-url';
4930
+ return `Network blocked: ${method} ${url}`;
4931
+ }
4932
+ function prefersReducedMotion() {
4933
+ return 'undefined' != typeof window && 'function' == typeof window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
4934
+ }
4935
+ function createPanelHeightAnimator() {
4936
+ let activePanel = null;
4937
+ let frameId = null;
4938
+ let timeoutId = null;
4939
+ let removeTransitionListener = null;
4940
+ function clearAnimationState() {
4941
+ if (null !== frameId) {
4942
+ window.cancelAnimationFrame(frameId);
4943
+ frameId = null;
4944
+ }
4945
+ if (null !== timeoutId) {
4946
+ clearTimeout(timeoutId);
4947
+ timeoutId = null;
4948
+ }
4949
+ if (removeTransitionListener) {
4950
+ removeTransitionListener();
4951
+ removeTransitionListener = null;
4952
+ }
4953
+ if (activePanel) {
4954
+ activePanel.style.height = '';
4955
+ activePanel.style.transition = '';
4956
+ activePanel.style.willChange = '';
4957
+ activePanel = null;
4958
+ }
4959
+ }
4960
+ function animate(panel, previousHeight) {
4961
+ if (!Number.isFinite(previousHeight) || prefersReducedMotion()) return;
4962
+ const nextHeight = panel.getBoundingClientRect().height;
4963
+ if (!Number.isFinite(nextHeight) || Math.abs(nextHeight - previousHeight) < 1) return;
4964
+ clearAnimationState();
4965
+ activePanel = panel;
4966
+ panel.style.height = `${previousHeight}px`;
4967
+ panel.style.willChange = 'height';
4968
+ panel.getBoundingClientRect();
4969
+ const handleTransitionEnd = (event)=>{
4970
+ const transitionEvent = event;
4971
+ if ('string' == typeof transitionEvent.propertyName && transitionEvent.propertyName && 'height' !== transitionEvent.propertyName) return;
4972
+ clearAnimationState();
4973
+ };
4974
+ panel.addEventListener('transitionend', handleTransitionEnd);
4975
+ removeTransitionListener = ()=>{
4976
+ panel.removeEventListener('transitionend', handleTransitionEnd);
4977
+ };
4978
+ frameId = window.requestAnimationFrame(()=>{
4979
+ frameId = null;
4980
+ panel.style.transition = PANEL_HEIGHT_TRANSITION;
4981
+ panel.style.height = `${nextHeight}px`;
4982
+ });
4983
+ timeoutId = setTimeout(()=>{
4984
+ clearAnimationState();
4985
+ }, PANEL_HEIGHT_TRANSITION_MS + PANEL_HEIGHT_TRANSITION_BUFFER_MS);
4986
+ }
4987
+ return {
4988
+ animate,
4989
+ destroy: clearAnimationState
4990
+ };
4991
+ }
4359
4992
  function createDevTools(options = {}) {
4360
4993
  const { namespace = 'c15tStore', position = 'bottom-right', defaultOpen = false } = options;
4361
4994
  const stateManager = state_manager_createStateManager({
@@ -4363,6 +4996,8 @@ var __webpack_exports__ = {};
4363
4996
  isOpen: defaultOpen
4364
4997
  });
4365
4998
  let originalCallbacks = {};
4999
+ let originalNetworkBlockedCallback;
5000
+ let hasWrappedNetworkBlockerCallback = false;
4366
5001
  const storeConnector = store_connector_createStoreConnector({
4367
5002
  namespace,
4368
5003
  onConnect: (state, store)=>{
@@ -4406,6 +5041,48 @@ var __webpack_exports__ = {};
4406
5041
  });
4407
5042
  if ('function' == typeof originalCallbacks.onBeforeConsentRevocationReload) originalCallbacks.onBeforeConsentRevocationReload(payload);
4408
5043
  });
5044
+ const currentNetworkBlocker = store.getState().networkBlocker;
5045
+ if (currentNetworkBlocker && !hasWrappedNetworkBlockerCallback) {
5046
+ originalNetworkBlockedCallback = currentNetworkBlocker.onRequestBlocked;
5047
+ hasWrappedNetworkBlockerCallback = true;
5048
+ store.getState().setNetworkBlocker({
5049
+ ...currentNetworkBlocker,
5050
+ onRequestBlocked: (payload)=>{
5051
+ stateManager.addEvent({
5052
+ type: 'network',
5053
+ message: getBlockedRequestMessage(payload),
5054
+ data: payload
5055
+ });
5056
+ if ('function' == typeof originalNetworkBlockedCallback) originalNetworkBlockedCallback(payload);
5057
+ }
5058
+ });
5059
+ }
5060
+ const persistedOverrides = override_storage_loadPersistedOverrides();
5061
+ if (persistedOverrides) {
5062
+ const currentOverrides = normalizeOverridesForPersistence(store.getState().overrides);
5063
+ if (!persistedOverridesEqual(persistedOverrides, currentOverrides)) store.getState().setOverrides({
5064
+ country: persistedOverrides.country,
5065
+ region: persistedOverrides.region,
5066
+ language: persistedOverrides.language,
5067
+ gpc: persistedOverrides.gpc
5068
+ }).then(()=>{
5069
+ stateManager.addEvent({
5070
+ type: 'info',
5071
+ message: 'Applied persisted devtools overrides',
5072
+ data: {
5073
+ country: persistedOverrides.country,
5074
+ region: persistedOverrides.region,
5075
+ language: persistedOverrides.language,
5076
+ gpc: persistedOverrides.gpc
5077
+ }
5078
+ });
5079
+ }).catch(()=>{
5080
+ stateManager.addEvent({
5081
+ type: 'error',
5082
+ message: 'Failed to apply persisted devtools overrides'
5083
+ });
5084
+ });
5085
+ }
4409
5086
  },
4410
5087
  onDisconnect: ()=>{
4411
5088
  stateManager.setConnected(false);
@@ -4417,14 +5094,18 @@ var __webpack_exports__ = {};
4417
5094
  onStateChange: ()=>{}
4418
5095
  });
4419
5096
  let tabsInstance = null;
5097
+ const panelHeightAnimator = createPanelHeightAnimator();
4420
5098
  const panelInstance = createPanel({
4421
5099
  stateManager,
4422
5100
  storeConnector,
5101
+ namespace,
4423
5102
  onRenderContent: (container)=>{
4424
5103
  renderContent(container, stateManager, storeConnector);
4425
5104
  }
4426
5105
  });
4427
5106
  function renderContent(container, stateManager, storeConnector) {
5107
+ const panel = container.parentElement;
5108
+ const previousPanelHeight = panel?.getBoundingClientRect().height ?? 0;
4428
5109
  clearElement(container);
4429
5110
  const storeState = storeConnector.getState();
4430
5111
  const disabledTabs = [];
@@ -4506,38 +5187,46 @@ var __webpack_exports__ = {};
4506
5187
  case 'location':
4507
5188
  location_renderLocationPanel(panelContent, {
4508
5189
  getState: getStoreState,
4509
- onSetOverrides: async (overrides)=>{
5190
+ onApplyOverrides: async (overrides)=>{
4510
5191
  const store = storeConnector.getStore();
4511
5192
  if (store) {
4512
- const currentOverrides = store.getState().overrides || {};
4513
5193
  await store.getState().setOverrides({
4514
- ...currentOverrides,
4515
- ...overrides
5194
+ country: overrides.country,
5195
+ region: overrides.region,
5196
+ language: overrides.language,
5197
+ gpc: overrides.gpc
4516
5198
  });
4517
- stateManager.addEvent({
4518
- type: 'info',
4519
- message: 'Overrides updated',
4520
- data: overrides
5199
+ override_storage_persistOverrides({
5200
+ country: overrides.country,
5201
+ region: overrides.region,
5202
+ language: overrides.language,
5203
+ gpc: overrides.gpc
4521
5204
  });
4522
- await store.getState().initConsentManager();
4523
5205
  stateManager.addEvent({
4524
5206
  type: 'info',
4525
- message: 'Consent manager re-initialized with new overrides'
5207
+ message: 'Overrides updated',
5208
+ data: {
5209
+ country: overrides.country,
5210
+ region: overrides.region,
5211
+ language: overrides.language,
5212
+ gpc: overrides.gpc
5213
+ }
4526
5214
  });
4527
5215
  }
4528
5216
  },
4529
5217
  onClearOverrides: async ()=>{
4530
5218
  const store = storeConnector.getStore();
4531
5219
  if (store) {
4532
- await store.getState().setOverrides(void 0);
4533
- stateManager.addEvent({
4534
- type: 'info',
4535
- message: 'Overrides cleared'
5220
+ await store.getState().setOverrides({
5221
+ country: void 0,
5222
+ region: void 0,
5223
+ language: void 0,
5224
+ gpc: void 0
4536
5225
  });
4537
- await store.getState().initConsentManager();
5226
+ override_storage_clearPersistedOverrides();
4538
5227
  stateManager.addEvent({
4539
5228
  type: 'info',
4540
- message: 'Consent manager re-initialized'
5229
+ message: 'Overrides cleared'
4541
5230
  });
4542
5231
  }
4543
5232
  }
@@ -4545,12 +5234,85 @@ var __webpack_exports__ = {};
4545
5234
  break;
4546
5235
  case "scripts":
4547
5236
  scripts_renderScriptsPanel(panelContent, {
4548
- getState: getStoreState
5237
+ getState: getStoreState,
5238
+ getEvents: ()=>stateManager.getState().eventLog
4549
5239
  });
4550
5240
  break;
4551
5241
  case 'iab':
4552
5242
  iab_renderIabPanel(panelContent, {
4553
5243
  getState: getStoreState,
5244
+ onSetPurposeConsent: (purposeId, value)=>{
5245
+ const iab = storeConnector.getStore()?.getState().iab;
5246
+ if (!iab) return;
5247
+ iab.setPurposeConsent(purposeId, value);
5248
+ stateManager.addEvent({
5249
+ type: 'iab',
5250
+ message: `IAB purpose ${purposeId} set to ${value}`,
5251
+ data: {
5252
+ purposeId,
5253
+ value
5254
+ }
5255
+ });
5256
+ },
5257
+ onSetVendorConsent: (vendorId, value)=>{
5258
+ const iab = storeConnector.getStore()?.getState().iab;
5259
+ if (!iab) return;
5260
+ iab.setVendorConsent(vendorId, value);
5261
+ stateManager.addEvent({
5262
+ type: 'iab',
5263
+ message: `IAB vendor ${vendorId} set to ${value}`,
5264
+ data: {
5265
+ vendorId,
5266
+ value
5267
+ }
5268
+ });
5269
+ },
5270
+ onSetSpecialFeatureOptIn: (featureId, value)=>{
5271
+ const iab = storeConnector.getStore()?.getState().iab;
5272
+ if (!iab) return;
5273
+ iab.setSpecialFeatureOptIn(featureId, value);
5274
+ stateManager.addEvent({
5275
+ type: 'iab',
5276
+ message: `IAB feature ${featureId} set to ${value}`,
5277
+ data: {
5278
+ featureId,
5279
+ value
5280
+ }
5281
+ });
5282
+ },
5283
+ onAcceptAll: ()=>{
5284
+ const iab = storeConnector.getStore()?.getState().iab;
5285
+ if (!iab) return;
5286
+ iab.acceptAll();
5287
+ stateManager.addEvent({
5288
+ type: 'iab',
5289
+ message: 'IAB accept all selected'
5290
+ });
5291
+ },
5292
+ onRejectAll: ()=>{
5293
+ const iab = storeConnector.getStore()?.getState().iab;
5294
+ if (!iab) return;
5295
+ iab.rejectAll();
5296
+ stateManager.addEvent({
5297
+ type: 'iab',
5298
+ message: 'IAB reject all selected'
5299
+ });
5300
+ },
5301
+ onSave: ()=>{
5302
+ const iab = storeConnector.getStore()?.getState().iab;
5303
+ if (!iab) return;
5304
+ iab.save().then(()=>{
5305
+ stateManager.addEvent({
5306
+ type: 'iab',
5307
+ message: 'IAB preferences saved'
5308
+ });
5309
+ }).catch((error)=>{
5310
+ stateManager.addEvent({
5311
+ type: 'error',
5312
+ message: `Failed to save IAB preferences: ${String(error)}`
5313
+ });
5314
+ });
5315
+ },
4554
5316
  onReset: async ()=>{
4555
5317
  const store = storeConnector.getStore();
4556
5318
  if (store) await reset_consents_resetAllConsents(store, stateManager);
@@ -4638,6 +5400,7 @@ var __webpack_exports__ = {};
4638
5400
  });
4639
5401
  break;
4640
5402
  }
5403
+ if (panel) panelHeightAnimator.animate(panel, previousPanelHeight);
4641
5404
  }
4642
5405
  storeConnector.subscribe(()=>{
4643
5406
  panelInstance.update();
@@ -4655,6 +5418,21 @@ var __webpack_exports__ = {};
4655
5418
  };
4656
5419
  },
4657
5420
  destroy: ()=>{
5421
+ const store = storeConnector.getStore();
5422
+ if (store) {
5423
+ store.getState().setCallback('onBannerFetched', originalCallbacks.onBannerFetched);
5424
+ store.getState().setCallback('onConsentSet', originalCallbacks.onConsentSet);
5425
+ store.getState().setCallback('onError', originalCallbacks.onError);
5426
+ store.getState().setCallback('onBeforeConsentRevocationReload', originalCallbacks.onBeforeConsentRevocationReload);
5427
+ if (hasWrappedNetworkBlockerCallback) {
5428
+ const currentNetworkBlocker = store.getState().networkBlocker;
5429
+ if (currentNetworkBlocker) store.getState().setNetworkBlocker({
5430
+ ...currentNetworkBlocker,
5431
+ onRequestBlocked: originalNetworkBlockedCallback
5432
+ });
5433
+ }
5434
+ }
5435
+ panelHeightAnimator.destroy();
4658
5436
  tabsInstance?.destroy();
4659
5437
  panelInstance.destroy();
4660
5438
  storeConnector.destroy();