import EditorImage from './image/EditorImage';
import ToolController from './tools/ToolController';
import { EditorNotifier, ImageLoader } from './types';
import { HTMLPointerEventFilter, InputEvtType, PointerEvtType } from './inputEvents';
import Command from './commands/Command';
import UndoRedoHistory from './UndoRedoHistory';
import Viewport from './Viewport';
import { Point2, Vec2, Color4, Mat33, Rect2 } from '@js-draw/math';
import Display, { RenderingMode } from './rendering/Display';
import { SVGLoaderPlugin } from './SVGLoader/SVGLoader';
import Pointer from './Pointer';
import { EditorLocalization } from './localization';
import IconProvider from './toolbar/IconProvider';
import AbstractComponent from './components/AbstractComponent';
import { BackgroundType } from './components/BackgroundComponent';
import KeyboardShortcutManager from './shortcuts/KeyboardShortcutManager';
import KeyBinding from './shortcuts/KeyBinding';
import AbstractToolbar from './toolbar/AbstractToolbar';
import RenderablePathSpec from './rendering/RenderablePathSpec';
import { AboutDialogEntry } from './dialogs/makeAboutDialog';
import ReactiveValue, { MutableReactiveValue } from './util/ReactiveValue';
import { PenTypeRecord } from './toolbar/widgets/PenToolWidget';
import { ShowCustomFilePickerCallback } from './toolbar/widgets/components/makeFileInput';
/**
 * Provides settings to an instance of an editor. See the Editor {@link Editor.constructor}.
 *
 * ## Example
 *
 * [[include:doc-pages/inline-examples/settings-example-1.md]]
 */
export interface EditorSettings {
    /** Defaults to `RenderingMode.CanvasRenderer` */
    renderingMode: RenderingMode;
    /** Uses a default English localization if a translation is not given. */
    localization: Partial<EditorLocalization>;
    /**
     * `true` if touchpad/mousewheel scrolling should scroll the editor instead of the document.
     * This does not include pinch-zoom events.
     * Defaults to true.
     */
    wheelEventsEnabled: boolean | 'only-if-focused';
    /** Minimum zoom fraction (e.g. 0.5 → 50% zoom). Defaults to $2 \cdot 10^{-10}$. */
    minZoom: number;
    /** Maximum zoom fraction (e.g. 2 → 200% zoom). Defaults to $1 \cdot 10^{12}$. */
    maxZoom: number;
    /**
     * Overrides for keyboard shortcuts. For example,
     * ```ts
     * {
     * 	'some.shortcut.id': [ KeyBinding.keyboardShortcutFromString('ctrl+a') ],
     * 	'another.shortcut.id': [ ]
     * }
     * ```
     * where shortcut IDs map to lists of associated keybindings.
     *
     * @see
     * - {@link KeyBinding}
     * - {@link KeyboardShortcutManager}
     */
    keyboardShortcutOverrides: Record<string, Array<KeyBinding>>;
    /**
     * Provides a set of icons for the editor.
     *
     * See, for example, the `@js-draw/material-icons` package.
     */
    iconProvider: IconProvider;
    /**
     * Additional messages to show in the "about" dialog.
     */
    notices: AboutDialogEntry[];
    /**
     * Information about the app/website js-draw is running within. This is shown
     * at the beginning of the about dialog.
     */
    appInfo: {
        name: string;
        description?: string;
        version?: string;
    } | null;
    /**
     * Configures the default {@link PenTool} tools.
     *
     * **Example**:
     * [[include:doc-pages/inline-examples/editor-settings-polyline-pen.md]]
     */
    pens: {
        /**
         * Additional pen types that can be selected in a toolbar.
         */
        additionalPenTypes?: readonly Readonly<PenTypeRecord>[];
        /**
         * Should return `true` if a pen type should be shown in the toolbar.
         *
         * @example
         * ```ts,runnable
         * import {Editor} from 'js-draw';
         * const editor = new Editor(document.body, {
         *   // Only allow selecting the polyline pen from the toolbar.
         *   pens: { filterPenTypes: p => p.id === 'polyline-pen' },
         * });
         * editor.addToolbar();
         * ```
         * Notice that this setting only affects the toolbar GUI.
         */
        filterPenTypes?: (penType: PenTypeRecord) => boolean;
    } | null;
    /** Configures the default {@link TextTool} control and text tool. */
    text: {
        /** Fonts to show in the text UI. */
        fonts?: string[];
    } | null;
    /** Configures the default {@link InsertImageWidget} control. */
    image: {
        /**
         * A custom callback to show an image picker. If given, this should return
         * a list of `File`s representing the images selected by the picker.
         *
         * If not given, the default file picker shown by a [file input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file)
         * is shown.
         */
        showImagePicker?: ShowCustomFilePickerCallback;
    } | null;
    /**
     * Allows changing how js-draw interacts with the clipboard.
     *
     * **Note**: Even when a custom `clipboardApi` is specified, if a `ClipboardEvent` is available
     * (e.g. from when a user pastes with ctrl+v), the `ClipboardEvent` will be preferred.
     */
    clipboardApi: {
        /** Called to read data to the clipboard. Keys in the result are MIME types. Values are the data associated with that type. */
        read(): Promise<Map<string, Blob | string>>;
        /** Called to write data to the clipboard. Keys in `data` are MIME types. Values are the data associated with that type. */
        write(data: Map<string, Blob | Promise<Blob> | string>): void | Promise<void>;
    } | null;
    svg: {
        /** Plugins that create custom components while loading with {@link Editor.loadFromSVG}. */
        loaderPlugins?: SVGLoaderPlugin[];
    } | null;
}
/**
 * The main entrypoint for the full editor.
 *
 * ## Example
 * To create an editor with a toolbar,
 * ```ts,runnable
 * import { Editor } from 'js-draw';
 *
 * const editor = new Editor(document.body);
 *
 * const toolbar = editor.addToolbar();
 * toolbar.addSaveButton(() => {
 *   const saveData = editor.toSVG().outerHTML;
 *   // Do something with saveData...
 * });
 * ```
 *
 * See also
 * * [`examples.md`](https://github.com/personalizedrefrigerator/js-draw/blob/main/docs/examples.md).
 */
