@preprio/toolkit 0.2.0 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -395,6 +395,20 @@ function walkTextNodes(root, visit) {
395
395
  visit(node);
396
396
  }
397
397
  }
398
+ function resolveEditTarget(node) {
399
+ const parent = node.parentElement;
400
+ if (!parent) return null;
401
+ const editTarget = parent.closest("[data-prepr-edit-target]");
402
+ if (editTarget) return editTarget;
403
+ return isRenderedElement(parent) ? parent : null;
404
+ }
405
+ function isRenderedElement(element) {
406
+ if (element.hidden) return false;
407
+ if (element.getClientRects().length === 0) return false;
408
+ const style = element.ownerDocument.defaultView?.getComputedStyle(element);
409
+ if (!style) return true;
410
+ return style.visibility !== "hidden" && style.display !== "none";
411
+ }
398
412
  function tagEncodedElement(element, decoded) {
399
413
  element.setAttribute("data-prepr-encoded", "");
400
414
  element.setAttribute("data-prepr-href", decoded.href);
@@ -403,32 +417,45 @@ function tagEncodedElement(element, decoded) {
403
417
 
404
418
  // src/core/stega/auto-clean.ts
405
419
  var debug2 = createScopedLogger("stega:auto-clean");
406
- function createStegaAutoClean() {
420
+ function createStegaAutoClean(options) {
421
+ const stripText = options?.enabled ?? true;
407
422
  let observer = null;
408
423
  let processing = false;
409
424
  let cleaned = /* @__PURE__ */ new WeakMap();
425
+ let pendingHidden = /* @__PURE__ */ new Set();
426
+ let pendingDirty = /* @__PURE__ */ new Set();
410
427
  let debounceTimeout = null;
411
428
  function cleanTextNode(textNode) {
412
429
  if (isIgnoredTextNode(textNode)) return false;
413
430
  const textContent = textNode.textContent;
414
431
  const info = cleaned.get(textNode);
415
- if (info && textContent === info.cleaned) return false;
432
+ const settled = stripText ? info?.cleaned : info?.original;
433
+ if (info && textContent === settled) {
434
+ const shown = resolveEditTarget(textNode);
435
+ if (!shown) return false;
436
+ pendingHidden.delete(textNode);
437
+ if (shown.hasAttribute("data-prepr-encoded")) return false;
438
+ tagEncodedElement(shown, info.decoded);
439
+ return true;
440
+ }
416
441
  try {
417
442
  const { cleaned: stripped, encoded } = (0, import_stega2.vercelStegaSplit)(textContent);
418
443
  if (!encoded || stripped === textContent) return false;
419
444
  const decoded = decodeStega(textContent);
420
445
  if (!decoded?.href) return false;
421
- cleaned.set(textNode, { original: textContent, cleaned: stripped });
422
- textNode.textContent = stripped;
423
- let target = textNode.parentElement;
424
- const editTargetParent = textNode.parentElement?.closest(
425
- "[data-prepr-edit-target]"
426
- );
427
- if (editTargetParent) target = editTargetParent;
446
+ cleaned.set(textNode, {
447
+ original: textContent,
448
+ cleaned: stripped,
449
+ decoded
450
+ });
451
+ if (stripText) textNode.textContent = stripped;
452
+ const target = resolveEditTarget(textNode);
428
453
  if (target) {
454
+ pendingHidden.delete(textNode);
429
455
  tagEncodedElement(target, decoded);
430
456
  return true;
431
457
  }
458
+ pendingHidden.add(textNode);
432
459
  } catch (error) {
433
460
  debug2.log("error cleaning text node", error);
434
461
  }
@@ -437,8 +464,10 @@ function createStegaAutoClean() {
437
464
  function scanAndClean() {
438
465
  processing = true;
439
466
  walkTextNodes(document.body, cleanTextNode);
440
- const title = (0, import_stega2.vercelStegaSplit)(document.title);
441
- if (title.encoded) document.title = title.cleaned;
467
+ if (stripText) {
468
+ const title = (0, import_stega2.vercelStegaSplit)(document.title);
469
+ if (title.encoded) document.title = title.cleaned;
470
+ }
442
471
  processing = false;
443
472
  }
444
473
  function collectAffected(mutations) {
@@ -463,15 +492,37 @@ function createStegaAutoClean() {
463
492
  });
464
493
  return affected;
465
494
  }
495
+ function retryPendingHidden() {
496
+ if (pendingHidden.size === 0) return;
497
+ processing = true;
498
+ [...pendingHidden].forEach((textNode) => {
499
+ if (!textNode.isConnected) {
500
+ pendingHidden.delete(textNode);
501
+ return;
502
+ }
503
+ cleanTextNode(textNode);
504
+ });
505
+ processing = false;
506
+ }
466
507
  function handleMutations(mutations) {
467
508
  if (processing) return;
468
509
  const affected = collectAffected(mutations);
469
- if (affected.size === 0) return;
510
+ if (affected.size === 0) {
511
+ retryPendingHidden();
512
+ return;
513
+ }
514
+ affected.forEach((textNode) => pendingDirty.add(textNode));
470
515
  if (debounceTimeout) clearTimeout(debounceTimeout);
471
516
  debounceTimeout = setTimeout(() => {
517
+ debounceTimeout = null;
472
518
  processing = true;
473
- affected.forEach((textNode) => cleanTextNode(textNode));
519
+ const batch = [...pendingDirty];
520
+ pendingDirty.clear();
521
+ batch.forEach((textNode) => {
522
+ if (textNode.isConnected) cleanTextNode(textNode);
523
+ });
474
524
  processing = false;
525
+ retryPendingHidden();
475
526
  }, 50);
476
527
  }
477
528
  function setupObserver() {
@@ -479,7 +530,11 @@ function createStegaAutoClean() {
479
530
  observer.observe(document.body, {
480
531
  childList: true,
481
532
  subtree: true,
482
- characterData: true
533
+ characterData: true,
534
+ // A dropdown opening only toggles a class or inline style; without these
535
+ // the nodes it reveals are never revisited and stay untagged.
536
+ attributes: true,
537
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
483
538
  });
484
539
  }
485
540
  function start() {
@@ -498,6 +553,8 @@ function createStegaAutoClean() {
498
553
  observer = null;
499
554
  }
500
555
  cleaned = /* @__PURE__ */ new WeakMap();
556
+ pendingHidden = /* @__PURE__ */ new Set();
557
+ pendingDirty = /* @__PURE__ */ new Set();
501
558
  debug2.log("stega auto-clean stopped");
502
559
  }
503
560
  return { start, stop };
@@ -520,7 +577,7 @@ var StegaElements = class {
520
577
  tagFromTextNode(node) {
521
578
  const decoded = this.decode(node.textContent);
522
579
  if (!decoded?.href) return false;
523
- const target = node.parentElement;
580
+ const target = resolveEditTarget(node);
524
581
  if (!target || target.hasAttribute("data-prepr-encoded")) return false;
525
582
  tagEncodedElement(target, decoded);
526
583
  return true;
@@ -566,8 +623,13 @@ var StegaElements = class {
566
623
  if (mutation.type === "characterData") {
567
624
  addedNodes.add(mutation.target);
568
625
  }
626
+ if (mutation.type === "attributes") {
627
+ addedNodes.add(mutation.target);
628
+ }
629
+ });
630
+ addedNodes.forEach((node) => {
631
+ if (node.isConnected) this.scanNode(node);
569
632
  });
570
- addedNodes.forEach((node) => this.scanNode(node));
571
633
  pending = [];
572
634
  this.elements = document.querySelectorAll("[data-prepr-encoded]");
573
635
  onUpdate?.();
@@ -580,7 +642,11 @@ var StegaElements = class {
580
642
  this.observer.observe(document.body, {
581
643
  childList: true,
582
644
  subtree: true,
583
- characterData: true
645
+ characterData: true,
646
+ // Reveal-on-class/style (dropdowns, accordions) changes no text and adds
647
+ // no nodes, but does change what is hoverable and needs a rescan.
648
+ attributes: true,
649
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
584
650
  });
585
651
  }
586
652
  /** Drops the active class but keeps the data attributes, unlike cleanup(). */
@@ -669,11 +735,13 @@ var StegaOverlay = class {
669
735
  const maxTop = window.scrollY + window.innerHeight - tooltip.clientHeight - 4;
670
736
  const minLeft = window.scrollX + 4;
671
737
  const maxLeft = window.scrollX + window.innerWidth - tooltip.clientWidth - 4;
672
- if (top < minTop) {
738
+ const below = top < minTop;
739
+ if (below) {
673
740
  top = rect.bottom + window.scrollY + 2;
674
741
  }
675
742
  top = Math.max(minTop, Math.min(top, maxTop));
676
743
  left = Math.max(minLeft, Math.min(left, maxLeft));
744
+ tooltip.dataset.preprPlacement = below ? "below" : "above";
677
745
  tooltip.style.top = `${top}px`;
678
746
  tooltip.style.left = `${left}px`;
679
747
  });
@@ -805,7 +873,7 @@ var StegaProximity = class {
805
873
  };
806
874
 
807
875
  // src/core/stega/stega.generated.ts
808
- var STEGA_STYLES = '[data-prepr-encoded]{position:relative}.prepr-overlay{pointer-events:none;z-index:10000;border:2px solid #4f46e5;border-radius:4px 0 4px 4px;transition:all .2s ease-in-out;position:absolute}.prepr-tooltip{color:#fff;white-space:nowrap;z-index:10001;text-align:center;pointer-events:auto;cursor:pointer;background-color:#4f46e5;border-radius:4px 4px 0 0;min-width:80px;padding:4px 8px;font-size:12px;line-height:1;transition:opacity .2s ease-in-out;position:absolute}.prepr-tooltip:hover{background-color:#4338ca}.prepr-proximity-highlight{z-index:1;position:relative}.prepr-proximity-highlight,.prepr-proximity-highlight *{overflow:visible!important}.prepr-proximity-highlight:before{content:"";pointer-events:none;background:radial-gradient(circle var(--gradient-size) at var(--cursor-x) var(--cursor-y), #4f46e526 0%, #2563eb00 70%);z-index:9999;border:2px solid #4f46e526;border-radius:4px;transition:all .2s;position:absolute;top:-2px;bottom:-2px;left:-4px;right:-4px;overflow:visible}';
876
+ var STEGA_STYLES = '[data-prepr-encoded]{position:relative}.prepr-overlay{pointer-events:none;z-index:10000;border:2px solid #4f46e5;border-radius:4px 0 4px 4px;transition:all .2s ease-in-out;position:absolute}.prepr-tooltip{color:#fff;white-space:nowrap;z-index:10001;text-align:center;pointer-events:auto;cursor:pointer;background-color:#4f46e5;border-radius:4px 4px 0 0;min-width:80px;padding:4px 8px;font-size:12px;line-height:1;transition:opacity .2s ease-in-out;position:absolute}.prepr-tooltip[data-prepr-placement=below]{border-radius:0 0 4px 4px}.prepr-tooltip:hover{background-color:#4338ca}.prepr-proximity-highlight{z-index:1;position:relative}.prepr-proximity-highlight,.prepr-proximity-highlight *{overflow:visible!important}.prepr-proximity-highlight:before{content:"";pointer-events:none;background:radial-gradient(circle var(--gradient-size) at var(--cursor-x) var(--cursor-y), #4f46e526 0%, #2563eb00 70%);z-index:9999;border:2px solid #4f46e526;border-radius:4px;transition:all .2s;position:absolute;top:-2px;bottom:-2px;left:-4px;right:-4px;overflow:visible}';
809
877
 
810
878
  // src/core/stega/styles.ts
811
879
  var STEGA_STYLE_MARKER = "data-prepr-stega";
@@ -1354,7 +1422,7 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
1354
1422
  </svg>`;
1355
1423
 
1356
1424
  // src/core/ui/toolbar.generated.ts
1357
- var TOOLBAR_CSS = ":host{--prepr-primary:#4338ca;--prepr-bg:#eef2ff;--prepr-text:#1f2937;--prepr-radius:8px;--prepr-shadow:0px 0px 40px 0px #1f29373d;--prepr-z-index:10000;--prepr-primary-50:#eef2ff;--prepr-primary-100:#e0e7ff;--prepr-primary-800:#3730a3;--prepr-indigo-600:#4f46e5;--prepr-indigo-50:#eef2ff;--prepr-indigo-700:#4338ca;--prepr-secondary-400:#fb923c;--prepr-secondary-500:#f97316;--prepr-gray-100:#f3f4f6;--prepr-gray-200:#e5e7eb;--prepr-gray-300:#d1d5db;--prepr-gray-400:#9ca3af;--prepr-gray-500:#6b7280;--prepr-gray-700:#374151;--prepr-gray-800:#1f2937;--prepr-gray-900:#111827;--prepr-shadow-sm:0px 0px 12px 0px #c3c3c3cc;color:var(--prepr-text);box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5}:host *,:host :before,:host :after,*,:before,:after{box-sizing:border-box}button{font-family:inherit;font-size:inherit;margin:0}.prepr-regular-text{font-size:.875rem;font-weight:500;line-height:1.5}.prepr-backdrop{z-index:calc(var(--prepr-z-index) - 1);opacity:0;pointer-events:none;background:#0000001a;transition:opacity .2s ease-in-out;position:fixed;top:0;bottom:0;left:0;right:0}.prepr-backdrop[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-container{z-index:var(--prepr-z-index);justify-content:flex-end;align-items:center;display:flex;position:fixed;top:calc(50% - 64px);right:0}.prepr-toggle-holder{padding:.5rem}.prepr-toggle{cursor:pointer;background:var(--prepr-primary);color:#fff;border:none;border-radius:9999px;justify-content:center;align-items:center;width:2.25rem;height:2.25rem;display:flex}.prepr-toggle>span{display:flex}.prepr-toggle svg{color:#fff}.prepr-panel{z-index:var(--prepr-z-index);opacity:0;pointer-events:none;justify-content:flex-end;padding:.75rem;transition:opacity .2s ease-in-out;display:flex;position:fixed;top:50%;right:0;transform:translateY(-50%)}.prepr-panel[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-content{box-shadow:var(--prepr-shadow);border-radius:var(--prepr-radius);background:var(--prepr-bg);flex-direction:column;gap:2.5rem;width:100%;padding:1.5rem;display:flex}@media (min-width:640px){.prepr-panel{margin-right:4rem;padding:0}.prepr-content{width:502px;padding:2.5rem}}.prepr-header{justify-content:space-between;align-items:center;gap:.5rem;display:flex}.prepr-header-left{align-items:flex-start;gap:.75rem;display:flex}.prepr-badge{background:var(--prepr-primary-100);height:1.5rem;color:var(--prepr-primary);border-radius:4px;align-items:center;padding:.25rem .75rem;font-size:.875rem;display:flex}.prepr-header-close{cursor:pointer;background:var(--prepr-primary-100);width:2rem;height:2rem;color:var(--prepr-gray-700);border:none;border-radius:6px;justify-content:center;align-items:center;display:flex}.prepr-section{flex-direction:column;gap:.5rem;display:flex}.prepr-section-label{color:var(--prepr-gray-400);font-size:.875rem}.prepr-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem 1.5rem;display:flex}.prepr-row-title{color:var(--prepr-gray-800);margin:0;font-size:1rem;font-weight:600}.prepr-radiogroup{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);background:#fff;align-items:center;gap:.25rem;height:2.5rem;padding:.25rem;display:flex}.prepr-radiogroup[data-disabled=true]{cursor:not-allowed;opacity:.5}.prepr-radiogroup[data-disabled=true] .prepr-radio{pointer-events:none}.prepr-radio{cursor:pointer;white-space:nowrap;text-align:center;height:2rem;color:var(--prepr-gray-900);background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:.5rem 1.125rem;font-size:.875rem;font-weight:500;transition:all .2s ease-in-out;display:flex}.prepr-radio[data-checked=true]{background:var(--prepr-indigo-600);color:#fff;box-shadow:var(--prepr-shadow-sm)}.prepr-radio[data-checked=true][data-off=true]{background:var(--prepr-gray-800);color:#fff}.prepr-radio-variant{width:82px}.prepr-listbox{position:relative}.prepr-segment-button{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);width:240px;height:2.5rem;color:var(--prepr-gray-500);cursor:pointer;background:#fff;flex-shrink:0;align-items:center;gap:.5rem;padding:0 .5rem;font-size:.875rem;font-weight:500;display:flex;overflow:hidden}@media (min-width:768px){.prepr-segment-button{padding:0 1rem}}.prepr-segment-button:disabled{cursor:not-allowed;background:var(--prepr-gray-200);color:var(--prepr-gray-400)}.prepr-segment-button[aria-expanded=true]{border-bottom-color:#fff;border-bottom-right-radius:0;border-bottom-left-radius:0}.prepr-segment-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-segment-caret{color:var(--prepr-gray-800);display:flex}.prepr-options{z-index:calc(var(--prepr-z-index) + 1);border-left:1px solid var(--prepr-gray-300);border-right:1px solid var(--prepr-gray-300);border-bottom:1px solid var(--prepr-gray-300);-ms-overflow-style:none;scrollbar-width:none;background:#fff;border-radius:0 0 6px 6px;width:240px;max-height:300px;margin:0;padding:0;list-style:none;position:absolute;top:100%;left:0;overflow-y:auto;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-options::-webkit-scrollbar{display:none}.prepr-options[hidden]{display:none}.prepr-option-search{background:#fff;padding:.5rem;position:-webkit-sticky;position:sticky;top:0}.prepr-segment-search{border:1px solid var(--prepr-gray-300);border-radius:var(--prepr-radius);width:100%;height:2rem;font:inherit;color:var(--prepr-gray-900);box-sizing:border-box;background:#fff;padding:0 .5rem;font-size:.875rem}.prepr-segment-search::placeholder{color:var(--prepr-gray-400)}.prepr-segment-search:focus{border-color:var(--prepr-gray-400);outline:none}.prepr-option{cursor:pointer;width:100%;color:var(--prepr-gray-900);background:#fff;align-items:center;padding:.5rem 1rem;font-size:.875rem;font-weight:500;display:flex}.prepr-option:hover{background:var(--prepr-gray-100)}.prepr-option[aria-selected=true]{background:var(--prepr-indigo-50);color:var(--prepr-indigo-700)}.prepr-option-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-reset{background:var(--prepr-secondary-400);color:#fff;cursor:pointer;border:none;border-radius:6px;justify-content:center;align-items:center;gap:.5rem;width:100%;height:2.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;display:flex}.prepr-reset:hover:not(:disabled){background:var(--prepr-secondary-500)}.prepr-reset:disabled{background:var(--prepr-gray-400);color:var(--prepr-gray-500);cursor:not-allowed}@media (min-width:768px){.prepr-reset{width:108px}}.prepr-indicators{z-index:var(--prepr-z-index);gap:.75rem;display:flex;position:fixed;bottom:1.5rem;right:1.5rem}.prepr-status-pill{background:var(--prepr-primary);color:#fff;cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-status-pill:hover{background:var(--prepr-primary-800)}.prepr-status-pill[hidden]{display:none}.prepr-status-viewing{color:#fff9;font-size:10px}.prepr-status-segment{text-overflow:ellipsis;white-space:nowrap;max-width:120px;display:inline-block;overflow:hidden}.prepr-status-variant{text-overflow:ellipsis;white-space:nowrap;background:#fff3;border-radius:4px;max-width:80px;padding:0 .5rem;display:inline-block;overflow:hidden}.prepr-status-x{color:#fff;width:.75rem;height:.75rem}.prepr-close-edit-pill{background:var(--prepr-primary-50);color:var(--prepr-gray-800);cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-close-edit-pill:hover{background:var(--prepr-primary-100)}.prepr-close-edit-pill[hidden]{display:none}.prepr-close-edit-x{width:1rem;height:1rem;color:var(--prepr-gray-500);transition:color .15s}.prepr-close-edit-pill:hover .prepr-close-edit-x{color:var(--prepr-gray-700)}.prepr-tip{z-index:calc(var(--prepr-z-index) + 2);overflow-wrap:break-word;background:var(--prepr-gray-900);color:#fff;pointer-events:none;border-radius:6px;width:auto;max-width:min(420px,100vw - 16px);padding:.5rem .75rem;font-size:.75rem;font-weight:500;position:fixed;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-tip-arrow{border-left:6px solid #0000;border-right:6px solid #0000;border-top:6px solid var(--prepr-gray-900);width:0;height:0;position:absolute;top:100%;transform:translate(-50%)}[hidden]{display:none!important}@keyframes prepr-fade-in{0%{opacity:0}to{opacity:1}}";
1425
+ var TOOLBAR_CSS = ":host{--prepr-primary:#4338ca;--prepr-bg:#eef2ff;--prepr-text:#1f2937;--prepr-radius:8px;--prepr-shadow:0px 0px 40px 0px #1f29373d;--prepr-z-index:10000;--prepr-primary-50:#eef2ff;--prepr-primary-100:#e0e7ff;--prepr-primary-800:#3730a3;--prepr-indigo-600:#4f46e5;--prepr-indigo-50:#eef2ff;--prepr-indigo-700:#4338ca;--prepr-secondary-400:#fb923c;--prepr-secondary-500:#f97316;--prepr-gray-100:#f3f4f6;--prepr-gray-200:#e5e7eb;--prepr-gray-300:#d1d5db;--prepr-gray-400:#9ca3af;--prepr-gray-500:#6b7280;--prepr-gray-700:#374151;--prepr-gray-800:#1f2937;--prepr-gray-900:#111827;--prepr-shadow-sm:0px 0px 12px 0px #c3c3c3cc;color:var(--prepr-text);box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5}:host *,:host :before,:host :after,*,:before,:after{box-sizing:border-box}button{font-family:inherit;font-size:inherit;margin:0}.prepr-regular-text{font-size:.875rem;font-weight:500;line-height:1.5}.prepr-backdrop{z-index:calc(var(--prepr-z-index) - 1);opacity:0;pointer-events:none;background:#0000001a;transition:opacity .2s ease-in-out;position:fixed;top:0;bottom:0;left:0;right:0}.prepr-backdrop[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-container{z-index:var(--prepr-z-index);justify-content:flex-end;align-items:center;display:flex;position:fixed;top:calc(50% - 64px);right:0}.prepr-toggle-holder{padding:.5rem}.prepr-toggle{cursor:pointer;background:var(--prepr-primary);color:#fff;border:none;border-radius:9999px;justify-content:center;align-items:center;width:2.25rem;height:2.25rem;display:flex}.prepr-toggle>span{display:flex}.prepr-toggle svg{color:#fff}.prepr-panel{z-index:var(--prepr-z-index);opacity:0;pointer-events:none;justify-content:flex-end;padding:.75rem;transition:opacity .2s ease-in-out;display:flex;position:fixed;top:50%;right:0;transform:translateY(-50%)}.prepr-panel[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-content{box-shadow:var(--prepr-shadow);border-radius:var(--prepr-radius);background:var(--prepr-bg);flex-direction:column;gap:2.5rem;width:100%;padding:1.5rem;display:flex}@media (min-width:640px){.prepr-panel{margin-right:4rem;padding:0}.prepr-content{width:502px;padding:2.5rem}}.prepr-header{justify-content:space-between;align-items:center;gap:.5rem;display:flex}.prepr-header-left{align-items:flex-start;gap:.75rem;display:flex}.prepr-badge{background:var(--prepr-primary-100);height:1.5rem;color:var(--prepr-primary);border-radius:4px;align-items:center;padding:.25rem .75rem;font-size:.875rem;display:flex}.prepr-header-close{cursor:pointer;background:var(--prepr-primary-100);width:2rem;height:2rem;color:var(--prepr-gray-700);border:none;border-radius:6px;justify-content:center;align-items:center;display:flex}.prepr-section{flex-direction:column;gap:.5rem;display:flex}.prepr-section-label{color:var(--prepr-gray-400);font-size:.875rem}.prepr-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem 1.5rem;display:flex}.prepr-row-title{color:var(--prepr-gray-800);margin:0;font-size:1rem;font-weight:600}.prepr-radiogroup{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);background:#fff;align-items:center;gap:.25rem;height:2.5rem;padding:.25rem;display:flex}.prepr-radiogroup[data-disabled=true]{cursor:not-allowed;opacity:.5}.prepr-radiogroup[data-disabled=true] .prepr-radio{pointer-events:none}.prepr-radio{cursor:pointer;white-space:nowrap;text-align:center;height:2rem;color:var(--prepr-gray-900);background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:.5rem 1.125rem;font-size:.875rem;font-weight:500;transition:all .2s ease-in-out;display:flex}.prepr-radio[data-checked=true]{background:var(--prepr-indigo-600);color:#fff;box-shadow:var(--prepr-shadow-sm)}.prepr-radio[data-checked=true][data-off=true]{background:var(--prepr-gray-800);color:#fff}.prepr-radio-variant{width:82px}.prepr-listbox{position:relative}.prepr-segment-button{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);width:240px;height:2.5rem;color:var(--prepr-gray-500);cursor:pointer;background:#fff;flex-shrink:0;align-items:center;gap:.5rem;padding:0 .5rem;font-size:.875rem;font-weight:500;display:flex;overflow:hidden}@media (min-width:768px){.prepr-segment-button{padding:0 1rem}}.prepr-segment-button:disabled{cursor:not-allowed;background:var(--prepr-gray-200);color:var(--prepr-gray-400)}.prepr-segment-button[aria-expanded=true]{border-bottom-color:#fff;border-bottom-right-radius:0;border-bottom-left-radius:0}.prepr-segment-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-segment-caret{color:var(--prepr-gray-800);display:flex}.prepr-options{z-index:calc(var(--prepr-z-index) + 1);border-left:1px solid var(--prepr-gray-300);border-right:1px solid var(--prepr-gray-300);border-bottom:1px solid var(--prepr-gray-300);-ms-overflow-style:none;scrollbar-width:none;background:#fff;border-radius:0 0 6px 6px;width:240px;max-height:300px;margin:0;padding:0;list-style:none;position:absolute;top:100%;left:0;overflow-y:auto;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-options::-webkit-scrollbar{display:none}.prepr-options[hidden]{display:none}.prepr-option-search{background:#fff;padding:.5rem;position:-webkit-sticky;position:sticky;top:0}.prepr-segment-search{border:1px solid var(--prepr-gray-300);border-radius:var(--prepr-radius);width:100%;height:2rem;font:inherit;color:var(--prepr-gray-900);box-sizing:border-box;background:#fff;padding:0 .5rem;font-size:.875rem}.prepr-segment-search::placeholder{color:var(--prepr-gray-400)}.prepr-segment-search:focus{border-color:var(--prepr-gray-400);outline:none}.prepr-option{cursor:pointer;width:100%;color:var(--prepr-gray-900);background:#fff;align-items:center;padding:.5rem 1rem;font-size:.875rem;font-weight:500;display:flex}.prepr-option:hover{background:var(--prepr-gray-100)}.prepr-option[aria-selected=true]{background:var(--prepr-indigo-50);color:var(--prepr-indigo-700)}.prepr-option-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-reset{background:var(--prepr-secondary-400);color:#fff;cursor:pointer;border:none;border-radius:6px;justify-content:center;align-items:center;gap:.5rem;width:100%;height:2.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;display:flex}.prepr-reset:hover:not(:disabled){background:var(--prepr-secondary-500)}.prepr-reset:disabled{background:var(--prepr-gray-400);color:var(--prepr-gray-500);cursor:not-allowed}@media (min-width:768px){.prepr-reset{width:108px}}.prepr-indicators{z-index:var(--prepr-z-index);gap:.75rem;display:flex;position:fixed;bottom:1.5rem;right:1.5rem}.prepr-status-pill{background:var(--prepr-primary);color:#fff;cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-status-pill[data-interactive=false]{cursor:default;opacity:1;color:#fff}.prepr-status-pill[data-interactive=true]:hover{background:var(--prepr-primary-800)}.prepr-status-pill[hidden]{display:none}.prepr-status-viewing{color:#fff9;font-size:10px}.prepr-status-segment{text-overflow:ellipsis;white-space:nowrap;max-width:120px;display:inline-block;overflow:hidden}.prepr-status-variant{text-overflow:ellipsis;white-space:nowrap;background:#fff3;border-radius:4px;max-width:80px;padding:0 .5rem;display:inline-block;overflow:hidden}.prepr-status-x{color:#fff;width:.75rem;height:.75rem}.prepr-close-edit-pill{background:var(--prepr-primary-50);color:var(--prepr-gray-800);cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-close-edit-pill:hover{background:var(--prepr-primary-100)}.prepr-close-edit-pill[hidden]{display:none}.prepr-close-edit-x{width:1rem;height:1rem;color:var(--prepr-gray-500);transition:color .15s}.prepr-close-edit-pill:hover .prepr-close-edit-x{color:var(--prepr-gray-700)}.prepr-tip{z-index:calc(var(--prepr-z-index) + 2);overflow-wrap:break-word;background:var(--prepr-gray-900);color:#fff;pointer-events:none;border-radius:6px;width:auto;max-width:min(420px,100vw - 16px);padding:.5rem .75rem;font-size:.75rem;font-weight:500;position:fixed;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-tip-arrow{border-left:6px solid #0000;border-right:6px solid #0000;border-top:6px solid var(--prepr-gray-900);width:0;height:0;position:absolute;top:100%;transform:translate(-50%)}[hidden]{display:none!important}@keyframes prepr-fade-in{0%{opacity:0}to{opacity:1}}";
1358
1426
 
1359
1427
  // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1360
1428
  var f2 = 0;
@@ -1613,13 +1681,17 @@ function StatusPill({
1613
1681
  } else {
1614
1682
  segmentLabel = defaultSegmentName;
1615
1683
  }
1684
+ const dirty = features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant === "B";
1685
+ const interactive = !state.previewMode || dirty;
1616
1686
  return /* @__PURE__ */ u2(
1617
1687
  "button",
1618
1688
  {
1619
1689
  type: "button",
1620
1690
  class: "prepr-status-pill",
1621
1691
  "data-prepr": "status-pill",
1692
+ "data-interactive": String(interactive),
1622
1693
  hidden: state.isIframe,
1694
+ disabled: !interactive,
1623
1695
  onClick: () => handlers.onStatusPill(),
1624
1696
  children: [
1625
1697
  /* @__PURE__ */ u2("span", { class: "prepr-status-viewing", "data-prepr": "status-viewing", children: t3("common.viewingAs") }),
@@ -1638,7 +1710,7 @@ function StatusPill({
1638
1710
  {
1639
1711
  class: "prepr-status-x",
1640
1712
  "data-prepr": "status-x",
1641
- hidden: !state.previewMode || !(features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant === "B"),
1713
+ hidden: !state.previewMode || !dirty,
1642
1714
  children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
1643
1715
  }
1644
1716
  )
@@ -2142,7 +2214,9 @@ function createPreprPreview(opts = {}) {
2142
2214
  }
2143
2215
  }
2144
2216
  });
2145
- const autoClean = createStegaAutoClean();
2217
+ const autoClean = createStegaAutoClean({
2218
+ enabled: options?.autoClean
2219
+ });
2146
2220
  autoClean.start();
2147
2221
  const handleChange = createChangeHandler({
2148
2222
  store,
@@ -2188,7 +2262,7 @@ function createPreprPreview(opts = {}) {
2188
2262
  }
2189
2263
 
2190
2264
  // src/core/pixel.ts
2191
- var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr-v2.min.js";
2265
+ var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
2192
2266
  var CACHE_BUST_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2193
2267
  function loadTrackingPixel(trackingId, config) {
2194
2268
  if (typeof window === "undefined" || typeof document === "undefined") {
@@ -62,6 +62,20 @@ interface PreprPreviewOptions extends PreprToolbarOptions {
62
62
  * Intended for self-hosted editors; when set, the wildcard no longer applies.
63
63
  */
64
64
  allowedEditorOrigins?: string[];
65
+ /**
66
+ * Strip the invisible stega characters out of visible text at runtime.
67
+ * Default `true`.
68
+ *
69
+ * Preview content carries an encoded payload inside the text itself. Left in
70
+ * place it is invisible but real: it inflates `String.length`, breaks text
71
+ * measurement and truncation, and is announced by screen readers.
72
+ *
73
+ * Set `false` only when the site already strips the characters itself — for
74
+ * example by passing every field through `stegaClean` as it renders.
75
+ * Click-to-edit is unaffected either way: elements are still tagged from the
76
+ * payload, so the overlay keeps working.
77
+ */
78
+ autoClean?: boolean;
65
79
  }
66
80
  interface PreprToolbarProps {
67
81
  /**
@@ -62,6 +62,20 @@ interface PreprPreviewOptions extends PreprToolbarOptions {
62
62
  * Intended for self-hosted editors; when set, the wildcard no longer applies.
63
63
  */
64
64
  allowedEditorOrigins?: string[];
65
+ /**
66
+ * Strip the invisible stega characters out of visible text at runtime.
67
+ * Default `true`.
68
+ *
69
+ * Preview content carries an encoded payload inside the text itself. Left in
70
+ * place it is invisible but real: it inflates `String.length`, breaks text
71
+ * measurement and truncation, and is announced by screen readers.
72
+ *
73
+ * Set `false` only when the site already strips the characters itself — for
74
+ * example by passing every field through `stegaClean` as it renders.
75
+ * Click-to-edit is unaffected either way: elements are still tagged from the
76
+ * payload, so the overlay keeps working.
77
+ */
78
+ autoClean?: boolean;
65
79
  }
66
80
  interface PreprToolbarProps {
67
81
  /**
@@ -371,6 +371,20 @@ function walkTextNodes(root, visit) {
371
371
  visit(node);
372
372
  }
373
373
  }
374
+ function resolveEditTarget(node) {
375
+ const parent = node.parentElement;
376
+ if (!parent) return null;
377
+ const editTarget = parent.closest("[data-prepr-edit-target]");
378
+ if (editTarget) return editTarget;
379
+ return isRenderedElement(parent) ? parent : null;
380
+ }
381
+ function isRenderedElement(element) {
382
+ if (element.hidden) return false;
383
+ if (element.getClientRects().length === 0) return false;
384
+ const style = element.ownerDocument.defaultView?.getComputedStyle(element);
385
+ if (!style) return true;
386
+ return style.visibility !== "hidden" && style.display !== "none";
387
+ }
374
388
  function tagEncodedElement(element, decoded) {
375
389
  element.setAttribute("data-prepr-encoded", "");
376
390
  element.setAttribute("data-prepr-href", decoded.href);
@@ -379,32 +393,45 @@ function tagEncodedElement(element, decoded) {
379
393
 
380
394
  // src/core/stega/auto-clean.ts
381
395
  var debug2 = createScopedLogger("stega:auto-clean");
382
- function createStegaAutoClean() {
396
+ function createStegaAutoClean(options) {
397
+ const stripText = options?.enabled ?? true;
383
398
  let observer = null;
384
399
  let processing = false;
385
400
  let cleaned = /* @__PURE__ */ new WeakMap();
401
+ let pendingHidden = /* @__PURE__ */ new Set();
402
+ let pendingDirty = /* @__PURE__ */ new Set();
386
403
  let debounceTimeout = null;
387
404
  function cleanTextNode(textNode) {
388
405
  if (isIgnoredTextNode(textNode)) return false;
389
406
  const textContent = textNode.textContent;
390
407
  const info = cleaned.get(textNode);
391
- if (info && textContent === info.cleaned) return false;
408
+ const settled = stripText ? info?.cleaned : info?.original;
409
+ if (info && textContent === settled) {
410
+ const shown = resolveEditTarget(textNode);
411
+ if (!shown) return false;
412
+ pendingHidden.delete(textNode);
413
+ if (shown.hasAttribute("data-prepr-encoded")) return false;
414
+ tagEncodedElement(shown, info.decoded);
415
+ return true;
416
+ }
392
417
  try {
393
418
  const { cleaned: stripped, encoded } = vercelStegaSplit(textContent);
394
419
  if (!encoded || stripped === textContent) return false;
395
420
  const decoded = decodeStega(textContent);
396
421
  if (!decoded?.href) return false;
397
- cleaned.set(textNode, { original: textContent, cleaned: stripped });
398
- textNode.textContent = stripped;
399
- let target = textNode.parentElement;
400
- const editTargetParent = textNode.parentElement?.closest(
401
- "[data-prepr-edit-target]"
402
- );
403
- if (editTargetParent) target = editTargetParent;
422
+ cleaned.set(textNode, {
423
+ original: textContent,
424
+ cleaned: stripped,
425
+ decoded
426
+ });
427
+ if (stripText) textNode.textContent = stripped;
428
+ const target = resolveEditTarget(textNode);
404
429
  if (target) {
430
+ pendingHidden.delete(textNode);
405
431
  tagEncodedElement(target, decoded);
406
432
  return true;
407
433
  }
434
+ pendingHidden.add(textNode);
408
435
  } catch (error) {
409
436
  debug2.log("error cleaning text node", error);
410
437
  }
@@ -413,8 +440,10 @@ function createStegaAutoClean() {
413
440
  function scanAndClean() {
414
441
  processing = true;
415
442
  walkTextNodes(document.body, cleanTextNode);
416
- const title = vercelStegaSplit(document.title);
417
- if (title.encoded) document.title = title.cleaned;
443
+ if (stripText) {
444
+ const title = vercelStegaSplit(document.title);
445
+ if (title.encoded) document.title = title.cleaned;
446
+ }
418
447
  processing = false;
419
448
  }
420
449
  function collectAffected(mutations) {
@@ -439,15 +468,37 @@ function createStegaAutoClean() {
439
468
  });
440
469
  return affected;
441
470
  }
471
+ function retryPendingHidden() {
472
+ if (pendingHidden.size === 0) return;
473
+ processing = true;
474
+ [...pendingHidden].forEach((textNode) => {
475
+ if (!textNode.isConnected) {
476
+ pendingHidden.delete(textNode);
477
+ return;
478
+ }
479
+ cleanTextNode(textNode);
480
+ });
481
+ processing = false;
482
+ }
442
483
  function handleMutations(mutations) {
443
484
  if (processing) return;
444
485
  const affected = collectAffected(mutations);
445
- if (affected.size === 0) return;
486
+ if (affected.size === 0) {
487
+ retryPendingHidden();
488
+ return;
489
+ }
490
+ affected.forEach((textNode) => pendingDirty.add(textNode));
446
491
  if (debounceTimeout) clearTimeout(debounceTimeout);
447
492
  debounceTimeout = setTimeout(() => {
493
+ debounceTimeout = null;
448
494
  processing = true;
449
- affected.forEach((textNode) => cleanTextNode(textNode));
495
+ const batch = [...pendingDirty];
496
+ pendingDirty.clear();
497
+ batch.forEach((textNode) => {
498
+ if (textNode.isConnected) cleanTextNode(textNode);
499
+ });
450
500
  processing = false;
501
+ retryPendingHidden();
451
502
  }, 50);
452
503
  }
453
504
  function setupObserver() {
@@ -455,7 +506,11 @@ function createStegaAutoClean() {
455
506
  observer.observe(document.body, {
456
507
  childList: true,
457
508
  subtree: true,
458
- characterData: true
509
+ characterData: true,
510
+ // A dropdown opening only toggles a class or inline style; without these
511
+ // the nodes it reveals are never revisited and stay untagged.
512
+ attributes: true,
513
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
459
514
  });
460
515
  }
461
516
  function start() {
@@ -474,6 +529,8 @@ function createStegaAutoClean() {
474
529
  observer = null;
475
530
  }
476
531
  cleaned = /* @__PURE__ */ new WeakMap();
532
+ pendingHidden = /* @__PURE__ */ new Set();
533
+ pendingDirty = /* @__PURE__ */ new Set();
477
534
  debug2.log("stega auto-clean stopped");
478
535
  }
479
536
  return { start, stop };
@@ -496,7 +553,7 @@ var StegaElements = class {
496
553
  tagFromTextNode(node) {
497
554
  const decoded = this.decode(node.textContent);
498
555
  if (!decoded?.href) return false;
499
- const target = node.parentElement;
556
+ const target = resolveEditTarget(node);
500
557
  if (!target || target.hasAttribute("data-prepr-encoded")) return false;
501
558
  tagEncodedElement(target, decoded);
502
559
  return true;
@@ -542,8 +599,13 @@ var StegaElements = class {
542
599
  if (mutation.type === "characterData") {
543
600
  addedNodes.add(mutation.target);
544
601
  }
602
+ if (mutation.type === "attributes") {
603
+ addedNodes.add(mutation.target);
604
+ }
605
+ });
606
+ addedNodes.forEach((node) => {
607
+ if (node.isConnected) this.scanNode(node);
545
608
  });
546
- addedNodes.forEach((node) => this.scanNode(node));
547
609
  pending = [];
548
610
  this.elements = document.querySelectorAll("[data-prepr-encoded]");
549
611
  onUpdate?.();
@@ -556,7 +618,11 @@ var StegaElements = class {
556
618
  this.observer.observe(document.body, {
557
619
  childList: true,
558
620
  subtree: true,
559
- characterData: true
621
+ characterData: true,
622
+ // Reveal-on-class/style (dropdowns, accordions) changes no text and adds
623
+ // no nodes, but does change what is hoverable and needs a rescan.
624
+ attributes: true,
625
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
560
626
  });
561
627
  }
562
628
  /** Drops the active class but keeps the data attributes, unlike cleanup(). */
@@ -645,11 +711,13 @@ var StegaOverlay = class {
645
711
  const maxTop = window.scrollY + window.innerHeight - tooltip.clientHeight - 4;
646
712
  const minLeft = window.scrollX + 4;
647
713
  const maxLeft = window.scrollX + window.innerWidth - tooltip.clientWidth - 4;
648
- if (top < minTop) {
714
+ const below = top < minTop;
715
+ if (below) {
649
716
  top = rect.bottom + window.scrollY + 2;
650
717
  }
651
718
  top = Math.max(minTop, Math.min(top, maxTop));
652
719
  left = Math.max(minLeft, Math.min(left, maxLeft));
720
+ tooltip.dataset.preprPlacement = below ? "below" : "above";
653
721
  tooltip.style.top = `${top}px`;
654
722
  tooltip.style.left = `${left}px`;
655
723
  });
@@ -781,7 +849,7 @@ var StegaProximity = class {
781
849
  };
782
850
 
783
851
  // src/core/stega/stega.generated.ts
784
- var STEGA_STYLES = '[data-prepr-encoded]{position:relative}.prepr-overlay{pointer-events:none;z-index:10000;border:2px solid #4f46e5;border-radius:4px 0 4px 4px;transition:all .2s ease-in-out;position:absolute}.prepr-tooltip{color:#fff;white-space:nowrap;z-index:10001;text-align:center;pointer-events:auto;cursor:pointer;background-color:#4f46e5;border-radius:4px 4px 0 0;min-width:80px;padding:4px 8px;font-size:12px;line-height:1;transition:opacity .2s ease-in-out;position:absolute}.prepr-tooltip:hover{background-color:#4338ca}.prepr-proximity-highlight{z-index:1;position:relative}.prepr-proximity-highlight,.prepr-proximity-highlight *{overflow:visible!important}.prepr-proximity-highlight:before{content:"";pointer-events:none;background:radial-gradient(circle var(--gradient-size) at var(--cursor-x) var(--cursor-y), #4f46e526 0%, #2563eb00 70%);z-index:9999;border:2px solid #4f46e526;border-radius:4px;transition:all .2s;position:absolute;top:-2px;bottom:-2px;left:-4px;right:-4px;overflow:visible}';
852
+ var STEGA_STYLES = '[data-prepr-encoded]{position:relative}.prepr-overlay{pointer-events:none;z-index:10000;border:2px solid #4f46e5;border-radius:4px 0 4px 4px;transition:all .2s ease-in-out;position:absolute}.prepr-tooltip{color:#fff;white-space:nowrap;z-index:10001;text-align:center;pointer-events:auto;cursor:pointer;background-color:#4f46e5;border-radius:4px 4px 0 0;min-width:80px;padding:4px 8px;font-size:12px;line-height:1;transition:opacity .2s ease-in-out;position:absolute}.prepr-tooltip[data-prepr-placement=below]{border-radius:0 0 4px 4px}.prepr-tooltip:hover{background-color:#4338ca}.prepr-proximity-highlight{z-index:1;position:relative}.prepr-proximity-highlight,.prepr-proximity-highlight *{overflow:visible!important}.prepr-proximity-highlight:before{content:"";pointer-events:none;background:radial-gradient(circle var(--gradient-size) at var(--cursor-x) var(--cursor-y), #4f46e526 0%, #2563eb00 70%);z-index:9999;border:2px solid #4f46e526;border-radius:4px;transition:all .2s;position:absolute;top:-2px;bottom:-2px;left:-4px;right:-4px;overflow:visible}';
785
853
 
786
854
  // src/core/stega/styles.ts
787
855
  var STEGA_STYLE_MARKER = "data-prepr-stega";
@@ -1330,7 +1398,7 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
1330
1398
  </svg>`;
1331
1399
 
1332
1400
  // src/core/ui/toolbar.generated.ts
1333
- var TOOLBAR_CSS = ":host{--prepr-primary:#4338ca;--prepr-bg:#eef2ff;--prepr-text:#1f2937;--prepr-radius:8px;--prepr-shadow:0px 0px 40px 0px #1f29373d;--prepr-z-index:10000;--prepr-primary-50:#eef2ff;--prepr-primary-100:#e0e7ff;--prepr-primary-800:#3730a3;--prepr-indigo-600:#4f46e5;--prepr-indigo-50:#eef2ff;--prepr-indigo-700:#4338ca;--prepr-secondary-400:#fb923c;--prepr-secondary-500:#f97316;--prepr-gray-100:#f3f4f6;--prepr-gray-200:#e5e7eb;--prepr-gray-300:#d1d5db;--prepr-gray-400:#9ca3af;--prepr-gray-500:#6b7280;--prepr-gray-700:#374151;--prepr-gray-800:#1f2937;--prepr-gray-900:#111827;--prepr-shadow-sm:0px 0px 12px 0px #c3c3c3cc;color:var(--prepr-text);box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5}:host *,:host :before,:host :after,*,:before,:after{box-sizing:border-box}button{font-family:inherit;font-size:inherit;margin:0}.prepr-regular-text{font-size:.875rem;font-weight:500;line-height:1.5}.prepr-backdrop{z-index:calc(var(--prepr-z-index) - 1);opacity:0;pointer-events:none;background:#0000001a;transition:opacity .2s ease-in-out;position:fixed;top:0;bottom:0;left:0;right:0}.prepr-backdrop[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-container{z-index:var(--prepr-z-index);justify-content:flex-end;align-items:center;display:flex;position:fixed;top:calc(50% - 64px);right:0}.prepr-toggle-holder{padding:.5rem}.prepr-toggle{cursor:pointer;background:var(--prepr-primary);color:#fff;border:none;border-radius:9999px;justify-content:center;align-items:center;width:2.25rem;height:2.25rem;display:flex}.prepr-toggle>span{display:flex}.prepr-toggle svg{color:#fff}.prepr-panel{z-index:var(--prepr-z-index);opacity:0;pointer-events:none;justify-content:flex-end;padding:.75rem;transition:opacity .2s ease-in-out;display:flex;position:fixed;top:50%;right:0;transform:translateY(-50%)}.prepr-panel[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-content{box-shadow:var(--prepr-shadow);border-radius:var(--prepr-radius);background:var(--prepr-bg);flex-direction:column;gap:2.5rem;width:100%;padding:1.5rem;display:flex}@media (min-width:640px){.prepr-panel{margin-right:4rem;padding:0}.prepr-content{width:502px;padding:2.5rem}}.prepr-header{justify-content:space-between;align-items:center;gap:.5rem;display:flex}.prepr-header-left{align-items:flex-start;gap:.75rem;display:flex}.prepr-badge{background:var(--prepr-primary-100);height:1.5rem;color:var(--prepr-primary);border-radius:4px;align-items:center;padding:.25rem .75rem;font-size:.875rem;display:flex}.prepr-header-close{cursor:pointer;background:var(--prepr-primary-100);width:2rem;height:2rem;color:var(--prepr-gray-700);border:none;border-radius:6px;justify-content:center;align-items:center;display:flex}.prepr-section{flex-direction:column;gap:.5rem;display:flex}.prepr-section-label{color:var(--prepr-gray-400);font-size:.875rem}.prepr-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem 1.5rem;display:flex}.prepr-row-title{color:var(--prepr-gray-800);margin:0;font-size:1rem;font-weight:600}.prepr-radiogroup{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);background:#fff;align-items:center;gap:.25rem;height:2.5rem;padding:.25rem;display:flex}.prepr-radiogroup[data-disabled=true]{cursor:not-allowed;opacity:.5}.prepr-radiogroup[data-disabled=true] .prepr-radio{pointer-events:none}.prepr-radio{cursor:pointer;white-space:nowrap;text-align:center;height:2rem;color:var(--prepr-gray-900);background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:.5rem 1.125rem;font-size:.875rem;font-weight:500;transition:all .2s ease-in-out;display:flex}.prepr-radio[data-checked=true]{background:var(--prepr-indigo-600);color:#fff;box-shadow:var(--prepr-shadow-sm)}.prepr-radio[data-checked=true][data-off=true]{background:var(--prepr-gray-800);color:#fff}.prepr-radio-variant{width:82px}.prepr-listbox{position:relative}.prepr-segment-button{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);width:240px;height:2.5rem;color:var(--prepr-gray-500);cursor:pointer;background:#fff;flex-shrink:0;align-items:center;gap:.5rem;padding:0 .5rem;font-size:.875rem;font-weight:500;display:flex;overflow:hidden}@media (min-width:768px){.prepr-segment-button{padding:0 1rem}}.prepr-segment-button:disabled{cursor:not-allowed;background:var(--prepr-gray-200);color:var(--prepr-gray-400)}.prepr-segment-button[aria-expanded=true]{border-bottom-color:#fff;border-bottom-right-radius:0;border-bottom-left-radius:0}.prepr-segment-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-segment-caret{color:var(--prepr-gray-800);display:flex}.prepr-options{z-index:calc(var(--prepr-z-index) + 1);border-left:1px solid var(--prepr-gray-300);border-right:1px solid var(--prepr-gray-300);border-bottom:1px solid var(--prepr-gray-300);-ms-overflow-style:none;scrollbar-width:none;background:#fff;border-radius:0 0 6px 6px;width:240px;max-height:300px;margin:0;padding:0;list-style:none;position:absolute;top:100%;left:0;overflow-y:auto;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-options::-webkit-scrollbar{display:none}.prepr-options[hidden]{display:none}.prepr-option-search{background:#fff;padding:.5rem;position:-webkit-sticky;position:sticky;top:0}.prepr-segment-search{border:1px solid var(--prepr-gray-300);border-radius:var(--prepr-radius);width:100%;height:2rem;font:inherit;color:var(--prepr-gray-900);box-sizing:border-box;background:#fff;padding:0 .5rem;font-size:.875rem}.prepr-segment-search::placeholder{color:var(--prepr-gray-400)}.prepr-segment-search:focus{border-color:var(--prepr-gray-400);outline:none}.prepr-option{cursor:pointer;width:100%;color:var(--prepr-gray-900);background:#fff;align-items:center;padding:.5rem 1rem;font-size:.875rem;font-weight:500;display:flex}.prepr-option:hover{background:var(--prepr-gray-100)}.prepr-option[aria-selected=true]{background:var(--prepr-indigo-50);color:var(--prepr-indigo-700)}.prepr-option-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-reset{background:var(--prepr-secondary-400);color:#fff;cursor:pointer;border:none;border-radius:6px;justify-content:center;align-items:center;gap:.5rem;width:100%;height:2.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;display:flex}.prepr-reset:hover:not(:disabled){background:var(--prepr-secondary-500)}.prepr-reset:disabled{background:var(--prepr-gray-400);color:var(--prepr-gray-500);cursor:not-allowed}@media (min-width:768px){.prepr-reset{width:108px}}.prepr-indicators{z-index:var(--prepr-z-index);gap:.75rem;display:flex;position:fixed;bottom:1.5rem;right:1.5rem}.prepr-status-pill{background:var(--prepr-primary);color:#fff;cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-status-pill:hover{background:var(--prepr-primary-800)}.prepr-status-pill[hidden]{display:none}.prepr-status-viewing{color:#fff9;font-size:10px}.prepr-status-segment{text-overflow:ellipsis;white-space:nowrap;max-width:120px;display:inline-block;overflow:hidden}.prepr-status-variant{text-overflow:ellipsis;white-space:nowrap;background:#fff3;border-radius:4px;max-width:80px;padding:0 .5rem;display:inline-block;overflow:hidden}.prepr-status-x{color:#fff;width:.75rem;height:.75rem}.prepr-close-edit-pill{background:var(--prepr-primary-50);color:var(--prepr-gray-800);cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-close-edit-pill:hover{background:var(--prepr-primary-100)}.prepr-close-edit-pill[hidden]{display:none}.prepr-close-edit-x{width:1rem;height:1rem;color:var(--prepr-gray-500);transition:color .15s}.prepr-close-edit-pill:hover .prepr-close-edit-x{color:var(--prepr-gray-700)}.prepr-tip{z-index:calc(var(--prepr-z-index) + 2);overflow-wrap:break-word;background:var(--prepr-gray-900);color:#fff;pointer-events:none;border-radius:6px;width:auto;max-width:min(420px,100vw - 16px);padding:.5rem .75rem;font-size:.75rem;font-weight:500;position:fixed;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-tip-arrow{border-left:6px solid #0000;border-right:6px solid #0000;border-top:6px solid var(--prepr-gray-900);width:0;height:0;position:absolute;top:100%;transform:translate(-50%)}[hidden]{display:none!important}@keyframes prepr-fade-in{0%{opacity:0}to{opacity:1}}";
1401
+ var TOOLBAR_CSS = ":host{--prepr-primary:#4338ca;--prepr-bg:#eef2ff;--prepr-text:#1f2937;--prepr-radius:8px;--prepr-shadow:0px 0px 40px 0px #1f29373d;--prepr-z-index:10000;--prepr-primary-50:#eef2ff;--prepr-primary-100:#e0e7ff;--prepr-primary-800:#3730a3;--prepr-indigo-600:#4f46e5;--prepr-indigo-50:#eef2ff;--prepr-indigo-700:#4338ca;--prepr-secondary-400:#fb923c;--prepr-secondary-500:#f97316;--prepr-gray-100:#f3f4f6;--prepr-gray-200:#e5e7eb;--prepr-gray-300:#d1d5db;--prepr-gray-400:#9ca3af;--prepr-gray-500:#6b7280;--prepr-gray-700:#374151;--prepr-gray-800:#1f2937;--prepr-gray-900:#111827;--prepr-shadow-sm:0px 0px 12px 0px #c3c3c3cc;color:var(--prepr-text);box-sizing:border-box;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.5}:host *,:host :before,:host :after,*,:before,:after{box-sizing:border-box}button{font-family:inherit;font-size:inherit;margin:0}.prepr-regular-text{font-size:.875rem;font-weight:500;line-height:1.5}.prepr-backdrop{z-index:calc(var(--prepr-z-index) - 1);opacity:0;pointer-events:none;background:#0000001a;transition:opacity .2s ease-in-out;position:fixed;top:0;bottom:0;left:0;right:0}.prepr-backdrop[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-container{z-index:var(--prepr-z-index);justify-content:flex-end;align-items:center;display:flex;position:fixed;top:calc(50% - 64px);right:0}.prepr-toggle-holder{padding:.5rem}.prepr-toggle{cursor:pointer;background:var(--prepr-primary);color:#fff;border:none;border-radius:9999px;justify-content:center;align-items:center;width:2.25rem;height:2.25rem;display:flex}.prepr-toggle>span{display:flex}.prepr-toggle svg{color:#fff}.prepr-panel{z-index:var(--prepr-z-index);opacity:0;pointer-events:none;justify-content:flex-end;padding:.75rem;transition:opacity .2s ease-in-out;display:flex;position:fixed;top:50%;right:0;transform:translateY(-50%)}.prepr-panel[data-open=true]{opacity:1;pointer-events:auto;animation:.2s ease-in-out prepr-fade-in}.prepr-content{box-shadow:var(--prepr-shadow);border-radius:var(--prepr-radius);background:var(--prepr-bg);flex-direction:column;gap:2.5rem;width:100%;padding:1.5rem;display:flex}@media (min-width:640px){.prepr-panel{margin-right:4rem;padding:0}.prepr-content{width:502px;padding:2.5rem}}.prepr-header{justify-content:space-between;align-items:center;gap:.5rem;display:flex}.prepr-header-left{align-items:flex-start;gap:.75rem;display:flex}.prepr-badge{background:var(--prepr-primary-100);height:1.5rem;color:var(--prepr-primary);border-radius:4px;align-items:center;padding:.25rem .75rem;font-size:.875rem;display:flex}.prepr-header-close{cursor:pointer;background:var(--prepr-primary-100);width:2rem;height:2rem;color:var(--prepr-gray-700);border:none;border-radius:6px;justify-content:center;align-items:center;display:flex}.prepr-section{flex-direction:column;gap:.5rem;display:flex}.prepr-section-label{color:var(--prepr-gray-400);font-size:.875rem}.prepr-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:.5rem 1.5rem;display:flex}.prepr-row-title{color:var(--prepr-gray-800);margin:0;font-size:1rem;font-weight:600}.prepr-radiogroup{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);background:#fff;align-items:center;gap:.25rem;height:2.5rem;padding:.25rem;display:flex}.prepr-radiogroup[data-disabled=true]{cursor:not-allowed;opacity:.5}.prepr-radiogroup[data-disabled=true] .prepr-radio{pointer-events:none}.prepr-radio{cursor:pointer;white-space:nowrap;text-align:center;height:2rem;color:var(--prepr-gray-900);background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;padding:.5rem 1.125rem;font-size:.875rem;font-weight:500;transition:all .2s ease-in-out;display:flex}.prepr-radio[data-checked=true]{background:var(--prepr-indigo-600);color:#fff;box-shadow:var(--prepr-shadow-sm)}.prepr-radio[data-checked=true][data-off=true]{background:var(--prepr-gray-800);color:#fff}.prepr-radio-variant{width:82px}.prepr-listbox{position:relative}.prepr-segment-button{border-radius:var(--prepr-radius);border:1px solid var(--prepr-gray-300);width:240px;height:2.5rem;color:var(--prepr-gray-500);cursor:pointer;background:#fff;flex-shrink:0;align-items:center;gap:.5rem;padding:0 .5rem;font-size:.875rem;font-weight:500;display:flex;overflow:hidden}@media (min-width:768px){.prepr-segment-button{padding:0 1rem}}.prepr-segment-button:disabled{cursor:not-allowed;background:var(--prepr-gray-200);color:var(--prepr-gray-400)}.prepr-segment-button[aria-expanded=true]{border-bottom-color:#fff;border-bottom-right-radius:0;border-bottom-left-radius:0}.prepr-segment-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-segment-caret{color:var(--prepr-gray-800);display:flex}.prepr-options{z-index:calc(var(--prepr-z-index) + 1);border-left:1px solid var(--prepr-gray-300);border-right:1px solid var(--prepr-gray-300);border-bottom:1px solid var(--prepr-gray-300);-ms-overflow-style:none;scrollbar-width:none;background:#fff;border-radius:0 0 6px 6px;width:240px;max-height:300px;margin:0;padding:0;list-style:none;position:absolute;top:100%;left:0;overflow-y:auto;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-options::-webkit-scrollbar{display:none}.prepr-options[hidden]{display:none}.prepr-option-search{background:#fff;padding:.5rem;position:-webkit-sticky;position:sticky;top:0}.prepr-segment-search{border:1px solid var(--prepr-gray-300);border-radius:var(--prepr-radius);width:100%;height:2rem;font:inherit;color:var(--prepr-gray-900);box-sizing:border-box;background:#fff;padding:0 .5rem;font-size:.875rem}.prepr-segment-search::placeholder{color:var(--prepr-gray-400)}.prepr-segment-search:focus{border-color:var(--prepr-gray-400);outline:none}.prepr-option{cursor:pointer;width:100%;color:var(--prepr-gray-900);background:#fff;align-items:center;padding:.5rem 1rem;font-size:.875rem;font-weight:500;display:flex}.prepr-option:hover{background:var(--prepr-gray-100)}.prepr-option[aria-selected=true]{background:var(--prepr-indigo-50);color:var(--prepr-indigo-700)}.prepr-option-label{white-space:nowrap;text-overflow:ellipsis;text-align:left;width:100%;margin-right:auto;overflow:hidden}.prepr-reset{background:var(--prepr-secondary-400);color:#fff;cursor:pointer;border:none;border-radius:6px;justify-content:center;align-items:center;gap:.5rem;width:100%;height:2.5rem;padding:.5rem .75rem;font-size:.875rem;font-weight:500;display:flex}.prepr-reset:hover:not(:disabled){background:var(--prepr-secondary-500)}.prepr-reset:disabled{background:var(--prepr-gray-400);color:var(--prepr-gray-500);cursor:not-allowed}@media (min-width:768px){.prepr-reset{width:108px}}.prepr-indicators{z-index:var(--prepr-z-index);gap:.75rem;display:flex;position:fixed;bottom:1.5rem;right:1.5rem}.prepr-status-pill{background:var(--prepr-primary);color:#fff;cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-status-pill[data-interactive=false]{cursor:default;opacity:1;color:#fff}.prepr-status-pill[data-interactive=true]:hover{background:var(--prepr-primary-800)}.prepr-status-pill[hidden]{display:none}.prepr-status-viewing{color:#fff9;font-size:10px}.prepr-status-segment{text-overflow:ellipsis;white-space:nowrap;max-width:120px;display:inline-block;overflow:hidden}.prepr-status-variant{text-overflow:ellipsis;white-space:nowrap;background:#fff3;border-radius:4px;max-width:80px;padding:0 .5rem;display:inline-block;overflow:hidden}.prepr-status-x{color:#fff;width:.75rem;height:.75rem}.prepr-close-edit-pill{background:var(--prepr-primary-50);color:var(--prepr-gray-800);cursor:pointer;border:none;border-radius:9999px;align-items:center;gap:.5rem;padding:.5rem 1rem;font-size:.75rem;font-weight:500;transition:background-color .15s;display:flex;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.prepr-close-edit-pill:hover{background:var(--prepr-primary-100)}.prepr-close-edit-pill[hidden]{display:none}.prepr-close-edit-x{width:1rem;height:1rem;color:var(--prepr-gray-500);transition:color .15s}.prepr-close-edit-pill:hover .prepr-close-edit-x{color:var(--prepr-gray-700)}.prepr-tip{z-index:calc(var(--prepr-z-index) + 2);overflow-wrap:break-word;background:var(--prepr-gray-900);color:#fff;pointer-events:none;border-radius:6px;width:auto;max-width:min(420px,100vw - 16px);padding:.5rem .75rem;font-size:.75rem;font-weight:500;position:fixed;box-shadow:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a}.prepr-tip-arrow{border-left:6px solid #0000;border-right:6px solid #0000;border-top:6px solid var(--prepr-gray-900);width:0;height:0;position:absolute;top:100%;transform:translate(-50%)}[hidden]{display:none!important}@keyframes prepr-fade-in{0%{opacity:0}to{opacity:1}}";
1334
1402
 
1335
1403
  // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1336
1404
  var f2 = 0;
@@ -1589,13 +1657,17 @@ function StatusPill({
1589
1657
  } else {
1590
1658
  segmentLabel = defaultSegmentName;
1591
1659
  }
1660
+ const dirty = features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant === "B";
1661
+ const interactive = !state.previewMode || dirty;
1592
1662
  return /* @__PURE__ */ u2(
1593
1663
  "button",
1594
1664
  {
1595
1665
  type: "button",
1596
1666
  class: "prepr-status-pill",
1597
1667
  "data-prepr": "status-pill",
1668
+ "data-interactive": String(interactive),
1598
1669
  hidden: state.isIframe,
1670
+ disabled: !interactive,
1599
1671
  onClick: () => handlers.onStatusPill(),
1600
1672
  children: [
1601
1673
  /* @__PURE__ */ u2("span", { class: "prepr-status-viewing", "data-prepr": "status-viewing", children: t3("common.viewingAs") }),
@@ -1614,7 +1686,7 @@ function StatusPill({
1614
1686
  {
1615
1687
  class: "prepr-status-x",
1616
1688
  "data-prepr": "status-x",
1617
- hidden: !state.previewMode || !(features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant === "B"),
1689
+ hidden: !state.previewMode || !dirty,
1618
1690
  children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
1619
1691
  }
1620
1692
  )
@@ -2118,7 +2190,9 @@ function createPreprPreview(opts = {}) {
2118
2190
  }
2119
2191
  }
2120
2192
  });
2121
- const autoClean = createStegaAutoClean();
2193
+ const autoClean = createStegaAutoClean({
2194
+ enabled: options?.autoClean
2195
+ });
2122
2196
  autoClean.start();
2123
2197
  const handleChange = createChangeHandler({
2124
2198
  store,
@@ -2164,7 +2238,7 @@ function createPreprPreview(opts = {}) {
2164
2238
  }
2165
2239
 
2166
2240
  // src/core/pixel.ts
2167
- var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr-v2.min.js";
2241
+ var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
2168
2242
  var CACHE_BUST_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2169
2243
  function loadTrackingPixel(trackingId, config) {
2170
2244
  if (typeof window === "undefined" || typeof document === "undefined") {
@@ -35,7 +35,7 @@ __export(sveltekit_exports, {
35
35
  module.exports = __toCommonJS(sveltekit_exports);
36
36
 
37
37
  // src/version.ts
38
- var VERSION = "0.2.0";
38
+ var VERSION = "0.3.4";
39
39
 
40
40
  // src/core/constants.ts
41
41
  var COOKIE_PREVIEW_MODE = "Prepr-Preview-Mode";