import { type SaveImageHandler } from '../toolbar.js';
export type { SaveImageHandler };
/**
 * `triggerBtn`, when given, is hidden for the modal's duration and shown
 * again on close — a card already sitting inside its own expand modal must
 * not offer a second "expand" of itself: clicking it would reparent the same
 * card into a *second*, nested modal, leaving the first one open but empty
 * (found via exactly that — every card kept its expand icon once expanded).
 */
export declare function openChartExpandModal(card: HTMLElement, title: string, triggerBtn?: HTMLButtonElement): void;
export interface ChartCanvasColors {
    text: string;
    textMuted: string;
    border: string;
    bg: string;
    bgHover: string;
    /** Subtle bar/row "track" background (full-extent backdrop behind a value bar) — deliberately much softer than `border`, which reads as a visible grey line/fill, not a backdrop. */
    track: string;
    warnBorder: string;
}
/** Resolve `--wmap-*` custom properties to concrete color strings for canvas
 *  drawing. Call once per draw (not cached) so a live theme change is picked
 *  up on the next redraw, matching `resolveCanvasTheme`'s own contract. */
export declare function resolveChartCanvasColors(el: HTMLElement): ChartCanvasColors;
export declare const PADDING = 12;
export declare const VALUE_WIDTH = 100;
export declare function observeResize(el: HTMLElement, onResize: () => void): {
    disconnect: () => void;
};
/**
 * Sets `card`'s own min-height so `body` can actually display
 * `contentHeight` px of content without `body`'s own `overflow-y: auto`
 * (see `cardShell`) silently turning any shortfall into a scrollbar.
 * Computed from `card`'s *live* chrome overhead (heading row, hint text,
 * padding) — not a guessed constant passed in from elsewhere, so it can
 * never drift out of sync with what the panel actually needs (a fixed
 * `card.style.minHeight` guessed once by the composer, as `analysisTab.ts`
 * used to do, drifts the moment hint text length or content height changes).
 *
 * Always *sets* the value fresh, never just grows it — `card`'s container
 * isn't always monotonically growing. The chart-expand modal
 * (`openChartExpandModal`) reparents this same card into a *resizable* box
 * (drag-resize, maximize/restore); a "only grow, never shrink" policy would
 * leave a stale, too-large min-height stuck from a bigger prior size after
 * the modal shrinks, forcing the exact overflow this function exists to
 * prevent. Recomputing from `card`'s current live overhead every call is
 * self-correcting in both directions and converges in one extra resize-
 * observer pass (chrome overhead doesn't change with `card`'s own height,
 * so the fixed point is reached immediately, not oscillating).
 *
 * The Analysis tab composes several of these cards into one CSS Grid row
 * per section (`makeChartGridWrap`); nothing about that grid's own row
 * auto-sizing knows a card needs more room unless the card itself asks for
 * it via `min-height` — a `position: absolute` canvas (`applyCanvasFlow`) is
 * out of normal flow and invisible to it, and even an in-flow one won't ask
 * on its own before this runs.
 *
 * Shared by two different content-sizing patterns:
 * - `chartFillHeight` below: canvas fills whatever's left in `body`.
 * - Panels with a fixed row cap and their own deliberate inner scroll area
 *   for the rest (`barPanel.ts`, `boxplot.ts`, `binCluster.ts`) call this
 *   directly with their visible-rows height.
 */
export declare function growCardToFitContent(card: HTMLElement, body: HTMLElement, contentHeight: number): void;
/**
 * Canvas height for a "fill the body" chart: siblings already in `body`
 * above the canvas (a stats label, a legend, ...) get their own natural
 * height, and the canvas gets whatever's left — floored at `minHeight` so
 * it never renders squashed below its own readable minimum. See
 * `growCardToFitContent` above for how `card` is kept large enough to
 * actually deliver that floor.
 */
export declare function chartFillHeight(card: HTMLElement, body: HTMLElement, canvas: HTMLCanvasElement, minHeight: number): number;
export declare function applyCanvasFlow(canvas: HTMLCanvasElement, topOffset?: number): void;
/**
 * Format a bare numeric value (no unit) for chart labels/tooltips —
 * callers append their own unit string separately when they have one. Uses
 * `fmt`'s engineering-notation fallback (fixed decimal for [0.1, 9999],
 * `NEexp` outside that range) rather than a plain `.toFixed(2)`, which
 * silently collapsed small-scale measurements (e.g. a 33.3 pA mean, as
 * `3.33e-11`) to a misleading "0.00".
 */
