@wafertools/wafermap 0.21.1 → 0.22.0
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/AGENTS.md +170 -0
- package/CHANGELOG.md +160 -1
- package/README.md +9 -1
- package/dist/packages/canvas-adapter/icons.js +1 -1
- package/dist/packages/canvas-adapter/index.d.ts +2 -0
- package/dist/packages/canvas-adapter/index.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +14 -0
- package/dist/packages/canvas-adapter/renderWaferGallery.js +6 -6
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +14 -0
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +11 -1
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toolbar.d.ts +4 -1
- package/dist/packages/canvas-adapter/toolbar.js +1 -1
- package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
- package/dist/packages/canvas-adapter/userGuideHtml.js +59 -22
- package/dist/packages/canvas-adapter/version.d.ts +2 -2
- package/dist/packages/canvas-adapter/version.js +1 -1
- package/dist/packages/canvas-adapter/warnings.d.ts +52 -0
- package/dist/packages/canvas-adapter/warnings.js +1 -0
- package/dist/packages/renderer/buildWaferMap.d.ts +15 -1
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/renderer/index.d.ts +1 -1
- package/dist/packages/renderer/index.js +1 -1
- package/dist/packages/stats/analyzeWaferLot.js +1 -1
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/renderFindingsReport.js +15 -15
- package/dist/packages/stats/types.d.ts +34 -4
- package/llms.txt +39 -0
- package/package.json +12 -8
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{isParametricTest as ae}from"../renderer/buildWaferMap.js";import{buildRingRegions as Q,buildQuadrantRegions as G,buildRegionYieldData as se}from"../stats/regions.js";import{computeFunctionalYield as le}from"../stats/analyzeWaferMap.js";import{openHtmlReport as U}from"../stats/renderFindingsReport.js";import{renderSummaryReportHtml as de,renderLotSummaryReportHtml as pe}from"../stats/renderSummaryReport.js";import{buildFindingsNarrative as ce}from"../stats/findingsNarrative.js";import{filterFindings as ue}from"../stats/filterFindings.js";import{buildFacetTable as fe,prettyKey as X}from"../stats/facets.js";import{getColorScheme as me}from"../renderer/colorSchemes.js";import{fmt as K,fmtAggregationMethod as he,plainBinTerms as I}from"../renderer/fmt.js";import{getUniqueTestNumbers as ge}from"../renderer/buildView.js";import{quantile as O}from"../stats/math.js";import{makeLabeledSelect as Z}from"./charts/chartShell.js";import{CLR as b,sevColor as q,openModal as xe,saveTextFile as J}from"./toolbar.js";import{medianOfSorted as be}from"../core/utils.js";const ve=b.panelBg,M=`1px solid ${b.menuBorder}`,ye="12px",F=b.label,W=b.value,ee="10px";function a(e,n,t){const i=document.createElement(e);return n&&Object.assign(i.style,n),t!==void 0&&(i.textContent=t),i}export function buildWarningsBanner(e){const n=a("div",{background:b.warnBg,border:`1px solid ${b.warnBorder}`,borderRadius:"4px",padding:"7px 9px",marginBottom:"10px",fontSize:"10px",color:b.warnText,lineHeight:"1.5"});for(const t of e)n.appendChild(a("div",{},`\u26A0 ${t}`));return n}function z(e){return a("div",{fontSize:ee,fontWeight:"700",letterSpacing:"0.06em",textTransform:"uppercase",color:F,marginBottom:"6px"},e)}function te(e,n=!0,t){const i=a("div"),r=document.createElement("button");r.type="button",Object.assign(r.style,{display:"flex",alignItems:"center",gap:"4px",width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const d=a("span",{fontSize:"9px",color:F,transition:"transform 0.15s",transform:n?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:"1",marginRight:"1px"},"\u25B6"),c=a("span",{fontSize:ee,fontWeight:"700",letterSpacing:"0.06em",textTransform:"uppercase",color:F,flex:"1"},e);if(r.setAttribute("aria-expanded",n?"true":"false"),r.appendChild(d),r.appendChild(c),t){const l=a("span",{fontSize:"9px",fontWeight:"700",background:b.warnBg,color:b.warnText,borderRadius:"10px",padding:"1px 5px"},t);r.appendChild(l)}const p=a("div");p.style.display=n?"block":"none";let o=n;return r.addEventListener("click",()=>{o=!o,p.style.display=o?"block":"none",d.style.transform=o?"rotate(90deg)":"rotate(0deg)",r.setAttribute("aria-expanded",o?"true":"false")}),i.appendChild(r),i.appendChild(p),{outer:i,content:p}}function ne(){return a("div",{height:"1px",background:b.separator,margin:`${ye} 0`,flexShrink:"0"})}function _(e,n,t="#2a6fc0",i,r,d){const c=a("div",{marginBottom:"5px"}),p=a("div",{display:"flex",justifyContent:"space-between",fontSize:"11px",color:W,marginBottom:"2px"}),o=a("span",{},e),l=a("span",{fontWeight:"600"},`${n.toFixed(1)}%`);p.appendChild(o),p.appendChild(l);const u=i!==void 0?i:Math.min(100,Math.max(0,n)),v=d?"#94a3b8":t,y=a("div",{position:"relative",height:"9px",background:b.bgActive,borderRadius:"4px",overflow:"hidden"}),R=a("div",{height:"100%",width:`${u}%`,background:v,borderRadius:"4px",transition:"width 0.3s ease"});if(y.appendChild(R),r!==void 0){const B=a("div",{position:"absolute",top:"0",bottom:"0",left:`${r}%`,width:"1px",background:b.infoText,opacity:"0.5"});y.appendChild(B)}return c.appendChild(p),c.appendChild(y),c}function P(e,n,t){const i=a("div",{background:b.menuBg,border:M,borderRadius:"6px",padding:"8px 10px",textAlign:"center",flex:"1"}),r=a("div",{fontSize:"20px",fontWeight:"700",color:W,lineHeight:"1.2"},e),d=a("div",{fontSize:"10px",color:F,marginTop:"2px"},n);return i.appendChild(r),i.appendChild(d),t&&i.appendChild(a("div",{fontSize:"9px",color:F,opacity:"0.85"},t)),i}function Se(e,n){const t=a("div",{display:"flex",justifyContent:"space-between",fontSize:"11px",gap:"8px",marginBottom:"3px"}),i=a("span",{color:F,flexShrink:"0"},e),r=a("span",{color:W,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},n);return t.appendChild(i),t.appendChild(r),t}function we(e,n){const t=a("div",{display:"flex",fontSize:"11px",gap:"6px",marginBottom:"3px"}),i=a("span",{color:F,flexShrink:"0"},`${e}:`),r=a("span",{color:W,fontWeight:"500",wordBreak:"break-all"},n);return t.appendChild(i),t.appendChild(r),t}export function metadataEntries(e){return Object.entries(e).filter(([,n])=>n!=null&&n!=="").map(([n,t])=>[n,String(t)])}export function buildFacetSummaryChips(e,n=3){if(!e.length)return null;const t=a("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 10px",fontSize:"11px"});for(const i of e){const r=a("span",{whiteSpace:"nowrap"}),d=a("span",{color:F},`${X(i.key)}: `);r.appendChild(d);const c=i.values.slice(0,n),p=i.values.length-c.length;let o=c.map(l=>l.value).join(", ");p>0&&(o+=` +${p} more`),r.appendChild(document.createTextNode(o)),t.appendChild(r)}return t}export function buildMetadataStripRow(e,n,t){const i=fe(e,t),r=buildFacetSummaryChips(i);if(!r&&!n)return null;const d=a("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px"});if(n){const c=a("span",{fontWeight:"500",whiteSpace:"nowrap"},n.aggrMethod?`${n.lotSize} wafers stacked \xB7 ${n.aggrMethod}`:`${n.lotSize} wafers stacked`);d.appendChild(c)}return r&&d.appendChild(r),d}const Ce={display:"flex",flexDirection:"column",gap:"6px",background:b.menuBg,border:`1px solid ${b.menuBorder}`,borderRadius:"6px",padding:"6px 10px",boxShadow:"0 1px 4px rgba(0,0,0,0.10)",fontSize:"12px",lineHeight:"1",boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(e,n,t){const i=buildMetadataStripRow(e,n,t);if(!i)return null;const r=a("div",Ce);return r.appendChild(i),r}export function buildCompactMetadataRows(e){const n=metadataEntries(e);if(!n.length)return null;const t=a("div");for(const[i,r]of n)t.appendChild(we(X(i),r));return t}export function buildMetadataInfoSection(e,n){const t=buildMetadataStripRow(e,n,{facetableOnly:e.length>1});if(!t)return null;const i=a("div");return i.appendChild(z("Wafer Info")),i.appendChild(t),i}export function buildYieldSection(e,n,t=[1]){const i=a("div");i.appendChild(z("Summary"));const r=a("div",{display:"flex",gap:"6px",marginBottom:"8px"});if(r.appendChild(P(String(n.totalDies),"Total dies")),e.partialDies>0&&r.appendChild(P(String(e.partialDies),"Partial")),e.yieldPercent!==null){const d=t.length===1?`bin ${t[0]}`:`bins ${t.join(", ")}`;r.appendChild(P(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return i.appendChild(r),e.edgeExcludedDies>0&&i.appendChild(Se("Edge excluded (outer zone)",String(e.edgeExcludedDies))),i}export function buildBinSection(e,n,t,i,r){const d=new Map;if(r)for(const[u,v]of Object.entries(r))d.set(Number(u),v);else for(const u of e){if(u.partial||u.edgeExcluded)continue;const v=t==="hard"?u.hbin:u.sbin;v!=null&&d.set(v,(d.get(v)??0)+1)}if(!d.size)return null;const c=[...d.values()].reduce((u,v)=>u+v,0),p=n?new Map(n.map(u=>[u.bin,u])):null,o=[...d.entries()].sort((u,v)=>u[0]-v[0]),l=a("div");l.appendChild(z(t==="hard"?"Hard Bin Breakdown":"Soft Bin Breakdown"));for(const[u,v]of o){const y=p?.get(u),R=y?.name?`Bin ${u} \xB7 ${y.name}`:`Bin ${u}`,B=v/c*100,$=me(i),L=(i==="custom"?y?.color:void 0)??$.forBin(u);l.appendChild(_(`${R} (${v})`,B,L))}return l}export function buildLotBinSection(e,n,t,i){return buildBinSection(e,n,t,i)}function Y(e,n,t,i,r,d){const c=se(e,n,t,i,r);if(!c.length)return null;const p=a("div");p.appendChild(z(d));for(const{label:o,n:l,yieldPercent:u}of c)p.appendChild(_(`${o} (N=${l})`,u));return p}export function buildRingSection(e,n,t,i){return Y([e],[n],t,i,Q,"Ring Yield")}export function buildQuadrantSection(e,n,t,i){return Y([e],[n],t,i,G,"Quadrant Yield")}export function buildLotRingSection(e,n,t,i){return Y(e,n,t,i,Q,"Ring Yield")}export function buildLotQuadrantSection(e,n,t,i){return Y(e,n,t,i,G,"Quadrant Yield")}export function buildLotOverviewSection(e){const n=a("div");n.appendChild(z("Lot Summary"));const t=a("div",{display:"flex",gap:"6px",marginBottom:"8px"});t.appendChild(P(String(e.stats.waferCount),"Wafers"));const i=e.perWafer.map(r=>r.summary.stats.yieldPercent).filter(r=>r!==null);if(i.length){const r=i.reduce((d,c)=>d+c,0)/i.length;t.appendChild(P(`${r.toFixed(1)}%`,"Mean wafer yield"))}return n.appendChild(t),n}export function buildPerWaferYieldSection(e,n,t){const i=e.perWafer.map(l=>({waferIndex:l.waferIndex,label:(n[l.waferIndex]?.label??`W${l.waferIndex+1}`).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:l.summary.stats.yieldPercent})).filter(l=>l.yieldPct!==null);if(!i.length)return null;const r=Math.min(...i.map(l=>l.yieldPct)),d=Math.max(...i.map(l=>l.yieldPct)),c=r===d?"":` (${r.toFixed(1)}\u2013${d.toFixed(1)}%)`,p=be([...i.map(l=>l.yieldPct)].sort((l,u)=>l-u)),o=a("div");o.appendChild(z("Wafer Yield"+c));for(const{waferIndex:l,label:u,yieldPct:v}of i){const y=_(u,v,void 0,void 0,p,v<p);t&&(y.style.cursor="pointer",y.style.borderRadius="4px",y.style.padding="2px 3px",y.style.marginLeft="-3px",y.style.marginRight="-3px",y.setAttribute("role","button"),y.setAttribute("aria-label",`${u}, ${v.toFixed(1)}% yield \u2014 view wafer`),y.tabIndex=0,y.addEventListener("mouseenter",()=>{y.style.background=b.bgHover}),y.addEventListener("mouseleave",()=>{y.style.background=""}),y.addEventListener("focus",()=>{y.style.background=b.bgHover}),y.addEventListener("blur",()=>{y.style.background=""}),y.addEventListener("click",()=>t(l)),y.addEventListener("keydown",R=>{(R.key==="Enter"||R.key===" ")&&(R.preventDefault(),t(l))})),o.appendChild(y)}return o}function ke(e){const n=[...e].sort((r,d)=>r-d),t=e.reduce((r,d)=>r+d,0)/e.length,i=e.reduce((r,d)=>r+(d-t)**2,0)/e.length;return{min:n[0],max:n[n.length-1],mean:t,count:e.length,stddev:Math.sqrt(i),median:O(n,.5),q1:O(n,.25),q3:O(n,.75)}}function A(e){return/[",\n]/.test(e)?`"${e.replace(/"/g,'""')}"`:e}export function buildTestSection(e,n,t,i,r){const d=e.filter(s=>!s.partial&&!s.edgeExcluded),c=new Map((i?.perTestStats??[]).map(s=>[s.testNumber,s])),p=new Map((i?.testSpecYield??[]).map(s=>[s.testNumber,s]));let o;if(n?.length?o=n.filter(ae).map(s=>({testNumber:s.testNumber,name:s.name,unit:s.unit,limitLow:s.limitLow,limitHigh:s.limitHigh})):o=ge(d).map(h=>({testNumber:h,name:`Test ${h}`})),!o.length)return null;const l=o.filter(s=>d.some(h=>{const S=h.testValues?.[s.testNumber];return S!==void 0&&isFinite(S)}));if(!l.length)return null;const u=l.some(s=>s.limitLow!==void 0||s.limitHigh!==void 0),v=[];for(const s of l){const h=c.get(s.testNumber),S=h&&h.stddev!==void 0&&h.median!==void 0&&h.q1!==void 0&&h.q3!==void 0;let C;if(S){const g=h;C={testNumber:s.testNumber,min:g.min,max:g.max,mean:g.mean,count:g.count,stddev:g.stddev,median:g.median,q1:g.q1,q3:g.q3}}else{const g=d.map(D=>D.testValues?.[s.testNumber]).filter(D=>D!==void 0&&isFinite(D));if(!g.length)continue;C={testNumber:s.testNumber,...ke(g)}}let x=null,f=0;if(s.limitLow!==void 0||s.limitHigh!==void 0){const g=p.get(s.testNumber);if(g)({yieldPercent:x,totalDies:f}=g);else{const D=d.map(N=>N.testValues?.[s.testNumber]).filter(N=>N!==void 0&&isFinite(N)),j=D.filter(N=>s.limitLow!==void 0&&N<s.limitLow||s.limitHigh!==void 0&&N>s.limitHigh).length;f=D.length,x=D.length>0?(D.length-j)/D.length*100:null}}v.push({entry:s,stats:C,specYieldPct:x,specN:f})}if(!v.length)return null;const y=a("div"),R=a("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"6px"}),B=z(`Test Values (${v.length})`);B.style.marginBottom="0",R.appendChild(B);const $=document.createElement("button");$.type="button",$.textContent="Export CSV",Object.assign($.style,{background:"none",border:M,borderRadius:"4px",cursor:"pointer",fontSize:"10px",color:b.iconHover,padding:"2px 7px"}),$.addEventListener("click",()=>{const s=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];u&&s.push("LSL","USL","Spec Yield %","Spec Yield N");const h=[s.map(A).join(",")],S=C=>K(C,void 0,"engineering");for(const{entry:C,stats:x,specYieldPct:f,specN:g}of v){const D=[C.name,C.unit??"",String(x.count),S(x.min),S(x.q1),S(x.median),S(x.mean),S(x.q3),S(x.max),S(x.stddev)];u&&D.push(C.limitLow!==void 0?S(C.limitLow):"",C.limitHigh!==void 0?S(C.limitHigh):"",f!==null?f.toFixed(1):"",C.limitLow!==void 0||C.limitHigh!==void 0?String(g):""),h.push(D.map(A).join(","))}J(h.join(`
|
|
2
|
-
`),"test-values.csv","text/csv",r)}),
|
|
3
|
-
`),"functional-tests.csv","text/csv",i)}),c.appendChild(o),d.appendChild(c);const l=a("table",{width:"100%",borderCollapse:"collapse",fontSize:"11px"}),u=document.createElement("thead"),v=document.createElement("tr");for(const B of["Test","N","Pass","Fail","Pass rate"])v.appendChild(a("th",{textAlign:B==="Test"?"left":"right",fontWeight:"700",fontSize:"10px",letterSpacing:"0.03em",textTransform:"uppercase",color:F,padding:"3px 8px 5px",borderBottom:`1px solid ${b.menuBorder}`,whiteSpace:"nowrap"},B));u.appendChild(v),l.appendChild(u);const y=document.createElement("tbody");for(const B of r){const $=document.createElement("tr"),L=(E,T="right")=>{$.appendChild(a("td",{textAlign:T,padding:"4px 8px",borderBottom:`1px solid ${b.menuBorder}`,color:W,whiteSpace:"nowrap"},E))};L(B.label,"left"),L(String(B.totalDies)),L(String(B.passDies)),L(String(B.failDies)),L(B.passRatePercent!==null?`${B.passRatePercent.toFixed(1)}% (N=${B.totalDies})`:"\u2014"),y.appendChild($)}l.appendChild(y);const R=a("div",{overflowX:"auto"});return R.appendChild(l),d.appendChild(R),d}export function buildLotFunctionalSection(e,n,t,i){if(t?.length&&t.every(r=>r.stats.functionalYield!==void 0)){const r=new Map;for(const c of t)for(const p of c.stats.functionalYield??[]){const o=r.get(p.testNumber)??{label:p.label,passDies:0,failDies:0,totalDies:0};o.passDies+=p.passDies,o.failDies+=p.failDies,o.totalDies+=p.totalDies,r.set(p.testNumber,o)}const d=[...r.entries()].map(([c,p])=>({testNumber:c,...p,passRatePercent:p.totalDies>0?p.passDies/p.totalDies*100:null}));if(d.length)return buildFunctionalTestSection(e,n,d,i)}return buildFunctionalTestSection(e,n,void 0,i)}const H={unusual:0,notable:1,info:2};function V(e){return a("span",{display:"inline-block",width:"7px",height:"7px",borderRadius:"50%",background:q(e),flexShrink:"0"})}function ie(e,n){let t=e.summary;return n&&(t.startsWith(`${n} has `)?t=t.slice(n.length+5):t.startsWith(`${n} `)&&(t=t.slice(n.length+1))),t=I(t),t.length?t[0].toUpperCase()+t.slice(1):t}export function buildFindingsSection(e,n,t,i,r=!1){if(!e.length)return null;const d=e.some(m=>m.severity==="unusual"||m.severity==="notable"),c=d?e.filter(m=>m.severity!=="info").length.toString():void 0,{outer:p,content:o}=r?(()=>{const m=a("div");return{outer:m,content:m}})():te(`Findings (${e.length})`,d,c);function l(m){return m.reduce((k,w)=>H[w.severity]<H[k]?w.severity:k,"info")}function u(m){const k=new Map;for(const s of m){const h=`${s.comparison.family}\0${s.comparison.left}`,S=k.get(h)??[];S.push(s),k.set(h,S)}const w=[...k.entries()].map(([s,h])=>{const S=[...h].sort((C,x)=>H[C.severity]-H[x.severity]);return{key:s,findings:S,worst:l(S)}});return w.sort((s,h)=>H[s.worst]-H[h.worst]),w}function v(m,k){const s={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[m]??m;return k.toLowerCase().startsWith(s.toLowerCase())?k:`${s}: ${k}`}const y=e.filter(m=>m.comparison.family==="spatial-pattern"),R=new Set(y.flatMap(m=>m.relatedIds??[])),B=e.filter(m=>m.comparison.family!=="spatial-pattern"&&!R.has(m.id)),$=u(B);function L(m,k=!1,w){const s=i===m.id,h=document.createElement("button");return h.type="button",h.dataset.wmapFinding=m.id,h.textContent=ie(m,w),h.title=m.summary,Object.assign(h.style,{border:`1px solid ${b.menuBorder}`,borderLeft:`3px solid ${q(m.severity)}`,background:s?b.bgActive:b.menuBg,borderRadius:"6px",padding:k?"6px 10px":"8px 10px",textAlign:"left",fontSize:k?"10px":"11px",fontWeight:s?"600":"400",color:b.iconHover,cursor:"pointer",width:"100%",marginBottom:"4px"}),h.addEventListener("click",()=>t(m,h)),h}const E=I(ce(e)??"");if(E){const m=a("div",{background:b.bgActive,borderRadius:"6px",padding:"8px 10px",marginBottom:"8px",display:"flex",gap:"8px",alignItems:"flex-start"}),k=a("span",{flex:"1",fontSize:"12px",lineHeight:"1.5",color:b.iconHover},E);m.appendChild(k);const w=a("button",{flexShrink:"0",border:"none",background:"none",fontSize:"10px",color:b.icon,cursor:"pointer",padding:"0",lineHeight:"1.5",whiteSpace:"nowrap"},"Detail \u25B8");w.type="button",w.addEventListener("click",()=>{const s=xe({title:"Findings Summary",onClose:()=>{},anchor:w}),h=a("p",{fontSize:"16px",lineHeight:"1.6",color:b.iconHover,padding:"20px 24px 16px",margin:"0",borderBottom:`1px solid ${b.menuBorder}`,flexShrink:"0"},E);s.contentWrap.appendChild(h);const S=a("div",{overflowY:"auto",padding:"16px 24px",flex:"1"}),C=(x,f)=>{const g=a("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:"13px",fontWeight:"600",color:W,marginTop:"10px",marginBottom:"4px"});return g.appendChild(V(x)),g.appendChild(a("span",{},f)),g};for(const x of y){S.appendChild(C(x.severity,x.comparison.left)),S.appendChild(a("div",{fontSize:"13px",color:b.iconHover,padding:"3px 0 3px 15px",marginBottom:"2px"},I(x.summary)));const f=e.filter(g=>x.relatedIds?.includes(g.id));for(const g of f)S.appendChild(a("div",{fontSize:"12px",color:b.icon,padding:"2px 0 2px 23px",marginBottom:"2px"},I(g.summary)))}for(const x of $){const[f,g]=x.key.split("\0");S.appendChild(C(x.worst,v(f,g)));for(const D of x.findings)S.appendChild(a("div",{fontSize:"13px",color:b.iconHover,padding:"3px 0 3px 15px",marginBottom:"2px"},ie(D,g)))}s.contentWrap.appendChild(S),Object.assign(s.contentWrap.style,{flexDirection:"column",overflow:"hidden"})}),m.appendChild(w),o.appendChild(m)}let T=!0;for(const m of y){T||o.appendChild(a("div",{height:"1px",background:b.separator,margin:"4px 0"})),T=!1;const k=e.filter(C=>m.relatedIds?.includes(C.id)),w=k.length>0,s=a("div",{position:"relative",marginBottom:w?"2px":"4px"}),h=i===m.id,S=document.createElement("button");if(S.type="button",S.dataset.wmapFinding=m.id,Object.assign(S.style,{border:`1px solid ${b.menuBorder}`,borderLeft:`3px solid ${q(m.severity)}`,background:h?b.bgActive:b.menuBg,borderRadius:"6px",padding:"8px 32px 8px 10px",textAlign:"left",fontSize:"11px",fontWeight:h?"600":"500",color:b.iconHover,cursor:"pointer",width:"100%"}),S.textContent=I(m.summary),S.title=m.summary,S.addEventListener("click",()=>t(m,S)),s.appendChild(S),w){const C=a("div",{display:"none",paddingLeft:"12px",marginBottom:"4px"});for(const g of k)C.appendChild(L(g,!0));s.appendChild(C);let x=!1;const f=a("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:"10px",color:b.icon,cursor:"pointer",padding:"2px 4px",lineHeight:"1"},"\u25B8");f.type="button",f.title="Show supporting findings",f.addEventListener("click",g=>{g.stopPropagation(),x=!x,C.style.display=x?"block":"none",f.textContent=x?"\u25BE":"\u25B8",f.title=x?"Hide supporting findings":"Show supporting findings"}),s.appendChild(f)}o.appendChild(s)}for(const m of $){T||o.appendChild(a("div",{height:"1px",background:b.separator,margin:"4px 0"})),T=!1;const[k,w]=m.key.split("\0"),s=a("div",{display:"flex",alignItems:"center",gap:"6px",fontSize:"11px",fontWeight:"600",color:W,margin:"2px 0 4px"});s.appendChild(V(m.worst)),s.appendChild(a("span",{},v(k,w))),o.appendChild(s);for(const h of m.findings)o.appendChild(L(h,!1,w))}return p}const Be=[{value:"",label:"All kinds"},{value:"yield",label:"Yield"},{value:"hardBin",label:"Hard bin"},{value:"softBin",label:"Soft bin"},{value:"test",label:"Test value"},{value:"functionalTest",label:"Functional test"},{value:"spatialPattern",label:"Spatial pattern"}],$e=[{value:"",label:"All regions"},{value:"ring",label:"Ring"},{value:"quadrant",label:"Quadrant"},{value:"reticle-position",label:"Reticle position"},{value:"test-site",label:"Test site"},{value:"wafer",label:"Wafer"},{value:"sector",label:"Sector"},{value:"cluster",label:"Cluster"},{value:"edge-arc",label:"Edge arc"},{value:"spatial-pattern",label:"Spatial pattern"}],Re=["unusual","notable","info"],Le={unusual:"Unusual",notable:"Notable",info:"Info"};function De(e,n,t){const i=a("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:"10px",marginBottom:"10px",paddingBottom:"10px",borderBottom:`1px solid ${b.separator}`}),r={unusual:0,notable:0,info:0};for(const o of e)r[o.severity]++;const d=Re.filter(o=>r[o]>0),c=new Set(n.severity===void 0?d:Array.isArray(n.severity)?n.severity:[n.severity]),p=a("div",{display:"flex",gap:"4px",flexWrap:"wrap"});for(const o of d){const l=document.createElement("button");l.type="button";const u=()=>{const v=c.has(o);l.setAttribute("aria-pressed",v?"true":"false"),Object.assign(l.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${b.menuBorder}`,borderRadius:"10px",background:v?b.bgActive:"none",opacity:v?"1":"0.5",color:b.text,fontSize:"11px",padding:"2px 8px",cursor:"pointer"})};l.appendChild(V(o)),l.appendChild(a("span",{},`${Le[o]} ${r[o]}`)),l.title=c.has(o)?"Click to hide these findings":"Click to show these findings",u(),l.addEventListener("click",()=>{c.has(o)?c.delete(o):c.add(o),n.severity=c.size===d.length?void 0:[...c],t()}),p.appendChild(l)}return i.appendChild(p),i.appendChild(Z("Kind:",Be,n.kind??"",o=>{n.kind=o||void 0,t()},{maxWidth:"130px"})),i.appendChild(Z("Region:",$e,n.family??"",o=>{n.family=o||void 0,t()},{maxWidth:"150px"})),i}export function buildFindingsSectionWithFilter(e,n,t,i,r){if(!e.findings.length)return null;const d=e.findings.some(v=>v.severity==="unusual"||v.severity==="notable"),c=d?e.findings.filter(v=>v.severity!=="info").length.toString():void 0,{outer:p,content:o}=te(`Findings (${e.findings.length})`,d,c);o.appendChild(De(e.findings,i,r));const l=ue(e,i);if(!l.length)return o.appendChild(a("div",{color:F,fontSize:"11px",textAlign:"center",padding:"16px 8px"},"No findings match the current filter.")),p;const u=buildFindingsSection(l,e,n,t,!0);return u&&o.appendChild(u),p}export function buildLotTestSection(e,n,t,i,r){let d;if(i?.length&&i.every(c=>c.stats.perTestStats!==void 0)){const c=new Map;for(const p of i)for(const o of p.stats.perTestStats??[]){const l=c.get(o.testNumber);l?(l.n+=o.count,l.sum+=o.mean*o.count,l.min=Math.min(l.min,o.min),l.max=Math.max(l.max,o.max)):c.set(o.testNumber,{n:o.count,sum:o.mean*o.count,min:o.min,max:o.max})}d={perTestStats:[...c.entries()].map(([p,o])=>({testNumber:p,count:o.n,min:o.min,max:o.max,mean:o.sum/o.n}))}}if(i?.length&&i.every(c=>c.stats.testSpecYield!==void 0)){const c=new Map;for(const p of i)for(const o of p.stats.testSpecYield??[]){const l=c.get(o.testNumber);l?(l.passDies+=o.passDies,l.totalDies+=o.totalDies):c.set(o.testNumber,{passDies:o.passDies,totalDies:o.totalDies})}d={...d,testSpecYield:[...c.entries()].map(([p,o])=>({testNumber:p,totalDies:o.totalDies,yieldPercent:o.totalDies>0?o.passDies/o.totalDies*100:null}))}}return buildTestSection(e,n,t,d,r)}export function createSummaryPanelEl(e){const n=e==="top"||e==="bottom",t=a("div",{background:ve,border:M,borderRadius:"8px",padding:"12px",overflowY:n?"hidden":"auto",overflowX:n?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:"system-ui, sans-serif",fontSize:"12px",boxShadow:"0 1px 4px rgba(0,0,0,0.08)"});return n?(t.style.height="180px",t.style.width="100%"):(t.style.width="260px",t.style.maxHeight="100%"),t}export function wrapWithSummaryPanel(e,n,t){const i=t==="top"||t==="bottom",r=a("div",{display:"flex",flexDirection:i?"column":"row",gap:"8px",width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:i?"flex-start":"stretch"});return e.style.flex="1 1 0",e.style.minWidth="0",e.style.minHeight="0",t==="right"||t==="bottom"?(r.appendChild(e),r.appendChild(n)):(r.appendChild(n),r.appendChild(e)),r}function oe(e){return a("div",{fontSize:"13px",fontWeight:"700",color:W,marginBottom:"10px"},e)}function re(e,n){const t=a("button",{background:"none",border:M,borderRadius:"4px",cursor:"pointer",fontSize:"10px",color:b.iconHover,padding:"2px 7px",marginBottom:"10px",display:"block"},e);return t.type="button",t.addEventListener("click",n),t}export function renderWaferSummaryContent(e,n){const t=e.scrollTop;e.innerHTML="";const{wafer:i,dies:r,yieldSummary:d,dataCoverage:c,hbinDefs:p,sbinDefs:o,testDefs:l,statsSummary:u,passBins:v=[1],ringCount:y=4,colorScheme:R,fallbackFormat:B,onFindingClick:$,activeFindingId:L=null,findingsFilter:E,onFindingsFilterChange:T,onSaveText:m}=n;e.appendChild(oe("Wafer Summary"));const k=u?.stats.warnings;k?.length&&e.appendChild(buildWarningsBanner(k)),d&&c&&e.appendChild(re("Summary report",()=>{U(de({wafer:i,dies:r,yieldSummary:d,dataCoverage:c,hbinDefs:p,sbinDefs:o,testDefs:l,statsSummary:u,passBins:v,ringCount:y}))}));const w=[],s=u?.stats.isLotStack?u.stats:void 0,h=s?.lotSize!==void 0?{lotSize:s.lotSize,aggrMethod:he(s.aggregationMethod)}:void 0;w.push(buildMetadataInfoSection([{metadata:i.metadata??void 0}],h)),d&&c&&w.push(buildYieldSection(d,c,v));const S=r.some(f=>f.hbin!=null),C=r.some(f=>f.sbin!=null);S?w.push(buildBinSection(r,p,"hard",R,u?.stats.hardBinCounts)):C&&w.push(buildBinSection(r,o,"soft",R,u?.stats.softBinCounts)),w.push(buildRingSection(r,i,y,v)),w.push(buildQuadrantSection(r,i,y,v)),w.push(buildTestSection(r,l,B,u?.stats,m)),w.push(buildFunctionalTestSection(r,l,u?.stats.functionalYield,m)),u&&$&&E&&T&&w.push(buildFindingsSectionWithFilter(u,$,L,E,T));let x=!0;for(const f of w)f&&(x||e.appendChild(ne()),x=!1,e.appendChild(f));e.appendChild(a("div",{height:"12px",flexShrink:"0"})),e.scrollTop=t}export function renderLotSummaryContent(e,n){const t=e.scrollTop;e.innerHTML="";const{lotSummary:i,items:r,hbinDefs:d,sbinDefs:c,testDefs:p,passBins:o=[1],ringCount:l=4,colorScheme:u,fallbackFormat:v,onFindingClick:y,activeFindingId:R=null,onWaferClick:B,findingsFilter:$,onFindingsFilterChange:L,onSaveText:E}=n;e.appendChild(oe(`Lot Summary \u2014 ${i.stats.waferCount} wafer${i.stats.waferCount===1?"":"s"}`));const T=[...new Set(i.perWafer.flatMap(f=>f.summary.stats.warnings??[]))];T.length&&e.appendChild(buildWarningsBanner(T)),e.appendChild(re("Summary report",()=>{U(pe({items:r.map((f,g)=>({label:f?.label??`W${g+1}`,wafer:f?.wafer,dies:f?.dies,statsSummary:f?.statsSummary})),hbinDefs:d,sbinDefs:c,testDefs:p,passBins:o,ringCount:l}))}));const m=[],k=[],w=[];for(const f of r){if(!f){k.push([]);continue}f.wafer&&m.push(f.wafer);const g=f.dies??[];k.push(g),w.push(...g)}const s=w.some(f=>f.hbin!=null),h=w.some(f=>f.sbin!=null),S=r.map(f=>f?.statsSummary).filter(f=>!!f),C=[buildLotOverviewSection(i),buildMetadataInfoSection(r.filter(f=>f!==null).map(f=>({metadata:f.wafer?.metadata}))),buildPerWaferYieldSection(i,r,B),s?buildLotBinSection(w,d,"hard",u):h?buildLotBinSection(w,c,"soft",u):null,buildLotRingSection(k,m,l,o),buildLotQuadrantSection(k,m,l,o),p?.length?buildLotTestSection(w,p,v,S,E):null,p?.length?buildLotFunctionalSection(w,p,S,E):null];y&&$&&L&&C.push(buildFindingsSectionWithFilter(i,y,R,$,L));let x=!0;for(const f of C)f&&(x||e.appendChild(ne()),x=!1,e.appendChild(f));e.appendChild(a("div",{height:"12px",flexShrink:"0"})),e.scrollTop=t}
|
|
1
|
+
import{isParametricTest as le}from"../renderer/buildWaferMap.js";import{buildRingRegions as G,buildQuadrantRegions as U,buildRegionYieldData as de}from"../stats/regions.js";import{computeFunctionalYield as pe}from"../stats/analyzeWaferMap.js";import{openHtmlReport as X}from"../stats/renderFindingsReport.js";import{renderSummaryReportHtml as ce,renderLotSummaryReportHtml as ue}from"../stats/renderSummaryReport.js";import{buildFindingsNarrative as fe}from"../stats/findingsNarrative.js";import{filterFindings as me}from"../stats/filterFindings.js";import{buildFacetTable as he,prettyKey as K}from"../stats/facets.js";import{getColorScheme as ge}from"../renderer/colorSchemes.js";import{buildWarningsBanner as O,collectWarnings as Z}from"./warnings.js";export{O as buildWarningsBanner};import{fmt as J,fmtAggregationMethod as xe,plainBinTerms as H}from"../renderer/fmt.js";import{getUniqueTestNumbers as be}from"../renderer/buildView.js";import{quantile as q}from"../stats/math.js";import{makeLabeledSelect as ee}from"./charts/chartShell.js";import{CLR as S,sevColor as _,openModal as ve,saveTextFile as te}from"./toolbar.js";import{medianOfSorted as ye}from"../core/utils.js";const Se=S.panelBg,M=`1px solid ${S.menuBorder}`,Ce="12px",F=S.label,W=S.value,ne="10px";function s(e,n,t){const i=document.createElement(e);return n&&Object.assign(i.style,n),t!==void 0&&(i.textContent=t),i}function I(e){return s("div",{fontSize:ne,fontWeight:"700",letterSpacing:"0.06em",textTransform:"uppercase",color:F,marginBottom:"6px"},e)}function ie(e,n=!0,t){const i=s("div"),r=document.createElement("button");r.type="button",Object.assign(r.style,{display:"flex",alignItems:"center",gap:"4px",width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const d=s("span",{fontSize:"9px",color:F,transition:"transform 0.15s",transform:n?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:"1",marginRight:"1px"},"\u25B6"),c=s("span",{fontSize:ne,fontWeight:"700",letterSpacing:"0.06em",textTransform:"uppercase",color:F,flex:"1"},e);if(r.setAttribute("aria-expanded",n?"true":"false"),r.appendChild(d),r.appendChild(c),t){const l=s("span",{fontSize:"9px",fontWeight:"700",background:S.warnBg,color:S.warnText,borderRadius:"10px",padding:"1px 5px"},t);r.appendChild(l)}const p=s("div");p.style.display=n?"block":"none";let o=n;return r.addEventListener("click",()=>{o=!o,p.style.display=o?"block":"none",d.style.transform=o?"rotate(90deg)":"rotate(0deg)",r.setAttribute("aria-expanded",o?"true":"false")}),i.appendChild(r),i.appendChild(p),{outer:i,content:p}}function oe(){return s("div",{height:"1px",background:S.separator,margin:`${Ce} 0`,flexShrink:"0"})}function V(e,n,t="#2a6fc0",i,r,d){const c=s("div",{marginBottom:"5px"}),p=s("div",{display:"flex",justifyContent:"space-between",fontSize:"11px",color:W,marginBottom:"2px"}),o=s("span",{},e),l=s("span",{fontWeight:"600"},`${n.toFixed(1)}%`);p.appendChild(o),p.appendChild(l);const u=i!==void 0?i:Math.min(100,Math.max(0,n)),b=d?"#94a3b8":t,v=s("div",{position:"relative",height:"9px",background:S.bgActive,borderRadius:"4px",overflow:"hidden"}),L=s("div",{height:"100%",width:`${u}%`,background:b,borderRadius:"4px",transition:"width 0.3s ease"});if(v.appendChild(L),r!==void 0){const B=s("div",{position:"absolute",top:"0",bottom:"0",left:`${r}%`,width:"1px",background:S.infoText,opacity:"0.5"});v.appendChild(B)}return c.appendChild(p),c.appendChild(v),c}function P(e,n,t){const i=s("div",{background:S.menuBg,border:M,borderRadius:"6px",padding:"8px 10px",textAlign:"center",flex:"1"}),r=s("div",{fontSize:"20px",fontWeight:"700",color:W,lineHeight:"1.2"},e),d=s("div",{fontSize:"10px",color:F,marginTop:"2px"},n);return i.appendChild(r),i.appendChild(d),t&&i.appendChild(s("div",{fontSize:"9px",color:F,opacity:"0.85"},t)),i}function we(e,n){const t=s("div",{display:"flex",justifyContent:"space-between",fontSize:"11px",gap:"8px",marginBottom:"3px"}),i=s("span",{color:F,flexShrink:"0"},e),r=s("span",{color:W,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},n);return t.appendChild(i),t.appendChild(r),t}function ke(e,n){const t=s("div",{display:"flex",fontSize:"11px",gap:"6px",marginBottom:"3px"}),i=s("span",{color:F,flexShrink:"0"},`${e}:`),r=s("span",{color:W,fontWeight:"500",wordBreak:"break-all"},n);return t.appendChild(i),t.appendChild(r),t}export function metadataEntries(e){return Object.entries(e).filter(([,n])=>n!=null&&n!=="").map(([n,t])=>[n,String(t)])}export function buildFacetSummaryChips(e,n=3){if(!e.length)return null;const t=s("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 10px",fontSize:"11px"});for(const i of e){const r=s("span",{whiteSpace:"nowrap"}),d=s("span",{color:F},`${K(i.key)}: `);r.appendChild(d);const c=i.values.slice(0,n),p=i.values.length-c.length;let o=c.map(l=>l.value).join(", ");p>0&&(o+=` +${p} more`),r.appendChild(document.createTextNode(o)),t.appendChild(r)}return t}export function buildMetadataStripRow(e,n,t){const i=he(e,t),r=buildFacetSummaryChips(i);if(!r&&!n)return null;const d=s("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px"});if(n){const c=s("span",{fontWeight:"500",whiteSpace:"nowrap"},n.aggrMethod?`${n.lotSize} wafers stacked \xB7 ${n.aggrMethod}`:`${n.lotSize} wafers stacked`);d.appendChild(c)}return r&&d.appendChild(r),d}const Be={display:"flex",flexDirection:"column",gap:"6px",background:S.menuBg,border:`1px solid ${S.menuBorder}`,borderRadius:"6px",padding:"6px 10px",boxShadow:"0 1px 4px rgba(0,0,0,0.10)",fontSize:"12px",lineHeight:"1",boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(e,n,t){const i=buildMetadataStripRow(e,n,t);if(!i)return null;const r=s("div",Be);return r.appendChild(i),r}export function buildCompactMetadataRows(e){const n=metadataEntries(e);if(!n.length)return null;const t=s("div");for(const[i,r]of n)t.appendChild(ke(K(i),r));return t}export function buildMetadataInfoSection(e,n){const t=buildMetadataStripRow(e,n,{facetableOnly:e.length>1});if(!t)return null;const i=s("div");return i.appendChild(I("Wafer Info")),i.appendChild(t),i}export function buildYieldSection(e,n,t=[1]){const i=s("div");i.appendChild(I("Summary"));const r=s("div",{display:"flex",gap:"6px",marginBottom:"8px"});if(r.appendChild(P(String(n.totalDies),"Total dies")),e.partialDies>0&&r.appendChild(P(String(e.partialDies),"Partial")),e.yieldPercent!==null){const d=t.length===1?`bin ${t[0]}`:`bins ${t.join(", ")}`;r.appendChild(P(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return i.appendChild(r),e.edgeExcludedDies>0&&i.appendChild(we("Edge excluded (outer zone)",String(e.edgeExcludedDies))),i}export function buildBinSection(e,n,t,i,r){const d=new Map;if(r)for(const[u,b]of Object.entries(r))d.set(Number(u),b);else for(const u of e){if(u.partial||u.edgeExcluded)continue;const b=t==="hard"?u.hbin:u.sbin;b!=null&&d.set(b,(d.get(b)??0)+1)}if(!d.size)return null;const c=[...d.values()].reduce((u,b)=>u+b,0),p=n?new Map(n.map(u=>[u.bin,u])):null,o=[...d.entries()].sort((u,b)=>u[0]-b[0]),l=s("div");l.appendChild(I(t==="hard"?"Hard Bin Breakdown":"Soft Bin Breakdown"));for(const[u,b]of o){const v=p?.get(u),L=v?.name?`Bin ${u} \xB7 ${v.name}`:`Bin ${u}`,B=b/c*100,$=ge(i),R=(i==="custom"?v?.color:void 0)??$.forBin(u);l.appendChild(V(`${L} (${b})`,B,R))}return l}export function buildLotBinSection(e,n,t,i){return buildBinSection(e,n,t,i)}function Y(e,n,t,i,r,d){const c=de(e,n,t,i,r);if(!c.length)return null;const p=s("div");p.appendChild(I(d));for(const{label:o,n:l,yieldPercent:u}of c)p.appendChild(V(`${o} (N=${l})`,u));return p}export function buildRingSection(e,n,t,i){return Y([e],[n],t,i,G,"Ring Yield")}export function buildQuadrantSection(e,n,t,i){return Y([e],[n],t,i,U,"Quadrant Yield")}export function buildLotRingSection(e,n,t,i){return Y(e,n,t,i,G,"Ring Yield")}export function buildLotQuadrantSection(e,n,t,i){return Y(e,n,t,i,U,"Quadrant Yield")}export function buildLotOverviewSection(e){const n=s("div");n.appendChild(I("Lot Summary"));const t=s("div",{display:"flex",gap:"6px",marginBottom:"8px"});t.appendChild(P(String(e.stats.waferCount),"Wafers"));const i=e.perWafer.map(r=>r.summary.stats.yieldPercent).filter(r=>r!==null);if(i.length){const r=i.reduce((d,c)=>d+c,0)/i.length;t.appendChild(P(`${r.toFixed(1)}%`,"Mean wafer yield"))}return n.appendChild(t),n}export function buildPerWaferYieldSection(e,n,t){const i=e.perWafer.map(l=>({waferIndex:l.waferIndex,label:(n[l.waferIndex]?.label??`W${l.waferIndex+1}`).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:l.summary.stats.yieldPercent})).filter(l=>l.yieldPct!==null);if(!i.length)return null;const r=Math.min(...i.map(l=>l.yieldPct)),d=Math.max(...i.map(l=>l.yieldPct)),c=r===d?"":` (${r.toFixed(1)}\u2013${d.toFixed(1)}%)`,p=ye([...i.map(l=>l.yieldPct)].sort((l,u)=>l-u)),o=s("div");o.appendChild(I("Wafer Yield"+c));for(const{waferIndex:l,label:u,yieldPct:b}of i){const v=V(u,b,void 0,void 0,p,b<p);t&&(v.style.cursor="pointer",v.style.borderRadius="4px",v.style.padding="2px 3px",v.style.marginLeft="-3px",v.style.marginRight="-3px",v.setAttribute("role","button"),v.setAttribute("aria-label",`${u}, ${b.toFixed(1)}% yield \u2014 view wafer`),v.tabIndex=0,v.addEventListener("mouseenter",()=>{v.style.background=S.bgHover}),v.addEventListener("mouseleave",()=>{v.style.background=""}),v.addEventListener("focus",()=>{v.style.background=S.bgHover}),v.addEventListener("blur",()=>{v.style.background=""}),v.addEventListener("click",()=>t(l)),v.addEventListener("keydown",L=>{(L.key==="Enter"||L.key===" ")&&(L.preventDefault(),t(l))})),o.appendChild(v)}return o}function $e(e){const n=[...e].sort((r,d)=>r-d),t=e.reduce((r,d)=>r+d,0)/e.length,i=e.reduce((r,d)=>r+(d-t)**2,0)/e.length;return{min:n[0],max:n[n.length-1],mean:t,count:e.length,stddev:Math.sqrt(i),median:q(n,.5),q1:q(n,.25),q3:q(n,.75)}}function A(e){return/[",\n]/.test(e)?`"${e.replace(/"/g,'""')}"`:e}export function buildTestSection(e,n,t,i,r){const d=e.filter(a=>!a.partial&&!a.edgeExcluded),c=new Map((i?.perTestStats??[]).map(a=>[a.testNumber,a])),p=new Map((i?.testSpecYield??[]).map(a=>[a.testNumber,a]));let o;if(n?.length?o=n.filter(le).map(a=>({testNumber:a.testNumber,name:a.name,unit:a.unit,limitLow:a.limitLow,limitHigh:a.limitHigh})):o=be(d).map(h=>({testNumber:h,name:`Test ${h}`})),!o.length)return null;const l=o.filter(a=>d.some(h=>{const y=h.testValues?.[a.testNumber];return y!==void 0&&isFinite(y)}));if(!l.length)return null;const u=l.some(a=>a.limitLow!==void 0||a.limitHigh!==void 0),b=[];for(const a of l){const h=c.get(a.testNumber),y=h&&h.stddev!==void 0&&h.median!==void 0&&h.q1!==void 0&&h.q3!==void 0;let w;if(y){const g=h;w={testNumber:a.testNumber,min:g.min,max:g.max,mean:g.mean,count:g.count,stddev:g.stddev,median:g.median,q1:g.q1,q3:g.q3}}else{const g=d.map(D=>D.testValues?.[a.testNumber]).filter(D=>D!==void 0&&isFinite(D));if(!g.length)continue;w={testNumber:a.testNumber,...$e(g)}}let x=null,m=0;if(a.limitLow!==void 0||a.limitHigh!==void 0){const g=p.get(a.testNumber);if(g)({yieldPercent:x,totalDies:m}=g);else{const D=d.map(N=>N.testValues?.[a.testNumber]).filter(N=>N!==void 0&&isFinite(N)),j=D.filter(N=>a.limitLow!==void 0&&N<a.limitLow||a.limitHigh!==void 0&&N>a.limitHigh).length;m=D.length,x=D.length>0?(D.length-j)/D.length*100:null}}b.push({entry:a,stats:w,specYieldPct:x,specN:m})}if(!b.length)return null;const v=s("div"),L=s("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"6px"}),B=I(`Test Values (${b.length})`);B.style.marginBottom="0",L.appendChild(B);const $=document.createElement("button");$.type="button",$.textContent="Export CSV",Object.assign($.style,{background:"none",border:M,borderRadius:"4px",cursor:"pointer",fontSize:"10px",color:S.iconHover,padding:"2px 7px"}),$.addEventListener("click",()=>{const a=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];u&&a.push("LSL","USL","Spec Yield %","Spec Yield N");const h=[a.map(A).join(",")],y=w=>J(w,void 0,"engineering");for(const{entry:w,stats:x,specYieldPct:m,specN:g}of b){const D=[w.name,w.unit??"",String(x.count),y(x.min),y(x.q1),y(x.median),y(x.mean),y(x.q3),y(x.max),y(x.stddev)];u&&D.push(w.limitLow!==void 0?y(w.limitLow):"",w.limitHigh!==void 0?y(w.limitHigh):"",m!==null?m.toFixed(1):"",w.limitLow!==void 0||w.limitHigh!==void 0?String(g):""),h.push(D.map(A).join(","))}te(h.join(`
|
|
2
|
+
`),"test-values.csv","text/csv",r)}),L.appendChild($),v.appendChild(L);const R=s("table",{width:"100%",borderCollapse:"collapse",fontSize:"11px"}),T=document.createElement("thead"),E=document.createElement("tr"),f=["Test","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];u&&f.push("LSL","USL","Spec yield");for(const a of f){const h=s("th",{textAlign:a==="Test"?"left":"right",fontWeight:"700",fontSize:"10px",letterSpacing:"0.03em",textTransform:"uppercase",color:F,padding:"3px 8px 5px",borderBottom:`1px solid ${S.menuBorder}`,whiteSpace:"nowrap"},a);E.appendChild(h)}T.appendChild(E),R.appendChild(T);const k=document.createElement("tbody");for(const{entry:a,stats:h,specYieldPct:y,specN:w}of b){const x=D=>J(D,a.unit,t),m=document.createElement("tr"),g=(D,j="right")=>{const N=s("td",{textAlign:j,padding:"4px 8px",borderBottom:`1px solid ${S.menuBorder}`,color:W,whiteSpace:"nowrap"},D);m.appendChild(N)};g(a.name,"left"),g(`${h.count}`),g(x(h.min)),g(x(h.q1)),g(x(h.median)),g(x(h.mean)),g(x(h.q3)),g(x(h.max)),g(x(h.stddev)),u&&(g(a.limitLow!==void 0?x(a.limitLow):"\u2014"),g(a.limitHigh!==void 0?x(a.limitHigh):"\u2014"),g(y!==null?`${y.toFixed(1)}% (N=${w})`:"\u2014")),k.appendChild(m)}R.appendChild(k);const C=s("div",{overflowX:"auto"});return C.appendChild(R),v.appendChild(C),v}export function buildFunctionalTestSection(e,n,t,i){const r=t??pe(e,n);if(!r?.length)return null;const d=s("div"),c=s("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"6px"}),p=I(`Functional Tests (${r.length})`);p.style.marginBottom="0",c.appendChild(p);const o=document.createElement("button");o.type="button",o.textContent="Export CSV",Object.assign(o.style,{background:"none",border:M,borderRadius:"4px",cursor:"pointer",fontSize:"10px",color:S.iconHover,padding:"2px 7px"}),o.addEventListener("click",()=>{const B=[["Test","N","Pass","Fail","Pass Rate %"].map(A).join(",")];for(const $ of r)B.push([$.label,String($.totalDies),String($.passDies),String($.failDies),$.passRatePercent!==null?$.passRatePercent.toFixed(1):""].map(A).join(","));te(B.join(`
|
|
3
|
+
`),"functional-tests.csv","text/csv",i)}),c.appendChild(o),d.appendChild(c);const l=s("table",{width:"100%",borderCollapse:"collapse",fontSize:"11px"}),u=document.createElement("thead"),b=document.createElement("tr");for(const B of["Test","N","Pass","Fail","Pass rate"])b.appendChild(s("th",{textAlign:B==="Test"?"left":"right",fontWeight:"700",fontSize:"10px",letterSpacing:"0.03em",textTransform:"uppercase",color:F,padding:"3px 8px 5px",borderBottom:`1px solid ${S.menuBorder}`,whiteSpace:"nowrap"},B));u.appendChild(b),l.appendChild(u);const v=document.createElement("tbody");for(const B of r){const $=document.createElement("tr"),R=(T,E="right")=>{$.appendChild(s("td",{textAlign:E,padding:"4px 8px",borderBottom:`1px solid ${S.menuBorder}`,color:W,whiteSpace:"nowrap"},T))};R(B.label,"left"),R(String(B.totalDies)),R(String(B.passDies)),R(String(B.failDies)),R(B.passRatePercent!==null?`${B.passRatePercent.toFixed(1)}% (N=${B.totalDies})`:"\u2014"),v.appendChild($)}l.appendChild(v);const L=s("div",{overflowX:"auto"});return L.appendChild(l),d.appendChild(L),d}export function buildLotFunctionalSection(e,n,t,i){if(t?.length&&t.every(r=>r.stats.functionalYield!==void 0)){const r=new Map;for(const c of t)for(const p of c.stats.functionalYield??[]){const o=r.get(p.testNumber)??{label:p.label,passDies:0,failDies:0,totalDies:0};o.passDies+=p.passDies,o.failDies+=p.failDies,o.totalDies+=p.totalDies,r.set(p.testNumber,o)}const d=[...r.entries()].map(([c,p])=>({testNumber:c,...p,passRatePercent:p.totalDies>0?p.passDies/p.totalDies*100:null}));if(d.length)return buildFunctionalTestSection(e,n,d,i)}return buildFunctionalTestSection(e,n,void 0,i)}const z={unusual:0,notable:1,info:2};function Q(e){return s("span",{display:"inline-block",width:"7px",height:"7px",borderRadius:"50%",background:_(e),flexShrink:"0"})}function re(e,n){let t=e.summary;return n&&(t.startsWith(`${n} has `)?t=t.slice(n.length+5):t.startsWith(`${n} `)&&(t=t.slice(n.length+1))),t=H(t),t.length?t[0].toUpperCase()+t.slice(1):t}export function buildFindingsSection(e,n,t,i,r=!1){if(!e.length)return null;const d=e.some(f=>f.severity==="unusual"||f.severity==="notable"),c=d?e.filter(f=>f.severity!=="info").length.toString():void 0,{outer:p,content:o}=r?(()=>{const f=s("div");return{outer:f,content:f}})():ie(`Findings (${e.length})`,d,c);function l(f){return f.reduce((k,C)=>z[C.severity]<z[k]?C.severity:k,"info")}function u(f){const k=new Map;for(const a of f){const h=`${a.comparison.family}\0${a.comparison.left}`,y=k.get(h)??[];y.push(a),k.set(h,y)}const C=[...k.entries()].map(([a,h])=>{const y=[...h].sort((w,x)=>z[w.severity]-z[x.severity]);return{key:a,findings:y,worst:l(y)}});return C.sort((a,h)=>z[a.worst]-z[h.worst]),C}function b(f,k){const a={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[f]??f;return k.toLowerCase().startsWith(a.toLowerCase())?k:`${a}: ${k}`}const v=e.filter(f=>f.comparison.family==="spatial-pattern"),L=new Set([...v.flatMap(f=>f.relatedIds??[]),...e.flatMap(f=>f.absorbedIds??[])]),B=e.filter(f=>f.comparison.family!=="spatial-pattern"&&!L.has(f.id)),$=u(B);function R(f,k=!1,C){const a=i===f.id,h=document.createElement("button");return h.type="button",h.dataset.wmapFinding=f.id,h.textContent=re(f,C),h.title=f.summary,Object.assign(h.style,{border:`1px solid ${S.menuBorder}`,borderLeft:`3px solid ${_(f.severity)}`,background:a?S.bgActive:S.menuBg,borderRadius:"6px",padding:k?"6px 10px":"8px 10px",textAlign:"left",fontSize:k?"10px":"11px",fontWeight:a?"600":"400",color:S.iconHover,cursor:"pointer",width:"100%",marginBottom:"4px"}),h.addEventListener("click",()=>t(f,h)),h}const T=H(fe(e)??"");if(T){const f=s("div",{background:S.bgActive,borderRadius:"6px",padding:"8px 10px",marginBottom:"8px",display:"flex",gap:"8px",alignItems:"flex-start"}),k=s("span",{flex:"1",fontSize:"12px",lineHeight:"1.5",color:S.iconHover},T);f.appendChild(k);const C=s("button",{flexShrink:"0",border:"none",background:"none",fontSize:"10px",color:S.icon,cursor:"pointer",padding:"0",lineHeight:"1.5",whiteSpace:"nowrap"},"Detail \u25B8");C.type="button",C.addEventListener("click",()=>{const a=ve({title:"Findings Summary",onClose:()=>{},anchor:C}),h=s("p",{fontSize:"16px",lineHeight:"1.6",color:S.iconHover,padding:"20px 24px 16px",margin:"0",borderBottom:`1px solid ${S.menuBorder}`,flexShrink:"0"},T);a.contentWrap.appendChild(h);const y=s("div",{overflowY:"auto",padding:"16px 24px",flex:"1"}),w=(x,m)=>{const g=s("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:"13px",fontWeight:"600",color:W,marginTop:"10px",marginBottom:"4px"});return g.appendChild(Q(x)),g.appendChild(s("span",{},m)),g};for(const x of v){y.appendChild(w(x.severity,x.comparison.left)),y.appendChild(s("div",{fontSize:"13px",color:S.iconHover,padding:"3px 0 3px 15px",marginBottom:"2px"},H(x.summary)));const m=e.filter(g=>x.relatedIds?.includes(g.id));for(const g of m)y.appendChild(s("div",{fontSize:"12px",color:S.icon,padding:"2px 0 2px 23px",marginBottom:"2px"},H(g.summary)))}for(const x of $){const[m,g]=x.key.split("\0");y.appendChild(w(x.worst,b(m,g)));for(const D of x.findings)y.appendChild(s("div",{fontSize:"13px",color:S.iconHover,padding:"3px 0 3px 15px",marginBottom:"2px"},re(D,g)))}a.contentWrap.appendChild(y),Object.assign(a.contentWrap.style,{flexDirection:"column",overflow:"hidden"})}),f.appendChild(C),o.appendChild(f)}let E=!0;for(const f of v){E||o.appendChild(s("div",{height:"1px",background:S.separator,margin:"4px 0"})),E=!1;const k=e.filter(w=>f.relatedIds?.includes(w.id)),C=k.length>0,a=s("div",{position:"relative",marginBottom:C?"2px":"4px"}),h=i===f.id,y=document.createElement("button");if(y.type="button",y.dataset.wmapFinding=f.id,Object.assign(y.style,{border:`1px solid ${S.menuBorder}`,borderLeft:`3px solid ${_(f.severity)}`,background:h?S.bgActive:S.menuBg,borderRadius:"6px",padding:"8px 32px 8px 10px",textAlign:"left",fontSize:"11px",fontWeight:h?"600":"500",color:S.iconHover,cursor:"pointer",width:"100%"}),y.textContent=H(f.summary),y.title=f.summary,y.addEventListener("click",()=>t(f,y)),a.appendChild(y),C){const w=s("div",{display:"none",paddingLeft:"12px",marginBottom:"4px"});for(const g of k)w.appendChild(R(g,!0));a.appendChild(w);let x=!1;const m=s("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:"10px",color:S.icon,cursor:"pointer",padding:"2px 4px",lineHeight:"1"},"\u25B8");m.type="button",m.title="Show supporting findings",m.addEventListener("click",g=>{g.stopPropagation(),x=!x,w.style.display=x?"block":"none",m.textContent=x?"\u25BE":"\u25B8",m.title=x?"Hide supporting findings":"Show supporting findings"}),a.appendChild(m)}o.appendChild(a)}for(const f of $){E||o.appendChild(s("div",{height:"1px",background:S.separator,margin:"4px 0"})),E=!1;const[k,C]=f.key.split("\0"),a=s("div",{display:"flex",alignItems:"center",gap:"6px",fontSize:"11px",fontWeight:"600",color:W,margin:"2px 0 4px"});a.appendChild(Q(f.worst)),a.appendChild(s("span",{},b(k,C))),o.appendChild(a);for(const h of f.findings)o.appendChild(R(h,!1,C))}return p}const Le=[{value:"",label:"All kinds"},{value:"yield",label:"Yield"},{value:"hardBin",label:"Hard bin"},{value:"softBin",label:"Soft bin"},{value:"test",label:"Test value"},{value:"functionalTest",label:"Functional test"},{value:"spatialPattern",label:"Spatial pattern"}],Re=[{value:"",label:"All regions"},{value:"ring",label:"Ring"},{value:"quadrant",label:"Quadrant"},{value:"reticle-position",label:"Reticle position"},{value:"test-site",label:"Test site"},{value:"wafer",label:"Wafer"},{value:"sector",label:"Sector"},{value:"cluster",label:"Cluster"},{value:"edge-arc",label:"Edge arc"},{value:"spatial-pattern",label:"Spatial pattern"}],De=["unusual","notable","info"],Ee={unusual:"Unusual",notable:"Notable",info:"Info"};function Te(e,n,t){const i=s("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:"10px",marginBottom:"10px",paddingBottom:"10px",borderBottom:`1px solid ${S.separator}`}),r={unusual:0,notable:0,info:0};for(const o of e)r[o.severity]++;const d=De.filter(o=>r[o]>0),c=new Set(n.severity===void 0?d:Array.isArray(n.severity)?n.severity:[n.severity]),p=s("div",{display:"flex",gap:"4px",flexWrap:"wrap"});for(const o of d){const l=document.createElement("button");l.type="button";const u=()=>{const b=c.has(o);l.setAttribute("aria-pressed",b?"true":"false"),Object.assign(l.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${S.menuBorder}`,borderRadius:"10px",background:b?S.bgActive:"none",opacity:b?"1":"0.5",color:S.text,fontSize:"11px",padding:"2px 8px",cursor:"pointer"})};l.appendChild(Q(o)),l.appendChild(s("span",{},`${Ee[o]} ${r[o]}`)),l.title=c.has(o)?"Click to hide these findings":"Click to show these findings",u(),l.addEventListener("click",()=>{c.has(o)?c.delete(o):c.add(o),n.severity=c.size===d.length?void 0:[...c],t()}),p.appendChild(l)}return i.appendChild(p),i.appendChild(ee("Kind:",Le,n.kind??"",o=>{n.kind=o||void 0,t()},{maxWidth:"130px"})),i.appendChild(ee("Region:",Re,n.family??"",o=>{n.family=o||void 0,t()},{maxWidth:"150px"})),i}export function buildFindingsSectionWithFilter(e,n,t,i,r){if(!e.findings.length)return null;const d=e.findings.some(b=>b.severity==="unusual"||b.severity==="notable"),c=d?e.findings.filter(b=>b.severity!=="info").length.toString():void 0,{outer:p,content:o}=ie(`Findings (${e.findings.length})`,d,c);o.appendChild(Te(e.findings,i,r));const l=me(e,i);if(!l.length)return o.appendChild(s("div",{color:F,fontSize:"11px",textAlign:"center",padding:"16px 8px"},"No findings match the current filter.")),p;const u=buildFindingsSection(l,e,n,t,!0);return u&&o.appendChild(u),p}export function buildLotTestSection(e,n,t,i,r){let d;if(i?.length&&i.every(c=>c.stats.perTestStats!==void 0)){const c=new Map;for(const p of i)for(const o of p.stats.perTestStats??[]){const l=c.get(o.testNumber);l?(l.n+=o.count,l.sum+=o.mean*o.count,l.min=Math.min(l.min,o.min),l.max=Math.max(l.max,o.max)):c.set(o.testNumber,{n:o.count,sum:o.mean*o.count,min:o.min,max:o.max})}d={perTestStats:[...c.entries()].map(([p,o])=>({testNumber:p,count:o.n,min:o.min,max:o.max,mean:o.sum/o.n}))}}if(i?.length&&i.every(c=>c.stats.testSpecYield!==void 0)){const c=new Map;for(const p of i)for(const o of p.stats.testSpecYield??[]){const l=c.get(o.testNumber);l?(l.passDies+=o.passDies,l.totalDies+=o.totalDies):c.set(o.testNumber,{passDies:o.passDies,totalDies:o.totalDies})}d={...d,testSpecYield:[...c.entries()].map(([p,o])=>({testNumber:p,totalDies:o.totalDies,yieldPercent:o.totalDies>0?o.passDies/o.totalDies*100:null}))}}return buildTestSection(e,n,t,d,r)}export function createSummaryPanelEl(e){const n=e==="top"||e==="bottom",t=s("div",{background:Se,border:M,borderRadius:"8px",padding:"12px",overflowY:n?"hidden":"auto",overflowX:n?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:"system-ui, sans-serif",fontSize:"12px",boxShadow:"0 1px 4px rgba(0,0,0,0.08)"});return n?(t.style.height="180px",t.style.width="100%"):(t.style.width="260px",t.style.maxHeight="100%"),t}export function wrapWithSummaryPanel(e,n,t){const i=t==="top"||t==="bottom",r=s("div",{display:"flex",flexDirection:i?"column":"row",gap:"8px",width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:i?"flex-start":"stretch"});return e.style.flex="1 1 0",e.style.minWidth="0",e.style.minHeight="0",t==="right"||t==="bottom"?(r.appendChild(e),r.appendChild(n)):(r.appendChild(n),r.appendChild(e)),r}function ae(e){return s("div",{fontSize:"13px",fontWeight:"700",color:W,marginBottom:"10px"},e)}function se(e,n){const t=s("button",{background:"none",border:M,borderRadius:"4px",cursor:"pointer",fontSize:"10px",color:S.iconHover,padding:"2px 7px",marginBottom:"10px",display:"block"},e);return t.type="button",t.addEventListener("click",n),t}export function renderWaferSummaryContent(e,n){const t=e.scrollTop;e.innerHTML="";const{wafer:i,dies:r,yieldSummary:d,dataCoverage:c,hbinDefs:p,sbinDefs:o,testDefs:l,statsSummary:u,passBins:b=[1],ringCount:v=4,colorScheme:L,fallbackFormat:B,onFindingClick:$,activeFindingId:R=null,findingsFilter:T,onFindingsFilterChange:E,onSaveText:f}=n;e.appendChild(ae("Wafer Summary"));const k=n.warnings??Z({statsSummary:u});k.length&&e.appendChild(O(k)),d&&c&&e.appendChild(se("Summary report",()=>{X(ce({wafer:i,dies:r,yieldSummary:d,dataCoverage:c,hbinDefs:p,sbinDefs:o,testDefs:l,statsSummary:u,passBins:b,ringCount:v}))}));const C=[],a=u?.stats.isLotStack?u.stats:void 0,h=a?.lotSize!==void 0?{lotSize:a.lotSize,aggrMethod:xe(a.aggregationMethod)}:void 0;C.push(buildMetadataInfoSection([{metadata:i.metadata??void 0}],h)),d&&c&&C.push(buildYieldSection(d,c,b));const y=r.some(m=>m.hbin!=null),w=r.some(m=>m.sbin!=null);y?C.push(buildBinSection(r,p,"hard",L,u?.stats.hardBinCounts)):w&&C.push(buildBinSection(r,o,"soft",L,u?.stats.softBinCounts)),C.push(buildRingSection(r,i,v,b)),C.push(buildQuadrantSection(r,i,v,b)),C.push(buildTestSection(r,l,B,u?.stats,f)),C.push(buildFunctionalTestSection(r,l,u?.stats.functionalYield,f)),u&&$&&T&&E&&C.push(buildFindingsSectionWithFilter(u,$,R,T,E));let x=!0;for(const m of C)m&&(x||e.appendChild(oe()),x=!1,e.appendChild(m));e.appendChild(s("div",{height:"12px",flexShrink:"0"})),e.scrollTop=t}export function renderLotSummaryContent(e,n){const t=e.scrollTop;e.innerHTML="";const{lotSummary:i,items:r,hbinDefs:d,sbinDefs:c,testDefs:p,passBins:o=[1],ringCount:l=4,colorScheme:u,fallbackFormat:b,onFindingClick:v,activeFindingId:L=null,onWaferClick:B,findingsFilter:$,onFindingsFilterChange:R,onSaveText:T}=n;e.appendChild(ae(`Lot Summary \u2014 ${i.stats.waferCount} wafer${i.stats.waferCount===1?"":"s"}`));const E=n.warnings??Z({lotStatsSummary:i});E.length&&e.appendChild(O(E)),e.appendChild(se("Summary report",()=>{X(ue({items:r.map((m,g)=>({label:m?.label??`W${g+1}`,wafer:m?.wafer,dies:m?.dies,statsSummary:m?.statsSummary})),hbinDefs:d,sbinDefs:c,testDefs:p,passBins:o,ringCount:l}))}));const f=[],k=[],C=[];for(const m of r){if(!m){k.push([]);continue}m.wafer&&f.push(m.wafer);const g=m.dies??[];k.push(g),C.push(...g)}const a=C.some(m=>m.hbin!=null),h=C.some(m=>m.sbin!=null),y=r.map(m=>m?.statsSummary).filter(m=>!!m),w=[buildLotOverviewSection(i),buildMetadataInfoSection(r.filter(m=>m!==null).map(m=>({metadata:m.wafer?.metadata}))),buildPerWaferYieldSection(i,r,B),a?buildLotBinSection(C,d,"hard",u):h?buildLotBinSection(C,c,"soft",u):null,buildLotRingSection(k,f,l,o),buildLotQuadrantSection(k,f,l,o),p?.length?buildLotTestSection(C,p,b,y,T):null,p?.length?buildLotFunctionalSection(C,p,y,T):null];v&&$&&R&&w.push(buildFindingsSectionWithFilter(i,v,L,$,R));let x=!0;for(const m of w)m&&(x||e.appendChild(oe()),x=!1,e.appendChild(m));e.appendChild(s("div",{height:"12px",flexShrink:"0"})),e.scrollTop=t}
|
|
@@ -3,7 +3,7 @@ import type { Die } from '../core/dies.js';
|
|
|
3
3
|
import type { TestDef, MetadataFieldDef } from '../renderer/buildWaferMap.js';
|
|
4
4
|
import type { StatsSeverity } from '../stats/types.js';
|
|
5
5
|
export declare function logWmapVersionOnce(): void;
|
|
6
|
-
export declare const WMAP_TOKEN_NAMES: readonly ["z", "icon", "icon-hover", "icon-active", "bg-hover", "bg-active", "separator", "surface", "border", "menu-hover", "menu-active", "panel-bg", "text-muted", "text", "text-strong", "warn-bg", "warn-border", "warn-text", "info-bg", "info-text", "selected", "finding-indicator", "canvas-bg"];
|
|
6
|
+
export declare const WMAP_TOKEN_NAMES: readonly ["z", "icon", "icon-hover", "icon-active", "bg-hover", "bg-active", "separator", "surface", "border", "menu-hover", "menu-active", "panel-bg", "text-muted", "text", "text-strong", "warn-bg", "warn-border", "warn-text", "err-bg", "err-border", "err-text", "info-bg", "info-text", "selected", "finding-indicator", "canvas-bg"];
|
|
7
7
|
export type WmapTokenName = (typeof WMAP_TOKEN_NAMES)[number];
|
|
8
8
|
export declare const CLR: {
|
|
9
9
|
icon: string;
|
|
@@ -23,6 +23,9 @@ export declare const CLR: {
|
|
|
23
23
|
warnBg: string;
|
|
24
24
|
warnBorder: string;
|
|
25
25
|
warnText: string;
|
|
26
|
+
errBg: string;
|
|
27
|
+
errBorder: string;
|
|
28
|
+
errText: string;
|
|
26
29
|
infoBg: string;
|
|
27
30
|
infoText: string;
|
|
28
31
|
findingHighlight: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{getUniqueTestNumbers as ue}from"../renderer/buildView.js";import{dieHasTestData as pe}from"../renderer/buildWaferMap.js";import{prettyKey as me}from"../core/utils.js";import{listColorSchemes as oe}from"../renderer/colorSchemes.js";import{ICONS as _}from"./icons.js";import{WMAP_VERSION as fe,WMAP_BUILD_TIME as be}from"./version.js";let ie=!1;export function logWmapVersionOnce(){ie||(ie=!0,console.log(`[wmap] v${fe} (built ${be})`))}export const WMAP_TOKEN_NAMES=["z","icon","icon-hover","icon-active","bg-hover","bg-active","separator","surface","border","menu-hover","menu-active","panel-bg","text-muted","text","text-strong","warn-bg","warn-border","warn-text","info-bg","info-text","selected","finding-indicator","canvas-bg"];const y=(e,t)=>`var(--wmap-${e}, ${t})`;export const CLR={icon:y("icon","#506784"),iconHover:y("icon-hover","#2a3f5f"),iconActive:y("icon-active","#1a65ca"),bgHover:y("bg-hover","#edf0f8"),bgActive:y("bg-active","#dce8f8"),separator:y("separator","rgba(0,0,0,0.12)"),menuBg:y("surface","#fff"),menuBorder:y("border","rgba(0,0,0,0.12)"),menuHover:y("menu-hover","#f0f4fc"),menuActive:y("menu-active","#dce8f8"),panelBg:y("panel-bg","#fafbfc"),label:y("text-muted","#647687"),value:y("text-strong","#1f2f43"),text:y("text","#333"),warnBg:y("warn-bg","#fffbe6"),warnBorder:y("warn-border","#f0c040"),warnText:y("warn-text","#7a5800"),infoBg:y("info-bg","#dce8f8"),infoText:y("info-text","#334155"),findingHighlight:y("selected","#e07a20"),findingIndicator:y("finding-indicator","#b7551a")};export function sevColor(e){return e==="unusual"?"#a84112":e==="notable"?"#8a6500":CLR.icon}export const ROTATIONS=[0,90,180,270],INLINE_TEST_LIMIT=6,MENU_SEARCH_THRESHOLD=8,DEFAULT_OVERLAY_Z=6e3,Z_BASE=`var(--wmap-z, ${DEFAULT_OVERLAY_Z})`,Z_ABOVE=`calc(var(--wmap-z, ${DEFAULT_OVERLAY_Z}) + 1)`,Z_ABOVE2=`calc(var(--wmap-z, ${DEFAULT_OVERLAY_Z}) + 2)`;export function applyOverlayZ(e){if(e==null)return()=>{};const t=document.documentElement,n=t.style.getPropertyValue("--wmap-z");return t.style.setProperty("--wmap-z",String(e)),()=>{n?t.style.setProperty("--wmap-z",n):t.style.removeProperty("--wmap-z")}}export function copyWmapThemeTokens(e,t){const n=getComputedStyle(e);for(const a of WMAP_TOKEN_NAMES){const i=n.getPropertyValue(`--wmap-${a}`).trim();i&&t.style.setProperty(`--wmap-${a}`,i)}}export function syncWmapPopupTheme(e,t,n){const a=()=>{copyWmapThemeTokens(e,t),n?.()},i=new window.MutationObserver(a);i.observe(e,{attributes:!0,attributeFilter:["style","class"]}),i.observe(document.documentElement,{attributes:!0,attributeFilter:["style","class"]});const s=window.matchMedia("(prefers-color-scheme: dark)");return s.addEventListener("change",a),()=>{i.disconnect(),s.removeEventListener("change",a)}}let ee=null;export function setDetachWindowOpener(e){ee=e}export function openDetachWindow(e){return ee?ee(e):window.open("","_blank","width=560,height=600")}export const MODE_LABELS={value:"Test Value",hardBin:"Hard Bin",softBin:"Soft Bin",stackedValues:"Stacked Test Values",stackedBins:"Stacked Hard Bins",stackedSoftBins:"Stacked Soft Bins",metadata:"Metadata"},BIN_LEGEND_MODES=new Set(["hardBin","softBin","metadata"]),STACKED_MODES=new Set(["stackedValues","stackedBins","stackedSoftBins"]);export function saveImageBlob(e,t,n){const a=`${t}.png`;if(n){n(e,a);return}const i=URL.createObjectURL(e),s=document.createElement("a");s.href=i,s.download=a,s.click(),URL.revokeObjectURL(i)}export function saveTextFile(e,t,n,a){if(a){a(e,t,n);return}const i=new Blob([e],{type:n}),s=URL.createObjectURL(i),l=document.createElement("a");l.href=s,l.download=t,l.click(),URL.revokeObjectURL(s)}const he='[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"]';export function nextFrame(e,t=window){const n=t.requestAnimationFrame;typeof n=="function"?n.call(t,e):setTimeout(e,0)}function Oe(e,t,n){e.setAttribute("role","menu"),e.setAttribute("aria-label",t);for(const a of Array.from(e.children)){const i=n(a);i&&(a.setAttribute("role",i),a.tabIndex=-1)}}function G(e,t,n){const a=()=>Array.from(e.querySelectorAll(he));e.addEventListener("keydown",s=>{const l=a();if(l.length===0)return;const o=document.activeElement,d=o?l.indexOf(o):-1;switch(s.key){case"ArrowDown":s.preventDefault(),l[d<0||d===l.length-1?0:d+1].focus();break;case"ArrowUp":s.preventDefault(),l[d<=0?l.length-1:d-1].focus();break;case"Home":s.preventDefault(),l[0].focus();break;case"End":s.preventDefault(),l[l.length-1].focus();break;case"Enter":case" ":d>=0&&(s.preventDefault(),l[d].click());break;case"Escape":case"Tab":s.preventDefault(),n(),t?.focus();break}});const i=a()[0];i&&nextFrame(()=>i.focus())}export function overlayRootFor(e){let t=e;for(;t;){if(t.classList.contains("wmap-overlay-box")||t.tagName==="DIALOG"&&t.matches(":modal"))return t;t=t.parentElement}return e.ownerDocument.body}const te=new WeakMap;export function getTooltip(e=document){const t=te.get(e);if(t&&t.isConnected)return t;const n=t??e.createElement("div");return t||(Object.assign(n.style,{position:"fixed",pointerEvents:"none",background:"rgba(30, 32, 40, 0.93)",color:"#f0f0f2",border:"1px solid rgba(255,255,255,0.10)",padding:"7px 11px",borderRadius:"5px",fontSize:"13px",lineHeight:"1.55",maxWidth:"280px",maxHeight:"min(60vh, 480px)",overflow:"hidden",whiteSpace:"pre-wrap",zIndex:Z_ABOVE,display:"none",fontFamily:"system-ui, sans-serif",boxShadow:"0 3px 10px rgba(0,0,0,0.45)"}),te.set(e,n)),e.body.appendChild(n),n}export function hideTooltip(e=document){const t=te.get(e);t&&(t.style.display="none")}export function reparentTooltip(e){const t=e?.ownerDocument??document,n=getTooltip(t);(e??t.body).appendChild(n)}export function positionTooltip(e,t,n,a){const i=overlayRootFor(t);e.parentElement!==i&&i.appendChild(e);const s=e.ownerDocument.defaultView??window;e.style.left="0",e.style.top="0";const l=e.offsetWidth,o=e.offsetHeight,d=8;let h=n+14,c=a-8;h+l+d>s.innerWidth&&(h=n-l-6),c+o+d>s.innerHeight&&(c=s.innerHeight-o-d),c<d&&(c=d),e.style.left=`${h}px`,e.style.top=`${c}px`}export function buildDataModeEntries(e,t,n){const a=e.some(pe),i=e.some(c=>c.testValues!==void 0&&Object.keys(c.testValues).length>0),s=e.some(c=>c.hbin!=null),l=e.some(c=>c.sbin!=null),o=a?t?.length?t.map(c=>({plotMode:"value",activeTest:c.testNumber,label:c.unit?`${c.name} (${c.unit})`:c.name,logScale:c.logScale})):ue(e).map(c=>({plotMode:"value",activeTest:c,label:`Test ${c}`})):[],d=[...s?[{plotMode:"hardBin",label:MODE_LABELS.hardBin}]:[],...l?[{plotMode:"softBin",label:MODE_LABELS.softBin}]:[]],h=n.includeStacked?[...i?[{plotMode:"stackedValues",label:MODE_LABELS.stackedValues}]:[],...s?[{plotMode:"stackedBins",label:MODE_LABELS.stackedBins}]:[],...l?[{plotMode:"stackedSoftBins",label:MODE_LABELS.stackedSoftBins}]:[]]:[];return{testEntries:o,binEntries:d,stackedEntries:h}}export function metadataKeyHasData(e,t){return e.some(n=>n.metadata?.[t]!==void 0&&n.metadata?.[t]!==null)}export function metadataModeEntry(e){return{plotMode:"metadata",activeMetadataKey:e.key,label:e.label??me(e.key)}}export function makeMenuSearchBox(e,t="Filter\u2026"){const n=document.createElement("input");return n.type="text",n.placeholder=t,n.setAttribute("aria-label",t),Object.assign(n.style,{display:"block",width:"calc(100% - 20px)",margin:"2px 10px 6px",padding:"4px 8px",fontSize:"12px",boxSizing:"border-box",background:CLR.menuBg,color:CLR.text,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",outline:"none"}),n.addEventListener("click",a=>a.stopPropagation()),n.addEventListener("mousedown",a=>a.stopPropagation()),n.addEventListener("keydown",a=>a.stopPropagation()),n.addEventListener("input",()=>e(n.value.trim().toLowerCase())),n.addEventListener("focus",()=>{n.style.borderColor=CLR.iconActive}),n.addEventListener("blur",()=>{n.style.borderColor=CLR.menuBorder}),queueMicrotask(()=>n.focus()),n}export function buildModeMenuEl(e,t,n,a,i,s,l,o,d=window,h=[]){const{makeMenuRow:c,makeMenuSection:p}=l,r=document.createElement("div"),v=180,x=e.left+v<=(d.innerWidth??1/0)?e.left:Math.max(4,e.right-v);if(Object.assign(r.style,{position:"fixed",top:`${e.bottom+4}px`,left:`${x}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_BASE,minWidth:`${v}px`,padding:"4px 0",pointerEvents:"auto"}),t.length)if(r.appendChild(p("Test Value")),t.length<=INLINE_TEST_LIMIT)for(const g of t)r.appendChild(c(g.label,i(g),!0,f=>{f.stopPropagation(),s(g,r)}));else{const g=o==="value",f=c(MODE_LABELS.value+" \u25B6",g,!1,()=>{});f.style.display="flex",f.style.justifyContent="space-between",f.style.alignItems="center";let b=null,M=null;const A=()=>{M!==null&&(clearTimeout(M),M=null)},E=()=>{A(),b?.remove(),b=null},U=()=>{A(),M=setTimeout(E,300)},F=()=>{if(b)return;const L=f.getBoundingClientRect(),w=160,C=320,I=L.right+2+w<=(d.innerWidth??1/0)?L.right+2:Math.max(4,L.left-2-w),T=Math.min(L.top-4,Math.max(4,(d.innerHeight??1/0)-C-4));if(b=document.createElement("div"),Object.assign(b.style,{position:"fixed",top:`${T}px`,left:`${I}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_ABOVE,minWidth:`${w}px`,maxHeight:`${C}px`,overflowY:"auto",padding:"4px 0",pointerEvents:"auto"}),t.length>MENU_SEARCH_THRESHOLD){const S=makeMenuSearchBox(j=>{for(const O of k)O.row.style.display=O.label.includes(j)?"":"none"},"Filter tests\u2026");Object.assign(S.style,{position:"sticky",top:"0",zIndex:"1",background:CLR.menuBg}),b.appendChild(S)}const k=[];for(const S of t){const j=c(S.label,i(S),!1,O=>{O.stopPropagation(),E(),s(S,r)});k.push({row:j,label:S.label.toLowerCase()}),b.appendChild(j)}b.addEventListener("mouseenter",A),b.addEventListener("mouseleave",U),(r.parentElement??d.document.body).appendChild(b),d.document.addEventListener("click",E,{once:!0})};f.addEventListener("mouseenter",()=>{A(),F()}),f.addEventListener("mouseleave",U),r.appendChild(f)}if(n.length){r.appendChild(p("Bins"));for(const g of n)r.appendChild(c(g.label,i(g),!1,f=>{f.stopPropagation(),s(g,r)}))}if(h.length){r.appendChild(p("Metadata"));for(const g of h)r.appendChild(c(g.label,i(g),!1,f=>{f.stopPropagation(),s(g,r)}))}if(a.length){r.appendChild(p("Lot Aggregation"));for(const g of a)r.appendChild(c(g.label,i(g),!1,f=>{f.stopPropagation(),s(g,r)}))}return r.setAttribute("role","menu"),r.setAttribute("aria-label","Plot mode"),r}export function markMenuTrigger(e,t){e.setAttribute("aria-haspopup","menu"),e.setAttribute("aria-expanded",t?"true":"false")}export function wireMenuA11y(e,t,n){G(e,t,n)}export function wireExpandToggle(e,t){const n=e.ownerDocument;let a=!1;function i(h){a!==h&&(a=h,t(a))}function s(){i(!1)}function l(){i(!a),a&&n.addEventListener("click",s,{once:!0})}const o=h=>{h.stopPropagation(),l()},d=h=>{h.key==="Enter"||h.key===" "?(h.preventDefault(),l()):h.key==="Escape"&&s()};return e.setAttribute("role","button"),e.tabIndex<0&&(e.tabIndex=0),e.addEventListener("click",o),e.addEventListener("keydown",d),{isOpen:()=>a,close:s,destroy(){e.removeEventListener("click",o),e.removeEventListener("keydown",d),n.removeEventListener("click",s)}}}export function buildCheckMenuEl(e,t,n,a=window){const{makeMenuRow:i,makeMenuSection:s}=n,l=document.createElement("div"),o=168,h=e.left+o<=(a.innerWidth??1/0)?e.left:Math.max(4,e.right-o);Object.assign(l.style,{position:"fixed",top:`${e.bottom+4}px`,left:`${h}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_BASE,minWidth:`${o}px`,padding:"4px 0",pointerEvents:"auto"});for(const c of t)if("section"in c)l.appendChild(s(c.section));else{if(!(c.enabled!==!1))continue;const r=document.createElement("div");r.setAttribute("role","menuitemcheckbox"),r.setAttribute("aria-checked",c.active?"true":"false"),r.tabIndex=-1,Object.assign(r.style,{display:"flex",alignItems:"center",gap:"6px",padding:"6px 14px",fontSize:"12px",cursor:"pointer",color:c.active?CLR.iconActive:CLR.text,fontWeight:c.active?"700":"400",background:c.active?CLR.menuActive:"transparent",whiteSpace:"nowrap",outline:"none"});const v=document.createElement("span");Object.assign(v.style,{width:"12px",flexShrink:"0",color:CLR.iconActive,visibility:c.active?"visible":"hidden"}),v.textContent="\u2713",v.setAttribute("aria-hidden","true");const m=document.createElement("span");m.textContent=c.label,r.appendChild(v),r.appendChild(m),r.addEventListener("mouseenter",()=>{c.active||(r.style.background=CLR.menuHover)}),r.addEventListener("mouseleave",()=>{r.style.background=c.active?CLR.menuActive:"transparent"}),r.addEventListener("focus",()=>{c.active||(r.style.background=CLR.menuHover)}),r.addEventListener("blur",()=>{r.style.background=c.active?CLR.menuActive:"transparent"}),r.addEventListener("click",x=>{x.stopPropagation(),c.onClick(x)}),l.appendChild(r)}return l}export function createToolbarHelpers(e){let t=null;const n=p=>overlayRootFor(p);function a(p,r,v){const m=document.createElement("button");return m.innerHTML=_[p],m.type="button",m.ariaLabel=r,Object.assign(m.style,{display:"flex",alignItems:"center",justifyContent:"center",width:"28px",height:"28px",padding:"0",border:"none",borderRadius:"3px",background:"transparent",color:CLR.icon,cursor:"pointer",pointerEvents:"auto",transition:"background 0.12s, color 0.12s",flexShrink:"0"}),m.addEventListener("mouseenter",x=>{m.dataset.active||(m.style.background=CLR.bgHover,m.style.color=CLR.iconHover),e.innerHTML=m.ariaLabel??r,e.style.display="block",positionTooltip(e,m,x.clientX,x.clientY)}),m.addEventListener("mousemove",x=>{e.style.display==="block"&&positionTooltip(e,m,x.clientX,x.clientY)}),m.addEventListener("mouseleave",()=>{m.dataset.active||(m.style.background="transparent",m.style.color=CLR.icon),e.style.display="none"}),m.addEventListener("click",()=>{e.style.display="none",v()}),m}function i(p,r){r?(p.dataset.active="1",p.style.background=CLR.bgActive,p.style.color=CLR.iconActive):(delete p.dataset.active,p.style.background="transparent",p.style.color=CLR.icon)}function s(){const p=document.createElement("div");return Object.assign(p.style,{width:"1px",height:"18px",background:CLR.separator,margin:"0 2px",flexShrink:"0"}),p}function l(p,r,v,m){const x=document.createElement("div");return x.textContent=p,x.setAttribute("role","menuitemradio"),x.setAttribute("aria-checked",r?"true":"false"),x.tabIndex=-1,Object.assign(x.style,{padding:`6px 14px 6px ${v?"26px":"14px"}`,fontSize:"12px",cursor:"pointer",color:r?CLR.iconActive:CLR.text,fontWeight:r?"700":"400",background:r?CLR.menuActive:"transparent",whiteSpace:"nowrap",outline:"none"}),x.addEventListener("mouseenter",()=>{r||(x.style.background=CLR.menuHover)}),x.addEventListener("mouseleave",()=>{x.style.background=r?CLR.menuActive:"transparent"}),x.addEventListener("focus",()=>{r||(x.style.background=CLR.menuHover)}),x.addEventListener("blur",()=>{x.style.background=r?CLR.menuActive:"transparent"}),x.addEventListener("click",m),x}function o(p){const r=document.createElement("div");return r.textContent=p,r.setAttribute("role","presentation"),Object.assign(r.style,{padding:"5px 14px 2px",fontSize:"10px",fontWeight:"600",letterSpacing:"0.05em",color:CLR.label,textTransform:"uppercase",pointerEvents:"none",userSelect:"none"}),r}function d(p,r,v,m,x){const g=()=>{t&&(t.remove(),t=null),f.setAttribute("aria-expanded","false")},f=a(p,r,()=>{if(t){g();return}const b=document.createElement("div"),M=f.getBoundingClientRect(),A=f.ownerDocument.defaultView??window,E=148,F=M.left+E<=(A.innerWidth??1/0)?M.left:Math.max(4,M.right-E);Object.assign(b.style,{position:"fixed",top:`${M.bottom+4}px`,left:`${F}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_BASE,minWidth:`${E}px`,padding:"4px 0",pointerEvents:"auto"});for(const L of v()){const w=document.createElement("div");w.textContent=L.label,w.dataset.wmapDropdownValue=L.value;const C=L.value===m();w.setAttribute("role","menuitemradio"),w.setAttribute("aria-checked",C?"true":"false"),w.tabIndex=-1,Object.assign(w.style,{padding:"6px 14px",fontSize:"12px",cursor:"pointer",color:C?CLR.iconActive:CLR.text,fontWeight:C?"700":"400",background:C?CLR.menuActive:"transparent",whiteSpace:"nowrap",outline:"none"});const D=()=>{L.value!==m()&&(w.style.background=CLR.menuHover)},I=()=>{w.style.background=L.value===m()?CLR.menuActive:"transparent"};w.addEventListener("mouseenter",D),w.addEventListener("mouseleave",I),w.addEventListener("focus",D),w.addEventListener("blur",I),w.addEventListener("click",T=>{T.stopPropagation(),x(L.value),g()}),b.appendChild(w)}b.setAttribute("role","menu"),b.setAttribute("aria-label",r),n(f).appendChild(b),t=b,f.setAttribute("aria-expanded","true"),G(b,f,g)});return f.setAttribute("aria-haspopup","menu"),f.setAttribute("aria-expanded","false"),f}function h(p,r,v,m){function x(){return buildCheckMenuEl(f.getBoundingClientRect(),v().map(b=>"section"in b?b:{...b,onClick:M=>{b.onClick(M),m(f);const A=t;if(!A)return;const E=x();E.setAttribute("role","menu"),E.setAttribute("aria-label",r),A.replaceWith(E),t=E,G(E,f,g)}}),{makeMenuRow:l,makeMenuSection:o},f.ownerDocument.defaultView??window)}const g=()=>{t&&(t.remove(),t=null),f.setAttribute("aria-expanded","false")},f=a(p,r,()=>{if(t){g();return}const b=x();b.setAttribute("role","menu"),b.setAttribute("aria-label",r),n(f).appendChild(b),t=b,f.setAttribute("aria-expanded","true"),G(b,f,g)});return f.setAttribute("aria-haspopup","menu"),f.setAttribute("aria-expanded","false"),m(f),f}function c(p){if(t&&!t.contains(p.target)&&(t.remove(),t=null,p.target?.getAttribute?.("aria-haspopup")!=="menu"))for(const v of document.querySelectorAll('[aria-haspopup="menu"][aria-expanded="true"]'))v.setAttribute("aria-expanded","false")}return{makeBtn:a,setActive:i,makeSep:s,makeMenuRow:l,makeMenuSection:o,makeDropdown:d,makeCheckMenuBtn:h,closeOpenMenu:c,getOpenMenu:()=>t,setOpenMenu:p=>{t=p}}}const xe=7e3;let ve=0;function ae(){return xe+ ++ve}const ge=32,ye=6;let we=0;function ke(){return we++%ye*ge}function Ee(e,t){if(t===e.body)return()=>{};let n=t;for(;n.parentElement&&n.parentElement!==e.body;)n=n.parentElement;return n===e.body?()=>{}:(n.classList.add("wmap-overlay-ancestor"),()=>n.classList.remove("wmap-overlay-ancestor"))}function re(e){const t=e.mode==="modal",n=e.ownerDocument??document,a=n.defaultView??window,i=n.body.style.overflow;t&&(n.body.style.overflow="hidden");let s=null;t&&(s=n.createElement("div"),s.id="wmap-modal-backdrop",Object.assign(s.style,{position:"fixed",inset:"0",background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:Z_ABOVE,backdropFilter:"blur(3px)"}));const l=n.activeElement,o=n.createElement("div");if(o.className=t?"wmap-modal-box wmap-overlay-box":"wmap-window-box wmap-overlay-box",o.setAttribute("role","dialog"),t&&o.setAttribute("aria-modal","true"),o.setAttribute("aria-label",e.title??"Expanded wafer map"),o.tabIndex=-1,Object.assign(o.style,{position:"relative",background:CLR.menuBg,borderRadius:"12px",overflow:"hidden",display:"flex",flexDirection:"column",width:"min(90vw, 700px)",height:"min(90vh, 700px)",boxShadow:"0 20px 60px rgba(0,0,0,0.4)",minWidth:"320px",minHeight:"240px",maxWidth:"100vw",maxHeight:"100vh",zIndex:t?Z_ABOVE2:String(ae())}),!t){const u=ke();Object.assign(o.style,{position:"fixed",top:`${Math.round(a.innerHeight*.08)+u}px`,left:`${Math.round(a.innerWidth*.08)+u}px`})}const d=n.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",gap:"6px",padding:"10px 14px",borderBottom:`1px solid ${CLR.menuBorder}`,flexShrink:"0"});const h={border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",background:CLR.panelBg,cursor:"pointer",color:CLR.label,lineHeight:"1",padding:"0",display:"flex",alignItems:"center",justifyContent:"center",width:"28px",height:"28px"};if(e.title){const u=n.createElement("span");u.textContent=e.title,u.title=e.title,u.dataset.wmapWindowTitle="1",Object.assign(u.style,{fontWeight:"700",fontSize:"14px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",minWidth:"0"}),d.appendChild(u)}const c=n.createElement("div");c.style.flex="1",d.appendChild(c);let p=null;t||(p=n.createElement("button"),p.type="button",p.innerHTML=_.windowMinimize,p.title="Minimize",p.setAttribute("aria-label","Minimize"),Object.assign(p.style,h),p.addEventListener("click",()=>U(!b)),d.appendChild(p));const r=n.createElement("button");r.type="button",r.innerHTML=_.maximize,r.title="Maximize (F)",r.setAttribute("aria-label","Maximize"),Object.assign(r.style,h),r.addEventListener("click",()=>f(!m));const v=n.createElement("button");v.type="button",v.innerHTML=_.close,v.title="Close (Esc)",v.setAttribute("aria-label","Close"),Object.assign(v.style,h),v.addEventListener("click",D),d.appendChild(r),d.appendChild(v);let m=!1,x="",g="";function f(u){m=u,r.innerHTML=m?_.minimize:_.maximize,r.title=m?"Restore (F)":"Maximize (F)",r.setAttribute("aria-label",m?"Restore":"Maximize"),k.style.display=m?"none":"block",m?(o.style.borderRadius="0",o.style.width="100vw",o.style.height="100vh",t||(x=o.style.top,g=o.style.left,o.style.top="0",o.style.left="0")):(o.style.borderRadius="12px",o.style.width="min(90vw, 700px)",o.style.height="min(90vh, 700px)",t||(o.style.top=x,o.style.left=g)),e.onMaximizeChange?.(m,o)}let b=!1,M="",A="";const E=220;function U(u){b=u,p.innerHTML=b?_.windowRestore:_.windowMinimize,p.title=b?"Restore":"Minimize",p.setAttribute("aria-label",b?"Restore":"Minimize"),k.style.display=b?"none":"block",b?(M=o.style.height,A=o.style.width,o.style.minHeight="0",o.style.height="auto",o.style.minWidth="0",o.style.width=`${E}px`,r.disabled=!0,r.style.opacity="0.4",r.style.cursor="default",T.style.display="none"):(o.style.minHeight="240px",o.style.height=M||"min(90vh, 700px)",o.style.minWidth="320px",o.style.width=A||"min(90vw, 700px)",r.disabled=!1,r.style.opacity="1",r.style.cursor="pointer",T.style.display="flex")}function F(){const u=n.body.style.userSelect;return n.body.style.userSelect="none",()=>{n.body.style.userSelect=u}}t||(d.style.cursor="move",d.addEventListener("pointerdown",u=>{if(m||u.target.closest('button, [role="button"]'))return;u.preventDefault();const B=F(),W=u.clientX,z=u.clientY,H=o.offsetTop,R=o.offsetLeft,Z=a.innerHeight-d.offsetHeight,Q=a.innerWidth-40,X=40-o.offsetWidth;d.setPointerCapture(u.pointerId);const N=V=>{const J=Math.min(Math.max(H+(V.clientY-z),0),Z),de=Math.min(Math.max(R+(V.clientX-W),X),Q);o.style.top=`${J}px`,o.style.left=`${de}px`},P=V=>{B(),d.releasePointerCapture(V.pointerId),d.removeEventListener("pointermove",N),d.removeEventListener("pointerup",P)};d.addEventListener("pointermove",N),d.addEventListener("pointerup",P)}));const L='button,[href],input,select,textarea,[tabindex]:not([tabindex="-1"]),[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"]';function w(u){const B=Array.from(o.querySelectorAll(L)).filter(R=>R.offsetParent!==null||R===n.activeElement);if(B.length===0){u.preventDefault(),o.focus();return}const W=B[0],z=B[B.length-1],H=n.activeElement;u.shiftKey&&(H===W||!o.contains(H))?(u.preventDefault(),z.focus()):!u.shiftKey&&H===z&&(u.preventDefault(),W.focus())}const C=u=>{if(u.key==="Escape"){D();return}if(t&&(u.key==="e"||u.key==="E")){D();return}if(t&&u.key==="Tab"){w(u);return}(u.key==="f"||u.key==="F")&&!b&&f(!m)};function D(){t?n.removeEventListener("keydown",C):o.removeEventListener("keydown",C),q.remove(),ce(),hideTooltip(n),reparentTooltip(n.body),s?s.remove():o.remove(),t&&(n.body.style.overflow=i),l?.focus?.(),e.onClose()}function I(){t||(o.style.zIndex=String(ae()))}const T=n.createElement("div");Object.assign(T.style,{flex:"1",minHeight:"0",minWidth:"0",display:"flex",overflow:"hidden"});const k=n.createElement("div");k.tabIndex=0,k.setAttribute("role","separator"),k.setAttribute("aria-label","Resize window (arrow keys, or drag)"),Object.assign(k.style,{position:"absolute",right:"0",bottom:"0",width:"16px",height:"16px",cursor:"nwse-resize",touchAction:"none"}),k.innerHTML='<svg viewBox="0 0 16 16" width="16" height="16" style="display:block"><path d="M15 15 L15 9 M15 15 L9 15 M15 15 L15 3 M15 15 L3 15" stroke="currentColor" stroke-width="1" opacity="0.35" fill="none"/></svg>',k.style.color=CLR.label;const S=320,j=240,O=20;function Y(u,B){const W=a.innerWidth-o.offsetLeft,z=a.innerHeight-o.offsetTop,H=Math.min(Math.max(o.offsetWidth+u,S),W),R=Math.min(Math.max(o.offsetHeight+B,j),z);o.style.width=`${H}px`,o.style.height=`${R}px`}k.addEventListener("keydown",u=>{if(!(m||b))switch(u.key){case"ArrowRight":u.preventDefault(),Y(O,0);break;case"ArrowLeft":u.preventDefault(),Y(-O,0);break;case"ArrowDown":u.preventDefault(),Y(0,O);break;case"ArrowUp":u.preventDefault(),Y(0,-O);break}}),k.addEventListener("pointerdown",u=>{if(m||b)return;u.preventDefault();const B=F(),W=u.clientX,z=u.clientY,H=o.offsetWidth,R=o.offsetHeight,Z=a.innerWidth-o.offsetLeft,Q=a.innerHeight-o.offsetTop;k.setPointerCapture(u.pointerId);const X=P=>{const V=Math.min(Math.max(H+(P.clientX-W),S),Z),J=Math.min(Math.max(R+(P.clientY-z),j),Q);o.style.width=`${V}px`,o.style.height=`${J}px`},N=P=>{B(),k.releasePointerCapture(P.pointerId),k.removeEventListener("pointermove",X),k.removeEventListener("pointerup",N)};k.addEventListener("pointermove",X),k.addEventListener("pointerup",N)}),o.appendChild(d),o.appendChild(T),o.appendChild(k);const K=e.anchor?overlayRootFor(e.anchor):n.body;s?(s.appendChild(o),K.appendChild(s)):K.appendChild(o);const ce=Ee(n,K),q=n.createElement("style");return q.textContent=`@media print{
|
|
1
|
+
import{getUniqueTestNumbers as ue}from"../renderer/buildView.js";import{dieHasTestData as pe}from"../renderer/buildWaferMap.js";import{prettyKey as me}from"../core/utils.js";import{listColorSchemes as oe}from"../renderer/colorSchemes.js";import{ICONS as _}from"./icons.js";import{WMAP_VERSION as fe,WMAP_BUILD_TIME as be}from"./version.js";let ie=!1;export function logWmapVersionOnce(){ie||(ie=!0,console.log(`[wmap] v${fe} (built ${be})`))}export const WMAP_TOKEN_NAMES=["z","icon","icon-hover","icon-active","bg-hover","bg-active","separator","surface","border","menu-hover","menu-active","panel-bg","text-muted","text","text-strong","warn-bg","warn-border","warn-text","err-bg","err-border","err-text","info-bg","info-text","selected","finding-indicator","canvas-bg"];const y=(e,t)=>`var(--wmap-${e}, ${t})`;export const CLR={icon:y("icon","#506784"),iconHover:y("icon-hover","#2a3f5f"),iconActive:y("icon-active","#1a65ca"),bgHover:y("bg-hover","#edf0f8"),bgActive:y("bg-active","#dce8f8"),separator:y("separator","rgba(0,0,0,0.12)"),menuBg:y("surface","#fff"),menuBorder:y("border","rgba(0,0,0,0.12)"),menuHover:y("menu-hover","#f0f4fc"),menuActive:y("menu-active","#dce8f8"),panelBg:y("panel-bg","#fafbfc"),label:y("text-muted","#647687"),value:y("text-strong","#1f2f43"),text:y("text","#333"),warnBg:y("warn-bg","#fffbe6"),warnBorder:y("warn-border","#f0c040"),warnText:y("warn-text","#7a5800"),errBg:y("err-bg","#fef2f2"),errBorder:y("err-border","#dc8a8a"),errText:y("err-text","#7a1c1c"),infoBg:y("info-bg","#dce8f8"),infoText:y("info-text","#334155"),findingHighlight:y("selected","#e07a20"),findingIndicator:y("finding-indicator","#b7551a")};export function sevColor(e){return e==="unusual"?"#a84112":e==="notable"?"#8a6500":CLR.icon}export const ROTATIONS=[0,90,180,270],INLINE_TEST_LIMIT=6,MENU_SEARCH_THRESHOLD=8,DEFAULT_OVERLAY_Z=6e3,Z_BASE=`var(--wmap-z, ${DEFAULT_OVERLAY_Z})`,Z_ABOVE=`calc(var(--wmap-z, ${DEFAULT_OVERLAY_Z}) + 1)`,Z_ABOVE2=`calc(var(--wmap-z, ${DEFAULT_OVERLAY_Z}) + 2)`;export function applyOverlayZ(e){if(e==null)return()=>{};const t=document.documentElement,n=t.style.getPropertyValue("--wmap-z");return t.style.setProperty("--wmap-z",String(e)),()=>{n?t.style.setProperty("--wmap-z",n):t.style.removeProperty("--wmap-z")}}export function copyWmapThemeTokens(e,t){const n=getComputedStyle(e);for(const a of WMAP_TOKEN_NAMES){const i=n.getPropertyValue(`--wmap-${a}`).trim();i&&t.style.setProperty(`--wmap-${a}`,i)}}export function syncWmapPopupTheme(e,t,n){const a=()=>{copyWmapThemeTokens(e,t),n?.()},i=new window.MutationObserver(a);i.observe(e,{attributes:!0,attributeFilter:["style","class"]}),i.observe(document.documentElement,{attributes:!0,attributeFilter:["style","class"]});const s=window.matchMedia("(prefers-color-scheme: dark)");return s.addEventListener("change",a),()=>{i.disconnect(),s.removeEventListener("change",a)}}let ee=null;export function setDetachWindowOpener(e){ee=e}export function openDetachWindow(e){return ee?ee(e):window.open("","_blank","width=560,height=600")}export const MODE_LABELS={value:"Test Value",hardBin:"Hard Bin",softBin:"Soft Bin",stackedValues:"Stacked Test Values",stackedBins:"Stacked Hard Bins",stackedSoftBins:"Stacked Soft Bins",metadata:"Metadata"},BIN_LEGEND_MODES=new Set(["hardBin","softBin","metadata"]),STACKED_MODES=new Set(["stackedValues","stackedBins","stackedSoftBins"]);export function saveImageBlob(e,t,n){const a=`${t}.png`;if(n){n(e,a);return}const i=URL.createObjectURL(e),s=document.createElement("a");s.href=i,s.download=a,s.click(),URL.revokeObjectURL(i)}export function saveTextFile(e,t,n,a){if(a){a(e,t,n);return}const i=new Blob([e],{type:n}),s=URL.createObjectURL(i),l=document.createElement("a");l.href=s,l.download=t,l.click(),URL.revokeObjectURL(s)}const he='[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"]';export function nextFrame(e,t=window){const n=t.requestAnimationFrame;typeof n=="function"?n.call(t,e):setTimeout(e,0)}function Oe(e,t,n){e.setAttribute("role","menu"),e.setAttribute("aria-label",t);for(const a of Array.from(e.children)){const i=n(a);i&&(a.setAttribute("role",i),a.tabIndex=-1)}}function G(e,t,n){const a=()=>Array.from(e.querySelectorAll(he));e.addEventListener("keydown",s=>{const l=a();if(l.length===0)return;const o=document.activeElement,d=o?l.indexOf(o):-1;switch(s.key){case"ArrowDown":s.preventDefault(),l[d<0||d===l.length-1?0:d+1].focus();break;case"ArrowUp":s.preventDefault(),l[d<=0?l.length-1:d-1].focus();break;case"Home":s.preventDefault(),l[0].focus();break;case"End":s.preventDefault(),l[l.length-1].focus();break;case"Enter":case" ":d>=0&&(s.preventDefault(),l[d].click());break;case"Escape":case"Tab":s.preventDefault(),n(),t?.focus();break}});const i=a()[0];i&&nextFrame(()=>i.focus())}export function overlayRootFor(e){let t=e;for(;t;){if(t.classList.contains("wmap-overlay-box")||t.tagName==="DIALOG"&&t.matches(":modal"))return t;t=t.parentElement}return e.ownerDocument.body}const te=new WeakMap;export function getTooltip(e=document){const t=te.get(e);if(t&&t.isConnected)return t;const n=t??e.createElement("div");return t||(Object.assign(n.style,{position:"fixed",pointerEvents:"none",background:"rgba(30, 32, 40, 0.93)",color:"#f0f0f2",border:"1px solid rgba(255,255,255,0.10)",padding:"7px 11px",borderRadius:"5px",fontSize:"13px",lineHeight:"1.55",maxWidth:"280px",maxHeight:"min(60vh, 480px)",overflow:"hidden",whiteSpace:"pre-wrap",zIndex:Z_ABOVE,display:"none",fontFamily:"system-ui, sans-serif",boxShadow:"0 3px 10px rgba(0,0,0,0.45)"}),te.set(e,n)),e.body.appendChild(n),n}export function hideTooltip(e=document){const t=te.get(e);t&&(t.style.display="none")}export function reparentTooltip(e){const t=e?.ownerDocument??document,n=getTooltip(t);(e??t.body).appendChild(n)}export function positionTooltip(e,t,n,a){const i=overlayRootFor(t);e.parentElement!==i&&i.appendChild(e);const s=e.ownerDocument.defaultView??window;e.style.left="0",e.style.top="0";const l=e.offsetWidth,o=e.offsetHeight,d=8;let h=n+14,c=a-8;h+l+d>s.innerWidth&&(h=n-l-6),c+o+d>s.innerHeight&&(c=s.innerHeight-o-d),c<d&&(c=d),e.style.left=`${h}px`,e.style.top=`${c}px`}export function buildDataModeEntries(e,t,n){const a=e.some(pe),i=e.some(c=>c.testValues!==void 0&&Object.keys(c.testValues).length>0),s=e.some(c=>c.hbin!=null),l=e.some(c=>c.sbin!=null),o=a?t?.length?t.map(c=>({plotMode:"value",activeTest:c.testNumber,label:c.unit?`${c.name} (${c.unit})`:c.name,logScale:c.logScale})):ue(e).map(c=>({plotMode:"value",activeTest:c,label:`Test ${c}`})):[],d=[...s?[{plotMode:"hardBin",label:MODE_LABELS.hardBin}]:[],...l?[{plotMode:"softBin",label:MODE_LABELS.softBin}]:[]],h=n.includeStacked?[...i?[{plotMode:"stackedValues",label:MODE_LABELS.stackedValues}]:[],...s?[{plotMode:"stackedBins",label:MODE_LABELS.stackedBins}]:[],...l?[{plotMode:"stackedSoftBins",label:MODE_LABELS.stackedSoftBins}]:[]]:[];return{testEntries:o,binEntries:d,stackedEntries:h}}export function metadataKeyHasData(e,t){return e.some(n=>n.metadata?.[t]!==void 0&&n.metadata?.[t]!==null)}export function metadataModeEntry(e){return{plotMode:"metadata",activeMetadataKey:e.key,label:e.label??me(e.key)}}export function makeMenuSearchBox(e,t="Filter\u2026"){const n=document.createElement("input");return n.type="text",n.placeholder=t,n.setAttribute("aria-label",t),Object.assign(n.style,{display:"block",width:"calc(100% - 20px)",margin:"2px 10px 6px",padding:"4px 8px",fontSize:"12px",boxSizing:"border-box",background:CLR.menuBg,color:CLR.text,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",outline:"none"}),n.addEventListener("click",a=>a.stopPropagation()),n.addEventListener("mousedown",a=>a.stopPropagation()),n.addEventListener("keydown",a=>a.stopPropagation()),n.addEventListener("input",()=>e(n.value.trim().toLowerCase())),n.addEventListener("focus",()=>{n.style.borderColor=CLR.iconActive}),n.addEventListener("blur",()=>{n.style.borderColor=CLR.menuBorder}),queueMicrotask(()=>n.focus()),n}export function buildModeMenuEl(e,t,n,a,i,s,l,o,d=window,h=[]){const{makeMenuRow:c,makeMenuSection:p}=l,r=document.createElement("div"),v=180,x=e.left+v<=(d.innerWidth??1/0)?e.left:Math.max(4,e.right-v);if(Object.assign(r.style,{position:"fixed",top:`${e.bottom+4}px`,left:`${x}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_BASE,minWidth:`${v}px`,padding:"4px 0",pointerEvents:"auto"}),t.length)if(r.appendChild(p("Test Value")),t.length<=INLINE_TEST_LIMIT)for(const g of t)r.appendChild(c(g.label,i(g),!0,f=>{f.stopPropagation(),s(g,r)}));else{const g=o==="value",f=c(MODE_LABELS.value+" \u25B6",g,!1,()=>{});f.style.display="flex",f.style.justifyContent="space-between",f.style.alignItems="center";let b=null,M=null;const A=()=>{M!==null&&(clearTimeout(M),M=null)},E=()=>{A(),b?.remove(),b=null},U=()=>{A(),M=setTimeout(E,300)},F=()=>{if(b)return;const L=f.getBoundingClientRect(),w=160,C=320,I=L.right+2+w<=(d.innerWidth??1/0)?L.right+2:Math.max(4,L.left-2-w),T=Math.min(L.top-4,Math.max(4,(d.innerHeight??1/0)-C-4));if(b=document.createElement("div"),Object.assign(b.style,{position:"fixed",top:`${T}px`,left:`${I}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_ABOVE,minWidth:`${w}px`,maxHeight:`${C}px`,overflowY:"auto",padding:"4px 0",pointerEvents:"auto"}),t.length>MENU_SEARCH_THRESHOLD){const S=makeMenuSearchBox(j=>{for(const O of k)O.row.style.display=O.label.includes(j)?"":"none"},"Filter tests\u2026");Object.assign(S.style,{position:"sticky",top:"0",zIndex:"1",background:CLR.menuBg}),b.appendChild(S)}const k=[];for(const S of t){const j=c(S.label,i(S),!1,O=>{O.stopPropagation(),E(),s(S,r)});k.push({row:j,label:S.label.toLowerCase()}),b.appendChild(j)}b.addEventListener("mouseenter",A),b.addEventListener("mouseleave",U),(r.parentElement??d.document.body).appendChild(b),d.document.addEventListener("click",E,{once:!0})};f.addEventListener("mouseenter",()=>{A(),F()}),f.addEventListener("mouseleave",U),r.appendChild(f)}if(n.length){r.appendChild(p("Bins"));for(const g of n)r.appendChild(c(g.label,i(g),!1,f=>{f.stopPropagation(),s(g,r)}))}if(h.length){r.appendChild(p("Metadata"));for(const g of h)r.appendChild(c(g.label,i(g),!1,f=>{f.stopPropagation(),s(g,r)}))}if(a.length){r.appendChild(p("Lot Aggregation"));for(const g of a)r.appendChild(c(g.label,i(g),!1,f=>{f.stopPropagation(),s(g,r)}))}return r.setAttribute("role","menu"),r.setAttribute("aria-label","Plot mode"),r}export function markMenuTrigger(e,t){e.setAttribute("aria-haspopup","menu"),e.setAttribute("aria-expanded",t?"true":"false")}export function wireMenuA11y(e,t,n){G(e,t,n)}export function wireExpandToggle(e,t){const n=e.ownerDocument;let a=!1;function i(h){a!==h&&(a=h,t(a))}function s(){i(!1)}function l(){i(!a),a&&n.addEventListener("click",s,{once:!0})}const o=h=>{h.stopPropagation(),l()},d=h=>{h.key==="Enter"||h.key===" "?(h.preventDefault(),l()):h.key==="Escape"&&s()};return e.setAttribute("role","button"),e.tabIndex<0&&(e.tabIndex=0),e.addEventListener("click",o),e.addEventListener("keydown",d),{isOpen:()=>a,close:s,destroy(){e.removeEventListener("click",o),e.removeEventListener("keydown",d),n.removeEventListener("click",s)}}}export function buildCheckMenuEl(e,t,n,a=window){const{makeMenuRow:i,makeMenuSection:s}=n,l=document.createElement("div"),o=168,h=e.left+o<=(a.innerWidth??1/0)?e.left:Math.max(4,e.right-o);Object.assign(l.style,{position:"fixed",top:`${e.bottom+4}px`,left:`${h}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_BASE,minWidth:`${o}px`,padding:"4px 0",pointerEvents:"auto"});for(const c of t)if("section"in c)l.appendChild(s(c.section));else{if(!(c.enabled!==!1))continue;const r=document.createElement("div");r.setAttribute("role","menuitemcheckbox"),r.setAttribute("aria-checked",c.active?"true":"false"),r.tabIndex=-1,Object.assign(r.style,{display:"flex",alignItems:"center",gap:"6px",padding:"6px 14px",fontSize:"12px",cursor:"pointer",color:c.active?CLR.iconActive:CLR.text,fontWeight:c.active?"700":"400",background:c.active?CLR.menuActive:"transparent",whiteSpace:"nowrap",outline:"none"});const v=document.createElement("span");Object.assign(v.style,{width:"12px",flexShrink:"0",color:CLR.iconActive,visibility:c.active?"visible":"hidden"}),v.textContent="\u2713",v.setAttribute("aria-hidden","true");const m=document.createElement("span");m.textContent=c.label,r.appendChild(v),r.appendChild(m),r.addEventListener("mouseenter",()=>{c.active||(r.style.background=CLR.menuHover)}),r.addEventListener("mouseleave",()=>{r.style.background=c.active?CLR.menuActive:"transparent"}),r.addEventListener("focus",()=>{c.active||(r.style.background=CLR.menuHover)}),r.addEventListener("blur",()=>{r.style.background=c.active?CLR.menuActive:"transparent"}),r.addEventListener("click",x=>{x.stopPropagation(),c.onClick(x)}),l.appendChild(r)}return l}export function createToolbarHelpers(e){let t=null;const n=p=>overlayRootFor(p);function a(p,r,v){const m=document.createElement("button");return m.innerHTML=_[p],m.type="button",m.ariaLabel=r,Object.assign(m.style,{display:"flex",alignItems:"center",justifyContent:"center",width:"28px",height:"28px",padding:"0",border:"none",borderRadius:"3px",background:"transparent",color:CLR.icon,cursor:"pointer",pointerEvents:"auto",transition:"background 0.12s, color 0.12s",flexShrink:"0"}),m.addEventListener("mouseenter",x=>{m.dataset.active||(m.style.background=CLR.bgHover,m.style.color=CLR.iconHover),e.innerHTML=m.ariaLabel??r,e.style.display="block",positionTooltip(e,m,x.clientX,x.clientY)}),m.addEventListener("mousemove",x=>{e.style.display==="block"&&positionTooltip(e,m,x.clientX,x.clientY)}),m.addEventListener("mouseleave",()=>{m.dataset.active||(m.style.background="transparent",m.style.color=CLR.icon),e.style.display="none"}),m.addEventListener("click",()=>{e.style.display="none",v()}),m}function i(p,r){r?(p.dataset.active="1",p.style.background=CLR.bgActive,p.style.color=CLR.iconActive):(delete p.dataset.active,p.style.background="transparent",p.style.color=CLR.icon)}function s(){const p=document.createElement("div");return Object.assign(p.style,{width:"1px",height:"18px",background:CLR.separator,margin:"0 2px",flexShrink:"0"}),p}function l(p,r,v,m){const x=document.createElement("div");return x.textContent=p,x.setAttribute("role","menuitemradio"),x.setAttribute("aria-checked",r?"true":"false"),x.tabIndex=-1,Object.assign(x.style,{padding:`6px 14px 6px ${v?"26px":"14px"}`,fontSize:"12px",cursor:"pointer",color:r?CLR.iconActive:CLR.text,fontWeight:r?"700":"400",background:r?CLR.menuActive:"transparent",whiteSpace:"nowrap",outline:"none"}),x.addEventListener("mouseenter",()=>{r||(x.style.background=CLR.menuHover)}),x.addEventListener("mouseleave",()=>{x.style.background=r?CLR.menuActive:"transparent"}),x.addEventListener("focus",()=>{r||(x.style.background=CLR.menuHover)}),x.addEventListener("blur",()=>{x.style.background=r?CLR.menuActive:"transparent"}),x.addEventListener("click",m),x}function o(p){const r=document.createElement("div");return r.textContent=p,r.setAttribute("role","presentation"),Object.assign(r.style,{padding:"5px 14px 2px",fontSize:"10px",fontWeight:"600",letterSpacing:"0.05em",color:CLR.label,textTransform:"uppercase",pointerEvents:"none",userSelect:"none"}),r}function d(p,r,v,m,x){const g=()=>{t&&(t.remove(),t=null),f.setAttribute("aria-expanded","false")},f=a(p,r,()=>{if(t){g();return}const b=document.createElement("div"),M=f.getBoundingClientRect(),A=f.ownerDocument.defaultView??window,E=148,F=M.left+E<=(A.innerWidth??1/0)?M.left:Math.max(4,M.right-E);Object.assign(b.style,{position:"fixed",top:`${M.bottom+4}px`,left:`${F}px`,background:CLR.menuBg,border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",zIndex:Z_BASE,minWidth:`${E}px`,padding:"4px 0",pointerEvents:"auto"});for(const L of v()){const w=document.createElement("div");w.textContent=L.label,w.dataset.wmapDropdownValue=L.value;const C=L.value===m();w.setAttribute("role","menuitemradio"),w.setAttribute("aria-checked",C?"true":"false"),w.tabIndex=-1,Object.assign(w.style,{padding:"6px 14px",fontSize:"12px",cursor:"pointer",color:C?CLR.iconActive:CLR.text,fontWeight:C?"700":"400",background:C?CLR.menuActive:"transparent",whiteSpace:"nowrap",outline:"none"});const D=()=>{L.value!==m()&&(w.style.background=CLR.menuHover)},I=()=>{w.style.background=L.value===m()?CLR.menuActive:"transparent"};w.addEventListener("mouseenter",D),w.addEventListener("mouseleave",I),w.addEventListener("focus",D),w.addEventListener("blur",I),w.addEventListener("click",T=>{T.stopPropagation(),x(L.value),g()}),b.appendChild(w)}b.setAttribute("role","menu"),b.setAttribute("aria-label",r),n(f).appendChild(b),t=b,f.setAttribute("aria-expanded","true"),G(b,f,g)});return f.setAttribute("aria-haspopup","menu"),f.setAttribute("aria-expanded","false"),f}function h(p,r,v,m){function x(){return buildCheckMenuEl(f.getBoundingClientRect(),v().map(b=>"section"in b?b:{...b,onClick:M=>{b.onClick(M),m(f);const A=t;if(!A)return;const E=x();E.setAttribute("role","menu"),E.setAttribute("aria-label",r),A.replaceWith(E),t=E,G(E,f,g)}}),{makeMenuRow:l,makeMenuSection:o},f.ownerDocument.defaultView??window)}const g=()=>{t&&(t.remove(),t=null),f.setAttribute("aria-expanded","false")},f=a(p,r,()=>{if(t){g();return}const b=x();b.setAttribute("role","menu"),b.setAttribute("aria-label",r),n(f).appendChild(b),t=b,f.setAttribute("aria-expanded","true"),G(b,f,g)});return f.setAttribute("aria-haspopup","menu"),f.setAttribute("aria-expanded","false"),m(f),f}function c(p){if(t&&!t.contains(p.target)&&(t.remove(),t=null,p.target?.getAttribute?.("aria-haspopup")!=="menu"))for(const v of document.querySelectorAll('[aria-haspopup="menu"][aria-expanded="true"]'))v.setAttribute("aria-expanded","false")}return{makeBtn:a,setActive:i,makeSep:s,makeMenuRow:l,makeMenuSection:o,makeDropdown:d,makeCheckMenuBtn:h,closeOpenMenu:c,getOpenMenu:()=>t,setOpenMenu:p=>{t=p}}}const xe=7e3;let ve=0;function ae(){return xe+ ++ve}const ge=32,ye=6;let we=0;function ke(){return we++%ye*ge}function Ee(e,t){if(t===e.body)return()=>{};let n=t;for(;n.parentElement&&n.parentElement!==e.body;)n=n.parentElement;return n===e.body?()=>{}:(n.classList.add("wmap-overlay-ancestor"),()=>n.classList.remove("wmap-overlay-ancestor"))}function re(e){const t=e.mode==="modal",n=e.ownerDocument??document,a=n.defaultView??window,i=n.body.style.overflow;t&&(n.body.style.overflow="hidden");let s=null;t&&(s=n.createElement("div"),s.id="wmap-modal-backdrop",Object.assign(s.style,{position:"fixed",inset:"0",background:"rgba(0,0,0,0.6)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:Z_ABOVE,backdropFilter:"blur(3px)"}));const l=n.activeElement,o=n.createElement("div");if(o.className=t?"wmap-modal-box wmap-overlay-box":"wmap-window-box wmap-overlay-box",o.setAttribute("role","dialog"),t&&o.setAttribute("aria-modal","true"),o.setAttribute("aria-label",e.title??"Expanded wafer map"),o.tabIndex=-1,Object.assign(o.style,{position:"relative",background:CLR.menuBg,borderRadius:"12px",overflow:"hidden",display:"flex",flexDirection:"column",width:"min(90vw, 700px)",height:"min(90vh, 700px)",boxShadow:"0 20px 60px rgba(0,0,0,0.4)",minWidth:"320px",minHeight:"240px",maxWidth:"100vw",maxHeight:"100vh",zIndex:t?Z_ABOVE2:String(ae())}),!t){const u=ke();Object.assign(o.style,{position:"fixed",top:`${Math.round(a.innerHeight*.08)+u}px`,left:`${Math.round(a.innerWidth*.08)+u}px`})}const d=n.createElement("div");Object.assign(d.style,{display:"flex",alignItems:"center",gap:"6px",padding:"10px 14px",borderBottom:`1px solid ${CLR.menuBorder}`,flexShrink:"0"});const h={border:`1px solid ${CLR.menuBorder}`,borderRadius:"4px",background:CLR.panelBg,cursor:"pointer",color:CLR.label,lineHeight:"1",padding:"0",display:"flex",alignItems:"center",justifyContent:"center",width:"28px",height:"28px"};if(e.title){const u=n.createElement("span");u.textContent=e.title,u.title=e.title,u.dataset.wmapWindowTitle="1",Object.assign(u.style,{fontWeight:"700",fontSize:"14px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",minWidth:"0"}),d.appendChild(u)}const c=n.createElement("div");c.style.flex="1",d.appendChild(c);let p=null;t||(p=n.createElement("button"),p.type="button",p.innerHTML=_.windowMinimize,p.title="Minimize",p.setAttribute("aria-label","Minimize"),Object.assign(p.style,h),p.addEventListener("click",()=>U(!b)),d.appendChild(p));const r=n.createElement("button");r.type="button",r.innerHTML=_.maximize,r.title="Maximize (F)",r.setAttribute("aria-label","Maximize"),Object.assign(r.style,h),r.addEventListener("click",()=>f(!m));const v=n.createElement("button");v.type="button",v.innerHTML=_.close,v.title="Close (Esc)",v.setAttribute("aria-label","Close"),Object.assign(v.style,h),v.addEventListener("click",D),d.appendChild(r),d.appendChild(v);let m=!1,x="",g="";function f(u){m=u,r.innerHTML=m?_.minimize:_.maximize,r.title=m?"Restore (F)":"Maximize (F)",r.setAttribute("aria-label",m?"Restore":"Maximize"),k.style.display=m?"none":"block",m?(o.style.borderRadius="0",o.style.width="100vw",o.style.height="100vh",t||(x=o.style.top,g=o.style.left,o.style.top="0",o.style.left="0")):(o.style.borderRadius="12px",o.style.width="min(90vw, 700px)",o.style.height="min(90vh, 700px)",t||(o.style.top=x,o.style.left=g)),e.onMaximizeChange?.(m,o)}let b=!1,M="",A="";const E=220;function U(u){b=u,p.innerHTML=b?_.windowRestore:_.windowMinimize,p.title=b?"Restore":"Minimize",p.setAttribute("aria-label",b?"Restore":"Minimize"),k.style.display=b?"none":"block",b?(M=o.style.height,A=o.style.width,o.style.minHeight="0",o.style.height="auto",o.style.minWidth="0",o.style.width=`${E}px`,r.disabled=!0,r.style.opacity="0.4",r.style.cursor="default",T.style.display="none"):(o.style.minHeight="240px",o.style.height=M||"min(90vh, 700px)",o.style.minWidth="320px",o.style.width=A||"min(90vw, 700px)",r.disabled=!1,r.style.opacity="1",r.style.cursor="pointer",T.style.display="flex")}function F(){const u=n.body.style.userSelect;return n.body.style.userSelect="none",()=>{n.body.style.userSelect=u}}t||(d.style.cursor="move",d.addEventListener("pointerdown",u=>{if(m||u.target.closest('button, [role="button"]'))return;u.preventDefault();const B=F(),W=u.clientX,z=u.clientY,H=o.offsetTop,R=o.offsetLeft,Z=a.innerHeight-d.offsetHeight,Q=a.innerWidth-40,X=40-o.offsetWidth;d.setPointerCapture(u.pointerId);const N=V=>{const J=Math.min(Math.max(H+(V.clientY-z),0),Z),de=Math.min(Math.max(R+(V.clientX-W),X),Q);o.style.top=`${J}px`,o.style.left=`${de}px`},P=V=>{B(),d.releasePointerCapture(V.pointerId),d.removeEventListener("pointermove",N),d.removeEventListener("pointerup",P)};d.addEventListener("pointermove",N),d.addEventListener("pointerup",P)}));const L='button,[href],input,select,textarea,[tabindex]:not([tabindex="-1"]),[role="menuitem"],[role="menuitemradio"],[role="menuitemcheckbox"]';function w(u){const B=Array.from(o.querySelectorAll(L)).filter(R=>R.offsetParent!==null||R===n.activeElement);if(B.length===0){u.preventDefault(),o.focus();return}const W=B[0],z=B[B.length-1],H=n.activeElement;u.shiftKey&&(H===W||!o.contains(H))?(u.preventDefault(),z.focus()):!u.shiftKey&&H===z&&(u.preventDefault(),W.focus())}const C=u=>{if(u.key==="Escape"){D();return}if(t&&(u.key==="e"||u.key==="E")){D();return}if(t&&u.key==="Tab"){w(u);return}(u.key==="f"||u.key==="F")&&!b&&f(!m)};function D(){t?n.removeEventListener("keydown",C):o.removeEventListener("keydown",C),q.remove(),ce(),hideTooltip(n),reparentTooltip(n.body),s?s.remove():o.remove(),t&&(n.body.style.overflow=i),l?.focus?.(),e.onClose()}function I(){t||(o.style.zIndex=String(ae()))}const T=n.createElement("div");Object.assign(T.style,{flex:"1",minHeight:"0",minWidth:"0",display:"flex",overflow:"hidden"});const k=n.createElement("div");k.tabIndex=0,k.setAttribute("role","separator"),k.setAttribute("aria-label","Resize window (arrow keys, or drag)"),Object.assign(k.style,{position:"absolute",right:"0",bottom:"0",width:"16px",height:"16px",cursor:"nwse-resize",touchAction:"none"}),k.innerHTML='<svg viewBox="0 0 16 16" width="16" height="16" style="display:block"><path d="M15 15 L15 9 M15 15 L9 15 M15 15 L15 3 M15 15 L3 15" stroke="currentColor" stroke-width="1" opacity="0.35" fill="none"/></svg>',k.style.color=CLR.label;const S=320,j=240,O=20;function Y(u,B){const W=a.innerWidth-o.offsetLeft,z=a.innerHeight-o.offsetTop,H=Math.min(Math.max(o.offsetWidth+u,S),W),R=Math.min(Math.max(o.offsetHeight+B,j),z);o.style.width=`${H}px`,o.style.height=`${R}px`}k.addEventListener("keydown",u=>{if(!(m||b))switch(u.key){case"ArrowRight":u.preventDefault(),Y(O,0);break;case"ArrowLeft":u.preventDefault(),Y(-O,0);break;case"ArrowDown":u.preventDefault(),Y(0,O);break;case"ArrowUp":u.preventDefault(),Y(0,-O);break}}),k.addEventListener("pointerdown",u=>{if(m||b)return;u.preventDefault();const B=F(),W=u.clientX,z=u.clientY,H=o.offsetWidth,R=o.offsetHeight,Z=a.innerWidth-o.offsetLeft,Q=a.innerHeight-o.offsetTop;k.setPointerCapture(u.pointerId);const X=P=>{const V=Math.min(Math.max(H+(P.clientX-W),S),Z),J=Math.min(Math.max(R+(P.clientY-z),j),Q);o.style.width=`${V}px`,o.style.height=`${J}px`},N=P=>{B(),k.releasePointerCapture(P.pointerId),k.removeEventListener("pointermove",X),k.removeEventListener("pointerup",N)};k.addEventListener("pointermove",X),k.addEventListener("pointerup",N)}),o.appendChild(d),o.appendChild(T),o.appendChild(k);const K=e.anchor?overlayRootFor(e.anchor):n.body;s?(s.appendChild(o),K.appendChild(s)):K.appendChild(o);const ce=Ee(n,K),q=n.createElement("style");return q.textContent=`@media print{
|
|
2
2
|
body{overflow:visible!important;height:auto!important}
|
|
3
3
|
body>*:not(.wmap-overlay-box):not(#wmap-modal-backdrop):not(.wmap-overlay-ancestor){display:none!important}
|
|
4
4
|
#wmap-modal-backdrop{position:static!important;background:none!important;backdrop-filter:none!important;display:block!important}
|