diff --git a/crates/context/assets/component-review.js b/crates/context/assets/component-review.js index c2e06b03d..49ac0b57b 100644 --- a/crates/context/assets/component-review.js +++ b/crates/context/assets/component-review.js @@ -92,14 +92,15 @@ `+ie+` .review-form:has(#feedback-form){max-height:75%;min-height:0;flex-shrink:1;display:flex;flex-direction:column;overflow:hidden;padding-top:8px} #feedback-form{display:flex;flex-direction:column;flex:1;min-height:0} -.feedback-fields{flex:1;min-height:0;overflow:auto;padding:3px} +/* Leave room inside the scrollport for the 2px focus ring and 3px offset. */ +.feedback-fields{flex:1;min-height:0;overflow:auto;padding:6px} .review-form:has(#feedback-form) .decision-notice{flex-shrink:0} .review-form:has(#feedback-form) .decisions{display:none} .feedback-actions{flex-shrink:0;position:static;background:var(--surface,var(--paper));padding:8px 0;margin-top:8px;box-shadow:0 -5px 8px -6px #24332838} .feedback-actions .shortcut-hint{flex-basis:auto;order:-1;margin-right:auto} .feedback-actions .primary{margin-left:0} @media(max-height:800px),(max-width:800px){.feedback-actions .shortcut-hint{display:none}.feedback-actions .primary{margin-left:auto}.review-form .feedback textarea{min-height:56px}.review-form:has(#feedback-form) .decision-notice{margin-bottom:4px}} -`;var ve={code:'',image:'',expand:'',compact:'',hideTray:'',showTray:'',next:'',mark:'',close:'',undo:'',external:'',zoom:''};function K(p){return``}var x=(p)=>p.replace(/[&<>"']/g,(e)=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[e]),D=(p)=>`${p*100}%`,O=(p)=>{let e=new URL(p,location.href);if(!["http:","https:"].includes(e.protocol))throw Error("Unsupported preview URL");return x(e.href)};function oe(p,e,a){let o=p.attachShadow({mode:"open"}),n=structuredClone(a.initialDraft??Si(e)),c=()=>[...e.components].sort((s,b)=>B(s,n,a.history).priority-B(b,n,a.history).priority),d=c().find((s)=>B(s,n,a.history).kind!=="approved")?.id??e.components[0]?.id,g=a.completed?"all":"attention",V=!1,J=!1,Q=a.completed??!1,si="",H={},M=!1,W=null,ne=/Mac|iPhone|iPad/.test(navigator.platform)?"⌘Enter":"Ctrl+Enter",L=!1,U=!1,k=!0,F=!1,y="comp",ji=y,_="fit",ei="checker",N=!1,R="isolated",fi,Hi="fit",T=null,X=null,oi=null,ci='',ai='',Mi=(s)=>`left:${D(s.x)};top:${D(s.y)};width:${D(s.w)};height:${D(s.h)}`;function ni(s){o.getElementById(s)?.focus({preventScroll:!0})}function re(s){let b=Pi(e,n,s);if(M=!b,b)d=b;if(y="component",N=!1,L=!1,_="fit",R="isolated",g==="approved")g="attention";h(),ni(M?"review-summary":H[d]?"feedback":"approve")}function bi(s){if(J||Q||N)return;let b=e.components.find((mi)=>mi.id===d);if(!b)return;let $=n.decisions[b.id],ri=$?.revision===b.revision?$:void 0;W={id:b.id,name:b.name,action:s,previous:$?{...$}:void 0};let ti=H[b.id]??ri;if(n.decisions[b.id]={revision:b.revision,action:s,feedback:s==="revise"?ti?.feedback??"":"",split:s==="revise"&&(ti?.split??!1)},delete H[b.id],F)k=!0,F=!1;re(b.id)}function pe(){if(J||Q||N)return;let s=e.components.find((ri)=>ri.id===d);if(!s)return;let b=n.decisions[s.id],$=b?.revision===s.revision?b:void 0;if(H[s.id]??={feedback:$?.feedback??"",split:$?.split??!1},k&&(o.querySelector(".workbench")?.clientHeight??0)<420)F=!0,k=!1;M=!1,h(),ni("feedback")}function qi(s){let b=`missing-${crypto.randomUUID()}`;n.missing.push({id:b,name:"Missing component",feedback:"",box:s}),n.inventoryConfirmed=!1,M=!1,d=b,y="component",V=!1,T=null,X=null,h(),o.querySelector("#missing-name")?.focus()}function h(){oi?.disconnect();let s=o.activeElement,b=s?.id,$=s?.dataset.select,ri=window.scrollX,ti=window.scrollY,mi=o.querySelector(".inventory")?.scrollLeft??0,xi=fi===d,ae=y==="component"&&(!xi||ji!==y);ji=y;let te=xi?o.querySelector(".inspection-content")?.scrollTop??0:0,xe=xi&&(o.querySelector(".changed-files")?.open??!1),Ei=o.querySelector(".pan-viewport"),Vi=fi===d&&Hi===_,le=Vi?Ei?.scrollLeft??0:0,de=Vi?Ei?.scrollTop??0:0;fi=d,Hi=_;let l=e.components.find((i)=>i.id===d),w=n.missing.find((i)=>i.id===d),Ji=l?.box??w?.box,Ni=l?e.components.indexOf(l)+1:e.components.length+n.missing.findIndex((i)=>i.id===d)+1,$i=l?n.decisions[l.id]:void 0,S=$i?.revision===l?.revision?$i:void 0,wi=l?H[l.id]:void 0,P=Object.keys(H).length>0,he=l?!e.components.some((i)=>i.id!==l.id&&B(i,n).kind==="pending"):!1,Gi=W?`
${x(W.name)} ${W.action==="approve"?"approved":"flagged for repair"}.
`:"",u=hi(e,n),v=a.history,q=l?di(l.id,v):void 0,C=v?.packet.components.find((i)=>i.id===l?.id),Y=N&&!!C,t=Y?C:l,E=Y?v.packet:e,Ki=Object.values(v?.changes??{}),Qi=Ki.filter((i)=>i.kind==="changed").length,Wi=Ki.filter((i)=>i.kind==="added").length,ui=e.components.filter((i)=>B(i,n,v).kind==="approved"&&di(i.id,v).carried).length,pi=(i)=>B(i,n,v),ge=e.components.length-u.approved+n.missing.length,_i=(g==="attention"?c():e.components).filter((i)=>g==="all"||pi(i).kind==="approved"===(g==="approved")),se=[u.revisions+n.missing.length?`${u.revisions+n.missing.length} feedback ready`:"",ui?`${ui} ${ui===1?"approval":"approvals"} kept`:"",Qi?`${Qi} changed`:"",Wi?`${Wi} added`:"",v?.removed.length?`${v.removed.length} removed`:""].filter(Boolean).join(" · "),fe=si||(P?"Save or cancel your open feedback before sending.":Q?a.preview?"Preview submitted. No run changed.":"Review submitted.":u.hasFeedback?"Ready to send for corrections.":u.pending?`${u.pending} left to review`:!n.inventoryConfirmed?"Confirm the map is complete.":"Ready to continue."),Z=t?gi(t):null,Ti=t?.preview.kind==="image"&&!Z?.code,I=!!(t?.context&&R==="context"),Xi=t&&(I?t.context?.kind!=="image":t.preview.kind==="page"),Yi=I&&t?.context?t.context.url:t?.preview.url,ce=Z?.code?`${Z.label} · ${Z.captured?"captured from code":"live preview"}`:t?.material?`${t.material.alpha==="transparent"?"Transparent":t.material.alpha==="opaque"?"Opaque":"Transparency unverified"} ${t.material.format}`:"Raster · transparency unverified";if(o.innerHTML=`
+`;var ve={code:'',image:'',expand:'',compact:'',hideTray:'',showTray:'',next:'',mark:'',close:'',undo:'',external:'',zoom:''};function K(p){return``}var x=(p)=>p.replace(/[&<>"']/g,(e)=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[e]),D=(p)=>`${p*100}%`,O=(p)=>{let e=new URL(p,location.href);if(!["http:","https:"].includes(e.protocol))throw Error("Unsupported preview URL");return x(e.href)};function oe(p,e,a){let o=p.attachShadow({mode:"open"}),n=structuredClone(a.initialDraft??Si(e)),c=()=>[...e.components].sort((s,b)=>B(s,n,a.history).priority-B(b,n,a.history).priority),d=c().find((s)=>B(s,n,a.history).kind!=="approved")?.id??e.components[0]?.id,g=a.completed?"all":"attention",V=!1,J=!1,Q=a.completed??!1,si="",H={},M=!1,W=null,ne=/Mac|iPhone|iPad/.test(navigator.platform)?"⌘Enter":"Ctrl+Enter",Y=!1,U=!1,k=!0,F=!1,y="comp",ji=y,_="fit",ei="checker",N=!1,R="isolated",fi,Hi="fit",L=null,T=null,oi=null,ci='',ai='',Mi=(s)=>`left:${D(s.x)};top:${D(s.y)};width:${D(s.w)};height:${D(s.h)}`;function ni(s){o.getElementById(s)?.focus({preventScroll:!0})}function re(s){let b=Pi(e,n,s);if(M=!b,b)d=b;if(y="component",N=!1,Y=!1,_="fit",R="isolated",g==="approved")g="attention";h(),ni(M?"review-summary":H[d]?"feedback":"approve")}function bi(s){if(J||Q||N)return;let b=e.components.find((mi)=>mi.id===d);if(!b)return;let $=n.decisions[b.id],ri=$?.revision===b.revision?$:void 0;W={id:b.id,name:b.name,action:s,previous:$?{...$}:void 0};let ti=H[b.id]??ri;if(n.decisions[b.id]={revision:b.revision,action:s,feedback:s==="revise"?ti?.feedback??"":"",split:s==="revise"&&(ti?.split??!1)},delete H[b.id],F)k=!0,F=!1;re(b.id)}function pe(){if(J||Q||N)return;let s=e.components.find((ri)=>ri.id===d);if(!s)return;let b=n.decisions[s.id],$=b?.revision===s.revision?b:void 0;if(H[s.id]??={feedback:$?.feedback??"",split:$?.split??!1},k&&(o.querySelector(".workbench")?.clientHeight??0)<420)F=!0,k=!1;M=!1,h(),ni("feedback")}function qi(s){let b=`missing-${crypto.randomUUID()}`;n.missing.push({id:b,name:"Missing component",feedback:"",box:s}),n.inventoryConfirmed=!1,M=!1,d=b,y="component",V=!1,L=null,T=null,h(),o.querySelector("#missing-name")?.focus()}function h(){oi?.disconnect();let s=o.activeElement,b=s?.id,$=s?.dataset.select,ri=window.scrollX,ti=window.scrollY,mi=o.querySelector(".inventory")?.scrollLeft??0,xi=fi===d,ae=y==="component"&&(!xi||ji!==y);ji=y;let te=xi?o.querySelector(".inspection-content")?.scrollTop??0:0,xe=xi&&(o.querySelector(".changed-files")?.open??!1),Ei=o.querySelector(".pan-viewport"),Vi=fi===d&&Hi===_,le=Vi?Ei?.scrollLeft??0:0,de=Vi?Ei?.scrollTop??0:0;fi=d,Hi=_;let l=e.components.find((i)=>i.id===d),w=n.missing.find((i)=>i.id===d),Ji=l?.box??w?.box,Ni=l?e.components.indexOf(l)+1:e.components.length+n.missing.findIndex((i)=>i.id===d)+1,$i=l?n.decisions[l.id]:void 0,S=$i?.revision===l?.revision?$i:void 0,wi=l?H[l.id]:void 0,P=Object.keys(H).length>0,he=l?!e.components.some((i)=>i.id!==l.id&&B(i,n).kind==="pending"):!1,Gi=W?`
${x(W.name)} ${W.action==="approve"?"approved":"flagged for repair"}.
`:"",u=hi(e,n),v=a.history,q=l?di(l.id,v):void 0,C=v?.packet.components.find((i)=>i.id===l?.id),X=N&&!!C,t=X?C:l,E=X?v.packet:e,Ki=Object.values(v?.changes??{}),Qi=Ki.filter((i)=>i.kind==="changed").length,Wi=Ki.filter((i)=>i.kind==="added").length,ui=e.components.filter((i)=>B(i,n,v).kind==="approved"&&di(i.id,v).carried).length,pi=(i)=>B(i,n,v),ge=e.components.length-u.approved+n.missing.length,_i=(g==="attention"?c():e.components).filter((i)=>g==="all"||pi(i).kind==="approved"===(g==="approved")),se=[u.revisions+n.missing.length?`${u.revisions+n.missing.length} feedback ready`:"",ui?`${ui} ${ui===1?"approval":"approvals"} kept`:"",Qi?`${Qi} changed`:"",Wi?`${Wi} added`:"",v?.removed.length?`${v.removed.length} removed`:""].filter(Boolean).join(" · "),fe=si||(P?"Save or cancel your open feedback before sending.":Q?a.preview?"Preview submitted. No run changed.":"Review submitted.":u.hasFeedback?"Ready to send for corrections.":u.pending?`${u.pending} left to review`:!n.inventoryConfirmed?"Confirm the map is complete.":"Ready to continue."),Z=t?gi(t):null,Li=t?.preview.kind==="image"&&!Z?.code,I=!!(t?.context&&R==="context"),Ti=t&&(I?t.context?.kind!=="image":t.preview.kind==="page"),Xi=I&&t?.context?t.context.url:t?.preview.url,ce=Z?.code?`${Z.label} · ${Z.captured?"captured from code":"live preview"}`:t?.material?`${t.material.alpha==="transparent"?"Transparent":t.material.alpha==="opaque"?"Opaque":"Transparency unverified"} ${t.material.format}`:"Raster · transparency unverified";if(o.innerHTML=`

Review the components.

${x(e.title)} · Round ${e.round}

${a.preview?'Interactive preview':""}
${a.preview?'

Historical hotel artwork for testing this interface. Decisions stay in this preview; no run is changed.

':""} ${v?`

${u.pending} ${u.pending===1?"component":"components"} to review${se}

${u.pending?``:""}${v.removed.length?`
Removed from the map

${v.removed.map((i)=>x(i.name)).join(" · ")}. Confirm these omissions are intentional before accepting the map.

`:""}
`:""} @@ -125,16 +126,16 @@ ${q?.prior?.action==="revise"?`

Previous feedback Round ${q.feedbackRound}

Needs work

${x(q.prior.feedback||"No written feedback was supplied.")}
${q.prior.split?"

Requested: split into separately reviewable components.

":""}
`:q?.carried?'

Unchanged · approval kept

':""} ${q?.change?.kind==="changed"?`
${q.change.files.length?`${q.change.files.length} changed ${q.change.files.length===1?"file":"files"}`:q.change.reasons.includes("region")?"Region changed":C?.note!==l.note?"Description changed · files unchanged":"Component definition changed · files unchanged"}${q.change.files.length?`
    ${q.change.files.map((i)=>`
  • ${x(i)}
  • `).join("")}
`:""}${C&&C.note!==l.note?`
Previous description
${x(C.note)}
Current description
${x(l.note)}
`:""}
`:""} `:""} - ${C?`
`:""} -
+ ${C?`
`:""} +
-
${Y?`Comp · Round ${v.packet.round}`:"In the comp"}
Reference region for ${x(t.name)}
-
${Y?`Previous · Round ${v.packet.round}`:v?`Current · Round ${e.round}`:I?"In the page":Z.caption}
${!Xi?`Produced ${x(t.name)}`:``}${L?`Reference overlay`:""}
+
${X?`Comp · Round ${v.packet.round}`:"In the comp"}
Reference region for ${x(t.name)}
+
${X?`Previous · Round ${v.packet.round}`:v?`Current · Round ${e.round}`:I?"In the page":Z.caption}
${!Ti?`Produced ${x(t.name)}`:``}${Y?`Reference overlay`:""}
- ${Ti?`
${t.context?`
`:""}
`:""} + ${Li?`
${t.context?`
`:""}
`:""}

${x(t?.context?.layering??"Layer placement not recorded.")}

${x(t.note)}

-
${Gi}${Y?'

Viewing the previous round. Return to Current to make a decision.

':""}
Your review Round ${e.round}${Y?"

Return to Current to review this round.

":""}
${S?``:""}
+
${Gi}${X?'

Viewing the previous round. Return to Current to make a decision.

':""}
Your review Round ${e.round}${X?"

Return to Current to review this round.

":""}
${S?``:""}
${wi?`
`:S?.action==="revise"?`

${x(S.feedback||"No note — agent will diagnose.")}

`:""}
`:w?`

This piece will be added to the unresolved inventory.

${["x","y","w","h"].map((i)=>``).join("")}
`:"

No components supplied.

"}
@@ -142,4 +143,4 @@

Components

${_i.map((i)=>{let r=e.components.indexOf(i),f=pi(i);return``}).join("")}${(g==="approved"?[]:n.missing).map((i,r)=>``).join("")}${!_i.length&&(g==="approved"||!n.missing.length)?`

${g==="attention"?"Every component is approved. Confirm the map is complete, then continue.":"No components approved yet."}

`:""}
-
`,Y)o.querySelectorAll(".decisions button,#feedback,#split,#save-feedback,#cancel-feedback,#undo-decision,#approve-rest,#submit,#inventory-confirm").forEach((i)=>i.disabled=!0);if(o.querySelector(".inspection-content").scrollTop=te,Q||J)o.querySelectorAll(".decisions button,#save-feedback,#cancel-feedback,#undo-decision,#approve-rest,#mark,#inventory-confirm,#missing-name,#missing-feedback,#feedback,#split,#remove-missing,[data-coordinate]").forEach((i)=>i.disabled=!0);if(o.querySelector(".inventory").scrollLeft=mi,!xi&&k)Array.from(o.querySelectorAll(".inventory [data-select]")).find((i)=>i.dataset.select===d)?.scrollIntoView({block:"nearest",inline:"nearest"});if(b)o.getElementById(b)?.focus({preventScroll:!0});else if($)Array.from(o.querySelectorAll(".item[data-select]")).find((i)=>i.dataset.select===$)?.focus({preventScroll:!0});let m=(i,r)=>o.querySelector(`#${i}`)?.addEventListener("click",r);o.querySelectorAll("[data-select]").forEach((i)=>i.onclick=()=>{if(V)return;M=!1,d=i.dataset.select,y="component",L=!1,_="fit",R="isolated",N=!1,h()}),m("previous-round",()=>{N=!0,h()}),m("current-round",()=>{N=!1,h()}),m("review-changes",()=>{let i=c().filter((j)=>pi(j).kind==="pending"),r=i.findIndex((j)=>j.id===d),f=i[(r+1)%i.length];if(f)M=!1,d=f.id,y="component",g="attention",N=!1,_="fit",L=!1,R="isolated",h()}),o.querySelectorAll("[data-filter]").forEach((i)=>i.onclick=()=>{M=!1,g=i.dataset.filter;let r=c().filter((j)=>g==="all"||pi(j).kind==="approved"===(g==="approved"));if(!(g!=="approved"&&n.missing.some((j)=>j.id===d))&&!r.some((j)=>j.id===d)&&r.length)d=r[0].id,y="component",N=!1,_="fit",L=!1,R="isolated";h()}),m("approve",()=>bi("approve")),m("revise",pe),m("clear",()=>{if(l)delete n.decisions[l.id],delete H[l.id];W=null,h()}),m("cancel-feedback",()=>{if(l)delete H[l.id];if(F)k=!0,F=!1;h(),ni("revise")}),o.querySelector("#feedback-form")?.addEventListener("submit",(i)=>{i.preventDefault(),bi("revise")}),o.querySelector("#feedback")?.addEventListener("keydown",(i)=>{let r=i;if(r.key==="Enter"&&(r.metaKey||r.ctrlKey)&&!r.isComposing)r.preventDefault(),r.stopPropagation(),bi("revise")}),m("undo-decision",()=>{if(!W||J||Q)return;let i=W;if(i.previous)n.decisions[i.id]=i.previous;else delete n.decisions[i.id];delete H[i.id],d=i.id,M=!1,N=!1,y="component",g="all",W=null,h(),ni("approve")}),m("overlay",()=>{L=!L,h()}),m("isolated",()=>{R="isolated",h()}),m("context",()=>{R="context",h()}),o.querySelector("#zoom")?.addEventListener("change",(i)=>{let r=i.target.value;_=r==="fit"?"fit":Number(r),h()}),m("background-checker",()=>{ei="checker",h()}),m("background-page",()=>{ei="page",h()}),m("show-all",()=>{U=!U,k=!0,h()}),m("toggle-tray",()=>{F=!1,k=!k,h()}),m("show-comp",()=>{y="comp",h()}),m("show-component",()=>{y="component",h()}),m("mark",()=>{V=!V,h()}),m("add-box",()=>qi({x:0.35,y:0.35,w:0.2,h:0.2})),m("remove-missing",()=>{n.missing=n.missing.filter((i)=>i.id!==d),d=e.components[0]?.id,h()}),m("approve-rest",()=>{if(P)return;n=Ci(e,n),W=null,M=!0,y="component",h(),ni("review-summary")}),o.querySelector("#inventory-confirm")?.addEventListener("change",(i)=>{n.inventoryConfirmed=i.target.checked,h()}),o.querySelector("#feedback")?.addEventListener("input",(i)=>{if(l&&H[l.id])H[l.id].feedback=i.target.value}),o.querySelector("#split")?.addEventListener("change",(i)=>{if(l&&H[l.id])H[l.id].split=i.target.checked}),o.querySelector("#missing-name")?.addEventListener("input",(i)=>{if(w)w.name=i.target.value;let r=o.querySelector("#submit");if(r)r.disabled=P||J||Q||!hi(e,n).canSubmit}),o.querySelector("#missing-feedback")?.addEventListener("input",(i)=>{if(w)w.feedback=i.target.value}),o.querySelectorAll("[data-coordinate]").forEach((i)=>i.addEventListener("change",()=>{if(!w)return;let r=i.dataset.coordinate,f=Number(i.value)/100;if(Number.isFinite(f))w.box[r]=Math.max(r==="w"||r==="h"?0.001:0,Math.min(1,f));w.box.w=Math.min(w.box.w,1-w.box.x),w.box.h=Math.min(w.box.h,1-w.box.y),h()})),m("submit",async()=>{if(P||J||Q)return;J=!0,si="",h();try{await a.onSubmit(Fi(e,n)),Q=!0}catch(i){si=i instanceof Error?i.message:"Could not save. Try again."}finally{J=!1,h()}});let A=o.querySelector(".map");function Li(i){let r=A.getBoundingClientRect();return{x:Math.max(0,Math.min(1,(i.clientX-r.left)/r.width)),y:Math.max(0,Math.min(1,(i.clientY-r.top)/r.height))}}A.addEventListener("pointerdown",(i)=>{if(!V)return;T=Li(i),A.setPointerCapture(i.pointerId),i.preventDefault()}),A.addEventListener("pointermove",(i)=>{if(!T)return;let r=Li(i);X={x:Math.min(T.x,r.x),y:Math.min(T.y,r.y),w:Math.abs(r.x-T.x),h:Math.abs(r.y-T.y)};let f=o.querySelector(".draw-box");f.hidden=!1,f.style.cssText=Mi(X)}),A.addEventListener("pointerup",()=>{if(X&&X.w>0.01&&X.h>0.01)qi(X);else T=null,X=null}),A.addEventListener("pointercancel",()=>{T=null,X=null,h()});let Ui=o.querySelector(".output"),li=o.querySelector("iframe"),Zi=o.querySelector(".workbench"),ii=o.querySelector(".inspection-content"),vi=o.querySelector(".inspector");function yi(){if(!ii||!vi)return;vi.dataset.scrollAbove=String(ii.scrollTop>1),vi.dataset.scrollBelow=String(ii.scrollHeight-ii.clientHeight-ii.scrollTop>1)}ii?.addEventListener("scroll",yi,{passive:!0});function Ii(){let i=o.querySelector(".map-space");if(i&&i.clientWidth&&i.clientHeight){let z=ki(e.comp.width,e.comp.height,Math.max(1,i.clientWidth-32),Math.max(1,i.clientHeight-32),"fit");A.style.width=`${z.width}px`,A.style.height=`${z.height}px`}let r=o.querySelector(".inspection-content"),f=Array.from(o.querySelectorAll(".pan-viewport"));if(r?.clientHeight)f.forEach((z)=>z.style.height=`${Math.min(248,Math.max(100,r.clientHeight-40))}px`);if(t&&f.length){let z=ki(t.box.w*E.comp.width,t.box.h*E.comp.height,Math.min(...f.map((G)=>G.clientWidth)),Math.min(...f.map((G)=>G.clientHeight)),_);o.querySelectorAll(".crop-stage").forEach((G)=>{G.style.width=`${z.width}px`,G.style.height=`${z.height}px`})}if(Ui&&li&&t){let z=Ui.clientWidth/(t.box.w*E.comp.width);li.style.transform=`scale(${z})`,li.style.left=`${-t.box.x*E.comp.width*z}px`,li.style.top=`${-t.box.y*E.comp.height*z}px`}let j=Zi.getBoundingClientRect(),Bi=o.querySelector(".region"),Di=o.querySelector(".number"),Oi=o.querySelector(".connector path");if(Bi&&Di&&Oi){let z=Bi.getBoundingClientRect(),G=Di.getBoundingClientRect(),be=z.right-j.left,me=z.top+z.height/2-j.top,Ri=G.left-j.left-8,we=G.top+G.height/2-j.top;Oi.setAttribute("d",`M ${be} ${me} H ${Ri-14} V ${we} H ${Ri}`)}}oi=new ResizeObserver(()=>{Ii(),yi()}),oi.observe(Zi);let Ai=o.querySelector(".inspection-content");if(Ai)oi.observe(Ai);Ii();let zi=Array.from(o.querySelectorAll(".pan-viewport"));if(zi.forEach((i)=>{i.scrollLeft=le,i.scrollTop=de}),zi.forEach((i)=>i.addEventListener("scroll",()=>{for(let r of zi)if(r!==i){if(r.scrollLeft!==i.scrollLeft)r.scrollLeft=i.scrollLeft;if(r.scrollTop!==i.scrollTop)r.scrollTop=i.scrollTop}})),ae&&window.matchMedia("(max-width:800px)").matches){let i=o.querySelector(".inspection-content"),r=o.querySelector(".compare");if(i&&r)i.scrollTop+=r.getBoundingClientRect().top-i.getBoundingClientRect().top}yi(),window.scrollTo(ri,ti)}return h(),{destroy(){oi?.disconnect(),o.replaceChildren()},getDraft(){return structuredClone(n)}}}async function ye(){let p=document.getElementById("review"),e=await fetch("/packet",{cache:"no-store"});if(!e.ok)throw Error("The review packet could not be loaded. Reload to retry.");let a=await e.json();if(a.sourceStatus){let o=document.createElement("p");o.textContent=a.sourceStatus,p.before(o)}oe(p,a.packet,{initialDraft:a.draft,history:a.history,completed:!!a.receipt,onSubmit:async(o)=>{let n=await fetch("/decision",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}),c=await n.json();if(!n.ok)throw Error(c.error??"The review could not be saved. Try again.")}})}ye().catch((p)=>{let e=document.createElement("p");e.textContent=p instanceof Error?p.message:String(p),document.getElementById("review")?.replaceChildren(e)});})(); + `,X)o.querySelectorAll(".decisions button,#feedback,#split,#save-feedback,#cancel-feedback,#undo-decision,#approve-rest,#submit,#inventory-confirm").forEach((i)=>i.disabled=!0);if(o.querySelector(".inspection-content").scrollTop=te,Q||J)o.querySelectorAll(".decisions button,#save-feedback,#cancel-feedback,#undo-decision,#approve-rest,#mark,#inventory-confirm,#missing-name,#missing-feedback,#feedback,#split,#remove-missing,[data-coordinate]").forEach((i)=>i.disabled=!0);if(o.querySelector(".inventory").scrollLeft=mi,!xi&&k)Array.from(o.querySelectorAll(".inventory [data-select]")).find((i)=>i.dataset.select===d)?.scrollIntoView({block:"nearest",inline:"nearest"});if(b)o.getElementById(b)?.focus({preventScroll:!0});else if($)Array.from(o.querySelectorAll(".item[data-select]")).find((i)=>i.dataset.select===$)?.focus({preventScroll:!0});let m=(i,r)=>o.querySelector(`#${i}`)?.addEventListener("click",r);o.querySelectorAll("[data-select]").forEach((i)=>i.onclick=()=>{if(V)return;M=!1,d=i.dataset.select,y="component",Y=!1,_="fit",R="isolated",N=!1,h()}),m("previous-round",()=>{N=!0,h()}),m("current-round",()=>{N=!1,h()}),m("review-changes",()=>{let i=c().filter((j)=>pi(j).kind==="pending"),r=i.findIndex((j)=>j.id===d),f=i[(r+1)%i.length];if(f)M=!1,d=f.id,y="component",g="attention",N=!1,_="fit",Y=!1,R="isolated",h()}),o.querySelectorAll("[data-filter]").forEach((i)=>i.onclick=()=>{M=!1,g=i.dataset.filter;let r=c().filter((j)=>g==="all"||pi(j).kind==="approved"===(g==="approved"));if(!(g!=="approved"&&n.missing.some((j)=>j.id===d))&&!r.some((j)=>j.id===d)&&r.length)d=r[0].id,y="component",N=!1,_="fit",Y=!1,R="isolated";h()}),m("approve",()=>bi("approve")),m("revise",pe),m("clear",()=>{if(l)delete n.decisions[l.id],delete H[l.id];W=null,h()}),m("cancel-feedback",()=>{if(l)delete H[l.id];if(F)k=!0,F=!1;h(),ni("revise")}),o.querySelector("#feedback-form")?.addEventListener("submit",(i)=>{i.preventDefault(),bi("revise")}),o.querySelector("#feedback")?.addEventListener("keydown",(i)=>{let r=i;if(r.key==="Enter"&&(r.metaKey||r.ctrlKey)&&!r.isComposing)r.preventDefault(),r.stopPropagation(),bi("revise")}),m("undo-decision",()=>{if(!W||J||Q)return;let i=W;if(i.previous)n.decisions[i.id]=i.previous;else delete n.decisions[i.id];delete H[i.id],d=i.id,M=!1,N=!1,y="component",g="all",W=null,h(),ni("approve")}),m("overlay",()=>{Y=!Y,h()}),m("isolated",()=>{R="isolated",h()}),m("context",()=>{R="context",h()}),o.querySelector("#zoom")?.addEventListener("change",(i)=>{let r=i.target.value;_=r==="fit"?"fit":Number(r),h()}),m("background-checker",()=>{ei="checker",h()}),m("background-page",()=>{ei="page",h()}),m("show-all",()=>{U=!U,k=!0,h()}),m("toggle-tray",()=>{F=!1,k=!k,h()}),m("show-comp",()=>{y="comp",h()}),m("show-component",()=>{y="component",h()}),m("mark",()=>{V=!V,h()}),m("add-box",()=>qi({x:0.35,y:0.35,w:0.2,h:0.2})),m("remove-missing",()=>{n.missing=n.missing.filter((i)=>i.id!==d),d=e.components[0]?.id,h()}),m("approve-rest",()=>{if(P)return;n=Ci(e,n),W=null,M=!0,y="component",h(),ni("review-summary")}),o.querySelector("#inventory-confirm")?.addEventListener("change",(i)=>{n.inventoryConfirmed=i.target.checked,h()}),o.querySelector("#feedback")?.addEventListener("input",(i)=>{if(l&&H[l.id])H[l.id].feedback=i.target.value}),o.querySelector("#split")?.addEventListener("change",(i)=>{if(l&&H[l.id])H[l.id].split=i.target.checked}),o.querySelector("#missing-name")?.addEventListener("input",(i)=>{if(w)w.name=i.target.value;let r=o.querySelector("#submit");if(r)r.disabled=P||J||Q||!hi(e,n).canSubmit}),o.querySelector("#missing-feedback")?.addEventListener("input",(i)=>{if(w)w.feedback=i.target.value}),o.querySelectorAll("[data-coordinate]").forEach((i)=>i.addEventListener("change",()=>{if(!w)return;let r=i.dataset.coordinate,f=Number(i.value)/100;if(Number.isFinite(f))w.box[r]=Math.max(r==="w"||r==="h"?0.001:0,Math.min(1,f));w.box.w=Math.min(w.box.w,1-w.box.x),w.box.h=Math.min(w.box.h,1-w.box.y),h()})),m("submit",async()=>{if(P||J||Q)return;J=!0,si="",h();try{await a.onSubmit(Fi(e,n)),Q=!0}catch(i){si=i instanceof Error?i.message:"Could not save. Try again."}finally{J=!1,h()}});let A=o.querySelector(".map");function Yi(i){let r=A.getBoundingClientRect();return{x:Math.max(0,Math.min(1,(i.clientX-r.left)/r.width)),y:Math.max(0,Math.min(1,(i.clientY-r.top)/r.height))}}A.addEventListener("pointerdown",(i)=>{if(!V)return;L=Yi(i),A.setPointerCapture(i.pointerId),i.preventDefault()}),A.addEventListener("pointermove",(i)=>{if(!L)return;let r=Yi(i);T={x:Math.min(L.x,r.x),y:Math.min(L.y,r.y),w:Math.abs(r.x-L.x),h:Math.abs(r.y-L.y)};let f=o.querySelector(".draw-box");f.hidden=!1,f.style.cssText=Mi(T)}),A.addEventListener("pointerup",()=>{if(T&&T.w>0.01&&T.h>0.01)qi(T);else L=null,T=null}),A.addEventListener("pointercancel",()=>{L=null,T=null,h()});let Ui=o.querySelector(".output"),li=o.querySelector("iframe"),Zi=o.querySelector(".workbench"),ii=o.querySelector(".inspection-content"),vi=o.querySelector(".inspector");function yi(){if(!ii||!vi)return;vi.dataset.scrollAbove=String(ii.scrollTop>1),vi.dataset.scrollBelow=String(ii.scrollHeight-ii.clientHeight-ii.scrollTop>1)}ii?.addEventListener("scroll",yi,{passive:!0});function Ii(){let i=o.querySelector(".map-space");if(i&&i.clientWidth&&i.clientHeight){let z=ki(e.comp.width,e.comp.height,Math.max(1,i.clientWidth-32),Math.max(1,i.clientHeight-32),"fit");A.style.width=`${z.width}px`,A.style.height=`${z.height}px`}let r=o.querySelector(".inspection-content"),f=Array.from(o.querySelectorAll(".pan-viewport"));if(r?.clientHeight)f.forEach((z)=>z.style.height=`${Math.min(248,Math.max(100,r.clientHeight-40))}px`);if(t&&f.length){let z=ki(t.box.w*E.comp.width,t.box.h*E.comp.height,Math.min(...f.map((G)=>G.clientWidth)),Math.min(...f.map((G)=>G.clientHeight)),_);o.querySelectorAll(".crop-stage").forEach((G)=>{G.style.width=`${z.width}px`,G.style.height=`${z.height}px`})}if(Ui&&li&&t){let z=Ui.clientWidth/(t.box.w*E.comp.width);li.style.transform=`scale(${z})`,li.style.left=`${-t.box.x*E.comp.width*z}px`,li.style.top=`${-t.box.y*E.comp.height*z}px`}let j=Zi.getBoundingClientRect(),Bi=o.querySelector(".region"),Di=o.querySelector(".number"),Oi=o.querySelector(".connector path");if(Bi&&Di&&Oi){let z=Bi.getBoundingClientRect(),G=Di.getBoundingClientRect(),be=z.right-j.left,me=z.top+z.height/2-j.top,Ri=G.left-j.left-8,we=G.top+G.height/2-j.top;Oi.setAttribute("d",`M ${be} ${me} H ${Ri-14} V ${we} H ${Ri}`)}}oi=new ResizeObserver(()=>{Ii(),yi()}),oi.observe(Zi);let Ai=o.querySelector(".inspection-content");if(Ai)oi.observe(Ai);Ii();let zi=Array.from(o.querySelectorAll(".pan-viewport"));if(zi.forEach((i)=>{i.scrollLeft=le,i.scrollTop=de}),zi.forEach((i)=>i.addEventListener("scroll",()=>{for(let r of zi)if(r!==i){if(r.scrollLeft!==i.scrollLeft)r.scrollLeft=i.scrollLeft;if(r.scrollTop!==i.scrollTop)r.scrollTop=i.scrollTop}})),ae&&window.matchMedia("(max-width:800px)").matches){let i=o.querySelector(".inspection-content"),r=o.querySelector(".compare");if(i&&r)i.scrollTop+=r.getBoundingClientRect().top-i.getBoundingClientRect().top}yi(),window.scrollTo(ri,ti)}return h(),{destroy(){oi?.disconnect(),o.replaceChildren()},getDraft(){return structuredClone(n)}}}async function ye(){let p=document.getElementById("review"),e=await fetch("/packet",{cache:"no-store"});if(!e.ok)throw Error("The review packet could not be loaded. Reload to retry.");let a=await e.json();if(a.sourceStatus){let o=document.createElement("p");o.textContent=a.sourceStatus,p.before(o)}oe(p,a.packet,{initialDraft:a.draft,history:a.history,completed:!!a.receipt,onSubmit:async(o)=>{let n=await fetch("/decision",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)}),c=await n.json();if(!n.ok)throw Error(c.error??"The review could not be saved. Try again.")}})}ye().catch((p)=>{let e=document.createElement("p");e.textContent=p instanceof Error?p.message:String(p),document.getElementById("review")?.replaceChildren(e)});})(); diff --git a/ui/component-review/styles.ts b/ui/component-review/styles.ts index 4a86f023b..baf929728 100644 --- a/ui/component-review/styles.ts +++ b/ui/component-review/styles.ts @@ -37,7 +37,8 @@ export const styles = ` ` + appLayout + ` .review-form:has(#feedback-form){max-height:75%;min-height:0;flex-shrink:1;display:flex;flex-direction:column;overflow:hidden;padding-top:8px} #feedback-form{display:flex;flex-direction:column;flex:1;min-height:0} -.feedback-fields{flex:1;min-height:0;overflow:auto;padding:3px} +/* Leave room inside the scrollport for the 2px focus ring and 3px offset. */ +.feedback-fields{flex:1;min-height:0;overflow:auto;padding:6px} .review-form:has(#feedback-form) .decision-notice{flex-shrink:0} .review-form:has(#feedback-form) .decisions{display:none} .feedback-actions{flex-shrink:0;position:static;background:var(--surface,var(--paper));padding:8px 0;margin-top:8px;box-shadow:0 -5px 8px -6px #24332838}