@wafertools/wafermap 0.21.1 → 0.23.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 +181 -0
- package/CHANGELOG.md +261 -1
- package/README.md +9 -1
- package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
- package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
- package/dist/packages/canvas-adapter/dieList.d.ts +41 -0
- package/dist/packages/canvas-adapter/dieList.js +2 -0
- package/dist/packages/canvas-adapter/icons.js +1 -1
- package/dist/packages/canvas-adapter/index.d.ts +4 -0
- package/dist/packages/canvas-adapter/index.js +1 -1
- package/dist/packages/canvas-adapter/maplessSummary.d.ts +34 -0
- package/dist/packages/canvas-adapter/maplessSummary.js +1 -0
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +9 -11
- package/dist/packages/canvas-adapter/renderWaferGallery.js +8 -8
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +31 -1
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +13 -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 +57 -0
- package/dist/packages/canvas-adapter/warnings.js +1 -0
- package/dist/packages/core/classify.d.ts +6 -2
- package/dist/packages/core/dies.d.ts +67 -7
- package/dist/packages/core/dies.js +1 -1
- package/dist/packages/core/probe.d.ts +5 -0
- package/dist/packages/core/probe.js +1 -1
- package/dist/packages/core/transforms.d.ts +4 -4
- package/dist/packages/core/transforms.js +1 -1
- package/dist/packages/renderer/buildView.d.ts +3 -3
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.d.ts +40 -9
- 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/clusterDetection.d.ts +2 -2
- package/dist/packages/stats/patternClassification.d.ts +2 -2
- package/dist/packages/stats/regions.d.ts +6 -6
- package/dist/packages/stats/regions.js +1 -1
- package/dist/packages/stats/renderFindingsReport.js +15 -15
- package/dist/packages/stats/renderSummaryReport.js +17 -17
- package/dist/packages/stats/types.d.ts +34 -4
- package/llms.txt +39 -0
- package/package.json +12 -8
|
@@ -3,6 +3,8 @@ import type { Die } from '../core/dies.js';
|
|
|
3
3
|
import { type BinDef, type TestDef, type YieldSummary } from '../renderer/buildWaferMap.js';
|
|
4
4
|
import type { StatsFinding, StatsSummary, LotStatsSummary } from '../stats/types.js';
|
|
5
5
|
import { type FindingsFilter } from '../stats/filterFindings.js';
|
|
6
|
+
import { buildWarningsBanner, type WaferWarning } from './warnings.js';
|
|
7
|
+
export { buildWarningsBanner };
|
|
6
8
|
import { type SaveTextHandler } from './toolbar.js';
|
|
7
9
|
export interface SummaryPanelOptions {
|
|
8
10
|
/** Which side of the content area to place the panel. Default 'right'. */
|
|
@@ -10,7 +12,6 @@ export interface SummaryPanelOptions {
|
|
|
10
12
|
/** Open the panel immediately on render without requiring the user to click the toolbar button. Default false. */
|
|
11
13
|
defaultOpen?: boolean;
|
|
12
14
|
}
|
|
13
|
-
export declare function buildWarningsBanner(warnings: string[]): HTMLDivElement;
|
|
14
15
|
/** Order-preserving [key, value] pairs from a metadata-like record, with
|
|
15
16
|
* null/undefined/empty-string entries dropped. The single source of truth
|
|
16
17
|
* for "what counts as a displayable metadata field" — shared by the map
|
|
@@ -124,6 +125,8 @@ export declare function buildLotOverviewSection(lotSummary: LotStatsSummary): HT
|
|
|
124
125
|
export declare function buildPerWaferYieldSection(lotSummary: LotStatsSummary, items: Array<{
|
|
125
126
|
label?: string;
|
|
126
127
|
} | null>, onWaferClick?: (waferIndex: number) => void): HTMLDivElement | null;
|
|
128
|
+
/** CSV field escaper — exported so `dieList.ts` shares it rather than a second copy. */
|
|
129
|
+
export declare function csvField(value: string): string;
|
|
127
130
|
export declare function buildTestSection(dies: Die[], testDefs: TestDef[] | undefined, fallbackFormat?: 'si' | 'engineering',
|
|
128
131
|
/**
|
|
129
132
|
* When supplied, each test's descriptive stats and spec-yield are read from
|
|
@@ -226,6 +229,13 @@ export declare function renderWaferSummaryContent(panel: HTMLDivElement, params:
|
|
|
226
229
|
sbinDefs?: BinDef[];
|
|
227
230
|
testDefs?: TestDef[];
|
|
228
231
|
statsSummary?: StatsSummary;
|
|
232
|
+
/**
|
|
233
|
+
* Warnings to show above the panel. Collected by the renderer via
|
|
234
|
+
* `collectWarnings` so this banner, the toolbar indicator and `onWarning`
|
|
235
|
+
* all show the same set. Falls back to the summary's own analysis warnings
|
|
236
|
+
* when omitted, which is the only set a bare panel could know about.
|
|
237
|
+
*/
|
|
238
|
+
warnings?: WaferWarning[];
|
|
229
239
|
passBins?: number[];
|
|
230
240
|
ringCount?: number;
|
|
231
241
|
colorScheme?: string;
|
|
@@ -258,5 +268,7 @@ export declare function renderLotSummaryContent(panel: HTMLDivElement, params: {
|
|
|
258
268
|
findingsFilter?: FindingsFilter;
|
|
259
269
|
onFindingsFilterChange?: () => void;
|
|
260
270
|
onSaveText?: SaveTextHandler;
|
|
271
|
+
/** See the wafer panel's `warnings` — collected by the renderer so every surface agrees. */
|
|
272
|
+
warnings?: WaferWarning[];
|
|
261
273
|
}): void;
|
|
262
274
|
//# sourceMappingURL=summaryPanel.d.ts.map
|
|
@@ -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)}),R.appendChild($),
|
|
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 se}from"../renderer/buildWaferMap.js";import{buildRingRegions as Q,buildQuadrantRegions as G,buildRegionYieldData as le}from"../stats/regions.js";import{computeFunctionalYield as de}from"../stats/analyzeWaferMap.js";import{openHtmlReport as U}from"../stats/renderFindingsReport.js";import{renderSummaryReportHtml as pe,renderLotSummaryReportHtml as ce}from"../stats/renderSummaryReport.js";import{buildFindingsNarrative as ue}from"../stats/findingsNarrative.js";import{filterFindings as fe}from"../stats/filterFindings.js";import{buildFacetTable as me,prettyKey as X}from"../stats/facets.js";import{getColorScheme as he}from"../renderer/colorSchemes.js";import{buildWarningsBanner as j,collectWarnings as K}from"./warnings.js";export{j as buildWarningsBanner};import{fmt as Z,fmtAggregationMethod as ge,plainBinTerms as H}from"../renderer/fmt.js";import{getUniqueTestNumbers as xe}from"../renderer/buildView.js";import{quantile as O}from"../stats/math.js";import{makeLabeledSelect as J}from"./charts/chartShell.js";import{CLR as y,sevColor as q,openModal as be,saveTextFile as ee}from"./toolbar.js";import{medianOfSorted as ve}from"../core/utils.js";const Se=y.panelBg,M=`1px solid ${y.menuBorder}`,ye="12px",F=y.label,W=y.value,te="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:te,fontWeight:"700",letterSpacing:"0.06em",textTransform:"uppercase",color:F,marginBottom:"6px"},e)}function ne(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:te,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:y.warnBg,color:y.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 ie(){return s("div",{height:"1px",background:y.separator,margin:`${ye} 0`,flexShrink:"0"})}function _(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 f=i!==void 0?i:Math.min(100,Math.max(0,n)),b=d?"#94a3b8":t,v=s("div",{position:"relative",height:"9px",background:y.bgActive,borderRadius:"4px",overflow:"hidden"}),R=s("div",{height:"100%",width:`${f}%`,background:b,borderRadius:"4px",transition:"width 0.3s ease"});if(v.appendChild(R),r!==void 0){const B=s("div",{position:"absolute",top:"0",bottom:"0",left:`${r}%`,width:"1px",background:y.infoText,opacity:"0.5"});v.appendChild(B)}return c.appendChild(p),c.appendChild(v),c}function A(e,n,t){const i=s("div",{background:y.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 Ce(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 we(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},`${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=me(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 ke={display:"flex",flexDirection:"column",gap:"6px",background:y.menuBg,border:`1px solid ${y.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",ke);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(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=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(A(String(e.totalDies),"Total dies")),e.partialDies>0&&r.appendChild(A(String(e.partialDies),"Partial")),e.yieldPercent!==null){const d=t.length===1?`bin ${t[0]}`:`bins ${t.join(", ")}`;r.appendChild(A(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return i.appendChild(r),e.edgeExcludedDies>0&&i.appendChild(Ce("Edge excluded (outer zone)",String(e.edgeExcludedDies))),i}export function buildBinSection(e,n,t,i,r){const d=new Map;if(r)for(const[f,b]of Object.entries(r))d.set(Number(f),b);else for(const f of e){if(f.partial||f.edgeExcluded)continue;const b=t==="hard"?f.hbin:f.sbin;b!=null&&d.set(b,(d.get(b)??0)+1)}if(!d.size)return null;const c=[...d.values()].reduce((f,b)=>f+b,0),p=n?new Map(n.map(f=>[f.bin,f])):null,o=[...d.entries()].sort((f,b)=>f[0]-b[0]),l=s("div");l.appendChild(I(t==="hard"?"Hard Bin Breakdown":"Soft Bin Breakdown"));for(const[f,b]of o){const v=p?.get(f),R=v?.name?`Bin ${f} \xB7 ${v.name}`:`Bin ${f}`,B=b/c*100,$=he(i),D=(i==="custom"?v?.color:void 0)??$.forBin(f);l.appendChild(_(`${R} (${b})`,B,D))}return l}export function buildLotBinSection(e,n,t,i){return buildBinSection(e,n,t,i)}function P(e,n,t,i,r,d){const c=le(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:f}of c)p.appendChild(_(`${o} (N=${l})`,f));return p}export function buildRingSection(e,n,t,i){return P([e],[n],t,i,Q,"Ring Yield")}export function buildQuadrantSection(e,n,t,i){return P([e],[n],t,i,G,"Quadrant Yield")}export function buildLotRingSection(e,n,t,i){return P(e,n,t,i,Q,"Ring Yield")}export function buildLotQuadrantSection(e,n,t,i){return P(e,n,t,i,G,"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(A(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(A(`${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=ve([...i.map(l=>l.yieldPct)].sort((l,f)=>l-f)),o=s("div");o.appendChild(I("Wafer Yield"+c));for(const{waferIndex:l,label:f,yieldPct:b}of i){const v=_(f,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",`${f}, ${b.toFixed(1)}% yield \u2014 view wafer`),v.tabIndex=0,v.addEventListener("mouseenter",()=>{v.style.background=y.bgHover}),v.addEventListener("mouseleave",()=>{v.style.background=""}),v.addEventListener("focus",()=>{v.style.background=y.bgHover}),v.addEventListener("blur",()=>{v.style.background=""}),v.addEventListener("click",()=>t(l)),v.addEventListener("keydown",R=>{(R.key==="Enter"||R.key===" ")&&(R.preventDefault(),t(l))})),o.appendChild(v)}return o}function Be(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)}}export function csvField(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(se).map(a=>({testNumber:a.testNumber,name:a.name,unit:a.unit,limitLow:a.limitLow,limitHigh:a.limitHigh})):o=xe(d).map(h=>({testNumber:h,name:`Test ${h}`})),!o.length)return null;const l=o.filter(a=>d.some(h=>{const S=h.testValues?.[a.testNumber];return S!==void 0&&isFinite(S)}));if(!l.length)return null;const f=l.some(a=>a.limitLow!==void 0||a.limitHigh!==void 0),b=[];for(const a of l){const h=c.get(a.testNumber),S=h&&h.stddev!==void 0&&h.median!==void 0&&h.q1!==void 0&&h.q3!==void 0;let w;if(S){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(L=>L.testValues?.[a.testNumber]).filter(L=>L!==void 0&&isFinite(L));if(!g.length)continue;w={testNumber:a.testNumber,...Be(g)}}let x=null,u=0;if(a.limitLow!==void 0||a.limitHigh!==void 0){const g=p.get(a.testNumber);if(g)({yieldPercent:x,totalDies:u}=g);else{const L=d.map(N=>N.testValues?.[a.testNumber]).filter(N=>N!==void 0&&isFinite(N)),Y=L.filter(N=>a.limitLow!==void 0&&N<a.limitLow||a.limitHigh!==void 0&&N>a.limitHigh).length;u=L.length,x=L.length>0?(L.length-Y)/L.length*100:null}}b.push({entry:a,stats:w,specYieldPct:x,specN:u})}if(!b.length)return null;const v=s("div"),R=s("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:"6px"}),B=I(`Test Values (${b.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:y.iconHover,padding:"2px 7px"}),$.addEventListener("click",()=>{const a=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];f&&a.push("LSL","USL","Spec Yield %","Spec Yield N");const h=[a.map(csvField).join(",")],S=w=>Z(w,void 0,"engineering");for(const{entry:w,stats:x,specYieldPct:u,specN:g}of b){const L=[w.name,w.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)];f&&L.push(w.limitLow!==void 0?S(w.limitLow):"",w.limitHigh!==void 0?S(w.limitHigh):"",u!==null?u.toFixed(1):"",w.limitLow!==void 0||w.limitHigh!==void 0?String(g):""),h.push(L.map(csvField).join(","))}ee(h.join(`
|
|
2
|
+
`),"test-values.csv","text/csv",r)}),R.appendChild($),v.appendChild(R);const D=s("table",{width:"100%",borderCollapse:"collapse",fontSize:"11px"}),T=document.createElement("thead"),E=document.createElement("tr"),m=["Test","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];f&&m.push("LSL","USL","Spec yield");for(const a of m){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 ${y.menuBorder}`,whiteSpace:"nowrap"},a);E.appendChild(h)}T.appendChild(E),D.appendChild(T);const k=document.createElement("tbody");for(const{entry:a,stats:h,specYieldPct:S,specN:w}of b){const x=L=>Z(L,a.unit,t),u=document.createElement("tr"),g=(L,Y="right")=>{const N=s("td",{textAlign:Y,padding:"4px 8px",borderBottom:`1px solid ${y.menuBorder}`,color:W,whiteSpace:"nowrap"},L);u.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)),f&&(g(a.limitLow!==void 0?x(a.limitLow):"\u2014"),g(a.limitHigh!==void 0?x(a.limitHigh):"\u2014"),g(S!==null?`${S.toFixed(1)}% (N=${w})`:"\u2014")),k.appendChild(u)}D.appendChild(k);const C=s("div",{overflowX:"auto"});return C.appendChild(D),v.appendChild(C),v}export function buildFunctionalTestSection(e,n,t,i){const r=t??de(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:y.iconHover,padding:"2px 7px"}),o.addEventListener("click",()=>{const B=[["Test","N","Pass","Fail","Pass Rate %"].map(csvField).join(",")];for(const $ of r)B.push([$.label,String($.totalDies),String($.passDies),String($.failDies),$.passRatePercent!==null?$.passRatePercent.toFixed(1):""].map(csvField).join(","));ee(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"}),f=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 ${y.menuBorder}`,whiteSpace:"nowrap"},B));f.appendChild(b),l.appendChild(f);const v=document.createElement("tbody");for(const B of r){const $=document.createElement("tr"),D=(T,E="right")=>{$.appendChild(s("td",{textAlign:E,padding:"4px 8px",borderBottom:`1px solid ${y.menuBorder}`,color:W,whiteSpace:"nowrap"},T))};D(B.label,"left"),D(String(B.totalDies)),D(String(B.passDies)),D(String(B.failDies)),D(B.passRatePercent!==null?`${B.passRatePercent.toFixed(1)}% (N=${B.totalDies})`:"\u2014"),v.appendChild($)}l.appendChild(v);const R=s("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 z={unusual:0,notable:1,info:2};function V(e){return s("span",{display:"inline-block",width:"7px",height:"7px",borderRadius:"50%",background:q(e),flexShrink:"0"})}function oe(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(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=s("div");return{outer:m,content:m}})():ne(`Findings (${e.length})`,d,c);function l(m){return m.reduce((k,C)=>z[C.severity]<z[k]?C.severity:k,"info")}function f(m){const k=new Map;for(const a of m){const h=`${a.comparison.family}\0${a.comparison.left}`,S=k.get(h)??[];S.push(a),k.set(h,S)}const C=[...k.entries()].map(([a,h])=>{const S=[...h].sort((w,x)=>z[w.severity]-z[x.severity]);return{key:a,findings:S,worst:l(S)}});return C.sort((a,h)=>z[a.worst]-z[h.worst]),C}function b(m,k){const a={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(a.toLowerCase())?k:`${a}: ${k}`}const v=e.filter(m=>m.comparison.family==="spatial-pattern"),R=new Set([...v.flatMap(m=>m.relatedIds??[]),...e.flatMap(m=>m.absorbedIds??[])]),B=e.filter(m=>m.comparison.family!=="spatial-pattern"&&!R.has(m.id)),$=f(B);function D(m,k=!1,C){const a=i===m.id,h=document.createElement("button");return h.type="button",h.dataset.wmapFinding=m.id,h.textContent=oe(m,C),h.title=m.summary,h.setAttribute("aria-current",a?"true":"false"),Object.assign(h.style,{border:`1px solid ${y.menuBorder}`,borderLeft:`3px solid ${q(m.severity)}`,background:a?y.bgActive:y.menuBg,borderRadius:"6px",padding:k?"6px 10px":"8px 10px",textAlign:"left",fontSize:k?"10px":"11px",fontWeight:a?"600":"400",color:y.iconHover,cursor:"pointer",width:"100%",marginBottom:"4px"}),h.addEventListener("click",()=>t(m,h)),h}const T=H(ue(e)??"");if(T){const m=s("div",{background:y.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:y.iconHover},T);m.appendChild(k);const C=s("button",{flexShrink:"0",border:"none",background:"none",fontSize:"10px",color:y.icon,cursor:"pointer",padding:"0",lineHeight:"1.5",whiteSpace:"nowrap"},"Detail \u25B8");C.type="button",C.addEventListener("click",()=>{const a=be({title:"Findings Summary",onClose:()=>{},anchor:C}),h=s("p",{fontSize:"16px",lineHeight:"1.6",color:y.iconHover,padding:"20px 24px 16px",margin:"0",borderBottom:`1px solid ${y.menuBorder}`,flexShrink:"0"},T);a.contentWrap.appendChild(h);const S=s("div",{overflowY:"auto",padding:"16px 24px",flex:"1"}),w=(x,u)=>{const g=s("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:"13px",fontWeight:"600",color:W,marginTop:"10px",marginBottom:"4px"});return g.appendChild(V(x)),g.appendChild(s("span",{},u)),g};for(const x of v){S.appendChild(w(x.severity,x.comparison.left)),S.appendChild(s("div",{fontSize:"13px",color:y.iconHover,padding:"3px 0 3px 15px",marginBottom:"2px"},H(x.summary)));const u=e.filter(g=>x.relatedIds?.includes(g.id));for(const g of u)S.appendChild(s("div",{fontSize:"12px",color:y.icon,padding:"2px 0 2px 23px",marginBottom:"2px"},H(g.summary)))}for(const x of $){const[u,g]=x.key.split("\0");S.appendChild(w(x.worst,b(u,g)));for(const L of x.findings)S.appendChild(s("div",{fontSize:"13px",color:y.iconHover,padding:"3px 0 3px 15px",marginBottom:"2px"},oe(L,g)))}a.contentWrap.appendChild(S),Object.assign(a.contentWrap.style,{flexDirection:"column",overflow:"hidden"})}),m.appendChild(C),o.appendChild(m)}let E=!0;for(const m of v){E||o.appendChild(s("div",{height:"1px",background:y.separator,margin:"4px 0"})),E=!1;const k=e.filter(w=>m.relatedIds?.includes(w.id)),C=k.length>0,a=s("div",{position:"relative",marginBottom:C?"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 ${y.menuBorder}`,borderLeft:`3px solid ${q(m.severity)}`,background:h?y.bgActive:y.menuBg,borderRadius:"6px",padding:"8px 32px 8px 10px",textAlign:"left",fontSize:"11px",fontWeight:h?"600":"500",color:y.iconHover,cursor:"pointer",width:"100%"}),S.textContent=H(m.summary),S.title=m.summary,S.setAttribute("aria-current",h?"true":"false"),S.addEventListener("click",()=>t(m,S)),a.appendChild(S),C){const w=s("div",{display:"none",paddingLeft:"12px",marginBottom:"4px"});for(const g of k)w.appendChild(D(g,!0));a.appendChild(w);let x=!1;const u=s("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:"10px",color:y.icon,cursor:"pointer",padding:"2px 4px",lineHeight:"1"},"\u25B8");u.type="button",u.title="Show supporting findings",u.setAttribute("aria-label","Show supporting findings"),u.setAttribute("aria-expanded","false"),u.addEventListener("click",g=>{g.stopPropagation(),x=!x,w.style.display=x?"block":"none",u.textContent=x?"\u25BE":"\u25B8";const L=x?"Hide supporting findings":"Show supporting findings";u.title=L,u.setAttribute("aria-label",L),u.setAttribute("aria-expanded",String(x))}),a.appendChild(u)}o.appendChild(a)}for(const m of $){E||o.appendChild(s("div",{height:"1px",background:y.separator,margin:"4px 0"})),E=!1;const[k,C]=m.key.split("\0"),a=s("div",{display:"flex",alignItems:"center",gap:"6px",fontSize:"11px",fontWeight:"600",color:W,margin:"2px 0 4px"});a.appendChild(V(m.worst)),a.appendChild(s("span",{},b(k,C))),o.appendChild(a);for(const h of m.findings)o.appendChild(D(h,!1,C))}return p}const $e=[{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"}],Le=[{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"],De={unusual:"Unusual",notable:"Notable",info:"Info"};function Ee(e,n,t){const i=s("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:"10px",marginBottom:"10px",paddingBottom:"10px",borderBottom:`1px solid ${y.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=s("div",{display:"flex",gap:"4px",flexWrap:"wrap"});for(const o of d){const l=document.createElement("button");l.type="button";const f=()=>{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 ${y.menuBorder}`,borderRadius:"10px",background:b?y.bgActive:"none",opacity:b?"1":"0.5",color:y.text,fontSize:"11px",padding:"2px 8px",cursor:"pointer"})};l.appendChild(V(o)),l.appendChild(s("span",{},`${De[o]} ${r[o]}`)),l.title=c.has(o)?"Click to hide these findings":"Click to show these findings",f(),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(J("Kind:",$e,n.kind??"",o=>{n.kind=o||void 0,t()},{maxWidth:"130px"})),i.appendChild(J("Region:",Le,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}=ne(`Findings (${e.findings.length})`,d,c);o.appendChild(Ee(e.findings,i,r));const l=fe(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 f=buildFindingsSection(l,e,n,t,!0);return f&&o.appendChild(f),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 re(e){return s("div",{fontSize:"13px",fontWeight:"700",color:W,marginBottom:"10px"},e)}function ae(e,n){const t=s("button",{background:"none",border:M,borderRadius:"4px",cursor:"pointer",fontSize:"10px",color:y.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:f,passBins:b=[1],ringCount:v=4,colorScheme:R,fallbackFormat:B,onFindingClick:$,activeFindingId:D=null,findingsFilter:T,onFindingsFilterChange:E,onSaveText:m}=n;e.appendChild(re("Wafer Summary"));const k=n.warnings??K({statsSummary:f});k.length&&e.appendChild(j(k)),d&&c&&e.appendChild(ae("Summary report",()=>{U(pe({wafer:i,dies:r,yieldSummary:d,dataCoverage:c,hbinDefs:p,sbinDefs:o,testDefs:l,statsSummary:f,passBins:b,ringCount:v}))}));const C=[],a=f?.stats.isLotStack?f.stats:void 0,h=a?.lotSize!==void 0?{lotSize:a.lotSize,aggrMethod:ge(a.aggregationMethod)}:void 0;C.push(buildMetadataInfoSection([{metadata:i.metadata??void 0}],h)),d&&c&&C.push(buildYieldSection(d,c,b));const S=r.some(u=>u.hbin!=null),w=r.some(u=>u.sbin!=null);S?C.push(buildBinSection(r,p,"hard",R,f?.stats.hardBinCounts)):w&&C.push(buildBinSection(r,o,"soft",R,f?.stats.softBinCounts)),C.push(buildRingSection(r,i,v,b)),C.push(buildQuadrantSection(r,i,v,b)),C.push(buildTestSection(r,l,B,f?.stats,m)),C.push(buildFunctionalTestSection(r,l,f?.stats.functionalYield,m)),f&&$&&T&&E&&C.push(buildFindingsSectionWithFilter(f,$,D,T,E));let x=!0;for(const u of C)u&&(x||e.appendChild(ie()),x=!1,e.appendChild(u));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:f,fallbackFormat:b,onFindingClick:v,activeFindingId:R=null,onWaferClick:B,findingsFilter:$,onFindingsFilterChange:D,onSaveText:T}=n;e.appendChild(re(`Lot Summary \u2014 ${i.stats.waferCount} wafer${i.stats.waferCount===1?"":"s"}`));const E=n.warnings??K({lotStatsSummary:i});E.length&&e.appendChild(j(E)),e.appendChild(ae("Summary report",()=>{U(ce({items:r.map((u,g)=>({label:u?.label??`W${g+1}`,wafer:u?.wafer,dies:u?.dies,statsSummary:u?.statsSummary})),hbinDefs:d,sbinDefs:c,testDefs:p,passBins:o,ringCount:l}))}));const m=[],k=[],C=[];for(const u of r){if(!u){k.push([]);continue}u.wafer&&m.push(u.wafer);const g=u.dies??[];k.push(g),C.push(...g)}const a=C.some(u=>u.hbin!=null),h=C.some(u=>u.sbin!=null),S=r.map(u=>u?.statsSummary).filter(u=>!!u),w=[buildLotOverviewSection(i),buildMetadataInfoSection(r.filter(u=>u!==null).map(u=>({metadata:u.wafer?.metadata}))),buildPerWaferYieldSection(i,r,B),a?buildLotBinSection(C,d,"hard",f):h?buildLotBinSection(C,c,"soft",f):null,buildLotRingSection(k,m,l,o),buildLotQuadrantSection(k,m,l,o),p?.length?buildLotTestSection(C,p,b,S,T):null,p?.length?buildLotFunctionalSection(C,p,S,T):null];v&&$&&D&&w.push(buildFindingsSectionWithFilter(i,v,R,$,D));let x=!0;for(const u of w)u&&(x||e.appendChild(ie()),x=!1,e.appendChild(u));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}
|