@siteping/widget 0.10.6 → 0.10.8
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/chunk-4CK3N4YE.js +1796 -0
- package/dist/chunk-4CK3N4YE.js.map +1 -0
- package/dist/chunk-BJFC7TVL.cjs +1796 -0
- package/dist/chunk-BJFC7TVL.cjs.map +1 -0
- package/dist/chunk-EYISG4OI.js +1796 -0
- package/dist/chunk-EYISG4OI.js.map +1 -0
- package/dist/chunk-OK2KX3KN.cjs +1796 -0
- package/dist/chunk-OK2KX3KN.cjs.map +1 -0
- package/dist/email.d.cts +19 -0
- package/dist/email.d.ts +19 -0
- package/dist/filters.d.cts +29 -4
- package/dist/filters.d.ts +29 -4
- package/dist/i18n.d.cts +67 -0
- package/dist/i18n.d.ts +67 -0
- package/dist/index.cjs +50 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +152 -6
- package/dist/index.d.ts +152 -6
- package/dist/index.global.js +74 -74
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +50 -50
- package/dist/index.js.map +1 -1
- package/dist/panel-KCYUMYAI.cjs +2 -0
- package/dist/panel-KCYUMYAI.cjs.map +1 -0
- package/dist/panel-KV2AQHC2.js +2 -0
- package/dist/panel-KV2AQHC2.js.map +1 -0
- package/dist/panel-LYS3425X.cjs +2 -0
- package/dist/panel-LYS3425X.cjs.map +1 -0
- package/dist/panel-W2LHYGFS.js +2 -0
- package/dist/panel-W2LHYGFS.js.map +1 -0
- package/dist/react.cjs +50 -50
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +49 -49
- package/dist/react.js.map +1 -1
- package/dist/screenshot-storage.d.cts +5 -0
- package/dist/screenshot-storage.d.ts +5 -0
- package/dist/siteping-core.d.cts +11 -5
- package/dist/siteping-core.d.ts +11 -5
- package/dist/store-helpers.d.cts +96 -0
- package/dist/store-helpers.d.ts +96 -0
- package/dist/type-utils.d.cts +13 -44
- package/dist/type-utils.d.ts +13 -44
- package/dist/types.d.cts +149 -112
- package/dist/types.d.ts +149 -112
- package/dist/wire.d.cts +35 -0
- package/dist/wire.d.ts +35 -0
- package/package.json +4 -3
- package/dist/chunk-D2AVRF24.js +0 -1796
- package/dist/chunk-D2AVRF24.js.map +0 -1
- package/dist/chunk-GRKBXAGP.cjs +0 -1796
- package/dist/chunk-GRKBXAGP.cjs.map +0 -1
- package/dist/panel-LMVRKAQH.cjs +0 -2
- package/dist/panel-LMVRKAQH.cjs.map +0 -1
- package/dist/panel-OXUE7PJY.js +0 -2
- package/dist/panel-OXUE7PJY.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {e,g,n,o,m,u,F,U,da,v,aa,W,Y,ha,ea,fa,f,p,Z,_,$,Q,J,R,M as M$1,L,K,S,q,E,w,B,x,y,z,A,D,C}from'./chunk-4CK3N4YE.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=n("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$1=this.current===t.value;if(s.setAttribute("aria-checked",String(n$1)),s.tabIndex=n$1?0:-1,n$1&&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=n("span",{class:"sp-segmented__icon"});a.appendChild(m(t.icon)),s.appendChild(a);}let o$1=n("span",{class:"sp-segmented__label"});o(o$1,t.label),s.appendChild(o$1),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 me=e.filter(O=>!g(O)),ue=class{constructor(e,t,s,n$1,o$1,a,d,c,b){this.colors=t;this.bus=s;this.client=n$1;this.projectName=o$1;this.markers=a;this.t=d;this.locale=c;this.shadowRoot=e,this.getScope=b?.getScope??(()=>({url:window.location.pathname,urlPattern:null})),this.scopeAnnotationsByUrl=b?.scopeAnnotationsByUrl??true,this.root=n("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 m$1=n("div",{class:"sp-panel-header"}),p=n("span",{class:"sp-panel-title"});o(p,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(m(u)),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(m(F));let y=document.createElement("span");o(y,` ${this.t("panel.deleteAll")}`),this.deleteAllBtn.appendChild(y),this.deleteAllBtn.addEventListener("click",()=>this.confirmDeleteAll()),this.exportBtn=new U(t,()=>this.feedbacks,this.t);let C=n("div",{class:"sp-panel-header-right"});C.appendChild(this.exportBtn.element),C.appendChild(this.deleteAllBtn),C.appendChild(this.closeBtn),m$1.appendChild(p),m$1.appendChild(C),this.stats=new da(t,this.t);let k=n("div",{class:"sp-filters"}),T=n("div",{class:"sp-search-wrap"}),f=m(v);f.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);}),T.appendChild(f),T.appendChild(this.searchInput);let L=n("div",{class:"sp-filter-bar"});L.appendChild(this.buildTypeDropdown()),L.appendChild(this.buildStatusSegmented()),L.appendChild(this.buildScopeSegmented()),this.sortControls=new aa(t,()=>this.renderList(),this.t),k.appendChild(T),k.appendChild(L),k.appendChild(this.sortControls.element),this.listContainer=n("div",{class:"sp-list"}),this.listContainer.setAttribute("role","list"),this.listContainer.setAttribute("aria-label",this.t("panel.feedbackList")),this.bulk=new W(t,{onResolve:i=>this.bulkResolve(i),onDelete:i=>this.bulkDelete(i)},this.t),this.bulk.setListContainer(this.listContainer),this.detail=new Y(t,{onBack:()=>this.detail.hide(),onResolve:async i=>{try{let r=!g(i.status);await this.client.resolveFeedback(i.id,r),await this.loadFeedbacks(),this.detail.hide();}catch(r){throw this.bus.emit("feedback:error",r instanceof Error?r:new Error(String(r))),r}},onDelete:async i=>{try{await this.client.deleteFeedback(i.id),this.bus.emit("feedback:deleted",i.id),await this.loadFeedbacks(),this.detail.hide();}catch(r){throw this.bus.emit("feedback:error",r instanceof Error?r:new Error(String(r))),r}},onGoToAnnotation:i=>{if(i.annotations.length>0){let r=i.annotations[0];if(!r)return;window.scrollTo({left:r.scrollX,top:r.scrollY,behavior:"smooth"}),this.markers.pinHighlight(i);}}},this.t,c),this.shortcuts=new ha(t,{onNavigate:i=>{let r=ea(this.listContainer);fa(this.listContainer,i==="down"?r+1:r-1);},onResolve:()=>{let i=this.getFocusedFeedback();if(i&&!this.pendingMutations.has(i.id)){let u=this.listContainer.querySelector(`[data-feedback-id="${CSS.escape(i.id)}"]`)?.querySelector('[data-action="resolve"]');u&&this.toggleResolve(i,u).catch(()=>{});}},onDelete:()=>{let i=this.getFocusedFeedback();if(i&&!this.pendingMutations.has(i.id)){let u=this.listContainer.querySelector(`[data-feedback-id="${CSS.escape(i.id)}"]`)?.querySelector('[data-action="delete"]');u&&this.deleteFeedback(i,u).catch(()=>{});}},onFocusSearch:()=>this.searchInput.focus(),onToggleSelect:()=>{let i=this.getFocusedFeedback();i&&this.bulk.toggle(i.id);}},this.t),this.root.appendChild(m$1),this.root.appendChild(this.stats.element),this.root.appendChild(k),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 r=i.target;if(r.closest(".sp-bulk-checkbox"))return;let u=r.closest("[data-action]");if(u){i.stopPropagation();let A=u.closest(".sp-card");if(!A)return;let w=A.dataset.feedbackId,g=this.feedbacks.find(E=>E.id===w);if(!g)return;let B=u.dataset.action;if(B==="expand"){let E=A.querySelector(".sp-card-message");if(!E)return;let R=E.classList.toggle("sp-card-message--expanded");o(u,R?this.t("panel.showLess"):this.t("panel.showMore")),u.setAttribute("aria-expanded",String(R));}else if(B==="resolve"){if(this.pendingMutations.has(g.id))return;let E=u;this.toggleResolve(g,E).catch(()=>{});}else if(B==="delete"){if(this.pendingMutations.has(g.id))return;let E=u;this.deleteFeedback(g,E).catch(()=>{});}return}let v=r.closest(".sp-card");if(v){let A=v.dataset.feedbackId,w=this.feedbacks.find(g=>g.id===A);if(w){let g=this.feedbacks.indexOf(w)+1;this.detail.show(w,g);}}},this.listContainer.addEventListener("click",this.onListClick),this.onListKeydown=i=>{let r=i;if(r.key!=="Enter"&&r.key!==" ")return;let u=r.target,v=u.closest(".sp-card");if(!v||u!==v)return;r.preventDefault();let A=v.dataset.feedbackId,w=this.feedbacks.find(g=>g.id===A);if(w){let g=this.feedbacks.indexOf(w)+1;this.detail.show(w,g);}},this.listContainer.addEventListener("keydown",this.onListKeydown),this.onListMouseover=i=>{let u=i.target.closest(".sp-card");if(!u)return;let v=u.dataset.feedbackId;v&&this.markers.highlight(v);},this.listContainer.addEventListener("mouseover",this.onListMouseover),this.onListMouseout=i=>{let r=i.relatedTarget;r&&this.listContainer.contains(r)||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 r=i;if(r.key==="Escape"&&this.isOpen){if(this.detail.isVisible){this.detail.hide();return}this.close();return}if(r.key==="Tab"&&this.isOpen){let u=B=>{let E=B;for(;E&&E!==this.root;){if(E.style.display==="none")return false;E=E.parentElement;}return true},v=Array.from(this.root.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')).filter(B=>u(B)&&!B.hasAttribute("disabled"));if(v.length===0)return;let A=v[0],w=v[v.length-1];if(!A||!w)return;let g=e.activeElement;r.shiftKey&&g===A?(r.preventDefault(),w.focus()):!r.shiftKey&&g===w&&(r.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=n("div",{class:"sp-loading"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite"),e.setAttribute("aria-label",this.t("panel.loading"));let t=n("div",{class:"sp-spinner"});e.appendChild(t),this.listContainer.appendChild(e);}showError(){this.listContainer.replaceChildren();let e=n("div",{class:"sp-empty"});e.setAttribute("role","status"),e.setAttribute("aria-live","polite");let t=n("div",{class:"sp-empty-text"});o(t,this.t("panel.loadError"));let s=document.createElement("button");s.className="sp-btn-ghost",s.style.marginTop="8px",o(s,this.t("panel.retry")),s.addEventListener("click",()=>this.loadFeedbacks().catch(()=>{})),e.appendChild(t),e.appendChild(s),this.listContainer.appendChild(e);}statusBucket(e){if(e!=="all")return g(e)?f:me}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.statusBucket(this.statusSegmented.value),o=this.getScope();this.syncScopeAvailability();let a=this.scopeSegmented.value,d={page:1,limit:20};s&&(d.type=s),n&&(d.statuses=n),t&&(d.search=t),a==="this"?d.url=o.url:a==="template"&&o.urlPattern&&(d.urlPattern=o.urlPattern);let c=this.feedbacks.length>0;c||this.showLoading();try{let{feedbacks:b,total:m}=await this.client.getFeedbacks(this.projectName,d);if(e.aborted)return;this.feedbacks=b,this.totalFeedbacks=m,this.stats.update(b,m),this.bulk.reset(),this.renderList();let p=this.scopeAnnotationsByUrl?b.filter(y=>y.url===o.url):b;this.markers.render(p);}catch(b){if(e.aborted)return;c||this.showError(),this.bus.emit("feedback:error",b instanceof Error?b:new Error(String(b)));}}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.statusBucket(this.statusSegmented.value),a=this.getScope(),d=this.scopeSegmented.value,c={page:t,limit:20};n&&(c.type=n),o&&(c.statuses=o),s&&(c.search=s),d==="this"?c.url=a.url:d==="template"&&a.urlPattern&&(c.urlPattern=a.urlPattern);let b=this.listContainer.querySelector(".sp-btn-load-more"),m;b&&(m=p(b));try{let{feedbacks:p,total:y}=await this.client.getFeedbacks(this.projectName,c);if(e!==this.loadController)return;this.currentPage=t,this.totalFeedbacks=y,this.feedbacks=[...this.feedbacks,...p],this.stats.update(this.feedbacks,y),this.renderList();let C=this.scopeAnnotationsByUrl?this.feedbacks.filter(k=>k.url===a.url):this.feedbacks;this.markers.render(C);}catch(p){m&&m(),this.bus.emit("feedback:error",p instanceof Error?p:new Error(String(p)));}finally{this.isLoadingMore=false;}}renderList(){if(this.listContainer.replaceChildren(),this.feedbacks.length===0){let o$1=n("div",{class:"sp-empty"});o$1.setAttribute("role","status"),o$1.setAttribute("aria-live","polite");let a=n("div",{class:"sp-empty-text"});o(a,this.t("panel.empty")),o$1.appendChild(a),this.listContainer.appendChild(o$1);return}let e=Z(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=_(e),a=0;for(let[d,c]of o){let b=$(d,c.length,this.colors);this.listContainer.appendChild(b);let m=n("div",{class:"sp-group-content"});for(let p of c){let y=this.createCard(p,a+1);y.style.setProperty("--sp-card-i",String(a)),m.appendChild(y),a++;}this.listContainer.appendChild(m);}}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$1=this.totalFeedbacks-this.feedbacks.length;if(n$1>0){let o$1=n("div",{class:"sp-load-more-wrap"}),a=document.createElement("button");a.className="sp-btn-ghost sp-btn-load-more",o(a,Q(this.t,"panel.loadMore",{remaining:n$1})),a.addEventListener("click",()=>this.loadMoreFeedbacks().catch(()=>{})),o$1.appendChild(a),this.listContainer.appendChild(o$1);}}createCard(e,t){let s=g(e.status),n$1=J(e.type,this.colors),o$1=n("div",{class:`sp-card ${s?"sp-card--resolved":""}`});o$1.setAttribute("role","listitem"),o$1.setAttribute("tabindex","0"),o$1.setAttribute("aria-label",`Feedback #${t}: ${R(e.type,this.t)} \u2014 ${e.message.slice(0,80)}`),o$1.dataset.feedbackId=e.id;let a=n("div",{class:"sp-card-bar"});a.style.background=s?"#9ca3af":n$1;let d=n("div",{class:"sp-card-body"}),c=n("div",{class:"sp-card-header"}),b=this.bulk.createCheckbox(e.id);c.appendChild(b);let m$1=n("span",{class:"sp-card-number"});o(m$1,`#${t}`);let p=n("span",{class:"sp-badge"}),y=M$1(e.type,this.colors);p.style.background=y,p.style.color=n$1,o(p,R(e.type,this.t));let C=n("span",{class:"sp-badge sp-badge--status"});C.dataset.status=e.status,C.style.background=L(e.status,this.colors),C.style.color=K(e.status,this.colors),o(C,S(e.status,this.t));let k=n("span",{class:"sp-card-date"});o(k,q(e.createdAt,this.locale)),c.appendChild(m$1),c.appendChild(p),c.appendChild(C),c.appendChild(k);let T=n("div",{class:"sp-card-message"});o(T,e.message);let f=document.createElement("button");f.className="sp-card-expand",f.dataset.action="expand",o(f,this.t("panel.showMore")),f.style.display="none",f.setAttribute("aria-expanded","false"),requestAnimationFrame(()=>{T.scrollHeight>T.clientHeight&&(f.style.display="block");});let L$1=n("div",{class:"sp-card-footer"}),i=document.createElement("button");if(i.className="sp-btn-resolve",i.dataset.action="resolve",s){i.appendChild(m(E));let v=document.createElement("span");o(v,` ${this.t("panel.reopen")}`),i.appendChild(v);}else {i.appendChild(m(w));let v=document.createElement("span");o(v,` ${this.t("panel.resolve")}`),i.appendChild(v);}let r=document.createElement("button");r.className="sp-btn-delete",r.dataset.action="delete",r.appendChild(m(F));let u=document.createElement("span");return o(u,` ${this.t("panel.delete")}`),r.appendChild(u),L$1.appendChild(i),L$1.appendChild(r),d.appendChild(c),d.appendChild(T),d.appendChild(f),d.appendChild(L$1),o$1.appendChild(a),o$1.appendChild(d),o$1}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$1=n("div",{class:"sp-confirm-backdrop"}),o$1=`sp-confirm-title-${Date.now()}`,a=`sp-confirm-msg-${Date.now()}`,d=n("div",{class:"sp-confirm-dialog"});d.setAttribute("role","alertdialog"),d.setAttribute("aria-modal","true"),d.setAttribute("aria-labelledby",o$1),d.setAttribute("aria-describedby",a);let c=n("div",{class:"sp-confirm-title"});c.id=o$1,o(c,e);let b=n("div",{class:"sp-confirm-message"});b.id=a,o(b,t);let m=n("div",{class:"sp-confirm-actions"}),p=document.createElement("button");p.type="button",p.className="sp-btn-ghost",o(p,this.t("panel.cancel"));let y=document.createElement("button");y.type="button",y.className="sp-btn-danger",o(y,this.t("panel.confirmDelete"));let C=false,k=f=>{C||(C=true,n$1.removeEventListener("keydown",T),n$1.style.opacity="0",d.style.transform="translateY(8px) scale(0.97)",setTimeout(()=>{n$1.remove(),s(f);},200));},T=f=>{let L=f;if(L.key==="Escape"){k(false);return}L.key==="Tab"&&(L.preventDefault(),n$1.getRootNode().activeElement===p?y.focus():p.focus());};n$1.addEventListener("keydown",T),p.addEventListener("click",()=>k(false)),y.addEventListener("click",()=>k(true)),n$1.addEventListener("click",f=>{f.target===n$1&&k(false);}),m.appendChild(p),m.appendChild(y),d.appendChild(c),d.appendChild(b),d.appendChild(m),n$1.appendChild(d),this.root.getRootNode()instanceof ShadowRoot?this.root.getRootNode().appendChild(n$1):this.root.appendChild(n$1),requestAnimationFrame(()=>{n$1.style.opacity="1",d.style.transform="translateY(0) scale(1)",p.focus();});})}async deleteFeedback(e,t){this.pendingMutations.add(e.id);let s=p(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=p(t);try{let n=!g(e.status);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:B,color:this.colors.accent,bg:this.colors.accentLight},{value:"question",label:this.t("type.question"),icon:x,color:this.colors.typeQuestion,bg:this.colors.typeQuestionBg},{value:"change",label:this.t("type.change"),icon:y,color:this.colors.typeChange,bg:this.colors.typeChangeBg},{value:"bug",label:this.t("type.bug"),icon:z,color:this.colors.typeBug,bg:this.colors.typeBugBg},{value:"other",label:this.t("type.other"),icon:A,color:this.colors.typeOther,bg:this.colors.typeOtherBg}],this.typeDropdownContainer=n("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=n("span",{class:"sp-filter-dropdown-btn__icon"});t.appendChild(m(e.icon)),this.typeDropdownBtn.appendChild(t);let s=n("span",{class:"sp-filter-dropdown-btn__label"}),n$1=n("span",{class:"sp-filter-dropdown-btn__prefix"});o(n$1,this.t("type.label"));let o$1=n("span",{class:"sp-filter-dropdown-btn__value"});o(o$1,e.label),s.appendChild(n$1),s.appendChild(o$1),this.typeDropdownBtn.appendChild(s);let a=n("span",{class:"sp-filter-dropdown-btn__chevron"});a.appendChild(m(D)),this.typeDropdownBtn.appendChild(a);}openTypeDropdown(){this.typeDropdownMenu=n("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$1=n("span",{class:"sp-filter-dropdown-option__icon"});n$1.appendChild(m(e.icon)),t.appendChild(n$1);let o$1=n("span",{class:"sp-filter-dropdown-option__label"});if(o(o$1,e.label),t.appendChild(o$1),s){let a=n("span",{class:"sp-filter-dropdown-option__check"});a.appendChild(m(w)),t.appendChild(a);}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:B,color:this.colors.accent,bg:this.colors.accentLight},{value:"open",label:this.t("panel.statusOpen"),icon:C,color:this.colors.statusOpen,bg:this.colors.statusOpenBg},{value:"resolved",label:this.t("panel.statusResolved"),icon:w,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=ea(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{ue as Panel};//# sourceMappingURL=panel-W2LHYGFS.js.map
|
|
2
|
+
//# sourceMappingURL=panel-W2LHYGFS.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","OPEN_FEEDBACK_STATUSES","FEEDBACK_STATUSES","s","isClosedStatus","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","tab","CLOSED_FEEDBACK_STATUSES","signal","search","typeFilter","statuses","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","tWithParams","isResolved","typeColor","getTypeColor","getTypeLabel","bar","body","checkbox","num","badge","typeBg","getTypeBgColor","statusBadge","getStatusBgColor","getStatusColor","getStatusLabel","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-W2LHYGFS.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 {\n CLOSED_FEEDBACK_STATUSES,\n FEEDBACK_STATUSES,\n type FeedbackResponse,\n type FeedbackStatus,\n type FeedbackType,\n isClosedStatus,\n type PageScope,\n} 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 { getStatusLabel, getTypeLabel, type TFunction, tWithParams } 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 { getStatusBgColor, getStatusColor, getTypeBgColor, getTypeColor, type ThemeColors } from \"./styles/theme.js\";\n\n/** Non-terminal statuses — complement of `CLOSED_FEEDBACK_STATUSES`; backs the panel's \"Open\" tab bucket. */\nconst OPEN_FEEDBACK_STATUSES: readonly FeedbackStatus[] = FEEDBACK_STATUSES.filter((s) => !isClosedStatus(s));\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 // Client-facing binary action: closed statuses (resolved, wont_fix)\n // reopen, everything else (open, in_progress) resolves.\n const newResolved = !isClosedStatus(fb.status);\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 /**\n * Map a status tab value to the bucket of statuses it represents. The panel's\n * binary tabs use bucket semantics (matching markers / FAB badge / stats):\n * \"open\" covers open + in_progress, \"resolved\" covers resolved + wont_fix,\n * and \"all\" applies no status filter. Returns `undefined` when unfiltered.\n */\n private statusBucket(tab: \"all\" | FeedbackStatus): readonly FeedbackStatus[] | undefined {\n if (tab === \"all\") return undefined;\n return isClosedStatus(tab) ? CLOSED_FEEDBACK_STATUSES : OPEN_FEEDBACK_STATUSES;\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 statuses = this.statusBucket(this.statusSegmented.value);\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 (statuses) options.statuses = statuses;\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 statuses = this.statusBucket(this.statusSegmented.value);\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 (statuses) options.statuses = statuses;\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, tWithParams(this.t, \"panel.loadMore\", { 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 // Closed = terminal (resolved, wont_fix): muted card + \"Reopen\" action.\n const isResolved = isClosedStatus(feedback.status);\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 // Status badge — renders the record's actual status (open, in_progress,\n // resolved, wont_fix) even though panel actions stay binary.\n const statusBadge = el(\"span\", { class: \"sp-badge sp-badge--status\" });\n statusBadge.dataset.status = feedback.status;\n statusBadge.style.background = getStatusBgColor(feedback.status, this.colors);\n statusBadge.style.color = getStatusColor(feedback.status, this.colors);\n setText(statusBadge, getStatusLabel(feedback.status, 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(statusBadge);\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 // Closed statuses (resolved, wont_fix) reopen; open/in_progress resolve.\n const newResolved = !isClosedStatus(feedback.status);\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"]}
|