@gemx-dev/heatmap-react 3.5.92-dev.33 → 3.5.92-dev.35

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 (54) hide show
  1. package/dist/esm/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -1
  2. package/dist/esm/index.js +536 -551
  3. package/dist/esm/index.mjs +536 -551
  4. package/dist/esm/libs/iframe-processor/index.d.ts +1 -0
  5. package/dist/esm/libs/iframe-processor/index.d.ts.map +1 -1
  6. package/dist/esm/libs/iframe-processor/lifecycle.d.ts +3 -3
  7. package/dist/esm/libs/iframe-processor/lifecycle.d.ts.map +1 -1
  8. package/dist/esm/libs/iframe-processor/orchestrator.d.ts +2 -2
  9. package/dist/esm/libs/iframe-processor/orchestrator.d.ts.map +1 -1
  10. package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts +1 -1
  11. package/dist/esm/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
  12. package/dist/esm/libs/iframe-processor/processors/height-observer/listeners.d.ts.map +1 -1
  13. package/dist/esm/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
  14. package/dist/esm/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
  15. package/dist/esm/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
  16. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +8 -8
  17. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -1
  18. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +1 -1
  19. package/dist/esm/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -1
  20. package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts +4 -4
  21. package/dist/esm/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -1
  22. package/dist/esm/libs/visualizer/GXVisualizer.d.ts +1 -1
  23. package/dist/esm/libs/visualizer/GXVisualizer.d.ts.map +1 -1
  24. package/dist/esm/libs/visualizer/renderers/ScrollBucketRenderer.d.ts +4 -3
  25. package/dist/esm/libs/visualizer/renderers/ScrollBucketRenderer.d.ts.map +1 -1
  26. package/dist/esm/types/viz-scrollmap.d.ts +1 -0
  27. package/dist/esm/types/viz-scrollmap.d.ts.map +1 -1
  28. package/dist/umd/hooks/viz-render/useHeatmapIframeProcessor.d.ts.map +1 -1
  29. package/dist/umd/index.js +1 -1
  30. package/dist/umd/libs/iframe-processor/index.d.ts +1 -0
  31. package/dist/umd/libs/iframe-processor/index.d.ts.map +1 -1
  32. package/dist/umd/libs/iframe-processor/lifecycle.d.ts +3 -3
  33. package/dist/umd/libs/iframe-processor/lifecycle.d.ts.map +1 -1
  34. package/dist/umd/libs/iframe-processor/orchestrator.d.ts +2 -2
  35. package/dist/umd/libs/iframe-processor/orchestrator.d.ts.map +1 -1
  36. package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts +1 -1
  37. package/dist/umd/libs/iframe-processor/processors/height-observer/index.d.ts.map +1 -1
  38. package/dist/umd/libs/iframe-processor/processors/height-observer/listeners.d.ts.map +1 -1
  39. package/dist/umd/libs/iframe-processor/processors/navigation/index.d.ts.map +1 -1
  40. package/dist/umd/libs/iframe-processor/processors/viewport/global-fixes/global-fixes/viewport-unit-replacer/fixes.d.ts.map +1 -1
  41. package/dist/umd/libs/iframe-processor/processors/viewport/index.d.ts.map +1 -1
  42. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts +8 -8
  43. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/functions.d.ts.map +1 -1
  44. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts +1 -1
  45. package/dist/umd/libs/iframe-processor/processors/viewport/style-enforcer/state.d.ts.map +1 -1
  46. package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts +4 -4
  47. package/dist/umd/libs/iframe-processor/shared/iframe-types.d.ts.map +1 -1
  48. package/dist/umd/libs/visualizer/GXVisualizer.d.ts +1 -1
  49. package/dist/umd/libs/visualizer/GXVisualizer.d.ts.map +1 -1
  50. package/dist/umd/libs/visualizer/renderers/ScrollBucketRenderer.d.ts +4 -3
  51. package/dist/umd/libs/visualizer/renderers/ScrollBucketRenderer.d.ts.map +1 -1
  52. package/dist/umd/types/viz-scrollmap.d.ts +1 -0
  53. package/dist/umd/types/viz-scrollmap.d.ts.map +1 -1
  54. package/package.json +1 -1
