import { type HTMLAttributes, type Ref, type RefCallback } from "react";
import { type NonNullRef, type UseStateInitializer, type UseStateSetter } from "../types.js";
/**
 * @since 6.0.0
 */
export type DraggableTouchEventHandlers<E extends HTMLElement> = Pick<HTMLAttributes<E>, "onTouchStart" | "onTouchMove">;
/**
 * @since 6.0.0
 */
export type DraggableMouseEventHandlers<E extends HTMLElement> = Pick<HTMLAttributes<E>, "onMouseDown" | "onMouseUp" | "onMouseMove">;
/**
 * @since 6.0.0
 */
export type DraggableKeyboardEventHandlers<E extends HTMLElement> = Pick<HTMLAttributes<E>, "onKeyDown">;
/**
 * @since 6.0.0
 */
export type DraggableEventHandlers<E extends HTMLElement> = DraggableTouchEventHandlers<E> & DraggableMouseEventHandlers<E> & DraggableKeyboardEventHandlers<E>;
/**
 * @since 6.0.0
 */
export interface ControllableDraggableStateOptions {
    value?: number;
    setValue?: UseStateSetter<number>;
    defaultValue?: UseStateInitializer<number>;
    dragging?: boolean;
    setDragging?: UseStateSetter<boolean>;
}
/**
 * @since 6.0.0
 */
export interface BaseDraggableOptions<E extends HTMLElement> extends DraggableEventHandlers<E>, ControllableDraggableStateOptions {
    /**
     * An optional ref to merge with the returned
     * {@link DraggableImplementation.draggableRef}.
     */
    ref?: Ref<E>;
    /**
     * The minimum number of pixels allowed for the draggable element. This must
     * be a number greater than or equal to 0.
     *
     * When {@link withinOffsetParent} is set to `true`, this is the minimum value
     * allowed instead of pixels.
     */
    min: number;
    /**
     * The maximum number of pixels allowed for the draggable element. This must
     * be a number greater than the {@link min} and usually a number less than the
     * viewport size.
     *
     * When {@link withinOffsetParent} is set to `true`, this is the maximum value
     * allowed instead of pixels.
     */
    max: number;
    /**
     * The amount to increment or decrement the value with arrow keys.
     *
     * @defaultValue `1`
     */
    step?: number;
    /**
     * This was added to support range sliders where there are two (or more)
     * draggable elements within the same container element and their values
     * cannot pass each other. Without these overrides, the range would keep
     * changing as the other values change, so the drag percentage would be
     * incorrect.
     *
     * @example Range Slider
     * ```ts
     * const min = 0;
     * const max = 100;
     * const minValue = 3;
     * const maxValue = 80;
     *
     * const minValueDraggable = useDraggable({
     *   min,
     *   max,
     *   rangeMax: maxValue,
     * });
     * const maxValueDraggable = useDraggable({
     *   min,
     *   max,
     *   rangeMin: minValue,
     * });
     * ```
     *
     * @defaultValue `min`
     */
    rangeMin?: number;
    /**
     * @see {@link rangeMin} for an explanation of this option.
     * @defaultValue `max`
     */
    rangeMax?: number;
    /**
     * Set this to `true` to enable dragging vertically instead of horizontally.
     *
     * @defaultValue `false`
     */
    vertical?: boolean;
    /**
     * The default drag behavior is to increase the value when:
     *
     * - dragging `"right"` and the writing direction is `"ltr"`
     * - dragging `"left"` and the writing direction is `"rtl"`
     * - dragging `"upwards"`
     *
     * When this is set to `true`, the value when increase when:
     *
     * - dragging `"left"` and the writing direction is `"ltr"`
     * - dragging `"right"` and the writing direction is `"rtl"`
     * - dragging `"downwards"`
     *
     * @defaultValue `false`
     */
    reversed?: boolean;
    /**
     * Set this to `true` to disable all drag behavior. This will still call any
     * of the provided {@link DraggableEventHandlers}.
     *
     * @defaultValue `false`
     */
    disabled?: boolean;
    /**
     * Set this to `true` if the dragging calculations should be to the
     * `draggableRef.current.offsetParent` instead of the entire window. The main
     * use case for this is sliders.
     *
     * @defaultValue `false`
     */
    withinOffsetParent?: boolean;
    /**
     * Set this to `true` to prevent the `document.documentElement` from gaining
     * the `.rmd-dragging` class names while dragging.
     *
     * This should normally remain as `false` to improve performance and prevent
     * other mouse events from firing while dragging.
     *
     * @defaultValue `false`
     */
    disableDraggingClassName?: boolean;
    /**
     * Set this to `true` to prevent the vertical or horizontal cursor from
     * appearing while dragging.
     *
     * @defaultValue `false`
     */
    disableDraggingCursorClassName?: boolean;
}
/**
 * @since 6.0.0
 */
