/**
 * A topological layout using {@link Grid}.
 *
 * @packageDocumentation
 */
import type { Graph, Rank } from "../graph";
import type { LayoutResult, NodeSize } from "../layout";
import type { Tweak } from "../tweaks";
import { type U } from "../utils";
import type { Lane } from "./lane";
import { type LaneGreedy } from "./lane/greedy";
/** all operators for the grid layout */
export interface GridOps<in N = never, in L = never> {
    /** the operator for assigning nodes to a lane */
    lane: Lane<N, L>;
    /** the operator for assigning nodes a rank */
    rank: Rank<N, L>;
    /** node size operator */
    nodeSize: NodeSize<N, L>;
    /** tweaks */
    tweaks: readonly Tweak<N, L>[];
}
/**
 * A simple grid based topological layout operator.
 *
 * This layout algorithm constructs a topological representation of the dag
 * meant for visualization. The nodes are topologically ordered and then nodes
 * are put into lanes such that an edge can travel horizontally to the lane of
 * a child node, and then down without intersecting to that child.
 *
 * Create with {@link grid}.
 */
export interface Grid<Ops extends GridOps = GridOps> {
    /**
     * layout a graph with the grid layout
     *
     * @param grf - the graph to layout
     * @returns dimensions - the width and height of the final layout
     */
    (grf: Ops extends GridOps<infer N, infer L> ? Graph<N, L> : never): LayoutResult;
    /**
     * set a custom {@link Lane} operator
     *
     * The lane operator controls how nodes are assigned to horizontal lanes.
     * This is the core piece of the layout. There are two builtin lane operators:
     * - {@link laneGreedy} - This is a fast reasonably effective lane operator.
     *   It supports a number of further tweaks to alter the layout.
     * - {@link laneOpt} - This assigns lanes to optimally minimize the number of
     *   edge crossings. This optimization is NP Hard, so outside of very small
     *   graphs, it will likely take too long to execute.
     *
     * You can also supply any function that satisfies the {@link Lane}
     * interface. See that documentation for more information about implementing
     * your own lane assignment.
     *
     * (default: {@link laneGreedy})
     *
     * @example
     *
     * ```ts
     * const layout = grid().lane(laneOpt());
     * ```
     *
     */
    lane<NewLane extends Lane>(val: NewLane): Grid<U<Ops, "lane", NewLane>>;
    /** get the current lane operator */
    lane(): Ops["lane"];
    /**
     * set the rank operator for the topological ordering
     *
     * Set the rank operator to the given {@link Rank} and returns a new
     * version of this operator.
     *
     * (default: noop)
     */
    rank<NewRank extends Rank>(val: NewRank): Grid<U<Ops, "rank", NewRank>>;
    /** get the current rank operator */
    rank(): Ops["rank"];
    /**
     * set the {@link Tweak}s to apply after layout
     */
    tweaks<const NewTweaks extends readonly Tweak[]>(val: NewTweaks): Grid<U<Ops, "tweaks", NewTweaks>>;
    /**
     * get the current {@link Tweak}s.
     */
    tweaks(): Ops["tweaks"];
    /**
     * Sets this grid layout's node size to the specified two-element array of
     * numbers [ *width*, *height* ] and returns a new operator. These sizes are
     * effectively the grid size, e.g. the spacing between adjacent lanes or rows
     * in the grid.
     *
     * (default: `[1, 1]`)
     */
    nodeSize<NewNodeSize extends NodeSize>(val: NewNodeSize): Grid<U<Ops, "nodeSize", NewNodeSize>>;
    /** Get the current node size */
    nodeSize(): Ops["nodeSize"];
    /**
     * Set the gap size between nodes
     *
     * (default: `[1, 1]`)
     */
    gap(val: readonly [number, number]): Grid<Ops>;
    /** Get the current gap size */
    gap(): readonly [number, number];
}
/** the default grid operator */
export type DefaultGrid = Grid<{
    /** default lane: greedy */
    lane: LaneGreedy;
    /** default rank: none */
    rank: Rank<unknown, unknown>;
    /** default size */
    nodeSize: readonly [1, 1];
    /** default tweaks: none */
    tweaks: readonly [];
}>;
/**
 * create a new {@link Grid} with default settings.
 *
 * The grid layout algorithm constructs a horizontally compact topological
 * representation of the dag. The nodes are topologically ordered and then
 * put into lanes such that an edge can travel horizontally to the lane of a
 * child node, and then down without intersecting to that child.
 *
 * This layout produces good representations when you want a compressed layout
 * where each node is on an independent horizontal line.
 *
 * <img alt="grid example" src="../../resources/grid-greedy-topdown.png" width="200">
 *
 * @remarks
 *
 * The current implementation doesn't render multi-dags any differently, so
 * multiple edges going to the same node will be rendered as a single edge.
 *
 * @example
 *
 * using the default layout
 *
 * ```ts
 * const grf = ...
 * const layout = grid();
 * const { width, height } = layout(dag);
 * for (const node of dag) {
 *   console.log(node.x, node.y);
 * }
 * ```
 *
 * @example
 *
 * In addition to the standard modifications of {@link Grid#rank},
 * {@link Grid#nodeSize}, {@link Grid#gap}, and {@link Grid#tweaks},
 * {@link Grid} also supports altering the lane assignment {@link Grid#lane}:
 *
 * ```ts
 * const grf = ...
 * const layout = grid().lane(laneOpt());
 * const { width, height } = layout(dag);
 * for (const node of dag) {
 *   console.log(node.x, node.y);
 * }
 * ```
 */
export declare function grid(...args: never[]): DefaultGrid;
