UNPKG

@react-hive/honey-utils

Version:

A lightweight TypeScript utility library providing a collection of helper functions for common programming tasks

344 lines (343 loc) 13.7 kB
import type { Nullable } from './types'; export declare const FOCUSABLE_HTML_TAGS: string[]; interface HTMLElementTransformationValues { translateX: number; translateY: number; scaleX: number; scaleY: number; skewX: number; skewY: number; } /** * Extracts transformation values (translate, scale, skew) from the 2D transformation matrix of a given HTML element. * * Only works with 2D transforms (i.e., `matrix(a, b, c, d, e, f)`). * * @param element - The element with a CSS transform applied. * @returns An object with parsed transformation values. * * @example * ```ts * const values = parse2DMatrix(myElement); * console.log(values.translateX); * console.log(values.scaleX); * ``` */ export declare const parse2DMatrix: (element: HTMLElement) => HTMLElementTransformationValues; /** * Creates a clone of a Blob object. * * @param blob - The Blob object to clone. * * @returns A new Blob with the same content and type as the original. */ export declare const cloneBlob: (blob: Blob) => Blob; /** * Calculates the intersection ratio between two DOM rectangles. * * The ratio represents the proportion of the `targetRect` that is covered by `sourceRect`. * A value of `1` means `sourceRect` completely covers `targetRect`, and `0` means no overlap. * * @param sourceRect - The rectangle used to measure overlap against the target. * @param targetRect - The rectangle whose covered area is measured. * * @returns A number between `0` and `1` representing the intersection ratio. */ export declare const getDOMRectIntersectionRatio: (sourceRect: DOMRect, targetRect: DOMRect) => number; /** * Returns the bounding DOMRect of an element based on offset and client dimensions. * * This utility is useful when you need a stable, layout-based rect * without triggering a reflow via `getBoundingClientRect()`. * * @param element - The target HTML element. * @returns A `DOMRect` representing the element’s offset position and size. */ export declare const getElementOffsetRect: (element: HTMLElement) => DOMRect; /** * Determines whether the given HTMLElement is an HTMLAnchorElement. * * Acts as a type guard so that TypeScript narrows `element` to * `HTMLAnchorElement` when the function returns `true`. * * An element qualifies as an anchor by having a tag name of `"A"`. * * @param element - The element to test. * * @returns Whether the element is an anchor element. */ export declare const isAnchorHtmlElement: (element: HTMLElement) => element is HTMLAnchorElement; /** * Checks whether an element is explicitly marked as contenteditable. * * Browsers treat elements with `contenteditable="true"` as focusable, * even if they are not normally keyboard-focusable. * * @param element - The element to inspect. * * @returns True if `contenteditable="true"` is set. */ export declare const isContentEditableHtmlElement: (element: HTMLElement) => boolean; /** * Determines whether an HTMLElement is focusable under standard browser rules. * * The function checks a combination of factors: * - The element must be rendered (not `display: none` or `visibility: hidden`). * - Disabled form controls are never focusable. * - Elements with `tabindex="-1"` are intentionally removed from the focus order. * - Certain native HTML elements are inherently focusable (e.g. inputs, buttons, anchors with `href`). * - Elements with `contenteditable="true"` are treated as focusable. * - Any element with a valid `tabindex` (not null) is considered focusable. * * This logic approximates how browsers and the accessibility tree * determine real-world focusability—not just tabindex presence. * * @param element - The element to test. `null` or `undefined` will return `false`. * * @returns Whether the element is focusable. */ export declare const isHtmlElementFocusable: (element: Nullable<HTMLElement>) => boolean; /** * Collects all focusable descendant elements within a container. * * The function queries *all* elements under the container and filters them * using `isHtmlElementFocusable`, producing a reliable list of elements * that can receive keyboard focus in real-world browser conditions. * * @param container - The root container whose focusable children will be found. * * @returns An array of focusable HTMLElements in DOM order. */ export declare const getFocusableHtmlElements: (container: HTMLElement) => HTMLElement[]; export type FocusMoveDirection = 'next' | 'previous'; export interface MoveFocusWithinContainerOptions { /** * Whether focus navigation should wrap around when reaching * the beginning or end of the focusable elements list. * * When enabled, moving past the last element focuses the first, * and moving before the first focuses the last. * * @default true */ wrap?: boolean; /** * Custom resolver for determining the next focus index. * * When provided, this function overrides the default navigation logic * and receives full control over how the focus moves. * * @param currentIndex - Index of the currently focused element. * @param direction - Direction in which focus is moving. * @param elements - Ordered list of focusable elements within the container. * * @returns The index of the element to focus next, or `null` to prevent focus movement. */ getNextIndex?: (currentIndex: number, direction: FocusMoveDirection, elements: HTMLElement[]) => Nullable<number>; } /** * Moves focus to the next or previous focusable element within a container. * * This utility is commonly used to implement accessible keyboard navigation patterns such as: * - roving tabindex * - custom dropdowns * - tablists * - menus * - horizontal or vertical navigation groups * * Focus movement is scoped to a container and operates on the list of * focusable descendants returned by `getFocusableHtmlElements`. * * @param direction - Direction in which focus should move (`'next'` or `'previous'`). * @param container - Optional container that defines the focus scope. * If omitted, the parent element of the currently focused element is used. * @param options - Optional configuration controlling wrapping behavior and custom index resolution. * * @remarks * - This function reads from and mutates the document's focus state. * - If no active element exists, no container can be resolved, * or the active element is not part of the focusable set, no action is taken. * - When `getNextIndex` is provided, it fully overrides the default wrapping and directional logic. */ export declare const moveFocusWithinContainer: (direction: FocusMoveDirection, container?: Nullable<HTMLElement>, { wrap, getNextIndex }?: MoveFocusWithinContainerOptions) => void; /** * Checks whether an element has horizontal overflow. * * @param element - The element to check. * * @returns `true` if the content overflows horizontally. */ export declare const hasXOverflow: (element: HTMLElement) => boolean; /** * Calculates the horizontal overflow width of an element. * * The overflow width represents how much wider the content is compared * to the visible container area. * * @param element - The scrollable container element. * * @returns The overflow width in pixels. Returns `0` when the content does not overflow horizontally. */ export declare const getXOverflowWidth: (element: HTMLElement) => number; /** * Checks whether an element has vertical overflow. * * @param element - The element to check. * * @returns `true` if the content overflows vertically. */ export declare const hasYOverflow: (element: HTMLElement) => boolean; /** * Calculates the vertical overflow height of an element. * * The overflow height represents how much taller the content is compared * to the visible container area. * * @param element - The scrollable container element. * * @returns The overflow height in pixels. Returns `0` when the content does not overflow vertically. */ export declare const getYOverflowHeight: (element: HTMLElement) => number; export interface CalculateCenterOffsetOptions { /** * Total overflow size for the axis. * * Represents how much larger the content is compared to the visible * container size (e.g. scroll width minus client width). */ overflowSize: number; /** * Visible size of the container along the axis. * * Typically, `clientWidth` for the X axis or `clientHeight` for the Y axis. */ containerSize: number; /** * Offset of the target element from the start of the container along the axis. * * Typically, `offsetLeft` (X axis) or `offsetTop` (Y axis). */ elementOffset: number; /** * Size of the target element along the axis. * * Typically, `clientWidth` (X axis) or `clientHeight` (Y axis). */ elementSize: number; } /** * Calculates the offset required to center an element within a container along a single axis. * * The returned value is clamped so that the resulting translation does not * exceed the container's scrollable bounds. * * This function performs pure math only and does not access the DOM. * * @returns A negative offset value suitable for use in a CSS `translate` * transform, or `0` when no overflow exists on the axis. */ export declare const calculateCenterOffset: ({ overflowSize, containerSize, elementOffset, elementSize, }: CalculateCenterOffsetOptions) => number; type Axis = 'x' | 'y' | 'both'; export interface CenterElementInContainerOptions { /** * Axis (or axes) along which centering is applied. * * @default 'both' */ axis?: Axis; } /** * Translates a container so that a target element is visually centered within its visible bounds. * * Centering is achieved by applying a CSS `transform: translate(...)` to the * container element rather than using native scrolling. * * ### Behavior * - Centering is calculated independently for each enabled axis. * - Translation is applied only when the container content overflows on that axis. * - When no overflow exists, the container remains untransformed for that axis. * * ### Notes * - This function performs immediate DOM reads and writes. * - The resulting transform is clamped to valid scrollable bounds. * * @param containerElement - The container whose content is translated. * @param elementToCenter - The descendant element to align to the container’s center. * @param options - Optional configuration controlling which axis or axes are centered. */ export declare const centerElementInContainer: (containerElement: HTMLElement, elementToCenter: HTMLElement, { axis }?: CenterElementInContainerOptions) => void; /** * Determines whether the browser environment allows safe read access to * `localStorage`. Some platforms (e.g., Safari Private Mode, sandboxed iframes) * expose `localStorage` but still throw when accessed. * * This function **only tests read access**, making it safe even when write * operations would fail due to `QuotaExceededError` or storage restrictions. * * @returns `true` if `localStorage` exists and calling `getItem()` does not * throw; otherwise `false`. */ export declare const isLocalStorageReadable: () => boolean; interface LocalStorageCapabilities { readable: boolean; writable: boolean; } interface LocalStorageCapabilities { readable: boolean; writable: boolean; } /** * Determines whether the browser's `localStorage` supports safe read and write operations. * This function performs two independent checks: * * **1. Readability** * - Verified by calling `localStorage.getItem()` inside a `try` block. * - Fails in environments where storage access throws immediately (e.g., disabled storage, * sandboxed iframes, strict privacy modes, SSR). * * **2. Writeability** * - Verified by attempting to `setItem()` and then `removeItem()` using a temporary key. * - Can fail due to: * - `QuotaExceededError` when storage is full. * - Disabled write access (e.g., Safari Private Mode). * - Security-restricted contexts (third-party frames, hardened privacy settings) * * @returns An object describing the detected `localStorage` capabilities. */ export declare const getLocalStorageCapabilities: () => LocalStorageCapabilities; export type Downloadable = Blob | MediaSource | string; export interface DownloadFileOptions { /** * Suggested filename for the downloaded file. * * When provided, the browser will attempt to save the file using this name. * If omitted and the source is a URL string, the browser may infer the name * from the URL. */ fileName?: string; /** * Target browsing context for the download link. */ target?: '_self' | '_blank'; } /** * Initiates a file download in a browser environment. * * This utility supports downloading from: * - a URL string * - a `Blob` * - a `MediaSource` * * For non-string inputs, an object URL is created temporarily and * automatically revoked after the download is triggered. * * @remarks * - This function performs direct DOM manipulation and must be executed in a browser environment. * - In non-DOM contexts (e.g. SSR), the function exits without side effects. * - Object URLs are revoked asynchronously to avoid Safari-related issues. * * @param file - The file source to download (URL string or binary object). * @param options - Optional configuration controlling filename and link target. */ export declare const downloadFile: (file: Downloadable, { fileName, target }?: DownloadFileOptions) => void; export {};