@wafertools/wafermap 0.33.0 → 0.34.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 +6 -6
- package/CHANGELOG.md +212 -0
- package/README.md +5 -5
- package/dist/packages/canvas-adapter/chartPopulation.d.ts +15 -10
- package/dist/packages/canvas-adapter/chartPopulation.js +1 -1
- package/dist/packages/canvas-adapter/charts/barPanel.d.ts +7 -0
- package/dist/packages/canvas-adapter/charts/barPanel.js +1 -1
- package/dist/packages/canvas-adapter/charts/binCluster.d.ts +7 -1
- package/dist/packages/canvas-adapter/charts/binCluster.js +1 -1
- package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
- package/dist/packages/canvas-adapter/charts/capability.js +1 -1
- package/dist/packages/canvas-adapter/charts/chartShell.d.ts +55 -3
- package/dist/packages/canvas-adapter/charts/chartShell.js +1 -1
- package/dist/packages/canvas-adapter/charts/correlation.js +1 -2
- package/dist/packages/canvas-adapter/charts/groupedBarPlot.d.ts +2 -0
- package/dist/packages/canvas-adapter/charts/groupedBarPlot.js +1 -1
- package/dist/packages/canvas-adapter/charts/histogram.d.ts +16 -0
- package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
- package/dist/packages/canvas-adapter/charts/palette.d.ts +2 -0
- package/dist/packages/canvas-adapter/charts/palette.js +1 -1
- package/dist/packages/canvas-adapter/charts/plotChart.d.ts +27 -0
- package/dist/packages/canvas-adapter/charts/plotChart.js +1 -0
- package/dist/packages/canvas-adapter/charts/pointInteractions.d.ts +45 -0
- package/dist/packages/canvas-adapter/charts/pointInteractions.js +1 -0
- package/dist/packages/canvas-adapter/charts/regionYieldDiagram.d.ts +2 -0
- package/dist/packages/canvas-adapter/charts/regionYieldDiagram.js +1 -1
- package/dist/packages/canvas-adapter/charts/scatter.d.ts +19 -0
- package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
- package/dist/packages/canvas-adapter/charts/sweep.d.ts +12 -0
- package/dist/packages/canvas-adapter/charts/sweep.js +1 -1
- package/dist/packages/canvas-adapter/charts/testPassRate.d.ts +7 -0
- package/dist/packages/canvas-adapter/charts/testPassRate.js +1 -1
- package/dist/packages/canvas-adapter/charts/trend.d.ts +11 -0
- package/dist/packages/canvas-adapter/charts/trend.js +1 -1
- package/dist/packages/canvas-adapter/confirmDialog.d.ts +13 -0
- package/dist/packages/canvas-adapter/confirmDialog.js +1 -0
- package/dist/packages/canvas-adapter/dataTab.d.ts +131 -0
- package/dist/packages/canvas-adapter/dataTab.js +1 -0
- package/dist/packages/canvas-adapter/dieList.d.ts +39 -4
- package/dist/packages/canvas-adapter/dieList.js +6 -7
- package/dist/packages/canvas-adapter/drilldown.d.ts +20 -3
- package/dist/packages/canvas-adapter/drilldown.js +1 -1
- package/dist/packages/canvas-adapter/guideWindow.d.ts +96 -0
- package/dist/packages/canvas-adapter/guideWindow.js +1 -0
- package/dist/packages/canvas-adapter/identityHeader.d.ts +16 -0
- package/dist/packages/canvas-adapter/identityHeader.js +1 -1
- package/dist/packages/canvas-adapter/index.d.ts +3 -3
- package/dist/packages/canvas-adapter/index.js +1 -1
- package/dist/packages/canvas-adapter/insightsTab.d.ts +73 -54
- package/dist/packages/canvas-adapter/insightsTab.js +1 -1
- package/dist/packages/canvas-adapter/maplessSummary.d.ts +2 -2
- package/dist/packages/canvas-adapter/plotEditor.d.ts +29 -0
- package/dist/packages/canvas-adapter/plotEditor.js +1 -0
- package/dist/packages/canvas-adapter/plotItems.d.ts +32 -0
- package/dist/packages/canvas-adapter/plotItems.js +1 -0
- package/dist/packages/canvas-adapter/plotModal.d.ts +30 -0
- package/dist/packages/canvas-adapter/plotModal.js +1 -0
- package/dist/packages/canvas-adapter/plotStore.d.ts +52 -0
- package/dist/packages/canvas-adapter/plotStore.js +1 -0
- package/dist/packages/canvas-adapter/plotTab.d.ts +30 -0
- package/dist/packages/canvas-adapter/plotTab.js +1 -0
- package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +3 -2
- package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +21 -2
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +27 -8
- package/dist/packages/canvas-adapter/summaryPanel.js +2 -4
- package/dist/packages/canvas-adapter/summaryRail.d.ts +7 -0
- package/dist/packages/canvas-adapter/summaryRail.js +1 -0
- package/dist/packages/canvas-adapter/sweepEditor.d.ts +17 -0
- package/dist/packages/canvas-adapter/sweepEditor.js +1 -0
- package/dist/packages/canvas-adapter/tableExport.d.ts +22 -0
- package/dist/packages/canvas-adapter/tableExport.js +3 -0
- package/dist/packages/canvas-adapter/toolbar.d.ts +25 -97
- package/dist/packages/canvas-adapter/toolbar.js +2 -2
- package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
- package/dist/packages/canvas-adapter/userGuideHtml.js +337 -42
- package/dist/packages/canvas-adapter/version.d.ts +2 -2
- package/dist/packages/canvas-adapter/version.js +1 -1
- package/dist/packages/canvas-adapter/viewSwitch.d.ts +13 -0
- package/dist/packages/canvas-adapter/viewSwitch.js +1 -0
- package/dist/packages/canvas-adapter/virtualTable.d.ts +44 -0
- package/dist/packages/canvas-adapter/virtualTable.js +1 -0
- package/dist/packages/core/classify.d.ts +3 -2
- package/dist/packages/core/classify.js +1 -1
- package/dist/packages/core/passBins.d.ts +17 -4
- package/dist/packages/core/passBins.js +1 -1
- package/dist/packages/core/ringCount.d.ts +22 -0
- package/dist/packages/core/ringCount.js +1 -0
- package/dist/packages/core/tableCsv.d.ts +43 -0
- package/dist/packages/core/tableCsv.js +3 -0
- package/dist/packages/renderer/binColors.d.ts +6 -6
- package/dist/packages/renderer/binColors.js +1 -1
- package/dist/packages/renderer/buildView.d.ts +1 -1
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/stats/analyzeWaferLot.js +1 -1
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/binPareto.d.ts +1 -1
- package/dist/packages/stats/binPareto.js +1 -1
- package/dist/packages/stats/histogram.d.ts +27 -0
- package/dist/packages/stats/histogram.js +1 -1
- package/dist/packages/stats/index.d.ts +2 -0
- package/dist/packages/stats/index.js +1 -1
- package/dist/packages/stats/lotDrift.js +1 -1
- package/dist/packages/stats/lotPattern.js +1 -1
- package/dist/packages/stats/math.d.ts +9 -6
- package/dist/packages/stats/math.js +1 -1
- package/dist/packages/stats/patternClassification.d.ts +1 -1
- package/dist/packages/stats/patternClassification.js +1 -1
- package/dist/packages/stats/plotData.d.ts +258 -0
- package/dist/packages/stats/plotData.js +1 -0
- package/dist/packages/stats/plotId.d.ts +3 -0
- package/dist/packages/stats/plotId.js +1 -0
- package/dist/packages/stats/plotSpec.d.ts +119 -0
- package/dist/packages/stats/plotSpec.js +4 -0
- package/dist/packages/stats/presentation.d.ts +2 -0
- package/dist/packages/stats/presentation.js +1 -1
- package/dist/packages/stats/regions.d.ts +6 -0
- package/dist/packages/stats/regions.js +1 -1
- package/dist/packages/stats/renderSummaryReport.d.ts +8 -3
- package/dist/packages/stats/renderSummaryReport.js +15 -15
- package/dist/packages/stats/reportHtml.d.ts +1 -1
- package/dist/packages/stats/reportHtml.js +36 -29
- package/dist/packages/stats/scatter.d.ts +6 -0
- package/dist/packages/stats/scatter.js +1 -1
- package/dist/packages/stats/sweep.d.ts +37 -1
- package/dist/packages/stats/sweep.js +1 -1
- package/dist/packages/stats/sweepText.d.ts +14 -0
- package/dist/packages/stats/sweepText.js +1 -0
- package/dist/packages/stats/sweepXFromName.d.ts +14 -0
- package/dist/packages/stats/sweepXFromName.js +1 -1
- package/dist/packages/stats/synthesis.d.ts +14 -4
- package/dist/packages/stats/synthesis.js +1 -1
- package/dist/packages/stats/testPassRate.d.ts +6 -0
- package/dist/packages/stats/testPassRate.js +1 -1
- package/dist/packages/stats/trend.js +1 -1
- package/dist/packages/stats/types.d.ts +1 -1
- package/dist/packages/stats/yield.d.ts +15 -6
- package/dist/packages/stats/yield.js +1 -1
- package/llms.txt +15 -3
- package/package.json +3 -3
|
@@ -10,7 +10,7 @@ export { buildWarningsBanner };
|
|
|
10
10
|
import type { PlotMode } from '../renderer/buildView.js';
|
|
11
11
|
import { type CapabilityItem } from '../stats/capability.js';
|
|
12
12
|
import { type SaveTextHandler } from './toolbar.js';
|
|
13
|
-
import {
|
|
13
|
+
import type { DieListDisplayOptions } from './dieList.js';
|
|
14
14
|
export { csvField } from '../core/utils.js';
|
|
15
15
|
import { type Chunked } from '../core/utils.js';
|
|
16
16
|
import type { WaferMetadata } from '../core/metadata.js';
|
|
@@ -31,7 +31,9 @@ export declare function buildFacetSummaryChips(table: Array<{
|
|
|
31
31
|
values: Array<{
|
|
32
32
|
value: string;
|
|
33
33
|
}>;
|
|
34
|
-
}>,
|
|
34
|
+
}>,
|
|
35
|
+
/** How many values a field lists before it has been laid out (no width yet: first paint, a hidden parent). */
|
|
36
|
+
maxValuesPerField?: number): HTMLDivElement | null;
|
|
35
37
|
export interface MetadataStripStacked {
|
|
36
38
|
lotSize: number;
|
|
37
39
|
aggrMethod?: string;
|
|
@@ -89,7 +91,7 @@ export declare function buildYieldSection(yieldSummary: YieldSummary, dataCovera
|
|
|
89
91
|
totalDies: number;
|
|
90
92
|
edgeExcludedDies: number;
|
|
91
93
|
ratio: number;
|
|
92
|
-
}, passBins
|
|
94
|
+
}, passBins: number[]): HTMLDivElement;
|
|
93
95
|
export declare function buildBinSection(dies: Die[], binDefs: BinDef[] | undefined, mode: 'hard' | 'soft',
|
|
94
96
|
/**
|
|
95
97
|
* The map's resolved bin colours (`View.binColors`) — colours AND pass
|
|
@@ -129,6 +131,7 @@ export declare function buildBinBreakdownSection(params: {
|
|
|
129
131
|
softCounts?: Record<number, number>;
|
|
130
132
|
/** The map's active plot mode. `hardBin`/`softBin` pick the matching bin type. */
|
|
131
133
|
plotMode?: PlotMode;
|
|
134
|
+
/** The pass bins to resolve colours by, when `binColors` is omitted. Never defaulted: with neither the section is refused. */
|
|
132
135
|
passBins?: number[];
|
|
133
136
|
panel?: HTMLElement;
|
|
134
137
|
}): HTMLDivElement | null;
|
|
@@ -437,7 +440,15 @@ export declare function createSummaryPanelEl(placement: 'right' | 'left' | 'top'
|
|
|
437
440
|
* gutter on the gallery's panel where 12 belonged, and 12px inside a map card
|
|
438
441
|
* where 4 belonged.
|
|
439
442
|
*/
|
|
440
|
-
edgeInset: string, ownerDocument?: Document
|
|
443
|
+
edgeInset: string, ownerDocument?: Document,
|
|
444
|
+
/**
|
|
445
|
+
* Right-click on a finding (its row, a parent row or a finding named in the text): the host selects that finding's
|
|
446
|
+
* dies if they are not already and opens the drilldown menu on them. Without it the browser's menu is left alone.
|
|
447
|
+
*/
|
|
448
|
+
onFindingMenu?: (findingId: string, row: HTMLElement, at: {
|
|
449
|
+
x: number;
|
|
450
|
+
y: number;
|
|
451
|
+
}) => void): HTMLDivElement;
|
|
441
452
|
/** Wrap the canvas + panel in a flex container according to placement. */
|
|
442
453
|
export declare function wrapWithSummaryPanel(content: HTMLElement, panel: HTMLDivElement, placement: 'right' | 'left' | 'top' | 'bottom'): HTMLDivElement;
|
|
443
454
|
/**
|
|
@@ -476,8 +487,10 @@ export declare function renderWaferSummaryContentSteps(panel: HTMLDivElement, pa
|
|
|
476
487
|
* when omitted, which is the only set a bare panel could know about.
|
|
477
488
|
*/
|
|
478
489
|
warnings?: WaferWarning[];
|
|
479
|
-
passBins
|
|
480
|
-
|
|
490
|
+
/** The map's own pass bins (`WaferMapResult.passBins`): every yield and bin verdict in the panel judges by them. */
|
|
491
|
+
passBins: number[];
|
|
492
|
+
/** The map's own ring count (`WaferMapResult.ringCount`). Required, never defaulted. */
|
|
493
|
+
ringCount: number;
|
|
481
494
|
/** The map's resolved bin colours (`View.binColors`), so bars match die fills. */
|
|
482
495
|
binColors?: BinColors;
|
|
483
496
|
/**
|
|
@@ -499,6 +512,8 @@ export declare function renderWaferSummaryContentSteps(panel: HTMLDivElement, pa
|
|
|
499
512
|
metadataFields?: MetadataFieldDef[];
|
|
500
513
|
/** See `RenderOptions.dieList` — gates the "View die list" link below. */
|
|
501
514
|
dieListOptions?: DieListDisplayOptions;
|
|
515
|
+
/** A die row clicked in the Data tables: show that die on its map. */
|
|
516
|
+
onLocateDie?: (die: Die, waferIndex: number | undefined) => void;
|
|
502
517
|
/**
|
|
503
518
|
* Suppress the "Wafer Info" metadata section because the caller already
|
|
504
519
|
* renders this metadata elsewhere — `renderWaferMap` passes true whenever its
|
|
@@ -530,9 +545,11 @@ type ReportItem = {
|
|
|
530
545
|
* @internal Gallery items as report maps — the one conversion for the gallery's
|
|
531
546
|
* and the lot panel's report buttons. A slot not yet loaded is skipped, but each
|
|
532
547
|
* wafer keeps the label its position gives it, so a report names wafers exactly
|
|
533
|
-
* as the cards do. `
|
|
548
|
+
* as the cards do. `ringCount` fills in only for an item built without one; `passBins` only from the caller's own option, never a default.
|
|
534
549
|
*/
|
|
535
|
-
export declare function reportMapsFromItems(items: ReadonlyArray<ReportItem | null | undefined>,
|
|
550
|
+
export declare function reportMapsFromItems(items: ReadonlyArray<ReportItem | null | undefined>, ringCount: number | undefined,
|
|
551
|
+
/** For an item built without pass bins, from the caller's own `passBins` option. Never a built-in default: an item with neither is refused. */
|
|
552
|
+
passBins?: readonly number[]): ReportMap[];
|
|
536
553
|
/**
|
|
537
554
|
* {@link renderLotSummaryContentSteps}, run straight through — the entry for a
|
|
538
555
|
* caller that is not staging the render across tasks.
|
|
@@ -575,6 +592,8 @@ export declare function renderLotSummaryContentSteps(panel: HTMLDivElement, para
|
|
|
575
592
|
warnings?: WaferWarning[];
|
|
576
593
|
/** See `RenderOptions.dieList` — gates the "View die list" link below. */
|
|
577
594
|
dieListOptions?: DieListDisplayOptions;
|
|
595
|
+
/** A die row clicked in the Data tables: show that die on its map. */
|
|
596
|
+
onLocateDie?: (die: Die, waferIndex: number | undefined) => void;
|
|
578
597
|
/** Per-wafer findings tally badged onto the Wafer Yield rows — see
|
|
579
598
|
* `buildPerWaferYieldSection`. */
|
|
580
599
|
findingsFor?: (waferIndex: number) => {
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
import{testValue as Be}from"../core/dieTable.js";import{waferDisplayLabel as ve}from"../core/waferLabel.js";import{commonPassBins as gt,itemPassBins as me,passBinsLabel as ht}from"../core/passBins.js";import{isParametricTest as bt}from"../renderer/buildWaferMap.js";import{testLabel as xt,markedTestLabel as yt,unmarkedLabel as Ct,derivedFields as we,derivedKeyText as vt,derivedCsvCell as Ee,isDerivedTest as Te,DERIVED_CSV_HEADER as De}from"../renderer/testLabel.js";import{buildRingRegions as wt,buildQuadrantRegions as St,buildRegionYieldData as Lt}from"../stats/regions.js";import{computeFunctionalYield as $t}from"../stats/analyzeWaferMap.js";import{buildSynthesis as Re,synthesisText as kt}from"../stats/synthesis.js";import{MEAN_WAFER_YIELD_LABEL as Bt,METER_DOTS as Ne,SEVERITY_MARK as Et,filledDots as Fe,impactWord as Tt,formatPoints as Dt,shortfallColor as Rt}from"../stats/presentation.js";import{regionYieldRows as Nt,waferYieldRows as Ft}from"../stats/yieldRows.js";import{formatFindingTooltip as Ae}from"../stats/findingText.js";import{arrangeFindings as At,filterFindings as Mt}from"../stats/filterFindings.js";import{buildFacetTable as Wt,prettyKey as Me}from"../stats/facets.js";import{commonMetadata as We}from"../stats/facets.js";import{resolveMetadataColumns as It}from"../stats/metadataColumns.js";import{resolveBinColors as Ie,resolveBinColorsByWafer as Pt}from"../renderer/binColors.js";import{NO_DATA_FILL as zt}from"../renderer/colorMap.js";import{classifySpec as Ht,isOutOfSpec as Yt}from"../renderer/spec.js";import{describeWaferPopulation as Pe,populationLabel as Ot}from"../stats/population.js";import{buildWarningsBanner as Se,collectWarnings as ze}from"./warnings.js";export{Se as buildWarningsBanner};import{fmt as He,fmtAggregationMethod as _t,plainBinTerms as ae}from"../renderer/fmt.js";import{getUniqueTestNumbers as jt}from"../renderer/buildView.js";import{describeValues as Vt}from"../stats/math.js";import{pooledTestStatsSteps as Kt}from"../stats/capability.js";import{binBreakdownRows as qt,binBreakdownTitle as Ye,binCountsFrom as Oe,totalOf as _e}from"../stats/binRows.js";import{poolFunctionalYield as Gt}from"../stats/testPassRate.js";import{makeLabeledSelect as je,makeSegmented as Le}from"./charts/chartShell.js";import{SHADOW as Ve,MOTION as Ke,LEADING as Q,TRACKING as le,wireControlHover as U,controlStyle as ge,SPACE as g,RADIUS as G,FONT as T,CLR as C,sevColor as de,openModal as qe,openReportModal as Ge,saveTextFile as Ue,wireTooltip as re}from"./toolbar.js";import{buildDieListSection as Ut}from"./dieList.js";export{csvField}from"../core/utils.js";import{csvField as he,drain as be,maxOf as Qt,minOf as Xt}from"../core/utils.js";import{metadataDisplayValue as Zt}from"../core/metadata.js";const Jt=C.panelBg,Qe=`1px solid ${C.menuBorder}`,en="12px",z=C.label,X=C.value,Xe="10px";function a(e,n,i,t=document){const o=t.createElement(e);return n&&Object.assign(o.style,n),i!==void 0&&(o.textContent=i),o}function pe(e){return a("div",{fontSize:Xe,fontWeight:"700",letterSpacing:le,textTransform:"uppercase",color:z,marginBottom:g.sm},e)}const Ze=new WeakMap,Je=["regionYield","testValues","functionalTests"];function xe(e){if(!e)return{collapsed:new Set(Je),regionMode:"ring",waferSort:"slot"};let n=Ze.get(e);return n||(n={collapsed:new Set(Je),regionMode:"ring",waferSort:"slot"},Ze.set(e,n)),n}function ne(e,n=!0,i,t){const o=a("div"),c=xe(t?.panel);t?.stateKey&&t.panel&&(n=!c.collapsed.has(t.stateKey));const s=document.createElement("button");s.type="button",Object.assign(s.style,{display:"flex",alignItems:"center",gap:g.xs,width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const h=a("span",{fontSize:T.meta,color:z,transition:`transform ${Ke.base}`,transform:n?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:Q.none,marginRight:"1px"},"\u25B6"),f=a("span",{fontSize:Xe,fontWeight:"700",letterSpacing:le,textTransform:"uppercase",color:z,flex:"1"},e);if(U(s,"bare"),s.setAttribute("aria-expanded",n?"true":"false"),s.appendChild(h),s.appendChild(f),i){const x=a("span",{fontSize:T.meta,fontWeight:"700",background:C.warnBg,color:C.warnText,borderRadius:G.pill,padding:"1px 5px"},i);s.appendChild(x)}const l=a("div");l.style.display=n?"block":"none";let p=n;if(s.addEventListener("click",()=>{p=!p,l.style.display=p?"block":"none",h.style.transform=p?"rotate(90deg)":"rotate(0deg)",s.setAttribute("aria-expanded",p?"true":"false"),t?.stateKey&&t.panel&&(p?c.collapsed.delete(t.stateKey):c.collapsed.add(t.stateKey))}),t?.control){const x=a("div",{display:"flex",alignItems:"center",gap:g.sm});s.style.width="auto",s.style.flex="1",x.appendChild(s);const r=()=>{l.innerHTML="",t.render?.(l)},m=t.control(r);m&&(m.style.marginBottom="6px",m.addEventListener("click",v=>v.stopPropagation()),x.appendChild(m)),o.appendChild(x)}else o.appendChild(s);return o.appendChild(l),t?.render?.(l),{outer:o,content:l}}function et(){return a("div",{height:"1px",background:C.separator,margin:`${en} 0`,flexShrink:"0"})}function $e(e,n,i=C.barFill,t,o,c){const s=a("div",{marginBottom:"5px"});c&&c.step>0&&Object.assign(s.style,{background:Rt(c.step),borderRadius:G.container,padding:"2px 4px",marginLeft:"-4px",marginRight:"-4px"});const h=a("div",{display:"flex",justifyContent:"space-between",fontSize:T.body,color:X,marginBottom:g.xxs}),f=a("span",{color:z},e),l=a("span",{fontWeight:"600",fontVariantNumeric:"tabular-nums"},`${n.toFixed(1)}%`);c&&(l.appendChild(a("span",{fontWeight:"400",marginLeft:g.sm,color:c.step>0?X:z},Dt(c.delta))),c.step>0&&(f.style.color=X)),h.appendChild(f),h.appendChild(l);const p=t!==void 0?t:Math.min(100,Math.max(0,n)),x=i,r=a("div",{position:"relative",height:"9px",background:C.bgActive,borderRadius:G.control,overflow:"hidden"}),m=a("div",{height:"100%",width:`${p}%`,background:x,borderRadius:G.control,transition:`width ${Ke.base}`});if(r.appendChild(m),o!==void 0){const v=a("div",{position:"absolute",top:"0",bottom:"0",left:`${o}%`,width:"2px",marginLeft:"-1px",background:C.value,opacity:"0.8"});r.appendChild(v)}return s.appendChild(h),s.appendChild(r),s}function tt(){const e=a("div",{display:"flex",gap:g.sm,marginBottom:g.md});return e.finish=()=>{const n=e.lastElementChild;n&&Object.assign(n.style,{borderRight:"none",paddingRight:"0"})},e}function ue(e,n,i){const t=a("div",{padding:`${g.xxs} ${g.md} ${g.xxs} 0`,borderRight:Qe,textAlign:"center",flex:"1"}),o=a("div",{fontSize:T.heading,fontWeight:"700",color:X,lineHeight:Q.tight},e),c=a("div",{fontSize:T.body,color:z,marginTop:g.xxs},n);return t.appendChild(o),t.appendChild(c),i&&t.appendChild(a("div",{fontSize:T.body,color:z,opacity:"0.85"},i)),t}function nt(e,n){const i=a("div",{display:"flex",justifyContent:"space-between",fontSize:T.body,gap:g.md,marginBottom:"3px"}),t=a("span",{color:z,flexShrink:"0"},e),o=a("span",{color:X,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},n);return i.appendChild(t),i.appendChild(o),i}function tn(e,n){const i=a("div",{display:"flex",fontSize:T.body,gap:g.sm,marginBottom:"3px"}),t=a("span",{color:z,flexShrink:"0"},`${e}:`),o=a("span",{color:X,fontWeight:"500",wordBreak:"break-all"},n);return i.appendChild(t),i.appendChild(o),i}export function metadataEntries(e){const n=[];for(const[i,t]of Object.entries(e)){const o=Zt(t);o!==void 0&&n.push([i,o])}return n}const nn=["lot","product","testprogram","split"],ye=e=>{const n=nn.indexOf(e.toLowerCase().replace(/[^a-z]/g,""));return n===-1?Number.MAX_SAFE_INTEGER:n};export function buildFacetSummaryChips(e,n=3){if(!e.length)return null;const i=a("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:`${g.xs} ${g.lg}`}),t=[...e].sort((h,f)=>ye(h.key)-ye(f.key)),o=t.filter(h=>ye(h.key)!==Number.MAX_SAFE_INTEGER),c=t.filter(h=>ye(h.key)===Number.MAX_SAFE_INTEGER),s=h=>{const f=a("span",{whiteSpace:"nowrap"}),l=a("span",{color:z},`${Me(h.key)}: `);f.appendChild(l);const p=h.values.slice(0,n),x=h.values.length-p.length;let r=p.map(m=>m.value).join(", ");return x>0&&(r+=` +${x} more`),f.appendChild(document.createTextNode(r)),f};for(const h of o)i.appendChild(s(h));if(c.length){const h=a("span",{display:"none",flexWrap:"wrap",alignItems:"baseline",gap:`${g.xs} ${g.lg}`});for(const p of c)h.appendChild(s(p));const f=a("button",{background:"none",border:"none",padding:"0",cursor:"pointer",color:C.iconActive,fontSize:T.body,whiteSpace:"nowrap"});f.type="button",U(f,"bare");const l=p=>{h.style.display=p?"contents":"none",f.textContent=p?"less":`+${c.length} more`,f.setAttribute("aria-expanded",String(p))};l(!1),f.addEventListener("click",()=>l(f.getAttribute("aria-expanded")!=="true")),i.appendChild(h),i.appendChild(f)}return i}export function buildMetadataStripRow(e,n,i){const t=Wt(e,i),o=buildFacetSummaryChips(t);if(!o&&!n)return null;const c=a("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px"});if(n){const s=a("span",{fontWeight:"500",whiteSpace:"nowrap"},n.aggrMethod?`${n.lotSize} wafers stacked \xB7 ${n.aggrMethod}`:`${n.lotSize} wafers stacked`);c.appendChild(s)}return o&&c.appendChild(o),c}const on={display:"flex",flexDirection:"column",gap:g.sm,background:C.menuBg,border:`1px solid ${C.menuBorder}`,borderRadius:G.container,padding:`${g.sm} ${g.lg}`,boxShadow:Ve.panel,fontSize:T.body,lineHeight:Q.none,boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(e,n,i){const t=buildMetadataStripRow(e,n,i);if(!t)return null;const o=a("div",on);return o.appendChild(t),o}export function buildCompactMetadataRows(e){const n=metadataEntries(e);if(!n.length)return null;const i=a("div");for(const[t,o]of n)i.appendChild(tn(Me(t),o));return i}export function buildMetadataInfoSection(e,n){const i=buildMetadataStripRow(e,n,{facetableOnly:e.length>1});if(!i)return null;const t=a("div");return t.appendChild(pe("Wafer Info")),t.appendChild(i),t}export function buildYieldSection(e,n,i=[1]){const t=a("div");t.appendChild(pe("Summary"));const o=tt();if(o.appendChild(ue(String(e.totalDies),"Total dies")),e.partialDies>0&&o.appendChild(ue(String(e.partialDies),"Partial")),e.yieldPercent!==null){const c=ht([i]);o.appendChild(ue(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${c}`))}return o.finish(),t.appendChild(o),e.edgeExcludedDies>0&&t.appendChild(nt("Edge excluded (outer zone)",String(e.edgeExcludedDies))),t}export function buildBinSection(e,n,i,t,o,c){const s=Oe(e,i,o);if(!s.size)return null;const h=t??Ie(e,{passBins:c,...i==="hard"?{hbinDefs:n}:{sbinDefs:n}}),f=a("div");f.appendChild(pe(Ye(i,_e(s))));for(const l of it(s,n,h[i],h.pass[i]))f.appendChild(l);return f}function it(e,n,i,t){return qt(e,n,t).map(o=>$e(`${o.label} (${o.count})`,o.percent,i.get(o.bin)??zt))}export function buildBinBreakdownSection(e){const{dies:n,hbinDefs:i,sbinDefs:t,hardCounts:o,softCounts:c,plotMode:s,passBins:h=[1],panel:f}=e,l=e.binColors??Ie(n,{passBins:h,hbinDefs:i,sbinDefs:t}),p=D=>Oe(n,D,D==="hard"?o:c),x=p("hard"),r=p("soft"),m=x.size>0,v=r.size>0;if(!m&&!v)return null;const L=xe(f),A=s==="softBin"||s==="stackedSoftBins"?"soft":s==="hardBin"||s==="stackedBins"?"hard":void 0;let u=L.binMode??A??(m?"hard":"soft");u==="hard"&&!m&&(u="soft"),u==="soft"&&!v&&(u="hard");const E=u==="hard"?x:r,W=u==="hard"?i:t,b=_e(E),{outer:S}=ne(Ye(u,b),!0,void 0,{stateKey:"bins",panel:f,render:D=>{const y=u==="hard"?l.hard:l.soft;for(const $ of it(E,W,y,l.pass[u]))D.appendChild($)},control:m&&v&&f?()=>Le([["hard","Hard"],["soft","Soft"]],u,D=>{L.binMode=D;const y=buildBinBreakdownSection(e);y&&S.replaceWith(y)},f.ownerDocument,!0):void 0});return S}export function buildLotBinSection(e,n,i,t){return buildBinSection(e,n,i,t)}export function buildRegionYieldPanelSection(e){const{diesByWafer:n,allWafers:i,ringCount:t,passBins:o,panel:c}=e,s=xe(c),h=p=>Lt(n,i,t,o,p==="ring"?wt:St);if(!h("ring").length&&!h("quadrant").length)return null;const f=s.regionMode,{outer:l}=ne(f==="ring"?"Ring Yield":"Quadrant Yield",!0,void 0,{stateKey:"regionYield",panel:c,render:p=>{const x=h(f);if(!x.length){p.appendChild(a("div",{fontSize:T.body,color:z},"No positioned dies for this breakdown."));return}for(const{label:r,n:m,yieldPercent:v,delta:L,step:A}of Nt(x).rows)p.appendChild($e(`${r} (N=${m})`,v,void 0,void 0,void 0,{delta:L,step:A}))},control:c?()=>Le([["ring","Ring"],["quadrant","Quadrant"]],f,p=>{s.regionMode=p;const x=buildRegionYieldPanelSection(e);x&&l.replaceWith(x)},c.ownerDocument,!0):void 0});return l}export function buildLotOverviewSection(e,n=[]){const i=a("div"),t=Pe(e.perWafer.map(s=>s.summary.wafer));i.appendChild(pe(t.lotId!==void 0?"Lot Summary":"Summary"));const o=tt();o.appendChild(ue(String(e.stats.waferCount),"Wafers"));const c=e.perWafer.map(s=>s.summary.stats.yieldPercent).filter(s=>s!==null);if(c.length){const s=c.reduce((h,f)=>h+f,0)/c.length;o.appendChild(ue(`${s.toFixed(1)}%`,Bt))}if(o.finish(),i.appendChild(o),n.length){const s=n.reduce((f,l)=>f+l.stats.analyzedDies,0),h=n.reduce((f,l)=>f+l.stats.excludedDies,0);(s||h)&&i.appendChild(nt("Dies analysed",h?`${s.toLocaleString()} (${h.toLocaleString()} excluded)`:s.toLocaleString()))}return i}export function buildPerWaferYieldSection(e,n,i,t,o){const c=e.perWafer.map(u=>({waferIndex:u.waferIndex,label:ve(n[u.waferIndex],u.waferIndex).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:u.summary.stats.yieldPercent})).filter(u=>u.yieldPct!==null);if(!c.length)return null;const s=Xt(c.map(u=>u.yieldPct)),h=Qt(c.map(u=>u.yieldPct)),f=s===h?"":` (${s.toFixed(1)}\u2013${h.toFixed(1)}%)`,{rows:l,median:p}=Ft(c.map(u=>({...u,yieldPercent:u.yieldPct}))),x=xe(t),r=u=>{const E=x.waferSort==="yield"?[...l].sort((W,b)=>W.yieldPct-b.yieldPct):l;for(const W of E){const{waferIndex:b,label:S,yieldPct:D,delta:y,step:$}=W,N=W.outlier?`${S} \xB7 ${W.outlier} outlier`:S,k=$e(N,D,void 0,void 0,p,{delta:y,step:$}),w=o?.(b);w?.total&&L(k,w),A(k,b,S,D,w),u.appendChild(k)}},m=` \xB7 median ${p.toFixed(1)}%`,{outer:v}=ne("Wafer Yield"+f+m,!0,void 0,{stateKey:"waferYield",panel:t,render:r,control:t?u=>Le([["slot","Slot"],["yield","Yield"]],x.waferSort,E=>{x.waferSort=E,u()},t.ownerDocument,!0):void 0});return v;function L(u,E){const W=E.unusual?"unusual":E.notable?"notable":"info",b=a("span",{marginLeft:g.sm,flexShrink:"0",background:de(W),color:"#fff",borderRadius:G.container,padding:"0 5px",fontSize:T.body,fontWeight:"600"},`${E.total}`);b.setAttribute("aria-hidden","true"),re(b,`${E.total} finding${E.total===1?"":"s"}`+(E.unusual?`, ${E.unusual} unusual`:"")+(E.notable?`, ${E.notable} notable`:"")),u.firstElementChild?.firstElementChild?.appendChild(b)}function A(u,E,W,b,S){i&&(u.style.cursor="pointer",u.style.borderRadius="4px",u.style.padding="2px 3px",u.style.marginLeft="-3px",u.style.marginRight="-3px",u.setAttribute("role","button"),u.setAttribute("aria-label",`${W}, ${b.toFixed(1)}% yield`+(S?.total?`, ${S.total} finding${S.total===1?"":"s"}${S.unusual?`, ${S.unusual} unusual`:""}`:"")+" \u2014 open wafer"),u.tabIndex=0,u.addEventListener("mouseenter",()=>{u.style.background=C.bgHover}),u.addEventListener("mouseleave",()=>{u.style.background=""}),u.addEventListener("focus",()=>{u.style.background=C.bgHover}),u.addEventListener("blur",()=>{u.style.background=""}),u.addEventListener("click",()=>i(E)),u.addEventListener("keydown",D=>{(D.key==="Enter"||D.key===" ")&&(D.preventDefault(),i(E))}))}}function sn(e){return Vt(Float64Array.from(e))}function ot(e,n){if(!e)return[];const i=e.waferMetadata??(e.perWaferMetadata?We(e.perWaferMetadata.map(t=>({metadata:t}))):void 0);return!i||!Object.keys(i).length?[]:It({waferMetadata:i,waferKeys:"identity",waferPlacement:"csv",reservedLabels:n}).columns}function st(e){return e?.populationLabel?[{key:"population",label:"Population",scope:"wafer",constant:e.populationLabel,get:()=>e.populationLabel,csvOnly:!0}]:[]}export function buildTestSection(...e){return be(buildTestSectionSteps(...e))}export function*buildTestSectionSteps(e,n,i,t,o,c,s,h,f="full"){const l=e.filter(d=>!d.partial&&!d.edgeExcluded),p=new Map((t?.perTestStats??[]).map(d=>[d.testNumber,d])),x=new Map((t?.testSpecYield??[]).map(d=>[d.testNumber,d]));let r;if(n?.length?r=n.filter(bt).map(d=>({testNumber:d.testNumber,name:d.name,unit:d.unit,limitLow:d.limitLow,limitHigh:d.limitHigh,limitLowInclusive:d.limitLowInclusive,limitHighInclusive:d.limitHighInclusive,...we(d)})):r=jt(l).map(P=>({testNumber:P,name:xt(void 0,P)})),!r.length)return null;const m=r.filter(d=>l.some(P=>{const _=Be(P,d.testNumber);return _!==void 0&&isFinite(_)}));if(!m.length)return null;const v=m.some(d=>d.limitLow!==void 0||d.limitHigh!==void 0),L=[],A=d=>!!d&&d.stddev!==void 0&&d.median!==void 0&&d.q1!==void 0&&d.q3!==void 0,u=d=>d.limitLow!==void 0||d.limitHigh!==void 0,E=!!(s?.length&&n?.length),b=(E||m.some(d=>!A(p.get(d.testNumber))||u(d)&&!x.has(d.testNumber)))&&n?.length?yield*Kt(s??[{dies:e}],n):void 0;for(const d of m){yield;const P=p.get(d.testNumber),_=b?.specTally.get(d.testNumber),K=b?.stats.get(d.testNumber),q=()=>l.map(M=>Be(M,d.testNumber)).filter(M=>M!==void 0&&isFinite(M));let J;if(A(P)){const M=P;J={testNumber:d.testNumber,min:M.min,max:M.max,mean:M.mean,count:M.count,stddev:M.stddev,median:M.median,q1:M.q1,q3:M.q3}}else if(K)J={testNumber:d.testNumber,...K};else{const M=q();if(!M.length)continue;J={testNumber:d.testNumber,...sn(M)}}let I=null,R=0;if(u(d)){const M=x.get(d.testNumber);if(M)({yieldPercent:I,totalDies:R}=M);else if(_)R=_.n,I=R>0?(R-_.fail)/R*100:null;else{const ee=q();let fe=0;for(const se of ee)Yt(Ht(se,d))&&fe++;R=ee.length,I=ee.length>0?(ee.length-fe)/ee.length*100:null}}L.push({entry:d,stats:J,specYieldPct:I,specN:R})}if(!L.length)return null;const S=new Map;for(const d of(E?b?.capability:void 0)??[])d.hasSpec&&S.set(d.testNumber,d.ppk);const D=S.size>0,$=new Set(L.map(d=>d.stats.count)).size===1?L[0].stats.count:null,N=a("div"),k=a("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:g.sm}),w=$!==null?` \xB7 N=${$.toLocaleString()}`:"",F=c?.populationLabel?`Test Values (${L.length}) \u2014 ${c.populationLabel}${w}`:`Test Values (${L.length})${w}`,j=pe(F);j.style.marginBottom="0",k.appendChild(j);const H=document.createElement("button");H.type="button",H.textContent="Test values CSV",Object.assign(H.style,{...ge("outlined")}),U(H),H.addEventListener("click",()=>{const d=["Test","Unit","N","Min","Q1","Median","Mean","Q3","Max","StdDev"];D&&d.push("Ppk");const P=L.some(R=>R.specYieldPct!==null&&R.specN!==R.stats.count);v&&(d.push("Lo limit","Hi limit","Limit Yield %"),P&&d.push("Limit Yield N"));const _=L.some(R=>Te(R.entry));_&&d.push(De);const K=[...ot(c,d),...st(c)],J=[[...K.map(R=>R.label),...d].map(he).join(",")],I=R=>He(R,void 0,"engineering");for(const{entry:R,stats:M,specYieldPct:ee,specN:fe}of L){const se=[...K.map(ce=>ce.constant??""),R.name,R.unit??"",String(M.count),I(M.min),I(M.q1),I(M.median),I(M.mean),I(M.q3),I(M.max),I(M.stddev)];if(D){const ce=S.get(R.testNumber);se.push(ce==null?"":ce.toFixed(3))}v&&(se.push(R.limitLow!==void 0?I(R.limitLow):"",R.limitHigh!==void 0?I(R.limitHigh):"",ee!==null?ee.toFixed(1):""),P&&se.push(R.limitLow!==void 0||R.limitHigh!==void 0?String(fe):"")),_&&se.push(Ee(R)),J.push(se.map(he).join(","))}Ue(J.join(`
|
|
2
|
-
`),"test-values.csv","text/csv",o)}),k.appendChild(H),N.appendChild(k);const Y=a("table",{width:"100%",borderCollapse:"collapse",fontSize:T.body}),te=document.createElement("thead"),ie=document.createElement("tr"),O=["Test"];$===null&&O.push("N"),f==="full"&&O.push("Min","Q1","Median"),O.push("Mean"),f==="full"&&O.push("Q3","Max","StdDev"),D&&O.push("Ppk"),f==="full"&&v&&O.push("Lo limit","Hi limit"),v&&O.push("Limit yield");for(const d of O){const P=a("th",{textAlign:d==="Test"?"left":"right",fontWeight:"600",fontSize:T.meta,letterSpacing:le,textTransform:"uppercase",color:z,padding:"3px 8px 5px",borderBottom:`1px solid ${C.menuBorder}`,whiteSpace:"nowrap"},d);ie.appendChild(P)}te.appendChild(ie),Y.appendChild(te);const Z=document.createElement("tbody");for(const{entry:d,stats:P,specYieldPct:_,specN:K}of L){const q=R=>He(R,d.unit,i),J=document.createElement("tr"),I=(R,M="right")=>{const ee=a("td",{textAlign:M,padding:`${g.xs} ${g.md}`,borderBottom:`1px solid ${C.menuBorder}`,color:C.text,whiteSpace:"nowrap"},R);J.appendChild(ee)};if(I(yt(d,d.testNumber),"left"),$===null&&I(`${P.count}`),f==="full"&&(I(q(P.min)),I(q(P.q1)),I(q(P.median))),I(q(P.mean)),f==="full"&&(I(q(P.q3)),I(q(P.max)),I(q(P.stddev))),D){const R=S.get(d.testNumber);I(R==null?"\u2014":R.toFixed(2))}f==="full"&&v&&(I(d.limitLow!==void 0?q(d.limitLow):"\u2014"),I(d.limitHigh!==void 0?q(d.limitHigh):"\u2014")),v&&I(_!==null?$!==null&&K===$?`${_.toFixed(1)}%`:`${_.toFixed(1)}% (N=${K})`:"\u2014"),Z.appendChild(J)}Y.appendChild(Z);const V=a("div",{overflowX:"auto"});V.appendChild(Y);const oe=dt(V,L.map(d=>({label:d.entry.name,...we(d.entry)})));if(!h)return N.appendChild(oe),N;k.remove();const{outer:B}=ne(F,!0,void 0,{stateKey:"testValues",panel:h,render:d=>d.appendChild(oe),control:()=>H});return B}export function buildFunctionalTestSection(e,n,i,t,o,c){const s=i??$t(e,n);if(!s?.length)return null;const f=new Set(s.map(y=>y.totalDies)).size===1?s[0].totalDies:null,l=f!==null?` \xB7 N=${f.toLocaleString()}`:"",p=a("div"),x=a("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:g.sm}),r=o?.populationLabel?`Functional Tests (${s.length}) \u2014 ${o.populationLabel}${l}`:`Functional Tests (${s.length})${l}`,m=pe(r);m.style.marginBottom="0",x.appendChild(m);const v=document.createElement("button");v.type="button",v.textContent="Functional CSV",Object.assign(v.style,{...ge("outlined")}),U(v),v.addEventListener("click",()=>{const y=["Test","N","Pass","Fail","Pass Rate %"],$=s.some(w=>Te(w));$&&y.push(De);const N=[...ot(o,y),...st(o)],k=[[...N.map(w=>w.label),...y].map(he).join(",")];for(const w of s)k.push([...N.map(F=>F.constant??""),Ct(w.label),String(w.totalDies),String(w.passDies),String(w.failDies),w.passRatePercent!==null?w.passRatePercent.toFixed(1):"",...$?[Ee(w)]:[]].map(he).join(","));Ue(k.join(`
|
|
3
|
-
`),"functional-tests.csv","text/csv",t)}),x.appendChild(v),p.appendChild(x);const L=a("table",{width:"100%",borderCollapse:"collapse",fontSize:T.body}),A=document.createElement("thead"),u=document.createElement("tr"),E=f===null?["Test","N","Pass","Fail","Pass rate"]:["Test","Pass","Fail","Pass rate"];for(const y of E)u.appendChild(a("th",{textAlign:y==="Test"?"left":"right",fontWeight:"700",fontSize:T.body,letterSpacing:le,textTransform:"uppercase",color:z,padding:"3px 8px 5px",borderBottom:`1px solid ${C.menuBorder}`,whiteSpace:"nowrap"},y));A.appendChild(u),L.appendChild(A);const W=document.createElement("tbody");for(const y of s){const $=document.createElement("tr"),N=(k,w="right")=>{$.appendChild(a("td",{textAlign:w,padding:`${g.xs} ${g.md}`,borderBottom:`1px solid ${C.menuBorder}`,color:X,whiteSpace:"nowrap"},k))};N(y.label,"left"),f===null&&N(String(y.totalDies)),N(String(y.passDies)),N(String(y.failDies)),N(y.passRatePercent!==null?`${y.passRatePercent.toFixed(1)}%`:"\u2014"),W.appendChild($)}L.appendChild(W);const b=a("div",{overflowX:"auto"});b.appendChild(L);const S=dt(b,s);if(!c)return p.appendChild(S),p;x.remove();const{outer:D}=ne(r,!0,void 0,{stateKey:"functionalTests",panel:c,render:y=>y.appendChild(S),control:()=>v});return D}export function buildLotFunctionalSection(e,n,i,t,o){const c=i?.length?{perWaferMetadata:i.map(h=>h.wafer??{}),populationLabel:`${i.length} wafer${i.length===1?"":"s"} pooled`}:void 0,s=Gt(i);return s?buildFunctionalTestSection(e,n,s,t,c,o):buildFunctionalTestSection(e,n,void 0,t,c,o)}function ke(e){const{tier:n,word:i}=Et[e],t=Fe(n),o=a("span",{flexShrink:"0",letterSpacing:"1px",lineHeight:Q.none,color:de(e)},"\u25CF".repeat(t)+"\u25CB".repeat(Ne-t));return o.setAttribute("role","img"),o.setAttribute("aria-label",i),re(o,i),o}function at(e,n){let i=e.summary;if(n){const t=[" has "," have "].find(o=>i.startsWith(`${n}${o}`));t?i=i.slice(n.length+t.length):i.startsWith(`${n} `)&&(i=i.slice(n.length+1))}return i=ae(i),i.length?i[0].toUpperCase()+i.slice(1):i}function rt(e){return lt(e.map(n=>({label:n.variable.label,...we(n.variable)})))}function lt(e){const n=vt(e);return n?a("div",{fontSize:T.body,color:z,marginTop:g.sm,lineHeight:Q.base},n):null}function dt(e,n){const i=lt(n);if(!i)return e;const t=a("div",{});return t.append(e,i),t}export function buildFindingsSection(e,n,i,t,o=!1,c){if(!e.length)return null;const s=e.some(b=>b.severity==="unusual"||b.severity==="notable"),h=s?e.filter(b=>b.severity!=="info").length.toString():void 0,{outer:f,content:l}=o?(()=>{const b=a("div");return{outer:b,content:b}})():ne(`Findings (${e.length})`,s,h);function p(b,S){const y={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[b]??b;return S.toLowerCase().startsWith(y.toLowerCase())?S:`${y}: ${S}`}const x=At(e),r=x.patterns.map(b=>b.finding),m=x.groups.map(b=>({...b,key:`${b.family}\0${b.left}`})),v=()=>[...m.flatMap(b=>b.findings),...r.flatMap(b=>e.filter(S=>b.relatedIds?.includes(S.id)))];function L(b,S=!1,D){const y=t===b.id,$=document.createElement("button");return $.type="button",$.dataset.wmapFinding=b.id,$.textContent=at(b,D),re($,Ae(b)),$.setAttribute("aria-current",y?"true":"false"),Object.assign($.style,{border:`1px solid ${C.menuBorder}`,borderLeft:`3px solid ${de(b.severity)}`,background:y?C.bgActive:C.menuBg,borderRadius:G.container,padding:S?"6px 10px":"8px 10px",textAlign:"left",fontSize:S?"10px":"11px",fontWeight:y?"600":"400",color:C.text,cursor:"pointer",width:"100%",marginBottom:g.xs}),U($,"bare"),$.addEventListener("click",()=>i(b,$)),$}const A=a("button",{flexShrink:"0",border:"none",background:"none",fontSize:T.body,color:C.icon,cursor:"pointer",padding:"0",lineHeight:Q.base,whiteSpace:"nowrap"},"Detail \u25B8");A.type="button",U(A,"bare"),A.addEventListener("click",()=>{const b=qe({title:"Findings Summary",onClose:()=>{},anchor:A}),S=Re(n,{passBins:c}),D=a("div",{fontSize:"16px",lineHeight:Q.base,color:C.text,padding:`${g.xxl} ${g.xxxl} ${g.xxl}`,margin:"0",borderBottom:`1px solid ${C.menuBorder}`,flexShrink:"0",display:"flex",flexDirection:"column",gap:g.md});for(const k of kt(S).split(`
|
|
4
|
-
`))D.appendChild(a("p",{margin:"0"},ae(k)));b.contentWrap.appendChild(D);const y=a("div",{overflowY:"auto",padding:`${g.xxl} ${g.xxxl}`,flex:"1"}),$=(k,w)=>{const F=a("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:T.sub,fontWeight:"600",color:X,marginTop:g.lg,marginBottom:g.xs});return F.appendChild(ke(k)),F.appendChild(a("span",{},w)),F};for(const k of r){y.appendChild($(k.severity,k.comparison.left)),y.appendChild(a("div",{fontSize:T.body,color:C.text,padding:"4px 0 4px 15px",marginBottom:g.xxs},ae(k.summary)));const w=e.filter(F=>k.relatedIds?.includes(F.id));for(const F of w)y.appendChild(a("div",{fontSize:T.body,color:z,padding:"2px 0 2px 23px",marginBottom:g.xxs},ae(F.summary)))}for(const k of m){const[w,F]=k.key.split("\0");y.appendChild($(k.worst,p(w,F)));for(const j of k.findings)y.appendChild(a("div",{fontSize:T.body,color:C.text,padding:"4px 0 4px 15px",marginBottom:g.xxs},at(j,F)))}const N=rt(v());N&&y.appendChild(N),b.contentWrap.appendChild(y),Object.assign(b.contentWrap.style,{flexDirection:"column",overflow:"hidden"})});const u=a("div",{display:"flex",justifyContent:"flex-end",marginBottom:g.xs});u.appendChild(A),l.appendChild(u);let E=!0;for(const b of r){E||l.appendChild(a("div",{height:"1px",background:C.separator,margin:"4px 0"})),E=!1;const S=e.filter(k=>b.relatedIds?.includes(k.id)),D=S.length>0,y=a("div",{position:"relative",marginBottom:D?"2px":"4px"}),$=t===b.id,N=document.createElement("button");if(N.type="button",N.dataset.wmapFinding=b.id,Object.assign(N.style,{border:`1px solid ${C.menuBorder}`,borderLeft:`3px solid ${de(b.severity)}`,background:$?C.bgActive:C.menuBg,borderRadius:G.container,padding:"8px 32px 8px 10px",textAlign:"left",fontSize:T.body,fontWeight:$?"600":"500",color:C.text,cursor:"pointer",width:"100%"}),N.textContent=ae(b.summary),re(N,b.summary),N.setAttribute("aria-current",$?"true":"false"),U(N,"bare"),N.addEventListener("click",()=>i(b,N)),y.appendChild(N),D){const k=a("div",{display:"none",paddingLeft:"12px",marginBottom:g.xs});for(const j of S)k.appendChild(L(j,!0));y.appendChild(k);let w=!1;const F=a("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:T.body,color:C.icon,cursor:"pointer",padding:`${g.xxs} ${g.xs}`,lineHeight:Q.none},"\u25B8");U(F,"bare"),F.type="button",re(F),F.setAttribute("aria-label","Show supporting findings"),F.setAttribute("aria-expanded","false"),F.addEventListener("click",j=>{j.stopPropagation(),w=!w,k.style.display=w?"block":"none",F.textContent=w?"\u25BE":"\u25B8";const H=w?"Hide supporting findings":"Show supporting findings";F.setAttribute("aria-label",H),F.setAttribute("aria-expanded",String(w))}),y.appendChild(F)}l.appendChild(y)}for(const b of m){E||l.appendChild(a("div",{height:"1px",background:C.separator,margin:"4px 0"})),E=!1;const[S,D]=b.key.split("\0"),y=a("div",{display:"flex",alignItems:"center",gap:g.sm,fontSize:T.body,fontWeight:"600",color:X,margin:"2px 0 4px"});y.appendChild(ke(b.worst)),y.appendChild(a("span",{},p(S,D))),l.appendChild(y);for(const $ of b.findings)l.appendChild(L($,!1,D))}const W=rt(v());return W&&l.appendChild(W),f}const an={high:"rgba(168, 65, 18, 0.10)",medium:"rgba(138, 101, 0, 0.10)",low:""},pt={high:"unusual",medium:"notable",low:"info"};function rn(e,n){const i=Fe(e),t=a("span",{display:"inline-flex",alignItems:"baseline",gap:g.xs,whiteSpace:"nowrap"}),o=a("span",{letterSpacing:"1px",color:de(pt[e])},"\u25CF".repeat(i)+"\u25CB".repeat(Ne-i));return o.setAttribute("aria-hidden","true"),t.appendChild(o),t.appendChild(a("span",{fontSize:T.meta,fontWeight:"600",letterSpacing:le,textTransform:"uppercase",color:X},n)),t}export function buildSynthesisSection(e,n,i,t,o,c){const s=Re(e,{passBins:n}),h=new Map(e.findings.map(r=>[r.id,r])),{outer:f,content:l}=ne("What stands out",!0,void 0,{stateKey:"synthesis",panel:o}),p=(r,m)=>{for(const v of m){const L=v.target?h.get(v.target.id):void 0,A=ae(v.text);if(!L||!i||!A){r.appendChild(document.createTextNode(A));continue}const u=document.createElement("button");u.type="button",u.textContent=A,u.dataset.wmapFinding=L.id,u.setAttribute("aria-current",t===L.id?"true":"false"),Object.assign(u.style,{border:"none",background:"none",padding:"0",margin:"0",font:"inherit",color:"inherit",textDecoration:"underline dotted",textUnderlineOffset:"2px",cursor:"pointer",textAlign:"inherit",fontWeight:t===L.id?"600":"inherit"}),re(u,Ae(L));const E=W=>{u.style.textDecoration=W?"underline solid":"underline dotted",u.style.color=W?C.iconActive:"inherit"};u.addEventListener("mouseenter",()=>E(!0)),u.addEventListener("mouseleave",()=>E(!1)),u.addEventListener("focus",()=>E(!0)),u.addEventListener("blur",()=>E(!1)),u.addEventListener("click",()=>i(L,u)),r.appendChild(u)}},x=(r,m)=>{const v=a("div",{fontSize:T.body,lineHeight:Q.base,color:C.text,...m});return p(v,r),v};l.appendChild(x(s.headline,{fontWeight:"600",marginBottom:g.sm})),s.nothing&&l.appendChild(a("div",{fontSize:T.body,lineHeight:Q.base,color:C.text,marginBottom:g.sm},s.nothing));for(const r of s.items){const m=a("div",{borderLeft:`3px solid ${de(pt[r.impact])}`,background:an[r.impact]||C.bgActive,borderRadius:`0 ${G.container} ${G.container} 0`,padding:`${g.sm} ${g.md}`,marginBottom:g.sm});m.appendChild(rn(r.impact,Tt(r.impact))),m.appendChild(x(r.parts,{marginTop:g.xxs})),l.appendChild(m)}s.also&&l.appendChild(x(s.also,{marginBottom:g.sm}));for(const r of s.watch??[]){const m=x(r.parts,{marginBottom:g.xs});m.insertBefore(a("span",{fontSize:T.meta,fontWeight:"600",letterSpacing:le,textTransform:"uppercase",color:z,marginRight:g.sm},"Watch"),m.firstChild),l.appendChild(m)}if(l.appendChild(a("div",{fontSize:T.body,lineHeight:Q.base,color:z},ae(s.checked))),c){const r=a("button",{border:"none",background:"none",padding:"0",marginTop:g.sm,fontSize:T.body,color:C.icon,cursor:"pointer",textDecoration:"underline",textUnderlineOffset:"2px"},"Full report \u25B8");r.type="button",U(r,"bare"),r.addEventListener("click",c),l.appendChild(r)}return f}const ln=[{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"}],dn=[{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"}],pn=["unusual","notable","info"],cn={unusual:"Unusual",notable:"Notable",info:"Minor"};function un(e,n,i){const t=a("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:g.lg,marginBottom:g.lg,paddingBottom:"10px",borderBottom:`1px solid ${C.separator}`}),o={unusual:0,notable:0,info:0};for(const l of e)o[l.severity]++;const c=pn.filter(l=>o[l]>0),s=new Set(n.severity===void 0?c:Array.isArray(n.severity)?n.severity:[n.severity]),h=a("div",{display:"flex",gap:g.xs,flexWrap:"wrap"});for(const l of c){const p=document.createElement("button");p.type="button";const x=()=>{const m=s.has(l);p.setAttribute("aria-pressed",m?"true":"false"),Object.assign(p.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${C.menuBorder}`,borderRadius:G.pill,background:m?C.bgActive:"none",opacity:m?"1":"0.5",color:C.text,fontSize:T.body,padding:`${g.xxs} ${g.md}`,cursor:"pointer"}),p.dataset.on=m?"true":"false"},r=ke(l);r.removeAttribute("role"),r.removeAttribute("aria-label"),r.setAttribute("aria-hidden","true"),p.appendChild(r),p.appendChild(a("span",{},`${cn[l]} ${o[l]}`)),re(p,()=>s.has(l)?"Click to hide these findings":"Click to show these findings"),x(),U(p,"bare"),p.addEventListener("click",()=>{s.has(l)?s.delete(l):s.add(l),n.severity=s.size===c.length?void 0:[...s],i()}),h.appendChild(p)}t.appendChild(h);const f=n.kind!==void 0||n.family!==void 0;return(e.length>=fn||f)&&(t.appendChild(je("Kind:",ln,n.kind??"",l=>{n.kind=l||void 0,i()},{maxWidth:"130px"})),t.appendChild(je("Region:",dn,n.family??"",l=>{n.family=l||void 0,i()},{maxWidth:"150px"}))),t}const fn=8;function mn(e,n){const i=a("div",{display:"flex",flexDirection:"column",gap:g.xs,padding:g.md,marginBottom:g.md,background:C.bgHover,borderRadius:G.control},void 0,n);if(i.appendChild(a("div",{fontSize:T.body,color:C.value},e.message,n)),e.detail&&i.appendChild(a("div",{fontSize:T.meta,color:z},e.detail,n)),e.actionLabel&&e.onAction){const t=a("button",ge("outlined"),e.actionLabel,n);t.type="button",t.style.alignSelf="flex-start",t.style.marginTop=g.xs,U(t),t.addEventListener("click",e.onAction),i.appendChild(t)}return i}export function buildFindingsSectionWithFilter(e,n,i,t,o,c,s,h){if(!e.findings.length&&!s)return null;const f=e.findings.some(L=>L.severity==="unusual"||L.severity==="notable"),l=f?e.findings.filter(L=>L.severity!=="info").length.toString():void 0,p=c?.ownerDocument??document,{outer:x,content:r}=ne(`Findings (${e.findings.length})`,f||!!s,l,{stateKey:"findings",panel:c});if(s&&r.appendChild(mn(s,p)),!e.findings.length)return x;r.appendChild(un(e.findings,t,o));const m=Mt(e,t);if(!m.length)return r.appendChild(a("div",{color:z,fontSize:T.body,textAlign:"center",padding:`${g.xxl} ${g.md}`},"No findings match the current filter.")),x;const v=buildFindingsSection(m,e,n,i,!0,h);return v&&r.appendChild(v),x}export function buildLotTestSection(...e){return be(buildLotTestSectionSteps(...e))}export function*buildLotTestSectionSteps(e,n,i,t,o,c,s,h="full"){const f=t?.length?{perWaferMetadata:t.map(p=>p.wafer??{}),populationLabel:`${t.length} wafer${t.length===1?"":"s"} pooled`}:void 0;let l;if(t?.length&&t.every(p=>p.stats.perTestStats!==void 0)){const p=new Map;for(const x of t)for(const r of x.stats.perTestStats??[]){const m=p.get(r.testNumber);m?(m.n+=r.count,m.sum+=r.mean*r.count,m.min=Math.min(m.min,r.min),m.max=Math.max(m.max,r.max)):p.set(r.testNumber,{n:r.count,sum:r.mean*r.count,min:r.min,max:r.max})}l={perTestStats:[...p.entries()].map(([x,r])=>({testNumber:x,count:r.n,min:r.min,max:r.max,mean:r.sum/r.n}))}}if(t?.length&&t.every(p=>p.stats.testSpecYield!==void 0)){const p=new Map;for(const x of t)for(const r of x.stats.testSpecYield??[]){const m=p.get(r.testNumber);m?(m.passDies+=r.passDies,m.totalDies+=r.totalDies):p.set(r.testNumber,{passDies:r.passDies,totalDies:r.totalDies})}l={...l,testSpecYield:[...p.entries()].map(([x,r])=>({testNumber:x,totalDies:r.totalDies,yieldPercent:r.totalDies>0?r.passDies/r.totalDies*100:null}))}}return yield*buildTestSectionSteps(e,n,i,l,o,f,c,s,h)}export function createSummaryPanelEl(e,n,i=document){const t=e==="top"||e==="bottom",o=a("div",{background:Jt,color:C.text,fontVariantNumeric:"tabular-nums",border:Qe,borderRadius:G.container,padding:g.xl,overflowY:"auto",overflowX:t?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:T.family,fontSize:T.sub,boxShadow:Ve.panel},void 0,i);return e==="right"&&(o.style.marginRight=n),e==="left"&&(o.style.marginLeft=n),e==="bottom"&&(o.style.marginBottom=n),t?(o.style.height="180px",o.style.width="100%"):(o.style.width="300px",o.style.maxHeight="100%"),o}export function wrapWithSummaryPanel(e,n,i){const t=i==="top"||i==="bottom",o=a("div",{display:"flex",flexDirection:t?"column":"row",gap:g.md,width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:t?"flex-start":"stretch"});return e.style.flex="1 1 0",e.style.minWidth="0",e.style.minHeight="0",i==="right"||i==="bottom"?(o.appendChild(e),o.appendChild(n)):(o.appendChild(n),o.appendChild(e)),o}function ct(e,n,i,t,o){const c=n.find(h=>h.id===i);if(!c||!o)return;t.close();const s=[...e.querySelectorAll("button[data-wmap-finding]")].find(h=>h.dataset.wmapFinding===i)??e.ownerDocument.createElement("button");o(c,s)}function ut(e){return a("div",{fontSize:T.heading,fontWeight:"600",color:X,marginBottom:g.lg},e)}function Ce(e,n){const i=a("button",ge("outlined"),e);return i.type="button",U(i),i.addEventListener("click",n),i}function ft(...e){const n=e.filter(t=>!!t);if(!n.length)return null;const i=a("div",{display:"flex",flexWrap:"wrap",gap:g.sm,marginBottom:g.lg});for(const t of n)i.appendChild(t);return i}function mt(e,n,i,t,o,c,s,h,f,l,p){const x=e.ownerDocument,r=qe({title:"Die list",onClose:()=>{},anchor:e,ownerDocument:x});r.contentWrap.style.padding="14px 16px";const m=Ut(n,i,{...s,title:t,onSaveText:h,waferMetadata:o,metadataFields:c,extraColumn:f,getWafer:l,ringCount:p,ownerDocument:x});m&&r.contentWrap.appendChild(m)}export function renderWaferSummaryContent(...e){be(renderWaferSummaryContentSteps(...e))}export function*renderWaferSummaryContentSteps(e,n){const i=e.scrollTop;e.innerHTML="";const{wafer:t,dies:o,yieldSummary:c,dataCoverage:s,hbinDefs:h,sbinDefs:f,testDefs:l,statsSummary:p,passBins:x=[1],ringCount:r=4,binColors:m,plotMode:v,fallbackFormat:L,onFindingClick:A,activeFindingId:u=null,findingsFilter:E,onFindingsFilterChange:W,findingsNotice:b,onSaveText:S,metadataFields:D,dieListOptions:y,metadataShownElsewhere:$}=n;e.appendChild(ut("Wafer Summary"));const N=n.warnings??ze({statsSummary:p});N.length&&e.appendChild(Se(N,e.ownerDocument));const k=c&&s?()=>{import("../stats/renderSummaryReport.js").then(({renderWaferReportHtml:Z})=>{Ge(Z({wafer:t,dies:o,yield:c,dataCoverage:s,hbinDefs:h,sbinDefs:f,testDefs:l,passBins:x,ringCount:r},p,{binColors:m,live:!!A}),{anchor:e,onFinding:(V,oe)=>ct(e,p?.findings??[],V,oe,A)})})}:null,w=k?Ce("Summary report",k):null,F=(y?.enabled??!0)&&o.length?Ce("View die list",()=>{mt(e,o,l,`Die list \u2014 ${o.length} dies`,t.metadata,D,y,S,void 0,()=>t,r)}):null,j=ft(w,F);j&&e.appendChild(j);let H=!0;const Y=Z=>{Z&&(H||e.appendChild(et()),H=!1,e.appendChild(Z))},te=p?.stats.isLotStack?p.stats:void 0,ie=te?.lotSize!==void 0?{lotSize:te.lotSize,aggrMethod:_t(te.aggregationMethod)}:void 0;$||Y(buildMetadataInfoSection([{metadata:t.metadata??void 0}],ie)),c&&s&&Y(buildYieldSection(c,s,x)),yield,p&&(Y(buildSynthesisSection(p,x,A,u,e,k??void 0)),yield),p&&A&&E&&W&&(Y(buildFindingsSectionWithFilter(p,A,u,E,W,e,b,x)),yield),Y(buildBinBreakdownSection({dies:o,hbinDefs:h,sbinDefs:f,binColors:m,hardCounts:p?.stats.hardBinCounts,softCounts:p?.stats.softBinCounts,plotMode:v,passBins:x,panel:e})),yield,Y(buildRegionYieldPanelSection({diesByWafer:[o],allWafers:[t],ringCount:r,passBins:x,panel:e})),yield;const O=t.metadata?{waferMetadata:t.metadata}:void 0;Y(yield*buildTestSectionSteps(o,l,L,p?.stats,S,O,[{dies:o}],e,"compact")),yield,Y(buildFunctionalTestSection(o,l,p?.stats.functionalYield,S,O,e)),e.appendChild(a("div",{height:"12px",flexShrink:"0"})),e.scrollTop=i}export function reportMapsFromItems(e,n,i){const t=[];return e.forEach((o,c)=>{!o?.wafer||!o.dies||t.push({...o,wafer:o.wafer,dies:o.dies,label:ve(o,c),passBins:[...me(o,n)],ringCount:o.ringCount??i})}),t}export function renderLotSummaryContent(...e){be(renderLotSummaryContentSteps(...e))}export function*renderLotSummaryContentSteps(e,n){const i=e.scrollTop;e.innerHTML="";const{lotSummary:t,items:o,hbinDefs:c,sbinDefs:s,testDefs:h,passBins:f=[1],ringCount:l=4,binColors:p,plotMode:x,fallbackFormat:r,onFindingClick:m,activeFindingId:v=null,onWaferClick:L,findingsFilter:A,onFindingsFilterChange:u,findingsNotice:E,onSaveText:W,dieListOptions:b,findingsFor:S}=n;e.appendChild(ut(`Summary \u2014 ${Ot(Pe(t.perWafer.map(B=>B.summary.wafer)))}`));const D=n.warnings??ze({lotStatsSummary:t});D.length&&e.appendChild(Se(D,e.ownerDocument));const y=()=>{import("../stats/renderSummaryReport.js").then(({renderLotReportHtml:B})=>{Ge(B(reportMapsFromItems(o,f,l),{binColors:p,live:!!m}),{anchor:e,onFinding:(d,P)=>ct(e,t.findings,d,P,m)})})},$=Ce("Summary report",y),N=[],k=[],w=[],F=[],j=[],H=new WeakMap,Y=new WeakMap;for(let B=0;B<o.length;B++){yield;const d=o[B];if(!d){k.push([]);continue}d.wafer&&(N.push(d.wafer),F.push(d.dies??[]),j.push(me(d,f)));const P=d.dies??[],_=ve(d,B);for(const K of P)H.set(K,_),d.wafer&&Y.set(K,d.wafer);k.push(P);for(const K of P)w.push(K)}const te=b?.enabled??!0?Ce("View die list",()=>{w.length&&mt(e,w,h,`Die list \u2014 ${w.length} dies across ${o.length} wafer${o.length===1?"":"s"}`,We(o.filter(B=>!!B).map(B=>({metadata:B.wafer?.metadata}))),o.find(B=>B?.metadataFields?.length)?.metadataFields,b,W,{label:"Wafer",get:B=>H.get(B)},B=>Y.get(B),l)}):null,ie=ft($,te);ie&&e.appendChild(ie);const O=o.map(B=>B?.statsSummary).filter(B=>!!B);let Z=!0;const V=B=>{B&&(Z||e.appendChild(et()),Z=!1,e.appendChild(B))};V(buildLotOverviewSection(t,O)),yield;const oe=gt(o.map(B=>B?me(B,f):void 0).filter(B=>B!==void 0));V(buildSynthesisSection(t,oe,m,v,e,y)),yield,m&&A&&u&&(V(buildFindingsSectionWithFilter(t,m,v,A,u,e,E,oe)),yield),V(buildPerWaferYieldSection(t,o,L,e,S)),yield,V(buildBinBreakdownSection({dies:w,hbinDefs:c,sbinDefs:s,plotMode:x,passBins:f,panel:e,binColors:p??Pt(o.flatMap(B=>B?[{dies:B.dies??[],passBins:me(B,f)}]:[]),{hbinDefs:c,sbinDefs:s}).colors})),yield,V(buildRegionYieldPanelSection({diesByWafer:F,allWafers:N,ringCount:l,passBins:B=>j[B],panel:e})),yield,h?.length&&(V(yield*buildLotTestSectionSteps(w,h,r,O,W,k.map(B=>({dies:B})),e,"compact")),yield,V(buildLotFunctionalSection(w,h,O,W,e))),e.appendChild(a("div",{height:"12px",flexShrink:"0"})),e.scrollTop=i}
|
|
1
|
+
import{testValue as Be}from"../core/dieTable.js";import{waferDisplayLabel as fe}from"../core/waferLabel.js";import{itemRingCount as $e}from"../core/ringCount.js";import{commonPassBins as ht,itemPassBins as pe,passBinsLabel as gt,requirePassBins as ke}from"../core/passBins.js";import{isParametricTest as bt}from"../renderer/buildWaferMap.js";import{testLabel as xt,markedTestLabel as yt,unmarkedLabel as Ct,derivedFields as xe,derivedKeyText as vt,derivedCsvCell as Ee,isDerivedTest as Re,DERIVED_CSV_HEADER as Te}from"../renderer/testLabel.js";import{buildRingRegions as wt,buildQuadrantRegions as St,buildRegionYieldData as Lt}from"../stats/regions.js";import{computeFunctionalYield as Bt}from"../stats/analyzeWaferMap.js";import{buildSynthesis as De,synthesisText as $t,synthesisRowShare as kt,SYNTHESIS_SMALLER_HEADING as Et}from"../stats/synthesis.js";import{MEAN_WAFER_YIELD_LABEL as Rt,METER_DOTS as Fe,SEVERITY_MARK as Tt,filledDots as Ne,impactWord as Dt,impactShortWord as Ft,formatPoints as Nt,shortfallColor as At}from"../stats/presentation.js";import{regionYieldRows as Wt,waferYieldRows as It}from"../stats/yieldRows.js";import{formatFindingTooltip as Ae}from"../stats/findingText.js";import{arrangeFindings as Mt,filterFindings as Pt}from"../stats/filterFindings.js";import{buildFacetTable as zt,prettyKey as We}from"../stats/facets.js";import{commonMetadata as Ot}from"../stats/facets.js";import{resolveMetadataColumns as Ht}from"../stats/metadataColumns.js";import{resolveBinColors as Ie,resolveBinColorsByWafer as Yt}from"../renderer/binColors.js";import{NO_DATA_FILL as _t}from"../renderer/colorMap.js";import{classifySpec as Vt,isOutOfSpec as Kt}from"../renderer/spec.js";import{describeWaferPopulation as Me,populationLabel as jt}from"../stats/population.js";import{buildWarningsBanner as ye,collectWarnings as Pe}from"./warnings.js";export{ye as buildWarningsBanner};import{fmt as qt,fmtAggregationMethod as Gt,plainBinTerms as oe}from"../renderer/fmt.js";import{getUniqueTestNumbers as Ut}from"../renderer/buildView.js";import{describeValues as Qt}from"../stats/math.js";import{pooledTestStatsSteps as Xt}from"../stats/capability.js";import{binBreakdownRows as Zt,binBreakdownTitle as ze,binCountsFrom as Oe,totalOf as He}from"../stats/binRows.js";import{poolFunctionalYield as Jt}from"../stats/testPassRate.js";import{makeLabeledSelect as Ye,makeSegmented as Ce}from"./charts/chartShell.js";import{SHADOW as _e,MOTION as Ve,LEADING as G,TRACKING as re,wireControlHover as U,controlStyle as me,SPACE as g,RADIUS as q,FONT as D,CLR as k,sevColor as le,openModal as Ke,wireTooltip as ae}from"./toolbar.js";import{openReportModal as je}from"./guideWindow.js";import{exportCsv as qe}from"./tableExport.js";export{csvField}from"../core/utils.js";import{drain as he,maxOf as en,minOf as tn}from"../core/utils.js";import{metadataDisplayValue as nn}from"../core/metadata.js";const on=k.panelBg,Ge=`1px solid ${k.menuBorder}`,an="12px",M=k.label,X=k.value,Ue="10px";function r(e,n,i,t=document){const o=t.createElement(e);return n&&Object.assign(o.style,n),i!==void 0&&(o.textContent=i),o}function de(e){return r("div",{fontSize:Ue,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:M,marginBottom:g.sm},e)}const Qe=new WeakMap,Xe=["regionYield","testValues","functionalTests"];function ge(e){if(!e)return{collapsed:new Set(Xe),regionMode:"ring",waferSort:"slot"};let n=Qe.get(e);return n||(n={collapsed:new Set(Xe),regionMode:"ring",waferSort:"slot"},Qe.set(e,n)),n}function ee(e,n=!0,i,t){const o=r("div"),d=ge(t?.panel);t?.stateKey&&t.panel&&(n=!d.collapsed.has(t.stateKey));const a=document.createElement("button");a.type="button",Object.assign(a.style,{display:"flex",alignItems:"center",gap:g.xs,width:"100%",background:"none",border:"none",cursor:"pointer",padding:"0 0 6px",textAlign:"left"});const b=r("span",{fontSize:D.meta,color:M,transition:`transform ${Ve.base}`,transform:n?"rotate(90deg)":"rotate(0deg)",display:"inline-block",lineHeight:G.none,marginRight:"1px"},"\u25B6"),h=r("span",{fontSize:Ue,fontWeight:"700",letterSpacing:re,textTransform:"uppercase",color:M,flex:"1"},e);if(U(a,"bare"),a.setAttribute("aria-expanded",n?"true":"false"),a.appendChild(b),a.appendChild(h),i){const y=r("span",{fontSize:D.meta,fontWeight:"700",background:k.warnBg,color:k.warnText,borderRadius:q.pill,padding:"1px 5px"},i);a.appendChild(y)}const p=r("div");p.style.display=n?"block":"none";let c=n;if(a.addEventListener("click",()=>{c=!c,p.style.display=c?"block":"none",b.style.transform=c?"rotate(90deg)":"rotate(0deg)",a.setAttribute("aria-expanded",c?"true":"false"),t?.stateKey&&t.panel&&(c?d.collapsed.delete(t.stateKey):d.collapsed.add(t.stateKey))}),t?.control){const y=r("div",{display:"flex",alignItems:"center",gap:g.sm});a.style.width="auto",a.style.flex="1",y.appendChild(a);const u=()=>{p.innerHTML="",t.render?.(p)},f=t.control(u);f&&(f.style.marginBottom="6px",f.addEventListener("click",v=>v.stopPropagation()),y.appendChild(f)),o.appendChild(y)}else o.appendChild(a);return o.appendChild(p),t?.render?.(p),{outer:o,content:p}}function Ze(){return r("div",{height:"1px",background:k.separator,margin:`${an} 0`,flexShrink:"0"})}function ve(e,n,i=k.barFill,t,o,d){const a=r("div",{marginBottom:"5px"});d&&d.step>0&&Object.assign(a.style,{background:At(d.step),borderRadius:q.container,padding:"2px 4px",marginLeft:"-4px",marginRight:"-4px"});const b=r("div",{display:"flex",justifyContent:"space-between",fontSize:D.body,color:X,marginBottom:g.xxs}),h=r("span",{color:M},e),p=r("span",{fontWeight:"600",fontVariantNumeric:"tabular-nums"},`${n.toFixed(1)}%`);d&&(p.appendChild(r("span",{fontWeight:"400",marginLeft:g.sm,color:d.step>0?X:M},Nt(d.delta))),d.step>0&&(h.style.color=X)),b.appendChild(h),b.appendChild(p);const c=t!==void 0?t:Math.min(100,Math.max(0,n)),y=i,u=r("div",{position:"relative",height:"9px",background:k.bgActive,borderRadius:q.control,overflow:"hidden"}),f=r("div",{height:"100%",width:`${c}%`,background:y,borderRadius:q.control,transition:`width ${Ve.base}`});if(u.appendChild(f),o!==void 0){const v=r("div",{position:"absolute",top:"0",bottom:"0",left:`${o}%`,width:"2px",marginLeft:"-1px",background:k.value,opacity:"0.8"});u.appendChild(v)}return a.appendChild(b),a.appendChild(u),a}function Je(){const e=r("div",{display:"flex",gap:g.sm,marginBottom:g.md});return e.finish=()=>{const n=e.lastElementChild;n&&Object.assign(n.style,{borderRight:"none",paddingRight:"0"})},e}function ce(e,n,i){const t=r("div",{padding:`${g.xxs} ${g.md} ${g.xxs} 0`,borderRight:Ge,textAlign:"center",flex:"1"}),o=r("div",{fontSize:D.heading,fontWeight:"700",color:X,lineHeight:G.tight},e),d=r("div",{fontSize:D.body,color:M,marginTop:g.xxs},n);return t.appendChild(o),t.appendChild(d),i&&t.appendChild(r("div",{fontSize:D.body,color:M,opacity:"0.85"},i)),t}function et(e,n){const i=r("div",{display:"flex",justifyContent:"space-between",fontSize:D.body,gap:g.md,marginBottom:"3px"}),t=r("span",{color:M,flexShrink:"0"},e),o=r("span",{color:X,textAlign:"right",fontWeight:"500",wordBreak:"break-all"},n);return i.appendChild(t),i.appendChild(o),i}function sn(e,n){const i=r("div",{display:"flex",fontSize:D.body,gap:g.sm,marginBottom:"3px"}),t=r("span",{color:M,flexShrink:"0"},`${e}:`),o=r("span",{color:X,fontWeight:"500",wordBreak:"break-all"},n);return i.appendChild(t),i.appendChild(o),i}export function metadataEntries(e){const n=[];for(const[i,t]of Object.entries(e)){const o=nn(t);o!==void 0&&n.push([i,o])}return n}const rn=["lot","product","testprogram","split"],we=e=>{const n=rn.indexOf(e.toLowerCase().replace(/[^a-z]/g,""));return n===-1?Number.MAX_SAFE_INTEGER:n},ln=new WeakMap,dn=12;export function buildFacetSummaryChips(e,n=3){if(!e.length)return null;const i=g.lg,t=r("div",{display:"flex",flexWrap:"nowrap",alignItems:"baseline",gap:`${g.xs} ${i}`,flex:"1 1 0%",minWidth:"0",overflow:"hidden",position:"relative"}),o=[...e].sort((f,v)=>we(f.key)-we(v.key)),d=(f,v)=>`${We(f.key)}${v<f.values.length?` (${f.values.length})`:""}: `,a=(f,v)=>f.values.slice(0,v).map(x=>x.value).join(", ")+(v<f.values.length?", \u2026":""),b=o.map(f=>{const v=r("span",{whiteSpace:"nowrap",minWidth:"0"}),x=r("span",{color:M}),L=document.createTextNode("");return v.append(x,L),{field:f,chip:v,setValues:S=>{x.textContent=d(f,S),L.data=a(f,S)},max:Math.min(f.values.length,dn)}});for(const f of b)t.appendChild(f.chip);const h=r("button",{background:"none",border:"none",padding:"0",cursor:"pointer",color:k.iconActive,fontSize:D.body,whiteSpace:"nowrap",flexShrink:"0"});h.type="button",U(h,"bare"),t.appendChild(h);const p=r("span",{position:"absolute",visibility:"hidden",whiteSpace:"nowrap",pointerEvents:"none",left:"0",top:"0"});t.appendChild(p);const c=f=>(p.textContent=f,p.getBoundingClientRect().width);let y=!1;function u(){const f=t.clientWidth;if(h.setAttribute("aria-expanded",String(y)),y){Object.assign(t.style,{flexWrap:"wrap",overflow:"visible"});for(const L of b)L.setValues(L.max),L.chip.style.display="";h.textContent="fewer fields",h.style.display="";return}Object.assign(t.style,{flexWrap:"nowrap",overflow:"hidden"});let v=0;if(f){const L=parseFloat(getComputedStyle(t).columnGap)||0;h.textContent=`${b.length} more fields`;const m=h.getBoundingClientRect().width+L;let S=0,N=!1;b.forEach((l,$)=>{if(N){l.chip.style.display="none";return}const R=v>0?L:0,T=$<b.length-1?m:0,w=f-S-R-T;let F=l.max;for(;F>1&&c(d(l.field,F)+a(l.field,F))>w;)F--;const C=c(d(l.field,F)+a(l.field,F));if(C>w&&v>0){N=!0,l.chip.style.display="none";return}l.setValues(F),l.chip.style.display="",v===0&&Object.assign(l.chip.style,{overflow:"hidden",textOverflow:"ellipsis"}),S+=R+C,v++})}else for(const L of b){const m=we(L.field.key)!==Number.MAX_SAFE_INTEGER;L.chip.style.display=m?"":"none",m&&(L.setValues(Math.min(L.field.values.length,n)),v++)}const x=b.length-v;h.textContent=`${x} more field${x===1?"":"s"}`,h.style.display=x>0?"":"none"}if(h.addEventListener("click",()=>{y=!y,u()}),u(),typeof ResizeObserver<"u"){const f=new ResizeObserver(()=>u());f.observe(t),ln.set(t,f)}return t}export function buildMetadataStripRow(e,n,i){const t=zt(e,i),o=buildFacetSummaryChips(t);if(!o&&!n)return null;const d=r("div",{display:"flex",flexWrap:"wrap",alignItems:"baseline",gap:"4px 14px",width:"100%",minWidth:"0"});if(n){const a=r("span",{fontWeight:"500",whiteSpace:"nowrap"},n.aggrMethod?`${n.lotSize} wafers stacked \xB7 ${n.aggrMethod}`:`${n.lotSize} wafers stacked`);d.appendChild(a)}return o&&d.appendChild(o),d}const pn={display:"flex",flexDirection:"column",gap:g.sm,background:k.menuBg,border:`1px solid ${k.menuBorder}`,borderRadius:q.container,padding:`${g.sm} ${g.lg}`,boxShadow:_e.panel,fontSize:D.body,lineHeight:G.none,boxSizing:"border-box",width:"100%",minWidth:"0"};export function buildMetadataStripBox(e,n,i){const t=buildMetadataStripRow(e,n,i);if(!t)return null;const o=r("div",pn);return o.appendChild(t),o}export function buildCompactMetadataRows(e){const n=metadataEntries(e);if(!n.length)return null;const i=r("div");for(const[t,o]of n)i.appendChild(sn(We(t),o));return i}export function buildMetadataInfoSection(e,n){const i=buildMetadataStripRow(e,n,{facetableOnly:e.length>1});if(!i)return null;const t=r("div");return t.appendChild(de("Wafer Info")),t.appendChild(i),t}export function buildYieldSection(e,n,i){const t=r("div");t.appendChild(de("Summary"));const o=Je();if(o.appendChild(ce(String(e.totalDies),"Total dies")),e.partialDies>0&&o.appendChild(ce(String(e.partialDies),"Partial")),e.yieldPercent!==null){const d=gt([i]);o.appendChild(ce(`${e.yieldPercent.toFixed(1)}%`,"Yield",`pass: ${d}`))}return o.finish(),t.appendChild(o),e.edgeExcludedDies>0&&t.appendChild(et("Edge excluded (outer zone)",String(e.edgeExcludedDies))),t}export function buildBinSection(e,n,i,t,o,d){const a=Oe(e,i,o);if(!a.size)return null;const b=t??Ie(e,{passBins:ke({passBins:d},"buildBinSection"),...i==="hard"?{hbinDefs:n}:{sbinDefs:n}}),h=r("div");h.appendChild(de(ze(i,He(a))));for(const p of tt(a,n,b[i],b.pass[i]))h.appendChild(p);return h}function tt(e,n,i,t){return Zt(e,n,t).map(o=>ve(`${o.label} (${o.count})`,o.percent,i.get(o.bin)??_t))}export function buildBinBreakdownSection(e){const{dies:n,hbinDefs:i,sbinDefs:t,hardCounts:o,softCounts:d,plotMode:a,passBins:b,panel:h}=e,p=e.binColors??Ie(n,{passBins:ke({passBins:b},"buildBinBreakdownSection"),hbinDefs:i,sbinDefs:t}),c=R=>Oe(n,R,R==="hard"?o:d),y=c("hard"),u=c("soft"),f=y.size>0,v=u.size>0;if(!f&&!v)return null;const x=ge(h),L=a==="softBin"||a==="stackedSoftBins"?"soft":a==="hardBin"||a==="stackedBins"?"hard":void 0;let m=x.binMode??L??(f?"hard":"soft");m==="hard"&&!f&&(m="soft"),m==="soft"&&!v&&(m="hard");const S=m==="hard"?y:u,N=m==="hard"?i:t,l=He(S),{outer:$}=ee(ze(m,l),!0,void 0,{stateKey:"bins",panel:h,render:R=>{const T=m==="hard"?p.hard:p.soft;for(const w of tt(S,N,T,p.pass[m]))R.appendChild(w)},control:f&&v&&h?()=>Ce([["hard","Hard"],["soft","Soft"]],m,R=>{x.binMode=R;const T=buildBinBreakdownSection(e);T&&$.replaceWith(T)},h.ownerDocument,!0):void 0});return $}export function buildLotBinSection(e,n,i,t){return buildBinSection(e,n,i,t)}export function buildRegionYieldPanelSection(e){const{diesByWafer:n,allWafers:i,ringCount:t,passBins:o,panel:d}=e,a=ge(d),b=c=>Lt(n,i,t,o,c==="ring"?wt:St);if(!b("ring").length&&!b("quadrant").length)return null;const h=a.regionMode,{outer:p}=ee(h==="ring"?"Ring Yield":"Quadrant Yield",!0,void 0,{stateKey:"regionYield",panel:d,render:c=>{const y=b(h);if(!y.length){c.appendChild(r("div",{fontSize:D.body,color:M},"No positioned dies for this breakdown."));return}for(const{label:u,n:f,yieldPercent:v,delta:x,step:L}of Wt(y).rows)c.appendChild(ve(`${u} (N=${f})`,v,void 0,void 0,void 0,{delta:x,step:L}))},control:d?()=>Ce([["ring","Ring"],["quadrant","Quadrant"]],h,c=>{a.regionMode=c;const y=buildRegionYieldPanelSection(e);y&&p.replaceWith(y)},d.ownerDocument,!0):void 0});return p}export function buildLotOverviewSection(e,n=[]){const i=r("div"),t=Me(e.perWafer.map(a=>a.summary.wafer));i.appendChild(de(t.lotId!==void 0?"Lot Summary":"Summary"));const o=Je();o.appendChild(ce(String(e.stats.waferCount),"Wafers"));const d=e.perWafer.map(a=>a.summary.stats.yieldPercent).filter(a=>a!==null);if(d.length){const a=d.reduce((b,h)=>b+h,0)/d.length;o.appendChild(ce(`${a.toFixed(1)}%`,Rt))}if(o.finish(),i.appendChild(o),n.length){const a=n.reduce((h,p)=>h+p.stats.analyzedDies,0),b=n.reduce((h,p)=>h+p.stats.excludedDies,0);(a||b)&&i.appendChild(et("Dies analysed",b?`${a.toLocaleString()} (${b.toLocaleString()} excluded)`:a.toLocaleString()))}return i}export function buildPerWaferYieldSection(e,n,i,t,o){const d=e.perWafer.map(m=>({waferIndex:m.waferIndex,label:fe(n[m.waferIndex],m.waferIndex).replace(/\s*·\s*\d+(\.\d+)?%$/,""),yieldPct:m.summary.stats.yieldPercent})).filter(m=>m.yieldPct!==null);if(!d.length)return null;const a=tn(d.map(m=>m.yieldPct)),b=en(d.map(m=>m.yieldPct)),h=a===b?"":` (${a.toFixed(1)}\u2013${b.toFixed(1)}%)`,{rows:p,median:c}=It(d.map(m=>({...m,yieldPercent:m.yieldPct}))),y=ge(t),u=m=>{const S=y.waferSort==="yield"?[...p].sort((N,l)=>N.yieldPct-l.yieldPct):p;for(const N of S){const{waferIndex:l,label:$,yieldPct:R,delta:T,step:w}=N,F=N.outlier?`${$} \xB7 ${N.outlier} outlier`:$,C=ve(F,R,void 0,void 0,c,{delta:T,step:w}),W=o?.(l);W?.total&&x(C,W),L(C,l,$,R,W),m.appendChild(C)}},f=` \xB7 median ${c.toFixed(1)}%`,{outer:v}=ee("Wafer Yield"+h+f,!0,void 0,{stateKey:"waferYield",panel:t,render:u,control:t?m=>Ce([["slot","Slot"],["yield","Yield"]],y.waferSort,S=>{y.waferSort=S,m()},t.ownerDocument,!0):void 0});return v;function x(m,S){const N=S.unusual?"unusual":S.notable?"notable":"info",l=r("span",{marginLeft:g.sm,flexShrink:"0",background:le(N),color:"#fff",borderRadius:q.container,padding:"0 5px",fontSize:D.body,fontWeight:"600"},`${S.total}`);l.setAttribute("aria-hidden","true"),ae(l,`${S.total} finding${S.total===1?"":"s"}`+(S.unusual?`, ${S.unusual} unusual`:"")+(S.notable?`, ${S.notable} notable`:"")),m.firstElementChild?.firstElementChild?.appendChild(l)}function L(m,S,N,l,$){i&&(m.style.cursor="pointer",m.style.borderRadius="4px",m.style.padding="2px 3px",m.style.marginLeft="-3px",m.style.marginRight="-3px",m.setAttribute("role","button"),m.setAttribute("aria-label",`${N}, ${l.toFixed(1)}% yield`+($?.total?`, ${$.total} finding${$.total===1?"":"s"}${$.unusual?`, ${$.unusual} unusual`:""}`:"")+" \u2014 open wafer"),m.tabIndex=0,m.addEventListener("mouseenter",()=>{m.style.background=k.bgHover}),m.addEventListener("mouseleave",()=>{m.style.background=""}),m.addEventListener("focus",()=>{m.style.background=k.bgHover}),m.addEventListener("blur",()=>{m.style.background=""}),m.addEventListener("click",()=>i(S)),m.addEventListener("keydown",R=>{(R.key==="Enter"||R.key===" ")&&(R.preventDefault(),i(S))}))}}function cn(e){return Qt(Float64Array.from(e))}function nt(e,n){if(!e)return[];const i=e.waferMetadata??(e.perWaferMetadata?Ot(e.perWaferMetadata.map(t=>({metadata:t}))):void 0);return!i||!Object.keys(i).length?[]:Ht({waferMetadata:i,waferKeys:"identity",waferPlacement:"csv",reservedLabels:n}).columns}function it(e){return e?.populationLabel?[{key:"population",label:"Population",scope:"wafer",constant:e.populationLabel,get:()=>e.populationLabel,csvOnly:!0}]:[]}export function buildTestSection(...e){return he(buildTestSectionSteps(...e))}export function*buildTestSectionSteps(e,n,i,t,o,d,a,b,h="full"){const p=e.filter(s=>!s.partial&&!s.edgeExcluded),c=new Map((t?.perTestStats??[]).map(s=>[s.testNumber,s])),y=new Map((t?.testSpecYield??[]).map(s=>[s.testNumber,s]));let u;if(n?.length?u=n.filter(bt).map(s=>({testNumber:s.testNumber,name:s.name,unit:s.unit,limitLow:s.limitLow,limitHigh:s.limitHigh,limitLowInclusive:s.limitLowInclusive,limitHighInclusive:s.limitHighInclusive,...xe(s)})):u=Ut(p).map(E=>({testNumber:E,name:xt(void 0,E)})),!u.length)return null;const f=u.filter(s=>p.some(E=>{const I=Be(E,s.testNumber);return I!==void 0&&isFinite(I)}));if(!f.length)return null;const v=f.some(s=>s.limitLow!==void 0||s.limitHigh!==void 0),x=[],L=s=>!!s&&s.stddev!==void 0&&s.median!==void 0&&s.q1!==void 0&&s.q3!==void 0,m=s=>s.limitLow!==void 0||s.limitHigh!==void 0,S=!!(a?.length&&n?.length),l=(S||f.some(s=>!L(c.get(s.testNumber))||m(s)&&!y.has(s.testNumber)))&&n?.length?yield*Xt(a??[{dies:e}],n):void 0;for(const s of f){yield;const E=c.get(s.testNumber),I=l?.specTally.get(s.testNumber),B=l?.stats.get(s.testNumber),P=()=>p.map(z=>Be(z,s.testNumber)).filter(z=>z!==void 0&&isFinite(z));let ne;if(L(E)){const z=E;ne={testNumber:s.testNumber,min:z.min,max:z.max,mean:z.mean,count:z.count,stddev:z.stddev,median:z.median,q1:z.q1,q3:z.q3}}else if(B)ne={testNumber:s.testNumber,...B};else{const z=P();if(!z.length)continue;ne={testNumber:s.testNumber,...cn(z)}}let O=null,_=0;if(m(s)){const z=y.get(s.testNumber);if(z)({yieldPercent:O,totalDies:_}=z);else if(I)_=I.n,O=_>0?(_-I.fail)/_*100:null;else{const ie=P();let Le=0;for(const mt of ie)Kt(Vt(mt,s))&&Le++;_=ie.length,O=ie.length>0?(ie.length-Le)/ie.length*100:null}}x.push({entry:s,stats:ne,specYieldPct:O,specN:_})}if(!x.length)return null;const $=new Map;for(const s of(S?l?.capability:void 0)??[])s.hasSpec&&$.set(s.testNumber,s.ppk);const R=$.size>0,w=new Set(x.map(s=>s.stats.count)).size===1?x[0].stats.count:null,F=r("div"),C=r("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:g.sm}),W=w!==null?` \xB7 N=${w.toLocaleString()}`:"",A=d?.populationLabel?`Test Values (${x.length}) \u2014 ${d.populationLabel}${W}`:`Test Values (${x.length})${W}`,H=de(A);H.style.marginBottom="0",C.appendChild(H);const Y=document.createElement("button");Y.type="button",Y.textContent="Test values CSV",Object.assign(Y.style,{...me("outlined")}),U(Y),Y.addEventListener("click",()=>{const s=[{header:"Test",get:B=>B.entry.name},{header:"Unit",get:B=>B.entry.unit??""},{header:"N",get:B=>B.stats.count},{header:"Min",get:B=>B.stats.min},{header:"Q1",get:B=>B.stats.q1},{header:"Median",get:B=>B.stats.median},{header:"Mean",get:B=>B.stats.mean},{header:"Q3",get:B=>B.stats.q3},{header:"Max",get:B=>B.stats.max},{header:"StdDev",get:B=>B.stats.stddev}];R&&s.push({header:"Ppk",get:B=>{const P=$.get(B.entry.testNumber);return P==null?"":P.toFixed(3)}});const E=x.some(B=>B.specYieldPct!==null&&B.specN!==B.stats.count);v&&(s.push({header:"Lo limit",get:B=>B.entry.limitLow},{header:"Hi limit",get:B=>B.entry.limitHigh},{header:"Limit Yield %",get:B=>B.specYieldPct!==null?B.specYieldPct.toFixed(1):""}),E&&s.push({header:"Limit Yield N",get:B=>B.entry.limitLow!==void 0||B.entry.limitHigh!==void 0?B.specN:""})),x.some(B=>Re(B.entry))&&s.push({header:Te,get:B=>Ee(B.entry)});const I=[...nt(d,s.map(B=>B.header)),...it(d)];qe([...I.map(B=>({header:B.label,get:()=>B.constant??""})),...s],x,"test-values.csv",o)});const Z=b===void 0;Z&&C.appendChild(Y),F.appendChild(C);const V=r("table",{width:"100%",borderCollapse:"collapse",fontSize:D.body}),J=document.createElement("thead"),se=document.createElement("tr"),K=["Test"];w===null&&K.push("N"),h==="full"&&K.push("Min","Q1","Median"),K.push("Mean"),h==="full"&&K.push("Q3","Max","StdDev"),R&&K.push("Ppk"),h==="full"&&v&&K.push("Lo limit","Hi limit"),v&&K.push("Limit yield");for(const s of K){const E=r("th",{textAlign:s==="Test"?"left":"right",fontWeight:"600",fontSize:D.meta,letterSpacing:re,textTransform:"uppercase",color:M,padding:"3px 8px 5px",borderBottom:`1px solid ${k.menuBorder}`,whiteSpace:"nowrap"},s);se.appendChild(E)}J.appendChild(se),V.appendChild(J);const Q=document.createElement("tbody");for(const{entry:s,stats:E,specYieldPct:I,specN:B}of x){const P=_=>qt(_,s.unit,i),ne=document.createElement("tr"),O=(_,z="right")=>{const ie=r("td",{textAlign:z,padding:`${g.xs} ${g.md}`,borderBottom:`1px solid ${k.menuBorder}`,color:k.text,whiteSpace:"nowrap"},_);ne.appendChild(ie)};if(O(yt(s,s.testNumber),"left"),w===null&&O(`${E.count}`),h==="full"&&(O(P(E.min)),O(P(E.q1)),O(P(E.median))),O(P(E.mean)),h==="full"&&(O(P(E.q3)),O(P(E.max)),O(P(E.stddev))),R){const _=$.get(s.testNumber);O(_==null?"\u2014":_.toFixed(2))}h==="full"&&v&&(O(s.limitLow!==void 0?P(s.limitLow):"\u2014"),O(s.limitHigh!==void 0?P(s.limitHigh):"\u2014")),v&&O(I!==null?w!==null&&B===w?`${I.toFixed(1)}%`:`${I.toFixed(1)}% (N=${B})`:"\u2014"),Q.appendChild(ne)}V.appendChild(Q);const te=r("div",{overflowX:"auto"});te.appendChild(V);const j=rt(te,x.map(s=>({label:s.entry.name,...xe(s.entry)})));if(!b)return F.appendChild(j),F;C.remove();const{outer:ue}=ee(A,!0,void 0,{stateKey:"testValues",panel:b,render:s=>s.appendChild(j),control:Z?()=>Y:void 0});return ue}export function buildFunctionalTestSection(e,n,i,t,o,d){const a=i??Bt(e,n);if(!a?.length)return null;const h=new Set(a.map(w=>w.totalDies)).size===1?a[0].totalDies:null,p=h!==null?` \xB7 N=${h.toLocaleString()}`:"",c=r("div"),y=r("div",{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:g.sm}),u=o?.populationLabel?`Functional Tests (${a.length}) \u2014 ${o.populationLabel}${p}`:`Functional Tests (${a.length})${p}`,f=de(u);f.style.marginBottom="0",y.appendChild(f);const v=document.createElement("button");v.type="button",v.textContent="Functional CSV",Object.assign(v.style,{...me("outlined")}),U(v),v.addEventListener("click",()=>{const w=[{header:"Test",get:C=>Ct(C.label)},{header:"N",get:C=>C.totalDies},{header:"Pass",get:C=>C.passDies},{header:"Fail",get:C=>C.failDies},{header:"Pass Rate %",get:C=>C.passRatePercent!==null?C.passRatePercent.toFixed(1):""}];a.some(C=>Re(C))&&w.push({header:Te,get:C=>Ee(C)});const F=[...nt(o,w.map(C=>C.header)),...it(o)];qe([...F.map(C=>({header:C.label,get:()=>C.constant??""})),...w],a,"functional-tests.csv",t)});const x=d===void 0;x&&y.appendChild(v),c.appendChild(y);const L=r("table",{width:"100%",borderCollapse:"collapse",fontSize:D.body}),m=document.createElement("thead"),S=document.createElement("tr"),N=h===null?["Test","N","Pass","Fail","Pass rate"]:["Test","Pass","Fail","Pass rate"];for(const w of N)S.appendChild(r("th",{textAlign:w==="Test"?"left":"right",fontWeight:"700",fontSize:D.body,letterSpacing:re,textTransform:"uppercase",color:M,padding:"3px 8px 5px",borderBottom:`1px solid ${k.menuBorder}`,whiteSpace:"nowrap"},w));m.appendChild(S),L.appendChild(m);const l=document.createElement("tbody");for(const w of a){const F=document.createElement("tr"),C=(W,A="right")=>{F.appendChild(r("td",{textAlign:A,padding:`${g.xs} ${g.md}`,borderBottom:`1px solid ${k.menuBorder}`,color:X,whiteSpace:"nowrap"},W))};C(w.label,"left"),h===null&&C(String(w.totalDies)),C(String(w.passDies)),C(String(w.failDies)),C(w.passRatePercent!==null?`${w.passRatePercent.toFixed(1)}%`:"\u2014"),l.appendChild(F)}L.appendChild(l);const $=r("div",{overflowX:"auto"});$.appendChild(L);const R=rt($,a);if(!d)return c.appendChild(R),c;y.remove();const{outer:T}=ee(u,!0,void 0,{stateKey:"functionalTests",panel:d,render:w=>w.appendChild(R),control:x?()=>v:void 0});return T}export function buildLotFunctionalSection(e,n,i,t,o){const d=i?.length?{perWaferMetadata:i.map(b=>b.wafer??{}),populationLabel:`${i.length} wafer${i.length===1?"":"s"} pooled`}:void 0,a=Jt(i);return a?buildFunctionalTestSection(e,n,a,t,d,o):buildFunctionalTestSection(e,n,void 0,t,d,o)}function Se(e){const{tier:n,word:i}=Tt[e],t=Ne(n),o=r("span",{flexShrink:"0",letterSpacing:"1px",lineHeight:G.none,color:le(e)},"\u25CF".repeat(t)+"\u25CB".repeat(Fe-t));return o.setAttribute("role","img"),o.setAttribute("aria-label",i),ae(o,i),o}function ot(e,n){let i=e.summary;if(n){const t=[" has "," have "].find(o=>i.startsWith(`${n}${o}`));t?i=i.slice(n.length+t.length):i.startsWith(`${n} `)&&(i=i.slice(n.length+1))}return i=oe(i),i.length?i[0].toUpperCase()+i.slice(1):i}function at(e){return st(e.map(n=>({label:n.variable.label,...xe(n.variable)})))}function st(e){const n=vt(e);return n?r("div",{fontSize:D.body,color:M,marginTop:g.sm,lineHeight:G.base},n):null}function rt(e,n){const i=st(n);if(!i)return e;const t=r("div",{});return t.append(e,i),t}export function buildFindingsSection(e,n,i,t,o=!1,d){if(!e.length)return null;const a=e.some(l=>l.severity==="unusual"||l.severity==="notable"),b=a?e.filter(l=>l.severity!=="info").length.toString():void 0,{outer:h,content:p}=o?(()=>{const l=r("div");return{outer:l,content:l}})():ee(`Findings (${e.length})`,a,b);function c(l,$){const T={ring:"Ring",quadrant:"Quadrant",sector:"Sector","reticle-position":"Reticle","test-site":"Test site",cluster:"Cluster","edge-arc":"Edge arc",wafer:"Wafer"}[l]??l;return $.toLowerCase().startsWith(T.toLowerCase())?$:`${T}: ${$}`}const y=Mt(e),u=y.patterns.map(l=>l.finding),f=y.groups.map(l=>({...l,key:`${l.family}\0${l.left}`})),v=()=>[...f.flatMap(l=>l.findings),...u.flatMap(l=>e.filter($=>l.relatedIds?.includes($.id)))];function x(l,$=!1,R){const T=t===l.id,w=document.createElement("button");return w.type="button",w.dataset.wmapFinding=l.id,w.textContent=ot(l,R),ae(w,Ae(l)),w.setAttribute("aria-current",T?"true":"false"),Object.assign(w.style,{border:`1px solid ${k.menuBorder}`,borderLeft:`3px solid ${le(l.severity)}`,background:T?k.bgActive:k.menuBg,borderRadius:q.container,padding:$?"6px 10px":"8px 10px",textAlign:"left",fontSize:$?"10px":"11px",fontWeight:T?"600":"400",color:k.text,cursor:"pointer",width:"100%",marginBottom:g.xs}),U(w,"bare"),w.addEventListener("click",()=>i(l,w)),w}const L=r("button",{flexShrink:"0",border:"none",background:"none",fontSize:D.body,color:k.icon,cursor:"pointer",padding:"0",lineHeight:G.base,whiteSpace:"nowrap"},"Detail \u25B8");L.type="button",U(L,"bare"),L.addEventListener("click",()=>{const l=Ke({title:"Findings Summary",onClose:()=>{},anchor:L}),$=De(n,{passBins:d}),R=r("div",{fontSize:"16px",lineHeight:G.base,color:k.text,padding:`${g.xxl} ${g.xxxl} ${g.xxl}`,margin:"0",borderBottom:`1px solid ${k.menuBorder}`,flexShrink:"0",display:"flex",flexDirection:"column",gap:g.md});for(const C of $t($).split(`
|
|
2
|
+
`))R.appendChild(r("p",{margin:"0"},oe(C)));l.contentWrap.appendChild(R);const T=r("div",{overflowY:"auto",padding:`${g.xxl} ${g.xxxl}`,flex:"1"}),w=(C,W)=>{const A=r("div",{display:"flex",alignItems:"center",gap:"7px",fontSize:D.sub,fontWeight:"600",color:X,marginTop:g.lg,marginBottom:g.xs});return A.appendChild(Se(C)),A.appendChild(r("span",{},W)),A};for(const C of u){T.appendChild(w(C.severity,C.comparison.left)),T.appendChild(r("div",{fontSize:D.body,color:k.text,padding:"4px 0 4px 15px",marginBottom:g.xxs},oe(C.summary)));const W=e.filter(A=>C.relatedIds?.includes(A.id));for(const A of W)T.appendChild(r("div",{fontSize:D.body,color:M,padding:"2px 0 2px 23px",marginBottom:g.xxs},oe(A.summary)))}for(const C of f){const[W,A]=C.key.split("\0");T.appendChild(w(C.worst,c(W,A)));for(const H of C.findings)T.appendChild(r("div",{fontSize:D.body,color:k.text,padding:"4px 0 4px 15px",marginBottom:g.xxs},ot(H,A)))}const F=at(v());F&&T.appendChild(F),l.contentWrap.appendChild(T),Object.assign(l.contentWrap.style,{flexDirection:"column",overflow:"hidden"})});const m=r("div",{display:"flex",justifyContent:"flex-end",marginBottom:g.xs});m.appendChild(L),p.appendChild(m);let S=!0;for(const l of u){S||p.appendChild(r("div",{height:"1px",background:k.separator,margin:"4px 0"})),S=!1;const $=e.filter(C=>l.relatedIds?.includes(C.id)),R=$.length>0,T=r("div",{position:"relative",marginBottom:R?"2px":"4px"}),w=t===l.id,F=document.createElement("button");if(F.type="button",F.dataset.wmapFinding=l.id,Object.assign(F.style,{border:`1px solid ${k.menuBorder}`,borderLeft:`3px solid ${le(l.severity)}`,background:w?k.bgActive:k.menuBg,borderRadius:q.container,padding:"8px 32px 8px 10px",textAlign:"left",fontSize:D.body,fontWeight:w?"600":"500",color:k.text,cursor:"pointer",width:"100%"}),F.textContent=oe(l.summary),ae(F,l.summary),F.setAttribute("aria-current",w?"true":"false"),U(F,"bare"),F.addEventListener("click",()=>i(l,F)),T.appendChild(F),R){const C=r("div",{display:"none",paddingLeft:"12px",marginBottom:g.xs});for(const H of $)C.appendChild(x(H,!0));T.appendChild(C);let W=!1;const A=r("button",{position:"absolute",top:"50%",right:"8px",transform:"translateY(-50%)",border:"none",background:"none",fontSize:D.body,color:k.icon,cursor:"pointer",padding:`${g.xxs} ${g.xs}`,lineHeight:G.none},"\u25B8");U(A,"bare"),A.type="button",ae(A),A.setAttribute("aria-label","Show supporting findings"),A.setAttribute("aria-expanded","false"),A.addEventListener("click",H=>{H.stopPropagation(),W=!W,C.style.display=W?"block":"none",A.textContent=W?"\u25BE":"\u25B8";const Y=W?"Hide supporting findings":"Show supporting findings";A.setAttribute("aria-label",Y),A.setAttribute("aria-expanded",String(W))}),T.appendChild(A)}p.appendChild(T)}for(const l of f){S||p.appendChild(r("div",{height:"1px",background:k.separator,margin:"4px 0"})),S=!1;const[$,R]=l.key.split("\0"),T=r("div",{display:"flex",alignItems:"center",gap:g.sm,fontSize:D.body,fontWeight:"600",color:X,margin:"2px 0 4px"});T.appendChild(Se(l.worst)),T.appendChild(r("span",{},c($,R))),p.appendChild(T);for(const w of l.findings)p.appendChild(x(w,!1,R))}const N=at(v());return N&&p.appendChild(N),h}const un={high:"rgba(168, 65, 18, 0.10)",medium:"rgba(138, 101, 0, 0.10)",low:""},lt={high:"unusual",medium:"notable",low:"info"};function dt(e,n){const i=Ne(e),t=r("span",{display:"inline-flex",alignItems:"baseline",gap:g.xs,whiteSpace:"nowrap"}),o=r("span",{letterSpacing:"1px",color:le(lt[e])},"\u25CF".repeat(i)+"\u25CB".repeat(Fe-i));return o.setAttribute("aria-hidden","true"),t.appendChild(o),t.appendChild(r("span",{fontSize:D.meta,fontWeight:"600",letterSpacing:re,textTransform:"uppercase",color:X},n)),t}export function buildSynthesisSection(e,n,i,t,o,d){const a=De(e,{passBins:n}),b=new Map(e.findings.map(x=>[x.id,x])),{outer:h,content:p}=ee("What stands out",!0,void 0,{stateKey:"synthesis",panel:o}),c=(x,L)=>{for(const m of L){const S=m.target?b.get(m.target.id):void 0,N=oe(m.text);if(!S||!i||!N){x.appendChild(document.createTextNode(N));continue}const l=document.createElement("button");l.type="button",l.textContent=N,l.dataset.wmapFinding=S.id,l.setAttribute("aria-current",t===S.id?"true":"false"),Object.assign(l.style,{border:"none",background:"none",padding:"0",margin:"0",font:"inherit",color:"inherit",textDecoration:"underline dotted",textUnderlineOffset:"2px",cursor:"pointer",textAlign:"inherit",fontWeight:t===S.id?"600":"inherit"}),ae(l,Ae(S));const $=R=>{l.style.textDecoration=R?"underline solid":"underline dotted",l.style.color=R?k.iconActive:"inherit"};l.addEventListener("mouseenter",()=>$(!0)),l.addEventListener("mouseleave",()=>$(!1)),l.addEventListener("focus",()=>$(!0)),l.addEventListener("blur",()=>$(!1)),l.addEventListener("click",()=>i(S,l)),x.appendChild(l)}},y=(x,L)=>{const m=r("div",{fontSize:D.body,lineHeight:G.base,color:k.text,...L});return c(m,x),m};p.appendChild(y(a.headline,{fontWeight:"600",marginBottom:g.sm})),a.nothing&&p.appendChild(r("div",{fontSize:D.body,lineHeight:G.base,color:k.text,marginBottom:g.sm},a.nothing));const[u,...f]=a.items;if(u){const x=r("div",{borderLeft:`3px solid ${le(lt[u.impact])}`,background:un[u.impact]||k.bgActive,borderRadius:`0 ${q.container} ${q.container} 0`,padding:`${g.sm} ${g.md}`,marginBottom:g.sm});x.appendChild(dt(u.impact,Dt(u.impact))),x.appendChild(y(u.parts,{marginTop:g.xxs})),p.appendChild(x)}const v=[...f,...a.also?.items??[]];if(v.length){p.appendChild(r("div",{fontSize:D.meta,color:M,marginBottom:g.xxs},Et));const x=r("div",{marginBottom:g.sm});x.setAttribute("role","list");for(const m of v){const S=r("div",{display:"flex",alignItems:"baseline",gap:g.sm,fontSize:D.body,lineHeight:G.base,color:k.text});S.setAttribute("role","listitem"),S.appendChild(dt(m.impact,Ft(m.impact)));const N=r("span",{flex:"1",minWidth:"0"});c(N,[m.brief]),S.appendChild(N),S.appendChild(r("span",{color:M,fontVariantNumeric:"tabular-nums",whiteSpace:"nowrap"},kt(m))),x.appendChild(S)}const L=a.also?.more??0;L>0&&x.appendChild(r("div",{fontSize:D.meta,color:M},`and ${L} more`)),p.appendChild(x)}for(const x of a.watch??[]){const L=y(x.parts,{marginBottom:g.xs});L.insertBefore(r("span",{fontSize:D.meta,fontWeight:"600",letterSpacing:re,textTransform:"uppercase",color:M,marginRight:g.sm},"Watch"),L.firstChild),p.appendChild(L)}if(p.appendChild(r("div",{fontSize:D.body,lineHeight:G.base,color:M},oe(a.checked))),d){const x=r("button",{border:"none",background:"none",padding:"0",marginTop:g.sm,fontSize:D.body,color:k.icon,cursor:"pointer",textDecoration:"underline",textUnderlineOffset:"2px"},"Full report \u25B8");x.type="button",U(x,"bare"),x.addEventListener("click",d),p.appendChild(x)}return h}const fn=[{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"}],mn=[{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"}],hn=["unusual","notable","info"],gn={unusual:"Unusual",notable:"Notable",info:"Minor"};function bn(e,n,i){const t=r("div",{display:"flex",flexWrap:"wrap",alignItems:"center",gap:g.lg,marginBottom:g.lg,paddingBottom:"10px",borderBottom:`1px solid ${k.separator}`}),o={unusual:0,notable:0,info:0};for(const p of e)o[p.severity]++;const d=hn.filter(p=>o[p]>0),a=new Set(n.severity===void 0?d:Array.isArray(n.severity)?n.severity:[n.severity]),b=r("div",{display:"flex",gap:g.xs,flexWrap:"wrap"});for(const p of d){const c=document.createElement("button");c.type="button";const y=()=>{const f=a.has(p);c.setAttribute("aria-pressed",f?"true":"false"),Object.assign(c.style,{display:"inline-flex",alignItems:"center",gap:"5px",border:`1px solid ${k.menuBorder}`,borderRadius:q.pill,background:f?k.bgActive:"none",opacity:f?"1":"0.5",color:k.text,fontSize:D.body,padding:`${g.xxs} ${g.md}`,cursor:"pointer"}),c.dataset.on=f?"true":"false"},u=Se(p);u.removeAttribute("role"),u.removeAttribute("aria-label"),u.setAttribute("aria-hidden","true"),c.appendChild(u),c.appendChild(r("span",{},`${gn[p]} ${o[p]}`)),ae(c,()=>a.has(p)?"Click to hide these findings":"Click to show these findings"),y(),U(c,"bare"),c.addEventListener("click",()=>{a.has(p)?a.delete(p):a.add(p),n.severity=a.size===d.length?void 0:[...a],i()}),b.appendChild(c)}t.appendChild(b);const h=n.kind!==void 0||n.family!==void 0;return(e.length>=xn||h)&&(t.appendChild(Ye("Kind:",fn,n.kind??"",p=>{n.kind=p||void 0,i()},{maxWidth:"130px"})),t.appendChild(Ye("Region:",mn,n.family??"",p=>{n.family=p||void 0,i()},{maxWidth:"150px"}))),t}const xn=8;function yn(e,n){const i=r("div",{display:"flex",flexDirection:"column",gap:g.xs,padding:g.md,marginBottom:g.md,background:k.bgHover,borderRadius:q.control},void 0,n);if(i.appendChild(r("div",{fontSize:D.body,color:k.value},e.message,n)),e.detail&&i.appendChild(r("div",{fontSize:D.meta,color:M},e.detail,n)),e.actionLabel&&e.onAction){const t=r("button",me("outlined"),e.actionLabel,n);t.type="button",t.style.alignSelf="flex-start",t.style.marginTop=g.xs,U(t),t.addEventListener("click",e.onAction),i.appendChild(t)}return i}export function buildFindingsSectionWithFilter(e,n,i,t,o,d,a,b){if(!e.findings.length&&!a)return null;const h=e.findings.some(x=>x.severity==="unusual"||x.severity==="notable"),p=h?e.findings.filter(x=>x.severity!=="info").length.toString():void 0,c=d?.ownerDocument??document,{outer:y,content:u}=ee(`Findings (${e.findings.length})`,h||!!a,p,{stateKey:"findings",panel:d});if(a&&u.appendChild(yn(a,c)),!e.findings.length)return y;u.appendChild(bn(e.findings,t,o));const f=Pt(e,t);if(!f.length)return u.appendChild(r("div",{color:M,fontSize:D.body,textAlign:"center",padding:`${g.xxl} ${g.md}`},"No findings match the current filter.")),y;const v=buildFindingsSection(f,e,n,i,!0,b);return v&&u.appendChild(v),y}export function buildLotTestSection(...e){return he(buildLotTestSectionSteps(...e))}export function*buildLotTestSectionSteps(e,n,i,t,o,d,a,b="full"){const h=t?.length?{perWaferMetadata:t.map(c=>c.wafer??{}),populationLabel:`${t.length} wafer${t.length===1?"":"s"} pooled`}:void 0;let p;if(t?.length&&t.every(c=>c.stats.perTestStats!==void 0)){const c=new Map;for(const y of t)for(const u of y.stats.perTestStats??[]){const f=c.get(u.testNumber);f?(f.n+=u.count,f.sum+=u.mean*u.count,f.min=Math.min(f.min,u.min),f.max=Math.max(f.max,u.max)):c.set(u.testNumber,{n:u.count,sum:u.mean*u.count,min:u.min,max:u.max})}p={perTestStats:[...c.entries()].map(([y,u])=>({testNumber:y,count:u.n,min:u.min,max:u.max,mean:u.sum/u.n}))}}if(t?.length&&t.every(c=>c.stats.testSpecYield!==void 0)){const c=new Map;for(const y of t)for(const u of y.stats.testSpecYield??[]){const f=c.get(u.testNumber);f?(f.passDies+=u.passDies,f.totalDies+=u.totalDies):c.set(u.testNumber,{passDies:u.passDies,totalDies:u.totalDies})}p={...p,testSpecYield:[...c.entries()].map(([y,u])=>({testNumber:y,totalDies:u.totalDies,yieldPercent:u.totalDies>0?u.passDies/u.totalDies*100:null}))}}return yield*buildTestSectionSteps(e,n,i,p,o,h,d,a,b)}export function createSummaryPanelEl(e,n,i=document,t){const o=e==="top"||e==="bottom",d=r("div",{background:on,color:k.text,fontVariantNumeric:"tabular-nums",border:Ge,borderRadius:q.container,padding:g.xl,overflowY:"auto",overflowX:o?"auto":"hidden",flexShrink:"0",boxSizing:"border-box",fontFamily:D.family,fontSize:D.sub,boxShadow:_e.panel},void 0,i);return e==="right"&&(d.style.marginRight=n),e==="left"&&(d.style.marginLeft=n),e==="bottom"&&(d.style.marginBottom=n),o?(d.style.height="180px",d.style.width="100%"):(d.style.width="300px",d.style.maxHeight="100%"),t&&d.addEventListener("contextmenu",a=>{const b=a.target?.closest("[data-wmap-finding]");b?.dataset.wmapFinding&&(a.preventDefault(),t(b.dataset.wmapFinding,b,{x:a.clientX,y:a.clientY}))}),d}export function wrapWithSummaryPanel(e,n,i){const t=i==="top"||i==="bottom",o=r("div",{display:"flex",flexDirection:t?"column":"row",gap:g.md,width:"100%",height:"100%",flex:"1 1 0",minHeight:"0",boxSizing:"border-box",alignItems:t?"flex-start":"stretch"});return e.style.flex="1 1 0",e.style.minWidth="0",e.style.minHeight="0",i==="right"||i==="bottom"?(o.appendChild(e),o.appendChild(n)):(o.appendChild(n),o.appendChild(e)),o}function pt(e,n,i,t,o){const d=n.find(b=>b.id===i);if(!d||!o)return;t.close();const a=[...e.querySelectorAll("button[data-wmap-finding]")].find(b=>b.dataset.wmapFinding===i)??e.ownerDocument.createElement("button");o(d,a)}function ct(e){return r("div",{fontSize:D.heading,fontWeight:"600",color:X,marginBottom:g.lg},e)}function be(e,n){const i=r("button",me("outlined"),e);return i.type="button",U(i),i.addEventListener("click",n),i}function ut(...e){const n=e.filter(t=>!!t);if(!n.length)return null;const i=r("div",{display:"flex",flexWrap:"wrap",gap:g.sm,marginBottom:g.lg});for(const t of n)i.appendChild(t);return i}function ft(e,n,i){const t=e.ownerDocument;import("./dataTab.js").then(({renderDataTables:o})=>{let d;const a=n.onLocateDie,b=o({...n,doc:t,view:"dies",onLocateDie:a?(p,c)=>{d?.(),a(p,c)}:void 0}),h=Ke({title:i,onClose:()=>b.destroy(),anchor:e,ownerDocument:t,boxSize:{width:"min(96vw, 1200px)",height:"min(92vh, 780px)"}});d=()=>h.close(),h.contentWrap.appendChild(b.el)})}export function renderWaferSummaryContent(...e){he(renderWaferSummaryContentSteps(...e))}export function*renderWaferSummaryContentSteps(e,n){const i=e.scrollTop;e.innerHTML="";const{wafer:t,dies:o,yieldSummary:d,dataCoverage:a,hbinDefs:b,sbinDefs:h,testDefs:p,statsSummary:c,passBins:y,ringCount:u,binColors:f,plotMode:v,fallbackFormat:x,onFindingClick:L,activeFindingId:m=null,findingsFilter:S,onFindingsFilterChange:N,findingsNotice:l,onSaveText:$,metadataFields:R,dieListOptions:T,onLocateDie:w,metadataShownElsewhere:F}=n;e.appendChild(ct("Wafer Summary"));const C=n.warnings??Pe({statsSummary:c});C.length&&e.appendChild(ye(C,e.ownerDocument));const W=d&&a?()=>{import("../stats/renderSummaryReport.js").then(({renderWaferReportHtml:Q})=>{je(Q({wafer:t,dies:o,yield:d,dataCoverage:a,hbinDefs:b,sbinDefs:h,testDefs:p,passBins:y,ringCount:u},c,{binColors:f,live:!!L}),{anchor:e,onFinding:(te,j)=>pt(e,c?.findings??[],te,j,L)})})}:null,A=W?be("Summary report",W):null,H=(T?.enabled??!0)&&o.length?be("Data tables",()=>{ft(e,{items:[{label:t.metadata?.waferId!==void 0?String(t.metadata.waferId):"this wafer",dies:o,wafer:t,passBins:y}],testDefs:p,ringCount:u,metadataFields:R,dieListOptions:T,onSaveText:$,onLocateDie:w},`Data tables \u2014 ${o.length.toLocaleString()} dies`)}):null,Y=ut(A,H);Y&&e.appendChild(Y);let Z=!0;const V=Q=>{Q&&(Z||e.appendChild(Ze()),Z=!1,e.appendChild(Q))},J=c?.stats.isLotStack?c.stats:void 0,se=J?.lotSize!==void 0?{lotSize:J.lotSize,aggrMethod:Gt(J.aggregationMethod)}:void 0;F||V(buildMetadataInfoSection([{metadata:t.metadata??void 0}],se)),d&&a&&V(buildYieldSection(d,a,y)),yield,c&&(V(buildSynthesisSection(c,y,L,m,e,W??void 0)),yield),c&&L&&S&&N&&(V(buildFindingsSectionWithFilter(c,L,m,S,N,e,l,y)),yield),V(buildBinBreakdownSection({dies:o,hbinDefs:b,sbinDefs:h,binColors:f,hardCounts:c?.stats.hardBinCounts,softCounts:c?.stats.softBinCounts,plotMode:v,passBins:y,panel:e})),yield,V(buildRegionYieldPanelSection({diesByWafer:[o],allWafers:[t],ringCount:u,passBins:y,panel:e})),yield;const K=t.metadata?{waferMetadata:t.metadata}:void 0;V(yield*buildTestSectionSteps(o,p,x,c?.stats,$,K,[{dies:o}],e,"compact")),yield,V(buildFunctionalTestSection(o,p,c?.stats.functionalYield,$,K,e)),e.appendChild(r("div",{height:"12px",flexShrink:"0"})),e.scrollTop=i}export function reportMapsFromItems(e,n,i){const t=[];return e.forEach((o,d)=>{!o?.wafer||!o.dies||t.push({...o,wafer:o.wafer,dies:o.dies,label:fe(o,d),passBins:[...pe(o,i)],ringCount:$e(o,n)})}),t}export function renderLotSummaryContent(...e){he(renderLotSummaryContentSteps(...e))}export function*renderLotSummaryContentSteps(e,n){const i=e.scrollTop;e.innerHTML="";const{lotSummary:t,items:o,hbinDefs:d,sbinDefs:a,testDefs:b,passBins:h,ringCount:p,binColors:c,plotMode:y,fallbackFormat:u,onFindingClick:f,activeFindingId:v=null,onWaferClick:x,findingsFilter:L,onFindingsFilterChange:m,findingsNotice:S,onSaveText:N,dieListOptions:l,onLocateDie:$,findingsFor:R}=n,T=()=>p??$e(o.find(s=>!!s));e.appendChild(ct(`Summary \u2014 ${jt(Me(t.perWafer.map(s=>s.summary.wafer)))}`));const w=n.warnings??Pe({lotStatsSummary:t});w.length&&e.appendChild(ye(w,e.ownerDocument));const F=()=>{import("../stats/renderSummaryReport.js").then(({renderLotReportHtml:s})=>{je(s(reportMapsFromItems(o,p,h),{binColors:c,live:!!f}),{anchor:e,onFinding:(E,I)=>pt(e,t.findings,E,I,f)})})},C=be("Summary report",F),W=[],A=[],H=[],Y=[],Z=[],V=new WeakMap,J=new WeakMap;for(let s=0;s<o.length;s++){yield;const E=o[s];if(!E){A.push([]);continue}E.wafer&&(W.push(E.wafer),Y.push(E.dies??[]),Z.push(pe(E,h)));const I=E.dies??[],B=fe(E,s);for(const P of I)V.set(P,B),E.wafer&&J.set(P,E.wafer);A.push(I);for(const P of I)H.push(P)}const se=l?.enabled??!0?be("Data tables",()=>{if(!H.length)return;const s=o.map((E,I)=>({it:E,i:I})).filter(E=>!!E.it);ft(e,{items:s.map(({it:E,i:I})=>({label:fe(E,I),dies:E.dies??[],waferIndex:I,wafer:E.wafer,passBins:pe(E,h),statsSummary:E.statsSummary})),testDefs:b,ringCount:T(),metadataFields:o.find(E=>E?.metadataFields?.length)?.metadataFields,dieListOptions:l,onSaveText:N,onLocateDie:$},`Data tables \u2014 ${H.length.toLocaleString()} dies across ${o.length} wafer${o.length===1?"":"s"}`)}):null,K=ut(C,se);K&&e.appendChild(K);const Q=o.map(s=>s?.statsSummary).filter(s=>!!s);let te=!0;const j=s=>{s&&(te||e.appendChild(Ze()),te=!1,e.appendChild(s))};j(buildLotOverviewSection(t,Q)),yield;const ue=ht(o.map(s=>s?pe(s,h):void 0).filter(s=>s!==void 0));j(buildSynthesisSection(t,ue,f,v,e,F)),yield,f&&L&&m&&(j(buildFindingsSectionWithFilter(t,f,v,L,m,e,S,ue)),yield),j(buildPerWaferYieldSection(t,o,x,e,R)),yield,j(buildBinBreakdownSection({dies:H,hbinDefs:d,sbinDefs:a,plotMode:y,passBins:h,panel:e,binColors:c??Yt(o.flatMap(s=>s?[{dies:s.dies??[],passBins:pe(s,h)}]:[]),{hbinDefs:d,sbinDefs:a}).colors})),yield,W.length>0&&j(buildRegionYieldPanelSection({diesByWafer:Y,allWafers:W,ringCount:T(),passBins:s=>Z[s],panel:e})),yield,b?.length&&(j(yield*buildLotTestSectionSteps(H,b,u,Q,N,A.map(s=>({dies:s})),e,"compact")),yield,j(buildLotFunctionalSection(H,b,Q,N,e))),e.appendChild(r("div",{height:"12px",flexShrink:"0"})),e.scrollTop=i}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface SummaryRail {
|
|
2
|
+
el: HTMLButtonElement;
|
|
3
|
+
/** Show while the panel is closed and a Summary exists; `notable` tints it like the toolbar icon. */
|
|
4
|
+
sync(visible: boolean, notable: boolean): void;
|
|
5
|
+
}
|
|
6
|
+
export declare function createSummaryRail(doc: Document, side: 'left' | 'right', onOpen: () => void): SummaryRail;
|
|
7
|
+
//# sourceMappingURL=summaryRail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{CLR as e,FONT as s,RADIUS as d,SPACE as r,wireControlHover as c,wireTooltip as m}from"./toolbar.js";export function createSummaryRail(o,n,i){const t=o.createElement("button");return t.type="button",t.dataset.wmapSummaryRail="1",t.setAttribute("aria-expanded","false"),t.textContent=n==="right"?"\u25C2 Summary":"Summary \u25B8",Object.assign(t.style,{display:"none",flexShrink:"0",alignSelf:"flex-start",writingMode:"vertical-rl",cursor:"pointer",whiteSpace:"nowrap",fontSize:s.body,fontWeight:"600",color:e.icon,background:e.menuBg,border:`1px solid ${e.menuBorder}`,borderRadius:d.control,padding:`${r.md} ${r.sm}`,position:"sticky",top:r.md,order:n==="right"?"10":"-10"}),c(t,"bare"),m(t,"Open the Summary panel: what stands out, findings and statistics"),t.addEventListener("click",i),{el:t,sync(a,l){t.style.display=a?"block":"none",t.style.color=l?e.findingIndicator:e.icon}}}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PlotSpec } from '../stats/plotSpec.js';
|
|
2
|
+
import type { TestDef } from '../renderer/buildWaferMap.js';
|
|
3
|
+
export interface SweepEditorOptions {
|
|
4
|
+
doc: Document;
|
|
5
|
+
plot: PlotSpec;
|
|
6
|
+
/** The open lot's tests: with them, a series read from test names shows those names, and what its pattern reads. */
|
|
7
|
+
testDefs?: readonly TestDef[];
|
|
8
|
+
/** Called with the new spec after every valid change. */
|
|
9
|
+
onChange: (next: PlotSpec) => void;
|
|
10
|
+
}
|
|
11
|
+
export interface SweepEditorHandle {
|
|
12
|
+
el: HTMLElement;
|
|
13
|
+
/** The plot changed elsewhere (undo, an import): show it. */
|
|
14
|
+
setPlot(plot: PlotSpec): void;
|
|
15
|
+
}
|
|
16
|
+
export declare function createSweepEditor(o: SweepEditorOptions): SweepEditorHandle;
|
|
17
|
+
//# sourceMappingURL=sweepEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{formatNumberList as T,formatTestList as D,parseNumberList as N,parseTestList as R}from"../stats/sweepText.js";import{previewXFromName as V,recordSweepTestNames as X}from"../stats/sweep.js";import{NAME_PATTERN_EXAMPLES as P,NAME_PATTERN_LIMIT as k}from"../stats/sweepXFromName.js";import{CLR as h,FONT as S,RADIUS as O,SPACE as f,controlStyle as z,wireControlHover as $}from"./toolbar.js";import{makeSegmented as A,makeToggle as W}from"./charts/chartShell.js";import{fieldRow as b,inputStyle as _}from"./plotEditor.js";const B=x=>x.xFromName!==void 0?"name":x.xValues!==void 0?"values":"order";export function createSweepEditor(x){const{doc:r}=x;let y=x.plot;const w=r.createElement("div");w.dataset.wmapSweepEditor="1",Object.assign(w.style,{display:"flex",flexDirection:"column",gap:f.lg,minWidth:"0"});const u=a=>{const e=JSON.parse(JSON.stringify(y));e.sweep=e.sweep??{series:[]},a(e),e.sweep=X(e.sweep,x.testDefs),y=e,x.onChange(e)};function g(a,e,d,t,p={}){const m=r.createElement("div");Object.assign(m.style,{display:"flex",flexDirection:"column",gap:f.xxs,minWidth:"0"});const s=r.createElement("input");s.type="text",s.value=a,s.placeholder=d,s.setAttribute("aria-label",e),Object.assign(s.style,_(),{width:"100%",...p.mono?{fontVariantNumeric:"tabular-nums"}:{}});const i=r.createElement("div");return i.setAttribute("role","alert"),Object.assign(i.style,{display:"none",fontSize:S.sub,color:h.errText}),s.addEventListener("input",()=>{const n=t(s.value);i.textContent=n??"",i.style.display=n?"":"none",s.setAttribute("aria-invalid",String(!!n)),s.style.borderColor=n?h.errText:h.menuBorder}),s.addEventListener("keydown",n=>{n.key==="Escape"&&(n.stopPropagation(),s.blur())}),m.append(s,i),{el:m,input:s}}const E=(a,e,d)=>{const t=r.createElement("button");return t.type="button",t.textContent=a,t.dataset[e]="1",Object.assign(t.style,{...z("outlined"),fontSize:S.body}),$(t),t.addEventListener("click",d),t};function j(a,e){if(a.replaceChildren(),!e)return;const{rows:d,total:t,error:p}=V(e,x.testDefs),m=(s,i)=>{const n=r.createElement("div");n.textContent=s,i&&(n.style.color=i),a.appendChild(n)};if(d.length===0){m("This series has no tests yet, so there are no names to show.");return}m(p||!e.xFromName?"The names of these tests (write a pattern with {x} where the number is):":"What the pattern reads from the first names:");for(const s of d){const i=s.name===void 0?"(not in this data)":`\u201C${s.name}\u201D`;if(p||!e.xFromName){m(`${s.test} ${i}`);continue}const n=typeof s.x=="number"?`\u2192 ${s.x}`:s.x===null?"\u2192 no match":`\u2192 unclear: \u201C${s.x.ambiguous}\u201D could be milli or mega`;m(`${s.test} ${i} ${n}`,typeof s.x=="number"?void 0:h.errText)}t>d.length&&m(`\u2026 and ${t-d.length} more`)}function L(){const a=r.createElement("details");a.dataset.wmapSweepExamples="1",Object.assign(a.style,{fontSize:S.sub,color:h.label});const e=r.createElement("summary");e.textContent="Pattern examples",Object.assign(e.style,{cursor:"pointer"}),$(e,"bare"),a.appendChild(e);const d=r.createElement("div");Object.assign(d.style,{display:"flex",flexDirection:"column",gap:f.sm,paddingTop:f.sm});for(const p of P){const m=r.createElement("div");m.textContent=`\u201C${p.name}\u201D with ${p.pattern} reads ${p.reads}`+(p.note?` (${p.note})`:""),d.appendChild(m)}const t=r.createElement("div");return t.textContent=k,t.style.fontStyle="italic",d.appendChild(t),a.appendChild(d),a}function F(a,e,d){const t=r.createElement("div");t.dataset.wmapSweepSeries=String(e),Object.assign(t.style,{display:"flex",flexDirection:"column",gap:f.md,padding:f.lg,border:`1px solid ${h.menuBorder}`,borderRadius:O.control});const p=r.createElement("div");Object.assign(p.style,{display:"flex",gap:f.md,alignItems:"center"});const m=g(a.label,`Series ${e+1} name`,`Series ${e+1}`,l=>{u(o=>{o.sweep.series[e].label=l.trim()===""?`Series ${e+1}`:l})});m.el.style.flex="1",p.appendChild(m.el),d>1&&p.appendChild(E("Remove","wmapSweepRemoveSeries",()=>{u(l=>{l.sweep.series.splice(e,1)}),v()})),t.appendChild(p);let s;const i=g(D(a.tests),`Series ${e+1} tests`,"1010, 1011, 1020..1030",l=>{const o=R(l);if(!o.ok)return o.error;u(c=>{c.sweep.series[e].tests=o.value}),s?.()},{mono:!0});i.input.dataset.wmapSweepTests=String(e),t.appendChild(b(r,"Tests, in sweep order",i.el,"Test numbers, or a range such as 1010..1030 for the tests declared between them."));const n=B(a);if(t.appendChild(b(r,"X value of each test",A([["order","Test order"],["values","Values"],["name","From test name"]],n,l=>{u(o=>{const c=o.sweep.series[e];delete c.xValues,delete c.xFromName,l==="values"&&(c.xValues=[]),l==="name"&&(c.xFromName="")}),v()},r,!0))),n==="values"){const l=g(T(a.xValues??[]),`Series ${e+1} X values`,"0, 5, 10",o=>{const c=N(o);if(!c.ok)return c.error;u(C=>{C.sweep.series[e].xValues=c.value})},{mono:!0});t.appendChild(b(r,"X values",l.el,"One per test, in the same order. A different count is reported on the chart, which then uses test order."))}else if(n==="name"){const l=g(a.xFromName??"",`Series ${e+1} name pattern`,"LRS_STATS_{x}",o=>{u(c=>{c.sweep.series[e].xFromName=o}),s?.()});if(t.appendChild(b(r,"Name pattern",l.el,"{x} reads a number from each test\u2019s name, * matches any text and ? any one character. The pattern may match anywhere in the name: \u201C@ {x}\u201D reads 0.55 from \u201CFmax @ 0.55 V\u201D.")),t.appendChild(L()),x.testDefs){const o=r.createElement("div");o.dataset.wmapSweepNames=String(e),Object.assign(o.style,{display:"flex",flexDirection:"column",gap:f.xxs,fontSize:S.sub,color:h.label,fontVariantNumeric:"tabular-nums"}),s=()=>j(o,y.sweep?.series[e]),s(),t.appendChild(o)}}else{const l=r.createElement("div");l.textContent="The X axis is the position in the run, labelled by test number. No scale between the tests is assumed.",Object.assign(l.style,{fontSize:S.sub,color:h.label}),t.appendChild(l)}return t}function v(){w.replaceChildren();const a=y.sweep??{series:[]},e=g(y.title??"","Sweep title","Sweep",i=>{u(n=>{i.trim()===""?delete n.title:Object.assign(n,{title:i})})});e.input.dataset.wmapSweepTitle="1",w.appendChild(b(r,"Title",e.el));const d=r.createElement("div");Object.assign(d.style,{display:"flex",flexDirection:"column",gap:f.md}),a.series.forEach((i,n)=>d.appendChild(F(i,n,a.series.length))),w.appendChild(d),w.appendChild(E("+ Add series","wmapSweepAddSeries",()=>{u(i=>{i.sweep.series.push({label:`Series ${i.sweep.series.length+1}`,tests:[]})}),v()}));const t=r.createElement("div");Object.assign(t.style,{display:"flex",flexDirection:"column",gap:f.md,padding:f.lg,border:`1px solid ${h.menuBorder}`,borderRadius:O.control});const p=r.createElement("div");p.textContent="Axes and measurements",Object.assign(p.style,{fontSize:S.body,fontWeight:"600",color:h.value}),t.appendChild(p);const m=(i,n,l)=>{const o=g(a[i]??"",n,l,c=>{u(C=>{c.trim()===""?delete C.sweep[i]:C.sweep[i]=c})});return b(r,n,o.el)},s=r.createElement("div");if(Object.assign(s.style,{display:"grid",gridTemplateColumns:"1fr 1fr",gap:f.md}),s.append(m("xLabel","X title","automatic"),m("xUnit","X unit","e.g. V, Hz")),t.append(s,m("yLabel","Y title","automatic")),t.appendChild(b(r,"X scale",A([["linear","Linear"],["log","Log"]],a.xScale??"linear",i=>{u(n=>{i==="log"?n.sweep.xScale="log":delete n.sweep.xScale})},r),"Log needs every X value to be positive; the chart says so otherwise.")),a.series.length>=2){t.appendChild(W("Mark where the first two series cross",a.crossing??!0,n=>{u(l=>{l.sweep.crossing=n})},r));const i=g(T(a.separationAt??[]),"Widths at levels","1.2, 2.5",n=>{const l=N(n);if(!l.ok)return l.error;u(o=>{l.value.length?o.sweep.separationAt=l.value:delete o.sweep.separationAt})},{mono:!0});t.appendChild(b(r,"Width between the first two series at these Y levels",i.el,"Optional. In the tests\u2019 own unit."))}w.appendChild(t)}return v(),{el:w,setPlot(a){y=a,v()}}}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CsvColumn } from '../core/tableCsv.js';
|
|
2
|
+
import { type SaveTextHandler } from './toolbar.js';
|
|
3
|
+
export type { CsvCell, CsvColumn } from '../core/tableCsv.js';
|
|
4
|
+
/** Cells (rows × columns) from which a table is written in slices as a Blob. */
|
|
5
|
+
export declare const LARGE_EXPORT_CELLS = 1000000;
|
|
6
|
+
export interface ExportCsvOptions {
|
|
7
|
+
/** Row count, when `rows` is not an array — decides small vs large. Unknown → large. */
|
|
8
|
+
rowCount?: number;
|
|
9
|
+
/** Called after each slice of a large export with the rows written so far.
|
|
10
|
+
* Never called for a small export, which finishes before it could be shown. */
|
|
11
|
+
onProgress?: (rowsWritten: number, rowCount: number | undefined) => void;
|
|
12
|
+
/** Override {@link LARGE_EXPORT_CELLS}; for tests. */
|
|
13
|
+
largeCells?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Write `rows` as CSV and save it as `filename` via `onSaveText` (or the browser
|
|
17
|
+
* download). Returns `void` for a small table, which is saved before it returns,
|
|
18
|
+
* and a promise for a large one, which resolves once the host has been handed the
|
|
19
|
+
* Blob (not once the user has finished a native dialog).
|
|
20
|
+
*/
|
|
21
|
+
export declare function exportCsv<R>(columns: readonly CsvColumn<R>[], rows: Iterable<R>, filename: string, onSaveText?: SaveTextHandler, options?: ExportCsvOptions): void | Promise<void>;
|
|
22
|
+
//# sourceMappingURL=tableExport.d.ts.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{csvLines as x}from"../core/tableCsv.js";import{saveTextFile as L}from"./toolbar.js";export const LARGE_EXPORT_CELLS=1e6;const m=30,C=1<<20,_=()=>new Promise(e=>setTimeout(e,0));export function exportCsv(e,t,r,s,o={}){const n=Array.isArray(t)?t.length:o.rowCount;if(!(n===void 0||n*e.length>=(o.largeCells??LARGE_EXPORT_CELLS))){L(Array.from(x(e,t)).join(`
|
|
2
|
+
`),r,"text/csv",s);return}return v(e,t,n,r,s,o)}async function v(e,t,r,s,o,n){const c=[];let i=[],l=0;const p=()=>{i.length&&c.push(new Blob([i.join("")])),i=[],l=0};let g=performance.now(),f=0,a=!0;for(const u of x(e,t)){const h=a?u:`
|
|
3
|
+
`+u;i.push(h),l+=h.length,a||f++,a=!1,l>=C&&p(),performance.now()-g>=m&&(n.onProgress?.(f,r),await _(),g=performance.now())}p(),n.onProgress?.(f,r),L(new Blob(c,{type:"text/csv"}),s,"text/csv",o)}
|
|
@@ -320,6 +320,12 @@ export type SaveImageHandler = (blob: Blob, suggestedName: string) => void | Pro
|
|
|
320
320
|
* @param onSaveImage optional host hook; when present, bypasses `<a download>`
|
|
321
321
|
*/
|
|
322
322
|
export declare function saveImageBlob(blob: Blob, filename: string, onSaveImage?: SaveImageHandler): void;
|
|
323
|
+
/**
|
|
324
|
+
* Keeps a control out of printed output. Buttons that act on the screen (Edit, Delete, Save as PNG, Expand) are
|
|
325
|
+
* meaningless on paper and push the content they sit beside out of place. A single rule, added to the document once, that
|
|
326
|
+
* only matches elements carrying the attribute, so it cannot affect anything it was not asked to.
|
|
327
|
+
*/
|
|
328
|
+
export declare function markNoPrint(el: HTMLElement): void;
|
|
323
329
|
/**
|
|
324
330
|
* The browser's default save: a `<a download>` click. The one copy, used when
|
|
325
331
|
* no host hook is supplied — by `saveImageBlob`, `saveTextFile`, and the
|
|
@@ -330,10 +336,16 @@ export declare function downloadBlob(blob: Blob, filename: string): void;
|
|
|
330
336
|
* Host hook for saving a text file (CSV, etc). Mirrors `SaveImageHandler` —
|
|
331
337
|
* when provided, `saveTextFile` calls this instead of triggering a browser
|
|
332
338
|
* `<a download>`, letting embedded hosts (Tauri, Electron, WebView2) route
|
|
333
|
-
* the text through a native save dialog. Receives the
|
|
339
|
+
* the text through a native save dialog. Receives the content, a
|
|
334
340
|
* `suggestedName` (already includes its extension), and the `mimeType`.
|
|
341
|
+
*
|
|
342
|
+
* **The content is a `string`, or a `Blob` for a large table.** A table of a
|
|
343
|
+
* few million cells or more is written in pieces and handed over as a `Blob`
|
|
344
|
+
* (see `exportCsv`), because one string that size can exceed the engine's
|
|
345
|
+
* string limit and doubles the memory in use while it is joined. A host must
|
|
346
|
+
* handle both: for a file, write `blob.stream()`; to read it, `await blob.text()`.
|
|
335
347
|
*/
|
|
336
|
-
export type SaveTextHandler = (text: string, suggestedName: string, mimeType: string) => void | Promise<void>;
|
|
348
|
+
export type SaveTextHandler = (text: string | Blob, suggestedName: string, mimeType: string) => void | Promise<void>;
|
|
337
349
|
/**
|
|
338
350
|
* A callback for "a panel just opened or closed beside the map in this box": widens the box by the
|
|
339
351
|
* room the panel took when it opens, and gives it back when it closes. Pass it to whatever
|
|
@@ -369,7 +381,7 @@ export declare function openCompactDiagnostics(dies: readonly {
|
|
|
369
381
|
* @param mimeType e.g. `'text/csv'`
|
|
370
382
|
* @param onSaveText optional host hook; when present, bypasses `<a download>`
|
|
371
383
|
*/
|
|
372
|
-
export declare function saveTextFile(text: string, filename: string, mimeType: string, onSaveText?: SaveTextHandler): void;
|
|
384
|
+
export declare function saveTextFile(text: string | Blob, filename: string, mimeType: string, onSaveText?: SaveTextHandler): void;
|
|
373
385
|
/**
|
|
374
386
|
* Run `fn` on the next animation frame, falling back to a macrotask in
|
|
375
387
|
* environments without `requestAnimationFrame` (e.g. JSDOM under tests).
|
|
@@ -716,6 +728,16 @@ export interface OverlayOptions {
|
|
|
716
728
|
* where printing must target `iframe.contentWindow.print()`.
|
|
717
729
|
*/
|
|
718
730
|
printable?: boolean | (() => void);
|
|
731
|
+
/**
|
|
732
|
+
* Show the Maximize button, and honour the F shortcut. Default `true`. A small confirmation has nothing to gain from
|
|
733
|
+
* filling the window, and a Maximize button on it is a control that does nothing useful.
|
|
734
|
+
*/
|
|
735
|
+
maximizable?: boolean;
|
|
736
|
+
/**
|
|
737
|
+
* The element to focus once the overlay has opened. Default: its close button. A confirmation names its safe answer
|
|
738
|
+
* here, so a stray Enter cannot be the thing that confirms.
|
|
739
|
+
*/
|
|
740
|
+
initialFocus?: () => HTMLElement | null | undefined;
|
|
719
741
|
}
|
|
720
742
|
export interface OverlayHandle {
|
|
721
743
|
/** null in 'window' mode — there is no backdrop to block the page. */
|
|
@@ -932,98 +954,4 @@ export declare function makeOrientationBtn(helpers: ToolbarHelpers, getOpts: ()
|
|
|
932
954
|
flipY?: boolean;
|
|
933
955
|
showXYIndicator?: boolean;
|
|
934
956
|
}) => void): HTMLButtonElement;
|
|
935
|
-
type GuideApi = {
|
|
936
|
-
buildWaferMap: unknown;
|
|
937
|
-
renderWaferMap: unknown;
|
|
938
|
-
renderWaferGallery: unknown;
|
|
939
|
-
analyzeWaferMap: unknown;
|
|
940
|
-
};
|
|
941
|
-
/**
|
|
942
|
-
* Host-supplied content inserted into wmap's own embedded user-guide window,
|
|
943
|
-
* so a host app's own documentation and wmap's reference live behind one
|
|
944
|
-
* help button instead of two separate ones.
|
|
945
|
-
*/
|
|
946
|
-
export interface UserGuideExtension {
|
|
947
|
-
/**
|
|
948
|
-
* Host-provided HTML, inserted before wmap's own guide content. Static
|
|
949
|
-
* content only — must not contain `<script>` tags. wmap re-executes
|
|
950
|
-
* exactly one inline script (its own live-demo bootstrap, always the
|
|
951
|
-
* last element in `html`) by finding the content div's first
|
|
952
|
-
* `<script>` in document order; a `<script>` in this HTML would be
|
|
953
|
-
* found instead, silently breaking wmap's own live demos.
|
|
954
|
-
*/
|
|
955
|
-
html: string;
|
|
956
|
-
/**
|
|
957
|
-
* Overrides the window's title text (default `'Wafer Map — User Guide'`).
|
|
958
|
-
* Use this when the host's own content should frame the whole document —
|
|
959
|
-
* wmap's own `<h1>` stays as-is further down the page, so the result
|
|
960
|
-
* reads as one combined guide with the host's section first, not a title
|
|
961
|
-
* rewrite.
|
|
962
|
-
*/
|
|
963
|
-
title?: string;
|
|
964
|
-
}
|
|
965
|
-
/**
|
|
966
|
-
* Open the embedded user-guide window and populate its live demos. Closes any
|
|
967
|
-
* previously open guide window first (at most one may be open at a time).
|
|
968
|
-
* `api` must contain the four library functions the guide demos call at runtime.
|
|
969
|
-
* `html` is USER_GUIDE_HTML — passed in so toolbar.ts has no dependency on userGuideHtml.ts.
|
|
970
|
-
* `extension`, when provided, prepends host content and/or overrides the window title — see `UserGuideExtension`.
|
|
971
|
-
*
|
|
972
|
-
* Opens a real, separate window when available (draggable outside the host
|
|
973
|
-
* window's own bounds), falling back to the in-page floating window when
|
|
974
|
-
* `window.open` is blocked/unavailable — silently returns `null` in some
|
|
975
|
-
* embedded WebViews (Tauri, Electron, WebView2), same gap `openDetachWindow`
|
|
976
|
-
* exists for. Unlike gallery card detach, this doesn't go through
|
|
977
|
-
* `setDetachWindowOpener` — that opener's contract is scoped to per-wafer
|
|
978
|
-
* detach windows a host may have built specifically for that shape of
|
|
979
|
-
* content, and reusing it silently for the guide would broaden it without
|
|
980
|
-
* documentation.
|
|
981
|
-
*/
|
|
982
|
-
export declare function openUserGuideWindow(api: GuideApi, html: string, extension?: UserGuideExtension, anchor?: Element): void;
|
|
983
|
-
/**
|
|
984
|
-
* Opens wmap's own guide window with no live `WaferMapController`/
|
|
985
|
-
* `GalleryController` required — `WaferMapController.openUserGuide()`/
|
|
986
|
-
* `GalleryController.openUserGuide()` are thin wrappers around this exact
|
|
987
|
-
* same call (see their own `openGuideWindow` closures in `renderWaferMap.ts`/
|
|
988
|
-
* `renderWaferGallery.ts`), built from the library's own top-level functions
|
|
989
|
-
* rather than anything derived from a specific render — so a host with
|
|
990
|
-
* nothing rendered yet (e.g. an empty-state "Help" menu, before any file is
|
|
991
|
-
* loaded) can reach the same guide, with the same `extension` content, the
|
|
992
|
-
* same way. Prefer the controller method when one exists — this is for the
|
|
993
|
-
* gap it can't cover.
|
|
994
|
-
*
|
|
995
|
-
* `renderWaferMap`/`renderWaferGallery` are dynamically imported (like
|
|
996
|
-
* `USER_GUIDE_HTML` below) since `toolbar.ts` is itself imported BY both of
|
|
997
|
-
* them — a static import here would cycle back.
|
|
998
|
-
*/
|
|
999
|
-
export declare function openWaferMapGuide(extension?: UserGuideExtension, anchor?: Element): void;
|
|
1000
|
-
/**
|
|
1001
|
-
* Opens report HTML (from `renderSummaryReportHtml`/`renderLotSummaryReportHtml`)
|
|
1002
|
-
* in an in-app modal — no host-registered `setReportOpener` required just to
|
|
1003
|
-
* *view* a report. `setReportOpener`/`openHtmlReport` remain available as an
|
|
1004
|
-
* "Open as full page" action inside this modal (its header's print button, plus
|
|
1005
|
-
* a link in the toolbar strip below it), for a host that wants the report as a
|
|
1006
|
-
* real separate page — to keep it open outside this modal, or as a fallback if
|
|
1007
|
-
* in-app printing misbehaves on a given platform.
|
|
1008
|
-
*
|
|
1009
|
-
* The report HTML is a complete standalone document (its own `<style>`, its own
|
|
1010
|
-
* `<!DOCTYPE html>`) — rendered via `<iframe srcdoc>` rather than parsed apart
|
|
1011
|
-
* and inserted into the modal's own DOM (the way the guide's `buildGuideContent`
|
|
1012
|
-
* does it). This keeps the report's stylesheet naturally isolated from the host
|
|
1013
|
-
* page with no parsing, and lets `iframe.contentWindow.print()` scope printing
|
|
1014
|
-
* to just the report — `openOverlay`'s sibling-hiding print stylesheet (built
|
|
1015
|
-
* for content that lives directly in the host document, like the guide) isn't
|
|
1016
|
-
* needed here and wouldn't reach into the iframe's own document anyway.
|
|
1017
|
-
*/
|
|
1018
|
-
export declare function openReportModal(html: string, opts?: {
|
|
1019
|
-
anchor?: Element;
|
|
1020
|
-
ownerDocument?: Document;
|
|
1021
|
-
/**
|
|
1022
|
-
* A report built with `live` tells this page which finding a click on its row meant. Called with that
|
|
1023
|
-
* finding's id and the modal's handle, so the host can close the modal and show the finding on the map.
|
|
1024
|
-
* Only messages from this report's own frame are heeded.
|
|
1025
|
-
*/
|
|
1026
|
-
onFinding?: (findingId: string, handle: OverlayHandle) => void;
|
|
1027
|
-
}): OverlayHandle;
|
|
1028
|
-
export {};
|
|
1029
957
|
//# sourceMappingURL=toolbar.d.ts.map
|