import { d as SceneCommand, i as SnapTarget, g as SnapEngine, Z as ZoomPanMath } from '../command-stack-CcWi_2bN.js';
export { A as ApplySceneResult, a as DesignCanvasMode, D as DesignCanvasProps, b as EditorSceneState, E as ExportTriggerOptions, S as SCENE_COMMAND_HISTORY_LIMIT, e as SceneCommandStack, f as SceneCommandStackWithReapply, h as SnapResult, j as SnapTargetKind, k as SnapTargets, c as createSceneCommandStack } from '../command-stack-CcWi_2bN.js';
import { d as SceneElement, N as NewPageOptions, c as SceneDocument, a as PageGuides, P as PageBleed, B as Bounds, g as ScenePage } from '../model-BBwyOuWG.js';
import { f as SceneAttrsPatch, g as SceneOperation } from '../operations-DLIvvD00.js';
import { d as ExportCropRect, f as ExportPreset } from '../export-presets-DAsU5Wal.js';
export { h as bleedAwareExportBounds, s as scaleForPreset } from '../export-presets-DAsU5Wal.js';
import '../theme/index.js';

interface AddElementInput {
    pageId: string;
    element: SceneElement;
    /** Insertion z-index within owner; omitted → top. */
    index?: number;
    /** Parent group id; omitted → page root. */
    parentGroupId?: string;
}
declare function addElementCommand(input: AddElementInput): SceneCommand;
interface SetAttrsInput {
    pageId: string;
    elementId: string;
    /** Final attribute values after the gesture. */
    attrs: SceneAttrsPatch;
    /** Attribute values BEFORE the gesture began — inverse is built from these. */
    priorAttrs: SceneAttrsPatch;
}
declare function setAttrsCommand(input: SetAttrsInput): SceneCommand;
interface MultiSetAttrsEntry {
    pageId: string;
    elementId: string;
    attrs: SceneAttrsPatch;
    priorAttrs: SceneAttrsPatch;
}
declare function multiSetAttrsCommand(entries: MultiSetAttrsEntry[]): SceneCommand;
interface ReorderElementInput {
    pageId: string;
    elementId: string;
    toIndex: number;
}
declare function reorderElementCommand(input: ReorderElementInput): SceneCommand;
interface DeleteElementInput {
    document: SceneDocument;
    pageId: string;
    elementId: string;
}
declare function deleteElementCommand(input: DeleteElementInput): SceneCommand;
interface GroupElementsInput {
    document: SceneDocument;
    pageId: string;
    elementIds: string[];
    groupId: string;
    name?: string;
}
declare function groupElementsCommand(input: GroupElementsInput): SceneCommand;
interface UngroupElementInput {
    document: SceneDocument;
    pageId: string;
    groupId: string;
}
declare function ungroupElementCommand(input: UngroupElementInput): SceneCommand;
interface AddPageInput {
    pageId: string;
    options?: NewPageOptions;
    index?: number;
}
declare function addPageCommand(input: AddPageInput): SceneCommand;
interface DuplicatePageInput {
    document: SceneDocument;
    sourcePageId: string;
    /** Caller-minted id for the copy. */
    pageId: string;
}
declare function duplicatePageCommand(input: DuplicatePageInput): SceneCommand;
interface DeletePageInput {
    document: SceneDocument;
    pageId: string;
}
declare function deletePageCommand(input: DeletePageInput): SceneCommand;
interface ReorderPageInput {
    pageId: string;
    toIndex: number;
}
declare function reorderPageCommand(input: ReorderPageInput): SceneCommand;
interface SetPagePropsInput {
    document: SceneDocument;
    pageId: string;
    props: {
        name?: string;
        width?: number;
        height?: number;
        background?: string;
        bleed?: PageBleed | null;
    };
}
declare function setPagePropsCommand(input: SetPagePropsInput): SceneCommand;
interface SetPageGuidesInput {
    document: SceneDocument;
    pageId: string;
    guides: PageGuides;
}
declare function setPageGuidesCommand(input: SetPageGuidesInput): SceneCommand;
interface BindSlotInput {
    document: SceneDocument;
    pageId: string;
    elementId: string;
    slot: string | null;
}
declare function bindSlotCommand(input: BindSlotInput): SceneCommand;
interface SetDocumentTitleInput {
    document: SceneDocument;
    title: string;
}
declare function setDocumentTitleCommand(input: SetDocumentTitleInput): SceneCommand;

