import { RefObject, FC, PropsWithChildren } from 'react'; import { MouseEvent } from 'xterm-mouse'; import { DOMElement } from 'ink'; /** * Extended mouse event for Ink components * Inherits all properties from xterm-mouse MouseEvent */ type InkMouseEvent = MouseEvent & {}; /** * Click event handler */ type ClickHandler = (event: InkMouseEvent) => void; /** * Mouse enter event handler */ type MouseEnterHandler = (event: InkMouseEvent) => void; /** * Mouse leave event handler */ type MouseLeaveHandler = (event: InkMouseEvent) => void; /** * Mouse press event handler */ type MousePressHandler = (event: InkMouseEvent) => void; /** * Mouse release event handler */ type MouseReleaseHandler = (event: InkMouseEvent) => void; /** * Mouse move event handler */ type MouseMoveHandler = (event: InkMouseEvent) => void; /** * Mouse drag event handler */ type MouseDragHandler = (event: InkMouseEvent) => void; /** * Wheel event handler */ type WheelHandler = (event: InkMouseEvent) => void; /** * Element ref type */ type ElementRef = RefObject; /** * Mouse context value exposed by MouseProvider */ type MouseContextValue = { isEnabled: boolean; enable: () => void; disable: () => void; isTracking: boolean; }; /** * DOMRect type - browser standard for element bounding box */ type DOMRect = { readonly x: number; readonly y: number; readonly width: number; readonly height: number; readonly top: number; readonly right: number; readonly bottom: number; readonly left: number; }; /** * Alias for DOMRect - used for element bounding client rectangle */ type BoundingClientRect = DOMRect; /** * React context for mouse functionality * Provides access to mouse instance and control methods */ declare const MouseContext: React.Context; /** * Stateful hook to provide the position of the referenced element. * * @param ref - The reference to the element. * @param deps - Dependencies to recompute the position. * @returns The position of the element. */ declare function useElementPosition(ref: RefObject, deps?: unknown[]): { left: number; top: number; }; declare function useElementDimensions(ref: RefObject, deps?: unknown[]): { width: number; height: number; }; /** * Hook to get the bounding client rect of a referenced element. * * @param ref - The reference to the element. * @param deps - Dependencies to recompute the bounding rect. * @returns The bounding client rect of the element. */ declare function useBoundingClientRect(ref: RefObject, deps?: unknown[]): BoundingClientRect; /** * Get the dimensions of the element. */ declare function getElementDimensions(node: DOMElement | null): { width: number; height: number; } | undefined; /** * Get the position of the element. */ declare function getElementPosition(node: DOMElement | null): { left: number; top: number; } | undefined; /** * Get the bounding client rect of an element. * * @param node - The DOMElement node. * @returns The bounding client rect or undefined if node is null. */ declare function getBoundingClientRect(node: DOMElement | null): BoundingClientRect | undefined; type UseMouseReturn = { isEnabled: boolean; isTracking: boolean; isSupported: boolean; enable: () => void; disable: () => void; }; /** * Hook for accessing mouse control and state * Must be used within a MouseProvider * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function MyComponent() { * const mouse = useMouse(); * * return ( * * Mouse enabled: {mouse.isEnabled} * Supported: {mouse.isSupported} * * ); * } * ``` */ declare function useMouse(): UseMouseReturn; /** * Hook for handling click events on an element. * Must be used within a MouseProvider. * * @param ref - Reference to the element. * @param handler - Click event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Clickable() { * const ref = useRef(null); * * useOnClick(ref, (event) => { * console.log('Clicked at', event.x, event.y); * }); * * return Click me; * } * ``` */ declare function useOnClick(ref: ElementRef, handler: ClickHandler | null | undefined): void; /** * Hook for handling mouse drag events on an element. * Must be used within a MouseProvider. * * Drag events fire when the mouse moves while a button is held down. * This is useful for implementing drag-and-drop functionality. * * @param ref - Reference to the element. * @param handler - Mouse drag event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Draggable() { * const ref = useRef(null); * const [isDragging, setIsDragging] = useState(false); * const [position, setPosition] = useState({ x: 0, y: 0 }); * * useOnPress(ref, () => setIsDragging(true)); * useOnRelease(ref, () => setIsDragging(false)); * * useOnDrag(ref, (event) => { * if (isDragging) { * setPosition({ x: event.x, y: event.y }); * } * }); * * return ( * * Position: {position.x}, {position.y} * {isDragging ? '(dragging)' : '(not dragging)'} * * ); * } * ``` */ declare function useOnDrag(ref: ElementRef, handler: MouseDragHandler | null | undefined): void; /** * Hook for handling mouse enter events on an element. * Must be used within a MouseProvider. * * @param ref - Reference to the element. * @param handler - Mouse enter event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Component() { * const ref = useRef(null); * const [message, setMessage] = useState(''); * * useOnMouseEnter(ref, () => setMessage('Mouse entered!')); * * return ( * * {message} * * ); * } * ``` */ declare function useOnMouseEnter(ref: ElementRef, handler: MouseEnterHandler | null | undefined): void; /** * Hook for handling mouse leave events on an element. * Must be used within a MouseProvider. * * @param ref - Reference to the element. * @param handler - Mouse leave event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Component() { * const ref = useRef(null); * const [message, setMessage] = useState(''); * * useOnMouseLeave(ref, () => setMessage('Mouse left!')); * * return ( * * {message} * * ); * } * ``` */ declare function useOnMouseLeave(ref: ElementRef, handler: MouseLeaveHandler | null | undefined): void; /** * Hook for handling mouse move events on an element. * Must be used within a MouseProvider. * * Move events fire when the mouse cursor moves within the element's bounds. * Unlike hover events, move events fire continuously as the mouse moves. * * **Performance Note:** Move events fire very frequently. Consider debouncing * or throttling handlers for performance-sensitive applications. * * @param ref - Reference to the element. * @param handler - Mouse move event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Tracker() { * const ref = useRef(null); * const [position, setPosition] = useState({ x: 0, y: 0 }); * * useOnMouseMove(ref, (event) => { * setPosition({ x: event.x, y: event.y }); * }); * * return ( * * Mouse position: {position.x}, {position.y} * * ); * } * ``` */ declare function useOnMouseMove(ref: ElementRef, handler: MouseMoveHandler | null | undefined): void; /** * Hook for handling mouse button press events on an element. * Must be used within a MouseProvider. * * Press events fire immediately when a mouse button is pressed down, * before the click event (which requires press + release). * * @param ref - Reference to the element. * @param handler - Mouse press event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Button() { * const ref = useRef(null); * const [isPressed, setIsPressed] = useState(false); * * useOnPress(ref, () => setIsPressed(true)); * useOnRelease(ref, () => setIsPressed(false)); * * return ( * * {isPressed ? 'Pressed!' : 'Press me'} * * ); * } * ``` */ declare function useOnPress(ref: ElementRef, handler: MousePressHandler | null | undefined): void; /** * Hook for handling mouse button release events on an element. * Must be used within a MouseProvider. * * Release events fire when a mouse button is released. * * @param ref - Reference to the element. * @param handler - Mouse release event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Button() { * const ref = useRef(null); * const [isPressed, setIsPressed] = useState(false); * * useOnPress(ref, () => setIsPressed(true)); * useOnRelease(ref, () => setIsPressed(false)); * * return ( * * {isPressed ? 'Pressed!' : 'Press me'} * * ); * } * ``` */ declare function useOnRelease(ref: ElementRef, handler: MouseReleaseHandler | null | undefined): void; /** * Hook for handling wheel (scroll) events on an element. * Must be used within a MouseProvider. * * @param ref - Reference to the element. * @param handler - Wheel event handler. * * @throws {Error} If used outside of MouseProvider * * @example * ```tsx * function Scrollable() { * const ref = useRef(null); * const [offset, setOffset] = useState(0); * * useOnWheel(ref, (event) => { * if (event.button === 'wheel-up') { * setOffset((prev) => Math.max(0, prev - 1)); * } else if (event.button === 'wheel-down') { * setOffset((prev) => prev + 1); * } * }); * * return ( * * * {items.map((item) => ( * {item.name} * ))} * * * ); * } * ``` */ declare function useOnWheel(ref: ElementRef, handler: WheelHandler | null | undefined): void; type MouseProviderProps = PropsWithChildren<{ readonly autoEnable?: boolean; readonly cacheInvalidationMs?: number; }>; declare const MouseProvider: FC; /** * Check if an event has a specific modifier key pressed. * * @param event - The mouse event. * @param modifier - The modifier to check ('shift' | 'alt' | 'ctrl'). * @returns True if the modifier is pressed, false otherwise. * * @example * ```ts * const event = { shift: true, alt: false, ctrl: true, ... }; * hasModifier(event, 'shift'); // true * hasModifier(event, 'alt'); // false * ``` */ declare function hasModifier(event: InkMouseEvent, modifier: 'shift' | 'alt' | 'ctrl'): boolean; /** * Check if any modifier key is pressed. * * @param event - The mouse event. * @returns True if any modifier is pressed, false otherwise. * * @example * ```ts * const event = { shift: true, alt: false, ctrl: false, ... }; * hasAnyModifier(event); // true * ``` */ declare function hasAnyModifier(event: InkMouseEvent): boolean; /** * Transform an xterm-mouse event to InkMouseEvent. * Currently returns the event as-is since InkMouseEvent extends it. * This function exists for future extensibility. * * @param event - The xterm-mouse event. * @returns The transformed InkMouseEvent. */ declare function transformEvent(event: InkMouseEvent): InkMouseEvent; /** * Filter events based on modifier requirements. * * @param event - The mouse event. * @param options - Filter options. * @returns True if the event matches the filter, false otherwise. * * @example * ```ts * const event = { shift: true, alt: false, ctrl: false, ... }; * * // Event must have shift pressed * filterEvent(event, { shift: true }); // true * * // Event must have only shift pressed (no alt or ctrl) * filterEvent(event, { shift: true, alt: false, ctrl: false }); // true * * // Event must have no modifiers * filterEvent(event, { shift: false, alt: false, ctrl: false }); // false * ``` */ declare function filterEvent(event: InkMouseEvent, options: { shift?: boolean; alt?: boolean; ctrl?: boolean; }): boolean; /** * Check if a point (x, y) is inside a rectangle. * * @param x - The x coordinate of the point. * @param y - The y coordinate of the point. * @param rect - The bounding rectangle. * @returns True if the point is inside the rectangle, false otherwise. * * @example * ```ts * const rect = { left: 10, top: 10, right: 20, bottom: 20, width: 10, height: 10, x: 10, y: 10 }; * isPointInRect(15, 15, rect); // true * isPointInRect(5, 5, rect); // false * ``` */ declare function isPointInRect(x: number, y: number, rect: BoundingClientRect): boolean; /** * Get the center point of a rectangle. * * Useful for centering elements, calculating anchor points for connectors, * or positioning tooltips relative to elements. * * @param rect - The bounding rectangle. * @returns The center point {x, y}. * * @example * ```ts * const rect = { left: 0, top: 0, right: 10, bottom: 10, width: 10, height: 10, x: 0, y: 0 }; * getRectCenter(rect); // { x: 5, y: 5 } * ``` * * @example * ```ts * // Position a tooltip at the center of a button * import { getBoundingClientRect, getRectCenter } from '@ink-tools/ink-mouse'; * * const buttonRect = getBoundingClientRect(buttonRef.current); * if (buttonRect) { * const center = getRectCenter(buttonRect); * console.log(`Button center: ${center.x}, ${center.y}`); * } * ``` */ declare function getRectCenter(rect: BoundingClientRect): { x: number; y: number; }; /** * Check if two rectangles overlap. * * Useful for collision detection, determining if elements intersect, * or checking if a dragged element overlaps with drop targets. * * @param rect1 - The first rectangle. * @param rect2 - The second rectangle. * @returns True if the rectangles overlap, false otherwise. * * @example * ```ts * const rect1 = { left: 0, top: 0, right: 10, bottom: 10, width: 10, height: 10, x: 0, y: 0 }; * const rect2 = { left: 5, top: 5, right: 15, bottom: 15, width: 10, height: 10, x: 5, y: 5 }; * isRectOverlapping(rect1, rect2); // true * ``` * * @example * ```ts * // Check if a dragged element overlaps with drop zones * import { useBoundingClientRect, isRectOverlapping } from '@ink-tools/ink-mouse'; * * function DragItem() { * const dragRect = useBoundingClientRect(dragRef); * const dropZoneRect = useBoundingClientRect(dropZoneRef); * * const canDrop = dragRect && dropZoneRect && isRectOverlapping(dragRect, dropZoneRect); * * return {canDrop ? 'Drop here!' : 'Drag over target'}; * } * ``` */ declare function isRectOverlapping(rect1: BoundingClientRect, rect2: BoundingClientRect): boolean; export { type BoundingClientRect, type ClickHandler, type DOMRect, type ElementRef, type InkMouseEvent, MouseContext, type MouseContextValue, type MouseDragHandler, type MouseEnterHandler, type MouseLeaveHandler, type MouseMoveHandler, type MousePressHandler, MouseProvider, type MouseReleaseHandler, type WheelHandler, filterEvent, getBoundingClientRect, getElementDimensions, getElementPosition, getRectCenter, hasAnyModifier, hasModifier, isPointInRect, isRectOverlapping, transformEvent, useBoundingClientRect, useElementDimensions, useElementPosition, useMouse, useOnClick, useOnDrag, useOnMouseEnter, useOnMouseLeave, useOnMouseMove, useOnPress, useOnRelease, useOnWheel };