/**
 * Dashboard graph-viz tab renderer — embeds graphify's vis.js viewer.
 *
 * Sprint 3 pivot (2026-05-27): rather than build a custom cytoscape
 * tier drill-down, we embed the interactive viewer graphify itself
 * ships. The upstream `graphify.export.to_html` writes a self-
 * contained vis.js HTML page to `.dxkit/reports/graph.html` as a
 * side-effect of `gatherGraphifyGraph` (see `analyzers/tools/
 * graphify.ts`). This renderer:
 *
 *   1. reads that HTML
 *   2. swaps graphify's unpkg.com `<script src=…vis-network…>` tag for
 *      an inline `<script>` containing the locally-bundled
 *      `vis-network.min.js` (offline-friendly per dxkit's posture —
 *      no third-party fetch when the user opens the dashboard)
 *   3. emits the swapped HTML inside an `<iframe srcdoc>` so the
 *      embedded viewer's CSS + JS namespace stays isolated from the
 *      host dashboard
 *
 * Empty-state branches when `graph.html` is missing (gather never
 * ran, graph exceeded the 5000-node viz cap, etc.). Vendor-missing
 * branch when `dist/dashboard/vendor/vis-network.min.js` is absent
 * (`npm run build` hasn't run).
 *
 * Per CLAUDE.md Rule 12, we still flow `graph.json` reads through
 * `loadGraph` even though the renderer doesn't consume `graph.json`
 * itself — the loader doubles as our existence check before we go
 * read `graph.html` off disk.
 */
/** Options accepted by the tab renderer. */
export interface GraphTabOptions {
    /**
     * Project root. The renderer reads `.dxkit/reports/graph.json` for
     * the existence check (via Rule 12's `loadGraph`) and then loads
     * `.dxkit/reports/graph.html` from disk for embedding.
     */
    cwd?: string;
    /**
     * Override the vendor directory. Tests pass a tmpdir with a fake
     * `vis-network.min.js` so they don't depend on `npm run build`
     * having populated `dist/dashboard/vendor/`.
     */
    vendorDir?: string;
    /**
     * Override the on-disk path to graphify's `graph.html`. Defaults
     * to `<cwd>/.dxkit/reports/graph.html`. Tests use a fixture path.
     */
    graphHtmlPath?: string;
}
/**
 * One-stop renderer. Returns:
 *   - `html`: the HTML fragment to splice into the dashboard body
 *     (the new "Graph" tab pane).
 *   - `navBadge`: the badge text the sidebar shows next to "Graph"
 *     (community count when ready; "—" otherwise).
 *   - `hasData`: convenience boolean — true when a viewable graph
 *     was found and the iframe will render.
 */
export declare function renderGraphTab(opts: GraphTabOptions): {
    html: string;
    navBadge: string;
    hasData: boolean;
};
/** Sidecar metadata produced by the graphify gather. */
interface GraphHtmlMeta {
    mode: 'full' | 'aggregated';
    totalNodes: number;
    totalEdges: number;
    communities: number;
    aggregatedNodeCount: number | null;
}
/**
 * Prepend a small banner inside graphify's `<body>` explaining that
 * the visible view is community-aggregated. Surfaced for honesty —
 * the user should understand each node is a cluster, not a symbol,
 * when the full graph exceeded the 5000-node viz cap.
 *
 * Exported for tests.
 */
export declare function injectAggregateBanner(html: string, meta: GraphHtmlMeta): string;
/**
 * Replace graphify's `<script src="https://unpkg.com/vis-network/...">`
 * with an inline `<script>` containing the bundled vis-network source.
 * The replacement is conservative — we match the upstream tag exactly
 * (with optional version pin + path variations) and bail to the
 * untouched HTML if the pattern doesn't fit. That way an upstream
 * graphify change to a different CDN URL is surfaced as "viewer works
 * online only" rather than a corrupt swap.
 *
 * Exported for tests; downstream consumers should use `renderGraphTab`.
 */
export declare function inlineVisNetwork(upstreamHtml: string, visBundle: string): string;
/**
 * HTML-encode the supplied HTML so it can sit safely inside an
 * `<iframe srcdoc="…">` attribute. Only the characters that
 * specifically break the attribute boundary — `&`, `"`, and `<` — get
 * escaped. (`<` would prematurely close the iframe's start tag in the
 * outer document if naive UTF-8 left it unescaped.)
 */
export declare function encodeForSrcdoc(html: string): string;
/**
 * CSS for the graph tab. The host dashboard at
 * `src/analyzers/dashboard/index.ts` splices this into its global
 * `<style>` block via a sibling import. The iframe gets a fixed-height
 * fill of the tab area; the empty-state card centers vertically.
 */
export declare const GRAPH_TAB_CSS = "\n.graph-tab-pane { flex: 1; flex-direction: column; padding: 24px 28px; overflow: hidden; }\n.graph-tab-empty.graph-tab-pane { display: flex; align-items: center; justify-content: center; min-height: 400px; padding: 60px 32px; }\n.graph-empty-card { text-align: center; padding: 48px 32px; background: var(--bg-card); border-radius: 12px; border: 1px solid var(--border); max-width: 640px; }\n.graph-empty-icon { font-size: 56px; margin-bottom: 16px; }\n.graph-empty-card h2 { font-size: 22px; color: var(--text-primary); margin-bottom: 12px; }\n.graph-empty-card p { color: var(--text-secondary); line-height: 1.55; }\n.graph-empty-card code { background: var(--bg-tertiary); padding: 2px 6px; border-radius: 4px; font-family: ui-monospace, \"SF Mono\", Menlo, monospace; font-size: 0.92em; }\n.graph-iframe { width: 100%; height: 100%; min-height: 600px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg-primary); }\n";
export {};
//# sourceMappingURL=graph-tab.d.ts.map