package/dist/esm/index.js CHANGED
@@ -4324,206 +4324,207 @@ function setup(doc, onChange) {
4324
4324
  // cspell:ignore cooldown
4325
4325
  /**
4326
4326
  * Height Observer Processor
4327
- * Background observer — watches for iframe content height changes.
4327
+ * Background observer — watches for iframe content height changectx.
4328
4328
  */
4329
4329
  // ── Helpers ───────────────────────────────────────────────────────────────────
4330
- function readCurrentHeight(s) {
4331
- if (!s.iframe?.contentDocument || !s.iframe?.contentWindow)
4330
+ function readCurrentHeight(ctx) {
4331
+ if (!ctx.iframe?.contentDocument || !ctx.iframe?.contentWindow)
4332
4332
  return 0;
4333
- const height = getFinalHeight(s.iframe.contentDocument, false);
4334
- s.logger.log('Height:', height);
4333
+ const height = getFinalHeight(ctx.iframe.contentDocument, false);
4334
+ ctx.logger.log('Height:', height);
4335
4335
  return height;
4336
4336
  }
4337
- function isBlocked(s) {
4338
- return s.isProcessing || s.isCoolingDown || s.throttleTimeout !== null;
4337
+ function isBlocked(ctx) {
4338
+ return ctx.isProcessing || ctx.isCoolingDown || ctx.throttleTimeout !== null;
4339
4339
  }
4340
- function hasHeightChanged(s, height) {
4341
- return height !== s.lastHeight;
4340
+ function hasHeightChanged(ctx, height) {
4341
+ return height !== ctx.lastHeight;
4342
4342
  }
4343
4343
  // ── Cooldown ──────────────────────────────────────────────────────────────────
4344
- function startCooldown(s) {
4345
- s.isCoolingDown = true;
4346
- s.cooldownTimeout = setTimeout(() => {
4347
- s.cooldownTimeout = null;
4348
- s.isCoolingDown = false;
4349
- }, s.cooldownMs);
4344
+ function startCooldown(ctx) {
4345
+ const cooldownMs = ctx.cooldownMs;
4346
+ ctx.isCoolingDown = true;
4347
+ ctx.cooldownTimeout = setTimeout(() => {
4348
+ ctx.cooldownTimeout = null;
4349
+ ctx.isCoolingDown = false;
4350
+ }, cooldownMs);
4350
4351
  }
4351
- function stopCooldown(s) {
4352
- if (s.cooldownTimeout) {
4353
- clearTimeout(s.cooldownTimeout);
4354
- s.cooldownTimeout = null;
4352
+ function stopCooldown(ctx) {
4353
+ if (ctx.cooldownTimeout) {
4354
+ clearTimeout(ctx.cooldownTimeout);
4355
+ ctx.cooldownTimeout = null;
4355
4356
  }
4356
- s.isCoolingDown = false;
4357
+ ctx.isCoolingDown = false;
4357
4358
  }
4358
4359
  // ── Debounce ──────────────────────────────────────────────────────────────────
4359
- function cancelPendingDebounce(s) {
4360
- if (s.debounceTimeout) {
4361
- clearTimeout(s.debounceTimeout);
4362
- s.debounceTimeout = null;
4360
+ function cancelPendingDebounce(ctx) {
4361
+ if (ctx.debounceTimeout) {
4362
+ clearTimeout(ctx.debounceTimeout);
4363
+ ctx.debounceTimeout = null;
4363
4364
  }
4364
4365
  }
4365
- function processCurrentHeightIfChanged(s) {
4366
- const height = readCurrentHeight(s);
4367
- if (hasHeightChanged(s, height)) {
4368
- processHeightChange(s, height);
4366
+ function processCurrentHeightIfChanged(ctx) {
4367
+ const height = readCurrentHeight(ctx);
4368
+ if (hasHeightChanged(ctx, height)) {
4369
+ processHeightChange(ctx, height);
4369
4370
  }
4370
4371
  }
4371
- function scheduleDebounce(s) {
4372
- cancelPendingDebounce(s);
4373
- s.debounceTimeout = setTimeout(() => {
4374
- s.debounceTimeout = null;
4375
- processCurrentHeightIfChanged(s);
4376
- }, s.debounceMs);
4372
+ function scheduleDebounce(ctx) {
4373
+ cancelPendingDebounce(ctx);
4374
+ ctx.debounceTimeout = setTimeout(() => {
4375
+ ctx.debounceTimeout = null;
4376
+ processCurrentHeightIfChanged(ctx);
4377
+ }, ctx.debounceMs);
4377
4378
  }
4378
4379
  // ── Throttle ──────────────────────────────────────────────────────────────────
4379
- function scheduleThrottledCheck(s) {
4380
- s.throttleTimeout = setTimeout(() => {
4381
- s.throttleTimeout = null;
4382
- const height = readCurrentHeight(s);
4383
- if (!hasHeightChanged(s, height)) {
4384
- cancelPendingDebounce(s);
4380
+ function scheduleThrottledCheck(ctx) {
4381
+ ctx.throttleTimeout = setTimeout(() => {
4382
+ ctx.throttleTimeout = null;
4383
+ const height = readCurrentHeight(ctx);
4384
+ if (!hasHeightChanged(ctx, height)) {
4385
+ cancelPendingDebounce(ctx);
4385
4386
  return;
4386
4387
  }
4387
- s.logger.log(`Height changed: ${s.lastHeight}px -> ${height}px`);
4388
- scheduleDebounce(s);
4389
- }, s.throttleMs);
4388
+ ctx.logger.log(`Height changed: ${ctx.lastHeight}px -> ${height}px`);
4389
+ scheduleDebounce(ctx);
4390
+ }, ctx.throttleMs);
4390
4391
  }
4391
4392
  // ── Core ──────────────────────────────────────────────────────────────────────
4392
- async function processHeightChange(s, newHeight) {
4393
- if (!s.iframe || !s.config)
4393
+ async function processHeightChange(ctx, newHeight) {
4394
+ if (!ctx.iframe || !ctx.config)
4394
4395
  return;
4395
- s.isProcessing = true;
4396
- s.logger.log(`Processing height change: ${newHeight}px`);
4396
+ ctx.isProcessing = true;
4397
+ ctx.logger.log(`Processing height change: ${newHeight}px`);
4397
4398
  try {
4398
4399
  const result = {
4399
4400
  height: newHeight,
4400
- width: s.iframe.contentWindow?.innerWidth ?? 0,
4401
+ width: ctx.iframe.contentWindow?.innerWidth ?? 0,
4401
4402
  };
4402
- s.lastHeight = newHeight;
4403
- s.config.onHeightChange?.(result);
4403
+ ctx.lastHeight = newHeight;
4404
+ ctx.config.onHeightChange?.(result);
4404
4405
  window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: result }));
4405
4406
  }
4406
4407
  catch (error) {
4407
- s.logger.error('Failed to process height change:', error);
4408
- s.config.onError?.(error);
4408
+ ctx.logger.error('Failed to process height change:', error);
4409
+ ctx.config.onError?.(error);
4409
4410
  }
4410
4411
  finally {
4411
- s.isProcessing = false;
4412
- if (s.cooldownMs > 0)
4413
- startCooldown(s);
4412
+ ctx.isProcessing = false;
4413
+ if (ctx.cooldownMs > 0)
4414
+ startCooldown(ctx);
4414
4415
  }
4415
4416
  }
4416
- function handleHeightChange(s) {
4417
- if (!s.running || isBlocked(s))
4417
+ function handleHeightChange(ctx) {
4418
+ if (!ctx.running || isBlocked(ctx))
4418
4419
  return;
4419
- scheduleThrottledCheck(s);
4420
+ scheduleThrottledCheck(ctx);
4420
4421
  }
4421
- function attachObserver(s) {
4422
- if (!s.iframe?.contentDocument?.body) {
4423
- s.logger.warn('Cannot observe height changes: iframe body not found');
4422
+ function attachObserver(ctx) {
4423
+ if (!ctx.iframe?.contentDocument?.body) {
4424
+ ctx.logger.warn('Cannot observe height changes: iframe body not found');
4424
4425
  return;
4425
4426
  }
4426
- s.observerCleanup?.();
4427
- const height = readCurrentHeight(s);
4428
- s.logger.log('Initial height:', height);
4429
- if (hasHeightChanged(s, height)) {
4430
- processHeightChange(s, height);
4427
+ ctx.observerCleanup?.();
4428
+ const height = readCurrentHeight(ctx);
4429
+ ctx.logger.log('Initial height:', height);
4430
+ if (hasHeightChanged(ctx, height)) {
4431
+ processHeightChange(ctx, height);
4431
4432
  }
4432
4433
  else {
4433
- s.lastHeight = height;
4434
+ ctx.lastHeight = height;
4434
4435
  }
4435
- s.observerCleanup = setup(s.iframe.contentDocument, () => handleHeightChange(s));
4436
+ ctx.observerCleanup = setup(ctx.iframe.contentDocument, () => handleHeightChange(ctx));
4436
4437
  }
4437
- function detachObserver(s) {
4438
- s.observerCleanup?.();
4439
- s.observerCleanup = null;
4438
+ function detachObserver(ctx) {
4439
+ ctx.observerCleanup?.();
4440
+ ctx.observerCleanup = null;
4440
4441
  }
4441
- function clearAllTimers(s) {
4442
- if (s.throttleTimeout) {
4443
- clearTimeout(s.throttleTimeout);
4444
- s.throttleTimeout = null;
4442
+ function clearAllTimers(ctx) {
4443
+ if (ctx.throttleTimeout) {
4444
+ clearTimeout(ctx.throttleTimeout);
4445
+ ctx.throttleTimeout = null;
4445
4446
  }
4446
- if (s.debounceTimeout) {
4447
- clearTimeout(s.debounceTimeout);
4448
- s.debounceTimeout = null;
4447
+ if (ctx.debounceTimeout) {
4448
+ clearTimeout(ctx.debounceTimeout);
4449
+ ctx.debounceTimeout = null;
4449
4450
  }
4450
- if (s.startDelayTimeout) {
4451
- clearTimeout(s.startDelayTimeout);
4452
- s.startDelayTimeout = null;
4451
+ if (ctx.startDelayTimeout) {
4452
+ clearTimeout(ctx.startDelayTimeout);
4453
+ ctx.startDelayTimeout = null;
4453
4454
  }
4454
- stopCooldown(s);
4455
+ stopCooldown(ctx);
4455
4456
  }
4456
4457
  // ── Lifecycle ─────────────────────────────────────────────────────────────────
4457
- function observeImmediately(s) {
4458
- attachObserver(s);
4459
- s.logger.log('Height observer started');
4460
- }
4461
- function observeAfterDelay(s, delayMs) {
4462
- s.logger.log(`Height observer will start in ${delayMs}ms`);
4463
- s.startDelayTimeout = setTimeout(() => {
4464
- s.startDelayTimeout = null;
4465
- if (!s.running)
4466
- return;
4467
- attachObserver(s);
4468
- s.logger.log('Height observer started (after delay)');
4458
+ function observeImmediately(ctx) {
4459
+ attachObserver(ctx);
4460
+ ctx.logger.log('Height observer started');
4461
+ }
4462
+ function observeAfterDelay(ctx, delayMs) {
4463
+ ctx.logger.log(`Height observer will start in ${delayMs}ms`);
4464
+ ctx.startDelayTimeout = setTimeout(() => {
4465
+ ctx.startDelayTimeout = null;
4466
+ if (!ctx.running)
4467
+ return;
4468
+ attachObserver(ctx);
4469
+ ctx.logger.log('Height observer started (after delay)');
4469
4470
  }, delayMs);
4470
4471
  }
4471
- function start$5(s, iframe, cfg) {
4472
- if (s.running) {
4473
- s.logger.warn('Observer is already running. Call stop() first.');
4472
+ function start$5(ctx, iframe, cfg) {
4473
+ if (ctx.running) {
4474
+ ctx.logger.warn('Observer is already running. Call stop() first.');
4474
4475
  return;
4475
4476
  }
4476
- s.iframe = iframe;
4477
- s.config = cfg;
4478
- s.throttleMs = cfg.throttleMs ?? 25;
4479
- s.debounceMs = cfg.debounceMs ?? 500;
4480
- s.cooldownMs = cfg.cooldownMs ?? 0;
4481
- s.running = true;
4477
+ ctx.iframe = iframe;
4478
+ ctx.config = cfg;
4479
+ ctx.throttleMs = cfg.throttleMs ?? 25;
4480
+ ctx.debounceMs = cfg.debounceMs ?? 500;
4481
+ ctx.cooldownMs = cfg.cooldownMs ?? 0;
4482
+ ctx.running = true;
4482
4483
  const startDelayMs = cfg.startDelayMs ?? 0;
4483
4484
  if (startDelayMs > 0) {
4484
- observeAfterDelay(s, startDelayMs);
4485
+ observeAfterDelay(ctx, startDelayMs);
4485
4486
  }
4486
4487
  else {
4487
- observeImmediately(s);
4488
+ observeImmediately(ctx);
4488
4489
  }
4489
4490
  }
4490
- function stop$5(s) {
4491
- if (!s.running)
4491
+ function stop$5(ctx) {
4492
+ if (!ctx.running)
4492
4493
  return;
4493
- detachObserver(s);
4494
- clearAllTimers(s);
4495
- s.iframe = null;
4496
- s.config = null;
4497
- s.lastHeight = 0;
4498
- s.isProcessing = false;
4499
- s.isCoolingDown = false;
4500
- s.running = false;
4501
- s.logger.log('Height observer stopped');
4502
- }
4503
- function clear(s) {
4504
- detachObserver(s);
4505
- clearAllTimers(s);
4506
- s.lastHeight = 0;
4507
- s.isProcessing = false;
4508
- }
4509
- function updateConfig$3(s, cfg) {
4510
- if (!s.running || !s.config) {
4511
- s.logger.warn('Observer is not running.');
4494
+ detachObserver(ctx);
4495
+ clearAllTimers(ctx);
4496
+ ctx.iframe = null;
4497
+ ctx.config = null;
4498
+ ctx.lastHeight = 0;
4499
+ ctx.isProcessing = false;
4500
+ ctx.isCoolingDown = false;
4501
+ ctx.running = false;
4502
+ ctx.logger.log('Height observer stopped');
4503
+ }
4504
+ function clear(ctx) {
4505
+ detachObserver(ctx);
4506
+ clearAllTimers(ctx);
4507
+ ctx.lastHeight = 0;
4508
+ ctx.isProcessing = false;
4509
+ }
4510
+ function updateConfig$3(ctx, cfg) {
4511
+ if (!ctx.running || !ctx.config) {
4512
+ ctx.logger.warn('Observer is not running.');
4512
4513
  return;
4513
4514
  }
4514
- s.config = { ...s.config, ...cfg };
4515
+ ctx.config = { ...ctx.config, ...cfg };
4515
4516
  if (cfg.throttleMs !== undefined)
4516
- s.throttleMs = cfg.throttleMs;
4517
+ ctx.throttleMs = cfg.throttleMs;
4517
4518
  if (cfg.debounceMs !== undefined)
4518
- s.debounceMs = cfg.debounceMs;
4519
+ ctx.debounceMs = cfg.debounceMs;
4519
4520
  if (cfg.cooldownMs !== undefined)
4520
- s.cooldownMs = cfg.cooldownMs;
4521
- s.logger.configure({ enabled: !!s.config.debug });
4522
- s.logger.log('Config updated');
4521
+ ctx.cooldownMs = cfg.cooldownMs;
4522
+ ctx.logger.configure({ enabled: !!ctx.config.debug });
4523
+ ctx.logger.log('Config updated');
4523
4524
  }
4524
4525
  // ── Factory ───────────────────────────────────────────────────────────────────
4525
4526
  function createHeightObserver() {
4526
- const s = {
4527
+ const ctx = {
4527
4528
  logger: createLogger({ enabled: true, prefix: 'IframeHeightObserver' }),
4528
4529
  iframe: null,
4529
4530
  config: null,
@@ -4541,18 +4542,18 @@ function createHeightObserver() {
4541
4542
  running: false,
4542
4543
  };
4543
4544
  return {
4544
- start: (iframe, cfg) => start$5(s, iframe, cfg),
4545
- stop: () => stop$5(s),
4546
- observe: () => attachObserver(s),
4547
- clear: () => clear(s),
4548
- updateConfig: (cfg) => updateConfig$3(s, cfg),
4549
- getCurrentHeight: () => s.lastHeight,
4550
- isRunning: () => s.running,
4545
+ start: (iframe, cfg) => start$5(ctx, iframe, cfg),
4546
+ stop: () => stop$5(ctx),
4547
+ observe: () => attachObserver(ctx),
4548
+ clear: () => clear(ctx),
4549
+ updateConfig: (cfg) => updateConfig$3(ctx, cfg),
4550
+ getCurrentHeight: () => ctx.lastHeight,
4551
+ isRunning: () => ctx.running,
4551
4552
  getStateInfo: () => ({
4552
- isRunning: s.running,
4553
- lastHeight: s.lastHeight,
4554
- isProcessing: s.isProcessing,
4555
- hasObservers: !!s.observerCleanup,
4553
+ isRunning: ctx.running,
4554
+ lastHeight: ctx.lastHeight,
4555
+ isProcessing: ctx.isProcessing,
4556
+ hasObservers: !!ctx.observerCleanup,
4556
4557
  }),
4557
4558
  };
4558
4559
  }
@@ -4565,27 +4566,27 @@ function createHeightObserver() {
4565
4566
  * - Dispatch navigation events to the parent window
4566
4567
  */
4567
4568
  // ── Module-level functions ────────────────────────────────────────────────────
4568
- function attach$1(s, debug) {
4569
- s.logger.configure({ enabled: !!debug });
4570
- s.navigationBlockedListener = (e) => {
4569
+ function attach$1(ctx, debug) {
4570
+ ctx.logger.configure({ enabled: !!debug });
4571
+ ctx.navigationBlockedListener = (e) => {
4571
4572
  const ev = e;
4572
- s.logger.log('Navigation blocked:', ev.detail.url);
4573
+ ctx.logger.log('Navigation blocked:', ev.detail.url);
4573
4574
  };
4574
- s.formSubmitWindowListener = (e) => {
4575
+ ctx.formSubmitWindowListener = (e) => {
4575
4576
  const ev = e;
4576
- s.logger.log('Form submitted:', ev.detail.data);
4577
+ ctx.logger.log('Form submitted:', ev.detail.data);
4577
4578
  };
4578
- window.addEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
4579
- window.addEventListener('iframe-form-submit', s.formSubmitWindowListener);
4579
+ window.addEventListener('iframe-navigation-blocked', ctx.navigationBlockedListener);
4580
+ window.addEventListener('iframe-form-submit', ctx.formSubmitWindowListener);
4580
4581
  }
4581
- function detach$1(s) {
4582
- if (s.navigationBlockedListener) {
4583
- window.removeEventListener('iframe-navigation-blocked', s.navigationBlockedListener);
4584
- s.navigationBlockedListener = null;
4582
+ function detach$1(ctx) {
4583
+ if (ctx.navigationBlockedListener) {
4584
+ window.removeEventListener('iframe-navigation-blocked', ctx.navigationBlockedListener);
4585
+ ctx.navigationBlockedListener = null;
4585
4586
  }
4586
- if (s.formSubmitWindowListener) {
4587
- window.removeEventListener('iframe-form-submit', s.formSubmitWindowListener);
4588
- s.formSubmitWindowListener = null;
4587
+ if (ctx.formSubmitWindowListener) {
4588
+ window.removeEventListener('iframe-form-submit', ctx.formSubmitWindowListener);
4589
+ ctx.formSubmitWindowListener = null;
4589
4590
  }
4590
4591
  }
4591
4592
  function dispatchBlocked(url, showMessage) {
@@ -4598,14 +4599,14 @@ function dispatchFormSubmit(form, data) {
4598
4599
  }
4599
4600
  // ── Factory ───────────────────────────────────────────────────────────────────
4600
4601
  function createNavigationListeners() {
4601
- const s = {
4602
+ const ctx = {
4602
4603
  logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
4603
4604
  navigationBlockedListener: null,
4604
4605
  formSubmitWindowListener: null,
4605
4606
  };
4606
4607
  return {
4607
- attach: (debug) => attach$1(s, debug),
4608
- detach: () => detach$1(s),
4608
+ attach: (debug) => attach$1(ctx, debug),
4609
+ detach: () => detach$1(ctx),
4609
4610
  dispatchBlocked,
4610
4611
  dispatchFormSubmit,
4611
4612
  };
@@ -4739,9 +4740,9 @@ function setupDOMMonitor(doc) {
4739
4740
  * Continuous guard — blocks all navigation attempts within the iframe.
4740
4741
  */
4741
4742
  // ── Module-level functions ────────────────────────────────────────────────────
4742
- function start$4(s, iframe, cfg) {
4743
- if (s.running) {
4744
- s.logger.warn('Blocker is already running. Call stop() first.');
4743
+ function start$4(ctx, iframe, cfg) {
4744
+ if (ctx.running) {
4745
+ ctx.logger.warn('Blocker is already running. Call stop() first.');
4745
4746
  return;
4746
4747
  }
4747
4748
  if (!iframe.contentDocument || !iframe.contentWindow) {
@@ -4750,65 +4751,67 @@ function start$4(s, iframe, cfg) {
4750
4751
  const doc = iframe.contentDocument;
4751
4752
  const win = iframe.contentWindow;
4752
4753
  const originalOpen = win.open.bind(win);
4753
- s.logger.configure({ enabled: !!cfg?.debug });
4754
+ ctx.logger.configure({ enabled: !!cfg?.debug });
4754
4755
  configure$1(!!cfg?.debug);
4755
- s.cleanups = [
4756
- setupLinkBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
4757
- setupFormBlocker(doc, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage), s.listeners.dispatchFormSubmit),
4758
- setupWindowOpenBlocker(win, originalOpen, () => s.isEnabled, (url) => s.listeners.dispatchBlocked(url, s.showMessage)),
4759
- setupUnloadBlocker(win, () => s.isEnabled),
4760
- setupDOMMonitor(doc),
4761
- ];
4762
- s.listeners.attach(cfg?.debug);
4763
- s.running = true;
4764
- s.logger.log('Started');
4765
- }
4766
- function stop$4(s) {
4767
- if (!s.running)
4756
+ const isEnabledFn = () => ctx.isEnabled;
4757
+ const dispatchBlocked = (url) => ctx.listeners.dispatchBlocked(url, ctx.showMessage);
4758
+ const dispatchFormSubmit = ctx.listeners.dispatchFormSubmit;
4759
+ const linkBlocker = setupLinkBlocker(doc, isEnabledFn, dispatchBlocked);
4760
+ const formBlocker = setupFormBlocker(doc, isEnabledFn, dispatchBlocked, dispatchFormSubmit);
4761
+ const windowOpenBlocker = setupWindowOpenBlocker(win, originalOpen, isEnabledFn, dispatchBlocked);
4762
+ const unloadBlocker = setupUnloadBlocker(win, isEnabledFn);
4763
+ const domMonitor = setupDOMMonitor(doc);
4764
+ ctx.cleanups = [linkBlocker, formBlocker, windowOpenBlocker, unloadBlocker, domMonitor];
4765
+ ctx.listeners.attach(cfg?.debug);
4766
+ ctx.running = true;
4767
+ ctx.logger.log('Started');
4768
+ }
4769
+ function stop$4(ctx) {
4770
+ if (!ctx.running)
4768
4771
  return;
4769
- s.cleanups.forEach((fn) => fn());
4770
- s.cleanups = [];
4771
- s.listeners.detach();
4772
- s.isEnabled = false;
4773
- s.showMessage = false;
4774
- s.running = false;
4775
- s.logger.log('Stopped');
4776
- }
4777
- function enable(s) {
4778
- if (!s.running) {
4779
- s.logger.warn('Blocker is not running.');
4772
+ ctx.cleanups.forEach((fn) => fn());
4773
+ ctx.cleanups = [];
4774
+ ctx.listeners.detach();
4775
+ ctx.isEnabled = false;
4776
+ ctx.showMessage = false;
4777
+ ctx.running = false;
4778
+ ctx.logger.log('Stopped');
4779
+ }
4780
+ function enable(ctx) {
4781
+ if (!ctx.running) {
4782
+ ctx.logger.warn('Blocker is not running.');
4780
4783
  return;
4781
4784
  }
4782
- s.isEnabled = true;
4783
- s.logger.log('Navigation blocking enabled');
4785
+ ctx.isEnabled = true;
4786
+ ctx.logger.log('Navigation blocking enabled');
4784
4787
  }
4785
- function disable(s) {
4786
- if (!s.running) {
4787
- s.logger.warn('Blocker is not running.');
4788
+ function disable(ctx) {
4789
+ if (!ctx.running) {
4790
+ ctx.logger.warn('Blocker is not running.');
4788
4791
  return;
4789
4792
  }
4790
- s.isEnabled = false;
4791
- s.logger.log('Navigation blocking disabled');
4793
+ ctx.isEnabled = false;
4794
+ ctx.logger.log('Navigation blocking disabled');
4792
4795
  }
4793
- function enableMessage(s) {
4794
- if (!s.running) {
4795
- s.logger.warn('Blocker is not running.');
4796
+ function enableMessage(ctx) {
4797
+ if (!ctx.running) {
4798
+ ctx.logger.warn('Blocker is not running.');
4796
4799
  return;
4797
4800
  }
4798
- s.showMessage = true;
4799
- s.logger.log('Navigation blocking message enabled');
4801
+ ctx.showMessage = true;
4802
+ ctx.logger.log('Navigation blocking message enabled');
4800
4803
  }
4801
- function disableMessage(s) {
4802
- if (!s.running) {
4803
- s.logger.warn('Blocker is not running.');
4804
+ function disableMessage(ctx) {
4805
+ if (!ctx.running) {
4806
+ ctx.logger.warn('Blocker is not running.');
4804
4807
  return;
4805
4808
  }
4806
- s.showMessage = false;
4807
- s.logger.log('Navigation blocking message disabled');
4809
+ ctx.showMessage = false;
4810
+ ctx.logger.log('Navigation blocking message disabled');
4808
4811
  }
4809
4812
  // ── Factory ───────────────────────────────────────────────────────────────────
4810
4813
  function createNavigationBlocker() {
4811
- const s = {
4814
+ const ctx = {
4812
4815
  logger: createLogger({ enabled: false, prefix: 'IframeNavigationBlocker' }),
4813
4816
  listeners: createNavigationListeners(),
4814
4817
  isEnabled: false,
@@ -4817,42 +4820,42 @@ function createNavigationBlocker() {
4817
4820
  cleanups: [],
4818
4821
  };
4819
4822
  return {
4820
- start: (iframe, cfg) => start$4(s, iframe, cfg),
4821
- stop: () => stop$4(s),
4822
- enable: () => enable(s),
4823
- disable: () => disable(s),
4824
- enableMessage: () => enableMessage(s),
4825
- disableMessage: () => disableMessage(s),
4826
- isRunning: () => s.running,
4827
- isBlockingEnabled: () => s.isEnabled,
4828
- getStateInfo: () => ({ isRunning: s.running, isEnabled: s.isEnabled, showMessage: s.showMessage }),
4823
+ start: (iframe, cfg) => start$4(ctx, iframe, cfg),
4824
+ stop: () => stop$4(ctx),
4825
+ enable: () => enable(ctx),
4826
+ disable: () => disable(ctx),
4827
+ enableMessage: () => enableMessage(ctx),
4828
+ disableMessage: () => disableMessage(ctx),
4829
+ isRunning: () => ctx.running,
4830
+ isBlockingEnabled: () => ctx.isEnabled,
4831
+ getStateInfo: () => ({ isRunning: ctx.running, isEnabled: ctx.isEnabled, showMessage: ctx.showMessage }),
4829
4832
  };
4830
4833
  }
4831
4834
 
4832
4835
  // ── Module-level functions ────────────────────────────────────────────────────
4833
- function attach(s, debug) {
4834
- s.logger.configure({ enabled: !!debug });
4835
- s.dimensionsListener = (e) => {
4836
+ function attach(ctx, debug) {
4837
+ ctx.logger.configure({ enabled: !!debug });
4838
+ ctx.dimensionsListener = (_e) => {
4836
4839
  // const ev = e as CustomEvent<IframeDimensionsDetail>;
4837
- // s.logger.log('Dimensions applied:', ev.detail);
4840
+ // ctx.logger.log('Dimensions applied:', ev.detail);
4838
4841
  };
4839
- window.addEventListener('iframe-dimensions-applied', s.dimensionsListener);
4842
+ window.addEventListener('iframe-dimensions-applied', ctx.dimensionsListener);
4840
4843
  }
4841
- function detach(s) {
4842
- if (s.dimensionsListener) {
4843
- window.removeEventListener('iframe-dimensions-applied', s.dimensionsListener);
4844
- s.dimensionsListener = null;
4844
+ function detach(ctx) {
4845
+ if (ctx.dimensionsListener) {
4846
+ window.removeEventListener('iframe-dimensions-applied', ctx.dimensionsListener);
4847
+ ctx.dimensionsListener = null;
4845
4848
  }
4846
4849
  }
4847
4850
  // ── Factory ───────────────────────────────────────────────────────────────────
4848
4851
  function createViewportListeners() {
4849
- const s = {
4852
+ const ctx = {
4850
4853
  logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
4851
4854
  dimensionsListener: null,
4852
4855
  };
4853
4856
  return {
4854
- attach: (debug) => attach(s, debug),
4855
- detach: () => detach(s),
4857
+ attach: (debug) => attach(ctx, debug),
4858
+ detach: () => detach(ctx),
4856
4859
  };
4857
4860
  }
4858
4861
 
@@ -4896,33 +4899,33 @@ const CRITICAL_PROPERTIES = [
4896
4899
  ];
4897
4900
 
4898
4901
  // ── Helpers ───────────────────────────────────────────────────────────────────
4899
- function getViewportUnitMap(s) {
4900
- if (!s.config)
4902
+ function getViewportUnitMap(ctx) {
4903
+ if (!ctx.config)
4901
4904
  throw new Error('Config is not initialized');
4902
4905
  return {
4903
- vh: s.config.targetHeight,
4904
- svh: s.config.targetHeight,
4905
- lvh: s.config.targetHeight,
4906
- dvh: s.config.targetHeight,
4907
- vw: s.config.targetWidth,
4908
- svw: s.config.targetWidth,
4909
- lvw: s.config.targetWidth,
4910
- dvw: s.config.targetWidth,
4911
- };
4912
- }
4913
- function calculateExpectedPx(s, value, unit) {
4914
- if (!s.config)
4906
+ vh: ctx.config.targetHeight,
4907
+ svh: ctx.config.targetHeight,
4908
+ lvh: ctx.config.targetHeight,
4909
+ dvh: ctx.config.targetHeight,
4910
+ vw: ctx.config.targetWidth,
4911
+ svw: ctx.config.targetWidth,
4912
+ lvw: ctx.config.targetWidth,
4913
+ dvw: ctx.config.targetWidth,
4914
+ };
4915
+ }
4916
+ function calculateExpectedPx(ctx, value, unit) {
4917
+ if (!ctx.config)
4915
4918
  throw new Error('Config is not initialized');
4916
4919
  const unitLower = unit.toLowerCase();
4917
4920
  if (unitLower === '%')
4918
- return (value / 100) * s.config.targetHeight;
4919
- return (value / 100) * (getViewportUnitMap(s)[unitLower] || 0);
4921
+ return (value / 100) * ctx.config.targetHeight;
4922
+ return (value / 100) * (getViewportUnitMap(ctx)[unitLower] || 0);
4920
4923
  }
4921
4924
  function isDefaultCssValue(value) {
4922
4925
  return DEFAULT_CSS_VALUES.includes(value);
4923
4926
  }
4924
- function shouldReplaceValue(s, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4925
- if (!s.config)
4927
+ function shouldReplaceValue(ctx, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4928
+ if (!ctx.config)
4926
4929
  return false;
4927
4930
  const computedPx = parseFloat(computedValue);
4928
4931
  if (isNaN(computedPx))
@@ -4935,86 +4938,86 @@ function shouldReplaceValue(s, computedValue, originalValue, tolerance = DEFAULT
4935
4938
  const num = parseFloat(value);
4936
4939
  if (isNaN(num))
4937
4940
  return false;
4938
- const expectedPx = calculateExpectedPx(s, num, unit);
4941
+ const expectedPx = calculateExpectedPx(ctx, num, unit);
4939
4942
  const diff = Math.abs(computedPx - expectedPx);
4940
4943
  if (diff <= tolerance) {
4941
- s.logger.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
4944
+ ctx.logger.log(`OK to replace: computed=${computedValue} matches expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
4942
4945
  return true;
4943
4946
  }
4944
- s.logger.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
4947
+ ctx.logger.log(`Skip replace: computed=${computedValue} differs from expected=${expectedPx.toFixed(2)}px (diff=${diff.toFixed(2)}px)`);
4945
4948
  return false;
4946
4949
  }
4947
- function applyPropertyWithVerification(s, element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4948
- if (originalValue && shouldReplaceValue(s, computedValue, originalValue, tolerance)) {
4950
+ function applyPropertyWithVerification(ctx, element, prop, computedValue, originalValue, tolerance = DEFAULT_TOLERANCE_PX) {
4951
+ if (originalValue && shouldReplaceValue(ctx, computedValue, originalValue, tolerance)) {
4949
4952
  element.style.setProperty(prop, computedValue, 'important');
4950
4953
  return true;
4951
4954
  }
4952
- else if (!originalValue) {
4955
+ if (!originalValue) {
4953
4956
  element.style.setProperty(prop, computedValue, 'important');
4954
4957
  return true;
4955
4958
  }
4956
4959
  return false;
4957
4960
  }
4958
4961
  // ── Exported module-level functions ───────────────────────────────────────────
4959
- function start$3(s, d, w, cfg, options = {}) {
4960
- if (s.running) {
4961
- s.logger.warn('Enforcer is already running. Call stop() first.');
4962
+ function start$3(ctx, d, w, cfg, options = {}) {
4963
+ if (ctx.running) {
4964
+ ctx.logger.warn('Enforcer is already running. Call stop() first.');
4962
4965
  return;
4963
4966
  }
4964
- s.doc = d;
4965
- s.win = w;
4966
- s.config = cfg;
4967
- s.running = true;
4968
- s.logger.configure({ enabled: !!options.debug });
4969
- s.logger.log('Started');
4967
+ ctx.doc = d;
4968
+ ctx.win = w;
4969
+ ctx.config = cfg;
4970
+ ctx.running = true;
4971
+ ctx.logger.configure({ enabled: !!options.debug });
4972
+ ctx.logger.log('Started');
4970
4973
  }
4971
- function stop$3(s) {
4972
- if (!s.running)
4974
+ function stop$3(ctx) {
4975
+ if (!ctx.running)
4973
4976
  return;
4974
- s.doc = null;
4975
- s.win = null;
4976
- s.config = null;
4977
- s.elementsWithViewportUnits.clear();
4978
- s.originalValues = new WeakMap();
4979
- s.running = false;
4980
- s.logger.log('Stopped');
4981
- }
4982
- function reset(s) {
4983
- if (!s.running) {
4984
- s.logger.warn('Enforcer is not running. Call start() first.');
4977
+ ctx.doc = null;
4978
+ ctx.win = null;
4979
+ ctx.config = null;
4980
+ ctx.elementsWithViewportUnits.clear();
4981
+ ctx.originalValues = new WeakMap();
4982
+ ctx.running = false;
4983
+ ctx.logger.log('Stopped');
4984
+ }
4985
+ function reset(ctx) {
4986
+ if (!ctx.running) {
4987
+ ctx.logger.warn('Enforcer is not running. Call start() first.');
4985
4988
  return;
4986
4989
  }
4987
- s.elementsWithViewportUnits.clear();
4988
- s.originalValues = new WeakMap();
4989
- s.logger.log('Reset');
4990
+ ctx.elementsWithViewportUnits.clear();
4991
+ ctx.originalValues = new WeakMap();
4992
+ ctx.logger.log('Reset');
4990
4993
  }
4991
- function trackElement(s, element, propertyOriginalValues) {
4992
- if (!s.running) {
4993
- s.logger.warn('Enforcer is not running. Call start() first.');
4994
+ function trackElement(ctx, element, propertyOriginalValues) {
4995
+ if (!ctx.running) {
4996
+ ctx.logger.warn('Enforcer is not running. Call start() first.');
4994
4997
  return;
4995
4998
  }
4996
- s.elementsWithViewportUnits.add(element);
4997
- let elementOriginals = s.originalValues.get(element);
4999
+ ctx.elementsWithViewportUnits.add(element);
5000
+ let elementOriginals = ctx.originalValues.get(element);
4998
5001
  if (!elementOriginals) {
4999
5002
  elementOriginals = new Map();
5000
- s.originalValues.set(element, elementOriginals);
5003
+ ctx.originalValues.set(element, elementOriginals);
5001
5004
  }
5002
5005
  propertyOriginalValues.forEach((value, prop) => {
5003
5006
  if (!elementOriginals.has(prop))
5004
5007
  elementOriginals.set(prop, value);
5005
5008
  });
5006
5009
  }
5007
- function processElement(s, element, options = {}) {
5008
- if (!s.running || !s.doc || !s.win || !s.config) {
5009
- s.logger.warn('Enforcer is not running.');
5010
+ function processElement(ctx, element, options = {}) {
5011
+ if (!ctx.running || !ctx.doc || !ctx.win || !ctx.config) {
5012
+ ctx.logger.warn('Enforcer is not running.');
5010
5013
  return 0;
5011
5014
  }
5012
- if (!s.elementsWithViewportUnits.has(element))
5015
+ if (!ctx.elementsWithViewportUnits.has(element))
5013
5016
  return 0;
5014
5017
  const htmlElement = element;
5015
- const computed = s.win.getComputedStyle(htmlElement);
5018
+ const computed = ctx.win.getComputedStyle(htmlElement);
5016
5019
  const inlineStyle = htmlElement.style;
5017
- const elementOriginals = s.originalValues.get(element);
5020
+ const elementOriginals = ctx.originalValues.get(element);
5018
5021
  const tolerance = options.tolerance ?? DEFAULT_TOLERANCE_PX;
5019
5022
  let count = 0;
5020
5023
  CRITICAL_PROPERTIES.forEach((prop) => {
@@ -5022,31 +5025,31 @@ function processElement(s, element, options = {}) {
5022
5025
  const inlineValue = inlineStyle.getPropertyValue(prop);
5023
5026
  if (computedValue && (!inlineValue || inlineValue !== computedValue) && !isDefaultCssValue(computedValue)) {
5024
5027
  const originalValue = elementOriginals?.get(prop) || '';
5025
- if (applyPropertyWithVerification(s, htmlElement, prop, computedValue, originalValue, tolerance))
5028
+ if (applyPropertyWithVerification(ctx, htmlElement, prop, computedValue, originalValue, tolerance))
5026
5029
  count++;
5027
5030
  }
5028
5031
  });
5029
5032
  return count;
5030
5033
  }
5031
- function processAll(s, options = {}) {
5032
- if (!s.running || !s.doc || !s.win || !s.config) {
5033
- s.logger.warn('Enforcer is not running.');
5034
+ function processAll(ctx, options = {}) {
5035
+ if (!ctx.running || !ctx.doc || !ctx.win || !ctx.config) {
5036
+ ctx.logger.warn('Enforcer is not running.');
5034
5037
  return 0;
5035
5038
  }
5036
5039
  let totalCount = 0;
5037
- s.elementsWithViewportUnits.forEach((element) => {
5038
- totalCount += processElement(s, element, options);
5040
+ ctx.elementsWithViewportUnits.forEach((element) => {
5041
+ totalCount += processElement(ctx, element, options);
5039
5042
  });
5040
- s.logger.log(`Enforced ${totalCount} computed styles for ${s.elementsWithViewportUnits.size} elements`);
5043
+ ctx.logger.log(`Enforced ${totalCount} computed styles for ${ctx.elementsWithViewportUnits.size} elements`);
5041
5044
  return totalCount;
5042
5045
  }
5043
- function updateConfig$2(s, cfg) {
5044
- if (!s.running || !s.config) {
5045
- s.logger.warn('Enforcer is not running.');
5046
+ function updateConfig$2(ctx, cfg) {
5047
+ if (!ctx.running || !ctx.config) {
5048
+ ctx.logger.warn('Enforcer is not running.');
5046
5049
  return;
5047
5050
  }
5048
- s.config = { ...s.config, ...cfg };
5049
- s.logger.log('Config updated:', cfg);
5051
+ ctx.config = { ...ctx.config, ...cfg };
5052
+ ctx.logger.log('Config updated:', cfg);
5050
5053
  }
5051
5054
 
5052
5055
  /**
@@ -5055,7 +5058,7 @@ function updateConfig$2(s, cfg) {
5055
5058
  */
5056
5059
  // ── Factory ───────────────────────────────────────────────────────────────────
5057
5060
  function createEnforcer() {
5058
- const s = {
5061
+ const ctx = {
5059
5062
  logger: createLogger({ enabled: false, prefix: 'ComputedStyleEnforcer' }),
5060
5063
  doc: null,
5061
5064
  win: null,
@@ -5065,19 +5068,19 @@ function createEnforcer() {
5065
5068
  running: false,
5066
5069
  };
5067
5070
  return {
5068
- start: (d, w, cfg, options) => start$3(s, d, w, cfg, options),
5069
- stop: () => stop$3(s),
5070
- reset: () => reset(s),
5071
- trackElement: (element, propertyOriginalValues) => trackElement(s, element, propertyOriginalValues),
5072
- processElement: (element, options) => processElement(s, element, options),
5073
- processAll: (options) => processAll(s, options),
5074
- updateConfig: (cfg) => updateConfig$2(s, cfg),
5071
+ start: (d, w, cfg, options) => start$3(ctx, d, w, cfg, options),
5072
+ stop: () => stop$3(ctx),
5073
+ reset: () => reset(ctx),
5074
+ trackElement: (element, propertyOriginalValues) => trackElement(ctx, element, propertyOriginalValues),
5075
+ processElement: (element, options) => processElement(ctx, element, options),
5076
+ processAll: (options) => processAll(ctx, options),
5077
+ updateConfig: (cfg) => updateConfig$2(ctx, cfg),
5075
5078
  getStateInfo: () => ({
5076
- isRunning: s.running,
5077
- trackedElementsCount: s.elementsWithViewportUnits.size,
5078
- hasConfig: !!s.config,
5079
+ isRunning: ctx.running,
5080
+ trackedElementsCount: ctx.elementsWithViewportUnits.size,
5081
+ hasConfig: !!ctx.config,
5079
5082
  }),
5080
- isRunning: () => s.running,
5083
+ isRunning: () => ctx.running,
5081
5084
  };
5082
5085
  }
5083
5086
 
@@ -5446,82 +5449,83 @@ register(`566240210141053597`, {
5446
5449
  });
5447
5450
 
5448
5451
  // ── Module-level functions ────────────────────────────────────────────────────
5449
- function start$2(s, iframe, cfg) {
5450
- if (s.running) {
5451
- s.logger.warn('Already running. Call stop() first.');
5452
+ function start$2(ctx, iframe, cfg) {
5453
+ if (ctx.running) {
5454
+ ctx.logger.warn('Already running. Call stop() first.');
5452
5455
  return;
5453
5456
  }
5454
5457
  if (!iframe.contentDocument || !iframe.contentWindow) {
5455
5458
  throw new Error('Iframe document or window not accessible');
5456
5459
  }
5457
- s.doc = iframe.contentDocument;
5458
- s.win = iframe.contentWindow;
5459
- s.config = cfg;
5460
- s.running = true;
5461
- s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
5462
- if (s.shopFix)
5463
- s.logger.log(`Shop fix loaded for "${cfg.shopId}":`, s.shopFix.description ?? '(no description)');
5464
- s.logger.configure({ enabled: !!cfg.debug });
5460
+ ctx.doc = iframe.contentDocument;
5461
+ ctx.win = iframe.contentWindow;
5462
+ ctx.config = cfg;
5463
+ ctx.running = true;
5464
+ ctx.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
5465
+ if (ctx.shopFix) {
5466
+ ctx.logger.log(`Shop fix loaded for "${cfg.shopId}":`, ctx.shopFix.description ?? '(no description)');
5467
+ }
5468
+ ctx.logger.configure({ enabled: !!cfg.debug });
5465
5469
  configure(!!cfg.debug);
5466
- s.enforcer.start(s.doc, s.win, cfg, { debug: !!cfg.debug });
5467
- s.listeners.attach(cfg.debug);
5468
- s.logger.log('Started');
5470
+ ctx.enforcer.start(ctx.doc, ctx.win, cfg, { debug: !!cfg.debug });
5471
+ ctx.listeners.attach(cfg.debug);
5472
+ ctx.logger.log('Started');
5469
5473
  }
5470
- function stop$2(s) {
5471
- if (!s.running)
5474
+ function stop$2(ctx) {
5475
+ if (!ctx.running)
5472
5476
  return;
5473
- s.enforcer.stop();
5474
- s.listeners.detach();
5475
- s.doc = null;
5476
- s.win = null;
5477
- s.config = null;
5478
- s.shopFix = null;
5479
- s.running = false;
5480
- s.logger.log('Stopped');
5481
- }
5482
- async function run(s) {
5483
- if (!s.running || !s.doc || !s.win || !s.config) {
5484
- s.logger.warn('Not running. Call start() first.');
5477
+ ctx.enforcer.stop();
5478
+ ctx.listeners.detach();
5479
+ ctx.doc = null;
5480
+ ctx.win = null;
5481
+ ctx.config = null;
5482
+ ctx.shopFix = null;
5483
+ ctx.running = false;
5484
+ ctx.logger.log('Stopped');
5485
+ }
5486
+ async function run(ctx) {
5487
+ if (!ctx.running || !ctx.doc || !ctx.win || !ctx.config) {
5488
+ ctx.logger.warn('Not running. Call start() first.');
5485
5489
  return { height: 1000, width: 1000 };
5486
5490
  }
5487
- const ctx = {
5488
- doc: s.doc,
5489
- win: s.win,
5490
- deviceType: s.config.deviceType,
5491
- targetWidth: s.config.targetWidth,
5492
- targetHeight: s.config.targetHeight,
5493
- debug: s.config.debug,
5494
- enforcer: s.enforcer,
5495
- };
5496
- const activeGlobal = getActiveFixes(ctx);
5491
+ const pipelineCtx = {
5492
+ doc: ctx.doc,
5493
+ win: ctx.win,
5494
+ deviceType: ctx.config.deviceType,
5495
+ targetWidth: ctx.config.targetWidth,
5496
+ targetHeight: ctx.config.targetHeight,
5497
+ debug: ctx.config.debug,
5498
+ enforcer: ctx.enforcer,
5499
+ };
5500
+ const activeGlobal = getActiveFixes(pipelineCtx);
5497
5501
  if (activeGlobal.length > 0)
5498
- s.logger.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
5502
+ ctx.logger.log(`Active global fixes: ${activeGlobal.map((f) => f.name).join(', ')}`);
5499
5503
  const tRun = perf$3.mark('viewport.run');
5500
5504
  try {
5501
- const result = await run$1(ctx, activeGlobal, s.shopFix);
5505
+ const result = await run$1(pipelineCtx, activeGlobal, ctx.shopFix);
5502
5506
  perf$3.measure('viewport.run', tRun);
5503
5507
  return result;
5504
5508
  }
5505
5509
  catch (err) {
5506
5510
  perf$3.measure('viewport.run', tRun);
5507
- s.logger.error('Critical error:', err);
5508
- return { height: s.doc.body?.scrollHeight || 1000, width: s.doc.body?.scrollWidth || 1000 };
5511
+ ctx.logger.error('Critical error:', err);
5512
+ return { height: ctx.doc.body?.scrollHeight || 1000, width: ctx.doc.body?.scrollWidth || 1000 };
5509
5513
  }
5510
5514
  }
5511
- function updateConfig$1(s, cfg) {
5512
- if (!s.running || !s.config) {
5513
- s.logger.warn('Not running. Call start() first.');
5515
+ function updateConfig$1(ctx, cfg) {
5516
+ if (!ctx.running || !ctx.config) {
5517
+ ctx.logger.warn('Not running. Call start() first.');
5514
5518
  return;
5515
5519
  }
5516
- s.config = { ...s.config, ...cfg };
5520
+ ctx.config = { ...ctx.config, ...cfg };
5517
5521
  if (cfg.shopId !== undefined)
5518
- s.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
5519
- s.enforcer.updateConfig(cfg);
5520
- s.logger.log('Config updated');
5522
+ ctx.shopFix = cfg.shopId != null ? get(cfg.shopId) : null;
5523
+ ctx.enforcer.updateConfig(cfg);
5524
+ ctx.logger.log('Config updated');
5521
5525
  }
5522
5526
  // ── Factory ───────────────────────────────────────────────────────────────────
5523
5527
  function createViewportProcessor() {
5524
- const s = {
5528
+ const ctx = {
5525
5529
  logger: createLogger({ enabled: false, prefix: 'ViewportReplacer' }),
5526
5530
  enforcer: createEnforcer(),
5527
5531
  listeners: createViewportListeners(),
@@ -5532,11 +5536,11 @@ function createViewportProcessor() {
5532
5536
  running: false,
5533
5537
  };
5534
5538
  return {
5535
- start: (iframe, cfg) => start$2(s, iframe, cfg),
5536
- stop: () => stop$2(s),
5537
- run: () => run(s),
5538
- updateConfig: (cfg) => updateConfig$1(s, cfg),
5539
- isRunning: () => s.running,
5539
+ start: (iframe, cfg) => start$2(ctx, iframe, cfg),
5540
+ stop: () => stop$2(ctx),
5541
+ run: () => run(ctx),
5542
+ updateConfig: (cfg) => updateConfig$1(ctx, cfg),
5543
+ isRunning: () => ctx.running,
5540
5544
  };
5541
5545
  }
5542
5546
 
@@ -5544,117 +5548,117 @@ function createViewportProcessor() {
5544
5548
  function dispatchDimensionsEvent(dimensions) {
5545
5549
  window.dispatchEvent(new CustomEvent('iframe-dimensions-applied', { detail: dimensions }));
5546
5550
  }
5547
- async function process(s) {
5548
- if (!s.iframe || !s.config)
5551
+ async function process(ctx) {
5552
+ if (!ctx.iframe || !ctx.config)
5549
5553
  return;
5550
- if (!s.iframe.contentDocument || !s.iframe.contentWindow) {
5551
- s.logger.error('Cannot access iframe document');
5552
- s.config.onError?.(new Error('Cannot access iframe document'));
5554
+ if (!ctx.iframe.contentDocument || !ctx.iframe.contentWindow) {
5555
+ ctx.logger.error('Cannot access iframe document');
5556
+ ctx.config.onError?.(new Error('Cannot access iframe document'));
5553
5557
  return;
5554
5558
  }
5555
5559
  const sessionId = `render-${Date.now()}`;
5556
5560
  perf$3.startSession(sessionId);
5557
5561
  const t0 = perf$3.mark('orchestrator.process');
5558
5562
  try {
5559
- s.logger.groupCollapsed('Processing...');
5560
- s.viewportReplacer.start(s.iframe, s.config);
5561
- s.navigationBlocker.start(s.iframe, { debug: s.config.debug });
5562
- const result = await s.viewportReplacer.run();
5563
+ ctx.logger.groupCollapsed('Processing...');
5564
+ ctx.viewportReplacer.start(ctx.iframe, ctx.config);
5565
+ ctx.navigationBlocker.start(ctx.iframe, { debug: ctx.config.debug });
5566
+ const result = await ctx.viewportReplacer.run();
5563
5567
  perf$3.measure('orchestrator.process', t0);
5564
5568
  perf$3.endSession();
5565
- s.logger.groupEnd();
5566
- s.logger.log('Process completed:', result);
5567
- s.config.onSuccess?.(result);
5569
+ ctx.logger.groupEnd();
5570
+ ctx.logger.log('Process completed:', result);
5571
+ ctx.config.onSuccess?.(result);
5568
5572
  dispatchDimensionsEvent(result);
5569
5573
  }
5570
5574
  catch (error) {
5571
5575
  perf$3.measure('orchestrator.process', t0);
5572
5576
  perf$3.endSession();
5573
- s.logger.error('Failed to process:', error);
5574
- s.config.onError?.(error);
5577
+ ctx.logger.error('Failed to process:', error);
5578
+ ctx.config.onError?.(error);
5575
5579
  }
5576
5580
  }
5577
- async function initialize(s) {
5578
- if (!s.iframe || !s.config) {
5579
- s.logger.error('iframe not found');
5580
- s.config?.onError?.(new Error('iframe not found'));
5581
+ async function initialize(ctx) {
5582
+ if (!ctx.iframe || !ctx.config) {
5583
+ ctx.logger.error('iframe not found');
5584
+ ctx.config?.onError?.(new Error('iframe not found'));
5581
5585
  return;
5582
5586
  }
5583
- if (s.iframe.contentDocument?.readyState === 'complete') {
5584
- await process(s);
5587
+ if (ctx.iframe.contentDocument?.readyState === 'complete') {
5588
+ await process(ctx);
5585
5589
  }
5586
5590
  else {
5587
- s.loadListener = () => process(s);
5588
- s.iframe.addEventListener('load', s.loadListener);
5591
+ ctx.loadListener = () => process(ctx);
5592
+ ctx.iframe.addEventListener('load', ctx.loadListener);
5589
5593
  }
5590
5594
  }
5591
- function start$1(s, cfg) {
5592
- if (s.running) {
5593
- s.logger.warn('Fixer is already running. Call stop() first.');
5595
+ function start$1(ctx, cfg) {
5596
+ if (ctx.running) {
5597
+ ctx.logger.warn('Fixer is already running. Call stop() first.');
5594
5598
  return;
5595
5599
  }
5596
- s.iframe = cfg.iframe;
5597
- s.config = cfg;
5598
- s.running = true;
5599
- s.logger.configure({ enabled: !!cfg.debug });
5600
- s.logger.log('Started');
5601
- initialize(s);
5600
+ ctx.iframe = cfg.iframe;
5601
+ ctx.config = cfg;
5602
+ ctx.running = true;
5603
+ ctx.logger.configure({ enabled: !!cfg.debug });
5604
+ ctx.logger.log('Started');
5605
+ initialize(ctx);
5602
5606
  }
5603
- function stop$1(s) {
5604
- if (!s.running)
5607
+ function stop$1(ctx) {
5608
+ if (!ctx.running)
5605
5609
  return;
5606
- s.viewportReplacer.stop();
5607
- s.heightObserver.stop();
5608
- s.navigationBlocker.stop();
5609
- if (s.iframe && s.loadListener) {
5610
- s.iframe.removeEventListener('load', s.loadListener);
5611
- s.loadListener = null;
5612
- }
5613
- s.iframe = null;
5614
- s.config = null;
5615
- s.running = false;
5616
- s.logger.log('Stopped');
5617
- }
5618
- function startHeightObserver(s) {
5619
- if (!s.iframe || !s.config)
5610
+ ctx.viewportReplacer.stop();
5611
+ ctx.heightObserver.stop();
5612
+ ctx.navigationBlocker.stop();
5613
+ if (ctx.iframe && ctx.loadListener) {
5614
+ ctx.iframe.removeEventListener('load', ctx.loadListener);
5615
+ ctx.loadListener = null;
5616
+ }
5617
+ ctx.iframe = null;
5618
+ ctx.config = null;
5619
+ ctx.running = false;
5620
+ ctx.logger.log('Stopped');
5621
+ }
5622
+ function startHeightObserver(ctx, config) {
5623
+ if (!ctx.iframe || !ctx.config)
5620
5624
  return;
5621
- s.heightObserver.stop();
5622
- s.heightObserver.start(s.iframe, {
5623
- iframe: s.iframe,
5624
- debug: s.config.debug,
5625
+ ctx.heightObserver.stop();
5626
+ ctx.heightObserver.start(ctx.iframe, {
5627
+ iframe: ctx.iframe,
5628
+ debug: ctx.config.debug,
5625
5629
  throttleMs: 25,
5626
5630
  debounceMs: 500,
5627
5631
  cooldownMs: 1000,
5628
- startDelayMs: s.config.heightObserverStartDelayMs,
5632
+ startDelayMs: ctx.config.heightObserverStartDelayMs,
5629
5633
  onHeightChange: (result) => {
5630
- s.config?.onHeightChange?.(result);
5634
+ config?.onHeightChange?.(result);
5631
5635
  dispatchDimensionsEvent(result);
5632
5636
  },
5633
5637
  onError: (error) => {
5634
- s.config?.onError?.(error);
5638
+ (config?.onError ?? ctx.config?.onError)?.(error);
5635
5639
  },
5636
5640
  });
5637
5641
  }
5638
- async function recalculate$1(s) {
5639
- if (!s.running) {
5640
- s.logger.warn('Fixer is not running.');
5642
+ async function recalculate$1(ctx) {
5643
+ if (!ctx.running) {
5644
+ ctx.logger.warn('Fixer is not running.');
5641
5645
  return;
5642
5646
  }
5643
- s.logger.log('Recalculating...');
5644
- await process(s);
5647
+ ctx.logger.log('Recalculating...');
5648
+ await process(ctx);
5645
5649
  }
5646
- function updateConfig(s, cfg) {
5647
- if (!s.running || !s.config) {
5648
- s.logger.warn('Fixer is not running.');
5650
+ function updateConfig(ctx, cfg) {
5651
+ if (!ctx.running || !ctx.config) {
5652
+ ctx.logger.warn('Fixer is not running.');
5649
5653
  return;
5650
5654
  }
5651
- s.config = { ...s.config, ...cfg };
5652
- s.viewportReplacer.updateConfig(cfg);
5653
- s.logger.log('Config updated');
5655
+ ctx.config = { ...ctx.config, ...cfg };
5656
+ ctx.viewportReplacer.updateConfig(cfg);
5657
+ ctx.logger.log('Config updated');
5654
5658
  }
5655
5659
  // ── Factory ───────────────────────────────────────────────────────────────────
5656
5660
  function createOrchestrator() {
5657
- const s = {
5661
+ const ctx = {
5658
5662
  logger: createLogger({ enabled: false, prefix: 'IframeFixer' }),
5659
5663
  viewportReplacer: createViewportProcessor(),
5660
5664
  navigationBlocker: createNavigationBlocker(),
@@ -5665,23 +5669,23 @@ function createOrchestrator() {
5665
5669
  loadListener: null,
5666
5670
  };
5667
5671
  return {
5668
- start: (cfg) => start$1(s, cfg),
5669
- stop: () => stop$1(s),
5670
- recalculate: () => recalculate$1(s),
5671
- updateConfig: (cfg) => updateConfig(s, cfg),
5672
- enableNavigationBlocking: () => s.navigationBlocker.enable(),
5673
- enableNavigationBlockingMessage: () => s.navigationBlocker.enableMessage(),
5674
- disableNavigationBlocking: () => s.navigationBlocker.disable(),
5675
- disableNavigationBlockingMessage: () => s.navigationBlocker.disableMessage(),
5676
- startHeightObserver: () => startHeightObserver(s),
5677
- isRunning: () => s.running,
5672
+ start: (cfg) => start$1(ctx, cfg),
5673
+ stop: () => stop$1(ctx),
5674
+ recalculate: () => recalculate$1(ctx),
5675
+ updateConfig: (cfg) => updateConfig(ctx, cfg),
5676
+ enableNavigationBlocking: () => ctx.navigationBlocker.enable(),
5677
+ enableNavigationBlockingMessage: () => ctx.navigationBlocker.enableMessage(),
5678
+ disableNavigationBlocking: () => ctx.navigationBlocker.disable(),
5679
+ disableNavigationBlockingMessage: () => ctx.navigationBlocker.disableMessage(),
5680
+ startHeightObserver: (config) => startHeightObserver(ctx, config),
5681
+ isRunning: () => ctx.running,
5678
5682
  getStateInfo: () => ({
5679
- isRunning: s.running,
5680
- hasIframe: !!s.iframe,
5681
- hasConfig: !!s.config,
5682
- hasNavigationBlocker: s.navigationBlocker.isRunning(),
5683
- hasHeightObserver: s.heightObserver.isRunning(),
5684
- viewportReplacerRunning: s.viewportReplacer.isRunning(),
5683
+ isRunning: ctx.running,
5684
+ hasIframe: !!ctx.iframe,
5685
+ hasConfig: !!ctx.config,
5686
+ hasNavigationBlocker: ctx.navigationBlocker.isRunning(),
5687
+ hasHeightObserver: ctx.heightObserver.isRunning(),
5688
+ viewportReplacerRunning: ctx.viewportReplacer.isRunning(),
5685
5689
  }),
5686
5690
  };
5687
5691
  }
@@ -5690,50 +5694,50 @@ function createOrchestrator() {
5690
5694
  * Iframe Helper — factory entry point.
5691
5695
  *
5692
5696
  * Each call to `createIframeHelper()` returns a fully isolated instance
5693
- * with its own processor state. Use one instance per iframe.
5697
+ * with its own processor ctx. Use one instance per iframe.
5694
5698
  */
5695
5699
  // ── Module-level functions ────────────────────────────────────────────────────
5696
- function start(s, config) {
5697
- if (s.running) {
5700
+ function start(ctx, config) {
5701
+ if (ctx.running) {
5698
5702
  console.warn('[IframeHelper] Already running. Call stop() first.');
5699
5703
  return;
5700
5704
  }
5701
- s.fixer.start(config);
5702
- s.running = true;
5705
+ ctx.fixer.start(config);
5706
+ ctx.running = true;
5703
5707
  }
5704
- function stop(s) {
5705
- if (!s.running)
5708
+ function stop(ctx) {
5709
+ if (!ctx.running)
5706
5710
  return;
5707
- s.fixer.stop();
5708
- s.running = false;
5711
+ ctx.fixer.stop();
5712
+ ctx.running = false;
5709
5713
  }
5710
- async function recalculate(s) {
5711
- if (!s.running) {
5714
+ async function recalculate(ctx) {
5715
+ if (!ctx.running) {
5712
5716
  console.warn('[IframeHelper] Not running. Call start() first.');
5713
5717
  return;
5714
5718
  }
5715
- await s.fixer.recalculate();
5719
+ await ctx.fixer.recalculate();
5716
5720
  }
5717
- function enableNavigationBlocking(s) {
5718
- if (!s.running) {
5721
+ function enableNavigationBlocking(ctx) {
5722
+ if (!ctx.running) {
5719
5723
  console.warn('[IframeHelper] Not running. Call start() first.');
5720
5724
  return;
5721
5725
  }
5722
- s.fixer.enableNavigationBlocking();
5726
+ ctx.fixer.enableNavigationBlocking();
5723
5727
  }
5724
5728
  // ── Factory ───────────────────────────────────────────────────────────────────
5725
5729
  function createIframeHelper() {
5726
- const s = {
5730
+ const ctx = {
5727
5731
  fixer: createOrchestrator(),
5728
5732
  running: false,
5729
5733
  };
5730
5734
  return {
5731
- start: (config) => start(s, config),
5732
- stop: () => stop(s),
5733
- recalculate: () => recalculate(s),
5734
- enableNavigationBlocking: () => enableNavigationBlocking(s),
5735
- startHeightObserver: () => s.fixer.startHeightObserver(),
5736
- isRunning: () => s.running,
5735
+ start: (config) => start(ctx, config),
5736
+ stop: () => stop(ctx),
5737
+ recalculate: () => recalculate(ctx),
5738
+ enableNavigationBlocking: () => enableNavigationBlocking(ctx),
5739
+ startHeightObserver: (config) => ctx.fixer.startHeightObserver(config),
5740
+ isRunning: () => ctx.running,
5737
5741
  };
5738
5742
  }
5739
5743
 
@@ -6168,6 +6172,7 @@ class ScrollBucketRenderer {
6168
6172
  this.redrawTimeout = setTimeout(() => this.draw(this.lastData), REDRAW_INTERVAL);
6169
6173
  };
6170
6174
  attachDimensionsListener = () => {
6175
+ this.detachDimensionsListener();
6171
6176
  this.dimensionsListener = () => this.redraw();
6172
6177
  window.addEventListener('iframe-dimensions-applied', this.dimensionsListener);
6173
6178
  };
@@ -6212,6 +6217,7 @@ class ScrollBucketRenderer {
6212
6217
  const doc = this.heatmap.state.window.document;
6213
6218
  const body = doc.body;
6214
6219
  const de = doc.documentElement;
6220
+ // Same formula as HeatmapHelper.scroll() — self-contained, no external dependency
6215
6221
  const height = Math.max(body.scrollHeight, body.offsetHeight, de.clientHeight, de.scrollHeight, de.offsetHeight);
6216
6222
  // Same canvas setup as HeatmapHelper.scroll(): full content height, top=0
6217
6223
  canvas.height = Math.min(height, CANVAS_MAX_HEIGHT);
@@ -6220,23 +6226,32 @@ class ScrollBucketRenderer {
6220
6226
  return;
6221
6227
  const buckets = this.mapToBuckets(data);
6222
6228
  const maxPercent = buckets.length > 0 ? Math.max(...buckets.map((b) => b.percent)) : 0;
6223
- // Coldest hue (240 = blue) used as the baseline for buckets with no data
6224
- const coldColor = 'hsla(240, 100%, 50%, 0.6)';
6225
- const gradient = context.createLinearGradient(0, 0, 0, canvas.height);
6226
- if (buckets.length === 0 || maxPercent <= 0) {
6227
- // No data fill entire canvas with the coldest color
6228
- gradient.addColorStop(0, coldColor);
6229
- gradient.addColorStop(1, coldColor);
6230
- }
6231
- else {
6229
+ // Build a per-percentage-point hue array (same pattern as AttentionMapRenderer)
6230
+ // Cold hue (240 = blue) is the baseline when there is no data
6231
+ const hueStops = new Array(101).fill(240);
6232
+ if (buckets.length > 0 && maxPercent > 0) {
6233
+ // Pass 1: fill each bucket's pure color (exclusive of shared boundary point)
6232
6234
  for (const bucket of buckets) {
6233
- const stopMid = (bucket.startY + bucket.endY) / 2 / 100;
6234
- // Same hue direction as HeatmapHelper.scroll() (MaxHue = 240):
6235
6235
  // high percent → hue 0 (red/hot), low percent → hue 240 (blue/cold)
6236
- const hue = (1 - bucket.percent / maxPercent) * 240;
6237
- const color = `hsla(${Math.round(hue)}, 100%, 50%, 0.6)`;
6238
- gradient.addColorStop(stopMid, color);
6236
+ const hue = Math.round((1 - bucket.percent / maxPercent) * 240);
6237
+ for (let i = bucket.startY; i < bucket.endY; i++) {
6238
+ hueStops[i] = hue;
6239
+ }
6239
6240
  }
6241
+ // Set last point of final bucket
6242
+ const last = buckets[buckets.length - 1];
6243
+ hueStops[last.endY] = Math.round((1 - last.percent / maxPercent) * 240);
6244
+ // Pass 2: center transitions at bucket boundaries (average of two adjacent hues)
6245
+ for (let b = 0; b < buckets.length - 1; b++) {
6246
+ const boundary = buckets[b].endY; // = buckets[b+1].startY
6247
+ const hueA = Math.round((1 - buckets[b].percent / maxPercent) * 240);
6248
+ const hueB = Math.round((1 - buckets[b + 1].percent / maxPercent) * 240);
6249
+ hueStops[boundary] = Math.round((hueA + hueB) / 2);
6250
+ }
6251
+ }
6252
+ const gradient = context.createLinearGradient(0, 0, 0, canvas.height);
6253
+ for (let i = 0; i <= 100; i++) {
6254
+ gradient.addColorStop(i / 100, `hsla(${hueStops[i]}, 100%, 50%, 0.6)`);
6240
6255
  }
6241
6256
  context.fillStyle = gradient;
6242
6257
  context.fillRect(0, 0, canvas.width, canvas.height);
@@ -6245,34 +6260,19 @@ class ScrollBucketRenderer {
6245
6260
  * Convert flat position markers → structured buckets with startY/endY.
6246
6261
  *
6247
6262
  * Input positions: [0, 5, 10, 15, ..., 95]
6248
- * position=0 → { startY: 0, endY: 5 } (special start marker)
6249
- * position=10 → { startY: 5, endY: 10 }
6250
- * position=15 → { startY: 10, endY: 15 }
6263
+ * position=0 → { startY: 0, endY: 5 }
6264
+ * position=5 → { startY: 5, endY: 10 }
6265
+ * position=95 → { startY: 95, endY: 100 }
6266
+ * Each position is the START of its bucket; end = next position (or 100 for last).
6251
6267
  */
6252
6268
  mapToBuckets = (data) => {
6253
6269
  const sorted = [...data].sort((a, b) => a.position - b.position);
6254
- const buckets = [];
6255
- for (let i = 0; i < sorted.length; i++) {
6256
- const current = sorted[i];
6257
- let startY;
6258
- let endY;
6259
- if (current.position === 0) {
6260
- // position=0 is the start marker → range 0 to next position
6261
- const next = sorted[i + 1];
6262
- if (!next)
6263
- continue;
6264
- startY = 0;
6265
- endY = next.position;
6266
- }
6267
- else {
6268
- // Each non-zero position is the END of its bucket; start = previous position
6269
- const prev = sorted[i - 1];
6270
- startY = prev ? prev.position : 0;
6271
- endY = current.position;
6272
- }
6273
- buckets.push({ startY, endY, value: current.value, percent: current.percent });
6274
- }
6275
- return buckets;
6270
+ return sorted.map((current, i) => ({
6271
+ startY: current.position,
6272
+ endY: sorted[i + 1]?.position ?? 100,
6273
+ value: current.value,
6274
+ percent: current.percent,
6275
+ }));
6276
6276
  };
6277
6277
  }
6278
6278
 
@@ -6750,11 +6750,7 @@ const useHeatmapIframeProcessor = () => {
6750
6750
  const reset = useCallback(() => {
6751
6751
  pendingRef.current = null;
6752
6752
  }, []);
6753
- const run = useCallback((iframe, t0, abort) => {
6754
- if (viewport.width === 0 || viewport.height === 0) {
6755
- pendingRef.current = { iframe, t0, abort };
6756
- return;
6757
- }
6753
+ const callStartIframe = useCallback((iframe, t0, abort) => {
6758
6754
  startIframe({
6759
6755
  helperRef,
6760
6756
  iframe,
@@ -6762,16 +6758,30 @@ const useHeatmapIframeProcessor = () => {
6762
6758
  deviceType,
6763
6759
  size: viewport,
6764
6760
  t0,
6765
- onSuccess: (height) => {
6761
+ onSuccess: (data) => {
6766
6762
  if (abort.signal.aborted)
6767
6763
  return;
6768
- if (height)
6769
- setIframeHeight(height);
6764
+ if (data.height)
6765
+ setIframeHeight(data.height);
6770
6766
  setIsDomLoaded(true);
6771
- helperRef.current?.startHeightObserver();
6767
+ helperRef.current?.startHeightObserver({
6768
+ onHeightChange: (data) => {
6769
+ if (abort.signal.aborted)
6770
+ return;
6771
+ if (data.height)
6772
+ setIframeHeight(data.height);
6773
+ },
6774
+ });
6772
6775
  },
6773
6776
  });
6774
- }, [deviceType]);
6777
+ }, [deviceType, shopId, viewport, setIframeHeight, setIsDomLoaded]);
6778
+ const run = useCallback((iframe, t0, abort) => {
6779
+ if (viewport.width === 0 || viewport.height === 0) {
6780
+ pendingRef.current = { iframe, t0, abort };
6781
+ return;
6782
+ }
6783
+ callStartIframe(iframe, t0, abort);
6784
+ }, [callStartIframe, viewport]);
6775
6785
  // Retry when dims become available
6776
6786
  useEffect(() => {
6777
6787
  if (viewport.width === 0 || viewport.height === 0)
@@ -6782,29 +6792,8 @@ const useHeatmapIframeProcessor = () => {
6782
6792
  pendingRef.current = null;
6783
6793
  if (abort.signal.aborted)
6784
6794
  return;
6785
- startIframe({
6786
- helperRef,
6787
- iframe,
6788
- shopId,
6789
- deviceType,
6790
- size: viewport,
6791
- t0,
6792
- onSuccess: (height) => {
6793
- if (abort.signal.aborted)
6794
- return;
6795
- if (height)
6796
- setIframeHeight(height);
6797
- setIsDomLoaded(true);
6798
- helperRef.current?.startHeightObserver();
6799
- },
6800
- onHeightChange: (height) => {
6801
- if (abort.signal.aborted)
6802
- return;
6803
- if (height)
6804
- setIframeHeight(height);
6805
- },
6806
- });
6807
- }, [viewport]); // eslint-disable-line react-hooks/exhaustive-deps
6795
+ callStartIframe(iframe, t0, abort);
6796
+ }, [viewport, callStartIframe]);
6808
6797
  useEffect(() => {
6809
6798
  return () => {
6810
6799
  helperRef.current?.stop();
@@ -6814,7 +6803,7 @@ const useHeatmapIframeProcessor = () => {
6814
6803
  return { run, reset };
6815
6804
  };
6816
6805
  // ── Helpers ───────────────────────────────────────────────────────────────────
6817
- function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Desktop, size, t0, onSuccess, onHeightChange, }) {
6806
+ function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Desktop, size, t0, onSuccess, }) {
6818
6807
  const docWidth = size.width ?? 0;
6819
6808
  const docHeight = size.height ?? 0;
6820
6809
  if (docHeight === 0)
@@ -6835,11 +6824,7 @@ function startIframe({ helperRef, iframe, shopId, deviceType = EDeviceType.Deskt
6835
6824
  perf$1.measure('IframeHelper processing', tHelper);
6836
6825
  perf$1.measure('Total render', t0);
6837
6826
  iframe.style.height = `${data.height}px`;
6838
- onSuccess(data.height);
6839
- },
6840
- onHeightChange: (data) => {
6841
- iframe.style.height = `${data.height}px`;
6842
- onHeightChange?.(data.height);
6827
+ onSuccess(data);
6843
6828
  },
6844
6829
  });
6845
6830
  }