/**
 * 2-axis snap engine for the design-canvas editor. Targets come from element
 * AABBs (edges + centers), page edges + center, saved guides, and grid lines
 * near the moving bounds. Grid lines are generated lazily in the neighborhood
 * of the moving element, not the full page — avoids allocating thousands of
 * targets on large pages with fine grids.
 *
 * Threshold is a SCREEN distance (pixels), divided by zoom to convert to
 * document units — what "feels close" is a screen distance.
 *
 * Tie-breaking: non-grid kinds beat grid on equal distance; among equals of
 * the same priority the first in iteration order wins.
 */

declare function createSnapEngine(): SnapEngine;
/** Generate grid line targets within a neighborhood around the moving bounds.
 *  Call this and append to `SnapTargets.vertical`/`horizontal` before
 *  passing to `apply()` when `state.gridEnabled`. */
declare function collectGridTargets(bounds: Bounds, gridSize: number, page: ScenePage, thresholdDocPx: number): {
    vertical: SnapTarget[];
    horizontal: SnapTarget[];
};

/**
 * Selection math for the design-canvas editor: marquee hit-tests, keyboard
 * nudge deltas, and the duplicate offset constant. Pure functions — no DOM, no
 * Konva, no React.
 *
 * Marquee inclusion: by default any element whose AABB intersects the marquee
 * rect is included (the "touch" model). Pass `requireFullContainment: true` for
 * the "surround" model where the marquee must fully contain the element. Locked
 * and invisible elements are never selected regardless.
 */

/**
 * Top-most selectable element whose AABB contains the document-space point, or
 * null when the point is over empty space.
 *
 * This is the authoritative "is the pointer over an element?" test for the
 * pointer-down gesture router. It runs against the scene model in document
 * coordinates rather than Konva's hit-graph canvas, so it is independent of
 * clip groups, listening flags, and hit-canvas redraw timing — all of which
 * could make `stage.getIntersection` misclassify a press as empty space and
 * silently start a marquee instead of an element drag.
 *
 * Z-order: later elements paint on top, so we scan the array in reverse and
 * return the first hit. Groups descend into children (top child wins); a hit on
 * a group child resolves to the group itself, matching drag/selection which
 * operate on the group as a unit. Locked and invisible elements never hit.
 */
declare function hitTestPoint(page: ScenePage, x: number, y: number): string | null;
interface MarqueeSelectOptions {
    /** When true, the element's AABB must be fully inside the marquee; default is
     *  intersection (any overlap selects). */
    requireFullContainment?: boolean;
}
/** Returns the ids of selectable elements on `page` whose AABB intersects (or
 *  is contained by) `rect`. Locked and invisible elements are excluded. */
declare function marqueeSelect(page: ScenePage, rect: Bounds, opts?: MarqueeSelectOptions): string[];
interface NudgeDelta {
    dx: number;
    dy: number;
}
/** Map an arrow key to a document-px delta. `shift` engages the 10× step.
 *  Throws on unknown keys so callers handle only real nudge keys. */
declare function nudgeDelta(key: 'ArrowLeft' | 'ArrowRight' | 'ArrowUp' | 'ArrowDown', shift: boolean): NudgeDelta;
/** Document-px offset applied to duplicated elements so the copy is visually
 *  separated from the original (matching common design-tool convention). */
declare const DUPLICATE_OFFSET: NudgeDelta;

/**
 * Zoom + pan coordinate math for the design-canvas editor. Zoom is pixels-per-
 * document-px (e.g. 2 = 200% magnification). The key invariant for wheel-zoom
 * is that the document point under the cursor stays fixed in screen space:
 *
 *   docPoint = (screenPoint - pan) / zoom
 *   newPan   = screenPoint - docPoint * newZoom
 *
 * This module is pure math — no DOM, no Konva, no React.
 */

