@unhingged/vizu-core 0.1.2 → 0.1.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/vizu.min.js CHANGED
@@ -1,183 +1,4 @@
1
- "use strict";var VIZU=(()=>{var ie=Object.defineProperty;var _e=Object.getOwnPropertyDescriptor;var Ne=Object.getOwnPropertyNames;var je=Object.prototype.hasOwnProperty;var F=(s,e)=>()=>(s&&(e=s(s=0)),e);var me=(s,e)=>{for(var t in e)ie(s,t,{get:e[t],enumerable:!0})},Be=(s,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ne(e))!je.call(s,i)&&i!==t&&ie(s,i,{get:()=>e[i],enumerable:!(n=_e(e,i))||n.enumerable});return s};var qe=s=>Be(ie({},"__esModule",{value:!0}),s);function ze(s){let e=[],t=s,n=0;for(;t&&t!==document.documentElement&&n<8;){let i=t.tagName.toLowerCase();if(t.id){e.unshift("#"+CSS.escape(t.id));break}let r=Array.from(t.classList).filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")).slice(0,2);r.length&&(i+="."+r.map(a=>CSS.escape(a)).join("."));let o=t.parentElement;if(o){let a=Array.from(o.children).filter(l=>l.tagName===t.tagName);if(a.length>1){let l=a.indexOf(t);i+=":nth-of-type("+(l+1)+")"}}e.unshift(i),t=o,n++}return e.join(" > ")}function M(s){let e=s.innerText||s.textContent||"",t=s.parentElement,n=0;return t&&(n=Array.from(t.children).indexOf(s)),{selector:ze(s),parentSelector:t?ze(t):"",tagName:s.tagName,textSnippet:e.trim().slice(0,80),siblingIndex:n,attributes:{id:s.id||void 0,classList:Array.from(s.classList).filter(i=>!i.startsWith("vz-")&&!i.startsWith("vizu-")),role:s.getAttribute("role")||void 0,ariaLabel:s.getAttribute("aria-label")||void 0,dataKey:s.getAttribute("data-vizu-key")||void 0},ancestorChain:Ze(s,4),algorithmVersion:2}}function Ze(s,e){let t=[],n=s.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t.length>0?{steps:t}:void 0}function P(s,e=document){if(s.attributes.dataKey){try{let o=e.querySelector(`[data-vizu-key="${CSS.escape(s.attributes.dataKey)}"]`);if(o)return{element:o,confidence:"exact"}}catch{}return{element:null,confidence:"orphaned"}}if(s.attributes.id)try{let o=e.querySelector("#"+CSS.escape(s.attributes.id));if(o)return{element:o,confidence:"exact"}}catch{}let t=[],n=s.attributes.classList;if(n&&n.length>0){let o=Ge(e,s.tagName,n);o?.element&&t.push({el:o.element,rung:"class"})}try{let o=e.querySelector(s.selector);o&&t.push({el:o,rung:"selector"})}catch{}if(s.ancestorChain&&s.ancestorChain.steps.length>0){let o=Qe(e,s.tagName,s.ancestorChain.steps);o?.element&&t.push({el:o.element,rung:"chain"})}else try{let o=s.parentSelector?e.querySelector(s.parentSelector):e;if(o){let a=o.children[s.siblingIndex];a&&a.tagName===s.tagName&&t.push({el:a,rung:"chain"})}}catch{}if(s.textSnippet){let o=tt(e,s.tagName,s.textSnippet);o?.element&&t.push({el:o.element,rung:"text"})}if(t.length===0)return{element:null,confidence:"orphaned"};let i=new Map;for(let o of t){let a=i.get(o.el);a||(a=new Set,i.set(o.el,a)),a.add(o.rung)}let r=null;for(let[o,a]of i)(!r||a.size>r.rungs.size)&&(r={el:o,rungs:a});return r?r.rungs.size>=3?{element:r.el,confidence:"likely"}:r.rungs.size>=2?{element:r.el,confidence:"drifted"}:r.rungs.has("class")||r.rungs.has("chain")?{element:r.el,confidence:"drifted"}:{element:null,confidence:"orphaned"}:{element:null,confidence:"orphaned"}}function Ge(s,e,t){let n=new Set(t.filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")));if(n.size===0)return null;let i=s.querySelectorAll(e.toLowerCase()),r=null,o=0;for(let a of i){let l=new Set(Array.from(a.classList).filter(p=>!p.startsWith("vz-")&&!p.startsWith("vizu-")));if(l.size===0)continue;let c=st(n,l);c<.6||(!r||c>r.score?(o=r?.score??0,r={el:a,score:c}):c>o&&(o=c))}return!r||r.score-o<.1?null:{element:r.el,confidence:"likely"}}function Qe(s,e,t){let n=s.querySelectorAll(e.toLowerCase()),i=null;for(let r of n){let o=et(r,t.length+3),a=rt(o,t,3);a<2||(!i||a>i.score)&&(i={el:r,score:a})}return i?{element:i.el,confidence:i.score===t.length?"likely":"drifted"}:null}function et(s,e){let t=[],n=s.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t}function tt(s,e,t){let n=we(t);if(!n)return null;let i=s.querySelectorAll(e.toLowerCase()),r=null;for(let o of i){let a=o.innerText||o.textContent||"",l=we(a.slice(0,160));if(!l)continue;let c=nt(n,l);c<.75||(!r||c>r.score)&&(r={el:o,score:c})}return r?{element:r.el,confidence:"drifted"}:null}function we(s){return s.toLowerCase().replace(/\s+/g," ").trim()}function nt(s,e){if(s===e)return 1;if(s.length===0||e.length===0)return s.length===e.length?1:0;let t=Math.max(s.length,e.length);return 1-it(s,e)/t}function it(s,e){if(s.length>e.length){let i=s;s=e,e=i}let t=new Array(s.length+1),n=new Array(s.length+1);for(let i=0;i<=s.length;i++)t[i]=i;for(let i=1;i<=e.length;i++){n[0]=i;for(let r=1;r<=s.length;r++){let o=s.charCodeAt(r-1)===e.charCodeAt(i-1)?0:1;n[r]=Math.min(n[r-1]+1,t[r]+1,t[r-1]+o)}for(let r=0;r<=s.length;r++)t[r]=n[r]}return t[s.length]}function rt(s,e,t){let n=0;for(let i=0;i<=t;i++){let r=0;for(let o=0;o<e.length;o++){let a=s[o+i];if(!a)break;a.tag===e[o].tag&&a.nthOfType===e[o].nthOfType&&r++}r>n&&(n=r)}return n}function st(s,e){if(s.size===0&&e.size===0)return 1;let t=0;for(let i of s)e.has(i)&&t++;let n=s.size+e.size-t;return n===0?0:t/n}function R(s,e){return P(s,e).element}function m(s){return s.selector+"|"+s.textSnippet}function V(s){let e=s.tagName.toLowerCase();if(s.textSnippet){let t=s.textSnippet.length>24?s.textSnippet.slice(0,24)+"\u2026":s.textSnippet;return e+": "+t}return s.attributes.id?e+"#"+s.attributes.id:s.attributes.classList&&s.attributes.classList.length?e+"."+s.attributes.classList[0]:e}var $=F(()=>{"use strict"});function G(s){let e=0;for(let t=0;t<s.length;t++)e=e*31+s.charCodeAt(t)|0;return Se[Math.abs(e)%Se.length]}function I(){return typeof window>"u"||!window.matchMedia?!1:window.matchMedia("(prefers-reduced-motion: reduce)").matches}var Se,Q=F(()=>{"use strict";Se=["#4F46E5","#15803D","#C2410C","#BE185D","#0E7490","#7E22CE","#DC2626","#0F766E"]});function vt(s,e){let t=document.createElement("div");t.setAttribute("data-vizu-presence-avatar",s.id),t.setAttribute("data-vizu-presence-name",s.name),t.setAttribute("data-vizu-presence-color",s.color),s.avatar&&t.setAttribute("data-vizu-presence-img",s.avatar);let n=I(),i=n?"none":"transform 130ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 130ms ease-out";t.style.cssText=`
2
- position: relative;
3
- width: ${ee}px;
4
- height: ${ee}px;
5
- margin-left: -${Me}px;
6
- border-radius: 50%;
7
- background: ${s.color};
8
- padding: 1.5px;
9
- box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.95), 0 2px 6px rgba(0, 0, 0, 0.15);
10
- cursor: pointer;
11
- flex-shrink: 0;
12
- transition: ${i};
13
- `,t.addEventListener("click",a=>{a.preventDefault(),a.stopPropagation(),e()}),n||(t.addEventListener("mouseenter",()=>t.style.transform="translateY(-1px) scale(1.06)"),t.addEventListener("mouseleave",()=>t.style.transform=""));let r=document.createElement("div");r.setAttribute("data-vizu-presence-inner",""),r.style.cssText=`
14
- width: 100%;
15
- height: 100%;
16
- border-radius: 50%;
17
- overflow: hidden;
18
- background: ${s.color};
19
- color: #ffffff;
20
- display: flex;
21
- align-items: center;
22
- justify-content: center;
23
- font-size: 10.5px;
24
- font-weight: 600;
25
- letter-spacing: -0.01em;
26
- line-height: 1;
27
- user-select: none;
28
- `,Pe(r,s),t.appendChild(r);let o=bt(s.name);return t.appendChild(o),t.addEventListener("mouseenter",()=>{o.style.opacity="1",o.style.transform="translateY(0)"}),t.addEventListener("mouseleave",()=>{o.style.opacity="0",o.style.transform="translateY(-2px)"}),t}function ft(s,e){let t=s.querySelector("[data-vizu-presence-inner]");t&&Pe(t,e);let n=s.querySelector("[data-vizu-presence-tip]");n&&(n.textContent=e.name),s.setAttribute("data-vizu-presence-name",e.name),e.avatar?s.setAttribute("data-vizu-presence-img",e.avatar):s.removeAttribute("data-vizu-presence-img")}function gt(s){let e=s.getAttribute("data-vizu-presence-avatar"),t=s.getAttribute("data-vizu-presence-name"),n=s.getAttribute("data-vizu-presence-color");if(!e||!t||!n)return null;let i=s.getAttribute("data-vizu-presence-img")??void 0;return{id:e,name:t,color:n,avatar:i}}function Te(s,e,t){t?s.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.95), 0 0 0 4px var(--vizu-coral, #FF6647), 0 4px 12px rgba(255, 102, 71, 0.4)":s.style.boxShadow="0 0 0 2px rgba(255, 255, 255, 0.95), 0 2px 6px rgba(0, 0, 0, 0.15)"}function Pe(s,e){if(s.textContent="",e.avatar){let t=document.createElement("img");t.src=e.avatar,t.alt=e.name,t.referrerPolicy="no-referrer",t.style.cssText="width: 100%; height: 100%; object-fit: cover; display: block;",t.addEventListener("error",()=>{t.remove(),s.textContent=Le(e.name)},{once:!0}),s.appendChild(t)}else s.textContent=Le(e.name)}function bt(s){let e=document.createElement("div");return e.setAttribute("data-vizu-presence-tip",""),e.textContent=s,e.style.cssText=`
29
- position: absolute;
30
- top: calc(100% + 6px);
31
- right: 0;
32
- background: rgba(10, 10, 10, 0.92);
33
- color: #ffffff;
34
- font-size: 11px;
35
- font-weight: 500;
36
- padding: 4px 8px;
37
- border-radius: 4px;
38
- white-space: nowrap;
39
- pointer-events: none;
40
- opacity: 0;
41
- transform: translateY(-2px);
42
- transition: opacity 130ms ease-out, transform 130ms ease-out;
43
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
44
- max-width: 220px;
45
- overflow: hidden;
46
- text-overflow: ellipsis;
47
- `,e}function xt(){let s=document.createElement("div");return s.setAttribute("data-vizu-presence-overflow",""),s.style.cssText=`
48
- width: ${ee}px;
49
- height: ${ee}px;
50
- margin-left: -${Me}px;
51
- border-radius: 50%;
52
- background: rgba(82, 82, 82, 0.95);
53
- color: #ffffff;
54
- box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.95), 0 2px 6px rgba(0, 0, 0, 0.15);
55
- display: flex;
56
- align-items: center;
57
- justify-content: center;
58
- font-size: 10.5px;
59
- font-weight: 600;
60
- letter-spacing: -0.02em;
61
- line-height: 1;
62
- user-select: none;
63
- flex-shrink: 0;
64
- `,s}function Le(s){let e=s.trim();if(!e)return"?";let t=e.split(/\s+/);return t.length>=2&&t[0]&&t[t.length-1]?(t[0][0]+t[t.length-1][0]).toUpperCase():e.slice(0,2).toUpperCase()}var ht,mt,ee,Me,te,Re=F(()=>{"use strict";Q();ht=2147483640,mt=5,ee=28,Me=6,te=class{constructor(e){this.container=null;this.avatars=new Map;this.overflowEl=null;this.followingUserId=null;this.onAvatarClick=null;this.onAvatarClick=e?.onAvatarClick??null}mount(){typeof document>"u"||this.container||(this.container=document.createElement("div"),this.container.setAttribute("data-vizu-presence-stack",""),this.container.style.cssText=`
65
- position: fixed;
66
- top: 16px;
67
- right: 16px;
68
- z-index: ${ht};
69
- display: flex;
70
- align-items: center;
71
- pointer-events: auto;
72
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
73
- `,document.body.appendChild(this.container))}destroy(){for(let e of this.avatars.values())e.remove();this.avatars.clear(),this.overflowEl?.remove(),this.overflowEl=null,this.container?.remove(),this.container=null}setOthers(e){if(!this.container)return;let t=e.slice(0,mt),n=Math.max(0,e.length-t.length),i=new Set(t.map(r=>r.id));for(let[r,o]of Array.from(this.avatars))i.has(r)||(o.remove(),this.avatars.delete(r));for(let r of t){let o=this.avatars.get(r.id);o?ft(o,r):(o=vt(r,()=>this.onAvatarClick?.(r.id)),this.avatars.set(r.id,o)),Te(o,r,this.followingUserId===r.id),this.container.appendChild(o)}this.renderOverflow(n)}setFollowing(e){this.followingUserId=e;for(let[t,n]of this.avatars){let i=gt(n);i&&Te(n,i,t===e)}}renderOverflow(e){if(this.container){if(e<=0){this.overflowEl?.remove(),this.overflowEl=null;return}this.overflowEl||(this.overflowEl=xt()),this.overflowEl.textContent=`+${e}`,this.container.appendChild(this.overflowEl)}}}});function zt(s,e){let t=document.createElement("div");t.setAttribute("data-vizu-selection-overlay","");let n=I()?"none":"left 90ms ease-out, top 90ms ease-out, width 90ms ease-out, height 90ms ease-out";t.style.cssText=`
74
- position: fixed;
75
- pointer-events: none;
76
- display: none;
77
- border: 2px dashed ${s};
78
- border-radius: 4px;
79
- background: ${s}10;
80
- box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85);
81
- transition: ${n};
82
- will-change: left, top, width, height;
83
- `;let i=document.createElement("div");return i.setAttribute("data-selection-label",""),i.textContent=e,i.style.cssText=`
84
- position: absolute;
85
- top: -22px;
86
- left: -2px;
87
- padding: 2px 7px;
88
- background: ${s};
89
- color: #ffffff;
90
- font: 500 10.5px/1.4 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
91
- border-radius: 3px 3px 3px 0;
92
- white-space: nowrap;
93
- max-width: 180px;
94
- overflow: hidden;
95
- text-overflow: ellipsis;
96
- box-shadow: 0 2px 4px rgba(0,0,0,0.15);
97
- `,t.appendChild(i),t}var yt,ne,Ve=F(()=>{"use strict";$();Q();yt=2147483639,ne=class{constructor(){this.container=null;this.overlays=new Map;this.scrollListener=null;this.resizeListener=null;this.rafScheduled=!1}mount(){typeof document>"u"||this.container||(this.container=document.createElement("div"),this.container.setAttribute("data-vizu-selections",""),this.container.style.cssText=`
98
- position: fixed; inset: 0;
99
- pointer-events: none;
100
- z-index: ${yt};
101
- contain: strict;
102
- `,document.body.appendChild(this.container),this.scrollListener=()=>this.scheduleReposition(),this.resizeListener=()=>this.scheduleReposition(),window.addEventListener("scroll",this.scrollListener,{passive:!0,capture:!0}),window.addEventListener("resize",this.resizeListener))}destroy(){this.scrollListener&&(window.removeEventListener("scroll",this.scrollListener,!0),this.scrollListener=null),this.resizeListener&&(window.removeEventListener("resize",this.resizeListener),this.resizeListener=null);for(let e of this.overlays.values())e.el.remove();this.overlays.clear(),this.container?.remove(),this.container=null}setSelections(e){if(!this.container)return;let t=new Set(e.map(n=>n.id));for(let[n,i]of Array.from(this.overlays))t.has(n)||(i.el.remove(),this.overlays.delete(n));for(let n of e){let i=this.overlays.get(n.id);if(i){if(i.fingerprint=n.fingerprint,i.color!==n.color&&(i.color=n.color,i.el.style.borderColor=n.color),i.name!==n.name){i.name=n.name;let r=i.el.querySelector("[data-selection-label]");r&&(r.textContent=n.name,r.style.background=n.color)}}else{let r=zt(n.color,n.name);this.container.appendChild(r),i={el:r,fingerprint:n.fingerprint,color:n.color,name:n.name},this.overlays.set(n.id,i)}this.positionOverlay(i)}}positionOverlay(e){let n=P(e.fingerprint)?.element??null;if(!n){e.el.style.display="none";return}let i=n.getBoundingClientRect();if(i.width===0||i.height===0){e.el.style.display="none";return}e.el.style.display="block",e.el.style.left=`${i.left}px`,e.el.style.top=`${i.top}px`,e.el.style.width=`${i.width}px`,e.el.style.height=`${i.height}px`}scheduleReposition(){this.rafScheduled||(this.rafScheduled=!0,requestAnimationFrame(()=>{this.rafScheduled=!1;for(let e of this.overlays.values())this.positionOverlay(e)}))}}});var Ie={};me(Ie,{LiveCollab:()=>ae,roomIdFor:()=>$e});function wt(){let s=Math.floor(Math.random()*4294967295).toString(16).padStart(8,"0"),e=Math.floor(Math.random()*4294967295).toString(16).padStart(8,"0");return`${s}${e}`}function Mt(s){let e=2166136261;for(let t=0;t<s.length;t++)e^=s.charCodeAt(t),e=Math.imul(e,16777619);return(e>>>0).toString(16).padStart(8,"0")}function $e(s,e){return`ws_${s}__pg_${Mt(e)}`}function Pt(s,e){let t=document.createElement("div");t.setAttribute("data-vizu-cursor","");let n=I()?"none":`transform ${At}ms cubic-bezier(0.16, 1, 0.3, 1)`;t.style.cssText=`
103
- position: absolute; top: 0; left: 0;
104
- pointer-events: none;
105
- opacity: 0;
106
- transform: translate(0px, 0px);
107
- transition: ${n}, opacity 220ms ease-out;
108
- will-change: transform;
109
- `;let i=document.createElementNS("http://www.w3.org/2000/svg","svg");i.setAttribute("width","18"),i.setAttribute("height","20"),i.setAttribute("viewBox","0 0 16 18"),i.style.cssText="display: block; filter: drop-shadow(0 1px 1.5px rgba(0,0,0,0.3));";let r=document.createElementNS("http://www.w3.org/2000/svg","path");r.setAttribute("d","M0 0 L0 13 L4 9 L7 16 L9 15 L6 8 L11 8 Z"),r.setAttribute("fill",e),r.setAttribute("stroke","#ffffff"),r.setAttribute("stroke-width","1.2"),r.setAttribute("stroke-linejoin","round"),i.appendChild(r),t.appendChild(i);let o=document.createElement("div");return o.textContent=s,o.style.cssText=`
110
- margin-top: 2px;
111
- margin-left: 10px;
112
- padding: 2px 7px;
113
- background: ${e};
114
- color: #ffffff;
115
- font: 500 11px/1.4 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
116
- border-radius: 4px;
117
- white-space: nowrap;
118
- box-shadow: 0 2px 6px rgba(0,0,0,0.18);
119
- max-width: 160px;
120
- overflow: hidden;
121
- text-overflow: ellipsis;
122
- `,t.appendChild(o),t}function Rt(s){switch(s){case"connecting":return"Connecting\u2026";case"reconnecting":return"Reconnecting\u2026";case"disconnected":return"Offline";case"initial":return"Connecting\u2026";case"connected":return""}}var Ct,Et,kt,At,de,St,Tt,Lt,ae,le,ce,Fe=F(()=>{"use strict";Re();Ve();Q();Ct=100,Et=200,kt=5e3,At=220,de=2147483641,St=8,Tt=2,Lt=5;ae=class{constructor(e){this.opts=e;this.container=null;this.cursors=new Map;this.presenceStack=null;this.followPill=null;this.selectionOverlay=null;this.mouseListener=null;this.scrollListener=null;this.visibilityListener=null;this.keydownListener=null;this.statusIndicator=null;this.pushTimer=null;this.pullTimer=null;this.destroyed=!1;this.roomId=null;this.latestOthers=[];this.currentPresence={cursor:null,scrollY:0,selecting:null};this.presenceDirty=!1;this.status="initial";this.consecutiveErrors=0;this.followingUserId=null;this.lastFolloweeScrollY=null;this.connId=wt(),typeof window<"u"&&(this.currentPresence.scrollY=window.scrollY)}async start(){if(!(typeof window>"u"||typeof document>"u")&&!this.destroyed)try{let e=this.opts.pageUrl??window.location.origin+window.location.pathname;this.roomId=$e(this.opts.workspaceSlug,e),this.mountContainer(),this.presenceStack=new te({onAvatarClick:t=>this.setFollowing(t)}),this.presenceStack.mount(),this.followPill=new ce({onStop:()=>this.setFollowing(null)}),this.selectionOverlay=new ne,this.selectionOverlay.mount(),this.statusIndicator=new le,this.statusIndicator.mount(),this.setStatus("connecting"),this.attachMouseListener(),this.attachScrollListener(),this.attachVisibilityListener(),this.attachKeyboardListener(),this.pushTimer=window.setInterval(()=>{this.push()},Ct),this.pullTimer=window.setInterval(()=>{this.pull()},Et),this.presenceDirty=!0,this.push(),this.pull()}catch(e){typeof console<"u"&&console.warn("[vizu/live-collab] start failed; live cursors disabled:",e),this.cleanup()}}destroy(){this.destroyed=!0,this.cleanup()}cleanup(){this.clearRemotePresence(),this.mouseListener&&(window.removeEventListener("mousemove",this.mouseListener),this.mouseListener=null),this.scrollListener&&(window.removeEventListener("scroll",this.scrollListener),this.scrollListener=null),this.visibilityListener&&(document.removeEventListener("visibilitychange",this.visibilityListener),this.visibilityListener=null),this.keydownListener&&(document.removeEventListener("keydown",this.keydownListener),this.keydownListener=null),this.pushTimer!=null&&(window.clearInterval(this.pushTimer),this.pushTimer=null),this.pullTimer!=null&&(window.clearInterval(this.pullTimer),this.pullTimer=null);for(let e of this.cursors.values())e.fadeTimer!=null&&window.clearTimeout(e.fadeTimer),e.el.remove();this.cursors.clear(),this.presenceStack?.destroy(),this.presenceStack=null,this.followPill?.destroy(),this.followPill=null,this.selectionOverlay?.destroy(),this.selectionOverlay=null,this.statusIndicator?.destroy(),this.statusIndicator=null,this.followingUserId=null,this.lastFolloweeScrollY=null,this.container?.remove(),this.container=null,this.roomId=null,this.latestOthers=[]}setLocalSelection(e){this.currentPresence.selecting=e?{fingerprintJson:JSON.stringify(e)}:null,this.presenceDirty=!0}setFollowing(e){this.followingUserId!==e&&(this.followingUserId=e,this.lastFolloweeScrollY=null,this.presenceStack?.setFollowing(e),this.followPill?.setFollowing(e?this.lookupUserForPill(e):null),e&&this.scrollToFolloweeIfKnown())}lookupUserForPill(e){for(let t of this.latestOthers)if(t.user.userId===e)return{id:e,name:t.user.name??"Anonymous",color:G(e),avatar:t.user.avatar};return null}scrollToFolloweeIfKnown(){if(this.followingUserId){for(let e of this.latestOthers)if(e.user.userId===this.followingUserId){typeof e.presence.scrollY=="number"&&this.followScrollTo(e.presence.scrollY);return}}}followScrollTo(e){this.lastFolloweeScrollY!==null&&Math.abs(this.lastFolloweeScrollY-e)<St||(this.lastFolloweeScrollY=e,window.scrollTo({top:e,behavior:"smooth"}))}mountContainer(){this.container=document.createElement("div"),this.container.setAttribute("data-vizu-live-cursors",""),this.container.style.cssText=`
123
- position: fixed; inset: 0;
124
- pointer-events: none;
125
- z-index: ${de};
126
- contain: strict;
127
- `,document.body.appendChild(this.container)}attachMouseListener(){this.mouseListener=e=>{this.currentPresence.cursor={xPct:e.clientX/window.innerWidth*100,yPct:e.clientY/window.innerHeight*100},this.presenceDirty=!0},window.addEventListener("mousemove",this.mouseListener,{passive:!0})}attachScrollListener(){this.scrollListener=()=>{this.currentPresence.scrollY=window.scrollY,this.presenceDirty=!0},window.addEventListener("scroll",this.scrollListener,{passive:!0})}attachVisibilityListener(){this.visibilityListener=()=>{document.hidden?this.clearRemotePresence():this.presenceDirty=!0},document.addEventListener("visibilitychange",this.visibilityListener)}attachKeyboardListener(){this.keydownListener=e=>{e.key==="Escape"&&this.followingUserId&&this.setFollowing(null)},document.addEventListener("keydown",this.keydownListener)}setStatus(e){this.status!==e&&(this.status=e,this.statusIndicator?.setStatus(e))}async push(){if(!(this.destroyed||!this.roomId)&&this.presenceDirty&&!(typeof document<"u"&&document.hidden)){this.presenceDirty=!1;try{let e=await this.fetchLive(`/api/live/${encodeURIComponent(this.roomId)}/me`,{method:"POST",body:JSON.stringify({connId:this.connId,presence:this.currentPresence})});if(!e.ok){if(e.status===402||e.status===401||e.status===503){this.setStatus("disconnected"),this.pushTimer!=null&&(window.clearInterval(this.pushTimer),this.pushTimer=null),this.pullTimer!=null&&(window.clearInterval(this.pullTimer),this.pullTimer=null);return}throw new Error(`push HTTP ${e.status}`)}this.noteSuccess()}catch(e){this.noteError(e),this.presenceDirty=!0}}}async pull(){if(!(this.destroyed||!this.roomId))try{let e=await this.fetchLive(`/api/live/${encodeURIComponent(this.roomId)}/others?me=${encodeURIComponent(this.connId)}`,{method:"GET"});if(!e.ok){if(e.status===503||e.status===401){this.setStatus("disconnected"),this.pullTimer!=null&&(window.clearInterval(this.pullTimer),this.pullTimer=null);return}throw new Error(`pull HTTP ${e.status}`)}let n=((await e.json()).others??[]).map(i=>({connId:i.connId,presence:i.payload.presence,user:i.payload.user}));this.latestOthers=n,this.renderOthers(n),this.noteSuccess()}catch(e){this.noteError(e)}}noteSuccess(){this.consecutiveErrors=0,this.status!=="connected"&&this.setStatus("connected")}noteError(e){this.consecutiveErrors++,this.consecutiveErrors>=Lt?this.setStatus("disconnected"):this.consecutiveErrors>=Tt&&this.setStatus("reconnecting"),typeof console<"u"&&this.consecutiveErrors===1&&console.warn("[vizu/live-collab] transport error",e)}renderOthers(e){let t=new Set,n=new Map,i=[],r=null,o=!1;for(let a of e){t.add(a.connId);let l=a.user.userId,c=a.user.name??"Anonymous",p=G(l);if(n.has(l)||n.set(l,{id:l,name:c,color:p,avatar:a.user.avatar}),this.followingUserId===l&&r===null&&(o=!0,typeof a.presence.scrollY=="number"&&(r=a.presence.scrollY)),a.presence.selecting&&!i.find(u=>u.id===l))try{let u=JSON.parse(a.presence.selecting.fingerprintJson);i.push({id:l,name:c,color:p,fingerprint:u})}catch{}if(!a.presence.cursor){this.removeCursor(a.connId);continue}this.upsertCursor(a.connId,l,c,a.presence.cursor)}for(let a of Array.from(this.cursors.keys()))t.has(a)||this.removeCursor(a);this.presenceStack?.setOthers(Array.from(n.values())),this.selectionOverlay?.setSelections(i),this.followingUserId&&(o?r!==null&&this.followScrollTo(r):this.setFollowing(null))}async fetchLive(e,t){let n=new Headers(t.headers);if(n.set("content-type","application/json"),this.opts.getAuthHeader){let i=await this.opts.getAuthHeader();i&&new Headers(i).forEach((r,o)=>n.set(o,r))}return fetch(this.opts.apiUrl+e,{...t,headers:n,credentials:"include"})}async clearRemotePresence(){if(this.roomId)try{await this.fetchLive(`/api/live/${encodeURIComponent(this.roomId)}/me`,{method:"POST",body:JSON.stringify({connId:this.connId,clearOnly:!0})})}catch{}}upsertCursor(e,t,n,i){if(!this.container)return;let r=this.cursors.get(e);if(!r){let c=G(t),p=Pt(n,c);this.container.appendChild(p),r={el:p,fadeTimer:null},this.cursors.set(e,r)}if(!(i.xPct>=0&&i.xPct<=100&&i.yPct>=0&&i.yPct<=100)){r.el.style.opacity="0";return}let a=window.innerWidth*i.xPct/100,l=window.innerHeight*i.yPct/100;r.el.style.transform=`translate(${a}px, ${l}px)`,r.el.style.opacity="1",r.fadeTimer!=null&&window.clearTimeout(r.fadeTimer),r.fadeTimer=window.setTimeout(()=>{r&&(r.el.style.opacity="0")},kt)}removeCursor(e){let t=this.cursors.get(e);t&&(t.fadeTimer!=null&&window.clearTimeout(t.fadeTimer),t.el.style.opacity="0",window.setTimeout(()=>t.el.remove(),220),this.cursors.delete(e))}};le=class{constructor(){this.el=null;this.label=null}mount(){if(typeof document>"u"||this.el)return;this.el=document.createElement("div"),this.el.setAttribute("data-vizu-connection-status",""),this.el.style.cssText=`
128
- position: fixed;
129
- top: 18px;
130
- right: 200px;
131
- z-index: ${de};
132
- display: none;
133
- align-items: center;
134
- gap: 7px;
135
- padding: 4px 10px 4px 8px;
136
- background: rgba(10, 10, 10, 0.88);
137
- color: #fafafa;
138
- font: 500 11px/1.4 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
139
- border-radius: 999px;
140
- box-shadow: 0 6px 16px rgba(0, 0, 0, 0.22);
141
- pointer-events: none;
142
- `;let e=document.createElement("span");e.style.cssText=`
143
- display: inline-block;
144
- width: 6px; height: 6px;
145
- border-radius: 50%;
146
- background: #F59E0B;
147
- box-shadow: 0 0 6px #F59E0B;
148
- `;let t=document.createElement("span");this.label=t,this.el.appendChild(e),this.el.appendChild(t),document.body.appendChild(this.el)}setStatus(e){if(!(!this.el||!this.label)){if(e==="connected"){this.el.style.display="none";return}this.label.textContent=Rt(e),this.el.style.display="inline-flex"}}destroy(){this.el?.remove(),this.el=null,this.label=null}};ce=class{constructor(e){this.el=null;this.onStop=e.onStop}setFollowing(e){if(!(typeof document>"u")){if(!e){this.el?.remove(),this.el=null;return}this.el||(this.el=this.mount()),this.paint(e)}}destroy(){this.el?.remove(),this.el=null}mount(){let e=document.createElement("div");return e.setAttribute("data-vizu-follow-pill",""),e.style.cssText=`
149
- position: fixed;
150
- top: 56px;
151
- right: 16px;
152
- z-index: ${de};
153
- display: inline-flex;
154
- align-items: center;
155
- gap: 8px;
156
- padding: 6px 6px 6px 12px;
157
- background: rgba(10, 10, 10, 0.92);
158
- color: #ffffff;
159
- border-radius: 999px;
160
- font: 500 12px/1.4 -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
161
- box-shadow: 0 10px 24px rgba(0, 0, 0, 0.28);
162
- pointer-events: auto;
163
- `,document.body.appendChild(e),e}paint(e){if(!this.el)return;this.el.textContent="";let t=document.createElement("span");t.style.cssText=`
164
- display: inline-block;
165
- width: 8px; height: 8px;
166
- border-radius: 50%;
167
- background: ${e.color};
168
- box-shadow: 0 0 8px ${e.color};
169
- `,this.el.appendChild(t);let n=document.createElement("span");n.textContent=`Following ${e.name}`,n.style.cssText="max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;",this.el.appendChild(n);let i=document.createElement("button");i.type="button",i.setAttribute("aria-label",`Stop following ${e.name}`),i.innerHTML='<svg width="11" height="11" viewBox="0 0 12 12" aria-hidden="true"><path d="M1 1 L11 11 M11 1 L1 11" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" /></svg>',i.style.cssText=`
170
- display: inline-flex;
171
- align-items: center;
172
- justify-content: center;
173
- width: 22px; height: 22px;
174
- border: none;
175
- background: rgba(255, 255, 255, 0.12);
176
- color: #ffffff;
177
- border-radius: 50%;
178
- cursor: pointer;
179
- transition: background 120ms ease-out;
180
- `,i.addEventListener("mouseenter",()=>i.style.background="rgba(255, 255, 255, 0.22)"),i.addEventListener("mouseleave",()=>i.style.background="rgba(255, 255, 255, 0.12)"),i.addEventListener("click",r=>{r.preventDefault(),this.onStop()}),this.el.appendChild(i)}}});var Ft={};me(Ft,{Vizu:()=>E});function O(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2)+Date.now().toString(36)}function re(s,e){return!!s.closest(e)}function d(s){return s.replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function A(s){let e=new Date(s),n=Date.now()-s;return n<6e4?"just now":n<36e5?Math.floor(n/6e4)+"m ago":n<864e5?Math.floor(n/36e5)+"h ago":e.toLocaleDateString()+" "+e.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function Ke(s){return s.split(/\s+/).filter(Boolean).slice(0,2).map(e=>e[0].toUpperCase()).join("")}function b(s,e="vz-comment-author-avatar"){return s?s.avatarUrl?`<span class="${e}"><img src="${d(s.avatarUrl)}" alt="${d(s.name)}" /></span>`:`<span class="${e}">${d(Ke(s.name)||"?")}</span>`:`<span class="${e}">\xB7</span>`}function ve(){return Math.random().toString(36).slice(2,10)}var Je=/\[@([^\]]+)\]\(vizu-mention:([a-zA-Z0-9_-]+)\)/g,We=/(\[#[^\]]+\]\(vizu-ref:[a-zA-Z0-9_-]+\)|\[@[^\]]+\]\(vizu-mention:[a-zA-Z0-9_-]+\))/g;function U(s,e){return s.split(We).map(n=>{let i=n.match(/^\[#([^\]]+)\]\(vizu-ref:([a-zA-Z0-9_-]+)\)$/);if(i)return`<a class="vz-ref" data-vz="ref" data-comment-id="${d(e)}" data-ref-id="${d(i[2])}" role="button" tabindex="0">${d(i[1])}</a>`;let r=n.match(/^\[@([^\]]+)\]\(vizu-mention:([a-zA-Z0-9_-]+)\)$/);return r?`<span class="vz-mention" data-vz="mention" data-mention-id="${d(r[2])}">@${d(r[1])}</span>`:d(n)}).join("")}function fe(s){let e=[];for(let t of s.matchAll(Je))e.includes(t[2])||e.push(t[2]);return e}function H(s){return!Array.isArray(s)||s.length===0?"":`<div class="vz-attachment-grid">${s.map(t=>{let n=t.mimeType?.startsWith("image/"),i=t.filename??t.url.split("/").pop()??"file";return n?`
1
+ "use strict";var VIZU=(()=>{var X=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ze=Object.getOwnPropertyNames;var xe=Object.prototype.hasOwnProperty;var ye=(o,e)=>{for(var t in e)X(o,t,{get:e[t],enumerable:!0})},Ce=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of ze(e))!xe.call(o,i)&&i!==t&&X(o,i,{get:()=>e[i],enumerable:!(n=be(e,i))||n.enumerable});return o};var we=o=>Ce(X({},"__esModule",{value:!0}),o);var We={};ye(We,{Vizu:()=>k});function R(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():Math.random().toString(36).slice(2)+Date.now().toString(36)}function Y(o,e){return!!o.closest(e)}function d(o){return o.replace(/[&<>"']/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[e])}function E(o){let e=new Date(o),n=Date.now()-o;return n<6e4?"just now":n<36e5?Math.floor(n/6e4)+"m ago":n<864e5?Math.floor(n/36e5)+"h ago":e.toLocaleDateString()+" "+e.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function ke(o){return o.split(/\s+/).filter(Boolean).slice(0,2).map(e=>e[0].toUpperCase()).join("")}function b(o,e="vz-comment-author-avatar"){return o?o.avatarUrl?`<span class="${e}"><img src="${d(o.avatarUrl)}" alt="${d(o.name)}" /></span>`:`<span class="${e}">${d(ke(o.name)||"?")}</span>`:`<span class="${e}">\xB7</span>`}function ne(){return Math.random().toString(36).slice(2,10)}var Ae=/\[@([^\]]+)\]\(vizu-mention:([a-zA-Z0-9_-]+)\)/g,Ee=/(\[#[^\]]+\]\(vizu-ref:[a-zA-Z0-9_-]+\)|\[@[^\]]+\]\(vizu-mention:[a-zA-Z0-9_-]+\))/g;function P(o,e){return o.split(Ee).map(n=>{let i=n.match(/^\[#([^\]]+)\]\(vizu-ref:([a-zA-Z0-9_-]+)\)$/);if(i)return`<a class="vz-ref" data-vz="ref" data-comment-id="${d(e)}" data-ref-id="${d(i[2])}" role="button" tabindex="0">${d(i[1])}</a>`;let r=n.match(/^\[@([^\]]+)\]\(vizu-mention:([a-zA-Z0-9_-]+)\)$/);return r?`<span class="vz-mention" data-vz="mention" data-mention-id="${d(r[2])}">@${d(r[1])}</span>`:d(n)}).join("")}function ie(o){let e=[];for(let t of o.matchAll(Ae))e.includes(t[2])||e.push(t[2]);return e}function $(o){return!Array.isArray(o)||o.length===0?"":`<div class="vz-attachment-grid">${o.map(t=>{let n=t.mimeType?.startsWith("image/"),i=t.filename??t.url.split("/").pop()??"file";return n?`
181
2
  <a class="vz-attachment-display" href="${d(t.url)}" target="_blank" rel="noreferrer" title="${d(i)}">
182
3
  <img src="${d(t.url)}" alt="${d(i)}" loading="lazy" />
183
4
  </a>
@@ -186,44 +7,44 @@
186
7
  <span class="vz-attachment-icon" aria-hidden="true">\u{1F4C4}</span>
187
8
  <span class="vz-attachment-filename">${d(i)}</span>
188
9
  </a>
189
- `}).join("")}</div>`}function w(s){if(!s||typeof s!="object")return s;let e={...s};return(!Array.isArray(e.fingerprints)||e.fingerprints.length===0)&&e.fingerprint&&(e.fingerprints=[e.fingerprint]),delete e.fingerprint,e.url&&!e.pageUrl&&(e.pageUrl=e.url),(!("status"in e)||!Xe(e.status))&&(e.status="open"),Array.isArray(e.replies)||(e.replies=[]),Array.isArray(e.attachments)||(e.attachments=[]),Array.isArray(e.mentions)||(e.mentions=[]),"fingerprintsRefreshedAt"in e||(e.fingerprintsRefreshedAt=null),e.schemaVersion=2,e}function Xe(s){return s==="open"||s==="resolved"||s==="wontfix"}function C(s){if(!Array.isArray(s))return[];let e=[];for(let t of s)!t||typeof t!="object"||e.push(w(t));return e}function ge(s){if(!Array.isArray(s))return!1;for(let e of s){if(!e||typeof e!="object")continue;let t=e;if(t.schemaVersion!==2||"fingerprint"in t||!Array.isArray(t.replies)||!Array.isArray(t.attachments)||!Array.isArray(t.mentions))return!0}return!1}var se=s=>`vizu:comments:${s}`,D=class{async load(e){return S(e)}async addComment(e,t){let n=S(e);n.push(t),T(e,n)}async updateComment(e,t,n){let i=S(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let o={...i[r],...n,id:i[r].id};return i[r]=o,T(e,i),o}async removeComment(e,t){let n=S(e);T(e,n.filter(i=>i.id!==t))}async setAll(e,t){T(e,t)}async clear(e){typeof localStorage>"u"||localStorage.removeItem(se(e))}async addReply(e,t,n){let i=S(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let o={...i[r],replies:[...i[r].replies??[],n]};return i[r]=o,T(e,i),o}async removeReply(e,t,n){let i=S(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let o={...i[r],replies:(i[r].replies??[]).filter(a=>a.id!==n)};return i[r]=o,T(e,i),o}};function S(s){if(typeof localStorage>"u")return[];let e=localStorage.getItem(se(s));if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?C(t):[]}catch{return[]}}function T(s,e){typeof localStorage>"u"||localStorage.setItem(se(s),JSON.stringify(e))}var _=class{constructor(){this.store=new Map}async load(e){return[...this.store.get(e)||[]]}async addComment(e,t){let n=this.store.get(e)??[];this.store.set(e,[...n,t])}async updateComment(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let o={...i[r],...n,id:i[r].id},a=[...i];return a[r]=o,this.store.set(e,a),o}async removeComment(e,t){let n=this.store.get(e)??[];this.store.set(e,n.filter(i=>i.id!==t))}async setAll(e,t){this.store.set(e,[...t])}async clear(e){this.store.delete(e)}async addReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let o={...i[r],replies:[...i[r].replies??[],n]},a=[...i];return a[r]=o,this.store.set(e,a),o}async removeReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let o={...i[r],replies:(i[r].replies??[]).filter(l=>l.id!==n)},a=[...i];return a[r]=o,this.store.set(e,a),o}},q=class{async load(){return[]}async addComment(){}async updateComment(){return null}async removeComment(){}async setAll(){}async clear(){}};function oe(s){if(!s||typeof s!="object")return!1;let e=s;return typeof e.load=="function"&&typeof e.save=="function"&&typeof e.clear=="function"&&typeof e.addComment!="function"}function be(s){if(!oe(s))return s;let e=!1,t=()=>{e||(e=!0,typeof console<"u"&&console.warn("[vizu] StorageAdapter v1 detected. Per-comment ops are emulated via full-array rewrites \u2014 upgrade your adapter to the v2 interface (addComment / updateComment / removeComment / setAll / load / clear) when you can."))};return{async load(n){return t(),s.load(n)},async addComment(n,i){t();let r=await s.load(n);r.push(i),await s.save(n,r)},async updateComment(n,i,r){t();let o=await s.load(n),a=o.findIndex(c=>c.id===i);if(a===-1)return null;let l={...o[a],...r,id:o[a].id};return o[a]=l,await s.save(n,o),l},async removeComment(n,i){t();let r=await s.load(n);await s.save(n,r.filter(o=>o.id!==i))},async setAll(n,i){t(),await s.save(n,i)},async clear(n){await s.clear(n)}}}var Ye="https://vizu.unhingged.com",xe=480,ye=640,L=class{constructor(e){this.cachedToken=null;this.pendingAuth=null;this.lastNotifiedTokenId=null;this.workspace=e.workspace,this.apiUrl=(e.apiUrl??Ye).replace(/\/$/,""),this.autoSignIn=e.autoSignIn!==!1,this.onAuthChanged=e.onAuthChanged,this.cachedToken=this.readStoredToken(),this.cachedToken&&!this.isExpired(this.cachedToken)&&this.fireAuthChanged(this.cachedToken)}async preflightAuth(){await this.resolveToken()}getCachedAuthToken(){return!this.cachedToken||this.isExpired(this.cachedToken)?null:this.cachedToken.token}async load(e){let t=[],n=null;do{let i=new URL(this.apiUrl+"/api/comments");i.searchParams.set("workspace",this.workspace),i.searchParams.set("limit","100"),n&&i.searchParams.set("cursor",n);let r=await this.fetchAuthed(i.toString(),{method:"GET"}),o=await this.parseJson(r);if(!r.ok)throw x(r.status,o);let a=Array.isArray(o.comments)?o.comments:[];t.push(...C(a)),n=typeof o.nextCursor=="string"?o.nextCursor:null}while(n);return t}async addComment(e,t){let n=await this.fetchAuthed(this.apiUrl+"/api/comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({workspace:this.workspace,comment:t})}),i=await this.parseJson(n);if(!n.ok)throw x(n.status,i)}async updateComment(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let o=await this.parseJson(r);if(!r.ok)throw x(r.status,o);return w(o.comment)}async removeComment(e,t){let n=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));n.searchParams.set("workspace",this.workspace);let i=await this.fetchAuthed(n.toString(),{method:"DELETE"});if(i.status!==404&&!i.ok){let r=await this.parseJson(i);throw x(i.status,r)}}async setAll(e,t){await this.clear(e);for(let n of t)await this.addComment(e,n)}async clear(e){let t=new URL(this.apiUrl+"/api/comments");t.searchParams.set("workspace",this.workspace),t.searchParams.set("all","true");let n=await this.fetchAuthed(t.toString(),{method:"DELETE"});if(n.status!==404&&!n.ok){let i=await this.parseJson(n);throw x(n.status,i)}}async addReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let o=await this.parseJson(r);if(!r.ok)throw x(r.status,o);return o?.comment?w(o.comment):null}async removeReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies/"+encodeURIComponent(n));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"DELETE"});if(r.status===404)return null;if(!r.ok){let o=await this.parseJson(r);throw x(r.status,o)}return null}async uploadAttachment(e,t){let n=new FormData;n.append("file",t,t.name);let i=new URL(this.apiUrl+"/api/uploads");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",body:n}),o=await this.parseJson(r);if(!r.ok)throw x(r.status,o);if(!o?.url||typeof o.url!="string")throw x(500,{error:"upload_failed",message:"Backend did not return a URL."});return{id:O(),url:o.url,mimeType:t.type||"application/octet-stream",sizeBytes:t.size,uploadedAt:Date.now(),filename:t.name}}getAuthContext(){return this.cachedToken?{userId:this.cachedToken.userId,token:this.cachedToken.token,expiresAt:this.cachedToken.expiresAt}:null}isExpired(e){if(!e)return!0;let t=new Date(e.expiresAt).getTime();return!Number.isFinite(t)||t-Date.now()<3e4}readStoredToken(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.sessionKey());if(!e)return null;try{let t=JSON.parse(e);return this.isExpired(t)?(sessionStorage.removeItem(this.sessionKey()),null):t}catch{return null}}writeStoredToken(e){this.cachedToken=e,typeof sessionStorage<"u"&&sessionStorage.setItem(this.sessionKey(),JSON.stringify(e))}clearStoredToken(){this.cachedToken=null,typeof sessionStorage<"u"&&sessionStorage.removeItem(this.sessionKey())}sessionKey(){return`vizu:cloud-token:v2:${this.workspace}`}async resolveToken(){if(this.cachedToken&&!this.isExpired(this.cachedToken))return this.cachedToken;let e=this.readStoredToken();if(e)return this.cachedToken=e,this.fireAuthChanged(e),e;if(!this.autoSignIn)throw K("auth_required","Sign-in required; autoSignIn is disabled.");return this.pendingAuth||(this.pendingAuth=this.openSignInPopup().then(t=>(this.writeStoredToken(t),this.fireAuthChanged(t),t)).finally(()=>{this.pendingAuth=null})),this.pendingAuth}fireAuthChanged(e){if(this.lastNotifiedTokenId!==e.token){this.lastNotifiedTokenId=e.token;try{this.onAuthChanged?.({userId:e.userId,user:e.user})}catch(t){typeof console<"u"&&console.warn("[vizu/cloud] onAuthChanged callback threw",t)}}}openSignInPopup(){return new Promise((e,t)=>{if(typeof window>"u")return t(K("auth_unavailable","Sign-in requires a browser environment."));let n=new URL(this.apiUrl).origin,i=window.location.origin,r=this.apiUrl+"/connect?workspace="+encodeURIComponent(this.workspace)+"&origin="+encodeURIComponent(i),o=Math.max(0,Math.round((window.screen.width-xe)/2)),a=Math.max(0,Math.round((window.screen.height-ye)/2)),l=window.open(r,"vizu-connect",`width=${xe},height=${ye},left=${o},top=${a},noopener=no,popup=yes`);if(!l)return t(K("popup_blocked","Sign-in popup was blocked by the browser. Allow popups for this site and try again."));let c=!1,p=j=>{if(j.origin!==n)return;let f=j.data;if(!f||f.type!=="vizu:auth"||f.workspace!==this.workspace||typeof f.token!="string"||typeof f.expiresAt!="string"||typeof f.userId!="string")return;c=!0,N();let g=f.user,h=g&&typeof g.name=="string"?{id:typeof g.id=="string"?g.id:f.userId,name:g.name,avatarUrl:typeof g.avatarUrl=="string"?g.avatarUrl:void 0}:null;e({token:f.token,expiresAt:f.expiresAt,userId:f.userId,user:h})},u=window.setInterval(()=>{l.closed&&(c||(N(),t(K("auth_canceled","Sign-in popup was closed before completing."))))},500);function N(){window.clearInterval(u),window.removeEventListener("message",p)}window.addEventListener("message",p)})}async fetchAuthed(e,t,n=!1){let i=await this.resolveToken(),r=new Headers(t.headers);r.set("authorization",`Bearer ${i.token}`);let o=await fetch(e,{...t,headers:r,credentials:"omit"});return o.status===401&&!n?(this.clearStoredToken(),this.fetchAuthed(e,t,!0)):o}async parseJson(e){try{let t=await e.text();return t?JSON.parse(t):null}catch{return null}}};function K(s,e){let t=new Error(e);return t.code=s,t}function x(s,e){let t=e?.error==="origin_not_allowed"?"origin_not_allowed":e?.error==="not_found"?"workspace_not_found":"http_error",n=new Error(e?.message??`HTTP ${s}`);return n.code=t,n.status=s,n.body=e,n}$();var ot="[data-vizu-root], [data-vizu-ignore], script, style, link, meta, head",J=class{constructor(e,t,n,i){this.current=null;this.active=!1;this.paused=!1;this.handleMove=e=>{if(this.paused){this.setCurrent(null),this.overlay.style.display="none";return}let t=document.elementFromPoint(e.clientX,e.clientY);if(!(!t||t===this.current)){if(this.shouldIgnore(t)){this.setCurrent(null),this.overlay.style.display="none";return}this.setCurrent(t),this.updateOverlay()}};this.handleClick=e=>{let t=document.elementFromPoint(e.clientX,e.clientY);t&&(this.shouldIgnore(t)||(e.preventDefault(),e.stopPropagation(),this.onClick(t,e)))};this.handleScroll=()=>{this.current&&this.updateOverlay()};this.root=e,this.extraIgnore=t,this.onClick=n,this.onCurrentChange=i??null,this.overlay=document.createElement("div"),this.overlay.className="vz-highlight",this.overlay.style.display="none",this.root.appendChild(this.overlay)}setCurrent(e){this.current!==e&&(this.current=e,this.onCurrentChange?.(e))}start(){this.active||(this.active=!0,document.addEventListener("mousemove",this.handleMove,!0),document.addEventListener("click",this.handleClick,!0),document.addEventListener("scroll",this.handleScroll,!0),window.addEventListener("resize",this.handleScroll))}stop(){this.active&&(this.active=!1,document.removeEventListener("mousemove",this.handleMove,!0),document.removeEventListener("click",this.handleClick,!0),document.removeEventListener("scroll",this.handleScroll,!0),window.removeEventListener("resize",this.handleScroll),this.overlay.style.display="none",this.setCurrent(null))}shouldIgnore(e){if(e===document.documentElement||e===document.body||re(e,ot))return!0;for(let t of this.extraIgnore)try{if(re(e,t))return!0}catch{}return!1}setPaused(e){this.paused=e,e&&(this.setCurrent(null),this.overlay.style.display="none")}isPaused(){return this.paused}updateOverlay(){if(!this.current)return;let e=this.current.getBoundingClientRect();if(e.width===0||e.height===0){this.overlay.style.display="none";return}this.overlay.style.display="block",this.overlay.style.left=e.left+"px",this.overlay.style.top=e.top+"px",this.overlay.style.width=e.width+"px",this.overlay.style.height=e.height+"px"}destroy(){this.stop(),this.overlay.remove()}};$();function Ce(s){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(s):s.replace(/["\\]/g,"\\$&")}function at(s){let t=(s.replies??[]).map(n=>`
10
+ `}).join("")}</div>`}function C(o){if(!o||typeof o!="object")return o;let e={...o};return(!Array.isArray(e.fingerprints)||e.fingerprints.length===0)&&e.fingerprint&&(e.fingerprints=[e.fingerprint]),delete e.fingerprint,e.url&&!e.pageUrl&&(e.pageUrl=e.url),(!("status"in e)||!Se(e.status))&&(e.status="open"),Array.isArray(e.replies)||(e.replies=[]),Array.isArray(e.attachments)||(e.attachments=[]),Array.isArray(e.mentions)||(e.mentions=[]),"fingerprintsRefreshedAt"in e||(e.fingerprintsRefreshedAt=null),e.schemaVersion=2,e}function Se(o){return o==="open"||o==="resolved"||o==="wontfix"}function w(o){if(!Array.isArray(o))return[];let e=[];for(let t of o)!t||typeof t!="object"||e.push(C(t));return e}function re(o){if(!Array.isArray(o))return!1;for(let e of o){if(!e||typeof e!="object")continue;let t=e;if(t.schemaVersion!==2||"fingerprint"in t||!Array.isArray(t.replies)||!Array.isArray(t.attachments)||!Array.isArray(t.mentions))return!0}return!1}var Z=o=>`vizu:comments:${o}`,F=class{async load(e){return S(e)}async addComment(e,t){let n=S(e);n.push(t),T(e,n)}async updateComment(e,t,n){let i=S(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],...n,id:i[r].id};return i[r]=s,T(e,i),s}async removeComment(e,t){let n=S(e);T(e,n.filter(i=>i.id!==t))}async setAll(e,t){T(e,t)}async clear(e){typeof localStorage>"u"||localStorage.removeItem(Z(e))}async addReply(e,t,n){let i=S(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],replies:[...i[r].replies??[],n]};return i[r]=s,T(e,i),s}async removeReply(e,t,n){let i=S(e),r=i.findIndex(a=>a.id===t);if(r===-1)return null;let s={...i[r],replies:(i[r].replies??[]).filter(a=>a.id!==n)};return i[r]=s,T(e,i),s}};function S(o){if(typeof localStorage>"u")return[];let e=localStorage.getItem(Z(o));if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?w(t):[]}catch{return[]}}function T(o,e){typeof localStorage>"u"||localStorage.setItem(Z(o),JSON.stringify(e))}var H=class{constructor(){this.store=new Map}async load(e){return[...this.store.get(e)||[]]}async addComment(e,t){let n=this.store.get(e)??[];this.store.set(e,[...n,t])}async updateComment(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],...n,id:i[r].id},a=[...i];return a[r]=s,this.store.set(e,a),s}async removeComment(e,t){let n=this.store.get(e)??[];this.store.set(e,n.filter(i=>i.id!==t))}async setAll(e,t){this.store.set(e,[...t])}async clear(e){this.store.delete(e)}async addReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],replies:[...i[r].replies??[],n]},a=[...i];return a[r]=s,this.store.set(e,a),s}async removeReply(e,t,n){let i=this.store.get(e)??[],r=i.findIndex(l=>l.id===t);if(r===-1)return null;let s={...i[r],replies:(i[r].replies??[]).filter(l=>l.id!==n)},a=[...i];return a[r]=s,this.store.set(e,a),s}},N=class{async load(){return[]}async addComment(){}async updateComment(){return null}async removeComment(){}async setAll(){}async clear(){}};function G(o){if(!o||typeof o!="object")return!1;let e=o;return typeof e.load=="function"&&typeof e.save=="function"&&typeof e.clear=="function"&&typeof e.addComment!="function"}function se(o){if(!G(o))return o;let e=!1,t=()=>{e||(e=!0,typeof console<"u"&&console.warn("[vizu] StorageAdapter v1 detected. Per-comment ops are emulated via full-array rewrites \u2014 upgrade your adapter to the v2 interface (addComment / updateComment / removeComment / setAll / load / clear) when you can."))};return{async load(n){return t(),o.load(n)},async addComment(n,i){t();let r=await o.load(n);r.push(i),await o.save(n,r)},async updateComment(n,i,r){t();let s=await o.load(n),a=s.findIndex(c=>c.id===i);if(a===-1)return null;let l={...s[a],...r,id:s[a].id};return s[a]=l,await o.save(n,s),l},async removeComment(n,i){t();let r=await o.load(n);await o.save(n,r.filter(s=>s.id!==i))},async setAll(n,i){t(),await o.save(n,i)},async clear(n){await o.clear(n)}}}var Te="https://vizu.unhingged.com",oe=480,ae=640,M=class{constructor(e){this.cachedToken=null;this.pendingAuth=null;this.lastNotifiedTokenId=null;this.workspace=e.workspace,this.apiUrl=(e.apiUrl??Te).replace(/\/$/,""),this.autoSignIn=e.autoSignIn!==!1,this.onAuthChanged=e.onAuthChanged,this.cachedToken=this.readStoredToken(),this.cachedToken&&!this.isExpired(this.cachedToken)&&this.fireAuthChanged(this.cachedToken)}async preflightAuth(){await this.resolveToken()}async load(e){let t=[],n=null;do{let i=new URL(this.apiUrl+"/api/comments");i.searchParams.set("workspace",this.workspace),i.searchParams.set("limit","100"),n&&i.searchParams.set("cursor",n);let r=await this.fetchAuthed(i.toString(),{method:"GET"}),s=await this.parseJson(r);if(!r.ok)throw z(r.status,s);let a=Array.isArray(s.comments)?s.comments:[];t.push(...w(a)),n=typeof s.nextCursor=="string"?s.nextCursor:null}while(n);return t}async addComment(e,t){let n=await this.fetchAuthed(this.apiUrl+"/api/comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({workspace:this.workspace,comment:t})}),i=await this.parseJson(n);if(!n.ok)throw z(n.status,i)}async updateComment(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let s=await this.parseJson(r);if(!r.ok)throw z(r.status,s);return C(s.comment)}async removeComment(e,t){let n=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t));n.searchParams.set("workspace",this.workspace);let i=await this.fetchAuthed(n.toString(),{method:"DELETE"});if(i.status!==404&&!i.ok){let r=await this.parseJson(i);throw z(i.status,r)}}async setAll(e,t){await this.clear(e);for(let n of t)await this.addComment(e,n)}async clear(e){let t=new URL(this.apiUrl+"/api/comments");t.searchParams.set("workspace",this.workspace),t.searchParams.set("all","true");let n=await this.fetchAuthed(t.toString(),{method:"DELETE"});if(n.status!==404&&!n.ok){let i=await this.parseJson(n);throw z(n.status,i)}}async addReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)});if(r.status===404)return null;let s=await this.parseJson(r);if(!r.ok)throw z(r.status,s);return s?.comment?C(s.comment):null}async removeReply(e,t,n){let i=new URL(this.apiUrl+"/api/comments/"+encodeURIComponent(t)+"/replies/"+encodeURIComponent(n));i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"DELETE"});if(r.status===404)return null;if(!r.ok){let s=await this.parseJson(r);throw z(r.status,s)}return null}async uploadAttachment(e,t){let n=new FormData;n.append("file",t,t.name);let i=new URL(this.apiUrl+"/api/uploads");i.searchParams.set("workspace",this.workspace);let r=await this.fetchAuthed(i.toString(),{method:"POST",body:n}),s=await this.parseJson(r);if(!r.ok)throw z(r.status,s);if(!s?.url||typeof s.url!="string")throw z(500,{error:"upload_failed",message:"Backend did not return a URL."});return{id:R(),url:s.url,mimeType:t.type||"application/octet-stream",sizeBytes:t.size,uploadedAt:Date.now(),filename:t.name}}getAuthContext(){return this.cachedToken?{userId:this.cachedToken.userId,token:this.cachedToken.token,expiresAt:this.cachedToken.expiresAt}:null}isExpired(e){if(!e)return!0;let t=new Date(e.expiresAt).getTime();return!Number.isFinite(t)||t-Date.now()<3e4}readStoredToken(){if(typeof sessionStorage>"u")return null;let e=sessionStorage.getItem(this.sessionKey());if(!e)return null;try{let t=JSON.parse(e);return this.isExpired(t)?(sessionStorage.removeItem(this.sessionKey()),null):t}catch{return null}}writeStoredToken(e){this.cachedToken=e,typeof sessionStorage<"u"&&sessionStorage.setItem(this.sessionKey(),JSON.stringify(e))}clearStoredToken(){this.cachedToken=null,typeof sessionStorage<"u"&&sessionStorage.removeItem(this.sessionKey())}sessionKey(){return`vizu:cloud-token:v2:${this.workspace}`}async resolveToken(){if(this.cachedToken&&!this.isExpired(this.cachedToken))return this.cachedToken;let e=this.readStoredToken();if(e)return this.cachedToken=e,this.fireAuthChanged(e),e;if(!this.autoSignIn)throw D("auth_required","Sign-in required; autoSignIn is disabled.");return this.pendingAuth||(this.pendingAuth=this.openSignInPopup().then(t=>(this.writeStoredToken(t),this.fireAuthChanged(t),t)).finally(()=>{this.pendingAuth=null})),this.pendingAuth}fireAuthChanged(e){if(this.lastNotifiedTokenId!==e.token){this.lastNotifiedTokenId=e.token;try{this.onAuthChanged?.({userId:e.userId,user:e.user})}catch(t){typeof console<"u"&&console.warn("[vizu/cloud] onAuthChanged callback threw",t)}}}openSignInPopup(){return new Promise((e,t)=>{if(typeof window>"u")return t(D("auth_unavailable","Sign-in requires a browser environment."));let n=new URL(this.apiUrl).origin,i=window.location.origin,r=this.apiUrl+"/connect?workspace="+encodeURIComponent(this.workspace)+"&origin="+encodeURIComponent(i),s=Math.max(0,Math.round((window.screen.width-oe)/2)),a=Math.max(0,Math.round((window.screen.height-ae)/2)),l=window.open(r,"vizu-connect",`width=${oe},height=${ae},left=${s},top=${a},noopener=no,popup=yes`);if(!l)return t(D("popup_blocked","Sign-in popup was blocked by the browser. Allow popups for this site and try again."));let c=!1,p=U=>{if(U.origin!==n)return;let v=U.data;if(!v||v.type!=="vizu:auth"||v.workspace!==this.workspace||typeof v.token!="string"||typeof v.expiresAt!="string"||typeof v.userId!="string")return;c=!0,I();let f=v.user,u=f&&typeof f.name=="string"?{id:typeof f.id=="string"?f.id:v.userId,name:f.name,avatarUrl:typeof f.avatarUrl=="string"?f.avatarUrl:void 0}:null;e({token:v.token,expiresAt:v.expiresAt,userId:v.userId,user:u})},m=window.setInterval(()=>{l.closed&&(c||(I(),t(D("auth_canceled","Sign-in popup was closed before completing."))))},500);function I(){window.clearInterval(m),window.removeEventListener("message",p)}window.addEventListener("message",p)})}async fetchAuthed(e,t,n=!1){let i=await this.resolveToken(),r=new Headers(t.headers);r.set("authorization",`Bearer ${i.token}`);let s=await fetch(e,{...t,headers:r,credentials:"omit"});return s.status===401&&!n?(this.clearStoredToken(),this.fetchAuthed(e,t,!0)):s}async parseJson(e){try{let t=await e.text();return t?JSON.parse(t):null}catch{return null}}};function D(o,e){let t=new Error(e);return t.code=o,t}function z(o,e){let t=e?.error==="origin_not_allowed"?"origin_not_allowed":e?.error==="not_found"?"workspace_not_found":"http_error",n=new Error(e?.message??`HTTP ${o}`);return n.code=t,n.status=o,n.body=e,n}function le(o){let e=[],t=o,n=0;for(;t&&t!==document.documentElement&&n<8;){let i=t.tagName.toLowerCase();if(t.id){e.unshift("#"+CSS.escape(t.id));break}let r=Array.from(t.classList).filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")).slice(0,2);r.length&&(i+="."+r.map(a=>CSS.escape(a)).join("."));let s=t.parentElement;if(s){let a=Array.from(s.children).filter(l=>l.tagName===t.tagName);if(a.length>1){let l=a.indexOf(t);i+=":nth-of-type("+(l+1)+")"}}e.unshift(i),t=s,n++}return e.join(" > ")}function O(o){let e=o.innerText||o.textContent||"",t=o.parentElement,n=0;return t&&(n=Array.from(t.children).indexOf(o)),{selector:le(o),parentSelector:t?le(t):"",tagName:o.tagName,textSnippet:e.trim().slice(0,80),siblingIndex:n,attributes:{id:o.id||void 0,classList:Array.from(o.classList).filter(i=>!i.startsWith("vz-")&&!i.startsWith("vizu-")),role:o.getAttribute("role")||void 0,ariaLabel:o.getAttribute("aria-label")||void 0,dataKey:o.getAttribute("data-vizu-key")||void 0},ancestorChain:Me(o,4),algorithmVersion:2}}function Me(o,e){let t=[],n=o.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t.length>0?{steps:t}:void 0}function j(o,e=document){if(o.attributes.dataKey){try{let s=e.querySelector(`[data-vizu-key="${CSS.escape(o.attributes.dataKey)}"]`);if(s)return{element:s,confidence:"exact"}}catch{}return{element:null,confidence:"orphaned"}}if(o.attributes.id)try{let s=e.querySelector("#"+CSS.escape(o.attributes.id));if(s)return{element:s,confidence:"exact"}}catch{}let t=[],n=o.attributes.classList;if(n&&n.length>0){let s=Ve(e,o.tagName,n);s?.element&&t.push({el:s.element,rung:"class"})}try{let s=e.querySelector(o.selector);s&&t.push({el:s,rung:"selector"})}catch{}if(o.ancestorChain&&o.ancestorChain.steps.length>0){let s=Le(e,o.tagName,o.ancestorChain.steps);s?.element&&t.push({el:s.element,rung:"chain"})}else try{let s=o.parentSelector?e.querySelector(o.parentSelector):e;if(s){let a=s.children[o.siblingIndex];a&&a.tagName===o.tagName&&t.push({el:a,rung:"chain"})}}catch{}if(o.textSnippet){let s=Pe(e,o.tagName,o.textSnippet);s?.element&&t.push({el:s.element,rung:"text"})}if(t.length===0)return{element:null,confidence:"orphaned"};let i=new Map;for(let s of t){let a=i.get(s.el);a||(a=new Set,i.set(s.el,a)),a.add(s.rung)}let r=null;for(let[s,a]of i)(!r||a.size>r.rungs.size)&&(r={el:s,rungs:a});return r?r.rungs.size>=3?{element:r.el,confidence:"likely"}:r.rungs.size>=2?{element:r.el,confidence:"drifted"}:r.rungs.has("class")||r.rungs.has("chain")?{element:r.el,confidence:"drifted"}:{element:null,confidence:"orphaned"}:{element:null,confidence:"orphaned"}}function Ve(o,e,t){let n=new Set(t.filter(a=>!a.startsWith("vz-")&&!a.startsWith("vizu-")));if(n.size===0)return null;let i=o.querySelectorAll(e.toLowerCase()),r=null,s=0;for(let a of i){let l=new Set(Array.from(a.classList).filter(p=>!p.startsWith("vz-")&&!p.startsWith("vizu-")));if(l.size===0)continue;let c=Oe(n,l);c<.6||(!r||c>r.score?(s=r?.score??0,r={el:a,score:c}):c>s&&(s=c))}return!r||r.score-s<.1?null:{element:r.el,confidence:"likely"}}function Le(o,e,t){let n=o.querySelectorAll(e.toLowerCase()),i=null;for(let r of n){let s=Re(r,t.length+3),a=He(s,t,3);a<2||(!i||a>i.score)&&(i={el:r,score:a})}return i?{element:i.el,confidence:i.score===t.length?"likely":"drifted"}:null}function Re(o,e){let t=[],n=o.parentElement;for(;n&&t.length<e;){let i=n.parentElement,r=1;i&&(r=Array.from(i.children).filter(a=>a.tagName===n.tagName).indexOf(n)+1),t.push({tag:n.tagName,nthOfType:r}),n=i}return t}function Pe(o,e,t){let n=ce(t);if(!n)return null;let i=o.querySelectorAll(e.toLowerCase()),r=null;for(let s of i){let a=s.innerText||s.textContent||"",l=ce(a.slice(0,160));if(!l)continue;let c=$e(n,l);c<.75||(!r||c>r.score)&&(r={el:s,score:c})}return r?{element:r.el,confidence:"drifted"}:null}function ce(o){return o.toLowerCase().replace(/\s+/g," ").trim()}function $e(o,e){if(o===e)return 1;if(o.length===0||e.length===0)return o.length===e.length?1:0;let t=Math.max(o.length,e.length);return 1-Fe(o,e)/t}function Fe(o,e){if(o.length>e.length){let i=o;o=e,e=i}let t=new Array(o.length+1),n=new Array(o.length+1);for(let i=0;i<=o.length;i++)t[i]=i;for(let i=1;i<=e.length;i++){n[0]=i;for(let r=1;r<=o.length;r++){let s=o.charCodeAt(r-1)===e.charCodeAt(i-1)?0:1;n[r]=Math.min(n[r-1]+1,t[r]+1,t[r-1]+s)}for(let r=0;r<=o.length;r++)t[r]=n[r]}return t[o.length]}function He(o,e,t){let n=0;for(let i=0;i<=t;i++){let r=0;for(let s=0;s<e.length;s++){let a=o[s+i];if(!a)break;a.tag===e[s].tag&&a.nthOfType===e[s].nthOfType&&r++}r>n&&(n=r)}return n}function Oe(o,e){if(o.size===0&&e.size===0)return 1;let t=0;for(let i of o)e.has(i)&&t++;let n=o.size+e.size-t;return n===0?0:t/n}function V(o,e){return j(o,e).element}function h(o){return o.selector+"|"+o.textSnippet}function L(o){let e=o.tagName.toLowerCase();if(o.textSnippet){let t=o.textSnippet.length>24?o.textSnippet.slice(0,24)+"\u2026":o.textSnippet;return e+": "+t}return o.attributes.id?e+"#"+o.attributes.id:o.attributes.classList&&o.attributes.classList.length?e+"."+o.attributes.classList[0]:e}var Ie="[data-vizu-root], [data-vizu-ignore], script, style, link, meta, head",q=class{constructor(e,t,n){this.current=null;this.active=!1;this.paused=!1;this.handleMove=e=>{if(this.paused){this.setCurrent(null),this.overlay.style.display="none";return}let t=document.elementFromPoint(e.clientX,e.clientY);if(!(!t||t===this.current)){if(this.shouldIgnore(t)){this.setCurrent(null),this.overlay.style.display="none";return}this.setCurrent(t),this.updateOverlay()}};this.handleClick=e=>{let t=document.elementFromPoint(e.clientX,e.clientY);t&&(this.shouldIgnore(t)||(e.preventDefault(),e.stopPropagation(),this.onClick(t,e)))};this.handleScroll=()=>{this.current&&this.updateOverlay()};this.root=e,this.extraIgnore=t,this.onClick=n,this.overlay=document.createElement("div"),this.overlay.className="vz-highlight",this.overlay.style.display="none",this.root.appendChild(this.overlay)}setCurrent(e){this.current!==e&&(this.current=e)}start(){this.active||(this.active=!0,document.addEventListener("mousemove",this.handleMove,!0),document.addEventListener("click",this.handleClick,!0),document.addEventListener("scroll",this.handleScroll,!0),window.addEventListener("resize",this.handleScroll))}stop(){this.active&&(this.active=!1,document.removeEventListener("mousemove",this.handleMove,!0),document.removeEventListener("click",this.handleClick,!0),document.removeEventListener("scroll",this.handleScroll,!0),window.removeEventListener("resize",this.handleScroll),this.overlay.style.display="none",this.setCurrent(null))}shouldIgnore(e){if(e===document.documentElement||e===document.body||Y(e,Ie))return!0;for(let t of this.extraIgnore)try{if(Y(e,t))return!0}catch{}return!1}setPaused(e){this.paused=e,e&&(this.setCurrent(null),this.overlay.style.display="none")}isPaused(){return this.paused}updateOverlay(){if(!this.current)return;let e=this.current.getBoundingClientRect();if(e.width===0||e.height===0){this.overlay.style.display="none";return}this.overlay.style.display="block",this.overlay.style.left=e.left+"px",this.overlay.style.top=e.top+"px",this.overlay.style.width=e.width+"px",this.overlay.style.height=e.height+"px"}destroy(){this.stop(),this.overlay.remove()}};function de(o){return typeof CSS<"u"&&typeof CSS.escape=="function"?CSS.escape(o):o.replace(/["\\]/g,"\\$&")}function Ue(o){let t=(o.replies??[]).map(n=>`
190
11
  <div class="vz-reply" data-reply-id="${d(n.id)}">
191
12
  ${n.author?`<div class="vz-comment-author">${b(n.author)} <span class="vz-comment-author-name">${d(n.author.name)}</span></div>`:""}
192
13
  <div class="vz-reply-text">${d(n.text)}</div>
193
14
  <div class="vz-comment-meta">
194
- <span>${d(A(typeof n.createdAt=="number"?n.createdAt:new Date(n.createdAt).getTime()))}</span>
195
- <button class="vz-comment-delete" data-vz="delete-reply" data-comment-id="${d(s.id)}" data-reply-id="${d(n.id)}">delete</button>
15
+ <span>${d(E(typeof n.createdAt=="number"?n.createdAt:new Date(n.createdAt).getTime()))}</span>
16
+ <button class="vz-comment-delete" data-vz="delete-reply" data-comment-id="${d(o.id)}" data-reply-id="${d(n.id)}">delete</button>
196
17
  </div>
197
18
  </div>
198
19
  `).join("");return`
199
- <div class="vz-replies" data-comment-id="${d(s.id)}" hidden>
20
+ <div class="vz-replies" data-comment-id="${d(o.id)}" hidden>
200
21
  <div class="vz-reply-list">${t}</div>
201
22
  <div class="vz-reply-form">
202
- <textarea class="vz-reply-input" placeholder="Reply\u2026" rows="2" data-comment-id="${d(s.id)}"></textarea>
203
- <button class="vz-btn vz-btn-primary vz-btn-reply" data-vz="send-reply" data-id="${d(s.id)}">Send</button>
23
+ <textarea class="vz-reply-input" placeholder="Reply\u2026" rows="2" data-comment-id="${d(o.id)}"></textarea>
24
+ <button class="vz-btn vz-btn-primary vz-btn-reply" data-vz="send-reply" data-id="${d(o.id)}">Send</button>
204
25
  </div>
205
26
  </div>
206
- `}var W=class{constructor(e,t){this.currentUser=null;this.anchorTargets=[];this.anchorFingerprints=[];this.pendingRefs={};this.pendingAttachments=[];this.handleEditorKey=e=>{let t=e.currentTarget;if(e.key==="#"){e.preventDefault();let n=this.saveRange();this.callbacks.onStartReferencePick(i=>this.insertChip(i,n),()=>{t.focus(),this.restoreRange(n)});return}if(e.key==="Enter"&&(e.metaKey||e.ctrlKey)){e.preventDefault(),this.save();return}e.key==="Escape"&&(e.preventDefault(),this.callbacks.onClose())};this.handleEditorPaste=e=>{if(this.callbacks.canUploadAttachments()){let i=e.clipboardData?.items??null;if(i){let r=[];for(let o=0;o<i.length;o++){let a=i[o];if(a.kind==="file"&&a.type.startsWith("image/")){let l=a.getAsFile();l&&r.push(l)}}if(r.length>0){e.preventDefault();for(let o of r)this.uploadAndAppend(o);return}}}e.preventDefault();let t=e.clipboardData?.getData("text/plain")??"",n=window.getSelection();if(n&&n.rangeCount>0){let i=n.getRangeAt(0);i.deleteContents(),i.insertNode(document.createTextNode(t)),i.collapse(!1),n.removeAllRanges(),n.addRange(i)}};this.handleDragOver=e=>{if(!e.dataTransfer||!Array.from(e.dataTransfer.types).includes("Files"))return;e.preventDefault(),this.el.querySelector('[data-vz="drop-hint"]')?.removeAttribute("hidden")};this.handleDragLeave=e=>{let t=e.currentTarget;if(e.relatedTarget instanceof Node&&t.contains(e.relatedTarget))return;this.el.querySelector('[data-vz="drop-hint"]')?.setAttribute("hidden","")};this.handleDrop=e=>{if(e.preventDefault(),this.el.querySelector('[data-vz="drop-hint"]')?.setAttribute("hidden",""),!e.dataTransfer)return;let n=Array.from(e.dataTransfer.files).filter(i=>i.type.startsWith("image/"));for(let i of n)this.uploadAndAppend(i)};this.handleFileChange=e=>{let t=e.currentTarget,n=t.files?Array.from(t.files):[];for(let i of n)this.uploadAndAppend(i);t.value=""};this.handleClick=e=>{let t=e.target,n=t.closest('[data-vz="remove-anchor"]');if(n){e.stopPropagation();let o=n.getAttribute("data-fp-key");o&&this.removeAnchor(o);return}let i=t.closest('[data-vz="ref"]');if(i){let o=i.getAttribute("data-comment-id"),a=i.getAttribute("data-ref-id");o&&a&&(e.stopPropagation(),this.callbacks.onJumpToReference(o,a));return}let r=t.getAttribute("data-vz");if(r==="close")this.callbacks.onClose();else if(r==="save")this.save();else if(r==="mention")e.preventDefault(),this.insertMentionChip(this.currentUser);else if(r==="upload")e.preventDefault(),this.el.querySelector('[data-vz="file-input"]')?.click();else if(r==="remove-attachment"){e.preventDefault();let o=t.getAttribute("data-attachment-id");o&&(this.pendingAttachments=this.pendingAttachments.filter(a=>a.id!==o),this.renderAttachmentList())}else if(r==="delete"){let o=t.getAttribute("data-id");o&&this.callbacks.onDelete(o)}else if(r==="toggle-reply"){e.preventDefault();let o=t.getAttribute("data-id");if(!o)return;let a=this.el.querySelector(`.vz-replies[data-comment-id="${Ce(o)}"]`);if(!a)return;a.hasAttribute("hidden")?(a.removeAttribute("hidden"),a.querySelector(".vz-reply-input")?.focus()):a.setAttribute("hidden","")}else if(r==="send-reply"){e.preventDefault();let o=t.getAttribute("data-id");if(!o)return;let a=this.el.querySelector(`.vz-reply-input[data-comment-id="${Ce(o)}"]`),l=a?.value.trim()??"";if(!l)return;this.callbacks.onAddReply(o,l),a&&(a.value="")}else if(r==="delete-reply"){e.preventDefault();let o=t.getAttribute("data-comment-id"),a=t.getAttribute("data-reply-id");o&&a&&this.callbacks.onDeleteReply(o,a)}};this.root=e,this.callbacks=t,this.el=document.createElement("div"),this.el.className="vz-popover",this.el.style.display="none",this.el.addEventListener("click",this.handleClick),this.root.appendChild(this.el)}setUser(e){this.currentUser=e}open(e,t,n){this.anchorTargets=[...e],this.anchorFingerprints=[...t],this.pendingRefs={},this.render(n),this.position()}update(e){this.anchorTargets.length&&(this.render(e),this.position())}addAnchor(e,t){let n=m(e);return this.anchorFingerprints.some(i=>m(i)===n)?!1:(this.anchorFingerprints.push(e),t&&this.anchorTargets.push(t),this.callbacks.onAnchorsChanged([...this.anchorFingerprints]),this.renderAnchorList(),this.updateHeader(),!0)}removeAnchor(e){if(this.anchorFingerprints.length<=1)return!1;let t=this.anchorFingerprints.findIndex(n=>m(n)===e);return t<0?!1:(this.anchorFingerprints.splice(t,1),this.anchorTargets.splice(t,1),this.callbacks.onAnchorsChanged([...this.anchorFingerprints]),this.renderAnchorList(),this.updateHeader(),!0)}updateHeader(){let e=this.el.querySelector(".vz-popover-header span:first-child");e&&(e.textContent=this.anchorFingerprints.length>1?`Comment on ${this.anchorFingerprints.length} elements`:"Comment")}reposition(){this.anchorTargets.length&&this.position()}close(){this.el.style.display="none",this.anchorTargets=[],this.anchorFingerprints=[],this.pendingRefs={}}isOpen(){return this.anchorTargets.length>0}getAnchors(){return[...this.anchorFingerprints]}getAnchorTargets(){return[...this.anchorTargets]}render(e){if(!this.anchorTargets.length)return;let t=this.anchorTargets[0],n=Array.from(t.classList).filter(u=>!u.startsWith("vz-")&&!u.startsWith("vizu-")).slice(0,2),i=t.tagName.toLowerCase()+(t.id?"#"+t.id:"")+(n.length?"."+n.join("."):""),r=(t.innerText||"").trim(),o=r.slice(0,60),a=this.currentUser?`<div class="vz-comment-author">${b(this.currentUser)} <span class="vz-comment-author-name">${d(this.currentUser.name)}</span> <span>\xB7 you</span></div>`:"";this.el.innerHTML=`
27
+ `}var B=class{constructor(e,t){this.currentUser=null;this.anchorTargets=[];this.anchorFingerprints=[];this.pendingRefs={};this.pendingAttachments=[];this.handleEditorKey=e=>{let t=e.currentTarget;if(e.key==="#"){e.preventDefault();let n=this.saveRange();this.callbacks.onStartReferencePick(i=>this.insertChip(i,n),()=>{t.focus(),this.restoreRange(n)});return}if(e.key==="Enter"&&(e.metaKey||e.ctrlKey)){e.preventDefault(),this.save();return}e.key==="Escape"&&(e.preventDefault(),this.callbacks.onClose())};this.handleEditorPaste=e=>{if(this.callbacks.canUploadAttachments()){let i=e.clipboardData?.items??null;if(i){let r=[];for(let s=0;s<i.length;s++){let a=i[s];if(a.kind==="file"&&a.type.startsWith("image/")){let l=a.getAsFile();l&&r.push(l)}}if(r.length>0){e.preventDefault();for(let s of r)this.uploadAndAppend(s);return}}}e.preventDefault();let t=e.clipboardData?.getData("text/plain")??"",n=window.getSelection();if(n&&n.rangeCount>0){let i=n.getRangeAt(0);i.deleteContents(),i.insertNode(document.createTextNode(t)),i.collapse(!1),n.removeAllRanges(),n.addRange(i)}};this.handleDragOver=e=>{if(!e.dataTransfer||!Array.from(e.dataTransfer.types).includes("Files"))return;e.preventDefault(),this.el.querySelector('[data-vz="drop-hint"]')?.removeAttribute("hidden")};this.handleDragLeave=e=>{let t=e.currentTarget;if(e.relatedTarget instanceof Node&&t.contains(e.relatedTarget))return;this.el.querySelector('[data-vz="drop-hint"]')?.setAttribute("hidden","")};this.handleDrop=e=>{if(e.preventDefault(),this.el.querySelector('[data-vz="drop-hint"]')?.setAttribute("hidden",""),!e.dataTransfer)return;let n=Array.from(e.dataTransfer.files).filter(i=>i.type.startsWith("image/"));for(let i of n)this.uploadAndAppend(i)};this.handleFileChange=e=>{let t=e.currentTarget,n=t.files?Array.from(t.files):[];for(let i of n)this.uploadAndAppend(i);t.value=""};this.handleClick=e=>{let t=e.target,n=t.closest('[data-vz="remove-anchor"]');if(n){e.stopPropagation();let s=n.getAttribute("data-fp-key");s&&this.removeAnchor(s);return}let i=t.closest('[data-vz="ref"]');if(i){let s=i.getAttribute("data-comment-id"),a=i.getAttribute("data-ref-id");s&&a&&(e.stopPropagation(),this.callbacks.onJumpToReference(s,a));return}let r=t.getAttribute("data-vz");if(r==="close")this.callbacks.onClose();else if(r==="save")this.save();else if(r==="mention")e.preventDefault(),this.insertMentionChip(this.currentUser);else if(r==="upload")e.preventDefault(),this.el.querySelector('[data-vz="file-input"]')?.click();else if(r==="remove-attachment"){e.preventDefault();let s=t.getAttribute("data-attachment-id");s&&(this.pendingAttachments=this.pendingAttachments.filter(a=>a.id!==s),this.renderAttachmentList())}else if(r==="delete"){let s=t.getAttribute("data-id");s&&this.callbacks.onDelete(s)}else if(r==="toggle-reply"){e.preventDefault();let s=t.getAttribute("data-id");if(!s)return;let a=this.el.querySelector(`.vz-replies[data-comment-id="${de(s)}"]`);if(!a)return;a.hasAttribute("hidden")?(a.removeAttribute("hidden"),a.querySelector(".vz-reply-input")?.focus()):a.setAttribute("hidden","")}else if(r==="send-reply"){e.preventDefault();let s=t.getAttribute("data-id");if(!s)return;let a=this.el.querySelector(`.vz-reply-input[data-comment-id="${de(s)}"]`),l=a?.value.trim()??"";if(!l)return;this.callbacks.onAddReply(s,l),a&&(a.value="")}else if(r==="delete-reply"){e.preventDefault();let s=t.getAttribute("data-comment-id"),a=t.getAttribute("data-reply-id");s&&a&&this.callbacks.onDeleteReply(s,a)}};this.root=e,this.callbacks=t,this.el=document.createElement("div"),this.el.className="vz-popover",this.el.style.display="none",this.el.addEventListener("click",this.handleClick),this.root.appendChild(this.el)}setUser(e){this.currentUser=e}open(e,t,n){this.anchorTargets=[...e],this.anchorFingerprints=[...t],this.pendingRefs={},this.render(n),this.position()}update(e){this.anchorTargets.length&&(this.render(e),this.position())}addAnchor(e,t){let n=h(e);return this.anchorFingerprints.some(i=>h(i)===n)?!1:(this.anchorFingerprints.push(e),t&&this.anchorTargets.push(t),this.callbacks.onAnchorsChanged([...this.anchorFingerprints]),this.renderAnchorList(),this.updateHeader(),!0)}removeAnchor(e){if(this.anchorFingerprints.length<=1)return!1;let t=this.anchorFingerprints.findIndex(n=>h(n)===e);return t<0?!1:(this.anchorFingerprints.splice(t,1),this.anchorTargets.splice(t,1),this.callbacks.onAnchorsChanged([...this.anchorFingerprints]),this.renderAnchorList(),this.updateHeader(),!0)}updateHeader(){let e=this.el.querySelector(".vz-popover-header span:first-child");e&&(e.textContent=this.anchorFingerprints.length>1?`Comment on ${this.anchorFingerprints.length} elements`:"Comment")}reposition(){this.anchorTargets.length&&this.position()}close(){this.el.style.display="none",this.anchorTargets=[],this.anchorFingerprints=[],this.pendingRefs={}}isOpen(){return this.anchorTargets.length>0}getAnchors(){return[...this.anchorFingerprints]}getAnchorTargets(){return[...this.anchorTargets]}render(e){if(!this.anchorTargets.length)return;let t=this.anchorTargets[0],n=Array.from(t.classList).filter(m=>!m.startsWith("vz-")&&!m.startsWith("vizu-")).slice(0,2),i=t.tagName.toLowerCase()+(t.id?"#"+t.id:"")+(n.length?"."+n.join("."):""),r=(t.innerText||"").trim(),s=r.slice(0,60),a=this.currentUser?`<div class="vz-comment-author">${b(this.currentUser)} <span class="vz-comment-author-name">${d(this.currentUser.name)}</span> <span>\xB7 you</span></div>`:"";this.el.innerHTML=`
207
28
  <div class="vz-popover-header">
208
29
  <span>${this.anchorFingerprints.length>1?`Comment on ${this.anchorFingerprints.length} elements`:"Comment"}</span>
209
30
  <button class="vz-popover-close" data-vz="close" aria-label="Close">\xD7</button>
210
31
  </div>
211
- <div class="vz-target-label">${d(i)}${o?" \xB7 &ldquo;"+d(o)+(r.length>60?"\u2026":"")+"&rdquo;":""}</div>
32
+ <div class="vz-target-label">${d(i)}${s?" \xB7 &ldquo;"+d(s)+(r.length>60?"\u2026":"")+"&rdquo;":""}</div>
212
33
  <div class="vz-anchor-list-wrap"></div>
213
34
  <div class="vz-comment-list">
214
- ${e.length===0?'<div class="vz-empty">No comments yet.</div>':e.map(u=>`
215
- <div class="vz-comment" data-comment-id="${d(u.id)}">
216
- ${u.author?`<div class="vz-comment-author">${b(u.author)} <span class="vz-comment-author-name">${d(u.author.name)}</span></div>`:""}
217
- <div>${U(u.text,u.id)}</div>
218
- ${H(u.attachments)}
35
+ ${e.length===0?'<div class="vz-empty">No comments yet.</div>':e.map(m=>`
36
+ <div class="vz-comment" data-comment-id="${d(m.id)}">
37
+ ${m.author?`<div class="vz-comment-author">${b(m.author)} <span class="vz-comment-author-name">${d(m.author.name)}</span></div>`:""}
38
+ <div>${P(m.text,m.id)}</div>
39
+ ${$(m.attachments)}
219
40
  <div class="vz-comment-meta">
220
- <span>${d(A(u.createdAt))}</span>
41
+ <span>${d(E(m.createdAt))}</span>
221
42
  <span class="vz-comment-actions">
222
- <button class="vz-comment-reply-toggle" data-vz="toggle-reply" data-id="${d(u.id)}">${(u.replies?.length??0)>0?`${u.replies.length} ${u.replies.length===1?"reply":"replies"}`:"reply"}</button>
223
- <button class="vz-comment-delete" data-vz="delete" data-id="${d(u.id)}">delete</button>
43
+ <button class="vz-comment-reply-toggle" data-vz="toggle-reply" data-id="${d(m.id)}">${(m.replies?.length??0)>0?`${m.replies.length} ${m.replies.length===1?"reply":"replies"}`:"reply"}</button>
44
+ <button class="vz-comment-delete" data-vz="delete" data-id="${d(m.id)}">delete</button>
224
45
  </span>
225
46
  </div>
226
- ${at(u)}
47
+ ${Ue(m)}
227
48
  </div>
228
49
  `).join("")}
229
50
  </div>
@@ -240,24 +61,24 @@
240
61
  <button class="vz-btn vz-btn-primary" data-vz="save">Save</button>
241
62
  </div>
242
63
  <input type="file" class="vz-file-input" data-vz="file-input" accept="image/png,image/jpeg,image/webp,image/gif,image/svg+xml" hidden />
243
- `,this.el.style.display="flex",this.renderAnchorList(),this.renderAttachmentList();let l=this.el.querySelector(".vz-textarea");l.focus(),l.addEventListener("keydown",this.handleEditorKey),l.addEventListener("paste",this.handleEditorPaste);let c=this.el.querySelector(".vz-editor-wrap");c&&this.callbacks.canUploadAttachments()&&(c.addEventListener("dragover",this.handleDragOver),c.addEventListener("dragleave",this.handleDragLeave),c.addEventListener("drop",this.handleDrop));let p=this.el.querySelector('[data-vz="file-input"]');p&&p.addEventListener("change",this.handleFileChange)}renderAnchorList(){let e=this.el.querySelector(".vz-anchor-list-wrap");if(!e)return;if(this.anchorFingerprints.length<=1){e.innerHTML="";return}let t=this.anchorFingerprints.map(n=>{let i=m(n),r=V(n);return`<span class="vz-anchor-chip" data-fp-key="${d(i)}">${d(r)}<button class="vz-anchor-chip-remove" data-vz="remove-anchor" data-fp-key="${d(i)}" aria-label="Remove anchor">\xD7</button></span>`}).join("");e.innerHTML=`
64
+ `,this.el.style.display="flex",this.renderAnchorList(),this.renderAttachmentList();let l=this.el.querySelector(".vz-textarea");l.focus(),l.addEventListener("keydown",this.handleEditorKey),l.addEventListener("paste",this.handleEditorPaste);let c=this.el.querySelector(".vz-editor-wrap");c&&this.callbacks.canUploadAttachments()&&(c.addEventListener("dragover",this.handleDragOver),c.addEventListener("dragleave",this.handleDragLeave),c.addEventListener("drop",this.handleDrop));let p=this.el.querySelector('[data-vz="file-input"]');p&&p.addEventListener("change",this.handleFileChange)}renderAnchorList(){let e=this.el.querySelector(".vz-anchor-list-wrap");if(!e)return;if(this.anchorFingerprints.length<=1){e.innerHTML="";return}let t=this.anchorFingerprints.map(n=>{let i=h(n),r=L(n);return`<span class="vz-anchor-chip" data-fp-key="${d(i)}">${d(r)}<button class="vz-anchor-chip-remove" data-vz="remove-anchor" data-fp-key="${d(i)}" aria-label="Remove anchor">\xD7</button></span>`}).join("");e.innerHTML=`
244
65
  <div class="vz-anchor-hint">Anchored to ${this.anchorFingerprints.length} elements:</div>
245
66
  <div class="vz-anchor-list">${t}</div>
246
- `}async uploadAndAppend(e){if(!this.callbacks.canUploadAttachments())return;let t="upload-"+Math.random().toString(36).slice(2,9),n={id:t,url:"",mimeType:e.type||"application/octet-stream",sizeBytes:e.size,uploadedAt:Date.now(),filename:e.name};this.pendingAttachments.push(n),this.renderAttachmentList(t);try{let i=await this.callbacks.onUploadAttachment(e),r=this.pendingAttachments.findIndex(o=>o.id===t);r>=0?this.pendingAttachments[r]=i:this.pendingAttachments.push(i),this.renderAttachmentList()}catch(i){this.pendingAttachments=this.pendingAttachments.filter(r=>r.id!==t),this.renderAttachmentList(),typeof console<"u"&&console.warn("[vizu] attachment upload failed",i)}}renderAttachmentList(e){let t=this.el.querySelector('[data-vz="attachment-list"]');if(t){if(this.pendingAttachments.length===0){t.innerHTML="";return}t.innerHTML=this.pendingAttachments.map(n=>{let r=n.id===e||n.url===""?'<div class="vz-attachment-thumb vz-attachment-thumb-loading">\u2026</div>':n.mimeType.startsWith("image/")?`<img class="vz-attachment-thumb" src="${d(n.url)}" alt="${d(n.filename??"")}" />`:'<div class="vz-attachment-thumb">\u{1F4C4}</div>';return`
67
+ `}async uploadAndAppend(e){if(!this.callbacks.canUploadAttachments())return;let t="upload-"+Math.random().toString(36).slice(2,9),n={id:t,url:"",mimeType:e.type||"application/octet-stream",sizeBytes:e.size,uploadedAt:Date.now(),filename:e.name};this.pendingAttachments.push(n),this.renderAttachmentList(t);try{let i=await this.callbacks.onUploadAttachment(e),r=this.pendingAttachments.findIndex(s=>s.id===t);r>=0?this.pendingAttachments[r]=i:this.pendingAttachments.push(i),this.renderAttachmentList()}catch(i){this.pendingAttachments=this.pendingAttachments.filter(r=>r.id!==t),this.renderAttachmentList(),typeof console<"u"&&console.warn("[vizu] attachment upload failed",i)}}renderAttachmentList(e){let t=this.el.querySelector('[data-vz="attachment-list"]');if(t){if(this.pendingAttachments.length===0){t.innerHTML="";return}t.innerHTML=this.pendingAttachments.map(n=>{let r=n.id===e||n.url===""?'<div class="vz-attachment-thumb vz-attachment-thumb-loading">\u2026</div>':n.mimeType.startsWith("image/")?`<img class="vz-attachment-thumb" src="${d(n.url)}" alt="${d(n.filename??"")}" />`:'<div class="vz-attachment-thumb">\u{1F4C4}</div>';return`
247
68
  <div class="vz-attachment-item" data-attachment-id="${d(n.id)}">
248
69
  ${r}
249
70
  <button class="vz-attachment-remove" data-vz="remove-attachment" data-attachment-id="${d(n.id)}" aria-label="Remove attachment">\xD7</button>
250
71
  </div>
251
- `}).join("")}}saveRange(){let e=window.getSelection();return!e||e.rangeCount===0?null:e.getRangeAt(0).cloneRange()}restoreRange(e){if(!e)return;let t=window.getSelection();t?.removeAllRanges(),t?.addRange(e)}insertChip(e,t){let n=ve();this.pendingRefs[n]=e;let i=V(e),r=document.createElement("span");r.className="vz-chip",r.contentEditable="false",r.setAttribute("data-ref-id",n),r.textContent=i;let o=this.el.querySelector(".vz-textarea");o.focus(),this.restoreRange(t);let a=window.getSelection();if(!a||a.rangeCount===0){o.appendChild(r),o.appendChild(document.createTextNode(" ")),this.moveCursorToEnd(o);return}let l=a.getRangeAt(0);l.deleteContents(),l.insertNode(r);let c=document.createTextNode(" ");r.after(c);let p=document.createRange();p.setStartAfter(c),p.collapse(!0),a.removeAllRanges(),a.addRange(p)}moveCursorToEnd(e){let t=document.createRange();t.selectNodeContents(e),t.collapse(!1);let n=window.getSelection();n?.removeAllRanges(),n?.addRange(t)}serializeEditor(e){let t=[],n=i=>{if(i.nodeType===Node.TEXT_NODE){t.push(i.textContent||"");return}if(i.nodeType!==Node.ELEMENT_NODE)return;let r=i;if(r.classList.contains("vz-chip")){let o=r.getAttribute("data-mention-id");if(o){let c=r.textContent||"",p=c.startsWith("@")?c.slice(1):c;t.push(`[@${p}](vizu-mention:${o})`);return}let a=r.getAttribute("data-ref-id"),l=r.textContent||"";a&&t.push(`[#${l}](vizu-ref:${a})`);return}if(r.tagName==="BR"){t.push(`
72
+ `}).join("")}}saveRange(){let e=window.getSelection();return!e||e.rangeCount===0?null:e.getRangeAt(0).cloneRange()}restoreRange(e){if(!e)return;let t=window.getSelection();t?.removeAllRanges(),t?.addRange(e)}insertChip(e,t){let n=ne();this.pendingRefs[n]=e;let i=L(e),r=document.createElement("span");r.className="vz-chip",r.contentEditable="false",r.setAttribute("data-ref-id",n),r.textContent=i;let s=this.el.querySelector(".vz-textarea");s.focus(),this.restoreRange(t);let a=window.getSelection();if(!a||a.rangeCount===0){s.appendChild(r),s.appendChild(document.createTextNode(" ")),this.moveCursorToEnd(s);return}let l=a.getRangeAt(0);l.deleteContents(),l.insertNode(r);let c=document.createTextNode(" ");r.after(c);let p=document.createRange();p.setStartAfter(c),p.collapse(!0),a.removeAllRanges(),a.addRange(p)}moveCursorToEnd(e){let t=document.createRange();t.selectNodeContents(e),t.collapse(!1);let n=window.getSelection();n?.removeAllRanges(),n?.addRange(t)}serializeEditor(e){let t=[],n=i=>{if(i.nodeType===Node.TEXT_NODE){t.push(i.textContent||"");return}if(i.nodeType!==Node.ELEMENT_NODE)return;let r=i;if(r.classList.contains("vz-chip")){let s=r.getAttribute("data-mention-id");if(s){let c=r.textContent||"",p=c.startsWith("@")?c.slice(1):c;t.push(`[@${p}](vizu-mention:${s})`);return}let a=r.getAttribute("data-ref-id"),l=r.textContent||"";a&&t.push(`[#${l}](vizu-ref:${a})`);return}if(r.tagName==="BR"){t.push(`
252
73
  `);return}r.tagName==="DIV"&&t.length&&!t[t.length-1].endsWith(`
253
74
  `)&&t.push(`
254
- `);for(let o of r.childNodes)n(o)};for(let i of e.childNodes)n(i);return t.join("").trim()}insertMentionChip(e){if(!e||!e.id)return;let t=this.el.querySelector(".vz-textarea");if(!t)return;let n=document.createElement("span");n.className="vz-chip vz-chip-mention",n.contentEditable="false",n.setAttribute("data-mention-id",e.id),n.textContent="@"+e.name,t.focus();let i=window.getSelection();if(!i||i.rangeCount===0){t.appendChild(n),t.appendChild(document.createTextNode(" ")),this.moveCursorToEnd(t);return}let r=i.getRangeAt(0);r.deleteContents(),r.insertNode(n);let o=document.createTextNode(" ");n.after(o);let a=document.createRange();a.setStartAfter(o),a.collapse(!0),i.removeAllRanges(),i.addRange(a)}save(){let e=this.el.querySelector(".vz-textarea");if(!e)return;let t=this.serializeEditor(e),n=this.pendingAttachments.filter(c=>c.url).length;if(!t&&n===0)return;let i={},r=/\[#[^\]]+\]\(vizu-ref:([a-zA-Z0-9_-]+)\)/g,o;for(;(o=r.exec(t))!==null;){let c=o[1];this.pendingRefs[c]&&(i[c]=this.pendingRefs[c])}let a=fe(t),l=this.pendingAttachments.filter(c=>c.url);this.callbacks.onAdd(t,[...this.anchorFingerprints],Object.keys(i).length?i:void 0,a.length?a:void 0,l.length?l:void 0),e.innerHTML="",this.pendingRefs={},this.pendingAttachments=[],this.renderAttachmentList()}position(){let e=this.anchorTargets[0];if(!e)return;let t=e.getBoundingClientRect(),n=this.el.getBoundingClientRect(),i=8,r=t.bottom+i,o=t.left;r+n.height>window.innerHeight-i&&(r=t.top-n.height-i,r<i&&(r=i)),o+n.width>window.innerWidth-i&&(o=window.innerWidth-n.width-i),o<i&&(o=i),this.el.style.top=r+"px",this.el.style.left=o+"px"}destroy(){this.el.removeEventListener("click",this.handleClick),this.el.remove()}};var X=class{constructor(e,t){this.sidebarOpen=!1;this.actions=[];this.commentsCount=0;this.user=null;this.multiSelectMode=!1;this.selectionCount=0;this.handleClick=e=>{let t=e.target.closest("[data-vz]");if(!t)return;let n=t.getAttribute("data-vz");if(n==="sidebar")this.callbacks.onToggleSidebar();else if(n==="disable")this.callbacks.onDisable();else if(n==="multi")this.callbacks.onToggleMultiSelect();else if(n==="commit-selection")this.callbacks.onCommitSelection();else if(n==="clear-selection")this.callbacks.onClearSelection();else if(n==="action"){let i=t.getAttribute("data-id");i&&this.callbacks.onAction(i)}};this.root=e,this.callbacks=t,this.el=document.createElement("div"),this.el.className="vz-pill",this.el.style.display="none",this.el.addEventListener("click",this.handleClick),this.root.appendChild(this.el)}setActions(e){this.actions=e,this.render()}setComments(e){this.commentsCount=e.length,this.render()}setUser(e){this.user=e,this.render()}setSidebarOpen(e){this.sidebarOpen=e;let t=this.el.querySelector('[data-vz="sidebar"]');t&&t.classList.toggle("is-active",e)}setMultiSelectState(e,t){this.multiSelectMode=e,this.selectionCount=t,this.el.classList.toggle("is-selecting",e&&t>0),this.render()}show(){this.el.style.display="flex",this.render()}hide(){this.el.style.display="none"}render(){if(this.el.style.display==="none")return;let e=this.actions.filter(o=>o.visibleWhen?o.visibleWhen({commentsCount:this.commentsCount}):!0),t=this.user?`<div class="vz-pill-user" title="${d(this.user.name)}">${b(this.user,"vz-pill-user-avatar")} ${d(this.user.name.split(" ")[0])}</div><span class="vz-pill-divider"></span>`:"",n=e.length?e.map(o=>`<button class="vz-pill-btn${o.variant==="primary"?" primary":""}" data-vz="action" data-id="${d(o.id)}"${o.title?` title="${d(o.title)}"`:""}>${d(o.label)}</button>`).join("")+'<span class="vz-pill-divider"></span>':"",i="";if(this.multiSelectMode&&this.selectionCount>0)i=`
75
+ `);for(let s of r.childNodes)n(s)};for(let i of e.childNodes)n(i);return t.join("").trim()}insertMentionChip(e){if(!e||!e.id)return;let t=this.el.querySelector(".vz-textarea");if(!t)return;let n=document.createElement("span");n.className="vz-chip vz-chip-mention",n.contentEditable="false",n.setAttribute("data-mention-id",e.id),n.textContent="@"+e.name,t.focus();let i=window.getSelection();if(!i||i.rangeCount===0){t.appendChild(n),t.appendChild(document.createTextNode(" ")),this.moveCursorToEnd(t);return}let r=i.getRangeAt(0);r.deleteContents(),r.insertNode(n);let s=document.createTextNode(" ");n.after(s);let a=document.createRange();a.setStartAfter(s),a.collapse(!0),i.removeAllRanges(),i.addRange(a)}save(){let e=this.el.querySelector(".vz-textarea");if(!e)return;let t=this.serializeEditor(e),n=this.pendingAttachments.filter(c=>c.url).length;if(!t&&n===0)return;let i={},r=/\[#[^\]]+\]\(vizu-ref:([a-zA-Z0-9_-]+)\)/g,s;for(;(s=r.exec(t))!==null;){let c=s[1];this.pendingRefs[c]&&(i[c]=this.pendingRefs[c])}let a=ie(t),l=this.pendingAttachments.filter(c=>c.url);this.callbacks.onAdd(t,[...this.anchorFingerprints],Object.keys(i).length?i:void 0,a.length?a:void 0,l.length?l:void 0),e.innerHTML="",this.pendingRefs={},this.pendingAttachments=[],this.renderAttachmentList()}position(){let e=this.anchorTargets[0];if(!e)return;let t=e.getBoundingClientRect(),n=this.el.getBoundingClientRect(),i=8,r=t.bottom+i,s=t.left;r+n.height>window.innerHeight-i&&(r=t.top-n.height-i,r<i&&(r=i)),s+n.width>window.innerWidth-i&&(s=window.innerWidth-n.width-i),s<i&&(s=i),this.el.style.top=r+"px",this.el.style.left=s+"px"}destroy(){this.el.removeEventListener("click",this.handleClick),this.el.remove()}};var K=class{constructor(e,t){this.sidebarOpen=!1;this.actions=[];this.commentsCount=0;this.user=null;this.multiSelectMode=!1;this.selectionCount=0;this.handleClick=e=>{let t=e.target.closest("[data-vz]");if(!t)return;let n=t.getAttribute("data-vz");if(n==="sidebar")this.callbacks.onToggleSidebar();else if(n==="disable")this.callbacks.onDisable();else if(n==="multi")this.callbacks.onToggleMultiSelect();else if(n==="commit-selection")this.callbacks.onCommitSelection();else if(n==="clear-selection")this.callbacks.onClearSelection();else if(n==="action"){let i=t.getAttribute("data-id");i&&this.callbacks.onAction(i)}};this.root=e,this.callbacks=t,this.el=document.createElement("div"),this.el.className="vz-pill",this.el.style.display="none",this.el.addEventListener("click",this.handleClick),this.root.appendChild(this.el)}setActions(e){this.actions=e,this.render()}setComments(e){this.commentsCount=e.length,this.render()}setUser(e){this.user=e,this.render()}setSidebarOpen(e){this.sidebarOpen=e;let t=this.el.querySelector('[data-vz="sidebar"]');t&&t.classList.toggle("is-active",e)}setMultiSelectState(e,t){this.multiSelectMode=e,this.selectionCount=t,this.el.classList.toggle("is-selecting",e&&t>0),this.render()}show(){this.el.style.display="flex",this.render()}hide(){this.el.style.display="none"}render(){if(this.el.style.display==="none")return;let e=this.actions.filter(s=>s.visibleWhen?s.visibleWhen({commentsCount:this.commentsCount}):!0),t=this.user?`<div class="vz-pill-user" title="${d(this.user.name)}">${b(this.user,"vz-pill-user-avatar")} ${d(this.user.name.split(" ")[0])}</div><span class="vz-pill-divider"></span>`:"",n=e.length?e.map(s=>`<button class="vz-pill-btn${s.variant==="primary"?" primary":""}" data-vz="action" data-id="${d(s.id)}"${s.title?` title="${d(s.title)}"`:""}>${d(s.label)}</button>`).join("")+'<span class="vz-pill-divider"></span>':"",i="";if(this.multiSelectMode&&this.selectionCount>0)i=`
255
76
  <span class="vz-pill-count-btn is-active" title="Selected ${this.selectionCount} element${this.selectionCount===1?"":"s"}">${this.selectionCount} selected</span>
256
77
  <button class="vz-pill-btn primary" data-vz="commit-selection">Comment on ${this.selectionCount} \u2192</button>
257
78
  <button class="vz-pill-btn" data-vz="clear-selection">Cancel</button>
258
79
  <span class="vz-pill-divider"></span>
259
- `;else{let o=this.commentsCount;i=`
260
- <button class="vz-pill-count-btn ${this.sidebarOpen?"is-active":""}" data-vz="sidebar" title="Show all comments">${o} comment${o===1?"":"s"}</button>
80
+ `;else{let s=this.commentsCount;i=`
81
+ <button class="vz-pill-count-btn ${this.sidebarOpen?"is-active":""}" data-vz="sidebar" title="Show all comments">${s} comment${s===1?"":"s"}</button>
261
82
  <span class="vz-pill-divider"></span>
262
83
  ${t}
263
84
  ${n}
@@ -269,44 +90,44 @@
269
90
  <svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="1" y="1" width="5" height="5"/><rect x="8" y="1" width="5" height="5"/><rect x="1" y="8" width="5" height="5"/><rect x="8" y="8" width="5" height="5"/></svg>
270
91
  </button>
271
92
  <button class="vz-pill-icon-btn" data-vz="disable" title="Disable Vizu (toggle with shortcut)" aria-label="Disable">\xD7</button>
272
- `}toast(e){let t=document.createElement("div");t.className="vz-toast",t.textContent=e,this.root.appendChild(t),setTimeout(()=>t.remove(),1800)}destroy(){this.el.removeEventListener("click",this.handleClick),this.el.remove()}};$();var Y=class{constructor(e,t){this.open=!1;this.filter="open";this.lastComments=[];this.lastConfidence=new Map;this.handleClick=e=>{let t=e.target,n=t.closest('[data-vz="ref"]');if(n){e.stopPropagation();let c=n.getAttribute("data-comment-id"),p=n.getAttribute("data-ref-id");c&&p&&this.callbacks.onJumpToReference(c,p);return}let i=t.closest('[data-vz="filter"]');if(i){e.stopPropagation();let c=i.getAttribute("data-filter");c&&c!==this.filter&&(this.filter=c,this.render(this.lastComments));return}let r=t.closest('[data-vz="status"]');if(r){e.stopPropagation();let c=r.getAttribute("data-id"),p=r.getAttribute("data-status");c&&p&&this.callbacks.onUpdateStatus(c,p);return}let o=t.closest('[data-vz="delete"]');if(o){e.stopPropagation();let c=o.getAttribute("data-id");c&&this.callbacks.onDelete(c);return}if(t.closest('[data-vz="close"]')){this.callbacks.onClose();return}let a=t.closest('[data-vz="jump-fp"]');if(a&&a.__fp){e.stopPropagation(),this.callbacks.onJumpTo(a.__fp);return}let l=t.closest('[data-vz="jump"]');l&&l.__group&&this.callbacks.onJumpTo(l.__group.fp)};this.root=e,this.callbacks=t,this.el=document.createElement("div"),this.el.className="vz-sidebar",this.el.addEventListener("click",this.handleClick),this.root.appendChild(this.el)}toggle(e,t){this.open?this.close():this.show(e,t)}show(e,t){this.render(e,t),requestAnimationFrame(()=>this.el.classList.add("is-open")),this.open=!0}update(e,t){this.open&&this.render(e,t)}close(){this.el.classList.remove("is-open"),this.open=!1}isOpen(){return this.open}render(e,t){this.lastComments=e,t&&(this.lastConfidence=new Map(t));let n=this.lastConfidence,i=e.filter(h=>n.get(h.id)==="orphaned"),r=e.filter(h=>n.get(h.id)!=="orphaned"),o=this.filter==="open"?r.filter(h=>(h.status??"open")==="open"):r,a=this.filter==="open"?[]:i,l=lt(e);if(o.length===0&&a.length===0){let h=this.filter==="open"&&e.length>0?`<strong>Nothing open.</strong>${l.resolved+l.wontfix} closed comment${l.resolved+l.wontfix===1?"":"s"} hidden. Switch to <em>All</em> to see them.`:"<strong>No comments yet</strong>Click any element on the page to leave one.";this.el.innerHTML=`
93
+ `}toast(e){let t=document.createElement("div");t.className="vz-toast",t.textContent=e,this.root.appendChild(t),setTimeout(()=>t.remove(),1800)}destroy(){this.el.removeEventListener("click",this.handleClick),this.el.remove()}};var J=class{constructor(e,t){this.open=!1;this.filter="open";this.lastComments=[];this.lastConfidence=new Map;this.handleClick=e=>{let t=e.target,n=t.closest('[data-vz="ref"]');if(n){e.stopPropagation();let c=n.getAttribute("data-comment-id"),p=n.getAttribute("data-ref-id");c&&p&&this.callbacks.onJumpToReference(c,p);return}let i=t.closest('[data-vz="filter"]');if(i){e.stopPropagation();let c=i.getAttribute("data-filter");c&&c!==this.filter&&(this.filter=c,this.render(this.lastComments));return}let r=t.closest('[data-vz="status"]');if(r){e.stopPropagation();let c=r.getAttribute("data-id"),p=r.getAttribute("data-status");c&&p&&this.callbacks.onUpdateStatus(c,p);return}let s=t.closest('[data-vz="delete"]');if(s){e.stopPropagation();let c=s.getAttribute("data-id");c&&this.callbacks.onDelete(c);return}if(t.closest('[data-vz="close"]')){this.callbacks.onClose();return}let a=t.closest('[data-vz="jump-fp"]');if(a&&a.__fp){e.stopPropagation(),this.callbacks.onJumpTo(a.__fp);return}let l=t.closest('[data-vz="jump"]');l&&l.__group&&this.callbacks.onJumpTo(l.__group.fp)};this.root=e,this.callbacks=t,this.el=document.createElement("div"),this.el.className="vz-sidebar",this.el.addEventListener("click",this.handleClick),this.root.appendChild(this.el)}toggle(e,t){this.open?this.close():this.show(e,t)}show(e,t){this.render(e,t),requestAnimationFrame(()=>this.el.classList.add("is-open")),this.open=!0}update(e,t){this.open&&this.render(e,t)}close(){this.el.classList.remove("is-open"),this.open=!1}isOpen(){return this.open}render(e,t){this.lastComments=e,t&&(this.lastConfidence=new Map(t));let n=this.lastConfidence,i=e.filter(u=>n.get(u.id)==="orphaned"),r=e.filter(u=>n.get(u.id)!=="orphaned"),s=this.filter==="open"?r.filter(u=>(u.status??"open")==="open"):r,a=this.filter==="open"?[]:i,l=_e(e);if(s.length===0&&a.length===0){let u=this.filter==="open"&&e.length>0?`<strong>Nothing open.</strong>${l.resolved+l.wontfix} closed comment${l.resolved+l.wontfix===1?"":"s"} hidden. Switch to <em>All</em> to see them.`:"<strong>No comments yet</strong>Click any element on the page to leave one.";this.el.innerHTML=`
273
94
  ${this.headerHtml(e.length,l)}
274
95
  <div class="vz-sidebar-body">
275
- <div class="vz-sidebar-empty">${h}</div>
96
+ <div class="vz-sidebar-empty">${u}</div>
276
97
  </div>
277
- `;return}let c=new Map;for(let h of o){let y=(h.fingerprints||[])[0];if(!y)continue;let v=m(y),z=c.get(v);z?z.comments.push(h):c.set(v,{fp:y,comments:[h]})}let p=[],u=0;for(let h of c.values()){let k=h.fp.tagName.toLowerCase()+(h.fp.attributes.id?"#"+h.fp.attributes.id:""),y=h.fp.textSnippet.slice(0,60);p.push(`
278
- <div class="vz-sidebar-group" data-group="${u}">
98
+ `;return}let c=new Map;for(let u of s){let x=(u.fingerprints||[])[0];if(!x)continue;let g=h(x),y=c.get(g);y?y.comments.push(u):c.set(g,{fp:x,comments:[u]})}let p=[],m=0;for(let u of c.values()){let A=u.fp.tagName.toLowerCase()+(u.fp.attributes.id?"#"+u.fp.attributes.id:""),x=u.fp.textSnippet.slice(0,60);p.push(`
99
+ <div class="vz-sidebar-group" data-group="${m}">
279
100
  <div class="vz-sidebar-group-head">
280
- ${d(k)}
281
- ${y?`<div class="vz-sidebar-group-text">&ldquo;${d(y)}${h.fp.textSnippet.length>60?"\u2026":""}&rdquo;</div>`:""}
101
+ ${d(A)}
102
+ ${x?`<div class="vz-sidebar-group-text">&ldquo;${d(x)}${u.fp.textSnippet.length>60?"\u2026":""}&rdquo;</div>`:""}
282
103
  </div>
283
- ${h.comments.map(v=>{let z=v.status??"open",ue=(v.fingerprints||[]).slice(1),Ue=ue.length?`<div class="vz-anchor-list" style="margin-top:6px">${ue.map((he,De)=>`<span class="vz-anchor-chip" data-vz="jump-fp" data-fp-key="${d(m(he))}" title="Jump to this element">+${De+2}/${(v.fingerprints||[]).length} ${d(V(he))}</span>`).join("")}</div>`:"",He=n.get(v.id)==="drifted"?'<span class="vz-status-pill vz-status-drifted" title="Anchored via a fallback match \u2014 the original element may have moved or changed.">drifted</span>':"";return`
284
- <div class="vz-sidebar-item ${z!=="open"?"vz-sidebar-item-dim":""}" data-comment-id="${d(v.id)}" data-vz="jump" data-group="${u}" role="button" tabindex="0">
104
+ ${u.comments.map(g=>{let y=g.status??"open",ee=(g.fingerprints||[]).slice(1),ge=ee.length?`<div class="vz-anchor-list" style="margin-top:6px">${ee.map((te,fe)=>`<span class="vz-anchor-chip" data-vz="jump-fp" data-fp-key="${d(h(te))}" title="Jump to this element">+${fe+2}/${(g.fingerprints||[]).length} ${d(L(te))}</span>`).join("")}</div>`:"",ve=n.get(g.id)==="drifted"?'<span class="vz-status-pill vz-status-drifted" title="Anchored via a fallback match \u2014 the original element may have moved or changed.">drifted</span>':"";return`
105
+ <div class="vz-sidebar-item ${y!=="open"?"vz-sidebar-item-dim":""}" data-comment-id="${d(g.id)}" data-vz="jump" data-group="${m}" role="button" tabindex="0">
285
106
  <div class="vz-sidebar-item-row">
286
- ${v.author?`<div class="vz-sidebar-item-author">${b(v.author)} <span class="vz-sidebar-item-author-name">${d(v.author.name)}</span></div>`:""}
287
- ${He}
288
- ${z!=="open"?`<span class="vz-status-pill vz-status-${z}">${z}</span>`:""}
107
+ ${g.author?`<div class="vz-sidebar-item-author">${b(g.author)} <span class="vz-sidebar-item-author-name">${d(g.author.name)}</span></div>`:""}
108
+ ${ve}
109
+ ${y!=="open"?`<span class="vz-status-pill vz-status-${y}">${y}</span>`:""}
289
110
  </div>
290
- <span class="vz-sidebar-item-text">${U(v.text,v.id)}</span>
291
- ${H(v.attachments)}
292
- ${Ue}
111
+ <span class="vz-sidebar-item-text">${P(g.text,g.id)}</span>
112
+ ${$(g.attachments)}
113
+ ${ge}
293
114
  <div class="vz-sidebar-item-meta">
294
- <span>${d(A(v.createdAt))}${(v.fingerprints||[]).length>1?` \xB7 grouped (${(v.fingerprints||[]).length})`:""}${(v.replies?.length??0)>0?` \xB7 ${v.replies.length} ${v.replies.length===1?"reply":"replies"}`:""}</span>
115
+ <span>${d(E(g.createdAt))}${(g.fingerprints||[]).length>1?` \xB7 grouped (${(g.fingerprints||[]).length})`:""}${(g.replies?.length??0)>0?` \xB7 ${g.replies.length} ${g.replies.length===1?"reply":"replies"}`:""}</span>
295
116
  <span class="vz-sidebar-item-actions">
296
- ${ct(v.id,z)}
297
- <button class="vz-sidebar-item-delete" data-vz="delete" data-id="${d(v.id)}" title="Delete comment">delete</button>
117
+ ${Ne(g.id,y)}
118
+ <button class="vz-sidebar-item-delete" data-vz="delete" data-id="${d(g.id)}" title="Delete comment">delete</button>
298
119
  </span>
299
120
  </div>
300
121
  </div>
301
122
  `}).join("")}
302
123
  </div>
303
- `),u++}let N=a.length>0?dt(a):"";this.el.innerHTML=`
124
+ `),m++}let I=a.length>0?De(a):"";this.el.innerHTML=`
304
125
  ${this.headerHtml(e.length,l)}
305
126
  <div class="vz-sidebar-body">
306
127
  ${p.join("")}
307
- ${N}
128
+ ${I}
308
129
  </div>
309
- `;let j=this.el.querySelectorAll('[data-vz="jump"]'),f=[...c.values()];for(let h of j){let k=Number(h.dataset.group);h.__group=f[k]}let g=this.el.querySelectorAll('[data-vz="jump-fp"]');for(let h of g){let k=h.getAttribute("data-fp-key"),y=pt(o,k||"");h.__fp=y}}headerHtml(e,t){return`
130
+ `;let U=this.el.querySelectorAll('[data-vz="jump"]'),v=[...c.values()];for(let u of U){let A=Number(u.dataset.group);u.__group=v[A]}let f=this.el.querySelectorAll('[data-vz="jump-fp"]');for(let u of f){let A=u.getAttribute("data-fp-key"),x=je(s,A||"");u.__fp=x}}headerHtml(e,t){return`
310
131
  <div class="vz-sidebar-header">
311
132
  <div class="vz-sidebar-title">
312
133
  Comments
@@ -322,22 +143,22 @@
322
143
  All <span class="vz-sidebar-filter-count">${e}</span>
323
144
  </button>
324
145
  </div>
325
- `}destroy(){this.el.removeEventListener("click",this.handleClick),this.el.remove()}};function lt(s){let e={open:0,resolved:0,wontfix:0};for(let t of s){let n=t.status??"open";e[n]=(e[n]??0)+1}return e}function ct(s,e){let t=d(s);return e==="open"?`
146
+ `}destroy(){this.el.removeEventListener("click",this.handleClick),this.el.remove()}};function _e(o){let e={open:0,resolved:0,wontfix:0};for(let t of o){let n=t.status??"open";e[n]=(e[n]??0)+1}return e}function Ne(o,e){let t=d(o);return e==="open"?`
326
147
  <button class="vz-sidebar-item-status" data-vz="status" data-id="${t}" data-status="resolved" title="Mark resolved">resolve</button>
327
148
  <button class="vz-sidebar-item-status" data-vz="status" data-id="${t}" data-status="wontfix" title="Won't fix">won&apos;t fix</button>
328
- `:`<button class="vz-sidebar-item-status" data-vz="status" data-id="${t}" data-status="open" title="Reopen">reopen</button>`}function dt(s){let e=s.map(t=>{let n=t.status??"open",i=(t.fingerprints||[])[0],r=i?i.tagName.toLowerCase():"comment",o=i?.textSnippet?.slice(0,60)??"";return`
149
+ `:`<button class="vz-sidebar-item-status" data-vz="status" data-id="${t}" data-status="open" title="Reopen">reopen</button>`}function De(o){let e=o.map(t=>{let n=t.status??"open",i=(t.fingerprints||[])[0],r=i?i.tagName.toLowerCase():"comment",s=i?.textSnippet?.slice(0,60)??"";return`
329
150
  <div class="vz-sidebar-item vz-sidebar-item-orphan" data-comment-id="${d(t.id)}">
330
151
  <div class="vz-sidebar-item-row">
331
152
  ${t.author?`<div class="vz-sidebar-item-author">${b(t.author)} <span class="vz-sidebar-item-author-name">${d(t.author.name)}</span></div>`:""}
332
153
  <span class="vz-status-pill vz-status-orphan">orphaned</span>
333
154
  </div>
334
155
  <div class="vz-sidebar-orphan-anchor">
335
- was on <code>${d(r)}</code>${o?` &ldquo;${d(o)}${(i?.textSnippet?.length??0)>60?"\u2026":""}&rdquo;`:""}
156
+ was on <code>${d(r)}</code>${s?` &ldquo;${d(s)}${(i?.textSnippet?.length??0)>60?"\u2026":""}&rdquo;`:""}
336
157
  </div>
337
- <span class="vz-sidebar-item-text">${U(t.text,t.id)}</span>
338
- ${H(t.attachments)}
158
+ <span class="vz-sidebar-item-text">${P(t.text,t.id)}</span>
159
+ ${$(t.attachments)}
339
160
  <div class="vz-sidebar-item-meta">
340
- <span>${d(A(t.createdAt))}${n!=="open"?` \xB7 ${n}`:""}</span>
161
+ <span>${d(E(t.createdAt))}${n!=="open"?` \xB7 ${n}`:""}</span>
341
162
  <span class="vz-sidebar-item-actions">
342
163
  <button class="vz-sidebar-item-delete" data-vz="delete" data-id="${d(t.id)}" title="Delete comment">delete</button>
343
164
  </span>
@@ -346,12 +167,12 @@
346
167
  `}).join("");return`
347
168
  <div class="vz-sidebar-orphans">
348
169
  <div class="vz-sidebar-orphans-head">
349
- Orphaned \xB7 ${s.length}
170
+ Orphaned \xB7 ${o.length}
350
171
  <span class="vz-sidebar-orphans-sub">couldn't find the original element on this page</span>
351
172
  </div>
352
173
  ${e}
353
174
  </div>
354
- `}function pt(s,e){for(let t of s)for(let n of t.fingerprints||[])if(m(n)===e)return n;return null}var ut=`
175
+ `}function je(o,e){for(let t of o)for(let n of t.fingerprints||[])if(h(n)===e)return n;return null}var qe=`
355
176
  [data-vizu-root] {
356
177
  position: fixed; top: 0; left: 0; width: 0; height: 0;
357
178
  z-index: 2147483647;
@@ -1268,12 +1089,12 @@
1268
1089
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
1269
1090
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
1270
1091
  }
1271
- `;function Ee(){if(typeof document>"u"||document.getElementById("vizu-styles"))return;let s=document.createElement("style");s.id="vizu-styles",s.textContent=ut,(document.head||document.documentElement).appendChild(s)}function ke(s){let e=s.toLowerCase().split("+").map(n=>n.trim());return{key:e.pop()||"",mod:e.includes("mod")||e.includes("cmdorctrl"),shift:e.includes("shift"),alt:e.includes("alt")||e.includes("option"),ctrl:e.includes("ctrl")||e.includes("control")}}function Ae(s,e){let t=typeof navigator<"u"&&/Mac|iPhone|iPad/.test(navigator.platform);if(s.key.toLowerCase()!==e.key)return!1;if(e.mod){if(!(t?s.metaKey:s.ctrlKey))return!1}else if(e.ctrl&&!s.ctrlKey)return!1;return!(e.shift!==s.shiftKey||e.alt!==s.altKey)}var Z=class{constructor(){this.listeners=new Map}on(e,t){let n=this.listeners.get(e);return n||(n=new Set,this.listeners.set(e,n)),n.add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){let n=this.listeners.get(e);if(n)for(let i of[...n])try{i(t)}catch(r){console.error("[vizu] event handler error for",e,r)}}clear(){this.listeners.clear()}};$();var pe={shortcut:"mod+shift+e",namespace:"default",accent:"#FF6647"};function Vt(s,e,t,n){return e?(s&&typeof console<"u"&&console.warn("[vizu] Both `cloud` and `storage` set; `cloud` wins. Drop `storage` to silence this."),new L({workspace:e.workspace,apiUrl:e.apiUrl,autoSignIn:e.autoSignIn,onAuthChanged:n})):s?s==="local"?new D:s==="memory"?new _:s==="none"?new q:oe(s)?be(s):s:t==="local"?new D:new _}var E=class{constructor(e={},t="memory"){this.root=null;this.highlighter=null;this.popover=null;this.pill=null;this.sidebar=null;this.markers=new Map;this.outlines=new Map;this.activeAnchorOutlines=new Map;this.spotlights=new Set;this.comments=[];this.resolvedConfidence=new Map;this.selfHealedThisSession=new Set;this.actions=[];this.user=null;this.liveCollab=null;this.enabled=!1;this.rafScheduled=!1;this.bus=new Z;this.picking=null;this.pickingBanner=null;this.multiSelectMode=!1;this.pendingFingerprints=[];this.pendingTargets=[];this.unsubscribeStorage=null;this.onKeyDown=e=>{if(this.picking&&e.key==="Escape"){e.preventDefault(),this.cancelPicking();return}if(this.pendingFingerprints.length>0&&e.key==="Escape"&&!this.popover?.isOpen()){e.preventDefault(),this.clearSelection();return}Ae(e,this.parsedShortcut)&&(e.preventDefault(),this.toggle())};this.scheduleReposition=()=>{this.rafScheduled||(this.rafScheduled=!0,requestAnimationFrame(()=>{this.rafScheduled=!1;for(let[,e]of this.outlines)e.target&&this.positionOutline(e.outline,e.target);for(let[,e]of this.markers)e.target&&this.positionMarker(e.marker,e.target);for(let[,e]of this.activeAnchorOutlines){let t=R(e.fp);t&&this.positionOutline(e.el,t)}for(let e of this.spotlights)e.target&&this.positionOutline(e.el,e.target);this.popover?.reposition()}))};if(this.opts={...e},this.opts.shortcut=e.shortcut??pe.shortcut,this.opts.namespace=e.namespace??pe.namespace,this.opts.accent=e.accent??pe.accent,this.parsedShortcut=ke(this.opts.shortcut),this.storage=Vt(e.storage,e.cloud,t,n=>{n.user&&this.setUser(n.user)}),this.user=e.user??null,e.actions&&(this.actions=[...e.actions]),e.onCommentAdded&&this.bus.on("comment:added",n=>e.onCommentAdded(n.comment)),e.onCommentRemoved&&this.bus.on("comment:removed",n=>e.onCommentRemoved(n.id)),e.cloud){let n=e.cloud,i=(n.apiUrl??"https://vizu.unhingged.com").replace(/\/$/,"");Promise.resolve().then(()=>(Fe(),Ie)).then(({LiveCollab:r})=>{this.liveCollab=new r({workspaceSlug:n.workspace,apiUrl:i,getAuthHeader:async()=>{if(typeof window>"u")return null;try{if(new URL(i).origin===window.location.origin)return null}catch{return null}let o=this.storage;if(o instanceof L){let a=o.getCachedAuthToken();if(a)return{Authorization:`Bearer ${a}`}}return null}}),this.liveCollab.start()})}typeof window<"u"&&(window.addEventListener("keydown",this.onKeyDown),this.loadComments().then(()=>this.subscribeStorage()),e.startEnabled&&this.deferred(()=>this.enable()))}on(e,t){return this.bus.on(e,t)}off(e,t){this.bus.off(e,t)}setUser(e){this.user=e,this.popover?.setUser(e),this.pill?.setUser(e),this.bus.emit("user:changed",{user:e})}getUser(){return this.user}enable(){this.enabled||(this.enabled=!0,this.bus.emit("enabled",{}),this.deferred(()=>this.mount()),this.storage instanceof L&&this.storage.preflightAuth().catch(e=>{e?.code==="auth_canceled"||e?.code==="popup_blocked"||typeof console<"u"&&console.warn("[vizu] preflight auth failed:",e)}))}disable(){this.enabled&&(this.enabled=!1,this.unmount(),this.bus.emit("disabled",{}))}toggle(){this.enabled?this.disable():this.enable()}isEnabled(){return this.enabled}destroy(){this.disable(),typeof window<"u"&&window.removeEventListener("keydown",this.onKeyDown),this.unsubscribeStorage?.(),this.unsubscribeStorage=null,this.selfHealedThisSession.clear(),this.liveCollab?.destroy(),this.liveCollab=null,this.bus.clear()}addAction(e){let t=this.actions.findIndex(n=>n.id===e.id);t>=0?this.actions[t]=e:this.actions.push(e),this.pill?.setActions(this.actions)}removeAction(e){this.actions=this.actions.filter(t=>t.id!==e),this.pill?.setActions(this.actions)}getActions(){return[...this.actions]}invokeAction(e){let t=this.actions.find(i=>i.id===e);if(!t)return;let n=this.actionContext();this.bus.emit("action:invoked",{id:e}),t.onClick(n)}getComments(){return[...this.comments]}async setComments(e,t){this.comments=C(e),t?.persist!==!1&&await this.storage.setAll(this.opts.namespace,this.comments),this.bus.emit("comments:set",{comments:this.getComments()}),this.refreshUi()}async updateComment(e,t){let n=this.comments.findIndex(c=>c.id===e);if(n===-1)return null;let{id:i,schemaVersion:r,...o}=t,a={...this.comments[n],...o};this.comments[n]=a;let l=await this.storage.updateComment(this.opts.namespace,e,o);return this.bus.emit("comment:updated",{comment:l??a}),this.refreshUi(),a}getAuthContext(){return this.storage.getAuthContext?.()??null}async selfHealComment(e,t){this.selfHealedThisSession.add(e.id);let n=[],i=!1;for(let a of e.fingerprints||[]){let l=t.get(m(a));if(l?.target){let c=M(l.target);n.push(c),!i&&m(c)!==m(a)&&(i=!0)}else n.push(a)}if(!i)return;let r={fingerprints:n,fingerprintsRefreshedAt:Date.now()},o=this.comments.findIndex(a=>a.id===e.id);o!==-1&&(this.comments[o]={...this.comments[o],...r});try{await this.storage.updateComment(this.opts.namespace,e.id,r)}catch(a){typeof console<"u"&&console.warn("[vizu] self-heal write failed for",e.id,a)}}getCommentConfidence(e){return this.resolvedConfidence.get(e)}getResolvedConfidence(){return new Map(this.resolvedConfidence)}canUploadAttachments(){return typeof this.storage.uploadAttachment=="function"}async uploadAttachment(e){if(!this.storage.uploadAttachment)throw new Error("[vizu] active storage adapter does not support uploadAttachment; only the CloudStorageAdapter does in v1");return this.storage.uploadAttachment(this.opts.namespace,e)}async addReply(e,t,n){let i=this.comments.findIndex(a=>a.id===e);if(i===-1)return null;let r={id:O(),text:t.trim(),createdAt:Date.now(),author:this.user??void 0,authorId:this.user?.id,mentions:n&&n.length?n:void 0};if(!r.text)return null;let o={...this.comments[i],replies:[...this.comments[i].replies??[],r]};if(this.comments[i]=o,this.storage.addReply?await this.storage.addReply(this.opts.namespace,e,r):await this.storage.updateComment(this.opts.namespace,e,{replies:o.replies}),this.bus.emit("comment:updated",{comment:o}),this.refreshUi(),this.popover?.isOpen()){let a=this.popover.getAnchors();a[0]&&this.popover.update(this.commentsForElement(a[0]))}return o}async removeReply(e,t){let n=this.comments.findIndex(o=>o.id===e);if(n===-1)return null;let i=(this.comments[n].replies??[]).filter(o=>o.id!==t);if(i.length===(this.comments[n].replies??[]).length)return null;let r={...this.comments[n],replies:i};if(this.comments[n]=r,this.storage.removeReply?await this.storage.removeReply(this.opts.namespace,e,t):await this.storage.updateComment(this.opts.namespace,e,{replies:i}),this.bus.emit("comment:updated",{comment:r}),this.refreshUi(),this.popover?.isOpen()){let o=this.popover.getAnchors();o[0]&&this.popover.update(this.commentsForElement(o[0]))}return r}async clearAll(){let e=this.comments;this.comments=[],await this.storage.clear(this.opts.namespace),this.bus.emit("comments:cleared",{previous:e}),this.refreshUi(),this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1)}toggleMultiSelectMode(){this.multiSelectMode=!this.multiSelectMode,this.multiSelectMode||this.clearSelection(),this.pill?.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length)}clearSelection(){this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.clearActiveAnchorOutlines(),this.pill?.setMultiSelectState(!1,0)}commitSelection(){if(this.pendingFingerprints.length===0)return;let e=[...this.pendingTargets],t=[...this.pendingFingerprints];this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.pill?.setMultiSelectState(!1,0),(e.find(i=>!!i)??R(t[0]))&&this.openPopoverFor(e.filter(Boolean),t)}getSelection(){return[...this.pendingFingerprints]}async loadComments(){let e=await this.storage.load(this.opts.namespace);this.comments=C(e),ge(e)&&this.storage.setAll(this.opts.namespace,this.comments).catch(()=>{}),this.bus.emit("comments:loaded",{comments:this.getComments()}),this.enabled&&this.refreshUi()}subscribeStorage(){this.unsubscribeStorage||this.storage.subscribe&&(this.unsubscribeStorage=this.storage.subscribe(this.opts.namespace,e=>{if(e.type==="added"){let t=w(e.comment);this.comments.some(n=>n.id===t.id)||(this.comments.push(t),this.bus.emit("comment:added",{comment:t}),this.refreshUi())}else if(e.type==="updated"){let t=this.comments.findIndex(i=>i.id===e.comment.id),n=w(e.comment);t>=0&&(this.comments[t]=n,this.bus.emit("comment:updated",{comment:n}),this.refreshUi())}else if(e.type==="removed"){let t=this.comments.findIndex(n=>n.id===e.id);if(t>=0){let[n]=this.comments.splice(t,1);this.bus.emit("comment:removed",{id:e.id,comment:n}),this.refreshUi()}}else if(e.type==="cleared"){let t=this.comments;this.comments=[],this.bus.emit("comments:cleared",{previous:t}),this.refreshUi()}}))}deferred(e){typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e,{once:!0}):e())}mount(){this.root||(Ee(),this.root=document.createElement("div"),this.root.setAttribute("data-vizu-root",""),this.root.style.setProperty("--vz-accent",this.opts.accent),document.body.appendChild(this.root),this.popover=new W(this.root,{onAdd:(e,t,n,i,r)=>{this.addCommentFromPopover(e,t,n,i,r)},onUploadAttachment:e=>this.uploadAttachment(e),canUploadAttachments:()=>this.canUploadAttachments(),onDelete:e=>{this.removeComment(e)},onAddReply:(e,t)=>{this.addReply(e,t)},onDeleteReply:(e,t)=>{this.removeReply(e,t)},onClose:()=>this.closePopover(),onStartReferencePick:(e,t)=>this.startPicking(e,t),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onAnchorsChanged:e=>this.syncActiveAnchorOutlines(e)}),this.popover.setUser(this.user),this.sidebar=new Y(this.root,{onJumpTo:e=>this.jumpToFingerprint(e),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onDelete:e=>{this.removeComment(e)},onUpdateStatus:(e,t)=>{this.updateComment(e,{status:t})},onClose:()=>this.closeSidebar()}),this.pill=new X(this.root,{onToggleSidebar:()=>this.toggleSidebar(),onDisable:()=>this.disable(),onAction:e=>this.invokeAction(e),onToggleMultiSelect:()=>this.toggleMultiSelectMode(),onCommitSelection:()=>this.commitSelection(),onClearSelection:()=>this.clearSelection()}),this.pill.setActions(this.actions),this.pill.setUser(this.user),this.pill.setComments(this.comments),this.pill.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length),this.pill.show(),this.highlighter=new J(this.root,this.opts.ignoreSelectors??[],(e,t)=>this.onElementClick(e,t),e=>{this.liveCollab&&this.liveCollab.setLocalSelection(e?M(e):null)}),this.highlighter.start(),this.renderAllMarkers(),window.addEventListener("scroll",this.scheduleReposition,!0),window.addEventListener("resize",this.scheduleReposition),this.bus.emit("mounted",{}))}unmount(){window.removeEventListener("scroll",this.scheduleReposition,!0),window.removeEventListener("resize",this.scheduleReposition),this.highlighter?.destroy(),this.popover?.destroy(),this.pill?.destroy(),this.sidebar?.destroy(),this.root?.remove(),this.root=null,this.highlighter=null,this.popover=null,this.pill=null,this.sidebar=null,this.markers.clear(),this.outlines.clear(),this.activeAnchorOutlines.clear();for(let e of this.spotlights)e.el.remove();this.spotlights.clear(),this.pendingFingerprints=[],this.pendingTargets=[],this.bus.emit("unmounted",{})}onElementClick(e,t){if(this.picking){let r=M(e),o=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),o.onSelect(r);return}let n=M(e);if(this.popover?.isOpen()&&t.shiftKey){this.popover.addAnchor(n,e);return}if(!this.popover?.isOpen()&&(this.multiSelectMode||t.shiftKey)){this.addToSelection(n,e);return}this.bus.emit("element:selected",{target:e,fingerprint:n});let i=this.commentsForElement(n);this.openPopoverFor([e],[n],i)}openPopoverFor(e,t,n){if(!this.popover)return;let i=n??this.commentsForElement(t[0]);this.popover.open(e,t,i),this.syncActiveAnchorOutlines(t),this.highlighter?.setPaused(!0)}closePopover(){this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1),this.bus.emit("element:deselected",{})}addToSelection(e,t){let n=m(e);this.pendingFingerprints.some(i=>m(i)===n)?(this.pendingFingerprints=this.pendingFingerprints.filter(i=>m(i)!==n),this.pendingTargets=this.pendingTargets.filter(i=>i!==t)):(this.pendingFingerprints.push(e),this.pendingTargets.push(t)),this.syncActiveAnchorOutlines(this.pendingFingerprints),this.pill?.setMultiSelectState(!0,this.pendingFingerprints.length),this.pendingFingerprints.length>0?this.multiSelectMode=!0:this.multiSelectMode=!1}commentsForElement(e){let t=m(e);return this.comments.filter(n=>(n.fingerprints||[]).some(i=>m(i)===t))}async addCommentFromPopover(e,t,n,i,r){if(t.length===0)return;let o=typeof location<"u"?location.href:void 0,a={id:O(),schemaVersion:2,fingerprints:t,text:e,createdAt:Date.now(),pageVersion:this.opts.pageVersion,pageUrl:o,author:this.user??void 0,authorId:this.user?.id,references:n&&Object.keys(n).length?n:void 0,status:"open",replies:[],attachments:r??[],mentions:i??[]};this.comments.push(a),await this.storage.addComment(this.opts.namespace,a),this.bus.emit("comment:added",{comment:a}),this.popover?.update(this.commentsForElement(t[0])),this.refreshUi()}async removeComment(e){let t=this.comments.find(n=>n.id===e);if(t){if(this.comments=this.comments.filter(n=>n.id!==e),await this.storage.removeComment(this.opts.namespace,e),this.bus.emit("comment:removed",{id:e,comment:t}),this.popover?.isOpen()){let n=this.popover.getAnchors();n[0]&&this.popover.update(this.commentsForElement(n[0]))}this.refreshUi()}}refreshUi(){this.pill?.setComments(this.comments),this.renderAllMarkers(),this.sidebar?.update(this.comments,this.resolvedConfidence)}toggleSidebar(){if(!this.sidebar)return;this.sidebar.isOpen()||this.renderAllMarkers(),this.sidebar.toggle(this.comments,this.resolvedConfidence);let e=this.sidebar.isOpen();this.pill?.setSidebarOpen(e),this.bus.emit(e?"sidebar:opened":"sidebar:closed",{})}closeSidebar(){this.sidebar?.close(),this.pill?.setSidebarOpen(!1),this.bus.emit("sidebar:closed",{})}startPicking(e,t){this.picking&&this.picking.onCancel(),this.picking={onSelect:e,onCancel:t},this.highlighter?.setPaused(!1),this.showPickingBanner()}cancelPicking(){if(!this.picking)return;let e=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),e.onCancel()}showPickingBanner(){this.root&&(this.pickingBanner=document.createElement("div"),this.pickingBanner.className="vz-picking-banner",this.pickingBanner.innerHTML=`
1092
+ `;function pe(){if(typeof document>"u"||document.getElementById("vizu-styles"))return;let o=document.createElement("style");o.id="vizu-styles",o.textContent=qe,(document.head||document.documentElement).appendChild(o)}function me(o){let e=o.toLowerCase().split("+").map(n=>n.trim());return{key:e.pop()||"",mod:e.includes("mod")||e.includes("cmdorctrl"),shift:e.includes("shift"),alt:e.includes("alt")||e.includes("option"),ctrl:e.includes("ctrl")||e.includes("control")}}function ue(o,e){let t=typeof navigator<"u"&&/Mac|iPhone|iPad/.test(navigator.platform);if(o.key.toLowerCase()!==e.key)return!1;if(e.mod){if(!(t?o.metaKey:o.ctrlKey))return!1}else if(e.ctrl&&!o.ctrlKey)return!1;return!(e.shift!==o.shiftKey||e.alt!==o.altKey)}var W=class{constructor(){this.listeners=new Map}on(e,t){let n=this.listeners.get(e);return n||(n=new Set,this.listeners.set(e,n)),n.add(t),()=>this.off(e,t)}off(e,t){this.listeners.get(e)?.delete(t)}emit(e,t){let n=this.listeners.get(e);if(n)for(let i of[...n])try{i(t)}catch(r){console.error("[vizu] event handler error for",e,r)}}clear(){this.listeners.clear()}};var Q={shortcut:"mod+shift+e",namespace:"default",accent:"#FF6647"};function Be(o,e,t,n){return e?(o&&typeof console<"u"&&console.warn("[vizu] Both `cloud` and `storage` set; `cloud` wins. Drop `storage` to silence this."),new M({workspace:e.workspace,apiUrl:e.apiUrl,autoSignIn:e.autoSignIn,onAuthChanged:n})):o?o==="local"?new F:o==="memory"?new H:o==="none"?new N:G(o)?se(o):o:t==="local"?new F:new H}var k=class{constructor(e={},t="memory"){this.root=null;this.highlighter=null;this.popover=null;this.pill=null;this.sidebar=null;this.markers=new Map;this.outlines=new Map;this.activeAnchorOutlines=new Map;this.spotlights=new Set;this.comments=[];this.resolvedConfidence=new Map;this.selfHealedThisSession=new Set;this.actions=[];this.user=null;this.enabled=!1;this.rafScheduled=!1;this.bus=new W;this.picking=null;this.pickingBanner=null;this.multiSelectMode=!1;this.pendingFingerprints=[];this.pendingTargets=[];this.unsubscribeStorage=null;this.onKeyDown=e=>{if(this.picking&&e.key==="Escape"){e.preventDefault(),this.cancelPicking();return}if(this.pendingFingerprints.length>0&&e.key==="Escape"&&!this.popover?.isOpen()){e.preventDefault(),this.clearSelection();return}ue(e,this.parsedShortcut)&&(e.preventDefault(),this.toggle())};this.scheduleReposition=()=>{this.rafScheduled||(this.rafScheduled=!0,requestAnimationFrame(()=>{this.rafScheduled=!1;for(let[,e]of this.outlines)e.target&&this.positionOutline(e.outline,e.target);for(let[,e]of this.markers)e.target&&this.positionMarker(e.marker,e.target);for(let[,e]of this.activeAnchorOutlines){let t=V(e.fp);t&&this.positionOutline(e.el,t)}for(let e of this.spotlights)e.target&&this.positionOutline(e.el,e.target);this.popover?.reposition()}))};this.opts={...e},this.opts.shortcut=e.shortcut??Q.shortcut,this.opts.namespace=e.namespace??Q.namespace,this.opts.accent=e.accent??Q.accent,this.parsedShortcut=me(this.opts.shortcut),this.storage=Be(e.storage,e.cloud,t,n=>{n.user&&this.setUser(n.user)}),this.user=e.user??null,e.actions&&(this.actions=[...e.actions]),e.onCommentAdded&&this.bus.on("comment:added",n=>e.onCommentAdded(n.comment)),e.onCommentRemoved&&this.bus.on("comment:removed",n=>e.onCommentRemoved(n.id)),typeof window<"u"&&(window.addEventListener("keydown",this.onKeyDown),this.loadComments().then(()=>this.subscribeStorage()),e.startEnabled&&this.deferred(()=>this.enable()))}on(e,t){return this.bus.on(e,t)}off(e,t){this.bus.off(e,t)}setUser(e){this.user=e,this.popover?.setUser(e),this.pill?.setUser(e),this.bus.emit("user:changed",{user:e})}getUser(){return this.user}requireUserOrAuth(){return!(this.storage instanceof M)||this.user?!0:(this.storage.preflightAuth().catch(()=>{}),!1)}enable(){this.enabled||(this.enabled=!0,this.bus.emit("enabled",{}),this.deferred(()=>this.mount()),this.storage instanceof M&&this.storage.preflightAuth().catch(e=>{e?.code==="auth_canceled"||e?.code==="popup_blocked"||typeof console<"u"&&console.warn("[vizu] preflight auth failed:",e)}))}disable(){this.enabled&&(this.enabled=!1,this.unmount(),this.bus.emit("disabled",{}))}toggle(){this.enabled?this.disable():this.enable()}isEnabled(){return this.enabled}destroy(){this.disable(),typeof window<"u"&&window.removeEventListener("keydown",this.onKeyDown),this.unsubscribeStorage?.(),this.unsubscribeStorage=null,this.selfHealedThisSession.clear(),this.bus.clear()}addAction(e){let t=this.actions.findIndex(n=>n.id===e.id);t>=0?this.actions[t]=e:this.actions.push(e),this.pill?.setActions(this.actions)}removeAction(e){this.actions=this.actions.filter(t=>t.id!==e),this.pill?.setActions(this.actions)}getActions(){return[...this.actions]}invokeAction(e){let t=this.actions.find(i=>i.id===e);if(!t)return;let n=this.actionContext();this.bus.emit("action:invoked",{id:e}),t.onClick(n)}getComments(){return[...this.comments]}async setComments(e,t){this.comments=w(e),t?.persist!==!1&&await this.storage.setAll(this.opts.namespace,this.comments),this.bus.emit("comments:set",{comments:this.getComments()}),this.refreshUi()}async updateComment(e,t){let n=this.comments.findIndex(c=>c.id===e);if(n===-1)return null;let{id:i,schemaVersion:r,...s}=t,a={...this.comments[n],...s};this.comments[n]=a;let l=await this.storage.updateComment(this.opts.namespace,e,s);return this.bus.emit("comment:updated",{comment:l??a}),this.refreshUi(),a}getAuthContext(){return this.storage.getAuthContext?.()??null}async selfHealComment(e,t){this.selfHealedThisSession.add(e.id);let n=[],i=!1;for(let a of e.fingerprints||[]){let l=t.get(h(a));if(l?.target){let c=O(l.target);n.push(c),!i&&h(c)!==h(a)&&(i=!0)}else n.push(a)}if(!i)return;let r={fingerprints:n,fingerprintsRefreshedAt:Date.now()},s=this.comments.findIndex(a=>a.id===e.id);s!==-1&&(this.comments[s]={...this.comments[s],...r});try{await this.storage.updateComment(this.opts.namespace,e.id,r)}catch(a){typeof console<"u"&&console.warn("[vizu] self-heal write failed for",e.id,a)}}getCommentConfidence(e){return this.resolvedConfidence.get(e)}getResolvedConfidence(){return new Map(this.resolvedConfidence)}canUploadAttachments(){return typeof this.storage.uploadAttachment=="function"}async uploadAttachment(e){if(!this.storage.uploadAttachment)throw new Error("[vizu] active storage adapter does not support uploadAttachment; only the CloudStorageAdapter does in v1");return this.storage.uploadAttachment(this.opts.namespace,e)}async addReply(e,t,n){if(!this.requireUserOrAuth())return null;let i=this.comments.findIndex(a=>a.id===e);if(i===-1)return null;let r={id:R(),text:t.trim(),createdAt:Date.now(),author:this.user??void 0,authorId:this.user?.id,mentions:n&&n.length?n:void 0};if(!r.text)return null;let s={...this.comments[i],replies:[...this.comments[i].replies??[],r]};if(this.comments[i]=s,this.storage.addReply?await this.storage.addReply(this.opts.namespace,e,r):await this.storage.updateComment(this.opts.namespace,e,{replies:s.replies}),this.bus.emit("comment:updated",{comment:s}),this.refreshUi(),this.popover?.isOpen()){let a=this.popover.getAnchors();a[0]&&this.popover.update(this.commentsForElement(a[0]))}return s}async removeReply(e,t){let n=this.comments.findIndex(s=>s.id===e);if(n===-1)return null;let i=(this.comments[n].replies??[]).filter(s=>s.id!==t);if(i.length===(this.comments[n].replies??[]).length)return null;let r={...this.comments[n],replies:i};if(this.comments[n]=r,this.storage.removeReply?await this.storage.removeReply(this.opts.namespace,e,t):await this.storage.updateComment(this.opts.namespace,e,{replies:i}),this.bus.emit("comment:updated",{comment:r}),this.refreshUi(),this.popover?.isOpen()){let s=this.popover.getAnchors();s[0]&&this.popover.update(this.commentsForElement(s[0]))}return r}async clearAll(){let e=this.comments;this.comments=[],await this.storage.clear(this.opts.namespace),this.bus.emit("comments:cleared",{previous:e}),this.refreshUi(),this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1)}toggleMultiSelectMode(){this.requireUserOrAuth()&&(this.multiSelectMode=!this.multiSelectMode,this.multiSelectMode||this.clearSelection(),this.pill?.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length))}clearSelection(){this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.clearActiveAnchorOutlines(),this.pill?.setMultiSelectState(!1,0)}commitSelection(){if(this.pendingFingerprints.length===0)return;let e=[...this.pendingTargets],t=[...this.pendingFingerprints];this.pendingFingerprints=[],this.pendingTargets=[],this.multiSelectMode=!1,this.pill?.setMultiSelectState(!1,0),(e.find(i=>!!i)??V(t[0]))&&this.openPopoverFor(e.filter(Boolean),t)}getSelection(){return[...this.pendingFingerprints]}async loadComments(){let e=await this.storage.load(this.opts.namespace);this.comments=w(e),re(e)&&this.storage.setAll(this.opts.namespace,this.comments).catch(()=>{}),this.bus.emit("comments:loaded",{comments:this.getComments()}),this.enabled&&this.refreshUi()}subscribeStorage(){this.unsubscribeStorage||this.storage.subscribe&&(this.unsubscribeStorage=this.storage.subscribe(this.opts.namespace,e=>{if(e.type==="added"){let t=C(e.comment);this.comments.some(n=>n.id===t.id)||(this.comments.push(t),this.bus.emit("comment:added",{comment:t}),this.refreshUi())}else if(e.type==="updated"){let t=this.comments.findIndex(i=>i.id===e.comment.id),n=C(e.comment);t>=0&&(this.comments[t]=n,this.bus.emit("comment:updated",{comment:n}),this.refreshUi())}else if(e.type==="removed"){let t=this.comments.findIndex(n=>n.id===e.id);if(t>=0){let[n]=this.comments.splice(t,1);this.bus.emit("comment:removed",{id:e.id,comment:n}),this.refreshUi()}}else if(e.type==="cleared"){let t=this.comments;this.comments=[],this.bus.emit("comments:cleared",{previous:t}),this.refreshUi()}}))}deferred(e){typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e,{once:!0}):e())}mount(){this.root||(pe(),this.root=document.createElement("div"),this.root.setAttribute("data-vizu-root",""),this.root.style.setProperty("--vz-accent",this.opts.accent),document.body.appendChild(this.root),this.popover=new B(this.root,{onAdd:(e,t,n,i,r)=>{this.addCommentFromPopover(e,t,n,i,r)},onUploadAttachment:e=>this.uploadAttachment(e),canUploadAttachments:()=>this.canUploadAttachments(),onDelete:e=>{this.removeComment(e)},onAddReply:(e,t)=>{this.addReply(e,t)},onDeleteReply:(e,t)=>{this.removeReply(e,t)},onClose:()=>this.closePopover(),onStartReferencePick:(e,t)=>this.startPicking(e,t),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onAnchorsChanged:e=>this.syncActiveAnchorOutlines(e)}),this.popover.setUser(this.user),this.sidebar=new J(this.root,{onJumpTo:e=>this.jumpToFingerprint(e),onJumpToReference:(e,t)=>this.jumpToReference(e,t),onDelete:e=>{this.removeComment(e)},onUpdateStatus:(e,t)=>{this.updateComment(e,{status:t})},onClose:()=>this.closeSidebar()}),this.pill=new K(this.root,{onToggleSidebar:()=>this.toggleSidebar(),onDisable:()=>this.disable(),onAction:e=>this.invokeAction(e),onToggleMultiSelect:()=>this.toggleMultiSelectMode(),onCommitSelection:()=>this.commitSelection(),onClearSelection:()=>this.clearSelection()}),this.pill.setActions(this.actions),this.pill.setUser(this.user),this.pill.setComments(this.comments),this.pill.setMultiSelectState(this.multiSelectMode,this.pendingFingerprints.length),this.pill.show(),this.highlighter=new q(this.root,this.opts.ignoreSelectors??[],(e,t)=>this.onElementClick(e,t)),this.highlighter.start(),this.renderAllMarkers(),window.addEventListener("scroll",this.scheduleReposition,!0),window.addEventListener("resize",this.scheduleReposition),this.bus.emit("mounted",{}))}unmount(){window.removeEventListener("scroll",this.scheduleReposition,!0),window.removeEventListener("resize",this.scheduleReposition),this.highlighter?.destroy(),this.popover?.destroy(),this.pill?.destroy(),this.sidebar?.destroy(),this.root?.remove(),this.root=null,this.highlighter=null,this.popover=null,this.pill=null,this.sidebar=null,this.markers.clear(),this.outlines.clear(),this.activeAnchorOutlines.clear();for(let e of this.spotlights)e.el.remove();this.spotlights.clear(),this.pendingFingerprints=[],this.pendingTargets=[],this.bus.emit("unmounted",{})}onElementClick(e,t){if(this.picking){let r=O(e),s=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),s.onSelect(r);return}if(!this.requireUserOrAuth())return;let n=O(e);if(this.popover?.isOpen()&&t.shiftKey){this.popover.addAnchor(n,e);return}if(!this.popover?.isOpen()&&(this.multiSelectMode||t.shiftKey)){this.addToSelection(n,e);return}this.bus.emit("element:selected",{target:e,fingerprint:n});let i=this.commentsForElement(n);this.openPopoverFor([e],[n],i)}openPopoverFor(e,t,n){if(!this.popover)return;let i=n??this.commentsForElement(t[0]);this.popover.open(e,t,i),this.syncActiveAnchorOutlines(t),this.highlighter?.setPaused(!0)}closePopover(){this.popover?.close(),this.clearActiveAnchorOutlines(),this.highlighter?.setPaused(!1),this.bus.emit("element:deselected",{})}addToSelection(e,t){let n=h(e);this.pendingFingerprints.some(i=>h(i)===n)?(this.pendingFingerprints=this.pendingFingerprints.filter(i=>h(i)!==n),this.pendingTargets=this.pendingTargets.filter(i=>i!==t)):(this.pendingFingerprints.push(e),this.pendingTargets.push(t)),this.syncActiveAnchorOutlines(this.pendingFingerprints),this.pill?.setMultiSelectState(!0,this.pendingFingerprints.length),this.pendingFingerprints.length>0?this.multiSelectMode=!0:this.multiSelectMode=!1}commentsForElement(e){let t=h(e);return this.comments.filter(n=>(n.fingerprints||[]).some(i=>h(i)===t))}async addCommentFromPopover(e,t,n,i,r){if(!this.requireUserOrAuth()||t.length===0)return;let s=typeof location<"u"?location.href:void 0,a={id:R(),schemaVersion:2,fingerprints:t,text:e,createdAt:Date.now(),pageVersion:this.opts.pageVersion,pageUrl:s,author:this.user??void 0,authorId:this.user?.id,references:n&&Object.keys(n).length?n:void 0,status:"open",replies:[],attachments:r??[],mentions:i??[]};this.comments.push(a),await this.storage.addComment(this.opts.namespace,a),this.bus.emit("comment:added",{comment:a}),this.popover?.update(this.commentsForElement(t[0])),this.refreshUi()}async removeComment(e){let t=this.comments.find(n=>n.id===e);if(t){if(this.comments=this.comments.filter(n=>n.id!==e),await this.storage.removeComment(this.opts.namespace,e),this.bus.emit("comment:removed",{id:e,comment:t}),this.popover?.isOpen()){let n=this.popover.getAnchors();n[0]&&this.popover.update(this.commentsForElement(n[0]))}this.refreshUi()}}refreshUi(){this.pill?.setComments(this.comments),this.renderAllMarkers(),this.sidebar?.update(this.comments,this.resolvedConfidence)}toggleSidebar(){if(!this.sidebar)return;this.sidebar.isOpen()||this.renderAllMarkers(),this.sidebar.toggle(this.comments,this.resolvedConfidence);let e=this.sidebar.isOpen();this.pill?.setSidebarOpen(e),this.bus.emit(e?"sidebar:opened":"sidebar:closed",{})}closeSidebar(){this.sidebar?.close(),this.pill?.setSidebarOpen(!1),this.bus.emit("sidebar:closed",{})}startPicking(e,t){this.picking&&this.picking.onCancel(),this.picking={onSelect:e,onCancel:t},this.highlighter?.setPaused(!1),this.showPickingBanner()}cancelPicking(){if(!this.picking)return;let e=this.picking;this.picking=null,this.hidePickingBanner(),this.highlighter?.setPaused(this.popover?.isOpen()??!1),e.onCancel()}showPickingBanner(){this.root&&(this.pickingBanner=document.createElement("div"),this.pickingBanner.className="vz-picking-banner",this.pickingBanner.innerHTML=`
1272
1093
  <span>Click any element to reference</span>
1273
1094
  <span class="vz-picking-banner-hint">or press <span class="vz-picking-banner-kbd">Esc</span></span>
1274
1095
  <button class="vz-picking-banner-cancel" data-vz="cancel-pick">Cancel</button>
1275
- `,this.pickingBanner.addEventListener("click",e=>{e.target.closest('[data-vz="cancel-pick"]')&&this.cancelPicking()}),this.root.appendChild(this.pickingBanner))}hidePickingBanner(){this.pickingBanner?.remove(),this.pickingBanner=null}jumpToReference(e,t){let i=this.comments.find(r=>r.id===e)?.references?.[t];i&&this.jumpToFingerprint(i)}jumpToFingerprint(e){let t=R(e);if(!t){this.pill?.toast("Element not found on this page");return}if(t.scrollIntoView({behavior:"smooth",block:"center"}),this.root){let r=document.createElement("div");r.className="vz-jump-spotlight",this.root.appendChild(r),this.positionOutline(r,t);let o={el:r,target:t};this.spotlights.add(o),setTimeout(()=>{r.remove(),this.spotlights.delete(o)},1800)}let n=m(e),i=this.outlines.get(n)?.outline;i&&setTimeout(()=>{i.classList.remove("is-pulsing"),i.offsetWidth,i.classList.add("is-pulsing"),setTimeout(()=>i.classList.remove("is-pulsing"),1500)},250)}renderAllMarkers(){if(!this.root)return;for(let{marker:r}of this.markers.values())r.remove();for(let{outline:r}of this.outlines.values())r.remove();this.markers.clear(),this.outlines.clear();let e=new Map,t=new Map,n=r=>r==="exact"?3:r==="likely"?2:r==="drifted"?1:0,i=(r,o)=>r===void 0||n(o)>n(r)?o:r;for(let r of this.comments)for(let o of r.fingerprints||[]){let a=m(o),l=e.get(a);if(!l){let c=P(o);l={fp:o,target:c.element,confidence:c.confidence,commentIds:[]},e.set(a,l)}l.commentIds.push(r.id),t.set(r.id,i(t.get(r.id),l.confidence))}this.resolvedConfidence.clear();for(let r of this.comments){let o=t.get(r.id)??"orphaned";this.resolvedConfidence.set(r.id,o);let a=(r.fingerprints||[])[0],l=a?e.get(m(a))?.target??null:null;this.bus.emit("anchor:resolved",{comment:r,confidence:o,element:l})}for(let r of this.comments)this.selfHealedThisSession.has(r.id)||this.resolvedConfidence.get(r.id)==="drifted"&&this.selfHealComment(r,e);for(let[r,o]of e){if(o.confidence==="orphaned"||!o.target)continue;let a=document.createElement("div");a.className="vz-comment-outline",o.confidence==="drifted"&&a.classList.add("vz-comment-outline-drifted"),this.root.appendChild(a),this.outlines.set(r,{outline:a,target:o.target,fp:o.fp});let l=document.createElement("button");l.className="vz-marker",o.confidence==="drifted"&&l.classList.add("vz-marker-drifted"),l.setAttribute("data-element-key",r),l.setAttribute("data-confidence",o.confidence);let c=o.commentIds.length;if(c>1)l.textContent=String(c),l.title=c+" comments";else{l.textContent="";let p=this.comments.find(u=>u.id===o.commentIds[0]);l.title=p?.author?"Comment by "+p.author.name:"Comment"}l.addEventListener("click",p=>{if(p.preventDefault(),p.stopPropagation(),o.target){let u=this.commentsForElement(o.fp);this.openPopoverFor([o.target],[o.fp],u)}}),l.addEventListener("mouseenter",()=>this.pulseRelatedElements(o.commentIds,r)),this.root.appendChild(l),this.markers.set(r,{marker:l,target:o.target,fp:o.fp,commentIds:o.commentIds}),o.target?(this.positionMarker(l,o.target),this.positionOutline(a,o.target)):(l.style.display="none",a.style.display="none")}}pulseRelatedElements(e,t){let n=new Set;for(let i of e){let r=this.comments.find(a=>a.id===i);if(!r)continue;let o=r.fingerprints||[];if(!(o.length<=1))for(let a of o){let l=m(a);l!==t&&n.add(l)}}for(let i of n){let r=this.outlines.get(i)?.outline;r&&(r.classList.remove("is-pulsing"),r.offsetWidth,r.classList.add("is-pulsing"),setTimeout(()=>r.classList.remove("is-pulsing"),900))}}positionOutline(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.left+"px",e.style.top=n.top+"px",e.style.width=n.width+"px",e.style.height=n.height+"px"}positionMarker(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.right+"px",e.style.top=n.top+"px"}syncActiveAnchorOutlines(e){if(!this.root)return;let t=new Set(e.map(n=>m(n)));for(let[n,i]of this.activeAnchorOutlines)t.has(n)||(i.el.remove(),this.activeAnchorOutlines.delete(n));for(let n of e){let i=m(n);if(this.activeAnchorOutlines.has(i))continue;let r=document.createElement("div");r.className="vz-comment-outline is-selected-pending",this.root.appendChild(r);let o=R(n);o?this.positionOutline(r,o):r.style.display="none",this.activeAnchorOutlines.set(i,{el:r,fp:n})}}clearActiveAnchorOutlines(){for(let e of this.activeAnchorOutlines.values())e.el.remove();this.activeAnchorOutlines.clear()}actionContext(){return{comments:this.getComments(),pageHtml:this.snapshotHtml(),pageUrl:typeof location<"u"?location.href:void 0,pageVersion:this.opts.pageVersion,user:this.user??void 0,timestamp:Date.now(),copyToClipboard:e=>this.copyToClipboard(e),toast:e=>this.pill?.toast(e)}}snapshotHtml(){let e=document.documentElement.cloneNode(!0);for(let n of e.querySelectorAll("[data-vizu-root], #vizu-styles"))n.remove();return`<!DOCTYPE html>
1096
+ `,this.pickingBanner.addEventListener("click",e=>{e.target.closest('[data-vz="cancel-pick"]')&&this.cancelPicking()}),this.root.appendChild(this.pickingBanner))}hidePickingBanner(){this.pickingBanner?.remove(),this.pickingBanner=null}jumpToReference(e,t){let i=this.comments.find(r=>r.id===e)?.references?.[t];i&&this.jumpToFingerprint(i)}jumpToFingerprint(e){let t=V(e);if(!t){this.pill?.toast("Element not found on this page");return}if(t.scrollIntoView({behavior:"smooth",block:"center"}),this.root){let r=document.createElement("div");r.className="vz-jump-spotlight",this.root.appendChild(r),this.positionOutline(r,t);let s={el:r,target:t};this.spotlights.add(s),setTimeout(()=>{r.remove(),this.spotlights.delete(s)},1800)}let n=h(e),i=this.outlines.get(n)?.outline;i&&setTimeout(()=>{i.classList.remove("is-pulsing"),i.offsetWidth,i.classList.add("is-pulsing"),setTimeout(()=>i.classList.remove("is-pulsing"),1500)},250)}renderAllMarkers(){if(!this.root)return;for(let{marker:r}of this.markers.values())r.remove();for(let{outline:r}of this.outlines.values())r.remove();this.markers.clear(),this.outlines.clear();let e=new Map,t=new Map,n=r=>r==="exact"?3:r==="likely"?2:r==="drifted"?1:0,i=(r,s)=>r===void 0||n(s)>n(r)?s:r;for(let r of this.comments)for(let s of r.fingerprints||[]){let a=h(s),l=e.get(a);if(!l){let c=j(s);l={fp:s,target:c.element,confidence:c.confidence,commentIds:[]},e.set(a,l)}l.commentIds.push(r.id),t.set(r.id,i(t.get(r.id),l.confidence))}this.resolvedConfidence.clear();for(let r of this.comments){let s=t.get(r.id)??"orphaned";this.resolvedConfidence.set(r.id,s);let a=(r.fingerprints||[])[0],l=a?e.get(h(a))?.target??null:null;this.bus.emit("anchor:resolved",{comment:r,confidence:s,element:l})}for(let r of this.comments)this.selfHealedThisSession.has(r.id)||this.resolvedConfidence.get(r.id)==="drifted"&&this.selfHealComment(r,e);for(let[r,s]of e){if(s.confidence==="orphaned"||!s.target)continue;let a=document.createElement("div");a.className="vz-comment-outline",s.confidence==="drifted"&&a.classList.add("vz-comment-outline-drifted"),this.root.appendChild(a),this.outlines.set(r,{outline:a,target:s.target,fp:s.fp});let l=document.createElement("button");l.className="vz-marker",s.confidence==="drifted"&&l.classList.add("vz-marker-drifted"),l.setAttribute("data-element-key",r),l.setAttribute("data-confidence",s.confidence);let c=s.commentIds.length;if(c>1)l.textContent=String(c),l.title=c+" comments";else{l.textContent="";let p=this.comments.find(m=>m.id===s.commentIds[0]);l.title=p?.author?"Comment by "+p.author.name:"Comment"}l.addEventListener("click",p=>{if(p.preventDefault(),p.stopPropagation(),s.target){let m=this.commentsForElement(s.fp);this.openPopoverFor([s.target],[s.fp],m)}}),l.addEventListener("mouseenter",()=>this.pulseRelatedElements(s.commentIds,r)),this.root.appendChild(l),this.markers.set(r,{marker:l,target:s.target,fp:s.fp,commentIds:s.commentIds}),s.target?(this.positionMarker(l,s.target),this.positionOutline(a,s.target)):(l.style.display="none",a.style.display="none")}}pulseRelatedElements(e,t){let n=new Set;for(let i of e){let r=this.comments.find(a=>a.id===i);if(!r)continue;let s=r.fingerprints||[];if(!(s.length<=1))for(let a of s){let l=h(a);l!==t&&n.add(l)}}for(let i of n){let r=this.outlines.get(i)?.outline;r&&(r.classList.remove("is-pulsing"),r.offsetWidth,r.classList.add("is-pulsing"),setTimeout(()=>r.classList.remove("is-pulsing"),900))}}positionOutline(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.left+"px",e.style.top=n.top+"px",e.style.width=n.width+"px",e.style.height=n.height+"px"}positionMarker(e,t){let n=t.getBoundingClientRect();if(n.width===0&&n.height===0){e.style.display="none";return}e.style.display="",e.style.left=n.right+"px",e.style.top=n.top+"px"}syncActiveAnchorOutlines(e){if(!this.root)return;let t=new Set(e.map(n=>h(n)));for(let[n,i]of this.activeAnchorOutlines)t.has(n)||(i.el.remove(),this.activeAnchorOutlines.delete(n));for(let n of e){let i=h(n);if(this.activeAnchorOutlines.has(i))continue;let r=document.createElement("div");r.className="vz-comment-outline is-selected-pending",this.root.appendChild(r);let s=V(n);s?this.positionOutline(r,s):r.style.display="none",this.activeAnchorOutlines.set(i,{el:r,fp:n})}}clearActiveAnchorOutlines(){for(let e of this.activeAnchorOutlines.values())e.el.remove();this.activeAnchorOutlines.clear()}actionContext(){return{comments:this.getComments(),pageHtml:this.snapshotHtml(),pageUrl:typeof location<"u"?location.href:void 0,pageVersion:this.opts.pageVersion,user:this.user??void 0,timestamp:Date.now(),copyToClipboard:e=>this.copyToClipboard(e),toast:e=>this.pill?.toast(e)}}snapshotHtml(){let e=document.documentElement.cloneNode(!0);for(let n of e.querySelectorAll("[data-vizu-root], #vizu-styles"))n.remove();return`<!DOCTYPE html>
1276
1097
  <html`+document.documentElement.getAttributeNames().map(n=>` ${n}="${(document.documentElement.getAttribute(n)||"").replace(/"/g,"&quot;")}"`).join("")+`>
1277
1098
  `+e.innerHTML+`
1278
- </html>`}copyToClipboard(e){navigator.clipboard?.writeText?navigator.clipboard.writeText(e).catch(()=>Oe(e)):Oe(e)}};function Oe(s){let e=document.createElement("textarea");e.value=s,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{document.execCommand("copy")}catch{}e.remove()}function $t(){if(typeof document>"u")return null;let s=document.currentScript;if(s)return s;let e=Array.from(document.scripts);return e.find(t=>t.dataset&&t.dataset.vizuAuto!==void 0)||e.find(t=>t.src&&/vizu(\.min)?\.js/.test(t.src))||null}function It(){if(typeof window>"u"||window.__vizu)return;let e=$t()?.dataset||{},t=e.storage&&["local","memory","none"].includes(e.storage)?e.storage:"local",n=e.userName?{id:e.userId,name:e.userName,avatarUrl:e.userAvatar,email:e.userEmail}:void 0,i={shortcut:e.shortcut||"mod+shift+e",namespace:e.namespace||"default",pageVersion:e.version,accent:e.accent,startEnabled:e.startEnabled==="true"||e.startEnabled===""||e.startEnabled==="1",ignoreSelectors:e.ignore?e.ignore.split(",").map(o=>o.trim()).filter(Boolean):[],storage:t,user:n},r=new E(i,"local");window.__vizu=r,window.Vizu=E}It();return qe(Ft);})();
1099
+ </html>`}copyToClipboard(e){navigator.clipboard?.writeText?navigator.clipboard.writeText(e).catch(()=>he(e)):he(e)}};function he(o){let e=document.createElement("textarea");e.value=o,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();try{document.execCommand("copy")}catch{}e.remove()}function Ke(){if(typeof document>"u")return null;let o=document.currentScript;if(o)return o;let e=Array.from(document.scripts);return e.find(t=>t.dataset&&t.dataset.vizuAuto!==void 0)||e.find(t=>t.src&&/vizu(\.min)?\.js/.test(t.src))||null}function Je(){if(typeof window>"u"||window.__vizu)return;let e=Ke()?.dataset||{},t=e.storage&&["local","memory","none"].includes(e.storage)?e.storage:"local",n=e.userName?{id:e.userId,name:e.userName,avatarUrl:e.userAvatar,email:e.userEmail}:void 0,i={shortcut:e.shortcut||"mod+shift+e",namespace:e.namespace||"default",pageVersion:e.version,accent:e.accent,startEnabled:e.startEnabled==="true"||e.startEnabled===""||e.startEnabled==="1",ignoreSelectors:e.ignore?e.ignore.split(",").map(s=>s.trim()).filter(Boolean):[],storage:t,user:n},r=new k(i,"local");window.__vizu=r,window.Vizu=k}Je();return we(We);})();
1279
1100
  //# sourceMappingURL=vizu.min.js.map