@siteping/widget 0.9.13 → 0.9.14
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/README.md +2 -1
- package/dist/{chunk-VC52F5JZ.js → chunk-W5TBUGIT.js} +10 -10
- package/dist/chunk-W5TBUGIT.js.map +1 -0
- package/dist/index.global.js +37 -37
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +40 -40
- package/dist/index.js.map +1 -1
- package/dist/panel-JGEW26L5.js +2 -0
- package/dist/panel-JGEW26L5.js.map +1 -0
- package/dist/react.js +40 -40
- package/dist/react.js.map +1 -1
- package/dist/siteping-core.d.ts +1 -1
- package/dist/types.d.ts +38 -5
- package/package.json +1 -1
- package/dist/chunk-VC52F5JZ.js.map +0 -1
- package/dist/panel-N6GZYG5N.js +0 -2
- package/dist/panel-N6GZYG5N.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {b,c,a,i,t,K,V,j,S,M as M$1,O,Z,W,X,d,P,Q,R,x,I,y,e,s,k,p,l,m,n,o,r,q}from'./chunk-W5TBUGIT.js';var M=class{element;current;opts;onChange;datasetKey;constructor(e){this.opts=e.options,this.current=e.value,this.onChange=e.onChange,this.datasetKey=e.datasetKey,this.element=b("div",{class:`sp-segmented${e.extraClass?` ${e.extraClass}`:""}`,role:"radiogroup"}),this.element.setAttribute("aria-label",e.ariaLabel);for(let t of this.opts){let s=document.createElement("button");s.type="button",s.className=e.modifierPrefix!==void 0?`sp-segmented__btn ${e.modifierPrefix}${t.value}`:"sp-segmented__btn",s.dataset[this.datasetKey]=t.value,s.setAttribute("role","radio");let n=this.current===t.value;if(s.setAttribute("aria-checked",String(n)),s.tabIndex=n?0:-1,n&&s.classList.add("sp-segmented__btn--active"),t.color&&s.style.setProperty("--sp-chip-color",t.color),t.bg&&s.style.setProperty("--sp-chip-bg",t.bg),t.icon){let a$1=b("span",{class:"sp-segmented__icon"});a$1.appendChild(a(t.icon)),s.appendChild(a$1);}let o=b("span",{class:"sp-segmented__label"});c(o,t.label),s.appendChild(o),s.addEventListener("click",()=>this.select(t.value)),s.addEventListener("keydown",a=>this.handleKey(a,t.value)),this.element.appendChild(s);}}select(e){this.current=e,this.syncSelection(),this.onChange(e);}syncSelection(){let e=this.element.querySelectorAll(".sp-segmented__btn");for(let t of e){let s=t.dataset[this.datasetKey]===this.current;t.classList.toggle("sp-segmented__btn--active",s),t.setAttribute("aria-checked",String(s)),t.tabIndex=s?0:-1;}}setOptionVisible(e,t){let s=this.element.querySelector(`[data-${this.kebabKey()}="${e}"]`);return s?(s.style.display=t?"":"none",true):false}get value(){return this.current}focusOption(e){this.element.querySelector(`[data-${this.kebabKey()}="${e}"]`)?.focus();}handleKey(e,t){let s=this.opts.map(d=>d.value).filter(d=>{let c=this.element.querySelector(`[data-${this.kebabKey()}="${d}"]`);return c!==null&&c.style.display!=="none"}),n=s.indexOf(t);if(n<0)return;let o;switch(e.key){case "ArrowLeft":o=(n-1+s.length)%s.length;break;case "ArrowRight":o=(n+1)%s.length;break;case "Home":o=0;break;case "End":o=s.length-1;break;default:return}e.preventDefault();let a=s[o];a!==void 0&&(this.select(a),this.focusOption(a));}kebabKey(){return this.datasetKey.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}};var oe=class{constructor(e,t$1,s,n,o,a$1,d,c$1,v){this.colors=t$1;this.bus=s;this.client=n;this.projectName=o;this.markers=a$1;this.t=d;this.locale=c$1;this.shadowRoot=e,this.getScope=v?.getScope??(()=>({url:window.location.pathname,urlPattern:null})),this.scopeAnnotationsByUrl=v?.scopeAnnotationsByUrl??true,this.root=b("div",{class:"sp-panel"}),this.root.setAttribute("role","complementary"),this.root.setAttribute("aria-label",this.t("panel.ariaLabel")),this.root.setAttribute("aria-hidden","true");let h=b("div",{class:"sp-panel-header"}),u=b("span",{class:"sp-panel-title"});c(u,this.t("panel.title")),this.closeBtn=document.createElement("button"),this.closeBtn.className="sp-panel-close",this.closeBtn.setAttribute("aria-label",this.t("panel.close")),this.closeBtn.appendChild(a(i)),this.closeBtn.addEventListener("click",()=>this.close()),this.deleteAllBtn=document.createElement("button"),this.deleteAllBtn.className="sp-btn-delete-all",this.deleteAllBtn.setAttribute("aria-label",this.t("panel.deleteAll")),this.deleteAllBtn.appendChild(a(t));let m=document.createElement("span");c(m,` ${this.t("panel.deleteAll")}`),this.deleteAllBtn.appendChild(m),this.deleteAllBtn.addEventListener("click",()=>this.confirmDeleteAll()),this.exportBtn=new K(t$1,()=>this.feedbacks,this.t);let k=b("div",{class:"sp-panel-header-right"});k.appendChild(this.exportBtn.element),k.appendChild(this.deleteAllBtn),k.appendChild(this.closeBtn),h.appendChild(u),h.appendChild(k),this.stats=new V(t$1,this.t);let f=b("div",{class:"sp-filters"}),y=b("div",{class:"sp-search-wrap"}),T=a(j);T.setAttribute("class","sp-search-icon"),this.searchInput=document.createElement("input"),this.searchInput.type="text",this.searchInput.className="sp-search",this.searchInput.placeholder=this.t("panel.search"),this.searchInput.setAttribute("aria-label",this.t("panel.searchAria")),this.searchInput.addEventListener("input",()=>{this.searchTimeout&&clearTimeout(this.searchTimeout),this.searchTimeout=setTimeout(()=>this.loadFeedbacks().catch(()=>{}),200);}),y.appendChild(T),y.appendChild(this.searchInput);let g=b("div",{class:"sp-filter-bar"});g.appendChild(this.buildTypeDropdown()),g.appendChild(this.buildStatusSegmented()),g.appendChild(this.buildScopeSegmented()),this.sortControls=new S(t$1,()=>this.renderList(),this.t),f.appendChild(y),f.appendChild(g),f.appendChild(this.sortControls.element),this.listContainer=b("div",{class:"sp-list"}),this.listContainer.setAttribute("role","list"),this.listContainer.setAttribute("aria-label",this.t("panel.feedbackList")),this.bulk=new M$1(t$1,{onResolve:i=>this.bulkResolve(i),onDelete:i=>this.bulkDelete(i)},this.t),this.bulk.setListContainer(this.listContainer),this.detail=new O(t$1,{onBack:()=>this.detail.hide(),onResolve:async i=>{try{let l=i.status!=="resolved";await this.client.resolveFeedback(i.id,l),await this.loadFeedbacks(),this.detail.hide();}catch(l){throw this.bus.emit("feedback:error",l instanceof Error?l:new Error(String(l))),l}},onDelete:async i=>{try{await this.client.deleteFeedback(i.id),this.bus.emit("feedback:deleted",i.id),await this.loadFeedbacks(),this.detail.hide();}catch(l){throw this.bus.emit("feedback:error",l instanceof Error?l:new Error(String(l))),l}},onGoToAnnotation:i=>{if(i.annotations.length>0){let l=i.annotations[0];if(!l)return;window.scrollTo({left:l.scrollX,top:l.scrollY,behavior:"smooth"}),this.markers.pinHighlight(i);}}},this.t,c$1),this.shortcuts=new Z(t$1,{onNavigate:i=>{let l=W(this.listContainer);X(this.listContainer,i==="down"?l+1:l-1);},onResolve:()=>{let i=this.getFocusedFeedback();if(i&&!this.pendingMutations.has(i.id)){let p=this.listContainer.querySelector(`[data-feedback-id="${CSS.escape(i.id)}"]`)?.querySelector('[data-action="resolve"]');p&&this.toggleResolve(i,p).catch(()=>{});}},onDelete:()=>{let i=this.getFocusedFeedback();if(i&&!this.pendingMutations.has(i.id)){let p=this.listContainer.querySelector(`[data-feedback-id="${CSS.escape(i.id)}"]`)?.querySelector('[data-action="delete"]');p&&this.deleteFeedback(i,p).catch(()=>{});}},onFocusSearch:()=>this.searchInput.focus(),onToggleSelect:()=>{let i=this.getFocusedFeedback();i&&this.bulk.toggle(i.id);}},this.t),this.root.appendChild(h),this.root.appendChild(this.stats.element),this.root.appendChild(f),this.root.appendChild(this.listContainer),this.root.appendChild(this.bulk.barElement),this.root.appendChild(this.detail.element),this.root.appendChild(this.shortcuts.helpOverlay),this.root.appendChild(this.shortcuts.hintButton),e.appendChild(this.root),this.onListClick=i=>{let l=i.target;if(l.closest(".sp-bulk-checkbox"))return;let p=l.closest("[data-action]");if(p){i.stopPropagation();let A=p.closest(".sp-card");if(!A)return;let L=A.dataset.feedbackId,C=this.feedbacks.find(E=>E.id===L);if(!C)return;let B=p.dataset.action;if(B==="expand"){let E=A.querySelector(".sp-card-message");if(!E)return;let I=E.classList.toggle("sp-card-message--expanded");c(p,I?this.t("panel.showLess"):this.t("panel.showMore")),p.setAttribute("aria-expanded",String(I));}else if(B==="resolve"){if(this.pendingMutations.has(C.id))return;let E=p;this.toggleResolve(C,E).catch(()=>{});}else if(B==="delete"){if(this.pendingMutations.has(C.id))return;let E=p;this.deleteFeedback(C,E).catch(()=>{});}return}let w=l.closest(".sp-card");if(w){let A=w.dataset.feedbackId,L=this.feedbacks.find(C=>C.id===A);if(L){let C=this.feedbacks.indexOf(L)+1;this.detail.show(L,C);}}},this.listContainer.addEventListener("click",this.onListClick),this.onListKeydown=i=>{let l=i;if(l.key!=="Enter"&&l.key!==" ")return;let p=l.target,w=p.closest(".sp-card");if(!w||p!==w)return;l.preventDefault();let A=w.dataset.feedbackId,L=this.feedbacks.find(C=>C.id===A);if(L){let C=this.feedbacks.indexOf(L)+1;this.detail.show(L,C);}},this.listContainer.addEventListener("keydown",this.onListKeydown),this.onListMouseover=i=>{let p=i.target.closest(".sp-card");if(!p)return;let w=p.dataset.feedbackId;w&&this.markers.highlight(w);},this.listContainer.addEventListener("mouseover",this.onListMouseover),this.onListMouseout=i=>{let l=i.relatedTarget;l&&this.listContainer.contains(l)||this.markers.highlight("");},this.listContainer.addEventListener("mouseout",this.onListMouseout),this.bus.on("panel:toggle",i=>{i?this.open():this.close();}),e.addEventListener("keydown",i=>{let l=i;if(l.key==="Escape"&&this.isOpen){if(this.detail.isVisible){this.detail.hide();return}this.close();return}if(l.key==="Tab"&&this.isOpen){let p=B=>{let E=B;for(;E&&E!==this.root;){if(E.style.display==="none")return false;E=E.parentElement;}return true},w=Array.from(this.root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')).filter(B=>p(B)&&!B.hasAttribute("disabled"));if(w.length===0)return;let A=w[0],L=w[w.length-1];if(!A||!L)return;let C=e.activeElement;l.shiftKey&&C===A?(l.preventDefault(),L.focus()):!l.shiftKey&&C===L&&(l.preventDefault(),A.focus());}}),this.onMarkerClick=(i=>{this.scrollToFeedback(i.detail.feedbackId);}),document.addEventListener("sp-marker-click",this.onMarkerClick);}colors;bus;client;projectName;markers;t;locale;root;listContainer;searchInput;closeBtn;deleteAllBtn;activeFilters=new Set(["all"]);typeDropdownBtn;typeDropdownContainer;typeDropdownMenu=null;typeDropdownOutsideHandler=null;statusSegmented;typeOptions;feedbacks=[];currentPage=1;totalFeedbacks=0;isLoadingMore=false;isOpen=false;searchTimeout=null;loadController=null;pendingMutations=new Set;stats;sortControls;bulk;exportBtn;shortcuts;detail;shadowRoot;getScope;scopeAnnotationsByUrl;scopeSegmented;initialScopeFilter="this";onMarkerClick;onListClick;onListKeydown;onListMouseover;onListMouseout;async open(){this.isOpen||(this.isOpen=true,this.root.classList.add("sp-panel--open"),this.root.setAttribute("aria-hidden","false"),this.bus.emit("open"),this.shortcuts.enable(this.shadowRoot),await this.loadFeedbacks(),requestAnimationFrame(()=>{this.searchInput?this.searchInput.focus():this.closeBtn.focus();}));}close(){if(!this.isOpen)return;this.isOpen=false,this.root.classList.remove("sp-panel--open"),this.root.setAttribute("aria-hidden","true"),this.bus.emit("close"),this.shortcuts.disable(),this.detail.hide(),this.root.getRootNode().querySelector(".sp-fab")?.focus();}showLoading(){this.listContainer.replaceChildren();let e=b("div",{class:"sp-loading"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-label",this.t("panel.loading"));let t=b("div",{class:"sp-spinner"});e.appendChild(t),this.listContainer.appendChild(e);}showError(){this.listContainer.replaceChildren();let e=b("div",{class:"sp-empty"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite");let t=b("div",{class:"sp-empty-text"});c(t,this.t("panel.loadError"));let s=document.createElement("button");s.className="sp-btn-ghost",s.style.marginTop="8px",c(s,this.t("panel.retry")),s.addEventListener("click",()=>this.loadFeedbacks().catch(()=>{})),e.appendChild(t),e.appendChild(s),this.listContainer.appendChild(e);}async loadFeedbacks(){this.loadController?.abort(),this.loadController=new AbortController;let{signal:e}=this.loadController;this.currentPage=1;let t=this.searchInput.value.trim()||void 0,s=this.activeFilters.has("all")?void 0:Array.from(this.activeFilters)[0],n=this.statusSegmented.value,o=n==="all"?void 0:n,a=this.getScope();this.syncScopeAvailability();let d=this.scopeSegmented.value,c={page:1,limit:20};s&&(c.type=s),o&&(c.status=o),t&&(c.search=t),d==="this"?c.url=a.url:d==="template"&&a.urlPattern&&(c.urlPattern=a.urlPattern);let v=this.feedbacks.length>0;v||this.showLoading();try{let{feedbacks:h,total:u}=await this.client.getFeedbacks(this.projectName,c);if(e.aborted)return;this.feedbacks=h,this.totalFeedbacks=u,this.stats.update(h,u),this.bulk.reset(),this.renderList();let m=this.scopeAnnotationsByUrl?h.filter(k=>k.url===a.url):h;this.markers.render(m);}catch(h){if(e.aborted)return;v||this.showError(),this.bus.emit("feedback:error",h instanceof Error?h:new Error(String(h)));}}async loadMoreFeedbacks(){if(this.isLoadingMore)return;this.isLoadingMore=true;let e=this.loadController,t=this.currentPage+1,s=this.searchInput.value.trim()||void 0,n=this.activeFilters.has("all")?void 0:Array.from(this.activeFilters)[0],o=this.statusSegmented.value,a=o==="all"?void 0:o,d$1=this.getScope(),c=this.scopeSegmented.value,v={page:t,limit:20};n&&(v.type=n),a&&(v.status=a),s&&(v.search=s),c==="this"?v.url=d$1.url:c==="template"&&d$1.urlPattern&&(v.urlPattern=d$1.urlPattern);let h=this.listContainer.querySelector(".sp-btn-load-more"),u;h&&(u=d(h));try{let{feedbacks:m,total:k}=await this.client.getFeedbacks(this.projectName,v);if(e!==this.loadController)return;this.currentPage=t,this.totalFeedbacks=k,this.feedbacks=[...this.feedbacks,...m],this.stats.update(this.feedbacks,k),this.renderList();let f=this.scopeAnnotationsByUrl?this.feedbacks.filter(y=>y.url===d$1.url):this.feedbacks;this.markers.render(f);}catch(m){u&&u(),this.bus.emit("feedback:error",m instanceof Error?m:new Error(String(m)));}finally{this.isLoadingMore=false;}}renderList(){if(this.listContainer.replaceChildren(),this.feedbacks.length===0){let o=b("div",{class:"sp-empty"});o.setAttribute("role","status"),o.setAttribute("aria-live","polite");let a=b("div",{class:"sp-empty-text"});c(a,this.t("panel.empty")),o.appendChild(a),this.listContainer.appendChild(o);return}let e=P(this.feedbacks,this.sortControls.sortMode),t=e.map(o=>o.id),s=this.bulk.createSelectAllBar(t,this.t("bulk.selectAll"));if(this.listContainer.appendChild(s),this.sortControls.groupByPage){let o=Q(e),a=0;for(let[d,c]of o){let v=R(d,c.length,this.colors);this.listContainer.appendChild(v);let h=b("div",{class:"sp-group-content"});for(let u of c){let m=this.createCard(u,a+1);m.style.setProperty("--sp-card-i",String(a)),h.appendChild(m),a++;}this.listContainer.appendChild(h);}}else e.forEach((o,a)=>{let d=this.createCard(o,a+1);d.style.setProperty("--sp-card-i",String(a)),this.listContainer.appendChild(d);});let n=this.totalFeedbacks-this.feedbacks.length;if(n>0){let o=b("div",{class:"sp-load-more-wrap"}),a=document.createElement("button");a.className="sp-btn-ghost sp-btn-load-more",c(a,this.t("panel.loadMore").replace("{remaining}",String(n))),a.addEventListener("click",()=>this.loadMoreFeedbacks().catch(()=>{})),o.appendChild(a),this.listContainer.appendChild(o);}}createCard(e$1,t$1){let s$1=e$1.status==="resolved",n=x(e$1.type,this.colors),o=b("div",{class:`sp-card ${s$1?"sp-card--resolved":""}`});o.setAttribute("role","listitem"),o.setAttribute("tabindex","0"),o.setAttribute("aria-label",`Feedback #${t$1}: ${I(e$1.type,this.t)} \u2014 ${e$1.message.slice(0,80)}`),o.dataset.feedbackId=e$1.id;let a$1=b("div",{class:"sp-card-bar"});a$1.style.background=s$1?"#9ca3af":n;let d=b("div",{class:"sp-card-body"}),c$1=b("div",{class:"sp-card-header"}),v=this.bulk.createCheckbox(e$1.id);c$1.appendChild(v);let h=b("span",{class:"sp-card-number"});c(h,`#${t$1}`);let u=b("span",{class:"sp-badge"}),m=y(e$1.type,this.colors);u.style.background=m,u.style.color=n,c(u,I(e$1.type,this.t));let k$1=b("span",{class:"sp-card-date"});c(k$1,e(e$1.createdAt,this.locale)),c$1.appendChild(h),c$1.appendChild(u),c$1.appendChild(k$1);let f=b("div",{class:"sp-card-message"});c(f,e$1.message);let y$1=document.createElement("button");y$1.className="sp-card-expand",y$1.dataset.action="expand",c(y$1,this.t("panel.showMore")),y$1.style.display="none",y$1.setAttribute("aria-expanded","false"),requestAnimationFrame(()=>{f.scrollHeight>f.clientHeight&&(y$1.style.display="block");});let T=b("div",{class:"sp-card-footer"}),g=document.createElement("button");if(g.className="sp-btn-resolve",g.dataset.action="resolve",s$1){g.appendChild(a(s));let p=document.createElement("span");c(p,` ${this.t("panel.reopen")}`),g.appendChild(p);}else {g.appendChild(a(k));let p=document.createElement("span");c(p,` ${this.t("panel.resolve")}`),g.appendChild(p);}let i=document.createElement("button");i.className="sp-btn-delete",i.dataset.action="delete",i.appendChild(a(t));let l=document.createElement("span");return c(l,` ${this.t("panel.delete")}`),i.appendChild(l),T.appendChild(g),T.appendChild(i),d.appendChild(c$1),d.appendChild(f),d.appendChild(y$1),d.appendChild(T),o.appendChild(a$1),o.appendChild(d),o}async bulkResolve(e){try{await Promise.all(e.map(t=>this.client.resolveFeedback(t,!0))),await this.loadFeedbacks();}catch(t){throw this.bus.emit("feedback:error",t instanceof Error?t:new Error(String(t))),t}}async bulkDelete(e){try{await Promise.all(e.map(t=>this.client.deleteFeedback(t)));for(let t of e)this.bus.emit("feedback:deleted",t);await this.loadFeedbacks();}catch(t){throw this.bus.emit("feedback:error",t instanceof Error?t:new Error(String(t))),t}}async confirmDeleteAll(){if(await this.showConfirmDialog(this.t("panel.deleteAllConfirmTitle"),this.t("panel.deleteAllConfirmMessage"))){this.deleteAllBtn.disabled=true;try{await this.client.deleteAllFeedbacks(this.projectName),this.bus.emit("feedback:all-deleted"),await this.loadFeedbacks();}catch(t){this.bus.emit("feedback:error",t instanceof Error?t:new Error(String(t)));}finally{this.deleteAllBtn.disabled=false;}}}showConfirmDialog(e,t){return new Promise(s=>{let n=b("div",{class:"sp-confirm-backdrop"}),o=`sp-confirm-title-${Date.now()}`,a=`sp-confirm-msg-${Date.now()}`,d=b("div",{class:"sp-confirm-dialog"});d.setAttribute("role","alertdialog"),d.setAttribute("aria-modal","true"),d.setAttribute("aria-labelledby",o),d.setAttribute("aria-describedby",a);let c$1=b("div",{class:"sp-confirm-title"});c$1.id=o,c(c$1,e);let v=b("div",{class:"sp-confirm-message"});v.id=a,c(v,t);let h=b("div",{class:"sp-confirm-actions"}),u=document.createElement("button");u.type="button",u.className="sp-btn-ghost",c(u,this.t("panel.cancel"));let m=document.createElement("button");m.type="button",m.className="sp-btn-danger",c(m,this.t("panel.confirmDelete"));let k=false,f=T=>{k||(k=true,n.removeEventListener("keydown",y),n.style.opacity="0",d.style.transform="translateY(8px) scale(0.97)",setTimeout(()=>{n.remove(),s(T);},200));},y=T=>{let g=T;if(g.key==="Escape"){f(false);return}g.key==="Tab"&&(g.preventDefault(),n.getRootNode().activeElement===u?m.focus():u.focus());};n.addEventListener("keydown",y),u.addEventListener("click",()=>f(false)),m.addEventListener("click",()=>f(true)),n.addEventListener("click",T=>{T.target===n&&f(false);}),h.appendChild(u),h.appendChild(m),d.appendChild(c$1),d.appendChild(v),d.appendChild(h),n.appendChild(d),this.root.getRootNode()instanceof ShadowRoot?this.root.getRootNode().appendChild(n):this.root.appendChild(n),requestAnimationFrame(()=>{n.style.opacity="1",d.style.transform="translateY(0) scale(1)",u.focus();});})}async deleteFeedback(e,t){this.pendingMutations.add(e.id);let s=d(t);try{await this.client.deleteFeedback(e.id),this.bus.emit("feedback:deleted",e.id),await this.loadFeedbacks();}catch(n){s(),this.bus.emit("feedback:error",n instanceof Error?n:new Error(String(n)));}finally{this.pendingMutations.delete(e.id);}}async toggleResolve(e,t){this.pendingMutations.add(e.id);let s=d(t);try{let n=e.status!=="resolved";await this.client.resolveFeedback(e.id,n),await this.loadFeedbacks();}catch(n){s(),this.bus.emit("feedback:error",n instanceof Error?n:new Error(String(n)));}finally{this.pendingMutations.delete(e.id);}}buildTypeDropdown(){return this.typeOptions=[{value:"all",label:this.t("panel.filterAll"),icon:p,color:this.colors.accent,bg:this.colors.accentLight},{value:"question",label:this.t("type.question"),icon:l,color:this.colors.typeQuestion,bg:this.colors.typeQuestionBg},{value:"change",label:this.t("type.change"),icon:m,color:this.colors.typeChange,bg:this.colors.typeChangeBg},{value:"bug",label:this.t("type.bug"),icon:n,color:this.colors.typeBug,bg:this.colors.typeBugBg},{value:"other",label:this.t("type.other"),icon:o,color:this.colors.typeOther,bg:this.colors.typeOtherBg}],this.typeDropdownContainer=b("div",{class:"sp-filter-dropdown"}),this.typeDropdownBtn=document.createElement("button"),this.typeDropdownBtn.type="button",this.typeDropdownBtn.className="sp-filter-dropdown-btn",this.typeDropdownBtn.setAttribute("aria-haspopup","listbox"),this.typeDropdownBtn.setAttribute("aria-expanded","false"),this.renderTypeDropdownTrigger(),this.typeDropdownBtn.addEventListener("click",e=>{e.stopPropagation(),this.typeDropdownMenu?this.closeTypeDropdown():this.openTypeDropdown();}),this.typeDropdownContainer.appendChild(this.typeDropdownBtn),this.typeDropdownContainer}renderTypeDropdownTrigger(){let e=this.typeOptions.find(d=>this.activeFilters.has(d.value))??this.typeOptions[0];if(!e)return;this.typeDropdownBtn.replaceChildren(),this.typeDropdownBtn.style.setProperty("--sp-chip-color",e.color),this.typeDropdownBtn.style.setProperty("--sp-chip-bg",e.bg),this.typeDropdownBtn.dataset.filter=e.value,this.typeDropdownBtn.classList.toggle("sp-filter-dropdown-btn--filtered",e.value!=="all"),this.typeDropdownBtn.setAttribute("aria-label",`${this.t("type.label")}: ${e.label}`);let t=b("span",{class:"sp-filter-dropdown-btn__icon"});t.appendChild(a(e.icon)),this.typeDropdownBtn.appendChild(t);let s=b("span",{class:"sp-filter-dropdown-btn__label"}),n=b("span",{class:"sp-filter-dropdown-btn__prefix"});c(n,this.t("type.label"));let o=b("span",{class:"sp-filter-dropdown-btn__value"});c(o,e.label),s.appendChild(n),s.appendChild(o),this.typeDropdownBtn.appendChild(s);let a$1=b("span",{class:"sp-filter-dropdown-btn__chevron"});a$1.appendChild(a(r)),this.typeDropdownBtn.appendChild(a$1);}openTypeDropdown(){this.typeDropdownMenu=b("div",{class:"sp-filter-dropdown-menu"}),this.typeDropdownMenu.setAttribute("role","listbox"),this.typeDropdownMenu.setAttribute("aria-label",this.t("type.label")),this.typeDropdownBtn.setAttribute("aria-expanded","true");for(let e of this.typeOptions){let t=document.createElement("button");t.type="button";let s=this.activeFilters.has(e.value);t.className=`sp-filter-dropdown-option${s?" sp-filter-dropdown-option--active":""}`,t.style.setProperty("--sp-chip-color",e.color),t.style.setProperty("--sp-chip-bg",e.bg),t.dataset.filter=e.value,t.setAttribute("role","option"),t.setAttribute("aria-selected",String(s));let n=b("span",{class:"sp-filter-dropdown-option__icon"});n.appendChild(a(e.icon)),t.appendChild(n);let o=b("span",{class:"sp-filter-dropdown-option__label"});if(c(o,e.label),t.appendChild(o),s){let a$1=b("span",{class:"sp-filter-dropdown-option__check"});a$1.appendChild(a(k)),t.appendChild(a$1);}t.addEventListener("click",a=>{a.stopPropagation(),this.selectTypeFilter(e.value);}),this.typeDropdownMenu.appendChild(t);}this.typeDropdownContainer.appendChild(this.typeDropdownMenu),requestAnimationFrame(()=>{this.typeDropdownOutsideHandler=e=>{this.typeDropdownMenu&&!this.typeDropdownContainer.contains(e.target)&&this.closeTypeDropdown();},document.addEventListener("click",this.typeDropdownOutsideHandler,true);}),this.typeDropdownMenu.addEventListener("keydown",e=>{e.key==="Escape"&&(this.closeTypeDropdown(),this.typeDropdownBtn.focus());});}closeTypeDropdown(){this.typeDropdownMenu&&(this.typeDropdownMenu.remove(),this.typeDropdownMenu=null),this.typeDropdownBtn.setAttribute("aria-expanded","false"),this.typeDropdownOutsideHandler&&(document.removeEventListener("click",this.typeDropdownOutsideHandler,true),this.typeDropdownOutsideHandler=null);}selectTypeFilter(e){this.activeFilters.clear(),this.activeFilters.add(e),this.renderTypeDropdownTrigger(),this.closeTypeDropdown(),this.loadFeedbacks().catch(()=>{});}buildStatusSegmented(){return this.statusSegmented=new M({options:[{value:"all",label:this.t("panel.statusAll"),icon:p,color:this.colors.accent,bg:this.colors.accentLight},{value:"open",label:this.t("panel.statusOpen"),icon:q,color:this.colors.statusOpen,bg:this.colors.statusOpenBg},{value:"resolved",label:this.t("panel.statusResolved"),icon:k,color:this.colors.statusResolved,bg:this.colors.statusResolvedBg}],value:"all",onChange:()=>{this.loadFeedbacks().catch(()=>{});},ariaLabel:this.t("status.label"),datasetKey:"statusFilter",modifierPrefix:"sp-segmented__btn--"}),this.statusSegmented.element}buildScopeSegmented(){return this.scopeSegmented=new M({options:[{value:"this",label:this.t("scope.thisPage")},{value:"template",label:this.t("scope.thisType")},{value:"all",label:this.t("scope.all")}],value:this.initialScopeFilter,onChange:()=>{this.loadFeedbacks().catch(()=>{});},ariaLabel:this.t("scope.label"),datasetKey:"scopeFilter",modifierPrefix:"sp-segmented__btn--scope-",extraClass:"sp-segmented--scope"}),this.syncScopeAvailability(),this.scopeSegmented.element}syncScopeAvailability(){if(!this.scopeSegmented)return;let t=!!this.getScope().urlPattern;this.scopeSegmented.setOptionVisible("template",t),!t&&this.scopeSegmented.value==="template"&&this.scopeSegmented.select("this");}getFocusedFeedback(){let e=W(this.listContainer);if(e<0)return;let t=this.listContainer.querySelectorAll(".sp-card")[e];if(t)return this.feedbacks.find(s=>s.id===t.dataset.feedbackId)}scrollToFeedback(e){let t=CSS.escape(e),s=this.listContainer.querySelector(`[data-feedback-id="${t}"]`);s&&(s.scrollIntoView({behavior:"smooth",block:"center"}),s.classList.add("sp-anim-flash"),s.addEventListener("animationend",()=>{s.classList.remove("sp-anim-flash");},{once:true}));}async refresh(){this.isOpen&&await this.loadFeedbacks();}get isCurrentlyOpen(){return this.isOpen}destroy(){this.loadController?.abort(),this.searchTimeout&&clearTimeout(this.searchTimeout),this.listContainer.removeEventListener("click",this.onListClick),this.listContainer.removeEventListener("keydown",this.onListKeydown),this.listContainer.removeEventListener("mouseover",this.onListMouseover),this.listContainer.removeEventListener("mouseout",this.onListMouseout),document.removeEventListener("sp-marker-click",this.onMarkerClick),this.closeTypeDropdown(),this.sortControls.destroy(),this.bulk.destroy(),this.exportBtn.destroy(),this.shortcuts.destroy(),this.detail.destroy(),this.root.remove();}};export{oe as Panel};//# sourceMappingURL=panel-JGEW26L5.js.map
|
|
2
|
+
//# sourceMappingURL=panel-JGEW26L5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/segmented-control.ts","../src/panel.ts"],"names":["SegmentedControl","config","el","option","btn","isActive","iconWrap","parseSvg","labelEl","setText","e","value","buttons","visible","current","visibleValues","o","v","idx","nextIdx","next","m","Panel","shadowRoot","colors","bus","client","projectName","markers","t","locale","pageScopeOptions","header","title","ICON_CLOSE","ICON_TRASH","deleteAllLabel","ExportButton","headerRight","PanelStats","filters","searchWrap","searchIcon","ICON_SEARCH","filterBar","PanelSortControls","BulkActions","ids","DetailView","fb","newResolved","error","ann","KeyboardShortcuts","dir","getFocusedCardIndex","focusCardByIndex","target","actionEl","card","feedbackId","feedback","f","action","message","isExpanded","number","ke","open","isVisible","cur","focusable","first","last","active","loading","spinner","empty","text","retryBtn","signal","search","typeFilter","currentStatus","statusFilter","scope","currentScope","options","hasContent","feedbacks","total","markerFeedbacks","controller","nextPage","loadMoreBtn","restoreBtn","setButtonLoading","emptyText","sorted","sortFeedbacks","feedbackIds","selectAllBar","groups","groupFeedbacksByPage","globalIndex","pagePath","groupFeedbacks","groupHeader","createPageGroupHeader","groupContent","index","remaining","loadMoreWrap","isResolved","typeColor","getTypeColor","getTypeLabel","bar","body","checkbox","num","badge","typeBg","getTypeBgColor","date","formatRelativeDate","expandBtn","footer","resolveBtn","ICON_UNDO","span","ICON_CHECK","deleteBtn","deleteBtnLabel","id","resolve","backdrop","titleId","messageId","dialog","titleEl","messageEl","btnRow","cancelBtn","confirmBtn","closed","close","result","onKeydown","restore","ICON_LAYERS","ICON_QUESTION","ICON_CHANGE","ICON_BUG","ICON_OTHER","labelWrap","prefix","chevron","ICON_CHEVRON_DOWN","item","checkWrap","ICON_DOT_OPEN","showTemplate","escapedId"],"mappings":"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","file":"panel-JGEW26L5.js","sourcesContent":["/**\n * Accessible segmented (radiogroup) control.\n *\n * Replaces the near-identical `buildStatusSegmented` / `buildScopeSegmented`\n * pairs that previously lived inline in `panel.ts`: keyboard navigation\n * (ArrowLeft/Right, Home/End), aria-checked toggling, `tabIndex` roving,\n * and optional icon+colour decoration.\n *\n * Visibility filtering — needed by the scope control which hides the\n * \"this type\" option when there is no urlPattern — is handled by\n * `setOptionVisible(value, visible)` and is respected by keyboard\n * navigation so users can't focus a hidden option via arrow keys.\n */\n\nimport { el, parseSvg, setText } from \"../dom-utils.js\";\n\n/**\n * Visual decoration for a segmented option.\n * Both fields are optional: scope options omit them entirely.\n */\nexport interface SegmentedDecoration {\n icon?: string;\n color?: string;\n bg?: string;\n}\n\nexport interface SegmentedOption<T extends string> extends SegmentedDecoration {\n value: T;\n label: string;\n}\n\nexport interface SegmentedControlConfig<T extends string> {\n /** Options to render — order is preserved. */\n options: ReadonlyArray<SegmentedOption<T>>;\n /** Initial selected value — must appear in `options`. */\n value: T;\n /** Called whenever selection changes (click or keyboard). */\n onChange: (value: T) => void;\n /** Accessible label exposed via `aria-label` on the radiogroup. */\n ariaLabel: string;\n /** Extra CSS class appended to the wrapper (e.g. `sp-segmented--scope`). */\n extraClass?: string;\n /** dataset attribute name used per-button, e.g. `statusFilter` → `data-status-filter`. */\n datasetKey: string;\n /** Class prefix used for per-option modifier, e.g. `sp-segmented__btn--` + option.value. */\n modifierPrefix?: string;\n}\n\n/**\n * Build a segmented (radiogroup) control. Returns both the root element and\n * the imperative API for updating selection / visibility from outside —\n * Panel needs the latter when scope availability changes between SPA\n * navigations.\n */\nexport class SegmentedControl<T extends string> {\n readonly element: HTMLElement;\n private current: T;\n private readonly opts: ReadonlyArray<SegmentedOption<T>>;\n private readonly onChange: (value: T) => void;\n private readonly datasetKey: string;\n\n constructor(config: SegmentedControlConfig<T>) {\n this.opts = config.options;\n this.current = config.value;\n this.onChange = config.onChange;\n this.datasetKey = config.datasetKey;\n\n this.element = el(\"div\", {\n class: `sp-segmented${config.extraClass ? ` ${config.extraClass}` : \"\"}`,\n role: \"radiogroup\",\n });\n this.element.setAttribute(\"aria-label\", config.ariaLabel);\n\n for (const option of this.opts) {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className =\n config.modifierPrefix !== undefined\n ? `sp-segmented__btn ${config.modifierPrefix}${option.value}`\n : \"sp-segmented__btn\";\n btn.dataset[this.datasetKey] = option.value;\n btn.setAttribute(\"role\", \"radio\");\n const isActive = this.current === option.value;\n btn.setAttribute(\"aria-checked\", String(isActive));\n btn.tabIndex = isActive ? 0 : -1;\n if (isActive) btn.classList.add(\"sp-segmented__btn--active\");\n if (option.color) btn.style.setProperty(\"--sp-chip-color\", option.color);\n if (option.bg) btn.style.setProperty(\"--sp-chip-bg\", option.bg);\n\n if (option.icon) {\n const iconWrap = el(\"span\", { class: \"sp-segmented__icon\" });\n iconWrap.appendChild(parseSvg(option.icon));\n btn.appendChild(iconWrap);\n }\n\n const labelEl = el(\"span\", { class: \"sp-segmented__label\" });\n setText(labelEl, option.label);\n btn.appendChild(labelEl);\n\n btn.addEventListener(\"click\", () => this.select(option.value));\n btn.addEventListener(\"keydown\", (e) => this.handleKey(e, option.value));\n\n this.element.appendChild(btn);\n }\n }\n\n /** Imperatively change the selected option (also fires `onChange`). */\n select(value: T): void {\n this.current = value;\n this.syncSelection();\n this.onChange(value);\n }\n\n /** Apply selection-only DOM updates without firing `onChange`. Useful on init refresh. */\n private syncSelection(): void {\n const buttons = this.element.querySelectorAll<HTMLButtonElement>(\".sp-segmented__btn\");\n for (const btn of buttons) {\n const isActive = btn.dataset[this.datasetKey] === this.current;\n btn.classList.toggle(\"sp-segmented__btn--active\", isActive);\n btn.setAttribute(\"aria-checked\", String(isActive));\n btn.tabIndex = isActive ? 0 : -1;\n }\n }\n\n /**\n * Show / hide a specific option. Hidden options are skipped during keyboard\n * navigation. Returns true when an option was actually toggled.\n */\n setOptionVisible(value: T, visible: boolean): boolean {\n const btn = this.element.querySelector<HTMLButtonElement>(`[data-${this.kebabKey()}=\"${value}\"]`);\n if (!btn) return false;\n btn.style.display = visible ? \"\" : \"none\";\n return true;\n }\n\n /** Current selection. */\n get value(): T {\n return this.current;\n }\n\n /** Focus the button matching `value`, if it exists. */\n focusOption(value: T): void {\n const btn = this.element.querySelector<HTMLButtonElement>(`[data-${this.kebabKey()}=\"${value}\"]`);\n btn?.focus();\n }\n\n private handleKey(e: KeyboardEvent, current: T): void {\n const visibleValues = this.opts\n .map((o) => o.value)\n .filter((v) => {\n const btn = this.element.querySelector<HTMLButtonElement>(`[data-${this.kebabKey()}=\"${v}\"]`);\n return btn !== null && btn.style.display !== \"none\";\n });\n const idx = visibleValues.indexOf(current);\n if (idx < 0) return;\n\n let nextIdx: number;\n switch (e.key) {\n case \"ArrowLeft\":\n nextIdx = (idx - 1 + visibleValues.length) % visibleValues.length;\n break;\n case \"ArrowRight\":\n nextIdx = (idx + 1) % visibleValues.length;\n break;\n case \"Home\":\n nextIdx = 0;\n break;\n case \"End\":\n nextIdx = visibleValues.length - 1;\n break;\n default:\n return;\n }\n e.preventDefault();\n const next = visibleValues[nextIdx];\n if (next === undefined) return;\n this.select(next);\n this.focusOption(next);\n }\n\n /** Convert datasetKey (\"statusFilter\") to its DOM attribute form (\"status-filter\"). */\n private kebabKey(): string {\n return this.datasetKey.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);\n }\n}\n","import type { FeedbackResponse, FeedbackStatus, FeedbackType, PageScope } from \"@siteping/core\";\nimport type { GetFeedbacksOptions, WidgetClient } from \"./api-client.js\";\nimport { SegmentedControl } from \"./components/segmented-control.js\";\nimport { PAGE_SIZE } from \"./constants.js\";\nimport { el, formatRelativeDate, parseSvg, setButtonLoading, setText } from \"./dom-utils.js\";\nimport type { EventBus, WidgetEvents } from \"./events.js\";\nimport { ExportButton } from \"./export-utils.js\";\nimport { getTypeLabel, type TFunction } from \"./i18n/index.js\";\nimport {\n ICON_BUG,\n ICON_CHANGE,\n ICON_CHECK,\n ICON_CHEVRON_DOWN,\n ICON_CLOSE,\n ICON_DOT_OPEN,\n ICON_LAYERS,\n ICON_OTHER,\n ICON_QUESTION,\n ICON_SEARCH,\n ICON_TRASH,\n ICON_UNDO,\n} from \"./icons.js\";\nimport type { MarkerManager } from \"./markers.js\";\nimport { BulkActions } from \"./panel-bulk.js\";\nimport { DetailView } from \"./panel-detail.js\";\nimport { createPageGroupHeader, groupFeedbacksByPage, PanelSortControls, sortFeedbacks } from \"./panel-sort.js\";\nimport { PanelStats } from \"./panel-stats.js\";\nimport { focusCardByIndex, getFocusedCardIndex, KeyboardShortcuts } from \"./shortcuts.js\";\nimport { getTypeBgColor, getTypeColor, type ThemeColors } from \"./styles/theme.js\";\n\n/**\n * Side panel (400px) with feedback history, filters, search, stats,\n * sort/group, bulk actions, export, detail view, and keyboard shortcuts.\n *\n * Lives inside the Shadow DOM.\n * Glassmorphism: glass background, staggered card animations,\n * loading states, resolve feedback with disabled state.\n */\nexport class Panel {\n private root: HTMLElement;\n private listContainer: HTMLElement;\n private searchInput: HTMLInputElement;\n private closeBtn: HTMLButtonElement;\n private deleteAllBtn: HTMLButtonElement;\n private activeFilters = new Set<string>([\"all\"]);\n private typeDropdownBtn!: HTMLButtonElement;\n private typeDropdownContainer!: HTMLElement;\n private typeDropdownMenu: HTMLElement | null = null;\n private typeDropdownOutsideHandler: ((e: MouseEvent) => void) | null = null;\n private statusSegmented!: SegmentedControl<\"all\" | FeedbackStatus>;\n private typeOptions!: ReadonlyArray<{ value: string; label: string; icon: string; color: string; bg: string }>;\n private feedbacks: FeedbackResponse[] = [];\n private currentPage = 1;\n private totalFeedbacks = 0;\n private isLoadingMore = false;\n private isOpen = false;\n private searchTimeout: ReturnType<typeof setTimeout> | null = null;\n private loadController: AbortController | null = null;\n /** Tracks feedback IDs with in-flight mutations to prevent spam-click race conditions */\n private pendingMutations = new Set<string>();\n\n // New feature modules\n private readonly stats: PanelStats;\n private readonly sortControls: PanelSortControls;\n private readonly bulk: BulkActions;\n private readonly exportBtn: ExportButton;\n private readonly shortcuts: KeyboardShortcuts;\n private readonly detail: DetailView;\n private readonly shadowRoot: ShadowRoot;\n\n // i18n: t is shared with all submodules.\n\n // Page scope — supplied by launcher so the panel can scope its results to\n // the current page (or template) and filter markers accordingly.\n private readonly getScope: () => PageScope;\n private readonly scopeAnnotationsByUrl: boolean;\n /** \"this\" = current url, \"template\" = url pattern, \"all\" = no scope filter */\n private scopeSegmented!: SegmentedControl<\"this\" | \"template\" | \"all\">;\n /** Cached initial scope value — applied after construction in `buildScopeSegmented`. */\n private readonly initialScopeFilter: \"this\" | \"template\" | \"all\" = \"this\";\n\n constructor(\n shadowRoot: ShadowRoot,\n private readonly colors: ThemeColors,\n private readonly bus: EventBus<WidgetEvents>,\n private readonly client: WidgetClient,\n private readonly projectName: string,\n private readonly markers: MarkerManager,\n private readonly t: TFunction,\n private readonly locale: string,\n pageScopeOptions?: { getScope: () => PageScope; scopeAnnotationsByUrl: boolean },\n ) {\n this.shadowRoot = shadowRoot;\n this.getScope = pageScopeOptions?.getScope ?? (() => ({ url: window.location.pathname, urlPattern: null }));\n this.scopeAnnotationsByUrl = pageScopeOptions?.scopeAnnotationsByUrl ?? true;\n\n this.root = el(\"div\", { class: \"sp-panel\" });\n this.root.setAttribute(\"role\", \"complementary\");\n this.root.setAttribute(\"aria-label\", this.t(\"panel.ariaLabel\"));\n this.root.setAttribute(\"aria-hidden\", \"true\");\n\n // --- Header ---\n const header = el(\"div\", { class: \"sp-panel-header\" });\n const title = el(\"span\", { class: \"sp-panel-title\" });\n setText(title, this.t(\"panel.title\"));\n\n this.closeBtn = document.createElement(\"button\");\n this.closeBtn.className = \"sp-panel-close\";\n this.closeBtn.setAttribute(\"aria-label\", this.t(\"panel.close\"));\n this.closeBtn.appendChild(parseSvg(ICON_CLOSE));\n this.closeBtn.addEventListener(\"click\", () => this.close());\n\n this.deleteAllBtn = document.createElement(\"button\");\n this.deleteAllBtn.className = \"sp-btn-delete-all\";\n this.deleteAllBtn.setAttribute(\"aria-label\", this.t(\"panel.deleteAll\"));\n this.deleteAllBtn.appendChild(parseSvg(ICON_TRASH));\n const deleteAllLabel = document.createElement(\"span\");\n setText(deleteAllLabel, ` ${this.t(\"panel.deleteAll\")}`);\n this.deleteAllBtn.appendChild(deleteAllLabel);\n this.deleteAllBtn.addEventListener(\"click\", () => this.confirmDeleteAll());\n\n // Export button\n this.exportBtn = new ExportButton(colors, () => this.feedbacks, this.t);\n\n const headerRight = el(\"div\", { class: \"sp-panel-header-right\" });\n headerRight.appendChild(this.exportBtn.element);\n headerRight.appendChild(this.deleteAllBtn);\n headerRight.appendChild(this.closeBtn);\n\n header.appendChild(title);\n header.appendChild(headerRight);\n\n // --- Stats ---\n this.stats = new PanelStats(colors, this.t);\n\n // --- Filters ---\n const filters = el(\"div\", { class: \"sp-filters\" });\n\n // Search\n const searchWrap = el(\"div\", { class: \"sp-search-wrap\" });\n const searchIcon = parseSvg(ICON_SEARCH);\n searchIcon.setAttribute(\"class\", \"sp-search-icon\");\n this.searchInput = document.createElement(\"input\");\n this.searchInput.type = \"text\";\n this.searchInput.className = \"sp-search\";\n this.searchInput.placeholder = this.t(\"panel.search\");\n this.searchInput.setAttribute(\"aria-label\", this.t(\"panel.searchAria\"));\n this.searchInput.addEventListener(\"input\", () => {\n if (this.searchTimeout) clearTimeout(this.searchTimeout);\n this.searchTimeout = setTimeout(() => this.loadFeedbacks().catch(() => {}), 200);\n });\n searchWrap.appendChild(searchIcon);\n searchWrap.appendChild(this.searchInput);\n\n // Filter bar (type dropdown + status segmented + scope segmented).\n // The scope control gives users a fast way to widen results to \"this type\n // of page\" or \"all pages\" when the host provides a route template.\n const filterBar = el(\"div\", { class: \"sp-filter-bar\" });\n filterBar.appendChild(this.buildTypeDropdown());\n filterBar.appendChild(this.buildStatusSegmented());\n filterBar.appendChild(this.buildScopeSegmented());\n\n // Sort controls\n this.sortControls = new PanelSortControls(colors, () => this.renderList(), this.t);\n\n filters.appendChild(searchWrap);\n filters.appendChild(filterBar);\n filters.appendChild(this.sortControls.element);\n\n // --- List ---\n this.listContainer = el(\"div\", { class: \"sp-list\" });\n this.listContainer.setAttribute(\"role\", \"list\");\n this.listContainer.setAttribute(\"aria-label\", this.t(\"panel.feedbackList\"));\n\n // --- Bulk Actions ---\n this.bulk = new BulkActions(\n colors,\n {\n onResolve: (ids) => this.bulkResolve(ids),\n onDelete: (ids) => this.bulkDelete(ids),\n },\n this.t,\n );\n this.bulk.setListContainer(this.listContainer);\n\n // --- Detail View ---\n this.detail = new DetailView(\n colors,\n {\n onBack: () => this.detail.hide(),\n onResolve: async (fb) => {\n try {\n const newResolved = fb.status !== \"resolved\";\n await this.client.resolveFeedback(fb.id, newResolved);\n await this.loadFeedbacks();\n this.detail.hide();\n } catch (error) {\n // Surface the failure to the host (config.onError) like the list\n // and bulk paths do, then rethrow so DetailView restores its\n // buttons and stays open.\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n throw error;\n }\n },\n onDelete: async (fb) => {\n try {\n await this.client.deleteFeedback(fb.id);\n this.bus.emit(\"feedback:deleted\", fb.id);\n await this.loadFeedbacks();\n this.detail.hide();\n } catch (error) {\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n throw error;\n }\n },\n onGoToAnnotation: (fb) => {\n if (fb.annotations.length > 0) {\n const ann = fb.annotations[0];\n if (!ann) return;\n window.scrollTo({ left: ann.scrollX, top: ann.scrollY, behavior: \"smooth\" });\n this.markers.pinHighlight(fb);\n }\n },\n },\n this.t,\n locale,\n );\n\n // --- Keyboard Shortcuts ---\n this.shortcuts = new KeyboardShortcuts(\n colors,\n {\n onNavigate: (dir) => {\n const idx = getFocusedCardIndex(this.listContainer);\n focusCardByIndex(this.listContainer, dir === \"down\" ? idx + 1 : idx - 1);\n },\n onResolve: () => {\n const fb = this.getFocusedFeedback();\n if (fb && !this.pendingMutations.has(fb.id)) {\n const card = this.listContainer.querySelector<HTMLElement>(`[data-feedback-id=\"${CSS.escape(fb.id)}\"]`);\n const btn = card?.querySelector<HTMLButtonElement>('[data-action=\"resolve\"]');\n if (btn) this.toggleResolve(fb, btn).catch(() => {});\n }\n },\n onDelete: () => {\n const fb = this.getFocusedFeedback();\n if (fb && !this.pendingMutations.has(fb.id)) {\n const card = this.listContainer.querySelector<HTMLElement>(`[data-feedback-id=\"${CSS.escape(fb.id)}\"]`);\n const btn = card?.querySelector<HTMLButtonElement>('[data-action=\"delete\"]');\n if (btn) this.deleteFeedback(fb, btn).catch(() => {});\n }\n },\n onFocusSearch: () => this.searchInput.focus(),\n onToggleSelect: () => {\n const fb = this.getFocusedFeedback();\n if (fb) this.bulk.toggle(fb.id);\n },\n },\n this.t,\n );\n\n // --- Assemble DOM ---\n this.root.appendChild(header);\n this.root.appendChild(this.stats.element);\n this.root.appendChild(filters);\n this.root.appendChild(this.listContainer);\n this.root.appendChild(this.bulk.barElement);\n this.root.appendChild(this.detail.element);\n this.root.appendChild(this.shortcuts.helpOverlay);\n this.root.appendChild(this.shortcuts.hintButton);\n shadowRoot.appendChild(this.root);\n\n // --- Event delegation on listContainer ---\n\n this.onListClick = (e: Event) => {\n const target = e.target as Element;\n\n // Bulk checkbox clicks are handled by BulkActions, skip\n if (target.closest(\".sp-bulk-checkbox\")) return;\n\n // Action buttons (expand, resolve, delete)\n const actionEl = target.closest<HTMLElement>(\"[data-action]\");\n if (actionEl) {\n e.stopPropagation();\n const card = actionEl.closest<HTMLElement>(\".sp-card\");\n if (!card) return;\n const feedbackId = card.dataset.feedbackId;\n const feedback = this.feedbacks.find((f) => f.id === feedbackId);\n if (!feedback) return;\n\n const action = actionEl.dataset.action;\n if (action === \"expand\") {\n const message = card.querySelector<HTMLElement>(\".sp-card-message\");\n if (!message) return;\n const isExpanded = message.classList.toggle(\"sp-card-message--expanded\");\n setText(actionEl, isExpanded ? this.t(\"panel.showLess\") : this.t(\"panel.showMore\"));\n actionEl.setAttribute(\"aria-expanded\", String(isExpanded));\n } else if (action === \"resolve\") {\n if (this.pendingMutations.has(feedback.id)) return;\n const btn = actionEl as HTMLButtonElement;\n this.toggleResolve(feedback, btn).catch(() => {});\n } else if (action === \"delete\") {\n if (this.pendingMutations.has(feedback.id)) return;\n const btn = actionEl as HTMLButtonElement;\n this.deleteFeedback(feedback, btn).catch(() => {});\n }\n return;\n }\n\n // Card click → open detail view\n const card = target.closest<HTMLElement>(\".sp-card\");\n if (card) {\n const feedbackId = card.dataset.feedbackId;\n const feedback = this.feedbacks.find((f) => f.id === feedbackId);\n if (feedback) {\n const number = this.feedbacks.indexOf(feedback) + 1;\n this.detail.show(feedback, number);\n }\n }\n };\n this.listContainer.addEventListener(\"click\", this.onListClick);\n\n this.onListKeydown = (e: Event) => {\n const ke = e as KeyboardEvent;\n if (ke.key !== \"Enter\" && ke.key !== \" \") return;\n const target = ke.target as Element;\n const card = target.closest<HTMLElement>(\".sp-card\");\n // Only activate if the card itself is focused, not a button inside it\n if (!card || target !== card) return;\n ke.preventDefault();\n const feedbackId = card.dataset.feedbackId;\n const feedback = this.feedbacks.find((f) => f.id === feedbackId);\n if (feedback) {\n const number = this.feedbacks.indexOf(feedback) + 1;\n this.detail.show(feedback, number);\n }\n };\n this.listContainer.addEventListener(\"keydown\", this.onListKeydown);\n\n // mouseover/mouseout bubble (unlike mouseenter/mouseleave), enabling delegation\n this.onListMouseover = (e: Event) => {\n const target = (e as MouseEvent).target as Element;\n const card = target.closest<HTMLElement>(\".sp-card\");\n if (!card) return;\n const feedbackId = card.dataset.feedbackId;\n if (feedbackId) this.markers.highlight(feedbackId);\n };\n this.listContainer.addEventListener(\"mouseover\", this.onListMouseover);\n\n this.onListMouseout = (e: Event) => {\n const target = (e as MouseEvent).relatedTarget as Element | null;\n // Only clear highlight when leaving all cards (relatedTarget is outside listContainer)\n if (target && this.listContainer.contains(target)) return;\n this.markers.highlight(\"\");\n };\n this.listContainer.addEventListener(\"mouseout\", this.onListMouseout);\n\n // Events\n this.bus.on(\"panel:toggle\", (open) => {\n open ? this.open() : this.close();\n });\n\n // Keyboard handling: Escape to close + focus trap\n shadowRoot.addEventListener(\"keydown\", (e) => {\n const ke = e as KeyboardEvent;\n if (ke.key === \"Escape\" && this.isOpen) {\n // If detail view is open, close it instead\n if (this.detail.isVisible) {\n this.detail.hide();\n return;\n }\n this.close();\n return;\n }\n if (ke.key === \"Tab\" && this.isOpen) {\n // Filter out non-tabbable elements: those hidden via `display: none`\n // (either on themselves or any ancestor up to this.root) and elements\n // explicitly disabled. Without this filter, the trap can jump to a\n // button inside a closed detail view and effectively swallow the Tab\n // key. We use a walk of style.display rather than `offsetParent`\n // because the latter is unreliable in jsdom (always null without\n // layout) and breaks unit tests.\n const isVisible = (el: HTMLElement): boolean => {\n let cur: HTMLElement | null = el;\n while (cur && cur !== this.root) {\n if (cur.style.display === \"none\") return false;\n cur = cur.parentElement;\n }\n return true;\n };\n const focusable = Array.from(\n this.root.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])',\n ),\n ).filter((el) => isVisible(el) && !el.hasAttribute(\"disabled\"));\n if (focusable.length === 0) return;\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n if (!first || !last) return;\n const active = (shadowRoot as ShadowRoot).activeElement;\n if (ke.shiftKey && active === first) {\n ke.preventDefault();\n last.focus();\n } else if (!ke.shiftKey && active === last) {\n ke.preventDefault();\n first.focus();\n }\n }\n });\n\n // Listen for marker clicks\n this.onMarkerClick = ((e: CustomEvent) => {\n this.scrollToFeedback(e.detail.feedbackId);\n }) as EventListener;\n document.addEventListener(\"sp-marker-click\", this.onMarkerClick);\n }\n\n private onMarkerClick: EventListener;\n private onListClick: (e: Event) => void;\n private onListKeydown: (e: Event) => void;\n private onListMouseover: (e: Event) => void;\n private onListMouseout: (e: Event) => void;\n\n async open(): Promise<void> {\n if (this.isOpen) return;\n this.isOpen = true;\n this.root.classList.add(\"sp-panel--open\");\n this.root.setAttribute(\"aria-hidden\", \"false\");\n this.bus.emit(\"open\");\n this.shortcuts.enable(this.shadowRoot);\n await this.loadFeedbacks();\n // Move focus into the panel (search input or close button)\n requestAnimationFrame(() => {\n if (this.searchInput) {\n this.searchInput.focus();\n } else {\n this.closeBtn.focus();\n }\n });\n }\n\n close(): void {\n if (!this.isOpen) return;\n this.isOpen = false;\n this.root.classList.remove(\"sp-panel--open\");\n this.root.setAttribute(\"aria-hidden\", \"true\");\n this.bus.emit(\"close\");\n this.shortcuts.disable();\n this.detail.hide();\n // Restore focus to the FAB\n const fab = (this.root.getRootNode() as ShadowRoot).querySelector<HTMLButtonElement>(\".sp-fab\");\n fab?.focus();\n }\n\n private showLoading(): void {\n this.listContainer.replaceChildren();\n const loading = el(\"div\", { class: \"sp-loading\" });\n loading.setAttribute(\"role\", \"status\");\n loading.setAttribute(\"aria-live\", \"polite\");\n loading.setAttribute(\"aria-label\", this.t(\"panel.loading\"));\n const spinner = el(\"div\", { class: \"sp-spinner\" });\n loading.appendChild(spinner);\n this.listContainer.appendChild(loading);\n }\n\n private showError(): void {\n this.listContainer.replaceChildren();\n const empty = el(\"div\", { class: \"sp-empty\" });\n empty.setAttribute(\"role\", \"status\");\n empty.setAttribute(\"aria-live\", \"polite\");\n const text = el(\"div\", { class: \"sp-empty-text\" });\n setText(text, this.t(\"panel.loadError\"));\n const retryBtn = document.createElement(\"button\");\n retryBtn.className = \"sp-btn-ghost\";\n retryBtn.style.marginTop = \"8px\";\n setText(retryBtn, this.t(\"panel.retry\"));\n retryBtn.addEventListener(\"click\", () => this.loadFeedbacks().catch(() => {}));\n empty.appendChild(text);\n empty.appendChild(retryBtn);\n this.listContainer.appendChild(empty);\n }\n\n private async loadFeedbacks(): Promise<void> {\n // Cancel any in-flight request to prevent stale responses from overwriting newer results\n this.loadController?.abort();\n this.loadController = new AbortController();\n const { signal } = this.loadController;\n\n // Reset to page 1 on fresh load (filter/search change)\n this.currentPage = 1;\n\n const search = this.searchInput.value.trim() || undefined;\n const typeFilter = this.activeFilters.has(\"all\") ? undefined : (Array.from(this.activeFilters)[0] as FeedbackType);\n const currentStatus = this.statusSegmented.value;\n const statusFilter = currentStatus === \"all\" ? undefined : currentStatus;\n\n const scope = this.getScope();\n // Refresh scope-filter button visibility based on current scope (SPA nav).\n this.syncScopeAvailability();\n const currentScope = this.scopeSegmented.value;\n const options: GetFeedbacksOptions & { page: number; limit: number } = {\n page: 1,\n limit: PAGE_SIZE,\n };\n if (typeFilter) options.type = typeFilter;\n if (statusFilter) options.status = statusFilter;\n if (search) options.search = search;\n if (currentScope === \"this\") {\n options.url = scope.url;\n } else if (currentScope === \"template\" && scope.urlPattern) {\n options.urlPattern = scope.urlPattern;\n }\n\n // Only show spinner on first load (empty list) — otherwise keep current content visible\n const hasContent = this.feedbacks.length > 0;\n if (!hasContent) this.showLoading();\n\n try {\n const { feedbacks, total } = await this.client.getFeedbacks(this.projectName, options);\n if (signal.aborted) return; // Stale response — a newer request superseded this one\n this.feedbacks = feedbacks;\n this.totalFeedbacks = total;\n this.stats.update(feedbacks, total);\n this.bulk.reset();\n this.renderList();\n // Markers always render only the current-URL slice — even when the panel\n // shows a wider scope (\"template\" or \"all\"), markers stay strictly local\n // so the user never sees out-of-context dots on the page.\n const markerFeedbacks = this.scopeAnnotationsByUrl ? feedbacks.filter((f) => f.url === scope.url) : feedbacks;\n this.markers.render(markerFeedbacks);\n } catch (error) {\n if (signal.aborted) return; // Expected abort, not a real error\n if (!hasContent) this.showError();\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n private async loadMoreFeedbacks(): Promise<void> {\n if (this.isLoadingMore) return;\n this.isLoadingMore = true;\n\n // Capture current controller — if loadFeedbacks() runs while we're in-flight,\n // it replaces the controller, signaling that our results are stale.\n const controller = this.loadController;\n\n const nextPage = this.currentPage + 1;\n const search = this.searchInput.value.trim() || undefined;\n const typeFilter = this.activeFilters.has(\"all\") ? undefined : (Array.from(this.activeFilters)[0] as FeedbackType);\n const currentStatus = this.statusSegmented.value;\n const statusFilter = currentStatus === \"all\" ? undefined : currentStatus;\n\n const scope = this.getScope();\n const currentScope = this.scopeSegmented.value;\n const options: GetFeedbacksOptions & { page: number; limit: number } = {\n page: nextPage,\n limit: PAGE_SIZE,\n };\n if (typeFilter) options.type = typeFilter;\n if (statusFilter) options.status = statusFilter;\n if (search) options.search = search;\n if (currentScope === \"this\") {\n options.url = scope.url;\n } else if (currentScope === \"template\" && scope.urlPattern) {\n options.urlPattern = scope.urlPattern;\n }\n\n // Show spinner on the \"Load more\" button\n const loadMoreBtn = this.listContainer.querySelector<HTMLButtonElement>(\".sp-btn-load-more\");\n let restoreBtn: (() => void) | undefined;\n if (loadMoreBtn) restoreBtn = setButtonLoading(loadMoreBtn);\n\n try {\n const { feedbacks, total } = await this.client.getFeedbacks(this.projectName, options);\n if (controller !== this.loadController) return; // Filter/search changed — discard stale page\n this.currentPage = nextPage;\n this.totalFeedbacks = total;\n this.feedbacks = [...this.feedbacks, ...feedbacks];\n this.stats.update(this.feedbacks, total);\n this.renderList();\n const markerFeedbacks = this.scopeAnnotationsByUrl\n ? this.feedbacks.filter((f) => f.url === scope.url)\n : this.feedbacks;\n this.markers.render(markerFeedbacks);\n } catch (error) {\n if (restoreBtn) restoreBtn();\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n } finally {\n this.isLoadingMore = false;\n }\n }\n\n private renderList(): void {\n this.listContainer.replaceChildren();\n\n if (this.feedbacks.length === 0) {\n const empty = el(\"div\", { class: \"sp-empty\" });\n empty.setAttribute(\"role\", \"status\");\n empty.setAttribute(\"aria-live\", \"polite\");\n const emptyText = el(\"div\", { class: \"sp-empty-text\" });\n setText(emptyText, this.t(\"panel.empty\"));\n empty.appendChild(emptyText);\n this.listContainer.appendChild(empty);\n return;\n }\n\n // Apply sorting\n const sorted = sortFeedbacks(this.feedbacks, this.sortControls.sortMode);\n\n // Select all bar\n const feedbackIds = sorted.map((f) => f.id);\n const selectAllBar = this.bulk.createSelectAllBar(feedbackIds, this.t(\"bulk.selectAll\"));\n this.listContainer.appendChild(selectAllBar);\n\n if (this.sortControls.groupByPage) {\n // Group by page rendering\n const groups = groupFeedbacksByPage(sorted);\n let globalIndex = 0;\n for (const [pagePath, groupFeedbacks] of groups) {\n const groupHeader = createPageGroupHeader(pagePath, groupFeedbacks.length, this.colors);\n this.listContainer.appendChild(groupHeader);\n\n const groupContent = el(\"div\", { class: \"sp-group-content\" });\n for (const feedback of groupFeedbacks) {\n const card = this.createCard(feedback, globalIndex + 1);\n card.style.setProperty(\"--sp-card-i\", String(globalIndex));\n groupContent.appendChild(card);\n globalIndex++;\n }\n this.listContainer.appendChild(groupContent);\n }\n } else {\n // Flat list rendering\n sorted.forEach((feedback, index) => {\n const card = this.createCard(feedback, index + 1);\n card.style.setProperty(\"--sp-card-i\", String(index));\n this.listContainer.appendChild(card);\n });\n }\n\n // \"Load more\" button when there are remaining feedbacks\n const remaining = this.totalFeedbacks - this.feedbacks.length;\n if (remaining > 0) {\n const loadMoreWrap = el(\"div\", { class: \"sp-load-more-wrap\" });\n const loadMoreBtn = document.createElement(\"button\");\n loadMoreBtn.className = \"sp-btn-ghost sp-btn-load-more\";\n setText(loadMoreBtn, this.t(\"panel.loadMore\").replace(\"{remaining}\", String(remaining)));\n loadMoreBtn.addEventListener(\"click\", () => this.loadMoreFeedbacks().catch(() => {}));\n loadMoreWrap.appendChild(loadMoreBtn);\n this.listContainer.appendChild(loadMoreWrap);\n }\n }\n\n private createCard(feedback: FeedbackResponse, number: number): HTMLElement {\n const isResolved = feedback.status === \"resolved\";\n const typeColor = getTypeColor(feedback.type, this.colors);\n\n const card = el(\"div\", {\n class: `sp-card ${isResolved ? \"sp-card--resolved\" : \"\"}`,\n });\n card.setAttribute(\"role\", \"listitem\");\n card.setAttribute(\"tabindex\", \"0\");\n card.setAttribute(\n \"aria-label\",\n `Feedback #${number}: ${getTypeLabel(feedback.type, this.t)} — ${feedback.message.slice(0, 80)}`,\n );\n card.dataset.feedbackId = feedback.id;\n\n // Color bar\n const bar = el(\"div\", { class: \"sp-card-bar\" });\n bar.style.background = isResolved ? \"#9ca3af\" : typeColor;\n\n // Body\n const body = el(\"div\", { class: \"sp-card-body\" });\n\n // Header: checkbox + #number + badge + date\n const header = el(\"div\", { class: \"sp-card-header\" });\n\n // Bulk checkbox — inline in the header row\n const checkbox = this.bulk.createCheckbox(feedback.id);\n header.appendChild(checkbox);\n\n const num = el(\"span\", { class: \"sp-card-number\" });\n setText(num, `#${number}`);\n\n const badge = el(\"span\", { class: \"sp-badge\" });\n const typeBg = getTypeBgColor(feedback.type, this.colors);\n badge.style.background = typeBg;\n badge.style.color = typeColor;\n setText(badge, getTypeLabel(feedback.type, this.t));\n\n const date = el(\"span\", { class: \"sp-card-date\" });\n setText(date, formatRelativeDate(feedback.createdAt, this.locale));\n\n header.appendChild(num);\n header.appendChild(badge);\n header.appendChild(date);\n\n // Message\n const message = el(\"div\", { class: \"sp-card-message\" });\n setText(message, feedback.message);\n\n // Expand button\n const expandBtn = document.createElement(\"button\");\n expandBtn.className = \"sp-card-expand\";\n expandBtn.dataset.action = \"expand\";\n setText(expandBtn, this.t(\"panel.showMore\"));\n expandBtn.style.display = \"none\";\n expandBtn.setAttribute(\"aria-expanded\", \"false\");\n\n // Check if text is clamped (after render)\n requestAnimationFrame(() => {\n if (message.scrollHeight > message.clientHeight) {\n expandBtn.style.display = \"block\";\n }\n });\n\n // Footer: resolve button\n const footer = el(\"div\", { class: \"sp-card-footer\" });\n\n const resolveBtn = document.createElement(\"button\");\n resolveBtn.className = \"sp-btn-resolve\";\n resolveBtn.dataset.action = \"resolve\";\n if (isResolved) {\n resolveBtn.appendChild(parseSvg(ICON_UNDO));\n const span = document.createElement(\"span\");\n setText(span, ` ${this.t(\"panel.reopen\")}`);\n resolveBtn.appendChild(span);\n } else {\n resolveBtn.appendChild(parseSvg(ICON_CHECK));\n const span = document.createElement(\"span\");\n setText(span, ` ${this.t(\"panel.resolve\")}`);\n resolveBtn.appendChild(span);\n }\n\n const deleteBtn = document.createElement(\"button\");\n deleteBtn.className = \"sp-btn-delete\";\n deleteBtn.dataset.action = \"delete\";\n deleteBtn.appendChild(parseSvg(ICON_TRASH));\n const deleteBtnLabel = document.createElement(\"span\");\n setText(deleteBtnLabel, ` ${this.t(\"panel.delete\")}`);\n deleteBtn.appendChild(deleteBtnLabel);\n\n footer.appendChild(resolveBtn);\n footer.appendChild(deleteBtn);\n\n body.appendChild(header);\n body.appendChild(message);\n body.appendChild(expandBtn);\n body.appendChild(footer);\n\n card.appendChild(bar);\n card.appendChild(body);\n\n return card;\n }\n\n // ---------------------------------------------------------------------------\n // Bulk operations\n // ---------------------------------------------------------------------------\n\n private async bulkResolve(ids: string[]): Promise<void> {\n try {\n await Promise.all(ids.map((id) => this.client.resolveFeedback(id, true)));\n await this.loadFeedbacks();\n } catch (error) {\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n throw error;\n }\n }\n\n private async bulkDelete(ids: string[]): Promise<void> {\n try {\n await Promise.all(ids.map((id) => this.client.deleteFeedback(id)));\n for (const id of ids) this.bus.emit(\"feedback:deleted\", id);\n await this.loadFeedbacks();\n } catch (error) {\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n throw error;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Existing methods (preserved)\n // ---------------------------------------------------------------------------\n\n private async confirmDeleteAll(): Promise<void> {\n const confirmed = await this.showConfirmDialog(\n this.t(\"panel.deleteAllConfirmTitle\"),\n this.t(\"panel.deleteAllConfirmMessage\"),\n );\n if (!confirmed) return;\n\n this.deleteAllBtn.disabled = true;\n try {\n await this.client.deleteAllFeedbacks(this.projectName);\n this.bus.emit(\"feedback:all-deleted\");\n await this.loadFeedbacks();\n } catch (error) {\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n } finally {\n this.deleteAllBtn.disabled = false;\n }\n }\n\n private showConfirmDialog(title: string, message: string): Promise<boolean> {\n return new Promise((resolve) => {\n const backdrop = el(\"div\", { class: \"sp-confirm-backdrop\" });\n\n const titleId = `sp-confirm-title-${Date.now()}`;\n const messageId = `sp-confirm-msg-${Date.now()}`;\n\n const dialog = el(\"div\", { class: \"sp-confirm-dialog\" });\n dialog.setAttribute(\"role\", \"alertdialog\");\n dialog.setAttribute(\"aria-modal\", \"true\");\n dialog.setAttribute(\"aria-labelledby\", titleId);\n dialog.setAttribute(\"aria-describedby\", messageId);\n\n const titleEl = el(\"div\", { class: \"sp-confirm-title\" });\n titleEl.id = titleId;\n setText(titleEl, title);\n\n const messageEl = el(\"div\", { class: \"sp-confirm-message\" });\n messageEl.id = messageId;\n setText(messageEl, message);\n\n const btnRow = el(\"div\", { class: \"sp-confirm-actions\" });\n\n const cancelBtn = document.createElement(\"button\");\n cancelBtn.type = \"button\";\n cancelBtn.className = \"sp-btn-ghost\";\n setText(cancelBtn, this.t(\"panel.cancel\"));\n\n const confirmBtn = document.createElement(\"button\");\n confirmBtn.type = \"button\";\n confirmBtn.className = \"sp-btn-danger\";\n setText(confirmBtn, this.t(\"panel.confirmDelete\"));\n\n let closed = false;\n const close = (result: boolean) => {\n if (closed) return;\n closed = true;\n backdrop.removeEventListener(\"keydown\", onKeydown);\n backdrop.style.opacity = \"0\";\n dialog.style.transform = \"translateY(8px) scale(0.97)\";\n setTimeout(() => {\n backdrop.remove();\n resolve(result);\n }, 200);\n };\n\n // Focus trap: Tab cycles between cancel and confirm\n const onKeydown = (e: Event) => {\n const ke = e as KeyboardEvent;\n if (ke.key === \"Escape\") {\n close(false);\n return;\n }\n if (ke.key === \"Tab\") {\n ke.preventDefault();\n const active = (backdrop.getRootNode() as ShadowRoot).activeElement;\n if (active === cancelBtn) {\n confirmBtn.focus();\n } else {\n cancelBtn.focus();\n }\n }\n };\n backdrop.addEventListener(\"keydown\", onKeydown);\n\n cancelBtn.addEventListener(\"click\", () => close(false));\n confirmBtn.addEventListener(\"click\", () => close(true));\n backdrop.addEventListener(\"click\", (e) => {\n if (e.target === backdrop) close(false);\n });\n\n btnRow.appendChild(cancelBtn);\n btnRow.appendChild(confirmBtn);\n dialog.appendChild(titleEl);\n dialog.appendChild(messageEl);\n dialog.appendChild(btnRow);\n backdrop.appendChild(dialog);\n\n this.root.getRootNode() instanceof ShadowRoot\n ? (this.root.getRootNode() as ShadowRoot).appendChild(backdrop)\n : this.root.appendChild(backdrop);\n\n requestAnimationFrame(() => {\n backdrop.style.opacity = \"1\";\n dialog.style.transform = \"translateY(0) scale(1)\";\n cancelBtn.focus();\n });\n });\n }\n\n private async deleteFeedback(feedback: FeedbackResponse, btn: HTMLButtonElement): Promise<void> {\n this.pendingMutations.add(feedback.id);\n const restore = setButtonLoading(btn);\n try {\n await this.client.deleteFeedback(feedback.id);\n this.bus.emit(\"feedback:deleted\", feedback.id);\n await this.loadFeedbacks();\n } catch (error) {\n restore();\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n } finally {\n this.pendingMutations.delete(feedback.id);\n }\n }\n\n private async toggleResolve(feedback: FeedbackResponse, btn: HTMLButtonElement): Promise<void> {\n this.pendingMutations.add(feedback.id);\n const restore = setButtonLoading(btn);\n try {\n const newResolved = feedback.status !== \"resolved\";\n await this.client.resolveFeedback(feedback.id, newResolved);\n await this.loadFeedbacks();\n } catch (error) {\n restore();\n this.bus.emit(\"feedback:error\", error instanceof Error ? error : new Error(String(error)));\n } finally {\n this.pendingMutations.delete(feedback.id);\n }\n }\n\n private buildTypeDropdown(): HTMLElement {\n this.typeOptions = [\n {\n value: \"all\",\n label: this.t(\"panel.filterAll\"),\n icon: ICON_LAYERS,\n color: this.colors.accent,\n bg: this.colors.accentLight,\n },\n {\n value: \"question\",\n label: this.t(\"type.question\"),\n icon: ICON_QUESTION,\n color: this.colors.typeQuestion,\n bg: this.colors.typeQuestionBg,\n },\n {\n value: \"change\",\n label: this.t(\"type.change\"),\n icon: ICON_CHANGE,\n color: this.colors.typeChange,\n bg: this.colors.typeChangeBg,\n },\n {\n value: \"bug\",\n label: this.t(\"type.bug\"),\n icon: ICON_BUG,\n color: this.colors.typeBug,\n bg: this.colors.typeBugBg,\n },\n {\n value: \"other\",\n label: this.t(\"type.other\"),\n icon: ICON_OTHER,\n color: this.colors.typeOther,\n bg: this.colors.typeOtherBg,\n },\n ];\n\n this.typeDropdownContainer = el(\"div\", { class: \"sp-filter-dropdown\" });\n\n this.typeDropdownBtn = document.createElement(\"button\");\n this.typeDropdownBtn.type = \"button\";\n this.typeDropdownBtn.className = \"sp-filter-dropdown-btn\";\n this.typeDropdownBtn.setAttribute(\"aria-haspopup\", \"listbox\");\n this.typeDropdownBtn.setAttribute(\"aria-expanded\", \"false\");\n this.renderTypeDropdownTrigger();\n\n this.typeDropdownBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n if (this.typeDropdownMenu) this.closeTypeDropdown();\n else this.openTypeDropdown();\n });\n\n this.typeDropdownContainer.appendChild(this.typeDropdownBtn);\n return this.typeDropdownContainer;\n }\n\n private renderTypeDropdownTrigger(): void {\n const active = this.typeOptions.find((o) => this.activeFilters.has(o.value)) ?? this.typeOptions[0];\n if (!active) return;\n\n this.typeDropdownBtn.replaceChildren();\n this.typeDropdownBtn.style.setProperty(\"--sp-chip-color\", active.color);\n this.typeDropdownBtn.style.setProperty(\"--sp-chip-bg\", active.bg);\n this.typeDropdownBtn.dataset.filter = active.value;\n this.typeDropdownBtn.classList.toggle(\"sp-filter-dropdown-btn--filtered\", active.value !== \"all\");\n this.typeDropdownBtn.setAttribute(\"aria-label\", `${this.t(\"type.label\")}: ${active.label}`);\n\n const iconWrap = el(\"span\", { class: \"sp-filter-dropdown-btn__icon\" });\n iconWrap.appendChild(parseSvg(active.icon));\n this.typeDropdownBtn.appendChild(iconWrap);\n\n const labelWrap = el(\"span\", { class: \"sp-filter-dropdown-btn__label\" });\n const prefix = el(\"span\", { class: \"sp-filter-dropdown-btn__prefix\" });\n setText(prefix, this.t(\"type.label\"));\n const value = el(\"span\", { class: \"sp-filter-dropdown-btn__value\" });\n setText(value, active.label);\n labelWrap.appendChild(prefix);\n labelWrap.appendChild(value);\n this.typeDropdownBtn.appendChild(labelWrap);\n\n const chevron = el(\"span\", { class: \"sp-filter-dropdown-btn__chevron\" });\n chevron.appendChild(parseSvg(ICON_CHEVRON_DOWN));\n this.typeDropdownBtn.appendChild(chevron);\n }\n\n private openTypeDropdown(): void {\n this.typeDropdownMenu = el(\"div\", { class: \"sp-filter-dropdown-menu\" });\n this.typeDropdownMenu.setAttribute(\"role\", \"listbox\");\n this.typeDropdownMenu.setAttribute(\"aria-label\", this.t(\"type.label\"));\n this.typeDropdownBtn.setAttribute(\"aria-expanded\", \"true\");\n\n for (const option of this.typeOptions) {\n const item = document.createElement(\"button\");\n item.type = \"button\";\n const isActive = this.activeFilters.has(option.value);\n item.className = `sp-filter-dropdown-option${isActive ? \" sp-filter-dropdown-option--active\" : \"\"}`;\n item.style.setProperty(\"--sp-chip-color\", option.color);\n item.style.setProperty(\"--sp-chip-bg\", option.bg);\n item.dataset.filter = option.value;\n item.setAttribute(\"role\", \"option\");\n item.setAttribute(\"aria-selected\", String(isActive));\n\n const iconWrap = el(\"span\", { class: \"sp-filter-dropdown-option__icon\" });\n iconWrap.appendChild(parseSvg(option.icon));\n item.appendChild(iconWrap);\n\n const labelEl = el(\"span\", { class: \"sp-filter-dropdown-option__label\" });\n setText(labelEl, option.label);\n item.appendChild(labelEl);\n\n if (isActive) {\n const checkWrap = el(\"span\", { class: \"sp-filter-dropdown-option__check\" });\n checkWrap.appendChild(parseSvg(ICON_CHECK));\n item.appendChild(checkWrap);\n }\n\n item.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.selectTypeFilter(option.value);\n });\n\n this.typeDropdownMenu.appendChild(item);\n }\n\n this.typeDropdownContainer.appendChild(this.typeDropdownMenu);\n\n requestAnimationFrame(() => {\n this.typeDropdownOutsideHandler = (e: MouseEvent) => {\n if (this.typeDropdownMenu && !this.typeDropdownContainer.contains(e.target as Node)) {\n this.closeTypeDropdown();\n }\n };\n document.addEventListener(\"click\", this.typeDropdownOutsideHandler, true);\n });\n\n this.typeDropdownMenu.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Escape\") {\n this.closeTypeDropdown();\n this.typeDropdownBtn.focus();\n }\n });\n }\n\n private closeTypeDropdown(): void {\n if (this.typeDropdownMenu) {\n this.typeDropdownMenu.remove();\n this.typeDropdownMenu = null;\n }\n this.typeDropdownBtn.setAttribute(\"aria-expanded\", \"false\");\n if (this.typeDropdownOutsideHandler) {\n document.removeEventListener(\"click\", this.typeDropdownOutsideHandler, true);\n this.typeDropdownOutsideHandler = null;\n }\n }\n\n private selectTypeFilter(value: string): void {\n this.activeFilters.clear();\n this.activeFilters.add(value);\n this.renderTypeDropdownTrigger();\n this.closeTypeDropdown();\n this.loadFeedbacks().catch(() => {});\n }\n\n private buildStatusSegmented(): HTMLElement {\n this.statusSegmented = new SegmentedControl<\"all\" | FeedbackStatus>({\n options: [\n {\n value: \"all\",\n label: this.t(\"panel.statusAll\"),\n icon: ICON_LAYERS,\n color: this.colors.accent,\n bg: this.colors.accentLight,\n },\n {\n value: \"open\",\n label: this.t(\"panel.statusOpen\"),\n icon: ICON_DOT_OPEN,\n color: this.colors.statusOpen,\n bg: this.colors.statusOpenBg,\n },\n {\n value: \"resolved\",\n label: this.t(\"panel.statusResolved\"),\n icon: ICON_CHECK,\n color: this.colors.statusResolved,\n bg: this.colors.statusResolvedBg,\n },\n ],\n value: \"all\",\n onChange: () => {\n this.loadFeedbacks().catch(() => {});\n },\n ariaLabel: this.t(\"status.label\"),\n datasetKey: \"statusFilter\",\n modifierPrefix: \"sp-segmented__btn--\",\n });\n\n return this.statusSegmented.element;\n }\n\n /**\n * Build the page-scope segmented control: \"this page / this type / all\".\n * The \"this type\" button is hidden when the current scope has no urlPattern\n * (host did not provide one for this route). Visibility is refreshed on\n * every `loadFeedbacks` so SPA navigation stays consistent.\n */\n private buildScopeSegmented(): HTMLElement {\n this.scopeSegmented = new SegmentedControl<\"this\" | \"template\" | \"all\">({\n options: [\n { value: \"this\", label: this.t(\"scope.thisPage\") },\n { value: \"template\", label: this.t(\"scope.thisType\") },\n { value: \"all\", label: this.t(\"scope.all\") },\n ],\n value: this.initialScopeFilter,\n onChange: () => {\n this.loadFeedbacks().catch(() => {});\n },\n ariaLabel: this.t(\"scope.label\"),\n datasetKey: \"scopeFilter\",\n modifierPrefix: \"sp-segmented__btn--scope-\",\n extraClass: \"sp-segmented--scope\",\n });\n\n // Initial visibility — \"this type\" only meaningful when scope has urlPattern\n this.syncScopeAvailability();\n return this.scopeSegmented.element;\n }\n\n /**\n * Hide the \"this type\" button when the current scope has no urlPattern, and\n * fall back to \"this page\" if it was the active selection. Called on every\n * `loadFeedbacks` so SPA navigation stays consistent.\n */\n private syncScopeAvailability(): void {\n if (!this.scopeSegmented) return;\n const scope = this.getScope();\n const showTemplate = !!scope.urlPattern;\n this.scopeSegmented.setOptionVisible(\"template\", showTemplate);\n if (!showTemplate && this.scopeSegmented.value === \"template\") {\n this.scopeSegmented.select(\"this\");\n }\n }\n\n /** Get the focused feedback (for keyboard shortcuts) */\n private getFocusedFeedback(): FeedbackResponse | undefined {\n const idx = getFocusedCardIndex(this.listContainer);\n if (idx < 0) return undefined;\n const card = this.listContainer.querySelectorAll<HTMLElement>(\".sp-card\")[idx];\n if (!card) return undefined;\n return this.feedbacks.find((f) => f.id === card.dataset.feedbackId);\n }\n\n scrollToFeedback(feedbackId: string): void {\n const escapedId = CSS.escape(feedbackId);\n const card = this.listContainer.querySelector<HTMLElement>(`[data-feedback-id=\"${escapedId}\"]`);\n if (card) {\n card.scrollIntoView({ behavior: \"smooth\", block: \"center\" });\n card.classList.add(\"sp-anim-flash\");\n card.addEventListener(\n \"animationend\",\n () => {\n card.classList.remove(\"sp-anim-flash\");\n },\n { once: true },\n );\n }\n }\n\n /** Refresh the panel after a new feedback is submitted */\n async refresh(): Promise<void> {\n if (this.isOpen) {\n await this.loadFeedbacks();\n }\n }\n\n /** Whether the panel is currently open — used by the launcher to coordinate marker refreshes. */\n get isCurrentlyOpen(): boolean {\n return this.isOpen;\n }\n\n destroy(): void {\n this.loadController?.abort();\n if (this.searchTimeout) clearTimeout(this.searchTimeout);\n this.listContainer.removeEventListener(\"click\", this.onListClick);\n this.listContainer.removeEventListener(\"keydown\", this.onListKeydown);\n this.listContainer.removeEventListener(\"mouseover\", this.onListMouseover);\n this.listContainer.removeEventListener(\"mouseout\", this.onListMouseout);\n document.removeEventListener(\"sp-marker-click\", this.onMarkerClick);\n this.closeTypeDropdown();\n this.sortControls.destroy();\n this.bulk.destroy();\n this.exportBtn.destroy();\n this.shortcuts.destroy();\n this.detail.destroy();\n this.root.remove();\n }\n}\n"]}
|