@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.
package/dist/index.cjs CHANGED
@@ -44,7 +44,7 @@ __export(src_exports, {
44
44
  module.exports = __toCommonJS(src_exports);
45
45
 
46
46
  // src/version.ts
47
- var VERSION = "0.2.0";
47
+ var VERSION = "0.3.4";
48
48
 
49
49
  // src/core/features.ts
50
50
  function isEnabled(config) {
@@ -420,6 +420,20 @@ function walkTextNodes(root, visit) {
420
420
  visit(node);
421
421
  }
422
422
  }
423
+ function resolveEditTarget(node) {
424
+ const parent = node.parentElement;
425
+ if (!parent) return null;
426
+ const editTarget = parent.closest("[data-prepr-edit-target]");
427
+ if (editTarget) return editTarget;
428
+ return isRenderedElement(parent) ? parent : null;
429
+ }
430
+ function isRenderedElement(element) {
431
+ if (element.hidden) return false;
432
+ if (element.getClientRects().length === 0) return false;
433
+ const style = element.ownerDocument.defaultView?.getComputedStyle(element);
434
+ if (!style) return true;
435
+ return style.visibility !== "hidden" && style.display !== "none";
436
+ }
423
437
  function tagEncodedElement(element, decoded) {
424
438
  element.setAttribute("data-prepr-encoded", "");
425
439
  element.setAttribute("data-prepr-href", decoded.href);
@@ -428,32 +442,45 @@ function tagEncodedElement(element, decoded) {
428
442
 
429
443
  // src/core/stega/auto-clean.ts
430
444
  var debug2 = createScopedLogger("stega:auto-clean");
431
- function createStegaAutoClean() {
445
+ function createStegaAutoClean(options) {
446
+ const stripText = options?.enabled ?? true;
432
447
  let observer = null;
433
448
  let processing = false;
434
449
  let cleaned = /* @__PURE__ */ new WeakMap();
450
+ let pendingHidden = /* @__PURE__ */ new Set();
451
+ let pendingDirty = /* @__PURE__ */ new Set();
435
452
  let debounceTimeout = null;
436
453
  function cleanTextNode(textNode) {
437
454
  if (isIgnoredTextNode(textNode)) return false;
438
455
  const textContent = textNode.textContent;
439
456
  const info = cleaned.get(textNode);
440
- if (info && textContent === info.cleaned) return false;
457
+ const settled = stripText ? info?.cleaned : info?.original;
458
+ if (info && textContent === settled) {
459
+ const shown = resolveEditTarget(textNode);
460
+ if (!shown) return false;
461
+ pendingHidden.delete(textNode);
462
+ if (shown.hasAttribute("data-prepr-encoded")) return false;
463
+ tagEncodedElement(shown, info.decoded);
464
+ return true;
465
+ }
441
466
  try {
442
467
  const { cleaned: stripped, encoded } = (0, import_stega2.vercelStegaSplit)(textContent);
443
468
  if (!encoded || stripped === textContent) return false;
444
469
  const decoded = decodeStega(textContent);
445
470
  if (!decoded?.href) return false;
446
- cleaned.set(textNode, { original: textContent, cleaned: stripped });
447
- textNode.textContent = stripped;
448
- let target = textNode.parentElement;
449
- const editTargetParent = textNode.parentElement?.closest(
450
- "[data-prepr-edit-target]"
451
- );
452
- if (editTargetParent) target = editTargetParent;
471
+ cleaned.set(textNode, {
472
+ original: textContent,
473
+ cleaned: stripped,
474
+ decoded
475
+ });
476
+ if (stripText) textNode.textContent = stripped;
477
+ const target = resolveEditTarget(textNode);
453
478
  if (target) {
479
+ pendingHidden.delete(textNode);
454
480
  tagEncodedElement(target, decoded);
455
481
  return true;
456
482
  }
483
+ pendingHidden.add(textNode);
457
484
  } catch (error) {
458
485
  debug2.log("error cleaning text node", error);
459
486
  }
@@ -462,8 +489,10 @@ function createStegaAutoClean() {
462
489
  function scanAndClean() {
463
490
  processing = true;
464
491
  walkTextNodes(document.body, cleanTextNode);
465
- const title = (0, import_stega2.vercelStegaSplit)(document.title);
466
- if (title.encoded) document.title = title.cleaned;
492
+ if (stripText) {
493
+ const title = (0, import_stega2.vercelStegaSplit)(document.title);
494
+ if (title.encoded) document.title = title.cleaned;
495
+ }
467
496
  processing = false;
468
497
  }
469
498
  function collectAffected(mutations) {
@@ -488,15 +517,37 @@ function createStegaAutoClean() {
488
517
  });
489
518
  return affected;
490
519
  }
520
+ function retryPendingHidden() {
521
+ if (pendingHidden.size === 0) return;
522
+ processing = true;
523
+ [...pendingHidden].forEach((textNode) => {
524
+ if (!textNode.isConnected) {
525
+ pendingHidden.delete(textNode);
526
+ return;
527
+ }
528
+ cleanTextNode(textNode);
529
+ });
530
+ processing = false;
531
+ }
491
532
  function handleMutations(mutations) {
492
533
  if (processing) return;
493
534
  const affected = collectAffected(mutations);
494
- if (affected.size === 0) return;
535
+ if (affected.size === 0) {
536
+ retryPendingHidden();
537
+ return;
538
+ }
539
+ affected.forEach((textNode) => pendingDirty.add(textNode));
495
540
  if (debounceTimeout) clearTimeout(debounceTimeout);
496
541
  debounceTimeout = setTimeout(() => {
542
+ debounceTimeout = null;
497
543
  processing = true;
498
- affected.forEach((textNode) => cleanTextNode(textNode));
544
+ const batch = [...pendingDirty];
545
+ pendingDirty.clear();
546
+ batch.forEach((textNode) => {
547
+ if (textNode.isConnected) cleanTextNode(textNode);
548
+ });
499
549
  processing = false;
550
+ retryPendingHidden();
500
551
  }, 50);
501
552
  }
502
553
  function setupObserver() {
@@ -504,7 +555,11 @@ function createStegaAutoClean() {
504
555
  observer.observe(document.body, {
505
556
  childList: true,
506
557
  subtree: true,
507
- characterData: true
558
+ characterData: true,
559
+ // A dropdown opening only toggles a class or inline style; without these
560
+ // the nodes it reveals are never revisited and stay untagged.
561
+ attributes: true,
562
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
508
563
  });
509
564
  }
510
565
  function start() {
@@ -523,6 +578,8 @@ function createStegaAutoClean() {
523
578
  observer = null;
524
579
  }
525
580
  cleaned = /* @__PURE__ */ new WeakMap();
581
+ pendingHidden = /* @__PURE__ */ new Set();
582
+ pendingDirty = /* @__PURE__ */ new Set();
526
583
  debug2.log("stega auto-clean stopped");
527
584
  }
528
585
  return { start, stop };
@@ -545,7 +602,7 @@ var StegaElements = class {
545
602
  tagFromTextNode(node) {
546
603
  const decoded = this.decode(node.textContent);
547
604
  if (!decoded?.href) return false;
548
- const target = node.parentElement;
605
+ const target = resolveEditTarget(node);
549
606
  if (!target || target.hasAttribute("data-prepr-encoded")) return false;
550
607
  tagEncodedElement(target, decoded);
551
608
  return true;
@@ -591,8 +648,13 @@ var StegaElements = class {
591
648
  if (mutation.type === "characterData") {
592
649
  addedNodes.add(mutation.target);
593
650
  }
651
+ if (mutation.type === "attributes") {
652
+ addedNodes.add(mutation.target);
653
+ }
654
+ });
655
+ addedNodes.forEach((node) => {
656
+ if (node.isConnected) this.scanNode(node);
594
657
  });
595
- addedNodes.forEach((node) => this.scanNode(node));
596
658
  pending = [];
597
659
  this.elements = document.querySelectorAll("[data-prepr-encoded]");
598
660
  onUpdate?.();
@@ -605,7 +667,11 @@ var StegaElements = class {
605
667
  this.observer.observe(document.body, {
606
668
  childList: true,
607
669
  subtree: true,
608
- characterData: true
670
+ characterData: true,
671
+ // Reveal-on-class/style (dropdowns, accordions) changes no text and adds
672
+ // no nodes, but does change what is hoverable and needs a rescan.
673
+ attributes: true,
674
+ attributeFilter: ["class", "style", "hidden", "open", "aria-expanded"]
609
675
  });
610
676
  }
611
677
  /** Drops the active class but keeps the data attributes, unlike cleanup(). */
@@ -694,11 +760,13 @@ var StegaOverlay = class {
694
760
  const maxTop = window.scrollY + window.innerHeight - tooltip.clientHeight - 4;
695
761
  const minLeft = window.scrollX + 4;
696
762
  const maxLeft = window.scrollX + window.innerWidth - tooltip.clientWidth - 4;
697
- if (top < minTop) {
763
+ const below = top < minTop;
764
+ if (below) {
698
765
  top = rect.bottom + window.scrollY + 2;
699
766
  }
700
767
  top = Math.max(minTop, Math.min(top, maxTop));
701
768
  left = Math.max(minLeft, Math.min(left, maxLeft));
769
+ tooltip.dataset.preprPlacement = below ? "below" : "above";
702
770
  tooltip.style.top = `${top}px`;
703
771
  tooltip.style.left = `${left}px`;
704
772
  });
@@ -830,7 +898,7 @@ var StegaProximity = class {
830
898
  };
831
899
 
832
900
  // src/core/stega/stega.generated.ts
833
- 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}';
901
+ 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}';
834
902
 
835
903
  // src/core/stega/styles.ts
836
904
  var STEGA_STYLE_MARKER = "data-prepr-stega";
@@ -1379,7 +1447,7 @@ var CLOSE_ICON_SVG = `<svg width="10" height="10" viewBox="0 0 10 10" fill="none
1379
1447
  </svg>`;
1380
1448
 
1381
1449
  // src/core/ui/toolbar.generated.ts
1382
- 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}}";
1450
+ 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}}";
1383
1451
 
1384
1452
  // ../../node_modules/.pnpm/preact@10.29.7/node_modules/preact/jsx-runtime/dist/jsxRuntime.mjs
1385
1453
  var f2 = 0;
@@ -1638,13 +1706,17 @@ function StatusPill({
1638
1706
  } else {
1639
1707
  segmentLabel = defaultSegmentName;
1640
1708
  }
1709
+ const dirty = features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant === "B";
1710
+ const interactive = !state.previewMode || dirty;
1641
1711
  return /* @__PURE__ */ u2(
1642
1712
  "button",
1643
1713
  {
1644
1714
  type: "button",
1645
1715
  class: "prepr-status-pill",
1646
1716
  "data-prepr": "status-pill",
1717
+ "data-interactive": String(interactive),
1647
1718
  hidden: state.isIframe,
1719
+ disabled: !interactive,
1648
1720
  onClick: () => handlers.onStatusPill(),
1649
1721
  children: [
1650
1722
  /* @__PURE__ */ u2("span", { class: "prepr-status-viewing", "data-prepr": "status-viewing", children: t3("common.viewingAs") }),
@@ -1663,7 +1735,7 @@ function StatusPill({
1663
1735
  {
1664
1736
  class: "prepr-status-x",
1665
1737
  "data-prepr": "status-x",
1666
- hidden: !state.previewMode || !(features.segments && state.selectedSegment !== null || features.abTesting && state.selectedVariant === "B"),
1738
+ hidden: !state.previewMode || !dirty,
1667
1739
  children: /* @__PURE__ */ u2(RawSvg, { svg: XMARK_ICON_SVG })
1668
1740
  }
1669
1741
  )
@@ -2167,7 +2239,9 @@ function createPreprPreview(opts = {}) {
2167
2239
  }
2168
2240
  }
2169
2241
  });
2170
- const autoClean = createStegaAutoClean();
2242
+ const autoClean = createStegaAutoClean({
2243
+ enabled: options?.autoClean
2244
+ });
2171
2245
  autoClean.start();
2172
2246
  const handleChange = createChangeHandler({
2173
2247
  store,
@@ -2523,7 +2597,7 @@ function processPreprRequest(request, opts) {
2523
2597
  }
2524
2598
 
2525
2599
  // src/core/pixel.ts
2526
- var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr-v2.min.js";
2600
+ var PIXEL_SCRIPT_URL = "https://cdn.tracking.prepr.io/js/prepr.min.js";
2527
2601
  var CACHE_BUST_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2528
2602
  var warnedNoPixel = false;
2529
2603
  function warnNoPixelOnce() {
package/dist/index.d.cts CHANGED
@@ -1,11 +1,11 @@
1
- import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-Dd72wuJp.cjs';
2
- export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-Dd72wuJp.cjs';
1
+ import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-B6FtY-11.cjs';
2
+ export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-B6FtY-11.cjs';
3
3
 
4
4
  /**
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.2.0";
8
+ declare const VERSION = "0.3.4";
9
9
 
10
10
  /**
11
11
  * Resolve a `PreprFeatures` bag to plain booleans, defaulting every omitted key
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-Dd72wuJp.js';
2
- export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-Dd72wuJp.js';
1
+ import { P as PreprFeatures, R as ResolvedPreprFeatures, L as Locale, a as PreprSegment, b as PreprVariant, c as PreprToolbarProps, d as PreprPreviewOptions, e as PreprErrorCode, f as PreprHeaders } from './pixel-B6FtY-11.js';
2
+ export { g as PreprEnvironment, h as PreprEventType, i as PreprFeatureConfig, j as PreprHeaderName, k as PreprPixelConfig, l as PreprToolbarComponentProps, m as PreprToolbarOptions, n as loadTrackingPixel, s as setTrackingParam, t as trackEvent } from './pixel-B6FtY-11.js';
3
3
 
4
4
  /**
5
5
  * Package version; must match package.json. Lives in its own leaf module so
6
6
  * core can import it without cycling through the barrel.
7
7
  */
8
- declare const VERSION = "0.2.0";
8
+ declare const VERSION = "0.3.4";
9
9
 
10
10
  /**
11
11
  * Resolve a `PreprFeatures` bag to plain booleans, defaulting every omitted key
package/dist/index.js CHANGED
@@ -17,10 +17,10 @@ import {
17
17
  setTrackingParam,
18
18
  stegaClean,
19
19
  trackEvent
20
- } from "./chunk-4PJK6IQ4.js";
20
+ } from "./chunk-HXQ6JUZM.js";
21
21
 
22
22
  // src/version.ts
23
- var VERSION = "0.2.0";
23
+ var VERSION = "0.3.4";
24
24
 
25
25
  // src/core/server.ts
26
26
  var PreprError = class extends Error {