interface ZoomPanConfig {
    minZoom: number;
    maxZoom: number;
}
declare function createZoomPanMath(config: ZoomPanConfig): ZoomPanMath;

/**
 * Pure export math for the design-canvas surface — no Konva, no DOM, no React.
 *
 * All stage-interaction code (save/restore, node visibility, toDataURL) lives
 * in export.ts and delegates the decision math here so it can be tested
 * without a canvas environment.
 */

/** Returns true for any Konva node that must be hidden during export. Nodes
 *  whose names start with 'overlay:' are editor-only chrome (snap lines,
 *  selection indicators, rulers, bleed guides). The transformer node is
 *  identified by its canonical name 'Transformer'. */
declare function isExportHiddenNodeName(name: string): boolean;
interface ResolvedExportParams {
    cropRect: ExportCropRect;
    pixelRatio: number;
    mimeType: 'image/png' | 'image/jpeg';
    quality: number | undefined;
}
/**
 * Resolve the full set of toDataURL params from a page, format, pixel ratio,
 * bleed flag, and optional preset. When a preset is supplied it overrides
 * `pixelRatio` and `includeBleed` — the explicit args are ignored for those
 * two values so the preset is the single source of truth.
 *
 * `quality` is set to 0.92 for jpeg, undefined for png (Konva ignores it).
 */
declare function resolveExportParams(page: ScenePage, opts: {
    format: 'png' | 'jpeg';
    pixelRatio?: number;
    includeBleed?: boolean;
    preset?: ExportPreset;
}): ResolvedExportParams;
/**
 * Walk image nodes to find the src of any that may have caused a SecurityError
 * when the stage called toDataURL. Returns the first offending src found, or
 * null if none can be identified.
 *
 * `imageSrcs` is a flat list of { name, src } records collected from all image
 * nodes on the stage before calling toDataURL — export.ts builds it before
 * attempting the export so that if the SecurityError fires we have the data.
 */
declare function identifyTaintedSrc(imageSrcs: ReadonlyArray<{
    name: string;
    src: string;
}>): string | null;
/**
 * Heuristic: a src is potentially cross-origin when it is an absolute http(s)
 * URL. Same-origin relative paths (/api/...) and data: blobs are safe.
 * This is intentionally conservative — the taint check runs only after a
 * SecurityError fires, so a false positive is "blamed" without being silently
 * ignored. NOTE: same-origin https:// assets will also match; if a
 * SecurityError fires, the cross-origin culprit may be a different image than
 * the one this function flags first.
 */
declare function isCrossOriginSrc(src: string): boolean;
/** Minimal snapshot of stage view state that export.ts saves before mutating
 *  zoom/pan/visibility and restores afterward. */
interface ExportViewSnapshot {
    /** Stage scale factor before export. */
    scaleX: number;
    scaleY: number;
    /** Stage translation before export. */
    x: number;
    y: number;
    /** node name → prior visibility, for the nodes that were hidden. */
    hiddenNodeNames: string[];
}
/**
 * Build the toDataURL crop rect translated to stage output coordinates.
 * Konva's `stage.toDataURL({ x, y, width, height })` takes STAGE OUTPUT
 * coordinates, not document coordinates. When the stage has been scaled to fit
 * (zoom × stageScale), the crop rect in document px must be multiplied by the
 * combined scale to land on the right pixels.
 *
 * `stageScale` is the stage's current uniform scale (scaleX == scaleY);
 * `pixelRatio` is separate and handed directly to toDataURL — Konva multiplies
 * it internally when rendering to the backing canvas, so we must NOT include
 * it in the stage-coordinate rect.
 */
declare function documentCropToStageCoords(cropRect: ExportCropRect, stageScale: number, stageX: number, stageY: number): {
    x: number;
    y: number;
    width: number;
    height: number;
};

