@gemx-dev/heatmap-react 3.5.92-dev.34 → 3.5.92-dev.36

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