export declare class Editor {
    private container;
    private renderingRegion;
    /** Manages drawing surfaces/{@link AbstractRenderer}s. */
    display: Display;
    /**
     * Handles undo/redo.
     *
     * @example
     * ```
     * const editor = new Editor(document.body);
     *
     * // Do something undoable.
     * // ...
     *
     * // Undo the last action
     * editor.history.undo();
     * ```
     */
    history: UndoRedoHistory;
    /**
     * Data structure for adding/removing/querying objects in the image.
     *
     * @example
     * ```ts,runnable
     * import { Editor, Stroke, Path, Color4, pathToRenderable } from 'js-draw';
     * const editor = new Editor(document.body);
     *
     * // Create a path.
     * const stroke = new Stroke([
     *   pathToRenderable(Path.fromString('M0,0 L100,100 L300,30 z'), { fill: Color4.red }),
     * ]);
     * const addComponentCommand = editor.image.addComponent(stroke);
     *
     * // Add the stroke to the editor
     * editor.dispatch(addComponentCommand);
     * ```
     */
    readonly image: EditorImage;
    /**
     * Allows transforming the view and querying information about
     * what is currently visible.
     */
    readonly viewport: Viewport;
    /** @internal */
    readonly localization: EditorLocalization;
    /** {@link EditorSettings.iconProvider} */
    readonly icons: IconProvider;
    /**
     * Manages and allows overriding of keyboard shortcuts.
     *
     * @internal
     */
    readonly shortcuts: KeyboardShortcutManager;
    /**
     * Controls the list of tools. See
     * [the custom tool example](https://github.com/personalizedrefrigerator/js-draw/tree/main/docs/examples/example-custom-tools)
     * for more.
     */
    readonly toolController: ToolController;
    /**
     * Global event dispatcher/subscriber.
     *
     * @example
     *
     * ```ts,runnable
     * import { Editor, EditorEventType, SerializableCommand } from 'js-draw';
     *
     * // Create a minimal editor
     * const editor = new Editor(document.body);
     * editor.addToolbar();
     *
     * // Create a place to show text output
     * const log = document.createElement('textarea');
     * document.body.appendChild(log);
     * log.style.width = '100%';
     * log.style.height = '200px';
     *
     * // Listen for CommandDone events (there's also a CommandUndone)
     * editor.notifier.on(EditorEventType.CommandDone, event => {
     *   // Type narrowing for TypeScript -- event will always be of kind CommandDone,
     *   // but TypeScript doesn't know this.
     *   if (event.kind !== EditorEventType.CommandDone) return;
     *
     *   log.value = `Command done ${event.command.description(editor, editor.localization)}\n`;
     *
     *   if (event.command instanceof SerializableCommand) {
     *     log.value += `serializes to: ${JSON.stringify(event.command.serialize())}`;
     *   }
     * });
     *
     * // Dispatch an initial command to trigger the event listener for the first time
     * editor.dispatch(editor.image.setAutoresizeEnabled(true));
     * ```
     */
    readonly notifier: EditorNotifier;
    private loadingWarning;
    private accessibilityAnnounceArea;
    private accessibilityControlArea;
    private eventListenerTargets;
    private readOnly;
    private readonly settings;
    /**
     * @example
     * ```ts,runnable
     * import { Editor } from 'js-draw';
     *
     * const container = document.body;
     *
     * // Create an editor
     * const editor = new Editor(container, {
     *   // 2e-10 and 1e12 are the default values for minimum/maximum zoom.
     *   minZoom: 2e-10,
     *   maxZoom: 1e12,
     * });
     *
     * // Add the default toolbar
     * const toolbar = editor.addToolbar();
     *
     * const createCustomIcon = () => {
     *   // Create/return an icon here.
     * };
     *
     * // Add a custom button
     * toolbar.addActionButton({
     *   label: 'Custom Button'
     *   icon: createCustomIcon(),
     * }, () => {
     *   // Do something here
     * });
     * ```
     */
    constructor(parent: HTMLElement, settings?: Partial<EditorSettings>);
    /**
     * @returns a shallow copy of the current settings of the editor.
     *
     * Do not modify.
     */
    getCurrentSettings(): Readonly<EditorSettings>;
    /**
     * @returns a reference to the editor's container.
     *
     * @example
     * ```
     *   // Set the editor's height to 500px
     *   editor.getRootElement().style.height = '500px';
     * ```
     */
    getRootElement(): HTMLElement;
    /**
     * @returns the bounding box of the main rendering region of the editor in the HTML viewport.
     *
     * @internal
     */
    getOutputBBoxInDOM(): Rect2;
    /**
     * Shows a "Loading..." message.
     * @param fractionLoaded - should be a number from 0 to 1, where 1 represents completely loaded.
     */
    showLoadingWarning(fractionLoaded: number): void;
    /** @see {@link showLoadingWarning} */
    hideLoadingWarning(): void;
    private previousAccessibilityAnnouncement;
    /**
     * Announce `message` for screen readers. If `message` is the same as the previous
     * message, it is re-announced.
     */
    announceForAccessibility(message: string): void;
    /**
     * Creates a toolbar. If `defaultLayout` is true, default buttons are used.
     * @returns a reference to the toolbar.
     */
    addToolbar(defaultLayout?: boolean): AbstractToolbar;
    private registerListeners;
    private updateEditorSizeVariables;
    /** @internal */
    handleHTMLWheelEvent(event: WheelEvent): boolean | undefined;
    private pointers;
    private getPointerList;
    /**
     * A protected method that can override setPointerCapture in environments where it may fail
     * (e.g. with synthetic events). @internal
     */
    protected setPointerCapture(target: HTMLElement, pointerId: number): void;
    /** Can be overridden in a testing environment to handle synthetic events. @internal */
    protected releasePointerCapture(target: HTMLElement, pointerId: number): void;
    /**
     * Dispatches a `PointerEvent` to the editor. The target element for `evt` must have the same top left
     * as the content of the editor.
     */
    handleHTMLPointerEvent(eventType: 'pointerdown' | 'pointermove' | 'pointerup' | 'pointercancel', evt: PointerEvent): boolean;
    private isEventSink;
    /** @internal */
    protected handleDrop(evt: DragEvent | ClipboardEvent): Promise<void>;
    /** @internal */
    protected handlePaste(evt: DragEvent | ClipboardEvent): Promise<boolean | undefined>;
    /**
     * Forward pointer events from `elem` to this editor. Such that right-click/right-click drag
     * events are also forwarded, `elem`'s contextmenu is disabled.
     *
     * `filter` is called once per pointer event, before doing any other processing. If `filter` returns `true` the event is
     * forwarded to the editor.
     *
     * **Note**: `otherEventsFilter` is like `filter`, but is called for other pointer-related
     * events that could also be forwarded to the editor. To forward just pointer events,
     * for example, `otherEventsFilter` could be given as `()=>false`.
     *
     * @example
     * ```ts
     * const overlay = document.createElement('div');
     * editor.createHTMLOverlay(overlay);
     *
     * // Send all pointer events that don't have the control key pressed
     * // to the editor.
     * editor.handlePointerEventsFrom(overlay, (event) => {
     *   if (event.ctrlKey) {
     *     return false;
     *   }
     *   return true;
     * });
     * ```
     */
    handlePointerEventsFrom(elem: HTMLElement, filter?: HTMLPointerEventFilter, otherEventsFilter?: (eventName: string, event: Event) => boolean): {
        /** Remove all event listeners registered by this function. */
        remove: () => void;
    };
    /**
     * Like {@link handlePointerEventsFrom} except ignores short input gestures like clicks.
     *
     * `filter` is called once per event, before doing any other processing. If `filter` returns `true` the event is
     * forwarded to the editor.
     *
     * `otherEventsFilter` is passed unmodified to `handlePointerEventsFrom`.
     */
    handlePointerEventsExceptClicksFrom(elem: HTMLElement, filter?: HTMLPointerEventFilter, otherEventsFilter?: (eventName: string, event: Event) => boolean): {
        /** Remove all event listeners registered by this function. */
        remove: () => void;
    };
    /** @internal */
    handleHTMLKeyDownEvent(htmlEvent: KeyboardEvent): boolean;
    /** @internal */
    handleHTMLKeyUpEvent(htmlEvent: KeyboardEvent): boolean;
    /**
     * Adds event listners for keypresses (and drop events) on `elem` and forwards those
     * events to the editor.
     *
     * If the given `filter` returns `false` for an event, the event is ignored and not
     * passed to the editor.
     */
    handleKeyEventsFrom(elem: HTMLElement, filter?: (event: KeyboardEvent) => boolean): void;
    /**
     * Attempts to prevent **user-triggered** events from modifying
     * the content of the image.
     */
    setReadOnly(readOnly: boolean): void;
    isReadOnlyReactiveValue(): ReactiveValue<boolean>;
    isReadOnly(): MutableReactiveValue<boolean>;
    /**
     * `apply` a command. `command` will be announced for accessibility.
     *
     * **Example**:
     * [[include:doc-pages/inline-examples/adding-a-stroke.md]]
     */
    dispatch(command: Command, addToHistory?: boolean): void | Promise<void>;
    /**
     * Dispatches a command without announcing it. By default, does not add to history.
     * Use this to show finalized commands that don't need to have `announceForAccessibility`
     * called.
     *
     * If `addToHistory` is `false`, this is equivalent to `command.apply(editor)`.
     *
     * @example
     * ```
     * const addToHistory = false;
     * editor.dispatchNoAnnounce(editor.viewport.zoomTo(someRectangle), addToHistory);
     * ```
     */
    dispatchNoAnnounce(command: Command, addToHistory?: boolean): void | Promise<void>;
    /**
     * Apply a large transformation in chunks.
     * If `apply` is `false`, the commands are unapplied.
     * Triggers a re-render after each `updateChunkSize`-sized group of commands
     * has been applied.
     */
    asyncApplyOrUnapplyCommands(commands: Command[], apply: boolean, updateChunkSize: number): Promise<void>;
    /** @see {@link asyncApplyOrUnapplyCommands } */
    asyncApplyCommands(commands: Command[], chunkSize: number): Promise<void>;
    /**
     * @see {@link asyncApplyOrUnapplyCommands}
     *
     * If `unapplyInReverseOrder`, commands are reversed before unapplying.
     */
    asyncUnapplyCommands(commands: Command[], chunkSize: number, unapplyInReverseOrder?: boolean): Promise<void>;
    private announceUndoCallback;
    private announceRedoCallback;
    private nextRerenderListeners;
    private rerenderQueued;
    /**
     * Schedule a re-render for some time in the near future. Does not schedule an additional
     * re-render if a re-render is already queued.
     *
     * @returns a promise that resolves when re-rendering has completed.
     */
    queueRerender(): Promise<void>;
    isRerenderQueued(): boolean;
    /**
     * Re-renders the entire image.
     *
     * @see {@link Editor.queueRerender}
     */
    rerender(showImageBounds?: boolean): void;
    /**
     * Draws the given path onto the wet ink renderer. The given path will
     * be displayed on top of the main image.
     *
     * @see {@link Display.getWetInkRenderer} {@link Display.flatten}
     */
    drawWetInk(...path: RenderablePathSpec[]): void;
    /**
     * Clears the wet ink display.
     *
     * The wet ink display can be used by the currently active tool to display a preview
     * of an in-progress action.
     *
     * @see {@link Display.getWetInkRenderer}
     */
    clearWetInk(): void;
    /**
     * Focuses the region used for text input/key commands.
     */
    focus(): void;
    /**
     * Creates an element that will be positioned on top of the dry/wet ink
     * renderers.
     *
     * So as not to change the position of other overlays, `overlay` should either
     * be styled to have 0 height or have `position: absolute`.
     *
     * This is useful for displaying content on top of the rendered content
     * (e.g. a selection box).
     */
    createHTMLOverlay(overlay: HTMLElement): {
        remove: () => void;
    };
    /**
     * Anchors the given `element` to the canvas with a given position/transformation in canvas space.
     */
    anchorElementToCanvas(element: HTMLElement, canvasTransform: Mat33 | ReactiveValue<Mat33>): {
        remove: () => void;
    };
    /**
     * Creates a CSS stylesheet with `content` and applies it to the document
     * (and thus, to this editor).
     */
    addStyleSheet(content: string): HTMLStyleElement;
    /**
     * Dispatch a keyboard event to the currently selected tool.
     * Intended for unit testing.
     *
     * If `shiftKey` is undefined, it is guessed from `key`.
     *
     * At present, the **key code** dispatched is guessed from the given key and,
     * while this works for ASCII alphanumeric characters, this does not work for
     * most non-alphanumeric keys.
     *
     * Because guessing the key code from `key` is problematic, **only use this for testing**.
     */
    sendKeyboardEvent(eventType: InputEvtType.KeyPressEvent | InputEvtType.KeyUpEvent, key: string, ctrlKey?: boolean, altKey?: boolean, shiftKey?: boolean | undefined): void;
    /**
     * Dispatch a pen event to the currently selected tool.
     * Intended primarially for unit tests.
     *
     * @deprecated
     * @see {@link sendPenEvent} {@link sendTouchEvent}
     */
    sendPenEvent(eventType: PointerEvtType, point: Point2, allPointers?: Pointer[]): void;
    /**
     * Adds all components in `components` such that they are in the center of the screen.
     * This is a convenience method that creates **and applies** a single command.
     *
     * If `selectComponents` is true (the default), the components are selected.
     *
     * `actionDescription`, if given, should be a screenreader-friendly description of the
     * reason components were added (e.g. "pasted").
     */
    addAndCenterComponents(components: AbstractComponent[], selectComponents?: boolean, actionDescription?: string): Promise<void>;
    /**
     * Get a data URL (e.g. as produced by `HTMLCanvasElement::toDataURL`).
     * If `format` is not `image/png`, a PNG image URL may still be returned (as in the
     * case of `HTMLCanvasElement::toDataURL`).
     *
     * The export resolution is the same as the size of the drawing canvas, unless `outputSize`
     * is given.
     *
     * **Example**:
     * [[include:doc-pages/inline-examples/adding-an-image-and-data-urls.md]]
     */
    toDataURL(format?: 'image/png' | 'image/jpeg' | 'image/webp', outputSize?: Vec2): string;
    /**
     * Converts the editor's content into an SVG image.
     *
     * If the output SVG has width or height less than `options.minDimension`, its size
     * will be increased.
     *
     * @see
     * {@link SVGRenderer}
     */
    toSVG(options?: {
        minDimension?: number;
    }): SVGElement;
    /**
     * Converts the editor's content into an SVG image in an asynchronous,
     * but **potentially lossy** way.
     *
     * **Warning**: If the image is being edited during an async rendering, edited components
     * may not be rendered.
     *
     * Like {@link toSVG}, but can be configured to briefly pause after processing every
     * `pauseAfterCount` items. This can prevent the editor from becoming unresponsive
     * when saving very large images.
     */
    toSVGAsync(options?: {
        minDimension?: number;
        pauseAfterCount?: number;
        onProgress?: (processedCountInLayer: number, totalToProcessInLayer: number) => Promise<void | boolean>;
    }): Promise<SVGElement>;
    /**
     * Load editor data from an `ImageLoader` (e.g. an {@link SVGLoader}).
     *
     * @see loadFromSVG
     */
    loadFrom(loader: ImageLoader): Promise<void>;
    private getTopmostBackgroundComponent;
    /**
     * This is a convenience method for adding or updating the {@link BackgroundComponent}
     * and {@link EditorImage.setAutoresizeEnabled} for the current image.
     *
     * If there are multiple {@link BackgroundComponent}s in the image, this only modifies
     * the topmost such element.
     *
     * **Example**:
     * ```ts,runnable
     * import { Editor, Color4, BackgroundComponentBackgroundType } from 'js-draw';
     * const editor = new Editor(document.body);
     * editor.dispatch(editor.setBackgroundStyle({
     *     color: Color4.orange,
     *     type: BackgroundComponentBackgroundType.Grid,
     *     autoresize: true,
     * }));
     * ```
     *
     * To change the background size, see {@link EditorImage.setImportExportRect}.
     */
    setBackgroundStyle(style: {
        color?: Color4;
        type?: BackgroundType;
        autoresize?: boolean;
    }): Command;
    /**
     * Set the background color of the image.
     *
     * This is a convenience method for adding or updating the {@link BackgroundComponent}
     * for the current image.
     *
     * @see {@link setBackgroundStyle}
     */
    setBackgroundColor(color: Color4): Command;
    /**
     * @returns the average of the colors of all background components. Use this to get the current background
     * color.
     */
    estimateBackgroundColor(): Color4;
    getImportExportRect(): Rect2;
    setImportExportRect(imageRect: Rect2): Command;
    /**
     * Alias for `loadFrom(SVGLoader.fromString)`.
     *
     * @example
     * ```ts,runnable
     * import {Editor} from 'js-draw';
     * const editor = new Editor(document.body);
     *
     * ---visible---
     * await editor.loadFromSVG(`
     *   <svg viewBox="5 23 52 30" width="52" height="16" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
     *     <text style="
     *       transform: matrix(0.181846, 0.1, 0, 0.181846, 11.4, 33.2);
     *       font-family: serif;
     *       font-size: 32px;
     *       fill: rgb(100, 140, 61);
     *     ">An SVG image!</text>
     *   </svg>
     * `);
     * ```
     */
    loadFromSVG(svgData: string, sanitize?: boolean): Promise<void>;
    private closeAboutDialog;
    /**
     * Shows an information dialog with legal notices.
     */
    showAboutDialog(): void;
    /**
     * Removes and **destroys** the editor. The editor cannot be added to a parent
     * again after calling this method.
     */
    remove(): void;
}
export default Editor;
