/**
 * Utilities and types common to all layouts
 *
 * @packageDocumentation
 */
import type { Graph, GraphNode } from "./graph";
import type { Tweak } from "./tweaks";
/**
 * A strictly callable {@link NodeSize}
 */
export type CallableNodeSize<NodeDatum = never, LinkDatum = never> = (node: GraphNode<NodeDatum, LinkDatum>) => readonly [number, number];
/**
 * an accessor for computing the size of a node in the layout
 *
 * A node size can either be a constant tuple of `[width, height]`, or a
 * callable, that takes a node and returns the width and height for that node.
 *
 * @remarks
 *
 * Due to the way that d3-dag (and typescript) infers types, a constant
 * function (e.g. `() => [1, 1]`) may infer data types as `never` producing
 * errors down the line. In these cases, you'll want to use a constant tuple.
 *
 * @example
 *
 * This example sets the node width to the length of the name. In most cases
 * you'd probably want to actually render the text and measure the size, rather
 * than assume a fixed width, but this example is easier to understand.
 *
 * ```ts
 * function widthSize({ data }: GraphNode<{ name: string }>): [number, number] {
 *   return [data.name.length, 1];
 * }
 * ```
 */
export type NodeSize<NodeDatum = never, LinkDatum = never> = readonly [number, number] | CallableNodeSize<NodeDatum, LinkDatum>;
/** An accessor for computing the length of a node */
export type NodeLength<in NodeDatum = never, in LinkDatum = never> = (node: GraphNode<NodeDatum, LinkDatum>) => number;
/**
 * cache a {@link NodeSize} so it is called at most once for every node
 */
export declare function cachedNodeSize<N, L>(nodeSize: NodeSize<N, L>): CallableNodeSize<N, L>;
/**
 * split a {@link NodeSize} into x and y {@link NodeLength}s
 *
 * This allows you to split a NodeSize into independent x and y accessors.
 *
 * The only real reason to use this would be to run the steps of
 * {@link sugiyama} independently.
 */
export declare function splitNodeSize<N, L>(nodeSize: NodeSize<N, L>): readonly [NodeLength<N, L>, NodeLength<N, L>];
/** direction of layout */
export type Rankdir = "TB" | "BT" | "LR" | "RL";
/** the height and width returned after laying out a graph */
export interface LayoutResult {
    /** the total width after layout */
    width: number;
    /** the total height after layout */
    height: number;
}
/**
 * how to handle optimally solving certain layouts
 *
 * - `"fast"` - raise an exception if the layout can't be done quickly
 * - `"slow"` - raise an exception if the layout might oom
 * - `"oom"` - never raise an exception, use at your own risk
 */
export type OptChecking = "fast" | "slow" | "oom";
/**
 * common interface shared by all layout operators
 *
 * {@link Sugiyama}, {@link Zherebko}, and {@link Grid} all satisfy this
 * interface, allowing code that is agnostic to the specific layout algorithm.
 */
export interface Operator<in N = never, in L = never> {
    /** run the layout */
    (graph: Graph<N, L>): LayoutResult;
    /** get current tweaks */
    tweaks(): readonly Tweak<N, L>[];
    /** set tweaks */
    tweaks(val: readonly Tweak<N, L>[]): Operator<N, L>;
    /** set node size accessor */
    nodeSize(val: NodeSize<N, L>): Operator<N, L>;
    /** get current node size */
    nodeSize(): NodeSize<N, L>;
    /** set gap between nodes */
    gap(val: readonly [number, number]): Operator<N, L>;
    /** get current gap */
    gap(): readonly [number, number];
}