export interface UncontrolledDraggableOptions {
    value?: never;
    setValue?: never;
    dragging?: never;
    setDragging?: never;
}
/**
 * @since 6.0.0
 */
export interface ControlledValueDraggableOptions {
    value: number;
    setValue: UseStateSetter<number>;
    defaultValue?: never;
    dragging?: never;
    setDragging?: never;
}
/**
 * @since 6.0.0
 */
export interface ControlledDraggingDraggableOptions {
    value?: never;
    setValue?: never;
    defaultValue?: never;
    dragging: boolean;
    setDragging: UseStateSetter<boolean>;
}
/**
 * @since 6.0.0
 */
export interface FullyControlledDraggableOptions {
    value: number;
    setValue: UseStateSetter<number>;
    dragging: boolean;
    setDragging: UseStateSetter<boolean>;
}
/**
 * @since 6.0.0
 */
export type DraggableStateOptions = UncontrolledDraggableOptions | ControlledValueDraggableOptions | ControlledDraggingDraggableOptions | FullyControlledDraggableOptions;
/**
 * @since 6.0.0
 */
export type DraggableOptions<E extends HTMLElement = HTMLElement> = BaseDraggableOptions<E> & DraggableStateOptions;
/**
 * @since 6.0.0
 */
export interface DraggableImplementation<E extends HTMLElement = HTMLElement> extends Required<DraggableEventHandlers<E>> {
    mouseEventHandlers: Required<DraggableMouseEventHandlers<E>>;
    touchEventHandlers: Required<DraggableTouchEventHandlers<E>>;
    keyboardEventHandlers: Required<DraggableKeyboardEventHandlers<E>>;
    /**
     * Set the {@link value} to {@link DraggableOptions.min}.
     */
    minimum: () => void;
    /**
     * Set the {@link value} to {@link DraggableOptions.max}.
     */
    maximum: () => void;
    /**
     * Increment the {@link value} by {@link DraggableOptions.step}.
     */
    increment: () => void;
    /**
     * Decrement the {@link value} by {@link DraggableOptions.step}.
     */
    decrement: () => void;
    /**
     * The current percentage the `value` is within the range.
     *
     * ```ts
     * const percentage =
     *   dragging && withinOffsetParent
     *     ? : dragPercentage
     *     : getPercentage({ min, max, value });
     * ```
     */
    percentage: number;
    /**
     * A ref that **Must** be passed to the element that should be draggable.
     */
    draggableRef: RefCallback<E>;
    /**
     * This value will only update while dragging with a mouse or touch and should
     * be used for the positioning styles while dragging.
     *
     * Note: The {@link percentage} will use this value while dragging.
     */
    dragPercentage: number;
    /**
     * Flag to determine if the user has dragged at least once. Used internally
     * for manually persisting the value into local storage once the user has
     * stopped dragging.
     */
    draggedOnce: NonNullRef<boolean>;
    value: number;
    setValue: UseStateSetter<number>;
    dragging: boolean;
    setDragging: UseStateSetter<boolean>;
}
/**
 * This is most likely an internal only hook that provides the functionality for
 * dragging an element through mouse, touch, and keyboard events. The main use
 * cases so far for this hook are:
 * - window splitters
 * - sliders
 *
 * NOTE: This requires `touch-action: none` to be applied to the draggable
 * element to help prevent page scrolling on mobile devices.
 *
 * @see {@link https://react-md.dev/components/use-draggable | useDraggable Demos}
 * @since 6.0.0
 */
export declare function useDraggable<E extends HTMLElement>(options: DraggableOptions<E>): DraggableImplementation<E>;