/**
 * Pure builders for the human "add element to the canvas" path — the math and
 * `SceneOperation` construction behind {@link CanvasInsertPanel}, separated from
 * the React/DOM layer so every insert is unit-testable without Konva or a
 * browser. The panel calls these to produce `add_element` operations and hands
 * them to the host's `onApplyOperations` (server-validated, undoable) — the same
 * pipeline every other edit flows through.
 *
 * Media boundary: image inserts must pass {@link assertSceneMediaSrc} (remote
 * http(s) or a rooted `/api/` path — never `data:` blobs or sandbox-local
 * files). Builders that take a src assert it up front so a bad url fails here,
 * not deep in the apply layer.
 */

/** Largest dimension (document px) a freshly inserted element is fitted to,
 *  before the page-size cap applies. Keeps a huge upload from filling the page. */
declare const MAX_INSERT_DIMENSION = 600;
/** Active page geometry an insert lands into — drives centering and fitting. */
interface InsertPageGeometry {
    pageId: string;
    width: number;
    height: number;
}
/** Mint a DOM-safe element id. Prefers `crypto.randomUUID`; falls back to a
 *  time+random id where crypto is unavailable (older runtimes, some test envs). */
declare function mintElementId(): string;
/** Fit (naturalW, naturalH) under a max-dimension cap (further bounded by the
 *  page), preserving aspect ratio. Never upscales past natural size. */
declare function fittedSize(naturalW: number, naturalH: number, pageWidth: number, pageHeight: number): {
    width: number;
    height: number;
};
/** Top-left position that centers a (width, height) box on the page. */
declare function centeredPosition(width: number, height: number, pageWidth: number, pageHeight: number): {
    x: number;
    y: number;
};
/**
 * Build an `add_element` op placing an image, fitted and centered on the page.
 * `naturalSize` is the probed image dimensions (the panel reads them in the
 * browser); pass `{ width: 0, height: 0 }` when unknown to fall back to the cap.
 *
 * Throws (via `assertSceneMediaSrc`) when `src` is not http(s) or a rooted
 * `/api/` path — callers should surface the error, never insert a `data:` src.
 */
declare function buildInsertImageOp(src: string, naturalSize: {
    width: number;
    height: number;
}, page: InsertPageGeometry): SceneOperation;
/** A template the insert panel can drop without the agent. `build` is pure and
 *  produces the operations for the active page geometry. */
interface InsertTemplate {
    id: string;
    label: string;
    build(page: InsertPageGeometry): SceneOperation[];
}
/** The built-in starter templates (heading, body text, rectangle, ellipse).
 *  Consumers can pass their own list to {@link CanvasInsertPanel}; this is the
 *  default so every canvas gets a usable set out of the box. */
declare const DEFAULT_INSERT_TEMPLATES: readonly InsertTemplate[];

export { type AddElementInput, type AddPageInput, type BindSlotInput, DEFAULT_INSERT_TEMPLATES, DUPLICATE_OFFSET, type DeleteElementInput, type DeletePageInput, type DuplicatePageInput, ExportCropRect, ExportPreset, type ExportViewSnapshot, type GroupElementsInput, type InsertPageGeometry, type InsertTemplate, MAX_INSERT_DIMENSION, type MarqueeSelectOptions, type MultiSetAttrsEntry, type NudgeDelta, type ReorderElementInput, type ReorderPageInput, type ResolvedExportParams, SceneCommand, type SetAttrsInput, type SetDocumentTitleInput, type SetPageGuidesInput, type SetPagePropsInput, SnapEngine, SnapTarget, type UngroupElementInput, type ZoomPanConfig, ZoomPanMath, addElementCommand, addPageCommand, bindSlotCommand, buildInsertImageOp, centeredPosition, collectGridTargets, createSnapEngine, createZoomPanMath, deleteElementCommand, deletePageCommand, documentCropToStageCoords, duplicatePageCommand, fittedSize, groupElementsCommand, hitTestPoint, identifyTaintedSrc, isCrossOriginSrc, isExportHiddenNodeName, marqueeSelect, mintElementId, multiSetAttrsCommand, nudgeDelta, reorderElementCommand, reorderPageCommand, resolveExportParams, setAttrsCommand, setDocumentTitleCommand, setPageGuidesCommand, setPagePropsCommand, ungroupElementCommand };