export declare function formatValue(v: number): string;
/**
 * Shared axis formatter for a numeric chart axis: one SI scale chosen from
 * the largest-magnitude endpoint, applied to every tick, with the scaled
 * unit returned once as the axis label (e.g. ticks "861 · 1040 · 1220"
 * with label "(µA)") — the same `fmtColorbarAxis` contract the map's
 * colorbar uses, so axes never show raw exponent soup like "861E-6" next
 * to a tooltip that says "861 µA". Falls back to `formatValue` ticks and
 * no label when the test has no unit.
 */
export declare function makeAxisFormat(vRef: number, unit: string | undefined): {
    tick: (v: number) => string;
    unitLabel: string;
};
/** Draw a small "(unit)" label at (x, y), restoring the context's text state afterward. */
export declare function drawAxisUnit(ctx: CanvasRenderingContext2D, unit: string, x: number, y: number, color: string): void;
export declare function saveCanvasPng(canvas: HTMLCanvasElement, filenameStem: string, onSaveImage?: SaveImageHandler): void;
export interface CardShell {
    card: HTMLElement;
    heading: HTMLElement;
    controlsRow: HTMLElement;
    body: HTMLElement;
}
export declare function cardShell(title: string, onSaveImage?: SaveImageHandler): CardShell;
export declare function makeSegmented(options: Array<[value: string, label: string]>, current: string, onChange: (value: string) => void): HTMLElement;
export declare function makeBackButton(onBack: () => void): HTMLButtonElement;
export declare function renderEmptyState(body: HTMLElement, message: string, styleOverrides?: Partial<CSSStyleDeclaration>): void;
export interface TestSelectItem {
    testNumber: number;
    name?: string;
}
/**
 * Below `MENU_SEARCH_THRESHOLD` tests this is a plain native `<select>`. Past
 * it, a long native dropdown becomes hard to scan, so it's replaced by a
 * button + filterable popup list (`makeSearchableTestCombo` below) — sharing
 * `makeMenuSearchBox` with the plot-mode test-value cascade submenu
 * (toolbar.ts's `buildModeMenuEl`) so both long test lists get the same
 * filter-as-you-type box instead of two independent implementations. Either
 * shape exposes a settable `.value` (string of the testNumber, same as a real
 * `<select>`) so callers (boxplot/histogram/scatter, syncing from an external
 * click-through) don't need to know which one they got.
 */
export declare function makeTestSelect(testOptions: readonly TestSelectItem[], selected: number | null, onChange: (testNumber: number) => void, opts?: {
    maxWidth?: string;
    emptyText?: string;
}): HTMLElement & {
    value: string;
};
export interface WaferSelectItem {
    label?: string;
}
export declare function makeWaferSelect(items: readonly WaferSelectItem[], selectedIndex: number | null, onChange: (index: number | null) => void, opts?: {
    maxWidth?: string;
    allLabel?: string;
}): HTMLSelectElement;
export declare function makeToggle(labelText: string, checked: boolean, onChange: (v: boolean) => void): HTMLLabelElement;
export declare function makeLabeledSelect(labelText: string, options: readonly {
    value: string;
    label: string;
}[], selected: string, onChange: (value: string) => void, opts?: {
    maxWidth?: string;
    hook?: string;
}): HTMLLabelElement;
export declare function makeChartGridWrap(): HTMLDivElement;
/** Small positioned hover tooltip, matching the pattern each ported panel builds for itself. */
export declare function makeTooltip(card: HTMLElement): HTMLElement;
/**
 * Position a `makeTooltip` element from a mousemove event, flipping to the
 * opposite side of the cursor when the default placement would overflow
 * `card`'s own bounds (the tooltip is an absolutely-positioned child of
 * `card`, so staying within its rect keeps it on-screen without needing the
 * window's own bounds).
 */
export declare function positionChartTooltip(tooltip: HTMLElement, card: HTMLElement, clientX: number, clientY: number): void;
//# sourceMappingURL=chartShell.d.ts.map